def __init__(self): self.pybird = PyBird() self.prev_md5s = LRU_cache( maxlen=5 ) # store previous configs like: {'md5_key': bird_cfg_string } self._config_fragments = {'md5': None, 'frags': []} self.bird_methods = { 'get_config': { 'method_ptr': self.get_config, 'is_command': False }, 'set_config': { 'method_ptr': self.set_config, 'is_command': True }, 'get_protocols_info': { 'method_ptr': self.get_protocols_info, 'is_command': False } } try: current_cfg = self.pybird.get_config().encode('utf-8') self._current_md5 = hashlib.md5(current_cfg).hexdigest() self.prev_md5s[self._current_md5] = current_cfg except Exception as e: print( "Error occurred while reading from bird current cfg in the first time: %s" % e) self._current_md5 = -1 # signify no md5 loaded
class BirdWrapper: def __init__(self): self.pybird = PyBird() self.prev_md5s = LRU_cache(maxlen=5) # store previous configs like: {'md5_key': bird_cfg_string } self._config_fragments = {'md5': None, 'frags': []} self.bird_methods = { 'connect': {'method_ptr': self.connect, 'is_command': False}, 'get_config': {'method_ptr': self.get_config, 'is_command': False}, 'set_config': {'method_ptr': self.set_config, 'is_command': True}, 'set_empty_config': {'method_ptr': self.set_empty_config, 'is_command': True}, 'get_protocols_info': {'method_ptr': self.get_protocols_info, 'is_command': False}, 'disconnect': {'method_ptr': self.disconnect, 'is_command': False}, } try: current_cfg = self.pybird.get_config().encode('utf-8') self._current_md5 = hashlib.md5(current_cfg).hexdigest() self.prev_md5s[self._current_md5] = current_cfg except Exception as e: print("Error occurred while reading from bird current cfg in the first time: %s" % e) self._current_md5 = -1 # signify no md5 loaded def __del__(self): self.logger.info('***IN BIRD WRAPPER DTOR***') self.execute('disconnect', []) def parse_req_msg(self, JSON_req): try: req = json.loads(JSON_req) req_id = 'null' if (type(req) != type({})): raise ParseException("Expected dictionary got: '%s' " % type(req)) json_rpc_keys = {'jsonrpc', 'id', 'method'} if set(req.keys()) != json_rpc_keys and set(req.keys()) != json_rpc_keys.union({'params'}): if 'id' in req.keys(): req_id = req['id'] raise InvalidRequest(req_id) req_id = req['id'] if 'params' in req.keys(): return req['method'], req['params'], req_id else: return req['method'], [], req_id except ValueError: raise ParseException(req_id) def connect(self, params): return self.pybird.connect() def disconnect(self, params): return self.pybird.disconnect() def get_config(self, params): return self.pybird.get_config() def get_protocols_info(self, params): return self.pybird.get_protocols_info() def set_config(self ,params): first, last = params.get('frag_first'), params.get('frag_last') fragment = params['fragment'] md5 = params.get('md5') self._config_fragments['frags'].append(fragment) if first and last: return self._set_new_config(fragment) elif first: self._config_fragments['md5'] = md5 elif last: all_cfg = ''.join(self._config_fragments['frags']) md5 = self._config_fragments['md5'] return self._set_new_config(all_cfg, md5) return 'send_another_frag' # middle fragment def set_empty_config(self, params): # In set_empty_config, we don't need to compare cache since # we are not uploading any long configuration file (unlike in set_config), # rather this is just an RPC call. # However, this changes the configuration, and as such self._current_md5 needs to be cleared. self._current_md5 = None return self.pybird.set_empty_config() def _set_new_config(self, config, md5=None): if md5 is None: if type(config) is str: config = config.encode('utf-8') md5 = hashlib.md5(config).hexdigest() self._config_fragments['frags'] = [] # reset fragments config self._config_fragments['md5'] = None cached = self._is_md5_cached(md5) if 'Already configured' in cached: return cached elif 'Found configuration in cache' in cached: self._current_md5 = md5 return cached + self.pybird.set_config(self.prev_md5s[md5]) else: res = self.pybird.set_config(config) # return a string if 'Configured successfully' in res: self._current_md5 = md5 self.prev_md5s[md5] = config # new md5, cache it return res def _is_md5_cached(self, md5): if md5 == self._current_md5: return 'Already configured' if md5 in self.prev_md5s.keys(): return 'Found configuration in cache. ' return '' def create_error_response(self, error_code, error_msg, req_id): return {"jsonrpc": "2.0", "error": {"code": error_code, "message": error_msg}, "id": req_id} def create_success_response(self, result, req_id): return {"jsonrpc": "2.0", "result": result, "id": req_id} def get_exception(self): return sys.exc_info() def has_method(self, method): return method in self.bird_methods.keys() def execute(self, method, params): return self.bird_methods[method]['method_ptr'](params) def is_command_method(self, method): return self.bird_methods[method]['is_command'] def error_handler(self, e, req_id): response = {"jsonrpc": "2.0", "error": {"code": -32097, "message": str(e)}, "id": req_id} try: raise e except ParseException as e: response = self.create_error_response(-32700, 'Parse error ', req_id) except InvalidRequest as e: response = self.create_error_response( -32600, 'Invalid Request', req_id) except MethodNotFound as e: response = self.create_error_response( -32601, 'Method not found', req_id) except InvalidParams as e: response = self.create_error_response( -32603, 'Invalid params', req_id) except SyntaxError as e: response = self.create_error_response(-32097, 'SyntaxError', req_id) except Exception as e: if hasattr(e, 'strerror'): response = self.create_error_response( -32099, 'Bird Server: '+str(e.strerror), req_id) # TODO maybe other code? elif hasattr(e, 'message'): response = self.create_error_response( -32098, 'Bird Server: '+str(e.message), req_id) elif (is_python(3)): response = self.create_error_response( -32096, 'Bird Server: '+str(e), req_id) else: response = self.create_error_response( -32096, 'Bird Server: Unknown Error', req_id) finally: return response