def on_receive(self, message): """ Handle being informed of a message. This function is called whenever a Lego receives a message, as specified in the pykka documentation. Legos should not override this function. :param message: :return: """ if self.log_file is not None and message['should_log']: message_copy = Message(message['text'], Metadata(None).__dict__, message['should_log']).__dict__ with open(self.log_file, mode='w') as f: f.write(json.dumps(message_copy)) logger.info(message['metadata']['source']) if self.listening_for(message): self_thread = self.HandlerThread(self.handle, message) self_thread.start() self.cleanup() for child in self.children: child.tell(message)
def _parse_metadata(self, message): """Parse incoming messages to build metadata dict Lots of 'if' statements. It sucks, I know. Args: message (dict): JSON dump of message sent from Slack Returns: Legobot.Metadata """ # Try to handle all the fields of events we care about. metadata = Metadata(source=self.actor_urn).__dict__ metadata['thread_ts'] = message.get('thread_ts') metadata['ts'] = message.get('ts') if 'presence' in message: metadata['presence'] = message['presence'] if 'text' in message: metadata['text'] = message['text'] elif 'previous_message' in message: # Try to handle slack links if 'text' in message['previous_message']: metadata['text'] = message['previous_message']['text'] else: metadata['text'] = None else: metadata['text'] = None if 'user' in message: metadata['source_user'] = message['user'] elif 'bot_id' in message: metadata['source_user'] = self.get_userid_from_botid( message['bot_id']) elif 'message' in message and 'user' in message['message']: metadata['source_user'] = message['message']['user'] else: metadata['source_user'] = None metadata['user_id'] = metadata['source_user'] metadata['display_name'] = self.get_user_name_by_id( metadata['source_user'], return_display_name=True, default=metadata['source_user']) if 'channel' in message: metadata['source_channel'] = message['channel'] # Slack starts DM channel IDs with "D" if message['channel'].startswith('D'): metadata['is_private_message'] = True else: metadata['is_private_message'] = False metadata['channel_display_name'] = self.get_channel_name_by_id( message['channel']) metadata['subtype'] = message.get('subtype') metadata['source_connector'] = 'slack' return metadata
def _parse_metadata(self, message): """ Sets metadata in Legobot message Args: message (dict): Full message from Discord websocket connection" Returns: Legobot.Metadata """ metadata = Metadata(source=self.actor_urn).__dict__ if 'author' in message['d']: metadata['source_user'] = message['d']['author']['username'] else: metadata['source_user'] = None if 'channel_id' in message['d']: metadata['source_channel'] = message['d']['channel_id'] metadata['channel_display_name'] = message['d']['channel_id'] else: metadata['source_channel'] = None metadata['user_id'] = metadata['source_user'] metadata['display_name'] = metadata['source_user'] metadata['source_connector'] = 'discord' return metadata
def test_reply(): # Setup baseplate = Lego.start(None, threading.Lock()) baseplate_proxy = baseplate.proxy() urn = baseplate.actor_urn meta = Metadata(source=urn).__dict__ message = Message(text='0', metadata=meta, should_log=True).__dict__ log_file_name = 'test_reply.log' children = baseplate_proxy.children.get() for child in children: print(child.actor_urn) # Test baseplate_proxy.add_child(ReplyTestingPingLego, log_file_name) baseplate.tell(message) time.sleep(1) # Cleanup children = baseplate_proxy.children.get() for child in children: child.stop() baseplate.stop() with open(log_file_name, mode='r') as f: log = json.loads(f.read()) os.remove(log_file_name) assert log['text'] == '1' # nosec
def _parse_metadata(self, message): ''' Parse incoming messages to build metadata dict Lots of 'if' statements. It sucks, I know. :param message: Message dict sent from Slack :return: dict ''' # Try to handle all the fields of events we care about. metadata = Metadata(source=self).__dict__ if 'presence' in metadata: metadata['presence'] = message['presence'] if 'text' in metadata: metadata['text'] = message['text'] if 'user' in message: metadata['source_user'] = message['user'] elif 'bot_id' in message: metadata['source_user'] = message['bot_id'] if 'channel' in message: metadata['source_channel'] = message['channel'] # Slack starts DM channel IDs with "D" if message['channel'].startswith('D'): metadata['is_private_message'] = True else: metadata['is_private_message'] = False return metadata
def handle(self, message): if message['text'] == '0': self.baseplate.tell( Message('1', Metadata(self).__dict__, True).__dict__) elif message['text'] == '2': self.reply(message, '3') else: print(message['text'])
def test_initialization(): source = Lego(None, threading.Lock()) metadata = Metadata(source) message = Message('a message', metadata) assert (message.text == 'a message') # nosec assert (message.metadata == metadata) # nosec message = Message('a message', metadata, True) assert (message.text == 'a message') # nosec assert (message.metadata == metadata) # nosec assert (message.should_log) # nosec
def test_receive_logs(): log_file_name = 'test_logging.log' lego = Lego(None, threading.Lock(), log_file_name) message = Message('Test Message 1', Metadata(None).__dict__, True).__dict__ lego.on_receive(message) with open(log_file_name, mode='r') as f: log = json.loads(f.read()) assert log == message # nosec os.remove(log_file_name)
def set_metadata(self, e): """ This function sets the metadata that is common between pub and priv """ metadata = Metadata(source=self.actor_urn).__dict__ metadata['source_connector'] = 'irc' metadata['source_channel'] = e.target metadata['source_user'] = e.source metadata['source_username'] = e.source.split('!')[0] metadata['user_id'] = metadata['source_user'] metadata['display_name'] = metadata['source_username'] return metadata
def on_pubmsg(self, c, e): """ This function runs when the bot receives a public message. """ text = e.arguments[0] metadata = Metadata(source=self.actor_urn).__dict__ metadata['source_channel'] = e.target metadata['source_user'] = e.source metadata['source_username'] = e.source.split('!')[0] metadata['is_private_message'] = False message = Message(text=text, metadata=metadata).__dict__ self.baseplate.tell(message)
def on_privmsg(self, c, e): """ This function runs when the bot receives a private message (query). """ text = e.arguments[0] metadata = Metadata(source=self).__dict__ logger.debug('{0!s}'.format(e.source)) metadata['source_channel'] = e.source.split('!')[0] metadata['source_username'] = e.source.split('!')[0] metadata['source_user'] = e.source metadata['is_private_message'] = True message = Message(text=text, metadata=metadata).__dict__ self.baseplate.tell(message)
def test_on_receive_informs_children(): log_file_name = 'test_child_informed.log' baseplate = Lego(None, threading.Lock()) child = Lego.start(baseplate, threading.Lock(), log_file_name) baseplate.children.append(child) message = Message('Test Message 1', Metadata(None).__dict__, True).__dict__ baseplate.on_receive(message) child.stop() with open(log_file_name, mode='r') as f: log = json.loads(f.read()) os.remove(log_file_name) assert log == message # nosec
def test_reply(self): log_file_name = 'test_reply.log' baseplate = Lego.start(None, threading.Lock()) baseplate_proxy = baseplate.proxy() baseplate_proxy.add_child(ReplyTestingPingLego, log_file_name) baseplate_proxy.add_child(ReplyTestingPongLego) baseplate.tell(Message('0', Metadata(None).__dict__, True).__dict__) time.sleep(1) children = baseplate_proxy.children.get() for child in children: child.stop() baseplate.stop() with open(log_file_name, mode='r') as f: log = json.loads(f.read()) os.remove(log_file_name) assert log['text'] == '4' # nosec
def reply(self, message, text, opts=None): """ Reply to the sender of the provided message with a message \ containing the provided text. :param message: the message to reply to :param text: the text to reply with :param opts: A dictionary of additional values to add to metadata :return: None """ metadata = Metadata(source=self, dest=message['metadata']['source']).__dict__ metadata['opts'] = opts message = Message(text=text, metadata=metadata, should_log=message['should_log']).__dict__ self.baseplate.tell(message)
def reply(self, message, text, opts=None): """Reply to the sender of the message with a containing the text :param message: the message to reply to :param text: the text to reply with :param opts: A dictionary of additional values to add to metadata :return: None """ metadata = Metadata(source=self.actor_urn, dest=message['metadata']['source']).__dict__ metadata['opts'] = opts message = Message(text=text, metadata=metadata, should_log=message['should_log']).__dict__ dest_actor = ActorRegistry.get_by_urn(message['metadata']['dest']) if dest_actor is not None: dest_actor.tell(message) else: raise("Tried to send message to nonexistent actor")
def _parse_metadata(self, message): '''Parse incoming messages to build metadata dict Lots of 'if' statements. It sucks, I know. Args: message (dict): JSON dump of message sent from Slack Returns: Legobot.Metadata ''' # Try to handle all the fields of events we care about. metadata = Metadata(source=self.actor_urn).__dict__ if 'presence' in message: metadata['presence'] = message['presence'] if 'text' in message: metadata['text'] = message['text'] elif 'previous_message' in message: # Try to handle slack links if 'text' in message['previous_message']: metadata['text'] = message['previous_message']['text'] else: metadata['text'] = None else: metadata['text'] = None if 'user' in message: metadata['source_user'] = message['user'] elif 'bot_id' in message: metadata['source_user'] = message['bot_id'] if 'channel' in message: metadata['source_channel'] = message['channel'] # Slack starts DM channel IDs with "D" if message['channel'].startswith('D'): metadata['is_private_message'] = True else: metadata['is_private_message'] = False return metadata
def handle(self, message): try: target = message['metadata']['source_channel'] opts = {'target': target} except IndexError: logger.error('Could not identify message source in message: %s' % str(message)) query = ' '.join(message['text'].split()[1:]) query = query.replace(' ', '%20') req_url = self._make_url(query) response = requests.get(req_url) urls = [] url_regex = '"https?://[^"]*\.(jpg|jpeg|png|gif|gifv)"' for url in re.finditer(url_regex, response.text): urls += [url.group(0).strip('"')] if len(urls) == 0: url = 'Nothing found :(' else: url = random.choice(urls) metadata = Metadata(source=self).__dict__ metadata['opts'] = opts message = Message(text=str(url), metadata=metadata).__dict__ self.baseplate.tell(message)
def test_default_init_values(): source = Lego(None, threading.Lock()) metadata = Metadata(source) message = Message('a message', metadata) assert (not message.should_log) # nosec
def test_initialization(): source = Lego(None, threading.Lock()) dest = Lego(None, threading.Lock()) metadata = Metadata(source, dest) assert (metadata.source == source) # nosec assert (metadata.dest == dest) # nosec
def test_default_init_values(): source = Lego(None, threading.Lock()) metadata = Metadata(source) assert (metadata.dest is None) # nosec
def _make_message(): source = Lego(None, threading.Lock()) metadata = Metadata(source) message = Message('blah', metadata) return message
def test_initialization(): lego = Lego(None, threading.Lock()) message = Message('Test Message', Metadata(lego)) thread = Lego.HandlerThread(lego.handle, message) assert thread.handler == lego.handle # nosec assert thread.message == message # nosec
def make_message(self): metadata = Metadata(self, None) return Message('a message', metadata)