def offline_jianmo(self, shujulujing, moxinglujingqianzhui, timestamp=0, send=send): """Start building model for offline data Arguments: shujulujing {str} -- The offline data moxinglujingqianzhui {str} -- The prefix of model path, '.mat' will be added for real mpdel path Keyword Arguments: timestamp {int} -- [description] (default: {0}) send {func} -- Sending method (default: {send}) Returns: {int} -- 0 means success, 1 means fail """ send(real_time_reply.OK()) # The state should be 'Idle' if self.check_state('Idle', 'offline_jianmo', send=send) == 1: return 1 # Check {shujulujing} if not os.path.exists(shujulujing): onerror(runtime_error.FileError, shujulujing, send=send) return 1 # Try to mkdir and check of [moxinglujingqianzhui] try: mkdir(os.path.dirname(moxinglujingqianzhui)) except: onerror(runtime_error.FileError, moxinglujingqianzhui, send=send) return 1 # Workload moxinglujing = f'{moxinglujingqianzhui}.mat' # todo: Building a model self.latest_jianmo_send = send self.latest_shujulujing = shujulujing self.latest_moxinglujing = moxinglujing try: self.send_backend( dict(cmd='jianmo', moxinglujing=moxinglujing, shujulujing=shujulujing)) except: logger.info('Fail on sending jianmo request to backend.') # If not USE_BACKEND,**************************************** # use response_jianmo if not USE_BACKEND: self.response_jianmo(zhunquelv="1.0", timestamp=0, send=send) logger.debug('Building model.') logger.info('Building model.') return 0
def response_jianmo(self, zhunquelv, timestamp=0, send=send): moxinglujing = self.latest_moxinglujing shujulujing = self.latest_shujulujing self.latest_jianmo_send( dict(mode='Offline', cmd='zhunquelv', moxinglujing=moxinglujing, zhunquelv=zhunquelv, timestamp=time.time())) if not USE_BACKEND: print('-' * 80) print(moxinglujing) with open(moxinglujing, 'w') as f: f.writelines(['Fake model.']) logger.debug( f'Built model based on {shujulujing}, model has been saved in {moxinglujing}.' ) logger.info( f'Built model based on {shujulujing}, model has been saved in {moxinglujing}.' ) pass
def offline_jieshucaiji(self, timestamp=0, send=send): """Stop offline collection Keyword Arguments: timestamp {int} -- [description] (default: {0}) send {func} -- Sending method (default: {send}) Returns: {int} -- 0 means success, 1 means fail """ send(real_time_reply.OK()) # The state should be 'Offline' if self.check_state('Offline', 'offline_jieshucaiji', send=send) == 1: return 1 # workload self.state = 'Idle' # Stop backend try: self.send_backend(dict(cmd='jieshucaiji')) except: logger.info('Fail to stop offline recording in backend.') traceback.print_exc() if not USE_BACKEND: with open(self._shujulujing, 'w') as f: f.writelines(['Fake data.']) logger.debug('Stopped offline collection.') return 0
def send(msg): """ Virtual sending method, used when sending method is not provided. Arguments: msg {object} -- Message to be recorded. """ logger.debug(f'Virtual send {msg}')
def state(self, s): """Safe switch STATE into [s] Arguments: s {str} -- The name of new state, one from ['Idle', 'Busy', 'Online', 'Offline'] """ assert (s in ['Idle', 'Busy', 'Online', 'Offline']) if not s == self._state: self._state = s logger.info(f'State switched to {s}.') logger.debug(f'State switched to {s}.')
def offline_kaishicaiji(self, shujulujingqianzhui, timestamp=0, send=send): """Start offline collection Arguments: shujulujingqianzhui {str} -- The prefix of data path, '.cnt' will be added for real data path Keyword Arguments: timestamp {int} -- [description] (default: {0}) send {func} -- Sending method (default: {send}) Returns: {int} -- 0 for success, 1 for fail """ # Send OK means I has got everything in need, # but not guartee that all the things are correct, # if incorrect, I will reply Error in further send(real_time_reply.OK()) # The state should be 'Idle' self.force_Idle() if self.check_state('Idle', 'offline_kaishicaiji', send=send) == 1: return 1 # Try to mkdir and check of [shujulujingqianzhui] dir try: mkdir(os.path.dirname(shujulujingqianzhui)) except: onerror(runtime_error.FileError, shujulujingqianzhui, send=send) return 1 # Workload self.get_ready(state='Offline') path = f'{shujulujingqianzhui}.mat' if not USE_BACKEND: self._shujulujing = path try: self.send_backend( dict(cmd='kaishicaiji', mat_path=path, model_path='[empty]')) except: logger.info('Fail to start offline recording in backend.') traceback.print_exc() # Start self.record function as separate daemon threading # t = threading.Thread(target=self.record, args=(path,)) # t.setDaemon(True) # t.start() logger.debug('Started offline collection.') return 0
def keepalive(self, timestamp=0, send=send): """Answer keep-alive package Keyword Arguments: timestamp {int} -- [description] (default: {0}) send {func} -- Sending method (default: {send}) Returns: {int} -- 0 means success, 1 means fail """ # Reply keep alive package send(real_time_reply.KeepAlive()) logger.debug(f'Responded to KeepAlive package.') return 0
def deal(self, D): """Deal with incoming message Arguments: D {dict} -- Parsed message dictionary """ # Make sure D is legal, # send ParseError if illegal # D is dict if not isinstance(D, dict): self.send(real_time_reply.ParseError()) logger.error(f'{D} is not dict') return 1 logger.debug(f'Dealing with {D}') # D contains timestamp if 'timestamp' not in D: self.send(real_time_reply.ParseError()) logger.error(f'{D} contains no timestamp') return 1 # Record Delay logger.debug('Delay is {}'.format(delay(D['timestamp']))) # D contains 'mode', ['cmd'], and worker can deal with them # D contains 'mode' if 'mode' not in D: self.send(real_time_reply.ParseError()) logger.error(f'{D} contains no mode') return 1 # Deal with 'cmd' if it exists if 'cmd' in D: workload = '{mode}_{cmd}'.format(**D).lower() else: workload = '{mode}'.format(**D).lower() # Worker can deal with them if not hasattr(worker, workload): self.send(real_time_reply.ParseError()) logger.error(f'{D} triggers no workload') return 1 # Get ride of 'mode' and ['cmd'] D.pop('mode') D.pop('cmd', None) # Operate logger.debug(f'Workload starts {workload}') try: eval(f'worker.{workload}(**D, send=self.send)') return 0 except Exception as e: logger.error(f'Something went wrong in workload {workload}') logger.debug(traceback.format_exc()) self.send(runtime_error.UnknownError(detail=e.__str__())) return 1
def onerror(error, detail, send=send): """ Handle runtime errors, logging and send RuntimeError, normally THIS should be followed by return 1. Arguments: error {RuntimeError func} -- Method for RuntimeError instance detail {object} -- Detail of the error. send {func} -- Send function to be used for Error report. (default: {send}) """ logger.error(detail) # Load [detail] into [error] errormsg = error(detail) # Send [errormsg] send(errormsg) logger.debug(f'Sent RuntimeError: {errormsg}')
def send(self, msg, encoding='utf-8'): """Send [msg] to connected TCP Client Arguments: msg {str} -- [description] """ # Dumps dict if isinstance(msg, dict): msg = json.dumps(msg, ensure_ascii=False).encode(encoding) # Encode str if isinstance(msg, str): msg = msg.encode(encoding) # Send self.client.sendall(msg) logger.info(f'Sent {msg} to {self.address}') logger.debug(f'Sent {msg} to {self.address}')
def mkdir(path): """Recursive (safe) mkdir function, use 1: Create [path], use 2: Check [path] is an already existing dir Arguments: path {str} -- Path to be created, it should be a legal dir path. """ # Mkdir if not exists if not os.path.exists(path): s = os.path.split(path) # Recursive create parent if s[0]: mkdir(s[0]) # Mkdir child os.mkdir(path) logger.debug(f'Created {path}') # Make sure path is a folder assert (os.path.isdir(path))
def force_Idle(self): """Force State to Idle, used for kaishicaiji by-force. """ if self.state == 'Idle': return 0 msg = f'Current state is {self.state}, setting it to Idle by-force.' logger.info(msg) logger.debug(msg) # Stop backend logger.debug('Send jieshucaiji to backend.') try: self.send_backend(dict(cmd='jieshucaiji')) except: logger.info('Fail to stop offline recording in backend.') traceback.print_exc() # workload self.state = 'Idle'
def response_query(self, gujibiaoqian, timestamp=0, send=send): self.latest_query_send( dict(mode='QueryReply', gujibiaoqian=gujibiaoqian, timestamp=time.time())) zhenshibiaoqian = self.latest_zhenshibiaoqian if all([gujibiaoqian == '1', zhenshibiaoqian == '1']): self.send_UI( dict(mode='Online', cmd='kaishiyundong', timestamp=time.time())) self.labels.append((gujibiaoqian, zhenshibiaoqian)) logger.info( f'Estimated label: {gujibiaoqian}, True label: {zhenshibiaoqian}') logger.debug( f'Estimated label: {gujibiaoqian}, True label: {zhenshibiaoqian}') logger.debug(f'Labels is {self.labels}') pass
def online_jieshucaiji(self, timestamp=0, send=send): """Stop online collection Keyword Arguments: timestamp {int} -- [description] (default: {0}) send {func} -- Sending method. (default: {send}) Returns: {int} -- 0 for success, 1 for fail """ send(real_time_reply.OK()) # The state should be 'Online' if self.check_state('Online', 'online_jieshucaiji', send=send) == 1: return 1 # Workload # Stop backend try: self.send_backend(dict(cmd='jieshucaiji')) except: logger.info('Fail to stop offline recording in backend.') traceback.print_exc() if not USE_BACKEND: with open(self._shujulujing, 'w') as f: f.writelines(['Fake online data.']) # Calculate accuracy try: zhunquelv = self.accuracy() logger.debug(f'Accuracy is {zhunquelv}, labels are {self.labels}.') except: logger.debug( f'Accuracy can not be calculated, labels are {self.labels}') raise ValueError( f'Accuracy can not be calculated, labels are {self.labels}') # Send accuracy back to UI as remembered send( dict( mode='Online', cmd='zhunquelv', zhunquelv=str(zhunquelv), # Covert accuracy into {str} moxinglujing=self.moxinglujing, shujulujing=self.shujulujing, timestamp=time.time())) self.state = 'Idle' logger.debug('Stopped online collection.') return 0
def listening(self): """ Listen and handling incoming message """ while True: try: # Get data data = self.client.recv(BUF_SIZE) logger.info(f'Received {data}, from {self.address}') logger.debug( '{dash} New data received {dash}'.format(dash='-' * 8)) logger.debug(f'Received {data}, from {self.address}') # If empty package received, it means the client to be closed. assert (not data == b'') # Parse data using JSON format, # Decode data try: decoded_data = data.decode('utf-8') except: logger.info(f'{data} can not be decoded.') logger.debug(f'{data} can not be decoded.') continue # send ParseError if parsing is failed try: D = json.loads(decoded_data) except: logger.debug( f'{decoded_data} can not be loaded by JSON, try linked expection.' ) try: split = decoded_data.split('}{') D = list() for s in split: if not s.startswith('{'): s = '{' + s if not s.endswith('}'): s = s + '}' D.append(json.loads(s)) logger.debug(f'Link exception success: {D}.') except: logger.error( f'{decoded_data} can not be loaded by JSON') logger.error('{}'.format(traceback.format_exc())) self.send( real_time_reply.ParseError(detail=decoded_data)) continue # print(D) # Deal with D if isinstance(D, list): for d in D: self.deal(d) else: self.deal(D) except Exception: traceback.print_exc() logger.debug(traceback.format_exc()) # Close the client self.client.close() # Stop listening break # Run onclose function self.onclose() logger.info(f'Connection closed {self.client}.')
def online_kaishicaiji(self, moxinglujing, shujulujingqianzhui, timestamp=0, send=send): """Start Online collection Arguments: moxinglujing {str} -- The path of model, it should be an existing path shujulujingqianzhui {str} -- The prefix of data path, '.cnt' will be added in real data path Keyword Arguments: timestamp {int} -- [description] (default: {0}) send {func} -- Sending method (default: {send}) Returns: {int} -- 0 for success, 1 for fail """ send(real_time_reply.OK()) # Check moxinglujing if not os.path.exists(os.path.dirname(moxinglujing)): onerror(runtime_error.FileError, moxinglujing, send=send) return 1 # Try to mkdir and check of {shujulujingqianzhui} try: mkdir(os.path.dirname(shujulujingqianzhui)) except: onerror(runtime_error.FileError, shujulujingqianzhui, send=send) return 1 # The state should be 'Idle' self.force_Idle() if self.check_state('Idle', 'online_kaishicaiji', send=send) == 1: return 1 # Workload path = f'{shujulujingqianzhui}.mat' if not USE_BACKEND: self._shujulujing = path # Remember Send-to-UI method, # as Start online collection can only be triggered by UI. self.get_ready(state='Online', moxinglujing=moxinglujing, shujulujing=path, send_UI=send) try: self.send_backend( dict(cmd='kaishicaiji', mat_path=path, model_path=moxinglujing)) except: logger.info('Fail to start online recording in backend.') traceback.print_exc() # Start daemon thread for data collection and start it # t = threading.Thread(target=self.record, args=(path, moxinglujing)) # t.setDaemon(True) # t.start() logger.debug('Started online collection.') return 0