diff --git a/meshchat.py b/meshchat.py index 580c8b1..fdee616 100644 --- a/meshchat.py +++ b/meshchat.py @@ -139,6 +139,52 @@ class GroupChatDataProvider(GroupDataProviderInterface): return members + # gets messages of a group + def get_messages(self, group_destination_hash: bytes, order: str | None, limit: int | None, after_id: int | None): + + # find group + group = self.find_group(group_destination_hash) + if group is None: + raise Exception("Group not found") + + # build group messages database query + query = database.GroupMessage.select().where(database.GroupMessage.group_destination_hash == group.destination_hash) + + # limit results + if limit is not None: + query = query.limit(limit) + + # order results + if order == "asc": + + # order asc + query = query.order_by(database.GroupMessage.id.asc()) + + # only results after provided id + if after_id is not None: + query = query.where(database.GroupMessage.id > int(after_id)) + + elif order == "desc": + + # order desc + query = query.order_by(database.GroupMessage.id.desc()) + + # only results before provided id + if after_id is not None: + query = query.where(database.GroupMessage.id < int(after_id)) + + # process messages + messages = [] + for message in query: + messages.append({ + "id": message.id, + "member_identity_hash": message.member_identity_hash, + "content": message.content, + "created_at": message.created_at, + }) + + return messages + # save a message sent to the group by the provided identity def on_message_received(self, group_destination_hash: bytes, identity_hash: bytes, data: dict): diff --git a/src/backend/group_chat/group_chat_client.py b/src/backend/group_chat/group_chat_client.py index 60b9581..cfb11fa 100644 --- a/src/backend/group_chat/group_chat_client.py +++ b/src/backend/group_chat/group_chat_client.py @@ -103,6 +103,14 @@ class GroupChatClient: "limit": limit, }).encode("utf-8")) + # get group messages + async def get_messages(self, order: str, limit: int, after_id: int | None): + return await self.request("/api/v1/messages", data=json.dumps({ + "order": order, + "limit": limit, + "after_id": after_id, + }).encode("utf-8")) + # send message async def send_message(self, content: str): return await self.request("/api/v1/messages/send", data=json.dumps({ @@ -128,6 +136,7 @@ async def main(): print(await group_chat_client.get_info()) print(await group_chat_client.get_members(page=1, limit=10)) print(await group_chat_client.send_message("hello world!")) + print(await group_chat_client.get_messages(order="desc", limit=1, after_id=None)) print(await group_chat_client.leave()) print(await group_chat_client.get_info()) diff --git a/src/backend/group_chat/group_chat_server.py b/src/backend/group_chat/group_chat_server.py index 02b53e1..be451d2 100644 --- a/src/backend/group_chat/group_chat_server.py +++ b/src/backend/group_chat/group_chat_server.py @@ -27,6 +27,10 @@ class GroupDataProviderInterface: def get_members(self, group_destination_hash: bytes, page: int | None, limit: int | None): raise Exception("Not Implemented") + # gets messages of a group + def get_messages(self, group_destination_hash: bytes, order: str | None, limit: int | None, after_id: int | None): + raise Exception("Not Implemented") + # save a message sent to the group by the provided identity def on_message_received(self, group_destination_hash: bytes, identity_hash: bytes, data: dict): raise Exception("Not Implemented") @@ -58,6 +62,7 @@ class GroupChatServer: self.group_destination.register_request_handler(path="/api/v1/join", response_generator=self.on_received_api_v1_join_request, allow=RNS.Destination.ALLOW_ALL) self.group_destination.register_request_handler(path="/api/v1/leave", response_generator=self.on_received_api_v1_leave_request, allow=RNS.Destination.ALLOW_ALL) self.group_destination.register_request_handler(path="/api/v1/members", response_generator=self.on_received_api_v1_members_request, allow=RNS.Destination.ALLOW_ALL) + self.group_destination.register_request_handler(path="/api/v1/messages", response_generator=self.on_received_api_v1_messages_request, allow=RNS.Destination.ALLOW_ALL) self.group_destination.register_request_handler(path="/api/v1/messages/send", response_generator=self.on_received_api_v1_messages_send_request, allow=RNS.Destination.ALLOW_ALL) # announce group destination @@ -171,6 +176,47 @@ class GroupChatServer: "members": group_members, }).encode("utf-8") + # /api/v1/messages + def on_received_api_v1_messages_request(self, path, data: bytes | None, request_id, remote_identity: RNS.Identity | None, requested_at): + + # ensure user has identified + if remote_identity is None: + return self.identity_not_provided_error_response() + + # ensure user is a member + if not self.data_provider.is_member(self.group_destination.hash, remote_identity.hash): + return self.error_response("You are not a member of this group") + + # attempt to parse data as json + order = None + limit = None + after_id = None + if data is not None: + try: + json_data = json.loads(data.decode("utf-8")) + order = json_data["order"] + limit = json_data["limit"] + after_id = json_data["after_id"] + except: + return self.request_json_parsing_error_response() + + # get group messages + database_group_messages = self.data_provider.get_messages(self.group_destination.hash, order, limit, after_id) + + # process group messages + group_messages = [] + for database_group_message in database_group_messages: + group_messages.append({ + "id": database_group_message["id"], + "member_identity_hash": database_group_message["member_identity_hash"], + "content": database_group_message["content"], + "created_at": database_group_message["created_at"], + }) + + return json.dumps({ + "messages": group_messages, + }).encode("utf-8") + # /api/v1/messages/send def on_received_api_v1_messages_send_request(self, path, data: bytes | None, request_id, remote_identity: RNS.Identity | None, requested_at):