def wrap_func(self: 'SlaveMessageManager', msg: wxpy.Message, *args, **kwargs): logger = logging.getLogger(__name__) logger.debug("[%s] Raw message: %r", msg.id, msg.raw) efb_msg: Optional[EFBMsg] = func(self, msg, *args, **kwargs) if efb_msg is None: return efb_msg.uid = getattr( msg, "id", constants.INVALID_MESSAGE_ID + str(uuid.uuid4())) chat: EFBChat = self.channel.chats.wxpy_chat_to_efb_chat( msg.chat) author: EFBChat = self.channel.chats.wxpy_chat_to_efb_chat( msg.author) # Do not override what's defined in the sub-functions efb_msg.chat = efb_msg.chat or chat efb_msg.author = efb_msg.author or author logger.debug("[%s] Chat: %s, Author: %s", efb_msg.uid, efb_msg.chat, efb_msg.author) efb_msg.deliver_to = coordinator.master coordinator.send_message(efb_msg) if efb_msg.file: efb_msg.file.close()
def send_status_message(self, status: StatusAttribute, chat: Chat, author: Optional[ChatMember] = None, target: Optional[Message] = None) -> Message: """Send a status message to master channel. Leave author blank to use “self” of the chat. Returns the message sent. """ author = author or chat.self uid = f"__msg_id_{uuid4()}__" message = Message(chat=chat, author=author, type=MsgType.Status, target=target, uid=uid, text="", attributes=status, deliver_to=coordinator.master) coordinator.send_message(message) self.messages_sent[uid] = message return message
def send_link_message(self, chat: Chat, author: Optional[ChatMember] = None, target: Optional[Message] = None, reactions: bool = False, commands: bool = False, substitution: bool = False) -> Message: author = author or chat.self uid = f"__msg_id_{uuid4()}__" message = Message(chat=chat, author=author, type=MsgType.Link, target=target, uid=uid, text=f"Content of link message with ID {uid}", attributes=LinkAttribute( title="EH Forwarder Bot", description="EH Forwarder Bot project site.", url="https://efb.1a23.studio"), deliver_to=coordinator.master) message = self.attach_message_properties(message, reactions, commands, substitution) self.messages_sent[uid] = message coordinator.send_message(message) return message
def exit_callback(self): self.logger.debug('Calling exit callback...') if self._stop_polling_event.is_set(): return msg = EFBMsg() chat = EFBChat(self).system() chat.chat_type = ChatType.System chat.chat_name = self._("EWS User Auth") msg.chat = msg.author = chat msg.deliver_to = coordinator.master msg.text = self._( "WeChat server has logged you out. Please log in again when you are ready." ) msg.uid = "__reauth__.%s" % int(time.time()) msg.type = MsgType.Text on_log_out = self.flag("on_log_out") on_log_out = on_log_out if on_log_out in ("command", "idle", "reauth") else "command" if on_log_out == "command": msg.type = MsgType.Text msg.commands = EFBMsgCommands([ EFBMsgCommand(name=self._("Log in again"), callable_name="reauth", kwargs={"command": True}) ]) elif on_log_out == "reauth": if self.flag("qr_reload") == "console_qr_code": msg.text += "\n" + self._("Please check your log to continue.") self.reauth() coordinator.send_message(msg)
def send_text_message(self, chat: Chat, author: Optional[ChatMember] = None, target: Optional[Message] = None, reactions: bool = False, commands: bool = False, substitution: bool = False, unsupported: bool = False) -> Message: """Send a text message to master channel. Leave author blank to use “self” of the chat. Returns the message sent. """ author = author or chat.self uid = f"__msg_id_{uuid4()}__" msg_type = MsgType.Unsupported if unsupported else MsgType.Text message = Message( chat=chat, author=author, type=msg_type, target=target, uid=uid, text=f"Content of {msg_type.name} message with ID {uid}", deliver_to=coordinator.master) message = self.attach_message_properties(message, reactions, commands, substitution) coordinator.send_message(message) self.messages_sent[uid] = message return message
def master_qr_code(self, uuid, status, qrcode=None): status = int(status) if self.qr_uuid == (uuid, status): return self.qr_uuid = (uuid, status) msg = EFBMsg() msg.uid = f"ews_auth_{uuid}_{status}" msg.type = MsgType.Text msg.chat = EFBChat(self).system() msg.chat.chat_name = self._("EWS User Auth") msg.author = msg.chat msg.deliver_to = coordinator.master if status == 201: msg.type = MsgType.Text msg.text = self._('Confirm on your phone.') elif status == 200: msg.type = MsgType.Text msg.text = self._("Successfully logged in.") elif uuid != self.qr_uuid: msg.type = MsgType.Image file = NamedTemporaryFile(suffix=".png") qr_url = "https://login.weixin.qq.com/l/" + uuid QRCode(qr_url).png(file, scale=10) msg.text = self._("QR code expired, please scan the new one.") msg.path = file.name msg.file = file msg.mime = 'image/png' if status in (200, 201) or uuid != self.qr_uuid: coordinator.send_message(msg)
def wrap_func(self: 'SlaveMessageManager', msg: wxpy.Message, *args, **kwargs): logger = logging.getLogger(__name__) logger.debug("[%s] Raw message: %r", msg.id, msg.raw) efb_msg: Optional[Message] = func(self, msg, *args, **kwargs) if efb_msg is None: return if getattr(coordinator, 'master', None) is None: logger.debug("[%s] Dropping message as master channel is not ready yet.", efb_msg.uid) return efb_msg.deliver_to = coordinator.master # Format message IDs as JSON of List[List[str]]. efb_msg.uid = MessageID(json.dumps( [[str(getattr(msg, "id", constants.INVALID_MESSAGE_ID + str(uuid.uuid4())))]] )) if not efb_msg.chat or not efb_msg.author: chat, author = self.get_chat_and_author(msg) # Do not override what's defined in the wrapped methods efb_msg.chat = efb_msg.chat or chat efb_msg.author = efb_msg.author or author logger.debug("[%s] Chat: %s, Author: %s", efb_msg.uid, efb_msg.chat, efb_msg.author) coordinator.send_message(efb_msg) if efb_msg.file: efb_msg.file.close()
def exit_callback(self): # Don't send prompt if there's nowhere to send. if not getattr(coordinator, 'master', None): raise Exception(self._("Web WeChat logged your account out before master channel is ready.")) self.logger.debug('Calling exit callback...') if self._stop_polling_event.is_set(): return msg = EFBMsg() chat = EFBChat(self).system() chat.chat_type = ChatType.System chat.chat_name = self._("EWS User Auth") msg.chat = msg.author = chat msg.deliver_to = coordinator.master msg.text = self._("WeChat server has logged you out. Please log in again when you are ready.") msg.uid = f"__reauth__.{int(time.time())}" msg.type = MsgType.Text on_log_out = self.flag("on_log_out") on_log_out = on_log_out if on_log_out in ("command", "idle", "reauth") else "command" if on_log_out == "command": msg.type = MsgType.Text msg.commands = EFBMsgCommands( [EFBMsgCommand(name=self._("Log in again"), callable_name="reauth", kwargs={"command": True})]) elif on_log_out == "reauth": if self.flag("qr_reload") == "console_qr_code": msg.text += "\n" + self._("Please check your log to continue.") self.reauth() coordinator.send_message(msg)
def send_file_like_message(self, msg_type: MsgType, file_path: Path, mime: str, chat: Chat, author: Optional[ChatMember] = None, target: Optional[Message] = None, reactions: bool = False, commands: bool = False, substitution: bool = False) -> Message: author = author or chat.self uid = f"__msg_id_{uuid4()}__" message = Message( chat=chat, author=author, type=msg_type, target=target, uid=uid, file=file_path.open('rb'), filename=file_path.name, path=file_path, mime=mime, text=f"Content of {msg_type.name} message with ID {uid}", deliver_to=coordinator.master) message = self.attach_message_properties(message, reactions, commands, substitution) self.messages_sent[uid] = message coordinator.send_message(message) return message
def master_qr_code(self, uuid, status, qrcode=None): status = int(status) msg = EFBMsg() msg.type = MsgType.Text msg.chat = EFBChat(self).system() msg.chat.chat_name = self._("EWS User Auth") msg.author = msg.chat msg.deliver_to = coordinator.master if status == 201: msg.type = MsgType.Text msg.text = self._('Confirm on your phone.') elif status == 200: msg.type = MsgType.Text msg.text = self._("Successfully logged in.") elif uuid != self.qr_uuid: msg.type = MsgType.Image # path = os.path.join("storage", self.channel_id) # if not os.path.exists(path): # os.makedirs(path) # path = os.path.join(path, 'QR-%s.jpg' % int(time.time())) # self.logger.debug("master_qr_code file path: %s", path) file = NamedTemporaryFile(suffix=".png") qr_url = "https://login.weixin.qq.com/l/" + uuid QRCode(qr_url).png(file, scale=10) msg.text = self._("QR code expired, please scan the new one.") msg.path = file.name msg.file = file msg.mime = 'image/png' if status in (200, 201) or uuid != self.qr_uuid: coordinator.send_message(msg) self.qr_uuid = uuid
async def handle_new_telegram_message(self, event: NewMessage): msg: TgMsg = event.message chat_id = get_chat_id(msg.peer_id) chat = await self.async_get_chat(chat_id) self.logger.debug(msg) file = None path = None filename = None mime = None msg_type = MsgType.Text tempfile_suffix = '' if getattr(msg, 'media', None): media = msg.media tempfile_suffix = get_extension(media) if isinstance(media, MessageMediaPhoto): msg_type = MsgType.Image if isinstance(media, MessageMediaDocument): document = media.document mime = document.mime_type msg_type = MsgType.File for attr in document.attributes: if isinstance(attr, DocumentAttributeFilename): tempfile_suffix = attr.file_name filename = attr.file_name if isinstance(attr, DocumentAttributeSticker): msg_type = MsgType.Sticker if isinstance(attr, DocumentAttributeVideo): msg_type = MsgType.Video if isinstance(attr, DocumentAttributeAudio): msg_type = MsgType.Audio if msg_type != MsgType.Text: file = tempfile.NamedTemporaryFile(suffix=tempfile_suffix) path = file.name await self.client.download_media(msg, file) msg_peer = await self.client.get_entity( get_chat_id(msg.from_id or msg.peer_id)) self.logger.debug(msg_peer) chat_member = ChatMember( chat=chat, name=format_entity_name(msg_peer), uid=str(chat_id), ) efb_msg = Message( deliver_to=coordinator.master, author=chat_member, chat=chat, text=msg.message, type=msg_type, uid=f'{chat_id}_{msg.id}', file=file, filename=filename, mime=mime, path=path, ) coordinator.send_message(efb_msg)
def send_efb_group_notice(self, context): context['message_type'] = 'group' self.logger.debug(repr(context)) msg = EFBMsg() msg.author = self.chat_manager.build_efb_chat_as_system_user(context) msg.chat = self.chat_manager.build_efb_chat_as_group(context) msg.deliver_to = coordinator.master msg.type = MsgType.Text msg.uid = "__group_notice__.%s" % int(time.time()) msg.text = context['message'] coordinator.send_message(msg)
def send_msg_to_master(self, context): self.logger.debug(repr(context)) msg = EFBMsg() msg.chat = msg.author = self.chat_manager.build_efb_chat_as_system_user( context) msg.deliver_to = coordinator.master msg.type = MsgType.Text msg.uid = "__{context[uid_prefix]}__.{uni_id}".format( context=context, uni_id=str(int(time.time()))) msg.text = context['message'] coordinator.send_message(msg)
def send_message(self, msg: Message) -> Message: if msg.type == MsgType.Text: coordinator.send_message(Message( uid=MessageID(f'echo_{uuid4()}'), type=MsgType.Text, chat=self.chat, author=self.chat.other, deliver_to=coordinator.master, text=msg.text, )) return msg
def edit_text_message(self, message: Message, reactions: bool = False, commands: bool = False, substitution: bool = False) -> Message: message.edit = True message.text = f"Edited {message.type.name} message {message.uid} @ {time.time_ns()}" message = self.attach_message_properties(message, reactions, commands, substitution) self.messages_sent[message.uid] = message coordinator.send_message(message) return message
def edit_file_like_message_text(self, message: Message, reactions: bool = False, commands: bool = False, substitution: bool = False) -> Message: message.text = f"Content of edited {message.type.name} message with ID {message.uid}" message.edit = True message.edit_media = False message = self.attach_message_properties(message, reactions, commands, substitution) self.messages_sent[message.uid] = message coordinator.send_message(message) return message
def edit_location_message(self, message: Message, reactions: bool = False, commands: bool = False, substitution: bool = False) -> Message: message.text = f"Content of edited location message with ID {message.uid}" message.edit = True message.attributes = LocationAttribute( latitude=random.uniform(0.0, 90.0), longitude=random.uniform(0.0, 90.0)) message = self.attach_message_properties(message, reactions, commands, substitution) self.messages_sent[message.uid] = message coordinator.send_message(message) return message
def send_msg_to_master(self, context): self.logger.debug(repr(context)) msg = EFBMsg() efb_chat = EFBChat(self.channel).system() efb_chat.chat_type = ChatType.System efb_chat.chat_name = context['event_description'] msg.chat = msg.author = efb_chat msg.deliver_to = coordinator.master msg.type = MsgType.Text msg.uid = "__{context[uid_prefix]}__.{uni_id}".format( context=context, uni_id=str(int(time.time()))) if 'message' in context: msg.text = context['message'] if 'commands' in context: msg.commands = EFBMsgCommands(context['commands']) coordinator.send_message(msg)
def on_message(self, mid: str = '', author_id: str = '', message: str = '', message_object: Message = None, thread_id: str = '', thread_type: str = ThreadType.USER, ts: str = '', metadata=None, msg=None): """ Called when the client is listening, and somebody sends a message Args: mid: The message ID author_id: The ID of the author message: (deprecated. Use `message_object.text` instead) message_object (models.Message): The message (As a `Message` object) thread_id: Thread ID that the message was sent to. See :ref:`intro_threads` thread_type (models.ThreadType): Type of thread that the message was sent to. See :ref:`intro_threads` ts: The timestamp of the message metadata: Extra metadata about the message msg: A full set of the data received """ # Ignore messages sent by EFMS time.sleep(0.25) if mid in self.sent_messages: self.sent_messages.remove(mid) return self.logger.debug("[%s] Received message from Messenger: %s", mid, message_object) efb_msg = self.build_efb_msg(mid, thread_id, author_id, message_object) attachments = msg.get('attachments', []) if len(attachments) > 1: self.logger.debug("[%s] Multiple attachments detected. Splitting into %s messages.", mid, len(attachments)) self.message_mappings[mid] = len(attachments) for idx, i in enumerate(attachments): sub_msg = copy.copy(efb_msg) sub_msg.uid = MessageID(f"{efb_msg.uid}.{idx}") self.attach_media(sub_msg, i) coordinator.send_message(sub_msg) return if attachments: self.attach_media(efb_msg, attachments[0]) coordinator.send_message(efb_msg) self.markAsDelivered(mid, thread_id)
def reply_message(self, message: Message, text: str): reply = Message() reply.text = text # reply.chat = coordinator.slaves[message.chat.channel_id].get_chat(message.chat.chat_uid) reply.chat = coordinator.slaves[message.chat.module_id].get_chat( message.chat.uid) reply.author = message.chat.make_system_member( uid=self.middleware_id, name=self.middleware_name, middleware=self) reply.type = MsgType.Text # reply.deliver_to = coordinator.master reply.deliver_to = coordinator.slaves[message.chat.module_id] # reply.target = message reply.uid = str(uuid.uuid4()) r2 = reply coordinator.send_message(reply) r2.deliver_to = coordinator.master coordinator.send_message(r2)
def process_audio(self, message: Message, audio: NamedTemporaryFile): try: # reply_text: str = '\n'.join(self.recognize(audio.name, self.lang)) reply_text: str = '\n'.join(self.recognize(audio.name)) except Exception: reply_text = 'Failed to recognize voice content.' if getattr(message, 'text', None) is None: message.text = "" message.text += reply_text message.text = message.text[:4000] # message.file = None message.edit = True message.edit_media = False coordinator.send_message(message) audio.close()
def edit_link_message(self, message: Message, reactions: bool = False, commands: bool = False, substitution: bool = False) -> Message: message.text = f"Content of edited link message with ID {message.uid}" message.edit = True message.attributes = LinkAttribute( title="EH Forwarder Bot (edited)", description="EH Forwarder Bot project site. (edited)", url="https://efb.1a23.studio/#edited") message = self.attach_message_properties(message, reactions, commands, substitution) self.messages_sent[message.uid] = message coordinator.send_message(message) return message
def on_friend_msg(ctx: FriendMsg): self.logger.debug(ctx) if int(ctx.FromUin) == int(self.uin) and not IOTConfig.configs.get( 'receive_self_msg', True): self.logger.info( "Received self message and flag set. Cancel delivering...") return remark_name = self.get_friend_remark(ctx.FromUin) if not remark_name: info = self.get_stranger_info(ctx.FromUin) if info: remark_name = info.get('nickname', '') else: remark_name = str(ctx.FromUin) if ctx.MsgType == 'TempSessionMsg': # Temporary chat chat_uid = f'private_{ctx.FromUin}_{ctx.TempUin}' elif ctx.MsgType == 'PhoneMsg': chat_uid = f'phone_{ctx.FromUin}' else: chat_uid = f'friend_{ctx.FromUin}' chat = ChatMgr.build_efb_chat_as_private( EFBPrivateChat( uid=chat_uid, name=remark_name, )) author = chat.other # Splitting messages messages: List[Message] = [] func = getattr(self.iot_msg, f'iot_{ctx.MsgType}_friend') messages.extend(func(ctx, chat)) # Sending messages one by one message_id = ctx.MsgSeq for idx, val in enumerate(messages): if not isinstance(val, Message): continue val.uid = f"friend_{ctx.FromUin}_{message_id}_{idx}" val.chat = chat val.author = author val.deliver_to = coordinator.master coordinator.send_message(val) if val.file: val.file.close()
def send_text_msg(self): slave = coordinator.slaves['tests.mocks.slave'] wonderland = slave.get_chat('wonderland001') msg = EFBMsg() msg.deliver_to = slave msg.chat = wonderland msg.author = EFBChat(self).self() msg.type = MsgType.Text msg.text = "Hello, world." return coordinator.send_message(msg)
def edit_file_like_message(self, message: Message, file_path: Path, mime: str, reactions: bool = False, commands: bool = False, substitution: bool = False) -> Message: message.text = f"Content of edited {message.type.name} media with ID {message.uid}" message.edit = True message.edit_media = True message.file = file_path.open('rb') message.filename = file_path.name message.path = file_path message.mime = mime message = self.attach_message_properties(message, reactions, commands, substitution) self.messages_sent[message.uid] = message coordinator.send_message(message) return message
def send_text_msg(self): slave = next(iter(coordinator.slaves.values())) wonderland = slave.get_chat('wonderland001') msg = EFBMsg() msg.deliver_to = slave msg.chat = wonderland msg.author = EFBChat(self).self() msg.type = MsgType.Text msg.text = "Hello, world." return coordinator.send_message(msg)
def send_location_msg(self): slave = next(iter(coordinator.slaves.values())) alice = slave.get_chat('alice') msg = EFBMsg() msg.deliver_to = slave msg.chat = alice msg.author = EFBChat(self).self() msg.type = MsgType.Location msg.text = "I'm not here." msg.attributes = EFBMsgLocationAttribute(latitude=0.1, longitude=1.0) return coordinator.send_message(msg)
def send_text_msg(self): slave = next(iter(coordinator.slaves.values())) wonderland = slave.get_chat('wonderland001') msg = Message( deliver_to=slave, chat=wonderland, author=wonderland.self, type=MsgType.Text, text="Hello, world.", ) return coordinator.send_message(msg)
def handle_group_request(context): self.logger.debug(repr(context)) context['group_name'] = self._('[Request]') + self.get_group_info(context['group_id'])['group_name'] context['group_id_orig'] = context['group_id'] context['group_id'] = str(context['group_id']) + "_notification" context['message_type'] = 'group' context['event_description'] = '\u2139 New Group Join Request' original_group = self.get_group_info(context['group_id'], False) group_name = context['group_id'] if original_group is not None and 'group_name' in original_group: group_name = original_group['group_name'] msg = EFBMsg() msg.uid = 'group' + '_' + str(context['group_id']) msg.author = self.chat_manager.build_efb_chat_as_system_user(context) msg.chat = self.chat_manager.build_efb_chat_as_group(context) msg.deliver_to = coordinator.master msg.type = MsgType.Text name = "" if not self.get_friend_remark(context['user_id']): name = "{}({})[{}] ".format( self.get_stranger_info(context['user_id'])['nickname'], self.get_friend_remark(context['user_id']), context['user_id']) else: name = "{}[{}] ".format(self.get_stranger_info(context['user_id'])['nickname'], context['user_id']) msg.text = "{} wants to join the group {}({}). \nHere is the comment: {}".format( name, group_name, context['group_id_orig'], context['comment'] ) msg.commands = EFBMsgCommands([EFBMsgCommand( name=self._("Accept"), callable_name="process_group_request", kwargs={'result': 'accept', 'flag': context['flag'], 'sub_type': context['sub_type']} ), EFBMsgCommand( name=self._("Decline"), callable_name="process_group_request", kwargs={'result': 'decline', 'flag': context['flag'], 'sub_type': context['sub_type']} )]) coordinator.send_message(msg)
def send_link_msg(self): slave = next(iter(coordinator.slaves.values())) alice = slave.get_chat('alice') msg = EFBMsg() msg.deliver_to = slave msg.chat = alice msg.author = EFBChat(self).self() msg.type = MsgType.Link msg.text = "Check it out." msg.attributes = EFBMsgLinkAttribute(title="Example", url="https://example.com") return coordinator.send_message(msg)