refactor(@desktop/chat-communities): asynchronous fetching messages
This commit is contained in:
parent
d8dea2dc58
commit
eca74532ac
|
@ -6,6 +6,7 @@ import ../../app_service/service/contacts/service as contacts_service
|
|||
import ../../app_service/service/language/service as language_service
|
||||
import ../../app_service/service/chat/service as chat_service
|
||||
import ../../app_service/service/community/service as community_service
|
||||
import ../../app_service/service/message/service as message_service
|
||||
import ../../app_service/service/token/service as token_service
|
||||
import ../../app_service/service/transaction/service as transaction_service
|
||||
import ../../app_service/service/collectible/service as collectible_service
|
||||
|
@ -22,9 +23,11 @@ import ../core/local_account_settings
|
|||
import ../../app_service/service/profile/service as profile_service
|
||||
import ../../app_service/service/settings/service as settings_service
|
||||
import ../../app_service/service/about/service as about_service
|
||||
|
||||
import ../modules/startup/module as startup_module
|
||||
import ../modules/main/module as main_module
|
||||
|
||||
import ../core/local_account_settings
|
||||
import ../core/global_singleton
|
||||
|
||||
#################################################
|
||||
|
@ -70,6 +73,7 @@ type
|
|||
contactsService: contacts_service.Service
|
||||
chatService: chat_service.Service
|
||||
communityService: community_service.Service
|
||||
messageService: message_service.Service
|
||||
tokenService: token_service.Service
|
||||
transactionService: transaction_service.Service
|
||||
collectibleService: collectible_service.Service
|
||||
|
@ -136,12 +140,14 @@ proc newAppController*(appService: AppService): AppController =
|
|||
result.contactsService = contacts_service.newService(appService.status.events, appService.threadpool)
|
||||
result.chatService = chat_service.newService()
|
||||
result.communityService = community_service.newService(result.chatService)
|
||||
result.tokenService = token_service.newService(appService.status.events, appService.threadpool, result.settingService, result.settingsService)
|
||||
result.messageService = message_service.newService(appService.status.events, appService.threadpool)
|
||||
result.tokenService = token_service.newService(appService.status.events, appService.threadpool, result.settingService,
|
||||
result.settingsService)
|
||||
result.collectibleService = collectible_service.newService(result.settingService)
|
||||
result.walletAccountService = wallet_account_service.newService(
|
||||
appService.status.events, result.settingService, result.tokenService
|
||||
)
|
||||
result.transactionService = transaction_service.newService(appService.status.events, appService.threadpool, result.walletAccountService)
|
||||
result.walletAccountService = wallet_account_service.newService(appService.status.events, result.settingService,
|
||||
result.tokenService)
|
||||
result.transactionService = transaction_service.newService(appService.status.events, appService.threadpool,
|
||||
result.walletAccountService)
|
||||
result.bookmarkService = bookmark_service.newService()
|
||||
result.profileService = profile_service.newService()
|
||||
result.aboutService = about_service.newService()
|
||||
|
@ -173,6 +179,7 @@ proc newAppController*(appService: AppService): AppController =
|
|||
result.accountsService,
|
||||
result.chatService,
|
||||
result.communityService,
|
||||
result.messageService,
|
||||
result.tokenService,
|
||||
result.transactionService,
|
||||
result.collectibleService,
|
||||
|
@ -288,7 +295,7 @@ proc load(self: AppController) =
|
|||
self.buildAndRegisterUserProfile()
|
||||
|
||||
# load main module
|
||||
self.mainModule.load(self.chatService, self.communityService)
|
||||
self.mainModule.load(self.appService.status.events, self.chatService, self.communityService, self.messageService)
|
||||
|
||||
proc userLoggedIn*(self: AppController) =
|
||||
#################################################
|
||||
|
|
|
@ -5,6 +5,7 @@ import io_interface
|
|||
|
||||
import ../../../../app_service/service/chat/service as chat_service
|
||||
import ../../../../app_service/service/community/service as community_service
|
||||
import ../../../../app_service/service/message/service as message_service
|
||||
|
||||
export controller_interface
|
||||
|
||||
|
@ -17,16 +18,19 @@ type
|
|||
activeSubItemId: string
|
||||
chatService: chat_service.ServiceInterface
|
||||
communityService: community_service.ServiceInterface
|
||||
messageService: message_service.Service
|
||||
|
||||
proc newController*(delegate: io_interface.AccessInterface, id: string, isCommunity: bool,
|
||||
chatService: chat_service.ServiceInterface,
|
||||
communityService: community_service.ServiceInterface): Controller =
|
||||
communityService: community_service.ServiceInterface,
|
||||
messageService: message_service.Service): Controller =
|
||||
result = Controller()
|
||||
result.delegate = delegate
|
||||
result.id = id
|
||||
result.isCommunityModule = isCommunity
|
||||
result.chatService = chatService
|
||||
result.communityService = communityService
|
||||
result.messageService = messageService
|
||||
|
||||
method delete*(self: Controller) =
|
||||
discard
|
||||
|
@ -60,6 +64,11 @@ method setActiveItemSubItem*(self: Controller, itemId: string, subItemId: string
|
|||
self.activeItemId = itemId
|
||||
self.activeSubItemId = subItemId
|
||||
|
||||
if(self.activeSubItemId.len > 0):
|
||||
self.messageService.loadInitialMessagesForChat(self.activeSubItemId)
|
||||
else:
|
||||
self.messageService.loadInitialMessagesForChat(self.activeItemId)
|
||||
|
||||
# We need to take other actions here like notify status go that unviewed mentions count is updated and so...
|
||||
|
||||
self.delegate.activeItemSubItemSet(self.activeItemId, self.activeSubItemId)
|
|
@ -2,29 +2,39 @@ import controller_interface
|
|||
import io_interface
|
||||
|
||||
import ../../../../../app_service/service/community/service as community_service
|
||||
import ../../../../../app_service/service/message/service as message_service
|
||||
|
||||
import eventemitter
|
||||
import status/[signals]
|
||||
|
||||
export controller_interface
|
||||
|
||||
type
|
||||
Controller* = ref object of controller_interface.AccessInterface
|
||||
delegate: io_interface.AccessInterface
|
||||
events: EventEmitter
|
||||
id: string
|
||||
isCommunityModule: bool
|
||||
communityService: community_service.ServiceInterface
|
||||
messageService: message_service.Service
|
||||
|
||||
proc newController*(delegate: io_interface.AccessInterface, id: string, isCommunity: bool,
|
||||
communityService: community_service.ServiceInterface): Controller =
|
||||
proc newController*(delegate: io_interface.AccessInterface, events: EventEmitter, id: string, isCommunity: bool,
|
||||
communityService: community_service.ServiceInterface, messageService: message_service.Service): Controller =
|
||||
result = Controller()
|
||||
result.delegate = delegate
|
||||
result.events = events
|
||||
result.id = id
|
||||
result.isCommunityModule = isCommunity
|
||||
result.communityService = communityService
|
||||
result.messageService = messageService
|
||||
|
||||
method delete*(self: Controller) =
|
||||
discard
|
||||
|
||||
method init*(self: Controller) =
|
||||
discard
|
||||
self.events.on(SIGNAL_MESSAGES_LOADED) do(e:Args):
|
||||
let args = MessagesLoadedArgs(e)
|
||||
echo "RECEIVED MESSAGES ASYNC: ", repr(args)
|
||||
|
||||
method getId*(self: Controller): string =
|
||||
return self.id
|
||||
|
|
|
@ -1,21 +1,77 @@
|
|||
import NimQml
|
||||
type
|
||||
ContentType* {.pure.} = enum
|
||||
FetchMoreMessagesButton = -2
|
||||
ChatIdentifier = -1
|
||||
Unknown = 0
|
||||
Message = 1
|
||||
Sticker = 2
|
||||
Status = 3
|
||||
Emoji = 4
|
||||
Transaction = 5
|
||||
Group = 6
|
||||
Image = 7
|
||||
Audio = 8
|
||||
Community = 9
|
||||
Gap = 10
|
||||
Edit = 11
|
||||
|
||||
QtObject:
|
||||
type
|
||||
Item* = ref object of QObject
|
||||
|
||||
proc setup(self: Item) =
|
||||
self.QObject.setup
|
||||
type
|
||||
Item* = object
|
||||
id: string
|
||||
`from`: string
|
||||
alias: string
|
||||
identicon: string
|
||||
seen: bool
|
||||
outgoingStatus: string
|
||||
text: string
|
||||
stickerHash: string
|
||||
stickerPack: int
|
||||
image: string
|
||||
gapFrom: int64
|
||||
gapTo: int64
|
||||
timestamp: int64
|
||||
contentType: ContentType
|
||||
messageType: int
|
||||
|
||||
proc delete*(self: Item) =
|
||||
self.QObject.delete
|
||||
proc initItem*(id, `from`, alias, identicon, outgoingStatus, text: string, seen: bool, timestamp: int64,
|
||||
contentType: ContentType, messageType: int): Item =
|
||||
result.id = id
|
||||
result.`from` = `from`
|
||||
result.alias = alias
|
||||
result.identicon = identicon
|
||||
result.seen = seen
|
||||
result.outgoingStatus = outgoingStatus
|
||||
result.text = text
|
||||
result.timestamp = timestamp
|
||||
result.contentType = contentType
|
||||
result.messageType = messageType
|
||||
|
||||
proc newItem*(): Item =
|
||||
new(result, delete)
|
||||
result.setup()
|
||||
proc id*(self: Item): string {.inline.} =
|
||||
self.id
|
||||
|
||||
proc id*(self: Item): string {.slot.} =
|
||||
self.id
|
||||
proc `from`*(self: Item): string {.inline.} =
|
||||
self.`from`
|
||||
|
||||
QtProperty[string] id:
|
||||
read = id
|
||||
proc alias*(self: Item): string {.inline.} =
|
||||
self.alias
|
||||
|
||||
proc identicon*(self: Item): string {.inline.} =
|
||||
self.identicon
|
||||
|
||||
proc outgoingStatus*(self: Item): string {.inline.} =
|
||||
self.outgoingStatus
|
||||
|
||||
proc text*(self: Item): string {.inline.} =
|
||||
self.text
|
||||
|
||||
proc seen*(self: Item): bool {.inline.} =
|
||||
self.seen
|
||||
|
||||
proc timestamp*(self: Item): int64 {.inline.} =
|
||||
self.timestamp
|
||||
|
||||
proc contentType*(self: Item): ContentType {.inline.} =
|
||||
self.contentType
|
||||
|
||||
proc messageType*(self: Item): int {.inline.} =
|
||||
self.messageType
|
|
@ -1,17 +1,101 @@
|
|||
import NimQml
|
||||
import NimQml, Tables, strutils, strformat
|
||||
|
||||
import item
|
||||
|
||||
type
|
||||
ModelRole {.pure.} = enum
|
||||
Id = UserRole + 1
|
||||
From
|
||||
Alias
|
||||
Identicon
|
||||
Seen
|
||||
OutgoingStatus
|
||||
Text
|
||||
Timestamp
|
||||
ContentType
|
||||
MessageType
|
||||
# StickerHash
|
||||
# StickerPack
|
||||
# Image
|
||||
# GapFrom
|
||||
# GapTo
|
||||
|
||||
QtObject:
|
||||
type
|
||||
type
|
||||
Model* = ref object of QAbstractListModel
|
||||
sections: seq[Item]
|
||||
items: seq[Item]
|
||||
|
||||
proc setup(self: Model) =
|
||||
self.QAbstractListModel.setup
|
||||
|
||||
proc delete*(self: Model) =
|
||||
proc delete(self: Model) =
|
||||
self.items = @[]
|
||||
self.QAbstractListModel.delete
|
||||
|
||||
proc setup(self: Model) =
|
||||
self.QAbstractListModel.setup
|
||||
|
||||
proc newModel*(): Model =
|
||||
new(result, delete)
|
||||
result.setup
|
||||
result.setup
|
||||
|
||||
method rowCount(self: Model, index: QModelIndex = nil): int =
|
||||
return self.items.len
|
||||
|
||||
method roleNames(self: Model): Table[int, string] =
|
||||
{
|
||||
ModelRole.Id.int:"id",
|
||||
ModelRole.From.int:"from",
|
||||
ModelRole.Alias.int:"alias",
|
||||
ModelRole.Identicon.int:"identicon",
|
||||
ModelRole.Seen.int:"seen",
|
||||
ModelRole.OutgoingStatus.int:"outgoingStatus",
|
||||
ModelRole.Text.int:"text",
|
||||
ModelRole.Timestamp.int:"timestamp",
|
||||
ModelRole.ContentType.int:"contentType",
|
||||
ModelRole.MessageType.int:"messageType",
|
||||
# ModelRole.StickerHash.int:"stickerHash",
|
||||
# ModelRole.StickerPack.int:"stickerPack",
|
||||
# ModelRole.Image.int:"image",
|
||||
# ModelRole.GapFrom.int:"gapFrom",
|
||||
# ModelRole.GapTo.int:"gapTo"
|
||||
}.toTable
|
||||
|
||||
method data(self: Model, index: QModelIndex, role: int): QVariant =
|
||||
if (not index.isValid):
|
||||
return
|
||||
|
||||
if (index.row < 0 or index.row >= self.items.len):
|
||||
return
|
||||
|
||||
let item = self.items[index.row]
|
||||
let enumRole = role.ModelRole
|
||||
|
||||
case enumRole:
|
||||
of ModelRole.Id:
|
||||
result = newQVariant(item.id)
|
||||
of ModelRole.From:
|
||||
result = newQVariant(item.`from`)
|
||||
of ModelRole.Alias:
|
||||
result = newQVariant(item.alias)
|
||||
of ModelRole.Identicon:
|
||||
result = newQVariant(item.identicon)
|
||||
of ModelRole.Seen:
|
||||
result = newQVariant(item.seen)
|
||||
of ModelRole.OutgoingStatus:
|
||||
result = newQVariant(item.outgoingStatus)
|
||||
of ModelRole.Text:
|
||||
result = newQVariant(item.text)
|
||||
of ModelRole.Timestamp:
|
||||
result = newQVariant(item.timestamp)
|
||||
of ModelRole.ContentType:
|
||||
result = newQVariant(item.contentType.int)
|
||||
of ModelRole.MessageType:
|
||||
result = newQVariant(item.messageType)
|
||||
# of ModelRole.StickerHash:
|
||||
# result = newQVariant(item.stickerHash)
|
||||
# of ModelRole.StickerPack:
|
||||
# result = newQVariant(item.stickerPack)
|
||||
# of ModelRole.Image:
|
||||
# result = newQVariant(item.image)
|
||||
# of ModelRole.GapFrom:
|
||||
# result = newQVariant(item.gapFrom)
|
||||
# of ModelRole.GapTo:
|
||||
# result = newQVariant(item.gapTo)
|
|
@ -6,6 +6,9 @@ import ../../../../core/global_singleton
|
|||
|
||||
import ../../../../../app_service/service/chat/service as chat_service
|
||||
import ../../../../../app_service/service/community/service as community_service
|
||||
import ../../../../../app_service/service/message/service as message_service
|
||||
|
||||
import eventemitter
|
||||
|
||||
export io_interface
|
||||
|
||||
|
@ -17,14 +20,14 @@ type
|
|||
controller: controller.AccessInterface
|
||||
moduleLoaded: bool
|
||||
|
||||
proc newModule*(delegate: delegate_interface.AccessInterface, id: string, isCommunity: bool,
|
||||
chatService: chat_service.Service, communityService: community_service.Service):
|
||||
proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, id: string, isCommunity: bool,
|
||||
chatService: chat_service.Service, communityService: community_service.Service, messageService: message_service.Service):
|
||||
Module =
|
||||
result = Module()
|
||||
result.delegate = delegate
|
||||
result.view = view.newView(result)
|
||||
result.viewVariant = newQVariant(result.view)
|
||||
result.controller = controller.newController(result, id, isCommunity, communityService)
|
||||
result.controller = controller.newController(result, events, id, isCommunity, communityService, messageService)
|
||||
result.moduleLoaded = false
|
||||
|
||||
method delete*(self: Module) =
|
||||
|
|
|
@ -10,6 +10,9 @@ import users/module as users_module
|
|||
|
||||
import ../../../../app_service/service/chat/service as chat_service
|
||||
import ../../../../app_service/service/community/service as community_service
|
||||
import ../../../../app_service/service/message/service as message_service
|
||||
|
||||
import eventemitter
|
||||
|
||||
export io_interface
|
||||
|
||||
|
@ -27,18 +30,20 @@ type
|
|||
usersModule: users_module.AccessInterface
|
||||
moduleLoaded: bool
|
||||
|
||||
proc newModule*(delegate: delegate_interface.AccessInterface, id: string, isCommunity: bool,
|
||||
chatService: chat_service.Service, communityService: community_service.Service):
|
||||
proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitter, id: string, isCommunity: bool,
|
||||
chatService: chat_service.Service, communityService: community_service.Service,
|
||||
messageService: message_service.Service):
|
||||
Module =
|
||||
result = Module()
|
||||
result.delegate = delegate
|
||||
result.view = view.newView(result)
|
||||
result.viewVariant = newQVariant(result.view)
|
||||
result.controller = controller.newController(result, id, isCommunity, chatService, communityService)
|
||||
result.controller = controller.newController(result, id, isCommunity, chatService, communityService, messageService)
|
||||
result.moduleLoaded = false
|
||||
|
||||
result.inputAreaModule = input_area_module.newModule(result, id, isCommunity, chatService, communityService)
|
||||
result.messagesModule = messages_module.newModule(result, id, isCommunity, chatService, communityService)
|
||||
result.messagesModule = messages_module.newModule(result, events, id, isCommunity, chatService, communityService,
|
||||
messageService)
|
||||
result.usersModule = users_module.newModule(result, id, isCommunity, chatService, communityService)
|
||||
|
||||
method delete*(self: Module) =
|
||||
|
@ -62,7 +67,7 @@ proc buildChatUI(self: Module) =
|
|||
if(selectedItemId.len == 0):
|
||||
selectedItemId = item.id
|
||||
|
||||
self.controller.setActiveItemSubItem(selectedItemId, "")
|
||||
self.setActiveItemSubItem(selectedItemId, "")
|
||||
|
||||
proc buildCommunityUI(self: Module) =
|
||||
var selectedItemId = ""
|
||||
|
|
|
@ -44,6 +44,13 @@ method delete*(self: Controller) =
|
|||
discard
|
||||
|
||||
method init*(self: Controller) =
|
||||
self.events.on("mailserverAvailable") do(e:Args):
|
||||
echo "MAILSERVER AVAILABLE: ", repr(e)
|
||||
# We need to take some actions here. This is the only pace where "mailserverAvailable" signal should be handled.
|
||||
# Do the following, if we really need that.
|
||||
# requestAllHistoricMessagesResult
|
||||
# requestMissingCommunityInfos
|
||||
|
||||
if(defined(macosx)):
|
||||
let account = self.accountsService.getLoggedInAccount()
|
||||
singletonInstance.localAccountSettings.setFileName(account.name)
|
||||
|
|
|
@ -11,6 +11,7 @@ import profile_section/module as profile_section_module
|
|||
import ../../../app_service/service/keychain/service as keychain_service
|
||||
import ../../../app_service/service/chat/service as chat_service
|
||||
import ../../../app_service/service/community/service as community_service
|
||||
import ../../../app_service/service/message/service as message_service
|
||||
import ../../../app_service/service/token/service as token_service
|
||||
import ../../../app_service/service/transaction/service as transaction_service
|
||||
import ../../../app_service/service/collectible/service as collectible_service
|
||||
|
@ -20,7 +21,6 @@ import ../../../app_service/service/bookmarks/service as bookmark_service
|
|||
import ../../../app_service/service/dapp_permissions/service as dapp_permissions_service
|
||||
import ../../../app_service/service/provider/service as provider_service
|
||||
|
||||
import eventemitter
|
||||
import ../../../app_service/service/profile/service as profile_service
|
||||
import ../../../app_service/service/accounts/service as accounts_service
|
||||
import ../../../app_service/service/settings/service as settings_service
|
||||
|
@ -30,6 +30,8 @@ import ../../../app_service/service/language/service as language_service
|
|||
import ../../../app_service/service/mnemonic/service as mnemonic_service
|
||||
import ../../../app_service/service/privacy/service as privacy_service
|
||||
|
||||
import eventemitter
|
||||
|
||||
export io_interface
|
||||
|
||||
type
|
||||
|
@ -52,6 +54,7 @@ proc newModule*[T](
|
|||
accountsService: accounts_service.ServiceInterface,
|
||||
chatService: chat_service.Service,
|
||||
communityService: community_service.Service,
|
||||
messageService: message_service.Service,
|
||||
tokenService: token_service.Service,
|
||||
transactionService: transaction_service.Service,
|
||||
collectibleService: collectible_service.Service,
|
||||
|
@ -77,7 +80,8 @@ proc newModule*[T](
|
|||
result.moduleLoaded = false
|
||||
|
||||
# Submodules
|
||||
result.chatSectionModule = chat_section_module.newModule(result, "chat", false, chatService, communityService)
|
||||
result.chatSectionModule = chat_section_module.newModule(result, events, "chat", false, chatService, communityService,
|
||||
messageService)
|
||||
result.communitySectionsModule = initOrderedTable[string, chat_section_module.AccessInterface]()
|
||||
result.walletSectionModule = wallet_section_module.newModule[Module[T]](result, events, tokenService,
|
||||
transactionService, collectible_service, walletAccountService, settingService)
|
||||
|
@ -98,8 +102,8 @@ method delete*[T](self: Module[T]) =
|
|||
self.viewVariant.delete
|
||||
self.controller.delete
|
||||
|
||||
method load*[T](self: Module[T], chatService: chat_service.Service,
|
||||
communityService: community_service.Service) =
|
||||
method load*[T](self: Module[T], events: EventEmitter, chatService: chat_service.Service,
|
||||
communityService: community_service.Service, messageService: message_service.Service) =
|
||||
singletonInstance.engine.setRootContextProperty("mainModule", self.viewVariant)
|
||||
self.controller.init()
|
||||
self.view.load()
|
||||
|
@ -107,7 +111,8 @@ method load*[T](self: Module[T], chatService: chat_service.Service,
|
|||
# Create community modules here, since we don't know earlier how many communities we have.
|
||||
let communities = self.controller.getCommunities()
|
||||
for c in communities:
|
||||
self.communitySectionsModule[c.id] = chat_section_module.newModule(self, c.id, true, chatService, communityService)
|
||||
self.communitySectionsModule[c.id] = chat_section_module.newModule(self, events, c.id, true, chatService,
|
||||
communityService, messageService)
|
||||
|
||||
var activeSection: Item
|
||||
var activeSectionId = singletonInstance.localAccountSensitiveSettings.getActiveSection()
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import ../../../../app_service/service/chat/service as chat_service
|
||||
import ../../../../app_service/service/community/service as community_service
|
||||
import ../../../../app_service/service/message/service as message_service
|
||||
|
||||
import eventemitter
|
||||
|
||||
method delete*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method load*(self: AccessInterface, chatService: chat_service.Service, communityService: community_service.Service,)
|
||||
method load*(self: AccessInterface, events: EventEmitter, chatService: chat_service.Service, communityService: community_service.Service,
|
||||
messageService: message_service.Service)
|
||||
{.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
include ../../common/json_utils
|
||||
include ../../tasks/common
|
||||
|
||||
#################################################
|
||||
# Async load messages
|
||||
#################################################
|
||||
type
|
||||
AsyncFetchChatMessagesTaskArg = ref object of QObjectTaskArg
|
||||
chatId: string
|
||||
msgCursor: string
|
||||
pinnedMsgCursor: string
|
||||
limit: int
|
||||
|
||||
const asyncFetchChatMessagesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[AsyncFetchChatMessagesTaskArg](argEncoded)
|
||||
|
||||
# handle messages
|
||||
var messagesArr: JsonNode
|
||||
var messagesCursor: string
|
||||
let msgsResponse = status_go.fetchMessages(arg.chatId, arg.msgCursor, arg.limit)
|
||||
discard msgsResponse.result.getProp("cursor", messagesCursor)
|
||||
discard msgsResponse.result.getProp("messages", messagesArr)
|
||||
|
||||
# handle pinned messages
|
||||
var pinnedMsgArr: JsonNode
|
||||
var pinnedMsgCursor: string
|
||||
let pinnedMsgsResponse = status_go.fetchPinnedMessages(arg.chatId, arg.pinnedMsgCursor, arg.limit)
|
||||
discard pinnedMsgsResponse.result.getProp("cursor", pinnedMsgCursor)
|
||||
discard pinnedMsgsResponse.result.getProp("pinnedMessages", pinnedMsgArr)
|
||||
|
||||
# handle reactions
|
||||
var reactionsArr: JsonNode
|
||||
# messages and reactions are using the same cursor
|
||||
let rResponse = status_go.fetchReactions(arg.chatId, arg.msgCursor, arg.limit)
|
||||
reactionsArr = rResponse.result
|
||||
|
||||
let responseJson = %*{
|
||||
"chatId": arg.chatId,
|
||||
"messages": messagesArr,
|
||||
"messagesCursor": messagesCursor,
|
||||
"pinnedMessages": pinnedMsgArr,
|
||||
"pinnedMessagesCursor": pinnedMsgCursor,
|
||||
"reactions": reactionsArr
|
||||
}
|
||||
|
||||
arg.finish(responseJson)
|
|
@ -0,0 +1,100 @@
|
|||
{.used.}
|
||||
|
||||
import json
|
||||
|
||||
include ../../../common/json_utils
|
||||
|
||||
type QuotedMessage* = object
|
||||
`from`*: string
|
||||
text*: string
|
||||
#parsedText*: Not sure if we use it
|
||||
|
||||
type Sticker* = object
|
||||
hash*: string
|
||||
pack*: int
|
||||
|
||||
type GapParameters* = object
|
||||
`from`*: int64
|
||||
to*: int64
|
||||
|
||||
type MessageDto* = object
|
||||
id*: string
|
||||
whisperTimestamp*: int64
|
||||
`from`*: string
|
||||
alias*: string
|
||||
identicon*: string
|
||||
seen*: bool
|
||||
outgoingStatus*: string
|
||||
quotedMessage*: QuotedMessage
|
||||
rtl*: bool
|
||||
#parsedText*: Not sure if we use it
|
||||
lineCount*: int
|
||||
text*: string
|
||||
chatId*: string
|
||||
localChatId*: string
|
||||
clock*: int64
|
||||
replace*: string
|
||||
responseTo*: string
|
||||
ensName*: string
|
||||
sticker*: Sticker
|
||||
image*: string
|
||||
gapParameters*: GapParameters
|
||||
timestamp*: int64
|
||||
contentType*: int
|
||||
messageType*: int
|
||||
links*: seq[string]
|
||||
|
||||
proc toQuotedMessage*(jsonObj: JsonNode): QuotedMessage =
|
||||
result = QuotedMessage()
|
||||
discard jsonObj.getProp("from", result.from)
|
||||
discard jsonObj.getProp("text", result.text)
|
||||
|
||||
proc toSticker*(jsonObj: JsonNode): Sticker =
|
||||
result = Sticker()
|
||||
discard jsonObj.getProp("hash", result.hash)
|
||||
discard jsonObj.getProp("pack", result.pack)
|
||||
|
||||
proc toGapParameters*(jsonObj: JsonNode): GapParameters =
|
||||
result = GapParameters()
|
||||
discard jsonObj.getProp("from", result.from)
|
||||
discard jsonObj.getProp("to", result.to)
|
||||
|
||||
proc toMessageDto*(jsonObj: JsonNode): MessageDto =
|
||||
result = MessageDto()
|
||||
discard jsonObj.getProp("id", result.id)
|
||||
discard jsonObj.getProp("whisperTimestamp", result.whisperTimestamp)
|
||||
discard jsonObj.getProp("from", result.from)
|
||||
discard jsonObj.getProp("alias", result.alias)
|
||||
discard jsonObj.getProp("identicon", result.identicon)
|
||||
discard jsonObj.getProp("seen", result.seen)
|
||||
discard jsonObj.getProp("outgoingStatus", result.outgoingStatus)
|
||||
discard jsonObj.getProp("rtl", result.rtl)
|
||||
discard jsonObj.getProp("lineCount", result.lineCount)
|
||||
discard jsonObj.getProp("text", result.text)
|
||||
discard jsonObj.getProp("chatId", result.chatId)
|
||||
discard jsonObj.getProp("localChatId", result.localChatId)
|
||||
discard jsonObj.getProp("clock", result.clock)
|
||||
discard jsonObj.getProp("replace", result.replace)
|
||||
discard jsonObj.getProp("responseTo", result.responseTo)
|
||||
discard jsonObj.getProp("ensName", result.ensName)
|
||||
discard jsonObj.getProp("timestamp", result.timestamp)
|
||||
discard jsonObj.getProp("contentType", result.contentType)
|
||||
discard jsonObj.getProp("messageType", result.messageType)
|
||||
discard jsonObj.getProp("image", result.image)
|
||||
|
||||
var quotedMessageObj: JsonNode
|
||||
if(jsonObj.getProp("quotedMessage", quotedMessageObj)):
|
||||
result.quotedMessage = toQuotedMessage(quotedMessageObj)
|
||||
|
||||
var stickerObj: JsonNode
|
||||
if(jsonObj.getProp("sticker", stickerObj)):
|
||||
result.sticker = toSticker(stickerObj)
|
||||
|
||||
var gapParametersObj: JsonNode
|
||||
if(jsonObj.getProp("gapParameters", gapParametersObj)):
|
||||
result.gapParameters = toGapParameters(gapParametersObj)
|
||||
|
||||
var linksArr: JsonNode
|
||||
if(jsonObj.getProp("links", linksArr)):
|
||||
for link in linksArr:
|
||||
result.links.add(link.getStr)
|
|
@ -0,0 +1,21 @@
|
|||
{.used.}
|
||||
|
||||
import json
|
||||
|
||||
import message
|
||||
|
||||
include ../../../common/json_utils
|
||||
|
||||
type PinnedMessageDto* = object
|
||||
pinnedAt*: int64
|
||||
pinnedBy*: string
|
||||
message*: MessageDto
|
||||
|
||||
proc toPinnedMessageDto*(jsonObj: JsonNode): PinnedMessageDto =
|
||||
result = PinnedMessageDto()
|
||||
discard jsonObj.getProp("pinnedAt", result.pinnedAt)
|
||||
discard jsonObj.getProp("pinnedBy", result.pinnedBy)
|
||||
|
||||
var messageObj: JsonNode
|
||||
if(jsonObj.getProp("message", messageObj)):
|
||||
result.message = toMessageDto(messageObj)
|
|
@ -0,0 +1,24 @@
|
|||
{.used.}
|
||||
|
||||
import json
|
||||
|
||||
include ../../../common/json_utils
|
||||
|
||||
type ReactionDto* = object
|
||||
id*: string
|
||||
clock*: int64
|
||||
chatId*: string
|
||||
localChatId*: string
|
||||
`from`*: string
|
||||
messageId*: string
|
||||
emojiId*: int
|
||||
|
||||
proc toReactionDto*(jsonObj: JsonNode): ReactionDto =
|
||||
result = ReactionDto()
|
||||
discard jsonObj.getProp("id", result.id)
|
||||
discard jsonObj.getProp("clock", result.clock)
|
||||
discard jsonObj.getProp("chatId", result.chatId)
|
||||
discard jsonObj.getProp("localChatId", result.localChatId)
|
||||
discard jsonObj.getProp("from", result.from)
|
||||
discard jsonObj.getProp("messageId", result.messageId)
|
||||
discard jsonObj.getProp("emojiId", result.emojiId)
|
|
@ -0,0 +1,133 @@
|
|||
import NimQml, tables, json, sequtils, chronicles
|
||||
|
||||
import eventemitter
|
||||
import ../../tasks/[qt, threadpool]
|
||||
|
||||
import status/statusgo_backend_new/messages as status_go
|
||||
|
||||
import ./dto/message as message_dto
|
||||
import ./dto/pinnedMessage as pinned_msg_dto
|
||||
import ./dto/reaction as reaction_dto
|
||||
|
||||
export message_dto
|
||||
export pinned_msg_dto
|
||||
export reaction_dto
|
||||
|
||||
include async_tasks
|
||||
|
||||
logScope:
|
||||
topics = "messages-service"
|
||||
|
||||
const MESSAGES_PER_PAGE = 20
|
||||
|
||||
# Signals which may be emitted by this service:
|
||||
const SIGNAL_MESSAGES_LOADED* = "new-messagesLoaded" #Once we are done with refactoring we should remove "new-" from this signal name
|
||||
|
||||
type
|
||||
MessagesLoadedArgs* = ref object of Args
|
||||
chatId*: string
|
||||
messages*: seq[MessageDto]
|
||||
pinnedMessages*: seq[PinnedMessageDto]
|
||||
reactions*: seq[ReactionDto]
|
||||
|
||||
QtObject:
|
||||
type Service* = ref object of QObject
|
||||
events: EventEmitter
|
||||
threadpool: ThreadPool
|
||||
msgCursor: Table[string, string]
|
||||
pinnedMsgCursor: Table[string, string]
|
||||
|
||||
proc delete*(self: Service) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newService*(events: EventEmitter, threadpool: ThreadPool): Service =
|
||||
new(result, delete)
|
||||
result.QObject.setup
|
||||
result.events = events
|
||||
result.threadpool = threadpool
|
||||
result.msgCursor = initTable[string, string]()
|
||||
result.pinnedMsgCursor = initTable[string, string]()
|
||||
|
||||
proc getCurrentMessageCursor(self: Service, chatId: string): string =
|
||||
if(not self.msgCursor.hasKey(chatId)):
|
||||
self.msgCursor[chatId] = ""
|
||||
|
||||
return self.msgCursor[chatId]
|
||||
|
||||
proc getCurrentPinnedMessageCursor(self: Service, chatId: string): string =
|
||||
if(not self.pinnedMsgCursor.hasKey(chatId)):
|
||||
self.pinnedMsgCursor[chatId] = ""
|
||||
|
||||
return self.pinnedMsgCursor[chatId]
|
||||
|
||||
proc onLoadMoreMessagesForChat*(self: Service, response: string) {.slot.} =
|
||||
let responseObj = response.parseJson
|
||||
if (responseObj.kind != JObject):
|
||||
info "load more messages response is not a json object"
|
||||
|
||||
# notify view, this is important
|
||||
self.events.emit(SIGNAL_MESSAGES_LOADED, MessagesLoadedArgs())
|
||||
return
|
||||
|
||||
var chatId: string
|
||||
discard responseObj.getProp("chatId", chatId)
|
||||
|
||||
# handling messages
|
||||
var msgCursor: string
|
||||
if(responseObj.getProp("messagesCursor", msgCursor)):
|
||||
self.msgCursor[chatId] = msgCursor
|
||||
|
||||
var messagesArr: JsonNode
|
||||
var messages: seq[MessageDto]
|
||||
if(responseObj.getProp("messages", messagesArr)):
|
||||
messages = map(messagesArr.getElems(), proc(x: JsonNode): MessageDto = x.toMessageDto())
|
||||
|
||||
# handling pinned messages
|
||||
var pinnedMsgCursor: string
|
||||
if(responseObj.getProp("pinnedMessagesCursor", pinnedMsgCursor)):
|
||||
self.pinnedMsgCursor[chatId] = pinnedMsgCursor
|
||||
|
||||
var pinnedMsgArr: JsonNode
|
||||
var pinnedMessages: seq[PinnedMessageDto]
|
||||
if(responseObj.getProp("pinnedMessages", pinnedMsgArr)):
|
||||
pinnedMessages = map(pinnedMsgArr.getElems(), proc(x: JsonNode): PinnedMessageDto = x.toPinnedMessageDto())
|
||||
|
||||
# handling reactions
|
||||
var reactionsArr: JsonNode
|
||||
var reactions: seq[ReactionDto]
|
||||
if(responseObj.getProp("reactions", reactionsArr)):
|
||||
reactions = map(reactionsArr.getElems(), proc(x: JsonNode): ReactionDto = x.toReactionDto())
|
||||
|
||||
let data = MessagesLoadedArgs(chatId: chatId,
|
||||
messages: messages,
|
||||
pinnedMessages: pinnedMessages,
|
||||
reactions: reactions)
|
||||
|
||||
self.events.emit(SIGNAL_MESSAGES_LOADED, data)
|
||||
|
||||
|
||||
proc loadMoreMessagesForChat*(self: Service, chatId: string) =
|
||||
if (chatId.len == 0):
|
||||
error "empty chat id", methodName="loadMoreMessagesForChat"
|
||||
return
|
||||
|
||||
let arg = AsyncFetchChatMessagesTaskArg(
|
||||
tptr: cast[ByteAddress](asyncFetchChatMessagesTask),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "onLoadMoreMessagesForChat",
|
||||
chatId: chatId,
|
||||
msgCursor: self.getCurrentMessageCursor(chatId),
|
||||
pinnedMsgCursor: self.getCurrentPinnedMessageCursor(chatId),
|
||||
limit: MESSAGES_PER_PAGE
|
||||
)
|
||||
|
||||
self.threadpool.start(arg)
|
||||
|
||||
proc loadInitialMessagesForChat*(self: Service, chatId: string) =
|
||||
if(self.getCurrentMessageCursor(chatId).len > 0):
|
||||
return
|
||||
|
||||
# we're here if initial messages are not loaded yet
|
||||
self.loadMoreMessagesForChat(chatId)
|
||||
|
||||
|
Loading…
Reference in New Issue