async def send_request(self, operation, to, data=None, **kwargs): try: msg = OcfRequest( to=to, fr=self.link, op=operation, cn=data, # uri_path=link['href'], # operation=operation, # data=data, # code=kwargs.pop('code', 1), # token=self.coap.token, # mid=self.coap.mid, **kwargs ) coap_msg, remote = msg.encode_to_coap() result = await self.coap.send_request(coap_msg, remote) return result except TimeoutError: raise ExtTimeoutError(action='request', dump=dict(op=operation, to=to, data=data, kwargs=kwargs)) from None except ExtException as err: raise ExtException(parent=err, action='{}.request()'.format(self.__class__.__name__), dump=dict(op=operation, to=to, data=data, kwargs=kwargs)) from None except Exception as err: raise ExtException(parent=err, action='{}.request()'.format(self.__class__.__name__), dump=dict(op=operation, to=to, data=data, kwargs=kwargs)) from None
async def observe(self, to, callback=None): try: token = self.coap.token msg = OcfRequest( to=to, fr=self.link, op='retrieve', token=token, mid=self.coap.mid, obs=1 if callback is None else 0 ) coap_msg, remote = msg.encode_to_coap() await self.coap.send_multi_answer_request(coap_msg, remote, callback) if callback is None: del self.coap.answer[token] except TimeoutError as e: raise ExtTimeoutError(action='request', dump=dict(op='observe', to=to)) from None except ExtException as e: raise ExtException(parent=e, action='{}.request()'.format(self.__class__.__name__), dump=dict(op='observe', to=to)) from None except Exception as e: raise ExtException(parent=e, action='{}.request()'.format(self.__class__.__name__), dump=dict(op='observe', to=to)) from None
def load_from_file(cls, file_name, **kwargs): try: self = cls(**kwargs) _path = None for _dir in self.dir: _path = '{0}/{1}'.format(_dir, file_name) if os.path.isfile(_path): break else: _path = None if _path is None: raise ExtException(message='Json schema file not found', detail=file_name) with open(_path, 'r', encoding='utf-8') as file: try: raw = json.load(file) except Exception as err: raise ExtException(message='JsonSchema not load from file', detail=f'{file_name} {str(err)}') from err self.load(raw) return self.cache[self.id]['data'] except Exception as err: raise ExtException( action='JsonSchemaLoaderMixin.load_from_file', dump={'file_name': file_name}, parent=err) from err
def get_resource_by_uri(cls, resources, uri): link = ResourceLink.init_from_uri(uri) if not link.di: raise ExtException(message='bad schema id, need ocf') try: return resources[link.di].links[link.href] except KeyError: raise ExtException(message='resource not found', detail=uri)
async def execute_in_queue(self, queue, task, name=''): try: self.log.debug('execute_in_queue {}'.format(name)) result = asyncio.Future() queue.put_nowait((task, result)) return await result except ExtException as e: raise ExtException(parent=e) from None except Exception as e: raise ExtException(parent=e, action='QueueMixin.execute_in_queue')
def test_raise_from_other_ext_exception(self): try: try: err1 = ExtException(message='msg1', action='action1') raise err1 except ExtException as err: err2 = ExtException(message='msg2', action='action2', parent=err) raise err2 except ExtException as err: err3 = ExtException(action='action3', parent=err) self.assertEqual(2, len(err3.stack)) self.assertEqual('msg1', err3.stack[0]['message']) self.assertEqual('msg2', err3.message) print(err3)
def init_from_file(cls, **kwargs): kwargs['path'] = os.path.abspath(kwargs.get('path', './')) kwargs['log'] = kwargs['log'] if kwargs.get('log') else logging.getLogger() class_name = kwargs.get('class_name', cls.__name__) di = kwargs.get('di') config = {} if di is None: di = cls.find_first_config('{}'.format(kwargs['path']), class_name) if di: config_path = path.normpath('{0}/{1}.{2}.json'.format(kwargs['path'], class_name, di)) try: with open(config_path, encoding='utf-8') as file: config = json.load(file) kwargs['log'].info('OcfDevice.init_from_file {0}.{1}'.format(class_name, di)) except FileNotFoundError: kwargs['log'].warning('OcfDevice config not found {0}'.format(config_path)) except Exception as e: raise ExtException( 7004, detail='{0} {1}'.format(str(e), config_path), action='OcfDevice.init_from_config', dump=dict( class_name=class_name, di=di, ) ) kwargs['class_name'] = class_name kwargs['di'] = di return cls.init_from_config(config, **kwargs)
def init(self, config=None, **kwargs): try: cache = kwargs.get('cache', self.cache) _config = self.get_default_config(self.__class__, Device, cache) if config: Helper.update_dict(_config, config) self.resource_layer.init_from_config(_config) if not self.get_param('/oic/d', 'piid', None): self.set_param('/oic/d', 'piid', str(uuid4()), save_config=kwargs.get('save_config', True)) di = self.get_device_id() if not self.get_device_id(): di = kwargs.get('di') self.set_device_id(di) self.change_provisioning_state() self.log = logging.getLogger('{0}:{1}'.format(self.__class__.__name__, self.get_device_id()[-5:])) self.log.setLevel(getattr(logging, self.get_param('/oic/con', 'logLevel', 'error').upper())) return self except Exception as e: raise ExtException( message='Bad driver config', detail=self.__class__.__name__, action='OcfDevice.init_from_config', dump=dict( config=config, kwargs=kwargs ) ) from e
async def call_handler(self, task): _action = Action(name='request_handler') try: res = _action.add_stat(await task) _action.set_end() await self.ws.send_json({ "type": "success", "uid": self.uid, "data": res, "stat": _action.stat }) except CancelOperation: await self.ws.send_json({ "type": "cancel", "uid": self.uid, }) except ExtException as err: await self.ws.send_json({ "type": "error", "uid": self.uid, "data": err.to_dict() }) except Exception as err: await self.ws.send_json({ "type": "error", "uid": self.uid, "data": ExtException(parent=err).to_dict() }) finally: try: del self.device.ws[self.ws_uid]['task'][ self.uid] # удаляем task except KeyError: pass
async def add_auth(self, data, **kwargs): action = kwargs['_action'] session = kwargs.get('session', {}) user_id = session.get('user') res = action.add_stat(await self.query(filter={ 'auth.type': data['type'], 'auth.id': data['id'] }, projection={ '_id': 1, 'auth': 1 }, limit=1)) if res: raise ExtException( message='Такой пользователь уже зарегистрирован') if user_id: try: action.add_stat(await self.find_by_id(user_id, projection={ '_id': 1, 'auth': 1 })) action.add_stat(await self.push('auth', data)) except KeyError: session['user'] = None else: self.data = {'title': data['id'], 'auth': [data]} res = action.add_stat(await self.update())
async def call_handler(self, msg): try: device, obj_name, action = msg.name.split('/') except ValueError: raise ExtException(action='call_handler', message='Bad format message', detail=msg.name) try: task = await msg.prepare(self.request, device, obj_name, action, 'api', Response) self.device.ws[self.ws_uid]['task'][msg.uid] = asyncio.create_task( msg.call_handler(task)) except ExtException as err: raise ExtException(action='call_handler', parent=err) except Exception as err: raise ExtException(action='call_handler', parent=err)
async def create_from_request(cls, user, view, **kwargs): action = kwargs['_action'] try: old_session = action.add_stat(await cls.init_from_request(view)) if not old_session.data['end']: if user.get_link()['_ref'] == old_session.data['user']['_ref']: return old_session action.add_stat(await old_session.close()) except ExtException as err: if err.code == 9010 or err.code == 9011: # нет сессии или идентификатор не ObjectId pass else: raise ExtException(parent=err) self = cls(view.storage) self.data = { "user": user.get_link(), "account": user.get_default_account(), "date": datetime.now(), "end": None } action.add_stat(await self.update()) _session = await new_session(view.request) identity = self.get_identity() _session.set_new_identity(identity) _session['user'] = self.data['user'] _session['account'] = self.data['account'] _session['_id'] = identity return self
async def cancel_handler(self, msg): try: task = self.device.ws[self.ws_uid]['task'][msg.uid] task.cancel() except KeyError: raise ExtException(action='cancel_handler', message='Task not found', detail=msg.name)
def test_raise_from_with_action(self): res = Action('action1') res2 = Action('action2') res2.add_stat(Action('action3').set_end()) try: try: err1 = ExtException(message='msg1', action=res2) raise err1 except ExtException as err: err2 = ExtException(message='msg2', action=res, parent=err) raise err2 except ExtException as err: err3 = ExtException(action='action3', parent=err) self.assertEqual(2, len(err3.stack)) self.assertEqual('msg1', err3.stack[0]['message']) self.assertEqual('msg2', err3.message) print(err3)
async def main(self): try: self.log.info("begin main") # self.coap = CoapServer(self) await self.transport_layer.start() update_time = self.get_param('/oic/con', 'updateTime', 30) await asyncio.sleep(random.random()) while True: last_run = time.time() self.set_param('/oic/mnt', 'lastRun', last_run) status = self.get_param('/oic/mnt', 'currentMachineState', 'pending') method = f'on_{status}' try: await getattr(self, method)() await asyncio.sleep(0.01) except asyncio.CancelledError: if self.get_param('/oic/mnt', 'currentMachineState', 'pending'): self.set_param('/oic/mnt', 'currentMachineState', 'cancelled') else: self.log.info("cancelled main") return # raise asyncio.CancelledError except ExtException as err: self.log.error(ExtException(detail=method, parent=err)) self.set_param('/oic/mnt', 'currentMachineState', 'stopped') self.set_param('/oic/mnt', 'message', str(err)) pass except Exception as err: self.log.error(ExtException(detail=method, parent=err)) self.set_param('/oic/mnt', 'currentMachineState', 'stopped') self.set_param('/oic/mnt', 'message', str(err)) pass await self.check_changes() elapsed_time = time.time() - last_run sleep_time = max(0.01, max(update_time - elapsed_time, 0)) await asyncio.sleep(sleep_time) except ExtException as err: self.log.error(f"end main {err}") raise pass
async def send_message(self, operation, to, data=None, *, secure=False, multicast=False, query=None, **kwargs): try: request = self._prepare_request(operation, to, data=data, secure=secure, multicast=multicast, query=query, **kwargs) response = await self.coap.send_message(request, **kwargs) return response except TimeoutError: raise ExtTimeoutError(action='request', dump=dict(op=operation, to=to, data=data, kwargs=kwargs)) from None except ExtException as err: raise ExtException(parent=err, action='{}.request()'.format( self.__class__.__name__), dump=dict(op=operation, to=to, data=data, kwargs=kwargs)) from None except Exception as err: raise ExtException(parent=err, action='{}.request()'.format( self.__class__.__name__), dump=dict(op=operation, to=to, data=data, kwargs=kwargs)) from err
def load_elem(self, data, value, name): try: value_type = value.__class__.__name__ getattr(self, f'load_elem_{value_type}')( data, value, name) except Exception as err: raise ExtException( action='JsonSchemaLoaderMixin.load_elem', dump={'elem_name': name}, parent=err) from err pass
async def prepare(self, request, device, obj_name, action, prefix, response_class): try: api_class = self.get_api_class(device, obj_name) except Exception as err: raise ExtException(message='Bad API handler', detail=f'{device}/{obj_name}', parent=err) try: api_class = api_class(response_class) except Exception as err: raise ExtException( message='Unknown error while initializing API handler', detail=f'{device}/{obj_name}', parent=err ) api_action = f'{prefix}_{action}' self.session = await get_session(request) self.session['last_visit'] = time.time() try: task = getattr(api_class, api_action) except Exception as err: raise ExtException(message='API handler not found', detail=f'{device}/{obj_name}/{action}') return task(self)
async def on_pending(self): links = self.get_param('/oic/con', 'running_devices') if links: for link in links: try: device = await self.action_run_device(link) if device: link['n'] = device.get_device_name() except Exception as err: raise ExtException(message='Not run device', detail=f'{link.get("n")} - {str(err)}', parent=err) await super().on_pending() self.save_config()
async def request_handler(self, prefix, **kwargs): _action = Action(name=f'{self.__class__.__name__}.request_handler') device = self.request.match_info.get('device') obj_name = self.request.match_info.get('obj_name') action = self.request.match_info.get('action') try: task = await self.prepare(self.request, device, obj_name, action, prefix, Response) response = _action.add_stat(await task) _action.set_end() response.headers['stat'] = dumps(_action.stat, ensure_ascii=True) return response except ExtException as err: return Response.json_response(ExtException( action=_action.name, dump={ "device": device, "obj_name": obj_name, "action": action }, parent=err).to_dict(), status=err.http_code) except Exception as err: return Response.json_response(ExtException(action=_action.name, parent=err).to_dict(), status=500)
async def queue_worker(self, queue, name=''): self.log.debug('start queue_worker "{}"'.format(name)) while True: (future, result) = await queue.get() try: _result = await future if result and asyncio.isfuture(result): result.set_result(_result) except ExtException as e: result.set_exception(e) except Exception as e: result.set_exception( ExtException(parent=e, action='queue_worker')) finally: queue.task_done()
def set_param(self, resource, name, new_value, **kwargs): try: old_value = self.get_param(resource, name, None) difference, changes = Helper.compare(old_value, new_value) if difference: self._resource_changed[resource] = True self.data[resource][name] = new_value if kwargs.get('save_config', False): self.save_config() except Exception as e: raise ExtException(detail=str(e), dump=dict(resource=resource, name=name, value=new_value))
async def notify(self, href, data): # send notify response to observer listening = self.get_param('/oic/con', 'listening') if not listening: return to = ResourceLink.init_from_link(self.link) to.href = href for elem in listening: if elem['href'] != href: continue try: self.log.debug('notify {0} {1}'.format(self.get_device_id(), href)) msg = OcfResponse.generate_answer( data, OcfRequest(to=to, fr=ResourceLink.init_from_link( dict(di=elem['di'], ep=elem['ep'])), op='retrieve', token=elem['token'], mid=self.coap.mid, obs=0)) await self.coap.send_answer(msg) except TimeoutError as e: raise Exception(9001, action='notify', dump=dict(op='observe', to=to)) from None except ExtException as e: raise ExtException(parent=e, action='{}.notify()'.format( self.__class__.__name__), dump=dict(op='observe', to=to)) from None except Exception as e: raise ExtException(parent=e, action='{}.notify()'.format( self.__class__.__name__), dump=dict(op='observe', to=to)) from None
async def execute(self, data): try: if self.need_change_serial(data): await self.set_serial_configuration(data) self.log.debug(data) message = OcfMessageRequest(**data) response = await self.modbus.execute(message, None) # self.log.debug('execute({0})={1}'.format(data, response)) return response.b64decode() except KeyError as err: self.log.error(f'Не указан обязательный параметр {err}') raise KeyNotFound(detail=str(err), action='ModbusMaster.execute') except asyncio.TimeoutError as err: self.log.error('ExtTimeoutError') raise ExtTimeoutError(action='ModbusMaster.execute') from err except Exception as err: self.log.error(err) raise ExtException(parent=err, action='ModbusMaster.execute')
def to_object_data(self): res = [] for href in self.links: data = self.links[href].data if 'rt' not in data or 'if' not in data: raise ExtException(message='bad resource', detail=f'{href} - rt or if not defined') res.append({ 'href': href, 'rt': self.links[href].data['rt'], 'if': self.links[href].data['if'], 'n': self.links[href].name }) return { '_id': self.di, 'n': self.name, 'ep': self.eps[0]['ep'] if self.eps else None, 'res': res }
def init_from_config(cls, config=None, **kwargs): class_name = cls.__name__ try: if config: class_name = config['/oic/d']['dmno'] except KeyError: pass class_name = kwargs.get('class_name', class_name) try: _handler = cls.get_device_class(class_name) self: Type[tDevice] = _handler(**kwargs) except Exception as err: raise ExtException( message='Bad driver', detail=class_name, action='OcfDevice.init_from_config', parent=err, dump=dict( config=config, kwargs=kwargs ) ) return self.init(config, **kwargs)
def load(self, schema): try: self.version = urllib.parse.urlparse(schema['$schema'])[2].split('/')[0] self.id = self.get_id_from_uri(urllib.parse.urlparse(schema['id'])) self.cache[self.id] = dict(data=dict(), definitions=dict()) if 'definitions' in schema: for tmpl in schema['definitions']: self.cache[self.id]['definitions'][tmpl] = dict() for props in schema['definitions'][tmpl]: _type = schema['definitions'][tmpl][props].__class__.__name__ self.load_elem( self.cache[self.id]['definitions'][tmpl], schema['definitions'][tmpl][props], props ) for elem in schema: if elem != 'definitions': self.load_elem(self.cache[self.id]['data'], schema[elem], elem) pass except Exception as err: raise ExtException( action='JsonSchemaLoaderMixin.load', parent=err) from err
def load_from_uri(self, uri, **kwargs): try: uri = urllib.parse.urlparse(uri) # (scheme, netloc, path, params, query, fragment) _id = self.get_id_from_uri(uri, self.id) if _id not in self.cache: JsonSchema4.load_from_file(_id, dir=self.dir, cache=self.cache) if not uri[5]: try: return self.cache[_id]['data'] except KeyError: raise Exception('bad schema id or definition in {}'.format(_id)) _fragment = uri[5].split('/')[1:] _result = self.cache[_id] for elem in _fragment: _result = _result[elem] return _result except Exception as err: raise ExtException( action='JsonSchemaLoaderMixin.load_from_uri', dump={'uri': uri}, parent=err) from err
async def discovery_unowned_devices(self, **kwargs): try: token = self.coap.token result = {} msg = OcfRequest( to=dict(href='/oic/res'), fr=self.link, op='retrieve', token=token, mid=self.coap.mid, multicast=True, **kwargs ) coap_msg, remote = msg.encode_to_coap() if self.coap.ipv6: await self.coap.send_multi_answer_request( coap_msg, (self.coap.coap_discovery_ipv6[0], self.coap.multicast_port), self.on_response_oic_res, result ) if self.coap.ipv4: await self.coap.send_multi_answer_request( coap_msg, (self.coap.coap_discovery_ipv4[0], self.coap.multicast_port), self.on_response_oic_res, result ) await asyncio.sleep(2) result = self.coap.answer[token]['result'] # del (self.coap.answer[token]) return result except ExtException as e: raise Exception(e) except Exception as e: raise ExtException(e)
async def start_coap(self): try: for href in self.device.res: self.coap.root[href] = self.device.res[href] # self.coap.add_resource(href, self.device.res[href]) # pass self.ipv6 = self.device.get_param('/oic/con', 'udpCoapIPv6', '::') self.ipv4 = self.device.get_param('/oic/con', 'udpCoapIPv4', '') self.ipv6ssl = self.device.get_param('/oic/con', 'udpCoapIPv6Ssl', True) self.ipv4ssl = self.device.get_param('/oic/con', 'udpCoapIPv4Ssl', True) certfile = f'{self.device.path}/bubot_cert.pem' keyfile = f'{self.device.path}/bubot_key.pem' unicast_port = self.device.get_param('/oic/con', 'udpCoapPort', None) unicast_ssl_port = self.device.get_param('/oic/con', 'udpCoapSslPort', None) if self.ipv4 is not None: res = await self.coap.add_endpoint( f'coap://{self.ipv4}:{unicast_port}', multicast=True, multicast_addresses=self.coap_discovery[AF_INET], multicast_port=self.coap_discovery_port) if not unicast_port: unicast_port = res[0].address[1] self.device.set_param('/oic/con', 'udpCoapPort', unicast_port) pass if self.ipv4ssl: res = await self.coap.add_endpoint( f'coaps://{self.ipv4}:{unicast_ssl_port}', multicast=False, multicast_addresses=self.coap_discovery[AF_INET], multicast_port=self.coap_discovery_port, keyfile=keyfile, certfile=certfile, socket_props=dict(identity_hint=UUID( self.device.get_device_id()).bytes, psk=None, ciphers=None)) if not unicast_ssl_port: unicast_ssl_port = res[0].address[1] self.device.set_param('/oic/con', 'udpCoapSslPort', unicast_ssl_port) if self.ipv6 is not None: res = await self.coap.add_endpoint( f'coap://[{self.ipv6}]:{unicast_port}', multicast=True, multicast_addresses=self.coap_discovery[AF_INET6], multicast_port=self.coap_discovery_port) if not unicast_port: unicast_port = res[0].address[1] self.device.set_param('/oic/con', 'udpCoapPort', unicast_port) if self.ipv6ssl: res = await self.coap.add_endpoint( f'coaps://[::]:{unicast_ssl_port}', multicast=False, multicast_addresses=self.coap_discovery[AF_INET6], multicast_port=self.coap_discovery_port, keyfile=keyfile, certfile=certfile) if not unicast_ssl_port: unicast_ssl_port = res[0].address[1] self.device.set_param('/oic/con', 'udpCoapSslPort', unicast_ssl_port) except Exception as err: raise ExtException(action='start_coap', dump={ 'device_id': self.device.get_device_id(), 'device': self.device.__class__.__name__ }, parent=err)