From 6abae85926fd0e352485cb500d0523f4d29f655c Mon Sep 17 00:00:00 2001 From: Nico Alt <nicoalt@posteo.org> Date: Wed, 11 Dec 2019 11:53:35 +0100 Subject: [PATCH] Automatically refresh contact list on added contact Also refactor socket_listener.py to make it more general. --- src/briar/api/models/contacts.py | 11 ++++++++++ src/briar/api/models/private_chat.py | 27 +++++++++++++++++-------- src/briar/api/models/socket_listener.py | 20 ++++++++---------- src/briar/gtk/containers/chat.py | 10 ++++----- src/briar/gtk/containers/main.py | 23 ++++++++++++++++++--- 5 files changed, 63 insertions(+), 28 deletions(-) diff --git a/src/briar/api/models/contacts.py b/src/briar/api/models/contacts.py index a706a90..6d4f6cf 100644 --- a/src/briar/api/models/contacts.py +++ b/src/briar/api/models/contacts.py @@ -15,6 +15,8 @@ class Contacts(Model): API_ENDPOINT = "contacts/" + _on_contact_added_callback = None + def add_pending(self, link, alias): url = urljoin(BASE_HTTP_URL, self.API_ENDPOINT + "add/" + "pending/") _post(url, headers=self._headers, json={"link": link, "alias": alias}) @@ -28,3 +30,12 @@ class Contacts(Model): url = urljoin(BASE_HTTP_URL, self.API_ENDPOINT + "add/" + "link/") request = _get(url, headers=self._headers).json() return request['link'] + + def watch_contacts(self, callback): + self._on_contact_added_callback = callback + self._api.socket_listener.watch("ContactAddedEvent", + self._on_contact_added) + + # pylint: disable=unused-argument + def _on_contact_added(self, event): + self._on_contact_added_callback() diff --git a/src/briar/api/models/private_chat.py b/src/briar/api/models/private_chat.py index 1d3351d..40caa46 100644 --- a/src/briar/api/models/private_chat.py +++ b/src/briar/api/models/private_chat.py @@ -15,16 +15,27 @@ class PrivateChat(Model): API_ENDPOINT = "messages/" - def get(self, contact_id): - url = urljoin(BASE_HTTP_URL, self.API_ENDPOINT + "/%i" % contact_id) + _contact_id = 0 + _on_message_received_callback = None + + def __init__(self, api, contact_id): + self._api = api + self._initialize_headers() + self._contact_id = contact_id + + def get(self): + url = urljoin(BASE_HTTP_URL, self.API_ENDPOINT + "/%d" % self._contact_id) request = _get(url, headers=self._headers) return request.json() - def watch_messages(self, contact_id, callback): - self._api.socket_listener.watch(callback, - "ConversationMessageReceivedEvent", - contact_id=contact_id) + def watch_messages(self, callback): + self._on_message_received_callback = callback + self._api.socket_listener.watch("ConversationMessageReceivedEvent", + self._on_message_received) + + def _on_message_received(self, event): + self._on_message_received_callback(event['data']) - def send(self, contact_id, message): - url = urljoin(BASE_HTTP_URL, self.API_ENDPOINT + "/%i" % contact_id) + def send(self, message): + url = urljoin(BASE_HTTP_URL, self.API_ENDPOINT + "/%i" % self._contact_id) _post(url, headers=self._headers, json={"text": message}) diff --git a/src/briar/api/models/socket_listener.py b/src/briar/api/models/socket_listener.py index 93808a0..c5b39ee 100644 --- a/src/briar/api/models/socket_listener.py +++ b/src/briar/api/models/socket_listener.py @@ -12,26 +12,22 @@ from briar.api.constants import WEBSOCKET_URL from briar.api.model import Model -# TODO: Make more general; currently very specific to private messages -# TODO: remove pylint disable once we have more methods class SocketListener(Model): # pylint: disable=too-few-public-methods - def watch(self, callback, event, contact_id="0"): + def watch(self, event, callback): websocket_thread = Thread(target=self._start_watch_loop, - args=(callback, event, contact_id), + args=(event, callback), daemon=True) websocket_thread.start() - def _start_watch_loop(self, callback, event, contact_id="0"): + def _start_watch_loop(self, event, callback): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) - loop.create_task(self._start_websocket(callback, event, contact_id)) + loop.create_task(self._start_websocket(event, callback)) loop.run_forever() loop.close() - # TODO: use contact id - # pylint: disable=unused-argument - async def _start_websocket(self, callback, event, contact_id="0"): + async def _start_websocket(self, event, callback): async with websockets.connect(WEBSOCKET_URL) as websocket: await websocket.send(self._api.auth_token) await self._watch_messages(websocket, event, callback) @@ -39,10 +35,10 @@ class SocketListener(Model): # pylint: disable=too-few-public-methods async def _watch_messages(self, websocket, event, callback): while not websocket.closed and not\ asyncio.get_event_loop().is_closed(): - message = await websocket.recv() - message = json.loads(message) + message_json = await websocket.recv() + message = json.loads(message_json) if message['name'] == event: - callback(message['data']) + callback(message) if not asyncio.get_event_loop().is_closed(): asyncio.get_event_loop().create_task( self._watch_messages(websocket, event, callback)) diff --git a/src/briar/gtk/containers/chat.py b/src/briar/gtk/containers/chat.py index 12b7103..b2e00b0 100644 --- a/src/briar/gtk/containers/chat.py +++ b/src/briar/gtk/containers/chat.py @@ -28,12 +28,12 @@ class ChatContainer(Container): chat_entry.connect("key-press-event", self._key_pressed) def _load_content(self): - private_chat = PrivateChat(self._api) - messages_list = private_chat.get(self._contact_id) + private_chat = PrivateChat(self._api, self._contact_id) + messages_list = private_chat.get() self._messages_list_box = self.builder.get_object("messages_list") for message in messages_list: self._add_message(message["text"], message["local"]) - private_chat.watch_messages(self._contact_id, self._add_message_async) + private_chat.watch_messages(self._add_message_async) def _add_message(self, message, local): message_label = Gtk.Label(message) @@ -52,8 +52,8 @@ class ChatContainer(Container): return chat_entry = self.builder.get_object("chat_entry") message = chat_entry.get_text() - private_chat = PrivateChat(self._api) - private_chat.send(self._contact_id, message) + private_chat = PrivateChat(self._api, self._contact_id) + private_chat.send(message) self._add_message(message, True) chat_entry.set_text("") diff --git a/src/briar/gtk/containers/main.py b/src/briar/gtk/containers/main.py index 5cdadcc..af6c04e 100644 --- a/src/briar/gtk/containers/main.py +++ b/src/briar/gtk/containers/main.py @@ -25,16 +25,33 @@ class MainContainer(Container): self.builder.connect_signals(self) def _load_content(self): - contacts = Contacts(self._api) - contacts_list = contacts.get() + self._contacts = Contacts(self._api) + self._load_contacts() + self._contacts.watch_contacts(self._refresh_contacts_async) + + def _load_contacts(self): + contacts_list = self._contacts.get() contacts_list_box = self.builder.get_object("contacts_list") for contact in contacts_list: - contact_button = Gtk.Button(contact["author"]["name"]) + contact_button = Gtk.Button(contact["alias"]) contact_button.connect("clicked", MainContainer._contact_clicked, contact["contactId"]) contact_button.show() contacts_list_box.add(contact_button) + def _refresh_contacts_async(self): + GLib.idle_add(self._refresh_contacts) + + def _refresh_contacts(self): + self._clear_contact_list() + self._load_contacts() + + def _clear_contact_list(self): + contacts_list_box = self.builder.get_object("contacts_list") + contacts_list_box_children = contacts_list_box.get_children() + for child in contacts_list_box_children: + contacts_list_box.remove(child) + # pylint: disable=unused-argument @staticmethod def _contact_clicked(widget, contact_id): -- GitLab