refactor: re-enable async search of ENS names for contacts

Fixes #3986
This commit is contained in:
Jonathan Rainville 2021-11-01 12:04:00 -04:00 committed by Iuri Matias
parent b6d41b67d8
commit 8aec0c62e7
12 changed files with 216 additions and 196 deletions

View File

@ -125,7 +125,7 @@ proc newAppController*(appService: AppService): AppController =
result.keychainService = keychain_service.newService(appService.status.events) result.keychainService = keychain_service.newService(appService.status.events)
result.settingService = setting_service.newService() result.settingService = setting_service.newService()
result.accountsService = accounts_service.newService() result.accountsService = accounts_service.newService()
result.contactsService = contacts_service.newService(appService.status.events) result.contactsService = contacts_service.newService(appService.status.events, appService.threadpool)
result.chatService = chat_service.newService() result.chatService = chat_service.newService()
result.communityService = community_service.newService(result.chatService) result.communityService = community_service.newService(result.chatService)
result.tokenService = token_service.newService(appService.status.events, result.settingService) result.tokenService = token_service.newService(appService.status.events, result.settingService)

View File

@ -70,7 +70,7 @@ proc newModule*[T](
settingService: setting_service.Service, settingService: setting_service.Service,
profileService: profile_service.ServiceInterface, profileService: profile_service.ServiceInterface,
settingsService: settings_service.ServiceInterface, settingsService: settings_service.ServiceInterface,
contactsService: contacts_service.ServiceInterface, contactsService: contacts_service.Service,
aboutService: about_service.ServiceInterface, aboutService: about_service.ServiceInterface,
dappPermissionsService: dapp_permissions_service.ServiceInterface, dappPermissionsService: dapp_permissions_service.ServiceInterface,
languageService: language_service.ServiceInterface, languageService: language_service.ServiceInterface,
@ -106,7 +106,7 @@ proc newModule*[T](
) )
result.browserSectionModule = browser_section_module.newModule(result, bookmarkService, settingsService, dappPermissionsService) result.browserSectionModule = browser_section_module.newModule(result, bookmarkService, settingsService, dappPermissionsService)
result.profileSectionModule = profile_section_module.newModule(result, events, accountsService, settingsService, profileService, contactsService, aboutService, languageService, mnemonicService, privacyService) result.profileSectionModule = profile_section_module.newModule(result,events, accountsService, settingsService, profileService, contactsService, aboutService, languageService, mnemonicService, privacyService)
method delete*[T](self: Module[T]) = method delete*[T](self: Module[T]) =
self.chatSectionModule.delete self.chatSectionModule.delete

View File

@ -13,7 +13,7 @@ type
Controller*[T: controller_interface.DelegateInterface] = ref object of controller_interface.AccessInterface Controller*[T: controller_interface.DelegateInterface] = ref object of controller_interface.AccessInterface
delegate: io_interface.AccessInterface delegate: io_interface.AccessInterface
events: EventEmitter events: EventEmitter
contactsService: contacts_service.ServiceInterface contactsService: contacts_service.Service
accountsService: accounts_service.ServiceInterface accountsService: accounts_service.ServiceInterface
# forward declaration: # forward declaration:
@ -21,7 +21,7 @@ method getContacts*[T](self: Controller[T]): seq[ContactsDto]
proc newController*[T](delegate: io_interface.AccessInterface, proc newController*[T](delegate: io_interface.AccessInterface,
events: EventEmitter, events: EventEmitter,
contactsService: contacts_service.ServiceInterface, contactsService: contacts_service.Service,
accountsService: accounts_service.ServiceInterface): Controller[T] = accountsService: accounts_service.ServiceInterface): Controller[T] =
result = Controller[T]() result = Controller[T]()
result.delegate = delegate result.delegate = delegate
@ -49,6 +49,9 @@ method init*[T](self: Controller[T]) =
let contacts = self.getContacts() let contacts = self.getContacts()
self.delegate.setContactList(contacts) self.delegate.setContactList(contacts)
self.events.on(SIGNAL_CONTACT_LOOKED_UP) do(e: Args):
let args = LookupResolvedArgs(e)
self.delegate.contactLookedUp(args.id)
method getContacts*[T](self: Controller[T]): seq[ContactsDto] = method getContacts*[T](self: Controller[T]): seq[ContactsDto] =
return self.contactsService.getContacts() return self.contactsService.getContacts()
@ -77,35 +80,5 @@ method removeContact*[T](self: Controller[T], publicKey: string): void =
method changeContactNickname*[T](self: Controller[T], accountKeyUID: string, publicKey: string, nicknameToSet: string): void = method changeContactNickname*[T](self: Controller[T], accountKeyUID: string, publicKey: string, nicknameToSet: string): void =
self.contactsService.changeContactNickname(accountKeyUID, publicKey, nicknameToSet) self.contactsService.changeContactNickname(accountKeyUID, publicKey, nicknameToSet)
# method getProfile*[T](self: Controller[T]): item.Item = method lookupContact*[T](self: Controller[T], value: string): void =
# let loggedInAccount = self.accountsService.getLoggedInAccount() self.contactsService.lookupContact(value)
# var pubKey = self.settingsService.getPubKey()
# var network = self.settingsService.getNetwork()
# var appearance = self.settingsService.getAppearance()
# var messagesFromContactsOnly = self.settingsService.getMessagesFromContactsOnly()
# var sendUserStatus = self.settingsService.getSendUserStatus()
# var currentUserStatus = self.settingsService.getCurrentUserStatus()
# var obj = self.settingsService.getIdentityImage(loggedInAccount.keyUid)
# var identityImage = item.IdentityImage(thumbnail: obj.thumbnail, large: obj.large)
# var item = item.Item(
# id: pubkey,
# alias: "",
# username: loggedInAccount.name,
# identicon: loggedInAccount.identicon,
# address: loggedInAccount.keyUid,
# ensName: "",
# ensVerified: false,
# localNickname: "",
# messagesFromContactsOnly: messagesFromContactsOnly,
# sendUserStatus: sendUserStatus,
# currentUserStatus: currentUserStatus,
# identityImage: identityImage,
# appearance: appearance,
# added: false,
# blocked: false,
# hasAddedUs: false
# )
# return item

View File

@ -39,6 +39,9 @@ method removeContact*(self: AccessInterface, publicKey: string): void {.base.} =
method changeContactNickname*(self: AccessInterface, accountKeyUID: string, publicKey: string, nicknameToSet: string): void {.base.} = method changeContactNickname*(self: AccessInterface, accountKeyUID: string, publicKey: string, nicknameToSet: string): void {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method lookupContact*(self: AccessInterface, value: string): void {.base.} =
raise newException(ValueError, "No implementation available")
type type
## Abstract class (concept) which must be implemented by object/s used in this ## Abstract class (concept) which must be implemented by object/s used in this
## module. ## module.

View File

@ -40,6 +40,12 @@ method removeContact*(self: AccessInterface, publicKey: string): void {.base.} =
method changeContactNickname*(self: AccessInterface, accountKeyUID: string, publicKey: string, nicknameToSet: string): void {.base.} = method changeContactNickname*(self: AccessInterface, accountKeyUID: string, publicKey: string, nicknameToSet: string): void {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method lookupContact*(self: AccessInterface, value: string): void {.base.} =
raise newException(ValueError, "No implementation available")
method contactLookedUp*(self: AccessInterface, id: string): void {.base.} =
raise newException(ValueError, "No implementation available")
type type
## Abstract class (concept) which must be implemented by object/s used in this ## Abstract class (concept) which must be implemented by object/s used in this
## module. ## module.

View File

@ -21,7 +21,7 @@ type
proc newModule*[T](delegate: T, proc newModule*[T](delegate: T,
events: EventEmitter, events: EventEmitter,
contactsService: contacts_service.ServiceInterface, contactsService: contacts_service.Service,
accountsService: accounts_service.ServiceInterface): accountsService: accounts_service.ServiceInterface):
Module[T] = Module[T] =
result = Module[T]() result = Module[T]()
@ -71,3 +71,9 @@ method removeContact*[T](self: Module[T], publicKey: string): void =
method changeContactNickname*[T](self: Module[T], accountKeyUID: string, publicKey: string, nicknameToSet: string): void = method changeContactNickname*[T](self: Module[T], accountKeyUID: string, publicKey: string, nicknameToSet: string): void =
self.controller.changeContactNickname(accountKeyUID, publicKey, nicknameToSet) self.controller.changeContactNickname(accountKeyUID, publicKey, nicknameToSet)
method lookupContact*[T](self: Module[T], value: string): void =
self.controller.lookupContact(value)
method contactLookedUp*[T](self: Module[T], id: string): void =
self.view.contactLookedUp(id)

View File

@ -12,17 +12,6 @@ import ./io_interface
import ../../../../../app_service/[main] import ../../../../../app_service/[main]
import ../../../../../app_service/tasks/[qt, threadpool] import ../../../../../app_service/tasks/[qt, threadpool]
type
LookupContactTaskArg = ref object of QObjectTaskArg
value: string
# const lookupContactTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
# let arg = decode[LookupContactTaskArg](argEncoded)
# var id = arg.value
# if not id.startsWith("0x"):
# id = status_ens.pubkey(id)
# arg.finish(id)
QtObject: QtObject:
type type
View* = ref object of QObject View* = ref object of QObject
@ -81,42 +70,31 @@ QtObject:
proc ensWasResolved*(self: View, resolvedPubKey: string) {.signal.} proc ensWasResolved*(self: View, resolvedPubKey: string) {.signal.}
proc ensResolved(self: View, id: string) {.slot.} = proc contactLookedUp*(self: View, id: string) {.slot.} =
echo "Resolved", id
self.ensWasResolved(id) self.ensWasResolved(id)
# if id == "":
# self.contactToAddChanged()
# return
# let contact = self.delegate.getContact(id) if id == "":
self.contactToAddChanged()
return
# if contact != nil: let contact = self.delegate.getContact(id)
# self.contactToAdd = contact
# else:
# self.contactToAdd = ContactsDto(
# id: id,
# alias: self.delegate.generateAlias(id),
# ensVerified: false
# )
# self.contactToAddChanged()
proc lookupContact(self: View, slot: string, value: string) = if contact != nil and contact.id != "":
# TODO reimplement the ENS search with the threadpool self.contactToAdd = contact
self.ensResolved(value) else:
# let arg = LookupContactTaskArg( self.contactToAdd = ContactsDto(
# tptr: cast[ByteAddress](lookupContactTask), id: id,
# vptr: cast[ByteAddress](self.vptr), alias: self.delegate.generateAlias(id),
# slot: slot, ensVerified: false
# value: value )
# )
# self.appService.threadpool.start(arg) self.contactToAddChanged()
proc lookupContact*(self: View, value: string) {.slot.} = proc lookupContact*(self: View, value: string) {.slot.} =
if value == "": if value == "":
return return
self.lookupContact("ensResolved", value) self.delegate.lookupContact(value)
proc addContact*(self: View, publicKey: string) {.slot.} = proc addContact*(self: View, publicKey: string) {.slot.} =
self.delegate.addContact(publicKey) self.delegate.addContact(publicKey)

View File

@ -42,7 +42,7 @@ proc newModule*[T](delegate: T,
accountsService: accounts_service.ServiceInterface, accountsService: accounts_service.ServiceInterface,
settingsService: settings_service.ServiceInterface, settingsService: settings_service.ServiceInterface,
profileService: profile_service.ServiceInterface, profileService: profile_service.ServiceInterface,
contactsService: contacts_service.ServiceInterface, contactsService: contacts_service.Service,
aboutService: about_service.ServiceInterface, aboutService: about_service.ServiceInterface,
languageService: language_service.ServiceInterface, languageService: language_service.ServiceInterface,
mnemonicService: mnemonic_service.ServiceInterface, mnemonicService: mnemonic_service.ServiceInterface,

View File

@ -0,0 +1,19 @@
import status/ens as status_ens
include ../../common/json_utils
include ../../tasks/common
#################################################
# Async lookup ENS contact
#################################################
type
LookupContactTaskArg = ref object of QObjectTaskArg
value: string
const lookupContactTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[LookupContactTaskArg](argEncoded)
var id = arg.value
if not id.startsWith("0x"):
id = status_ens.pubkey(id)
arg.finish(id)

View File

@ -1,6 +1,7 @@
import Tables, json, sequtils, strformat, chronicles import NimQml, Tables, json, sequtils, strformat, chronicles, strutils
import eventemitter import eventemitter
import ../../tasks/[qt, threadpool]
import service_interface, ./dto/contacts import service_interface, ./dto/contacts
import status/statusgo_backend_new/contacts as status_contacts import status/statusgo_backend_new/contacts as status_contacts
@ -11,137 +12,172 @@ import status/contacts as old_status_contacts
export service_interface export service_interface
include async_tasks
logScope: logScope:
topics = "contacts-service" topics = "contacts-service"
type type
Service* = ref object of ServiceInterface LookupResolvedArgs* = ref object of Args
id*: string
# Signals which may be emitted by this service:
const SIGNAL_CONTACT_LOOKED_UP* = "SIGNAL_CONTACT_LOOKED_UP"
QtObject:
type Service* = ref object of QObject
threadpool: ThreadPool
contacts: Table[string, ContactsDto] # [contact_id, ContactsDto] contacts: Table[string, ContactsDto] # [contact_id, ContactsDto]
events: EventEmitter events: EventEmitter
method delete*(self: Service) = proc delete*(self: Service) =
discard self.QObject.delete
proc newService*(events: EventEmitter): Service = proc newService*(events: EventEmitter, threadpool: ThreadPool): Service =
result = Service() new(result, delete)
result.events = events result.QObject.setup
result.contacts = initTable[string, ContactsDto]() result.events = events
result.threadpool = threadpool
result.contacts = initTable[string, ContactsDto]()
method init*(self: Service) = proc init*(self: Service) =
discard discard
method getContacts*(self: Service): seq[ContactsDto] = proc getContacts*(self: Service): seq[ContactsDto] =
let profiles = status_contacts.getContacts() let profiles = status_contacts.getContacts()
for profile in profiles.result: for profile in profiles.result:
result.add(profile.toContactsDto) result.add(profile.toContactsDto)
method getContact*(self: Service, id: string): ContactsDto = proc getContact*(self: Service, id: string): ContactsDto =
return status_contacts.getContactByID(id).result.toContactsDto() return status_contacts.getContactByID(id).result.toContactsDto()
method getOrCreateContact*(self: Service, id: string): ContactsDto = proc getOrCreateContact*(self: Service, id: string): ContactsDto =
result = status_contacts.getContactByID(id).result.toContactsDto() result = self.getContact(id)
if result == nil or result.id == "": if result == nil or result.id == "":
let alias = $status_accounts.generateAlias(id) let alias = $status_accounts.generateAlias(id)
result = ContactsDto( result = ContactsDto(
id: id, id: id,
# username: alias, # username: alias,
# localNickname: "", # localNickname: "",
identicon: $status_accounts.generateIdenticon(id), identicon: $status_accounts.generateIdenticon(id),
alias: alias, alias: alias,
# ensName: "", # ensName: "",
ensVerified: false, ensVerified: false,
# appearance: 0, # appearance: 0,
added: false, added: false,
blocked: false, blocked: false,
hasAddedUs: false hasAddedUs: false
) )
proc saveContact(self: Service, contact: ContactsDto) = proc saveContact(self: Service, contact: ContactsDto) =
var thumbnail = "" var thumbnail = ""
var largeImage = "" var largeImage = ""
# if contact.identityImage != nil: # if contact.identityImage != nil:
# thumbnail = contact.identityImage.thumbnail # thumbnail = contact.identityImage.thumbnail
# largeImage = contact.identityImage.large # largeImage = contact.identityImage.large
# status_contacts.saveContact(contact.id, contact.ensVerified, contact.ensName, contact.alias, contact.identicon, thumbnail, largeImage, contact.added, contact.blocked, contact.hasAddedUs, contact.localNickname) # status_contacts.saveContact(contact.id, contact.ensVerified, contact.ensName, contact.alias, contact.identicon, thumbnail, largeImage, contact.added, contact.blocked, contact.hasAddedUs, contact.localNickname)
status_contacts.saveContact(contact.id, contact.ensVerified, "", contact.alias, contact.identicon, thumbnail, largeImage, contact.added, contact.blocked, contact.hasAddedUs, "") status_contacts.saveContact(contact.id, contact.ensVerified, "", contact.alias, contact.identicon, thumbnail, largeImage, contact.added, contact.blocked, contact.hasAddedUs, "")
method addContact*(self: Service, publicKey: string) = proc addContact*(self: Service, publicKey: string) =
var contact = self.getOrCreateContact(publicKey) var contact = self.getOrCreateContact(publicKey)
let updating = contact.added let updating = contact.added
if not updating: if not updating:
contact.added = true contact.added = true
# discard status_chat.createProfileChat(contact.id) # discard status_chat.createProfileChat(contact.id)
else: else:
contact.blocked = false
self.saveContact(contact)
self.events.emit("contactAdded", Args())
# sendContactUpdate(contact.id, accountKeyUID)
if updating:
let profile = ContactsDto(
id: contact.id,
# username: contact.alias,
identicon: contact.identicon,
alias: contact.alias,
# ensName: contact.ensName,
ensVerified: contact.ensVerified,
# appearance: 0,
added: contact.added,
blocked: contact.blocked,
hasAddedUs: contact.hasAddedUs,
# localNickname: contact.localNickname
)
# TODO fix this to use ContactsDto
# self.events.emit("contactUpdate", ContactUpdateArgs(contacts: @[profile]))
proc rejectContactRequest*(self: Service, publicKey: string) =
let contact = self.getContact(publicKey)
contact.hasAddedUs = false
self.saveContact(contact)
self.events.emit("contactRemoved", Args())
# status_contacts.rejectContactRequest(publicKey)
proc changeContactNickname*(self: Service, accountKeyUID: string, publicKey: string, nicknameToSet: string) =
# status_contacts.setNickName(publicKey, nicknameToSet, accountKeyUID)
var contact = self.getOrCreateContact(publicKey)
# let nickname =
# if (nicknameToSet == ""):
# contact.localNickname
# elif (nicknameToSet == DELETE_CONTACT):
# ""
# else:
# nicknameToSet
# contact.localNickname = nickname
self.saveContact(contact)
self.events.emit("contactAdded", Args())
# sendContactUpdate(contact.id, accountKeyUID)
proc unblockContact*(self: Service, publicKey: string) =
# status_contacts.unblockContact(publicKey)
var contact = self.getContact(publicKey)
contact.blocked = false contact.blocked = false
self.saveContact(contact)
self.events.emit("contactUnblocked", old_status_contacts.ContactIdArgs(id: publicKey))
self.saveContact(contact) proc blockContact*(self: Service, publicKey: string) =
var contact = self.getContact(publicKey)
self.events.emit("contactAdded", Args()) contact.blocked = true
# sendContactUpdate(contact.id, accountKeyUID) self.saveContact(contact)
if updating: self.events.emit("contactBlocked", old_status_contacts.ContactIdArgs(id: publicKey))
let profile = ContactsDto(
id: contact.id, proc removeContact*(self: Service, publicKey: string) =
# username: contact.alias, # status_contacts.removeContact(publicKey)
identicon: contact.identicon, var contact = self.getContact(publicKey)
alias: contact.alias, contact.added = false
# ensName: contact.ensName, contact.hasAddedUs = false
ensVerified: contact.ensVerified,
# appearance: 0, self.saveContact(contact)
added: contact.added, self.events.emit("contactRemoved", Args())
blocked: contact.blocked, # let channelId = status_utils.getTimelineChatId(publicKey)
hasAddedUs: contact.hasAddedUs, # if status_chat.hasChannel(channelId):
# localNickname: contact.localNickname # status_chat.leave(channelId)
proc ensResolved*(self: Service, id: string) {.slot.} =
# var contact = self.getContact(id)
# if contact == nil or contact.id == "":
# contact = ContactsDto(
# id: id,
# alias: $status_accounts.generateAlias(id),
# ensVerified: false
# )
let data = LookupResolvedArgs(id: id)
self.events.emit(SIGNAL_CONTACT_LOOKED_UP, data)
proc lookupContact*(self: Service, value: string) =
let arg = LookupContactTaskArg(
tptr: cast[ByteAddress](lookupContactTask),
vptr: cast[ByteAddress](self.vptr),
slot: "ensResolved",
value: value
) )
# TODO fix this to use ContactsDto self.threadpool.start(arg)
# self.events.emit("contactUpdate", ContactUpdateArgs(contacts: @[profile]))
method rejectContactRequest*(self: Service, publicKey: string) =
let contact = status_contacts.getContactByID(publicKey).result.toContactsDto()
contact.hasAddedUs = false
self.saveContact(contact)
self.events.emit("contactRemoved", Args())
# status_contacts.rejectContactRequest(publicKey)
method changeContactNickname*(self: Service, accountKeyUID: string, publicKey: string, nicknameToSet: string) =
# status_contacts.setNickName(publicKey, nicknameToSet, accountKeyUID)
var contact = self.getOrCreateContact(publicKey)
# let nickname =
# if (nicknameToSet == ""):
# contact.localNickname
# elif (nicknameToSet == DELETE_CONTACT):
# ""
# else:
# nicknameToSet
# contact.localNickname = nickname
self.saveContact(contact)
self.events.emit("contactAdded", Args())
# sendContactUpdate(contact.id, accountKeyUID)
method unblockContact*(self: Service, publicKey: string) =
# status_contacts.unblockContact(publicKey)
var contact = status_contacts.getContactByID(publicKey).result.toContactsDto()
contact.blocked = false
self.saveContact(contact)
self.events.emit("contactUnblocked", old_status_contacts.ContactIdArgs(id: publicKey))
method blockContact*(self: Service, publicKey: string) =
var contact = status_contacts.getContactByID(publicKey).result.toContactsDto()
contact.blocked = true
self.saveContact(contact)
self.events.emit("contactBlocked", old_status_contacts.ContactIdArgs(id: publicKey))
method removeContact*(self: Service, publicKey: string) =
# status_contacts.removeContact(publicKey)
var contact = status_contacts.getContactByID(publicKey).result.toContactsDto()
contact.added = false
contact.hasAddedUs = false
self.saveContact(contact)
self.events.emit("contactRemoved", Args())
# let channelId = status_utils.getTimelineChatId(publicKey)
# if status_chat.hasChannel(channelId):
# status_chat.leave(channelId)

View File

@ -186,7 +186,6 @@ QtObject {
} }
function lookupContact(value) { function lookupContact(value) {
console.log('lookup ples', value, profileModelInst)
contactsModuleInst.lookupContact(value) contactsModuleInst.lookupContact(value)
} }

View File

@ -173,7 +173,6 @@ Item {
} }
property var lookupContact: Backpressure.debounce(addContactSearchInput, 400, function (value) { property var lookupContact: Backpressure.debounce(addContactSearchInput, 400, function (value) {
console.log('Lookup', value)
root.isPending = true root.isPending = true
searchResults.showProfileNotFoundMessage = false searchResults.showProfileNotFoundMessage = false
root.store.lookupContact(value) root.store.lookupContact(value)
@ -182,6 +181,7 @@ Item {
onOpened: { onOpened: {
addContactSearchInput.text = "" addContactSearchInput.text = ""
searchResults.reset() searchResults.reset()
addContactSearchInput.forceActiveFocus()
} }
Input { Input {