From 20766d2dae00527cac0c5d9694b48606cf93de2a Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Mon, 25 May 2020 13:33:22 -0400 Subject: [PATCH] Add whisper.added.filter signal handler --- src/app/chat/core.nim | 19 +++++++++++++++++-- src/app/chat/view.nim | 8 ++++---- src/app/chat/views/channels_list.nim | 20 +++++++++++++------- src/models/chat.nim | 2 +- src/models/chat/chat_item.nim | 21 +++++++++++++++++---- src/nim_status_client.nim | 3 ++- src/signals/core.nim | 7 +++++++ src/signals/types.nim | 19 ++++++++++++++++--- src/signals/whisperFilter.nim | 21 +++++++++++++++++++++ src/status/chat.nim | 13 ++++++++++--- 10 files changed, 108 insertions(+), 25 deletions(-) create mode 100644 src/signals/whisperFilter.nim diff --git a/src/app/chat/core.nim b/src/app/chat/core.nim index 7ea82107d1..a87128c539 100644 --- a/src/app/chat/core.nim +++ b/src/app/chat/core.nim @@ -2,7 +2,12 @@ import NimQml import json, eventemitter import ../../models/chat as chat_model import ../../signals/types +import ../../status/types as status_types import view +import chronicles + +logScope: + topics = "chat-controller" type ChatController* = ref object of SignalSubscriber view*: ChatsView @@ -36,7 +41,7 @@ proc load*(self: ChatController, chatId: string) = discard self.view.joinChat(chatId) self.view.setActiveChannelByIndex(0) -method onSignal(self: ChatController, data: Signal) = +proc handleMessage(self: ChatController, data: Signal) = var messageSignal = cast[MessageSignal](data) for c in messageSignal.chats: @@ -45,4 +50,14 @@ method onSignal(self: ChatController, data: Signal) = for message in messageSignal.messages: let chatMessage = message.toChatMessage() - self.view.pushMessage(message.chatId, chatMessage) + self.view.pushMessage(message.localChatId, chatMessage) + +proc handleWhisperFilter(self: ChatController, data: Signal) = + echo "Do something" + +method onSignal(self: ChatController, data: Signal) = + case data.signalType: + of SignalType.Message: handleMessage(self, data) + of SignalType.WhisperFilterAdded: handleWhisperFilter(self, data) + else: + warn "Unhandled signal received", signalType = data.signalType diff --git a/src/app/chat/view.nim b/src/app/chat/view.nim index 9ddc1bdec2..f2ff3b082f 100644 --- a/src/app/chat/view.nim +++ b/src/app/chat/view.nim @@ -40,8 +40,8 @@ QtObject: proc setActiveChannelByIndex*(self: ChatsView, index: int) {.slot.} = let selectedChannel = self.chats.getChannel(index) - if self.activeChannel == selectedChannel.name: return - self.activeChannel = selectedChannel.name + if self.activeChannel == selectedChannel.id: return + self.activeChannel = selectedChannel.id self.activeChannelChanged() proc setActiveChannel*(self: ChatsView, channel: string) = @@ -72,10 +72,10 @@ QtObject: proc joinChat*(self: ChatsView, channel: string): int {.slot.} = self.setActiveChannel(channel) if self.model.hasChannel(channel): - result = self.chats.chats.findByName(channel) + result = self.chats.chats.findById(channel) else: self.model.join(channel) - result = self.chats.addChatItemToList(ChatItem(name: channel)) + result = self.chats.addChatItemToList(ChatItem(id: channel, name: channel)) proc updateChat*(self: ChatsView, chat: ChatItem) = self.chats.updateChat(chat) diff --git a/src/app/chat/views/channels_list.nim b/src/app/chat/views/channels_list.nim index 1684e82ddd..727171f33e 100644 --- a/src/app/chat/views/channels_list.nim +++ b/src/app/chat/views/channels_list.nim @@ -59,10 +59,16 @@ QtObject: proc getChannel*(self: ChannelsList, index: int): ChatItem = self.chats[index] - proc updateChat*(self: ChannelsList, chat: ChatItem) = - var idx = self.chats.findByName(chat.name) - if idx > -1: - self.chats[idx] = chat - var x = self.createIndex(idx,0,nil) - var y = self.createIndex(idx,0,nil) - self.dataChanged(x, y, @[ChannelsRoles.Timestamp.int, ChannelsRoles.LastMessage.int, ChannelsRoles.UnreadMessages.int]) + proc upsertChannel(self: ChannelsList, channel: ChatItem): int = + let idx = self.chats.findById(channel.id) + if idx == -1: + result = self.addChatItemToList(channel) + else: + result = idx + + proc updateChat*(self: ChannelsList, channel: ChatItem) = + let idx = self.upsertChannel(channel) + self.chats[idx] = channel + let topLeft = self.createIndex(idx, 0, nil) + let bottomRight = self.createIndex(idx, 0, nil) + self.dataChanged(topLeft, bottomRight, @[ChannelsRoles.Timestamp.int, ChannelsRoles.LastMessage.int, ChannelsRoles.UnreadMessages.int]) diff --git a/src/models/chat.nim b/src/models/chat.nim index a506f13117..8788b55e91 100644 --- a/src/models/chat.nim +++ b/src/models/chat.nim @@ -38,7 +38,7 @@ proc join*(self: ChatModel, chatId: string) = let oneToOne = isOneToOneChat(chatId) - status_chat.loadFilters(chatId, oneToOne) + status_chat.loadFilters(chatId = chatId, oneToOne = oneToOne) status_chat.saveChat(chatId, oneToOne) status_chat.chatMessages(chatId) diff --git a/src/models/chat/chat_item.nim b/src/models/chat/chat_item.nim index 39fee3cc7a..2488b49fa8 100644 --- a/src/models/chat/chat_item.nim +++ b/src/models/chat/chat_item.nim @@ -1,7 +1,9 @@ import ../../signals/types type ChatItem* = ref object + id*: string name*: string + chatType*: ChatType lastMessage*: string timestamp*: int64 unviewedMessagesCount*: int @@ -13,15 +15,26 @@ proc newChatItem*(): ChatItem = result.timestamp = 0 result.unviewedMessagesCount = 0 -proc findByName*(self: seq[ChatItem], name: string): int = +proc findById*(self: seq[ChatItem], id: string): int = result = -1 + var idx = -1 for item in self: - inc result - if(item.name == name): break + inc idx + if(item.id == id): + result = idx + break + +proc chatName(chat: Chat): string = + case chat.chatType + of ChatType.OneToOne: result = chat.lastMessage.alias + of ChatType.Public: result = chat.name + of ChatType.PrivateGroupChat: result = "TODO: determine private group name" proc toChatItem*(chat: Chat): ChatItem = result = ChatItem( - name: chat.name, + id: chat.id, + name: chatName(chat), + chatType: chat.chatType, lastMessage: chat.lastMessage.text, timestamp: chat.timestamp, unviewedMessagesCount: chat.unviewedMessagesCount diff --git a/src/nim_status_client.nim b/src/nim_status_client.nim index 628d339f37..3f56d8816f 100644 --- a/src/nim_status_client.nim +++ b/src/nim_status_client.nim @@ -72,7 +72,8 @@ proc mainProc() = signalController.addSubscriber(SignalType.Wallet, wallet) signalController.addSubscriber(SignalType.Wallet, node) signalController.addSubscriber(SignalType.Message, chat) - + signalController.addSubscriber(SignalType.WhisperFilterAdded, chat) + engine.setRootContextProperty("signals", signalController.variant) appState.subscribe(proc () = diff --git a/src/signals/core.nim b/src/signals/core.nim index fcb09fa105..ad43fbd538 100644 --- a/src/signals/core.nim +++ b/src/signals/core.nim @@ -5,6 +5,7 @@ import json import types import messages import chronicles +import whisperFilter logScope: topics = "signals" @@ -51,12 +52,18 @@ QtObject: of "messages.new": signalType = SignalType.Message signal = messages.fromEvent(jsonSignal) + of "whisper.filter.added": + signalType = SignalType.WhisperFilterAdded + signal = whisperFilter.fromEvent(jsonSignal) of "wallet": signalType = SignalType.Wallet signal = WalletSignal(content: $jsonSignal) else: warn "Unhandled signal received", type = signalString signalType = SignalType.Unknown + return + + signal.signalType = signalType if not self.signalSubscribers.hasKey(signalType): self.signalSubscribers[signalType] = @[] diff --git a/src/signals/types.nim b/src/signals/types.nim index ca3a56ffd8..d76e721e5c 100644 --- a/src/signals/types.nim +++ b/src/signals/types.nim @@ -1,8 +1,10 @@ import chronicles +import ../status/types type SignalSubscriber* = ref object of RootObj type Signal* = ref object of RootObj + signalType*: SignalType type WalletSignal* = ref object of Signal content*: string @@ -37,9 +39,9 @@ method onSignal*(self: SignalSubscriber, data: Signal) {.base.} = error "onSignal must be overriden in controller. Signal is unhandled" type ChatType* = enum - ChatTypeOneToOne = 1, - ChatTypePublic = 2, - ChatTypePrivateGroupChat = 3 + OneToOne = 1, + Public = 2, + PrivateGroupChat = 3 type Chat* = object id*: string # ID is the id of the chat, for public chats it is the name e.g. status, for one-to-one is the hex encoded public key and for group chats is a random uuid appended with the hex encoded pk of the creator of the chat @@ -59,3 +61,14 @@ type Chat* = object type MessageSignal* = ref object of Signal messages*: seq[Message] chats*: seq[Chat] + +type Filter* = object + chatId*: string + symKeyId*: string + listen*: bool + filterId*: string + identity*: string + topic*: string + +type WhisperFilterSignal* = ref object of Signal + filters*: seq[Filter] \ No newline at end of file diff --git a/src/signals/whisperFilter.nim b/src/signals/whisperFilter.nim new file mode 100644 index 0000000000..daafede54b --- /dev/null +++ b/src/signals/whisperFilter.nim @@ -0,0 +1,21 @@ +import json +import types + +proc toFilter(jsonMsg: JsonNode): Filter = + result = Filter( + chatId: jsonMsg{"chatId"}.getStr, + symKeyId: jsonMsg{"symKeyId"}.getStr, + listen: jsonMsg{"listen"}.getBool, + filterId: jsonMsg{"filterId"}.getStr, + identity: jsonMsg{"identity"}.getStr, + topic: jsonMsg{"topic"}.getStr, + ) + +proc fromEvent*(event: JsonNode): Signal = + var signal:WhisperFilterSignal = WhisperFilterSignal() + + if event["event"]{"filters"} != nil: + for jsonMsg in event["event"]["filters"]: + signal.filters.add(jsonMsg.toFilter) + + result = signal \ No newline at end of file diff --git a/src/status/chat.nim b/src/status/chat.nim index 0c509df617..cbe2f749db 100644 --- a/src/status/chat.nim +++ b/src/status/chat.nim @@ -2,11 +2,18 @@ import core import json import utils -proc loadFilters*(chatId: string, oneToOne = false) = +proc loadFilters*(chatId: string, filterId: string = "", symKeyId: string = "", oneToOne: bool = false, identity: string = "", topic: string = "", discovery: bool = false, negotiated: bool = false, listen: bool = true) = discard callPrivateRPC("loadFilters".prefix, %* [ [{ - "ChatID": chatId, - "OneToOne": oneToOne + "ChatID": chatId, # identifier of the chat + "FilterID": filterId, # whisper filter id generated + "SymKeyID": symKeyId, # symmetric key id used for symmetric filters + "OneToOne": oneToOne, # if asymmetric encryption is used for this chat + "Identity": identity, # public key of the other recipient for non-public filters. + "Topic": topic, # whisper topic + "Discovery": discovery, + "Negotiated": negotiated, + "Listen": listen # whether we are actually listening for messages on this chat, or the filter is only created in order to be able to post on the topic }] ])