class WebSocketFactory(ClientFactory): """ Implements device factory over websocket protocol. """ implements(IWebSocketProtocolCallback, IProtoFactory) url = 'localhost' host = 'localhost' port = 80 proto = None handler = None callbacks = dict() def __init__(self, handler): """ @type handler: C{object} @param handler: handler has to implement C{IProtoHandler} interface """ self.handler = handler if IProtoHandler.implementedBy(self.handler.__class__) : self.handler.factory = self else : raise TypeError('handler should implements IProtoHandler interface') self.devices = {} def buildProtocol(self, addr): self.proto = WebSocketDeviceHiveProtocol(self, '/device') if not IWebSocketMessanger.implementedBy(self.proto.__class__) : raise TypeError('Protocol has to implement IWebSocketMessanger interface.') return self.proto def clientConnectionFailed(self, connector, reason): """ TODO: rename on_connection_failed method """ LOG_ERR('Failed to connect to {0}, host: {1}, port: {2}. Reason: {3}.'.format(self.url, self.host, self.port, reason)) self.handler.on_connection_failed(reason) def clientConnectionLost(self, connector, reason): """ TODO: notify handler about disconnection. """ pass def send_message(self, message): return self.proto.send_message(message) # begin IWebSocketProtocolCallback implementation def failure(self, reason, connector): LOG_ERR('Critial error. Reason: {0}.'.format(reason)) self.handler.on_failure(None, reason) def connected(self): self.handler.on_connected() def closing_connection(self): self.handler.on_closing_connection() def frame_received(self, message): if ('action' in message) and (message['action'] == 'command/insert') : if not 'deviceGuid' in message : LOG_ERR('Malformed command/insert message {0}.'.format(message)) else : device_id = str(message['deviceGuid']).lower() if ('deviceGuid' in message) and (message['deviceGuid'] is not None) else None if device_id in self.devices : self.on_command_insert(WsCommand.create(message), self.devices[device_id]) else : LOG_ERR('Unable to process command {0}. Device {1} is not registered.'.format(message, device_id)) # End of IWebSocketProtocolCallback interface implementation def on_command_insert(self, cmd, info): """ @type cmd: C{object} @param cmd: object which implements C{ICommand} @type info: C{object} @param info: C{IDeviceInfo} object which is receiving the command """ LOG_MSG('Command {0} has been received for device {1}.'.format(cmd, info)) def on_ok(result): LOG_MSG('The command "{0}" successfully processed. Result: {1}.'.format(cmd, result)) if isinstance(result, CommandResult) : cmd.status = result.status cmd.result = result.result else : cmd.status = 'Success' cmd.result = result self.update_command(cmd, device_id = info.id, device_key = info.key) # def on_err(reason): LOG_ERR('Failed to process command "{0}". Reason: {1}.'.format(cmd, reason)) if isinstance(reason, Exception) : cmd.status = 'Failed' cmd.result = reason.message elif hasattr(reason, 'value') : if isinstance(reason.value, CommandResult) : cmd.status = reason.value.status cmd.result = reason.value.result elif isinstance(reason.value, Exception) : cmd.status = 'Failed' cmd.result = reason.value.message else : cmd.status = 'Failed' cmd.result = reason.value else : cmd.status = 'Failed' cmd.result = 'Unhandled Exception' self.update_command(cmd, device_id = info.id, device_key = info.key) # finished = Deferred() finished.addCallbacks(on_ok, on_err) try : self.handler.on_command(info.id, cmd, finished) except Exception as ex: err = DhError('Failed to invoke command {0}. Reason: {1}.'.format(cmd, ex.message)) LOG_ERR(err.message) on_err(err) def update_command(self, command, device_id = None, device_key = None): if not ICommand.implementedBy(command.__class__) : raise DhError('{0}.update_command expects ICommand'.format(self.__class__.__name__)) request = {'action': 'command/update', 'commandId': command.id, 'command': command.to_dict()} if device_id is not None : request['deviceId'] = device_id if device_key is not None : request['deviceKey'] = device_key return self.send_message(request) # begin IProtoFactory implementation def authenticate(self, device_id, device_key): request = {'action': 'authenticate', 'deviceId': device_id, 'deviceKey': device_key} return self.send_message(request) def notify(self, notification, params, device_id = None, device_key = None): request = {'action': 'notification/insert', 'notification': {'notification': notification, 'parameters': params}} if (device_id is not None) : request['deviceId'] = device_id if (device_key is not None) : request['deviceKey'] = device_key return self.send_message(request) def subscribe(self, device_id = None, device_key = None): LOG_MSG('Subscribe device {0}.'.format(device_id)) request = {'action': 'command/subscribe'} if device_id is not None : request['deviceId'] = device_id if device_key is not None : request['deviceKey'] = device_key return self.send_message(request) def unsubscribe(self, device_id = None, device_key = None): request = {'action': 'command/unsubscribe'} if device_id is not None : request['deviceId'] = device_id if device_key is not None : request['deviceKey'] = device_key return self.send_message(request) def device_save(self, info): LOG_MSG('device_save {0}'.format(info)) if not IDeviceInfo.implementedBy(info.__class__) : raise WebSocketError('info parameter has to implement IDeviceInfo interface') dev = {'key': info.key, 'name': info.name, 'equipment': [e.to_dict() for e in info.equipment]} if info.status is not None : dev['status'] = info.status if info.network is not None : dev['network'] = info.network.to_dict() if INetwork.implementedBy(info.network.__class__) else info.network if info.device_class is not None : dev['deviceClass'] = info.device_class.to_dict() if IDeviceClass.implementedBy(info.device_class.__class__) else info.device_class request = {'action': 'device/save', 'deviceId': info.id, 'deviceKey': info.key, 'device': dev} def on_ok(result): key = str(info.id).lower() self.devices[key] = info return self.send_message(request).addCallback(on_ok) def connect(self, url): reactor.connectDeviceHive(url, self)
class WebSocketFactory(ClientFactory): """ Implements client factory over websocket protocol. See devicehive.interfaces.IClientTransport for methods description. """ implements(IClientTransport, IWebSocketProtocolCallback) url = 'ws://localhost' proto = None def __init__(self, handler): if not IClientApp.implementedBy(handler.__class__) : raise TypeError('handler must implement devicehive.interfaces.IClientApp interface.') self.handler = handler self.handler.factory = self self.command_callbacks = {} def get_client_url(self): if not self.url: return '/client' else: path = urlparse(self.url).path if path[-1:] != '/': path += '/' return urljoin(path, 'client') def buildProtocol(self, addr): self.proto = WebSocketDeviceHiveProtocol(self, self.get_client_url()) return self.proto def clientConnectionFailed(self, connector, reason): LOG_ERR('Client connection failed. Reason: {0}.'.format(reason)) self.handler.failure(reason) def clientConnectionLost(self, connector, reason): pass # IClientTransport interface implementation def authenticate(self, login, password): LOG_MSG('Authenticating the client library.') defer = Deferred() def on_ok(res): if res.get('status', 'error') == 'success' : LOG_MSG('Client library has been authenticated.') defer.callback(res) else : LOG_ERR('Client failed authenticate. Reason: {0}.'.format(res.get('error', 'unknown'))) defer.errback(res) def on_err(reason): LOG_ERR('Failed to send authentication message. Reason: {0}.'.format(reason)) defer.errback(reason) self.proto.send_message({'action': 'authenticate', 'requestId': None, 'login': login, 'password': password}).addCallbacks(on_ok, on_err) return defer def subscribe(self, device_ids): if not (isinstance(device_ids, list) or isinstance(device_ids, tuple)) : raise TypeError('device_ids should be a list or a tuple') LOG_MSG('About to subscribe to notifications for {0} devices.'.format(device_ids)) defer = Deferred() def on_ok(res): if res.get('status', 'error') == 'success' : LOG_MSG('Subscribed.') defer.callback(res) else : LOG_ERR('Failed to subscribe to device(s) notifications. Reason: {0}.'.format(res.get('error', 'unknown'))) defer.errback(res) def on_err(reason): LOG_ERR('Failed to send subscribe command. Reason: {0}.'.format(reason)) defer.errback(reason) return self.proto.send_message({'action': 'notification/subscribe', 'requestId': None, 'deviceGuids': device_ids}).addCallbacks(on_ok, on_err) def unsubscribe(self, device_ids): if not (isinstance(device_ids, list) or isinstance(device_ids, tuple)) : raise TypeError('device_ids should be a list or a tuple') LOG_MSG('Unsubscibing from devices {0}.'.format(device_ids)) defer = Deferred() def on_ok(res): if res.get('status', 'error') == 'success' : LOG_MSG('Unsubscribed from device(s) notifications.') defer.callback(res) else : LOG_ERR('Failed to unsubscribe from device(s) notifications. Reason: {0}.'.format(res.get('error', 'unknown'))) defer.errback(res) def on_err(reason): LOG_ERR('Failed to send unsubscribe command. Reason: {0}.'.format(reason)) defer.errback(reason) self.proto.send_message({'action': 'notification/unsubscribe', 'requestId': None, 'deviceGuids': device_ids}).addCallbacks(on_ok, on_err) return defer def command(self, device_id, cmd): if not (isinstance(device_id, str) or isinstance(device_id, unicode)) : raise TypeError('device_id should be a str or a unicode value') defer = Deferred() def on_ok(res): if res.get('status', 'error') == 'success' : LOG_MSG('Command successfully sent.') cmdid = res['command']['id'] self.command_callbacks[cmdid] = defer else : LOG_ERR('Failed to send command {0}. Reason: {1}.'.format(cmd, res.get('error', 'unknown'))) defer.errback(res) def on_err(reason): LOG_ERR('Failed to send command {0}. Reason: {1}.'.format(cmd, reason)) defer.errback(reason) self.proto.send_message({'action': 'command/insert', 'requestId': None, 'deviceGuid': device_id, 'command': cmd.to_dict()}).addCallbacks(on_ok, on_err) return defer def do_notification(self, msg): LOG_MSG('Notification {0} has been received.'.format(msg['notification'])) self.handler.do_notification(msg['deviceGuid'], Notification(name = msg['notification']['notification'], parameters = msg['notification']['parameters'])) def do_command_update(self, msg): if not isinstance(msg, dict) : raise TypeError('msg should be dict') cmd = msg.get('command', None) if cmd is not None : cmdid = cmd.get('id', None) if cmdid in self.command_callbacks : LOG_MSG('Command {0} update has been received.'.format(msg)) defer = self.command_callbacks.pop(cmdid) ocmd = WsCommand.create(cmd) if (isinstance(ocmd.status, str) or isinstance(ocmd.status, unicode)) and ocmd.status.lower() == 'success' : defer.callback(ocmd) else : defer.errback(ocmd) else : LOG_ERR('Unattached command/update message {0} has been received.'.format(msg)) else : LOG_ERR('Malformed command response {0} has been received.'.format(msg)) def ping(self): return self.proto.ping() def connect(self, url): LOG_MSG('Connecting to {0} server.'.format(url)) self.url = url reactor.connectDeviceHive(url, self) # end IClientTransport interface implementation # IWebSocketProtocolCallback interface implementation def failure(self, reason, connector): LOG_ERR('WebSocekt client failure. Reason: {0}.'.format(reason)) self.handler.failure(reason) def connected(self): LOG_MSG('Client has connected to websocket server.') self.handler.connected() def closing_connection(self): LOG_MSG('WebSocket server has requested connection closing.') self.handler.closing_connection() def frame_received(self, message): action = message.get('action', '') if action == 'command/update' : self.do_command_update(message) elif action == 'notification/insert' : self.do_notification(message)
class WebSocketFactory(ClientFactory): """ Implements client factory over websocket protocol. See devicehive.interfaces.IClientTransport for methods description. """ implements(IClientTransport, IWebSocketProtocolCallback) url = 'localhost' host = 'localhost' port = 8010 proto = None def __init__(self, handler): if not IClientApp.implementedBy(handler.__class__): raise TypeError( 'handler must implement devicehive.interfaces.IClientApp interface.' ) self.handler = handler self.handler.factory = self self.command_callbacks = {} def buildProtocol(self, addr): self.proto = WebSocketDeviceHiveProtocol(self, '/client') return self.proto def clientConnectionFailed(self, connector, reason): LOG_ERR('Client connection failed. Reason: {0}.'.format(reason)) self.handler.failure(reason) def clientConnectionLost(self, connector, reason): pass # IClientTransport interface implementation def authenticate(self, login, password): LOG_MSG('Authenticating the client library.') defer = Deferred() def on_ok(res): if res.get('status', 'error') == 'success': LOG_MSG('Client library has been authenticated.') defer.callback(res) else: LOG_ERR('Client failed authenticate. Reason: {0}.'.format( res.get('error', 'unknown'))) defer.errback(res) def on_err(reason): LOG_ERR( 'Failed to send authentication message. Reason: {0}.'.format( reason)) defer.errback(reason) self.proto.send_message({ 'action': 'authenticate', 'requestId': None, 'login': login, 'password': password }).addCallbacks(on_ok, on_err) return defer def subscribe(self, device_ids): if not (isinstance(device_ids, list) or isinstance(device_ids, tuple)): raise TypeError('device_ids should be a list or a tuple') LOG_MSG('About to subscribe to notifications for {0} devices.'.format( device_ids)) defer = Deferred() def on_ok(res): if res.get('status', 'error') == 'success': LOG_MSG('Subscribed.') defer.callback(res) else: LOG_ERR( 'Failed to subscribe to device(s) notifications. Reason: {0}.' .format(res.get('error', 'unknown'))) defer.errback(res) def on_err(reason): LOG_ERR('Failed to send subscribe command. Reason: {0}.'.format( reason)) defer.errback(reason) return self.proto.send_message({ 'action': 'notification/subscribe', 'requestId': None, 'deviceGuids': device_ids }).addCallbacks(on_ok, on_err) def unsubscribe(self, device_ids): if not (isinstance(device_ids, list) or isinstance(device_ids, tuple)): raise TypeError('device_ids should be a list or a tuple') LOG_MSG('Unsubscibing from devices {0}.'.format(device_ids)) defer = Deferred() def on_ok(res): if res.get('status', 'error') == 'success': LOG_MSG('Unsubscribed from device(s) notifications.') defer.callback(res) else: LOG_ERR( 'Failed to unsubscribe from device(s) notifications. Reason: {0}.' .format(res.get('error', 'unknown'))) defer.errback(res) def on_err(reason): LOG_ERR('Failed to send unsubscribe command. Reason: {0}.'.format( reason)) defer.errback(reason) self.proto.send_message({ 'action': 'notification/unsubscribe', 'requestId': None, 'deviceGuids': device_ids }).addCallbacks(on_ok, on_err) return defer def command(self, device_id, cmd): if not (isinstance(device_id, str) or isinstance(device_id, unicode)): raise TypeError('device_id should be a str or a unicode value') defer = Deferred() def on_ok(res): if res.get('status', 'error') == 'success': LOG_MSG('Command successfully sent.') cmdid = res['command']['id'] self.command_callbacks[cmdid] = defer else: LOG_ERR('Failed to send command {0}. Reason: {1}.'.format( cmd, res.get('error', 'unknown'))) defer.errback(res) def on_err(reason): LOG_ERR('Failed to send command {0}. Reason: {1}.'.format( cmd, reason)) defer.errback(reason) self.proto.send_message({ 'action': 'command/insert', 'requestId': None, 'deviceGuid': device_id, 'command': cmd.to_dict() }).addCallbacks(on_ok, on_err) return defer def do_notification(self, msg): LOG_MSG('Notification {0} has been received.'.format( msg['notification'])) self.handler.do_notification( msg['deviceGuid'], Notification(name=msg['notification']['notification'], parameters=msg['notification']['parameters'])) def do_command_update(self, msg): if not isinstance(msg, dict): raise TypeError('msg should be dict') cmd = msg.get('command', None) if cmd is not None: cmdid = cmd.get('id', None) if cmdid in self.command_callbacks: LOG_MSG('Command {0} update has been received.'.format(msg)) defer = self.command_callbacks.pop(cmdid) ocmd = WsCommand.create(cmd) if (isinstance(ocmd.status, str) or isinstance( ocmd.status, unicode)) and ocmd.status.lower() == 'success': defer.callback(ocmd) else: defer.errback(ocmd) else: LOG_ERR( 'Unattached command/update message {0} has been received.'. format(msg)) else: LOG_ERR('Malformed command response {0} has been received.'.format( msg)) def ping(self): return self.proto.ping() def connect(self, url): reactor.connectDeviceHive(url, self) # end IClientTransport interface implementation # IWebSocketProtocolCallback interface implementation def failure(self, reason, connector): LOG_ERR('WebSocekt client failure. Reason: {0}.'.format(reason)) self.handler.failure(reason) def connected(self): LOG_MSG('Client has connected to websocket server.') self.handler.connected() def closing_connection(self): LOG_MSG('WebSocket server has requested connection closing.') self.handler.closing_connection() def frame_received(self, message): action = message.get('action', '') if action == 'command/update': self.do_command_update(message) elif action == 'notification/insert': self.do_notification(message)
class WebSocketFactory(ClientFactory): """ Implements device factory over websocket protocol. """ implements(IWebSocketProtocolCallback, IProtoFactory) url = 'localhost' host = 'localhost' port = 80 proto = None handler = None callbacks = dict() def __init__(self, handler): """ @type handler: C{object} @param handler: handler has to implement C{IProtoHandler} interface """ self.handler = handler if IProtoHandler.implementedBy(self.handler.__class__): self.handler.factory = self else: raise TypeError( 'handler should implements IProtoHandler interface') self.devices = {} def buildProtocol(self, addr): self.proto = WebSocketDeviceHiveProtocol(self, '/device') if not IWebSocketMessanger.implementedBy(self.proto.__class__): raise TypeError( 'Protocol has to implement IWebSocketMessanger interface.') return self.proto def clientConnectionFailed(self, connector, reason): """ TODO: rename on_connection_failed method """ LOG_ERR('Failed to connect to {0}, host: {1}, port: {2}. Reason: {3}.'. format(self.url, self.host, self.port, reason)) self.handler.on_connection_failed(reason) def clientConnectionLost(self, connector, reason): """ TODO: notify handler about disconnection. """ pass def send_message(self, message): return self.proto.send_message(message) # begin IWebSocketProtocolCallback implementation def failure(self, reason, connector): LOG_ERR('Critial error. Reason: {0}.'.format(reason)) self.handler.on_failure(None, reason) def connected(self): self.handler.on_connected() def closing_connection(self): self.handler.on_closing_connection() def frame_received(self, message): if ('action' in message) and (message['action'] == 'command/insert'): if not 'deviceGuid' in message: LOG_ERR( 'Malformed command/insert message {0}.'.format(message)) else: device_id = str(message['deviceGuid']).lower() if ( 'deviceGuid' in message) and (message['deviceGuid'] is not None) else None if device_id in self.devices: self.on_command_insert(WsCommand.create(message), self.devices[device_id]) else: LOG_ERR( 'Unable to process command {0}. Device {1} is not registered.' .format(message, device_id)) # End of IWebSocketProtocolCallback interface implementation def on_command_insert(self, cmd, info): """ @type cmd: C{object} @param cmd: object which implements C{ICommand} @type info: C{object} @param info: C{IDeviceInfo} object which is receiving the command """ LOG_MSG('Command {0} has been received for device {1}.'.format( cmd, info)) def on_ok(result): LOG_MSG('The command "{0}" successfully processed. Result: {1}.'. format(cmd, result)) if isinstance(result, CommandResult): cmd.status = result.status cmd.result = result.result else: cmd.status = 'Success' cmd.result = result self.update_command(cmd, device_id=info.id, device_key=info.key) # def on_err(reason): LOG_ERR('Failed to process command "{0}". Reason: {1}.'.format( cmd, reason)) if isinstance(reason, Exception): cmd.status = 'Failed' cmd.result = reason.message elif hasattr(reason, 'value'): if isinstance(reason.value, CommandResult): cmd.status = reason.value.status cmd.result = reason.value.result elif isinstance(reason.value, Exception): cmd.status = 'Failed' cmd.result = reason.value.message else: cmd.status = 'Failed' cmd.result = reason.value else: cmd.status = 'Failed' cmd.result = 'Unhandled Exception' self.update_command(cmd, device_id=info.id, device_key=info.key) # finished = Deferred() finished.addCallbacks(on_ok, on_err) try: self.handler.on_command(info.id, cmd, finished) except Exception as ex: err = DhError('Failed to invoke command {0}. Reason: {1}.'.format( cmd, ex.message)) LOG_ERR(err.message) on_err(err) def update_command(self, command, device_id=None, device_key=None): if not ICommand.implementedBy(command.__class__): raise DhError('{0}.update_command expects ICommand'.format( self.__class__.__name__)) request = { 'action': 'command/update', 'commandId': command.id, 'command': command.to_dict() } if device_id is not None: request['deviceId'] = device_id if device_key is not None: request['deviceKey'] = device_key return self.send_message(request) # begin IProtoFactory implementation def authenticate(self, device_id, device_key): request = { 'action': 'authenticate', 'deviceId': device_id, 'deviceKey': device_key } return self.send_message(request) def notify(self, notification, params, device_id=None, device_key=None): request = { 'action': 'notification/insert', 'notification': { 'notification': notification, 'parameters': params } } if (device_id is not None): request['deviceId'] = device_id if (device_key is not None): request['deviceKey'] = device_key return self.send_message(request) def subscribe(self, device_id=None, device_key=None): LOG_MSG('Subscribe device {0}.'.format(device_id)) request = {'action': 'command/subscribe'} if device_id is not None: request['deviceId'] = device_id if device_key is not None: request['deviceKey'] = device_key return self.send_message(request) def unsubscribe(self, device_id=None, device_key=None): request = {'action': 'command/unsubscribe'} if device_id is not None: request['deviceId'] = device_id if device_key is not None: request['deviceKey'] = device_key return self.send_message(request) def device_save(self, info): LOG_MSG('device_save {0}'.format(info)) if not IDeviceInfo.implementedBy(info.__class__): raise WebSocketError( 'info parameter has to implement IDeviceInfo interface') dev = { 'key': info.key, 'name': info.name, 'equipment': [e.to_dict() for e in info.equipment] } if info.status is not None: dev['status'] = info.status if info.network is not None: dev['network'] = info.network.to_dict() if INetwork.implementedBy( info.network.__class__) else info.network if info.device_class is not None: dev['deviceClass'] = info.device_class.to_dict( ) if IDeviceClass.implementedBy( info.device_class.__class__) else info.device_class request = { 'action': 'device/save', 'deviceId': info.id, 'deviceKey': info.key, 'device': dev } def on_ok(result): key = str(info.id).lower() self.devices[key] = info return self.send_message(request).addCallback(on_ok) def connect(self, url): reactor.connectDeviceHive(url, self)