feat: Add libstatus contacts caching

Fixes #2131.

After some heavy profiling, it became clear that sending of each message was causing a fetch to get all contacts from status-go. This was incurring a minimum of a 0.03s delay for each fetch, which was causing a bottleneck each time it was called for various operations throughout the codebase.

This code addds a layer of threadsafe caching to the contacts call, such that only the first call to contacts fetching will incur the delay, as well as every fetch after a contacts CUD operation.
This commit is contained in:
Eric Mastro 2021-04-15 13:11:51 +10:00 committed by Iuri Matias
parent 6529efda4d
commit 0a108dd849
1 changed files with 25 additions and 8 deletions

View File

@ -1,7 +1,12 @@
import json, strmisc
import json, strmisc, atomics
import core, utils, types, settings
from ../profile/profile import Profile
var
contacts {.threadvar.}: JsonNode
contactsInited {.threadvar.}: bool
dirty: Atomic[bool]
# TODO: remove Profile from here
proc blockContact*(contact: Profile): string =
callPrivateRPC("blockContact".prefix, %* [
@ -16,13 +21,22 @@ proc blockContact*(contact: Profile): string =
proc getContactByID*(id: string): string =
result = callPrivateRPC("getContactByID".prefix, %* [id])
dirty.store(true)
proc getContacts*(): JsonNode =
let payload = %* []
let response = callPrivateRPC("contacts".prefix, payload).parseJson
if response["result"].kind == JNull:
return %* []
return response["result"]
let cacheIsDirty = (not contactsInited) or dirty.load
if not cacheIsDirty:
result = contacts
else:
let payload = %* []
let response = callPrivateRPC("contacts".prefix, payload).parseJson
if response["result"].kind == JNull:
result = %* []
else:
result = response["result"]
dirty.store(false)
contacts = result
contactsInited = true
proc saveContact*(id: string, ensVerified: bool, ensName: string, alias: string, identicon: string, thumbnail: string, systemTags: seq[string], localNickname: string): string =
let payload = %* [{
@ -35,7 +49,10 @@ proc saveContact*(id: string, ensVerified: bool, ensName: string, alias: string,
"systemTags": systemTags,
"localNickname": localNickname
}]
callPrivateRPC("saveContact".prefix, payload)
# TODO: StatusGoError handling
result = callPrivateRPC("saveContact".prefix, payload)
dirty.store(true)
proc requestContactUpdate*(publicKey: string): string =
callPrivateRPC("sendContactUpdate".prefix, %* [publicKey, "", ""])
result = callPrivateRPC("sendContactUpdate".prefix, %* [publicKey, "", ""])
dirty.store(true)