mplServer2.py 11.4 KB
Newer Older
1
2
import SocketServer
import pickle
3
import threading
4

Yori Fournier's avatar
Yori Fournier committed
5
from . import Signal,Status,Query,Answer
6
7
8
9

from . import SERVER_IOFUNCTIONS
from . import SERVER_FIGURES

10
11
from . import MyFig

12
from . import DBUG,WARN,SPCE,SEVR,INFO
Yori Fournier's avatar
Yori Fournier committed
13
from . import MplUnpickler
14
15

G_RAWDATA = dict()
16
G_FIGURES = dict()
17
18

DEBUG = True
19
debug = True
20
class MplHandler(SocketServer.StreamRequestHandler):
21
    
22
    def servPrint(self,x) : # This should be replaced with a proper implementation (s.b.) ?
23
        print("SERVER: "+x)
24
25
26
27
28
29

    def dprint(*args): #likewise for WARN,SPCE,SEVR,INFO :wprint,sprint,sevprint,iprint ?
        argsl = list(args)
        if type(argsl[0]) is str :
            argsl[0] = DBUG + argsl[0]
        print(''.join([repr(arg) for arg in argsl]))
30
31
32
33
34
35
36
37
38
39
    
    def treatReadData(self,content):
        '''Treat signals of type readData.
        1. unpack signal with instruction size, 
        2. send receipt, 
        3. unpack instructions, 
        4. execute instructions,
        5. send dataID.
        '''
        
Yori Fournier's avatar
Yori Fournier committed
40
41
#        fct      = SERVER_IOFUNCTIONS[content.get('func')]
        fct      = self.server.knownFunctions[content.get('func')]
42
43
44
45
46
47
48
49
50
51
52
53
54
55
        args     = content.get('args')
        kwargs   = content.get('kwargs')
        dataName = content.get('dataname')
        
         # Try to execute the instructions
        try:
            G_RAWDATA[dataName] = fct(*args, **kwargs)
            if (DEBUG):
                print(INFO+"SERVER: I read the data following instructions")
#                print(str(G_RAWDATA[dataName].data))  # SHOULD BE SUPPRESS LATER
        except:
            if(DEBUG):
                print(WARN+"SERVER: The instructions of readData could not be executed.")
                print(SPCE+"SERVER: I tried: "+str(fct.__name__)+'('+str(args)+', '+str(kwargs)+')')
56
            return Status(False,"The instructions of readData could not be executed. I tried: "+str(fct.__name__)+'('+str(args)+', '+str(kwargs)+')')
57
        if dataName in G_RAWDATA :
58
59
60
61
62
63
64
            return Status(True,"SERVER: I read the data following instructions"+str(fct.__name__)+'('+str(args)+', '+str(kwargs)+')')
         
        return False #should never get here
        
    def treatNewSyncFigure(self,content) :
        # Try to create the requested figure
        
Yori Fournier's avatar
Yori Fournier committed
65
        FigClass = self.server.knownFigures[content.get('figClassName')]
66
67
        args     = content.get('args')
        kwargs   = content.get('kwargs')
68
69
70
        datanames = content.get('dataName')
        
        datas     = [G_RAWDATA[name] for name in datanames]
71
72
        
        try:
73
74
            # create the figure:
            fig = FigClass(datas, **kwargs)
75
76
            if (DEBUG):
                print(INFO+"SERVER: I created the requested Figure")
77
        except Exception as e:
78
79
80
            if (DEBUG):
                print(WARN+"SERVER: I could not create the requested Figure.")
                print(SPCE+"SERVER: I tried: "+str(FigClass.__name__)+'('+str(datas)+', '+str(kwargs)+')')
81
82
                print(SPCE+"SERVER: Exception details where:",e.message, e.args )
            return Status(False, "I could not create the requested Figure. I tried: "+str(FigClass.__name__)+'('+str(datas)+', '+str(kwargs)+')'+" Exception details where:"+str(e.message)+str(e.args))
83
        
84
85
86
87
88
        # add the figure to the global index
        G_FIGURES[fig.getFigID()] = fig
        
        if fig.getFigID() in G_FIGURES :
            return Answer(fig.getFigID())
89

90
91
    def getFigByID(self,figID) :
        """ Identify the figure by ID and return it. On error it will return a Status Signal"""
92
93
94
95
96
97
98
99
100
101
        
        # Identify the figure
        fig = G_FIGURES.get(figID,None)
        if fig is None :
            if DEBUG:
                print(WARN+"The figure ID: "+figID+" does not exist.")
            return Status(False,"The figure ID: "+figID+" does not exist.")
        elif isinstance(fig,MyFig) :
            if DEBUG :
                print('Figure ',figID,' found in database')
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
            return fig
        
    def treatUpdateSyncFigure(self,content) :
        """ If client request an update of the keywords of a figure. This function forwards the request to the corresponding figure"""
        
        figID,kwargs = content
        fig = self.getFigByID(figID)
        
        # if an error occured forward the signal
        if isinstance(fig,Signal) :
            return fig
        
        status = fig.update(**kwargs)
        
        if status :
            return Status(True,'Kewords of figure ID: '+figID+' successfully updated')
        else :
            return Status(False,'Kewords of figure ID: '+figID+' could not be updated')

    def treatSyncFigFormatRawData(self,figID):
        
        # Identify the figure
        fig = self.getFigByID(figID)
        
        # if an error occured forward the signal
        if isinstance(fig,Signal) :
            return fig
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
        
        # Format the rawdata
        try:
            fig.formatRawData()
        except Exception as e:
            if DEBUG:
                print(WARN+"I couldn't format the rawdata.")
                print(SPCE+"SERVER: Exception details where:",e.message, e.args )
            return Status(False,"I couldn't format the rawdata. Exception details where:",e.message, e.args)
        
        # compose the answer
        datas = ()
        for ax in fig.get_axes():
            # ax.data is any user defined object
            # ax.packFormattedData returns it's string representation
            # to be unpacked by ax.unpackFormattedData
#            datas.append(ax.packFormattedData(ax.data))
            datas = datas + (ax.data,)
        
148
        return Answer(datas)
149
150
151
152
153
154
155
156
        
    def treatDeleteSyncFigure(self,figID) :
        """ Deletes the figure with ID figID from G_FIGURES """
        if figID in G_FIGURES :
            del G_FIGURES[figID]
            return Status(True,'Figure with ID '+str(figID)+' deleted from server.')
        else :
            return Status(False,'Figure with ID '+str(figID)+' not found on server side.')
157
158
159
160
161
162
163
164
165
166
167
    
    def treatListData(self,content) :
        """ list the keys (and possibly (later) the location from G_RAWDATA """
        return Answer(G_RAWDATA.keys())
        
    def treatGetData(self,content) :
        """  from G_FIGURES """
        if content in G_RAWDATA:
            return Answer(G_RAWDATA[content])
        else :
            return Status(False,'Dataname not found in index of the server side...')
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
    
    def send(self,sig):
        # pickel the signal
        # send the str
        wf = self.server.socket.makefile(mode='wb')
        if debug:
            print('sending ',type(sig),' with content \"',sig.content,'\"')
        try :
            pickle.dump(sig,wf)
        except Exception as e:
            if DEBUG:
                print(SPCE+"SERVER: Exception details where:",e.message, e.args )
            return False
        wf.close()
        return True
        
    def waitForSignal(self):
        # wait for signal
        # unpickel
        
        rf = self.server.socket.makefile(mode='rb')
        try :
Yori Fournier's avatar
Yori Fournier committed
190
191
            unpickler = MplUnpickler(rf)
            response = unpickler.load()
192
193
194
195
196
197
198
199
200
201
202
203
204
            if DEBUG and isinstance(response,Signal):
                print('CLIENT Received: {} with content \"{}\"'.format(type(response),response.content))
        except EOFError :
            print('no answer received - or connection closed unexpectedly')
            response = None
        except Exception as e:
            print('unknown error while waiting for response')
            print(SPCE+"SERVER: Exception details where:",e.message, e.args )
            response = None
        rf.close()
        if isinstance(response,Signal) :
            return response
    
205
206
207
208
209
210
211
212
213
214
    def treatSig(self,sig):
        if   isinstance(sig,Query) :
            if   sig.queryType == sig.READDATA :
                return self.treatReadData(sig.content)
            elif sig.queryType == sig.NEWSYNCFIGURE :
                return self.treatNewSyncFigure(sig.content)
            elif sig.queryType == sig.UPDATESYNCFIGURE :
                return self.treatUpdateSyncFigure(sig.content) 
            elif sig.queryType == sig.SYNCFIGFORMATRAWDATA :
                return self.treatSyncFigFormatRawData(sig.content)
215
216
            elif sig.queryType == sig.DELETESYNCFIGURE :
                return self.treatDeleteSyncFigure(sig.content)
217
218
219
220
            elif sig.queryType == sig.LISTDATA :
                return self.treatListData(sig.content)
            elif sig.queryType == sig.GETDATA :
                return self.treatGetData(sig.content)
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
            else :
                self.servPrint('received unknown query type')
                return Status(False,"received unknown query type")
        elif isinstance(sig, Status) :
            if sig.value :
                pass #if it is just a positiv status message do nothing
            else :
                self.servPrint('the client Side reported of an error:')
                self.servPrint('----'+sig.content)
        elif isinstance(sig, Answer) :
            #~ #needed for server???
            pass
        elif isinstance(sig, Signal) :
            self.servPrint('received unknown signal')
            return Status(False,"received unknown signal")
        else : 
            self.servPrint('what is happening here??? received Object of type:')
            self.servPrint(str(sig))
            return Status(False,"received something totally diffenent")
            
    
    def handle(self):
        # self.rfile is a file-like object created by the handler;
        # we can now use e.g. readline() instead of raw recv() calls
        ## self.data = self.rfile.readline()#.strip()
246
        while self.server.running :
Yori Fournier's avatar
Yori Fournier committed
247
248
            unpickler = MplUnpickler(self.rfile)
            request = unpickler.load()
249
            reply = self.treatSig(request)
250
251
252
        # Likewise, self.wfile is a file-like object used to write back
        # to the client
        ## self.wfile.write(self.data.upper())
253
254
255
256
            if isinstance(reply,Signal) :
                if DEBUG:
                    self.servPrint("returning {}-Signal:".format(type(reply)))
                pickle.dump(reply,self.wfile)
257
258
259
260
261
262

class MplServer2(SocketServer.TCPServer):
    
    allow_reuse_address=True
    
    # DEFINE KNOWN I/O FUNCTIONS ---------------------------------------
Yori Fournier's avatar
Yori Fournier committed
263
    def defineKnownFunctions(self, functions):
264
265
        '''Function to overwrite in order to declare the known
        I/O functions by the server context.'''
Yori Fournier's avatar
Yori Fournier committed
266
        self.knownFunctions = functions
267
268

    # DEFINE KNOWN FIGURE CLASSES --------------------------------------
Yori Fournier's avatar
Yori Fournier committed
269
    def defineKnownFigures(self, figures):
270
271
        '''Function to overwrite in order to declare the known
        Figure classes by the server context.'''
Yori Fournier's avatar
Yori Fournier committed
272
        self.knownFigures = figures
273

Yori Fournier's avatar
Yori Fournier committed
274
    def __init__(self, ip='', port=52386, handler=MplHandler, knownFunctions=SERVER_IOFUNCTIONS, knownFigures=SERVER_FIGURES) :
275
276
277
278
        '''Intialisation of the server, defines known functions, known
        figure classes. It needs to be called.'''

        # Define functions and figure classes
Yori Fournier's avatar
Yori Fournier committed
279
280
281
        self.defineKnownFunctions(knownFunctions)
        self.defineKnownFigures(knownFigures)
        SocketServer.TCPServer.__init__(self, (ip, port), handler)
282
        self.running = False
283
        self.initialized = True
284
285
286
287
288
289

    def run(self, as_daemon=True):
        self.server_thread = threading.Thread(target=self.serve_forever)
        self.server_thread.daemon = as_daemon
        self.server_thread.start()

290
        self.running = True
291

292
    def stop(self):  # not yet working
293
        print('STOPING...')
294
#        self.server_thread.stop() 
295
        self.running = False
296