mpl_client.py 9.77 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
62
63
64
65
        print('makefile done')
        #~ if debug:
        print('Client sending ',
              type(sig),
              ' with content \"',
              sig.content, '\"')
66
67
68
        try:
            pickle.dump(sig, wf)
        except Exception:
69
            return False
70
71
72
        wf.close()
        return True

73
74
    def wait_for_signal(self):

75
76
        # wait for signal
        # unpickel
77

78
        rf = self.sock.makefile(mode='rb')
79
        try:
Yori Fournier's avatar
Yori Fournier committed
80
81
            unpickler = MplUnpickler(rf)
            response = unpickler.load()
82
83
84
85
            if debug and isinstance(response, Signal):
                print('CLIENT Received: {} with content \"{}\"'.format(
                    type(response), response.content))
        except EOFError:
86
87
            print('no answer received - or connection closed unexpectedly')
            response = None
88
        except Exception:
89
            print('unknown error while waiting for response')
90
91
            response = None
        rf.close()
92
        if isinstance(response, Signal):
93
            return response
94
95
96
97
98
99
100

    def test_status_sig(self, org_query, status_sig):

        if isinstance(status_sig, Status):
            if status_sig.value:
                if debug:
                    print('request type ',
101
                          org_query.query_type,
102
                          ' successful')
103
                return True
104
105
            else:
                if debug:
106
                    print('something went wrong on the '
107
108
109
                          'server side handling request type',
                          org_query.query_type)
                    print(status_sig.content)
110
                return False
111
112
113
        else:
            print('request type ', org_query.query_type,
                  ' returned unknown status type')
114
            return False
115
116

    def read_data(self, io_function, data_name, *args, **kwargs):
117
        # create a Signal of type Query with arguments
118
        self.connect((self.host, self.port))
119
        query = Query(Query.READDATA, {'func': io_function,
120
                                       'data_name': data_name,
121
122
                                       'args': args,
                                       'kwargs': kwargs})
123
        status = self.send(query)
124
125
126
127
        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
128
        self.disconnect()
129
        return self.test_status_sig(query, status_sig)
130

131
132
    def list_remote_data(self):
        """ The server retuns a list with the content of its G_RAWDATA
133
        """
134
        self.connect((self.host, self.port))
135
        query = Query(Query.LISTDATA, None)
136
        status = self.send(query)
137
        if not status:
138
            print('something went wrong with the '
139
                  'sending of listRemoteData request...')
140
        answer = self.wait_for_signal()
141
142

        self.disconnect()
143
144

        if isinstance(answer, Answer):
145
            return answer.content
146
        elif isinstance(answer, Status):
147
148
            print(answer.content)
            return None
149
150

    def list_remote_fig(self):
151
152
153
        """ The server retuns a list with the content of its G_FIGURES
        """
        self.connect((self.host, self.port))
154
        query = Query(Query.LISTFIG, None)
155
        status = self.send(query)
156
        if not status:
157
            print('something went wrong with the '
158
                  'sending of listRemoteFig request...')
159
        answer = self.wait_for_signal()
Yori Fournier's avatar
Yori Fournier committed
160
161

        self.disconnect()
162
163

        if isinstance(answer, Answer):
164
            return answer.content
165
        elif isinstance(answer, Status):
166
167
            print(answer.content)
            return None
168
169
170
171

    def get_data(self, dataname):
        """ The server returns the actual data known under "dataname"
        warning: this can possibly be HUGE
172
        """
173
        self.connect((self.host, self.port))
174
        query = Query(Query.GETDATA, dataname)
175
        status = self.send(query)
176
        if not status:
177
            print('something went wrong with the '
178
                  'sending of readData request...')
179
        answer = self.wait_for_signal()
Yori Fournier's avatar
Yori Fournier committed
180
181

        self.disconnect()
182
183

        if isinstance(answer, Answer):
184
            return answer.content
185
        elif isinstance(answer, Status):
186
187
            print(answer.content)
            return None
188
189

    def new_sync_figure(self, figname, dataname, *args, **kwargs):
190
191
192
193
194
        '''
        Send a query NEWSYNCFIGURE to the server
        wait for the status.
        if status ok then sync.
        '''
Yori Fournier's avatar
Yori Fournier committed
195

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

198
        # create a Signal of type Query with args
199
        query = Query(Query.NEWSYNCFIGURE, {
200
201
            'fig_class_came': figname.__name__,
            'data_name': dataname,
202
203
            'args': args,
            'kwargs': kwargs})
204
        status = self.send(query)
205
206

        if not status:
207
            print('something went wrong '
208
                  'with the sending of new_sync_figure request...')
209
        answer = self.wait_for_signal()
Yori Fournier's avatar
Yori Fournier committed
210

211
        self.disconnect()
212

213
        # try to create a figure of the same class on the client side
214
        if isinstance(answer, Answer):
Philipp Gast's avatar
Philipp Gast committed
215
216
            print('trying to create a figure of the same '
                  'class on the client side')
217
            fig = figname(dataname, *args, **kwargs)
218
            # Link the temporary Sync Figure
219
            fig.sync_id = answer.content
220
            fig.client = self
221
            return fig
222
223
224

        elif isinstance(answer, Status):
            self.test_status_sig(query, answer)
225
            print('>>>>>>>>>>>>>>>>>>>>>>>>>> response is not an Answer!!!')
226
            return None
227
        else:
228
229
            print('an unknown error occured')
            return None
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247

    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:
248
            return True
249
        else:
250
            return False
251

252
    def delete_sync_figure(self, sync_id):
253
        '''
254
255
256
257
        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
258

259
        self.connect((self.host, self.port))
260
261
262

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

265
        status_sig = self.wait_for_signal()
266

Yori Fournier's avatar
Yori Fournier committed
267
        self.disconnect()
268
269

        if status and status_sig.value:
270
271
272
            return True
        else:
            print('The remote figure could not be deleted')
273
            print status_sig.content
274
            return False
275
276

    # SYNC FIGURE FORMAT RAWDATA ---------------------------------------
277
    def sync_fig_format_rawdata(self, sync_id):
278
        ''' Send a FORMAT_SYNC_FIGURE query to the server.
279
        wait for the answer
280
        if answer not empty then set data to answer's value.'''
281

282
        self.connect((self.host, self.port))
283
284
285

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

288
289
        if debug:
            if not status:
290
                print(INFO + 'Sent Signal')
291

292
        formated_data = self.wait_for_signal()
293

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

296
        if not isinstance(formated_data, Answer):
297
            print(WARN + 'The server could not format the rawdata.')
298
299
300

            if isinstance(formated_data, Status):
                if formated_data.value:
301
                    print('This should not happen')
302
                else:
Philipp Gast's avatar
Philipp Gast committed
303
                    print('instead of answer a error was received')
304
305
            datas = (None,)
        else:
306
            # set the figure data to answerSig.value
307
            datas = formated_data.content
308
        return datas