mpl_client.py 11.2 KB
Newer Older
1
2
from . import socket, AF_INET, SOCK_STREAM
import pickle
Yori Fournier's avatar
Yori Fournier committed
3
from . import Query, Status, Answer, Signal
4
from . import DBUG, WARN, SPCE, SEVR, INFO
Yori Fournier's avatar
Yori Fournier committed
5
from . import MplUnpickler
6

7
8
9
from . import D_DEBUG

debug = D_DEBUG
10

11

12
class MplClient():
13

14
    def __init__(self):
15
16
17

        self.host, self.port = (None, None)

18
        # just a list of names
19
        self.current_remotedata = []
20

21
22
23
24
    def connect(self, con):

        self.host, self.port = con      # give (IP,PORT)
        self.sock = socket(AF_INET, SOCK_STREAM)
25
26
        self.sock.connect(con)
        self.connected = True
Yori Fournier's avatar
Yori Fournier committed
27

28
    def disconnect(self):
29
30
31
        ''' shutdown socket. Warning:
        If server and client are local the client can not shut down
        the port because the server has still a handle on it'''
32
        print('closing the connection...')
33
34
35
        # shutdown() is meant to shut down server without wait.
        # _Warning_ enabling will cause break of program. !!!
        # self.sock.shutdown(socket.SHUT_WR)
36
37
38
        self.sock.close()
        self.connected = False
        print('closing the connection... DONE')
39
40
41

    def reset_connection(self, new_con=None):

42
        self.disconnect()
43
44
45
46
47
48
        if new_con is not None:
            self.connect(new_con)
        else:                         # try to use the old values
            if (self.host is not None) and (self.port is not None):
                self.connect((self.host, self.port))
            else:
49
                print('connection not initialized with correct values:')
50
51
52
53
54
55
56
57
                print('please provide host,port. currently host: ',
                      self.host,
                      ' , port:',
                      self.port)

    def send(self, sig):
        """ Sending a Type derived from Signal through the socket
        after 'pickling' it"""
Philipp Gast's avatar
Philipp Gast committed
58
        print('prepare sending')
59
        wf = self.sock.makefile(mode='wb')
Philipp Gast's avatar
Philipp Gast committed
60
61
        print('makefile done')
        #~ if debug:
62
63
64
65
66
67
68
        if isinstance(sig, Query):
            print('Client sending {sig_type}, {query_type} with content {sig_content}'.format(sig_type=type(sig), query_type=sig.query_type, sig_content=sig.content))
        else:
            print('Client sending ',
                  type(sig), 
                  ' with content \"',
                  sig.content, '\"')
69
70
71
        try:
            pickle.dump(sig, wf)
        except Exception:
72
            return False
73
74
75
        wf.close()
        return True

76
77
    def wait_for_signal(self):

78
79
        # wait for signal
        # unpickel
80

81
        rf = self.sock.makefile(mode='rb')
82
        try:
Yori Fournier's avatar
Yori Fournier committed
83
84
            unpickler = MplUnpickler(rf)
            response = unpickler.load()
85
86
87
88
# THIS CAN RAISE AN EXCEPTION IF DATA TOO LARGE!!
#            if debug and isinstance(response, Signal):
#                print('CLIENT Received: {} with content \"{}\"'.format(
#                    type(response), response.content))
89
        except EOFError:
90
91
            print('no answer received - or connection closed unexpectedly')
            response = None
92
        except Exception as e:
93
            print('unknown error while waiting for response')
94
95
            print(type(e))
            print(e)
96
97
            response = None
        rf.close()
98
        if isinstance(response, Signal):
99
            return response
100
101
102
103
104
105
106

    def test_status_sig(self, org_query, status_sig):

        if isinstance(status_sig, Status):
            if status_sig.value:
                if debug:
                    print('request type ',
107
                          org_query.query_type,
108
                          ' successful')
109
                    print(status_sig.content)
110
                return True
111
112
            else:
                if debug:
113
                    print('something went wrong on the '
114
                          'server side handling request type ',
115
116
                          org_query.query_type)
                    print(status_sig.content)
117
                return False
118
119
120
        else:
            print('request type ', org_query.query_type,
                  ' returned unknown status type')
121
            return False
122
123

    def read_data(self, io_function, data_name, *args, **kwargs):
124
        # create a Signal of type Query with arguments
125
        self.connect((self.host, self.port))
126
127
128
129
130

        if not isinstance(io_function, str): # in case function is given instead of string
            io_function = io_function.__name__
            print('WARNING: You gave the function object instead of the function name in cilent.read_data.')

131
        query = Query(Query.READDATA, {'func': io_function,
132
                                       'data_name': data_name,
133
134
                                       'args': args,
                                       'kwargs': kwargs})
135
        status = self.send(query)
136
137
138
139
        if not status:
            print('''something went wrong with the
                    sending of readData request...''')
        status_sig = self.wait_for_signal()
Yori Fournier's avatar
Yori Fournier committed
140
        self.disconnect()
141
        return self.test_status_sig(query, status_sig)
142

143
144
145
    def merge_data(self, merged_name, data_names):
        # create a Signal of type Query with arguments
        self.connect((self.host, self.port))
146
        query = Query(Query.MERGEDATA, {'merged_name': merged_name,
147
                                       'data_names': data_names,})
148
149
150
151
152
153
154
155
        status = self.send(query)
        if not status:
            print('''something went wrong with the
                    sending of readData request...''')
        status_sig = self.wait_for_signal()
        self.disconnect()
        return self.test_status_sig(query, status_sig)

156
157
    def list_remote_data(self):
        """ The server retuns a list with the content of its G_RAWDATA
158
        """
159
        self.connect((self.host, self.port))
160
        query = Query(Query.LISTDATA, None)
161
        status = self.send(query)
162
        if not status:
163
            print('something went wrong with the '
164
                  'sending of listRemoteData request...')
165
        answer = self.wait_for_signal()
166
167

        self.disconnect()
168
169

        if isinstance(answer, Answer):
170
            return answer.content
171
        elif isinstance(answer, Status):
172
173
            print(answer.content)
            return None
174
175

    def list_remote_fig(self):
176
177
178
        """ The server retuns a list with the content of its G_FIGURES
        """
        self.connect((self.host, self.port))
179
        query = Query(Query.LISTFIG, None)
180
        status = self.send(query)
181
        if not status:
182
            print('something went wrong with the '
183
                  'sending of listRemoteFig request...')
184
        answer = self.wait_for_signal()
Yori Fournier's avatar
Yori Fournier committed
185
186

        self.disconnect()
187
188

        if isinstance(answer, Answer):
189
            return answer.content
190
        elif isinstance(answer, Status):
191
192
            print(answer.content)
            return None
193
194
195
196

    def get_data(self, dataname):
        """ The server returns the actual data known under "dataname"
        warning: this can possibly be HUGE
197
        """
198
        self.connect((self.host, self.port))
199
        query = Query(Query.GETDATA, dataname)
200
        status = self.send(query)
201
        if not status:
202
            print('something went wrong with the '
203
                  'sending of readData request...')
204
        answer = self.wait_for_signal()
Yori Fournier's avatar
Yori Fournier committed
205
206

        self.disconnect()
207
208

        if isinstance(answer, Answer):
209
            return answer.content
210
        elif isinstance(answer, Status):
211
212
            print(answer.content)
            return None
213
214

    def new_sync_figure(self, figname, dataname, *args, **kwargs):
215
216
217
218
219
        '''
        Send a query NEWSYNCFIGURE to the server
        wait for the status.
        if status ok then sync.
        '''
Yori Fournier's avatar
Yori Fournier committed
220

221
        self.connect((self.host, self.port))
222

223
        # create a Signal of type Query with args
224
        query = Query(Query.NEWSYNCFIGURE, {
225
226
            'fig_class_came': figname.__name__,
            'data_name': dataname,
227
228
            'args': args,
            'kwargs': kwargs})
229
        status = self.send(query)
230
231

        if not status:
232
            print('something went wrong '
233
                  'with the sending of new_sync_figure request...')
234
        answer = self.wait_for_signal()
Yori Fournier's avatar
Yori Fournier committed
235

236
        self.disconnect()
237

238
        # try to create a figure of the same class on the client side
239
        if isinstance(answer, Answer):
Philipp Gast's avatar
Philipp Gast committed
240
241
            print('trying to create a figure of the same '
                  'class on the client side')
242
            fig = figname(dataname, *args, **kwargs)
243
            # Link the temporary Sync Figure
244
            fig.sync_id = answer.content
245
            fig.client = self
246
            return fig
247
248
249

        elif isinstance(answer, Status):
            self.test_status_sig(query, answer)
250
            print('>>>>>>>>>>>>>>>>>>>>>>>>>> response is not an Answer!!!')
251
            return None
252
        else:
253
254
            print('an unknown error occured')
            return None
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272

    def update_sync_figure(self, sync_id, kwargs):
        ''' Send a UPDATE_SYNC_FIGURE query to the server.

        wait for the status
        if status ok then sync.
        '''

        self.connect((self.host, self.port))

        # create a signal with args
        query = Query(Query.UPDATESYNCFIGURE, (sync_id, kwargs))
        self.send(query)
        status_sig = self.wait_for_signal()

        self.disconnect()

        if status_sig.value:
273
            return True
274
        else:
275
            return False
276

277
    def delete_sync_figure(self, sync_id):
278
        '''
279
280
281
282
        Send a DELETESYNCFIGURE query to the server.
        If the FigID is known delete it from G_FIGURES (server)
        wait for the confirmation status
        if status ok then proceed deletion.'''
Yori Fournier's avatar
Yori Fournier committed
283

284
        self.connect((self.host, self.port))
285
286
287

        # create a signal with sync_id as content
        query = Query(Query.DELETESYNCFIGURE, sync_id)
288
        status = self.send(query)
Yori Fournier's avatar
Yori Fournier committed
289

290
        status_sig = self.wait_for_signal()
291

Yori Fournier's avatar
Yori Fournier committed
292
        self.disconnect()
293
294

        if status and status_sig.value:
295
296
297
            return True
        else:
            print('The remote figure could not be deleted')
298
            print(status_sig.content)
299
            return False
300
301

    # SYNC FIGURE FORMAT RAWDATA ---------------------------------------
302
    def sync_fig_format_rawdata(self, sync_id):
303
        ''' Send a FORMAT_SYNC_FIGURE query to the server.
304
        wait for the answer
305
        if answer not empty then set data to answer's value.'''
306

307
        self.connect((self.host, self.port))
308
309
310

        # Send the signal with sync_id as content
        signal = Query(Query.SYNCFIGFORMATRAWDATA, sync_id)
311
        status = self.send(signal)
312

313
314
        if debug:
            if not status:
315
                print(INFO + 'Sent Signal')
316

317
        formated_data = self.wait_for_signal()
318

Yori Fournier's avatar
Yori Fournier committed
319
320
        self.disconnect()

321
        if not isinstance(formated_data, Answer):
322
            print(WARN + 'The server could not format the rawdata.')
323
324
325

            if isinstance(formated_data, Status):
                if formated_data.value:
326
327
328
                    print('WARNING: This should not happen...')
                    print('Client recieved an Error with success status (True):')

329
                else:
330
331
332
333
334
                    print('instead of answer an error was received:')

                # Print error message
                print(str(formated_data.content))
                
335
            datas = None
Yori's avatar
Yori committed
336

337
        else:
338
            # set the figure data to answerSig.value
339
            datas = formated_data.content
340
        return datas