def handle_server_subscription(self, obj, client, clients): client.routing_id = obj.metadata['routing-id'] client.extra_routing_ids = RoutingMiddleware.extra_routing_ids(obj) client.subscriptions = obj.metadata.get('subscriptions', ['*']) client.echo = False client.server = True client.subscribed = True self.subscribe_to_server(client) client.send( BusinessObject( { 'event': 'routing/subscribe/reply', 'routing-id': client.routing_id, 'in-reply-to': obj.id, 'role': 'server' }, None), None) notification = BusinessObject( { 'event': 'routing/subscribe/notification', 'routing-id': client.routing_id, 'role': 'server' }, None) for c in clients: if c != client: c.send(notification, None) self.route(self.neighbor_announcement(clients), None, clients) logger.info(u"Server {0} subscribed!".format(client))
def handle_client_subscription(self, obj, client, clients): client.extra_routing_ids = RoutingMiddleware.extra_routing_ids(obj) client.subscriptions = obj.metadata.get('subscriptions', []) client.echo = False client.server = False client.subscribed = True notification = BusinessObject( { 'event': 'routing/subscribe/notification', 'routing-id': client.routing_id }, None) # Send a registration reply client.send( BusinessObject( { 'event': 'routing/subscribe/reply', 'routing-id': client.routing_id, 'in-reply-to': obj.id }, None), None) for c in clients: if c != client: c.send(notification, None) self.route(self.neighbor_announcement(clients), None, clients) logger.info(u"Client {0} subscribed!".format(client))
def test_clients_on_other_server_receive(self): client, routing_id = self.clients[0] to_client, to_routing_id = self.clients[2] obj = BusinessObject({'to': to_routing_id}, None) obj.serialize(socket=client) self.assert_receives_object(to_client, obj.id)
def test_answers_to_service_call(self): list_obj = BusinessObject({'event': 'services/request', 'name': 'clients', 'request': 'list'}, None) list_obj.serialize(socket=self.sock) logger.info(self.server) logger.info(self.service) reply, time = reply_for_object(list_obj, self.sock, select=select) self.assertIsNotNone(reply)
def test_server_doesnt_deliver_when_no_echo(self): client, routing_id = self.make_subscribe_client(no_echo=True) obj = BusinessObject({}, None) obj.serialize(socket=client) reply = read_object_with_timeout(client, timeout_secs=0.1, select=select) self.assertIsNone(reply) client.close()
def make_send_subscription(self): obj = BusinessObject( { 'event': 'routing/subscribe', 'receive-mode': 'all', 'types': 'all' }, None) obj.serialize(socket=self.sock) return obj
def handle_legacy_subscription(self, obj, sender, clients): client = sender RoutedSystemClient.promote(client, obj=obj) if 'route' in obj.metadata and len(obj.metadata['route']) > 1: return obj if 'routing-ids' in obj.metadata: routing_ids = obj.metadata['routing-ids'] if isinstance(routing_ids, basestring): logger.error(u"Got {0} as routing-ids from {1}".format( routing_ids, client)) else: for routing_id in routing_ids: client.extra_routing_ids.append(routing_id) # receive-mode handling receive_mode = obj.metadata.get( 'receive-mode', obj.metadata.get('receive_mode', 'none')) if receive_mode == "no_echo": client.echo = False else: client.echo = True client.subscriptions = [] if receive_mode == "events_only": client.subscriptions = ['@*'] else: client.subscriptions = ['*'] client.legacy = True client.subscribed = True logger.info(u"Legacy client {0} subscribed!".format(client)) if receive_mode != "none" and obj.metadata['types'] != "none": client.send( BusinessObject( { 'event': 'routing/subscribe/reply', 'routing-id': client.routing_id, 'in-reply-to': obj.id }, None), None) notification = BusinessObject( { 'event': 'routing/subscribe/notification', 'routing-id': client.routing_id }, None) for c in clients: if c != client: c.send(notification, None) return None
def make_send_subscription(self, sock, no_echo=False): metadata = {'event': 'routing/subscribe', 'receive-mode': 'all', 'types': 'all'} if no_echo: metadata['receive-mode'] = 'no_echo' obj = BusinessObject(metadata, None) obj.serialize(socket=sock) return obj
def test_answers_to_service_call(self): list_obj = BusinessObject( { 'event': 'services/request', 'name': 'clients', 'request': 'list' }, None) list_obj.serialize(socket=self.sock) logger.info(self.server) logger.info(self.service) reply, time = reply_for_object(list_obj, self.sock, select=select) self.assertIsNotNone(reply)
def make_send_subscription(self, sock, no_echo=False): metadata = { 'event': 'routing/subscribe', 'receive-mode': 'all', 'types': 'all' } if no_echo: metadata['receive-mode'] = 'no_echo' obj = BusinessObject(metadata, None) obj.serialize(socket=sock) return obj
def test_correct_registration(self): obj = BusinessObject( { 'event': 'services/request', 'name': 'clients', 'request': 'join', 'client': str(uuid4()), 'user': str(uuid4()) }, None) obj.serialize(socket=self.sock) list_obj = BusinessObject( { 'event': 'services/request', 'name': 'clients', 'request': 'list' }, None) list_obj.serialize(socket=self.sock) reply, time = reply_for_object(list_obj, self.sock, select=select) self.assertIsNotNone(reply, msg=u'No reply to service request') payload_text = reply.payload.decode('utf-8') payload = json.loads(payload_text) self.assertCorrectClientListReply(obj, payload)
def handle_legacy_registration(self, obj, sender, clients): client = sender RoutedSystemClient.promote(client, obj=obj) if 'route' in obj.metadata and len(obj.metadata['route']) > 1: return obj if 'routing-ids' in obj.metadata: routing_ids = obj.metadata['routing-ids'] if isinstance(routing_ids, basestring): logger.error(u"Got {0} as routing-ids from {1}".format( routing_ids, client)) else: for routing_id in routing_ids: client.extra_routing_ids.append(routing_id) client.receive_mode = obj.metadata.get('receive', 'all') client.types = obj.metadata.get('subscriptions', 'all') client.subscribed = True client.legacy = True logger.info( u"Legacy client {0} subscribed (registered)!".format(client)) if client.receive_mode != "none" and client.types != "none": client.send( BusinessObject( { 'event': 'clients/register/reply', 'routing-id': sender.routing_id }, None), None) notification = BusinessObject( { 'event': 'routing/subscribe/notification', 'routing-id': client.routing_id }, None) for c in clients: if c != client: c.send(notification, None) return BusinessObject( { 'event': 'services/request', 'name': 'clients', 'request': 'join', 'client': obj.metadata.get('name', 'no-client'), 'user': obj.metadata.get('user', 'no-user'), 'route': obj.metadata.get('route', []) }, None)
def setUp(self): super(ClientRegistryTestCase, self).setUp() self.start_client_registry(_host, _port) # TODO: multiple inheritance logger.info('Started client registry, connecting to %s:%s', _host, _port) global _host, _port self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((_host, _port)) obj = BusinessObject({'event': 'routing/subscribe', 'receive-mode': 'all', 'types': 'all'}, None) obj.serialize(socket=self.sock) resp, time = reply_for_object(obj, self.sock, select=select) self.routing_id = resp.metadata['routing-id']
def _run(self): client = self.client logger.info(u"Receiver handling connection from {0}".format( client.address)) last_activity = datetime.now() while True: if client.server and last_activity + timedelta( minutes=30) < datetime.now(): client.close('inactivity') return rlist, wlist, xlist = select([client.socket], [], [], timeout=30.0) if len(rlist) == 1: # logger.debug(u"Attempting to read an object from {0}".format(self.socket)) try: obj = BusinessObject.read_from_socket(client.socket) if obj is None: client.close("couldn't read object") return # logger.debug(u"Successfully read object {0}".format(str(obj))) logger.debug(u"<< {0}: {1}".format(client, obj)) client.gateway.send(obj, client) last_activity = datetime.now() except InvalidObject, ivo: client.close(u"{0}".format(ivo)) return except socket.error, e: client.close(u"{0}".format(e)) return except IOError, ioe: client.close(u"{0}".format(e)) return
def subscription_object(subscriptions=[], echo=False): metadata = { 'event': 'routing/subscribe', 'subscriptions': subscriptions, 'echo': echo } return BusinessObject(metadata, None)
def reply_for_object(obj, sock, timeout_secs=1.0, select=select): """ Waits for a reply to a sent object (connected by in-reply-to field). Returns the object and seconds elapsed as tuple (obj, secs). select-module is parameterizable (if not given, Python standard one is used); useful for e.g. gevent select. """ started = datetime.now() delta = timedelta(seconds=timeout_secs) while True: rlist, wlist, xlist = select.select([sock], [], [], 0.0001) if datetime.now() > started + delta: return None, timeout_secs if len(rlist) == 0: continue reply = BusinessObject.read_from_socket(sock) if reply is None: raise InvalidObject elif reply.metadata.get('in-reply-to', None) == obj.id: took = datetime.now() - started if hasattr(took, 'total_seconds'): return reply, took.total_seconds() else: return reply, _total_seconds(took)
def _run(self): client = self.client logger.info(u"Receiver handling connection from {0}".format(client.address)) last_activity = datetime.now() while True: if client.server and last_activity + timedelta(minutes=30) < datetime.now(): client.close('inactivity') return rlist, wlist, xlist = select([client.socket], [], [], timeout=30.0) if len(rlist) == 1: # logger.debug(u"Attempting to read an object from {0}".format(self.socket)) try: obj = BusinessObject.read_from_socket(client.socket) if obj is None: client.close("couldn't read object") return # logger.debug(u"Successfully read object {0}".format(str(obj))) logger.debug(u"<< {0}: {1}".format(client, obj)) client.gateway.send(obj, client) last_activity = datetime.now() except InvalidObject, ivo: client.close(u"{0}".format(ivo)) return except socket.error, e: client.close(u"{0}".format(e)) return except IOError, ioe: client.close(u"{0}".format(e)) return
def connect(self, client, clients): client.send( BusinessObject( { 'type': 'text/plain; charset=UTF-8', 'size': len(self.payload), 'sender': 'pyabboe' }, self.payload), None)
def test_server_delivers_to_specified_recipient(self): client, routing_id = self.clients[0] to_client, to_routing_id = self.clients[1] obj = BusinessObject({'to': to_routing_id}, None) obj.serialize(socket=client) self.assert_receives_object(to_client, obj.id) for client, routing_id in self.clients[2:]: reply = read_object_with_timeout(client, timeout_secs=0.1, select=select) if reply is not None: self.assertIsNotNone(reply.event) while reply is not None and reply.event is not None: reply = read_object_with_timeout(client, timeout_secs=0.1, select=select) self.assertIsNone(reply)
def registration_object(client_name, user_name): metadata = { 'event': 'services/request', 'name': 'clients', 'request': 'join', 'client': client_name, 'user': user_name } return BusinessObject(metadata, None)
def handle(self, obj): self.logger.debug(u"Request {0}".format(obj.metadata)) try: if 'url' not in obj.metadata: metadata = { 'event': 'services/reply', 'in-reply-to': obj.id, 'error': "URL for head request not found in metadata (attribute 'url')" } if 'route' in obj.metadata: metadata['to'] = obj.metadata['route'][0] reply = BusinessObject(metadata, None) self.logger.debug(u"Error reply {0}".format(reply.metadata)) return reply payload = {} r = requests.head(obj.metadata['url']) for k, v in r.headers.iteritems(): payload[k] = v payload['status_code'] = r.status_code metadata = { 'event': 'services/reply', 'in-reply-to': obj.id, 'type': 'text/json; charset=utf-8' } if 'route' in obj.metadata: metadata['to'] = obj.metadata['route'][0] payload = bytearray(json.dumps(payload, ensure_ascii=False), encoding='utf-8') metadata['size'] = len(payload) reply = BusinessObject(metadata, payload) self.logger.debug(u"Reply {0}".format(reply.metadata)) return reply except Exception, e: traceback.print_exc() self.logger.error(u"{0}".format(e))
def make_server_subscription(routing_id): metadata = { 'event': 'routing/subscribe', 'role': 'server', 'routing-id': routing_id, 'subscriptions': ['*'], 'name': 'Objectoplex', 'user': env.get('USER', 'unknown-user') } return BusinessObject(metadata, None)
def setUp(self): super(ClientRegistryTestCase, self).setUp() self.start_client_registry(_host, _port) # TODO: multiple inheritance logger.info('Started client registry, connecting to %s:%s', _host, _port) global _host, _port self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((_host, _port)) obj = BusinessObject( { 'event': 'routing/subscribe', 'receive-mode': 'all', 'types': 'all' }, None) obj.serialize(socket=self.sock) resp, time = reply_for_object(obj, self.sock, select=select) self.routing_id = resp.metadata['routing-id']
def handle(self, obj, sender, *args, **kwargs): if obj.event == 'ping' and isinstance(sender, RoutedSystemClient) and \ sender.subscribed: sender.send( BusinessObject( { 'event': 'pong', 'routing-id': sender.routing_id, 'in-reply-to': obj.id }, None), None) else: return obj
def neighbor_announcement(self, clients): logger.debug("Sending neighbor announcement") metadata = { 'event': 'routing/announcement/neighbors', 'node': self.routing_id, 'neighbors': [{ 'routing-id': client.routing_id } for client in clients] } obj = BusinessObject(metadata, None) return obj
def disconnect(self, client, clients): assert (client.__class__ == RoutedSystemClient) if client.server: logger.info(u"Server {0} disconnected!".format(client)) else: logger.info(u"Client {0} disconnected!".format(client)) if client.subscribed: self.route( BusinessObject( { 'event': 'routing/disconnect', 'routing-id': client.routing_id }, None), None, clients)
def send_statistics(self, client, original_id): statistics = { 'received objects': self.received_objects, 'clients connected total': self.clients_connected_total, 'clients disconnected total': self.clients_disconnected_total, 'objects by type': self.objects_by_type, 'events by type': self.events_by_type, 'client count': self.client_count, 'bytes in': self.bytes_in, 'average send queue length': self.average_send_queue_length, } payload = bytearray(json.dumps(statistics, ensure_ascii=False), encoding='utf-8') metadata = { 'event': 'server/statistics/reply', 'in-reply-to': original_id, 'size': len(payload), 'type': 'text/json' } client.send(BusinessObject(metadata, payload), None)
def test_correct_registration(self): obj = BusinessObject({'event': 'services/request', 'name': 'clients', 'request': 'join', 'client': str(uuid4()), 'user': str(uuid4())}, None) obj.serialize(socket=self.sock) list_obj = BusinessObject({'event': 'services/request', 'name': 'clients', 'request': 'list'}, None) list_obj.serialize(socket=self.sock) reply, time = reply_for_object(list_obj, self.sock, select=select) self.assertIsNotNone(reply, msg=u'No reply to service request') payload_text = reply.payload.decode('utf-8') payload = json.loads(payload_text) self.assertCorrectClientListReply(obj, payload)
def read_object_with_timeout(sock, timeout_secs=1.0, select=select): rlist, wlist, xlist = select.select([sock], [], [], timeout_secs) if len(rlist) > 0: return BusinessObject.read_from_socket(sock)
def test_server_delivers_to_all(self): obj = BusinessObject({}, None) obj.serialize(socket=self.clients[0][0]) for sock, routing_id in self.clients: self.assert_receives_object(sock, obj.id)
def test_server_delivers_to_sender(self): obj = BusinessObject({}, None) obj.serialize(socket=self.clients[0][0]) self.assert_receives_object(self.clients[0][0], obj.id)
def make_send_subscription(self): obj = BusinessObject({'event': 'routing/subscribe', 'receive-mode': 'all', 'types': 'all'}, None) obj.serialize(socket=self.sock) return obj