From 09f666f6615ab50b2fd0dcee36268e8a44b31b59 Mon Sep 17 00:00:00 2001 From: Alexander Zveruk Date: Sun, 3 May 2020 23:23:31 +0300 Subject: [PATCH 1/2] Update chat title dynamicly --- tg/controllers/__init__.py | 33 ++++++++++++++++++++------------- tg/main.py | 5 +++-- tg/models/__init__.py | 30 ++++++++++++++++++++++++------ 3 files changed, 47 insertions(+), 21 deletions(-) diff --git a/tg/controllers/__init__.py b/tg/controllers/__init__.py index 6e1da1f..e78f3d2 100644 --- a/tg/controllers/__init__.py +++ b/tg/controllers/__init__.py @@ -6,6 +6,8 @@ from utils import notify log = logging.getLogger(__name__) +SUPPORTED_MSG_TYPES = "updateNewMessage", "updateChatLastMessage" + class Controller: """ @@ -85,11 +87,7 @@ class Controller: # write new message msg = self.view.get_input() if msg: - chat_id = self.model.get_current_chat_id() - self.model.msgs.send_message( - chat_id=chat_id, - text=msg, - ) + self.model.send_message(text=msg) self.view.draw_status(f'Sent: {msg}') elif keys in ('h', '^D'): @@ -131,12 +129,14 @@ class Controller: self.refresh_chats() def refresh_chats(self): - self.view.draw_chats( - self.model.current_chat, - self.model.get_chats(limit=self.view.chats.h) - ) - self.refresh_msgs() - self.view.draw_status() + with self.lock: + # using lock here, because model.get_chats is vulnerable to race conditions + self.view.draw_chats( + self.model.current_chat, + self.model.get_chats(limit=self.view.chats.h) + ) + self.refresh_msgs() + self.view.draw_status() def refresh_msgs(self): self.view.msgs.users = self.model.users @@ -145,10 +145,10 @@ class Controller: def update_handler(self, update): try: - log.info('===Received: %s', update) _type = update['@type'] + log.info('===Received %s type: %s', _type, update) if _type == 'updateNewMessage': - # with self.lock: + # with self.lock(): chat_id = update['message']['chat_id'] self.model.msgs.msgs[chat_id].append(update['message']) # msgs = self.model.get_current_chat_msg() @@ -156,6 +156,13 @@ class Controller: if not update.get('disable_notification'): if update['message']['content'] == 'text': notify(update['message']['content']['text']['text']) + elif _type == 'updateChatLastMessage': + log.info("Proccessing updateChatLastMessage") + chat_id = update['chat_id'] + message = update['last_message'] + self.model.chats.update_last_message(chat_id, message) + self.refresh_chats() + except Exception: log.exception("Error happened in update_handler") # message_content = update['message']['content'].get('text', {}) diff --git a/tg/main.py b/tg/main.py index 72824fa..321e191 100644 --- a/tg/main.py +++ b/tg/main.py @@ -7,7 +7,7 @@ from functools import partial from telegram.client import Telegram -from tg.controllers import Controller +from tg.controllers import Controller, SUPPORTED_MSG_TYPES from tg.models import Model from tg.views import View @@ -37,7 +37,8 @@ def run(tg, stdscr): model = Model(tg) controller = Controller(model, view) controller.tg = tg - tg.add_message_handler(controller.update_handler) + for msg_type in SUPPORTED_MSG_TYPES: + tg.add_update_handler(msg_type, controller.update_handler) t = threading.Thread( target=controller.run, diff --git a/tg/models/__init__.py b/tg/models/__init__.py index 50155b9..2dc5a25 100644 --- a/tg/models/__init__.py +++ b/tg/models/__init__.py @@ -77,7 +77,14 @@ class Model: return self.msgs.jump_prev_msg(chat_id) def get_chats(self, offset=0, limit=10): - return self.chats.get_chats(offset=offset, limit=limit) + return self.chats.fetch_chats(offset=offset, limit=limit) + + def send_message(self, text): + chat_id = self.get_current_chat_id() + if chat_id is None: + return False + self.msgs.send_message(chat_id, text) + return True def delete_msg(self): chat_id = self.get_current_chat_id() @@ -92,14 +99,14 @@ class ChatModel: self.chats = [] # Dict[int, list] self.chat_ids = [] - def get_chats(self, offset=0, limit=10): + def fetch_chats(self, offset=0, limit=10): if offset + limit < len(self.chats): # return data from cache return self.chats[offset:limit] previous_chats_num = len(self.chat_ids) - self.get_chat_ids( + self.fetch_chat_ids( offset=len(self.chats), limit=len(self.chats) + limit ) @@ -107,12 +114,12 @@ class ChatModel: return self.chats[offset:limit] for chat_id in self.chat_ids: - chat = self.get_chat(chat_id) + chat = self.fetch_chat(chat_id) self.chats.append(chat) return self.chats[offset:limit] - def get_chat_ids(self, offset=0, limit=10): + def fetch_chat_ids(self, offset=0, limit=10): if len(self.chats): result = self.tg.get_chats( offset_chat_id=self.chats[-1]['id'], @@ -139,7 +146,7 @@ class ChatModel: return self.chat_ids[offset:limit] - def get_chat(self, chat_id): + def fetch_chat(self, chat_id): result = self.tg.get_chat(chat_id) result.wait() @@ -148,6 +155,17 @@ class ChatModel: return {} return result.update + def update_last_message(self, chat_id, message): + for i, c in enumerate(self.chats): + if c['id'] != chat_id: + continue + self.chats[i]['last_message'] = message + log.info("Updated last message") + return True + else: + log.error(f"Can't find chat {chat_id} in existing chats") + return False + class MsgModel: From 8c3e17450aef9b72f77e7e64218e488070c500d6 Mon Sep 17 00:00:00 2001 From: Alexander Zveruk Date: Mon, 4 May 2020 01:08:14 +0300 Subject: [PATCH 2/2] correctly proccess sending msgs --- tg/controllers/__init__.py | 10 ++++++++-- tg/models/__init__.py | 30 +++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/tg/controllers/__init__.py b/tg/controllers/__init__.py index e78f3d2..0461e24 100644 --- a/tg/controllers/__init__.py +++ b/tg/controllers/__init__.py @@ -6,7 +6,7 @@ from utils import notify log = logging.getLogger(__name__) -SUPPORTED_MSG_TYPES = "updateNewMessage", "updateChatLastMessage" +SUPPORTED_MSG_TYPES = "updateNewMessage", "updateChatLastMessage", "updateMessageSendSucceeded" class Controller: @@ -150,7 +150,7 @@ class Controller: if _type == 'updateNewMessage': # with self.lock(): chat_id = update['message']['chat_id'] - self.model.msgs.msgs[chat_id].append(update['message']) + self.model.msgs.add_message(chat_id, update['message']) # msgs = self.model.get_current_chat_msg() self.refresh_msgs() if not update.get('disable_notification'): @@ -162,6 +162,12 @@ class Controller: message = update['last_message'] self.model.chats.update_last_message(chat_id, message) self.refresh_chats() + elif _type == "updateMessageSendSucceeded": + chat_id = update['message']['chat_id'] + msg_id = update['old_message_id'] + self.model.msgs.add_message(chat_id, update['message']) + self.model.msgs.remove_message(chat_id, msg_id) + self.refresh_msgs() except Exception: log.exception("Error happened in update_handler") diff --git a/tg/models/__init__.py b/tg/models/__init__.py index 2dc5a25..766037b 100644 --- a/tg/models/__init__.py +++ b/tg/models/__init__.py @@ -173,6 +173,7 @@ class MsgModel: self.tg = tg self.msgs = defaultdict(list) # Dict[int, list] self.current_msgs = defaultdict(int) + self.msg_ids = defaultdict(set) def next_msg(self, chat_id, step=1): current_msg = self.current_msgs[chat_id] @@ -200,6 +201,29 @@ class MsgModel: return True return False + def remove_message(self, chat_id, msg_id): + msg_set = self.msg_ids[chat_id] + if msg_id not in msg_set: + return False + log.info(f"removing msg {msg_id=}") + # FIXME: potential bottleneck, replace with constan time operation + self.msgs[chat_id] = [m for m in self.msgs[chat_id] if m['id'] != msg_id] + msg_set.remove(msg_id) + return True + + def add_message(self, chat_id, message): + msg_id = message['id'] + msg_set = self.msg_ids[chat_id] + if msg_id in msg_set: + return False + log.info(f"adding {msg_id=} {message}") + self.msgs[chat_id].append(message) + msg_set.add(msg_id) + return True + + def add_messages(self, chat_id, messages): + return any(self.add_message(chat_id, msg) for msg in messages) + def fetch_msgs(self, chat_id, offset=0, limit=10): if offset + limit < len(self.msgs[chat_id]): return sorted(self.msgs[chat_id], key=lambda d: d['id'])[::-1][offset:limit] @@ -218,11 +242,7 @@ class MsgModel: ) result.wait() - for msg in result.update['messages']: - self.msgs[chat_id].append(msg) - # TODO: - # if len(self.msgs[chat_id]) >= offset + limit: - # break + self.add_messages(chat_id, result.update['messages']) return sorted(self.msgs[chat_id], key=lambda d: d["id"])[::-1][ offset:limit