refactor(communities): load curated communities asynchronously

This makes loading of curated communities asynchronous as the task
can take quite a while.

Closes #9341
This commit is contained in:
Pascal Precht 2023-01-31 14:03:25 +01:00 committed by Jonathan Rainville
parent ee9fe6d720
commit cf5271cfea
9 changed files with 118 additions and 15 deletions

View File

@ -90,6 +90,16 @@ proc init*(self: Controller) =
let args = CommunityIdArgs(e)
self.delegate.communityHistoryArchivesDownloadFinished(args.communityId)
self.events.on(SIGNAL_CURATED_COMMUNITIES_LOADING) do(e:Args):
self.delegate.curatedCommunitiesLoading()
self.events.on(SIGNAL_CURATED_COMMUNITIES_LOADING_FAILED) do(e:Args):
self.delegate.curatedCommunitiesLoadingFailed()
self.events.on(SIGNAL_CURATED_COMMUNITIES_LOADED) do(e:Args):
let args = CuratedCommunitiesArgs(e)
self.delegate.curatedCommunitiesLoaded(args.curatedCommunities)
proc getCommunityTags*(self: Controller): string =
result = self.communityService.getCommunityTags()
@ -219,6 +229,9 @@ proc userCanJoin*(self: Controller, communityId: string): bool =
proc isCommunityRequestPending*(self: Controller, communityId: string): bool =
return self.communityService.isCommunityRequestPending(communityId)
proc asyncLoadCuratedCommunities*(self: Controller) =
self.communityService.asyncLoadCuratedCommunities()
proc getStatusForContactWithId*(self: Controller, publicKey: string): StatusUpdateDto =
return self.contactsService.getStatusForContactWithId(publicKey)

View File

@ -14,6 +14,9 @@ method load*(self: AccessInterface) {.base.} =
method isLoaded*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method onActivated*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method setCommunityTags*(self: AccessInterface, communityTags: string) {.base.} =
raise newException(ValueError, "No implementation available")
@ -146,3 +149,11 @@ method communityHistoryArchivesDownloadStarted*(self: AccessInterface, community
method communityHistoryArchivesDownloadFinished*(self: AccessInterface, communityId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method curatedCommunitiesLoading*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method curatedCommunitiesLoadingFailed*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method curatedCommunitiesLoaded*(self: AccessInterface, curatedCommunities: seq[CuratedCOmmunity]) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -91,6 +91,19 @@ method viewDidLoad*(self: Module) =
self.delegate.communitiesModuleDidLoad()
method onActivated*(self: Module) =
self.controller.asyncLoadCuratedCommunities()
method curatedCommunitiesLoaded*(self: Module, curatedCommunities: seq[CuratedCOmmunity]) =
self.setCuratedCommunities(curatedCommunities)
self.view.setCuratedCommunitiesLoading(false)
method curatedCommunitiesLoading*(self: Module) =
self.view.setCuratedCommunitiesLoading(true)
method curatedCommunitiesLoadingFailed*(self: Module) =
self.view.setCuratedCommunitiesLoading(false)
proc createMemberItem(self: Module, memberId, requestId: string): MemberItem =
let contactDetails = self.controller.getContactDetails(memberId)
result = initMemberItem(

View File

@ -25,6 +25,7 @@ QtObject:
observedItem: ActiveSection
curatedCommunitiesModel: CuratedCommunityModel
curatedCommunitiesModelVariant: QVariant
curatedCommunitiesLoading: bool
discordFileListModel: DiscordFileListModel
discordFileListModelVariant: QVariant
discordCategoriesModel: DiscordCategoriesModel
@ -74,6 +75,7 @@ QtObject:
result.modelVariant = newQVariant(result.model)
result.curatedCommunitiesModel = newCuratedCommunityModel()
result.curatedCommunitiesModelVariant = newQVariant(result.curatedCommunitiesModel)
result.curatedCommunitiesLoading = false
result.discordFileListModel = newDiscordFileListModel()
result.discordFileListModelVariant = newQVariant(result.discordFileListModel)
result.discordCategoriesModel = newDiscordCategoriesModel()
@ -284,6 +286,20 @@ QtObject:
QtProperty[QVariant] curatedCommunities:
read = getCuratedCommunitiesModel
proc curatedCommunitiesLoadingChanged*(self: View) {.signal.}
proc setCuratedCommunitiesLoading*(self: View, flag: bool) =
if (self.curatedCommunitiesLoading == flag): return
self.curatedCommunitiesLoading = flag
self.curatedCommunitiesLoadingChanged()
proc getCuratedCommunitiesLoading*(self: View): bool {.slot.} =
return self.curatedCommunitiesLoading
QtProperty[bool] curatedCommunitiesLoading:
read = getCuratedCommunitiesLoading
notify = curatedCommunitiesLoadingChanged
proc discordFileListModel*(self: View): DiscordFileListModel =
result = self.discordFileListModel

View File

@ -669,6 +669,8 @@ method activeSectionSet*[T](self: Module[T], sectionId: string) =
echo "main-module, incorrect section id: ", sectionId
return
if sectionId == conf.COMMUNITIESPORTAL_SECTION_ID:
self.communitiesModule.onActivated()
self.view.model().setActiveSection(sectionId)
self.view.activeSectionSet(item)

View File

@ -11,3 +11,12 @@ const asyncRequestCommunityInfoTask: Task = proc(argEncoded: string) {.gcsafe, n
let response = status_go.requestCommunityInfo(arg.communityId)
let tpl: tuple[communityId: string, response: RpcResponse[JsonNode], importing: bool] = (arg.communityId, response, arg.importing)
arg.finish(tpl)
type
AsyncLoadCuratedCommunitiesTaskArg = ref object of QObjectTaskArg
const asyncLoadCuratedCommunitiesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncLoadCuratedCommunitiesTaskArg](argEncoded)
let response = status_go.getCuratedCommunities()
arg.finish(response)

View File

@ -222,7 +222,22 @@ proc parseCuratedCommunities*(response: RpcResponse[JsonNode]): seq[CuratedCommu
))
if (response.result["unknownCommunities"].kind == JArray):
for communityId in response.result["unknownCommunities"].items():
result.add(CuratedCOmmunity(
result.add(CuratedCommunity(
available: false,
communityId: communityId.getStr()
))
proc parseCuratedCommunities*(response: JsonNode): seq[CuratedCommunity] =
if (response["communities"].kind == JObject):
for (communityId, communityJson) in response["communities"].pairs():
result.add(CuratedCommunity(
available: true,
communityId: communityId,
community: communityJson.toCommunityDto()
))
if (response["unknownCommunities"].kind == JArray):
for communityId in response["unknownCommunities"].items():
result.add(CuratedCommunity(
available: false,
communityId: communityId.getStr()
))

View File

@ -31,6 +31,9 @@ type
CuratedCommunityArgs* = ref object of Args
curatedCommunity*: CuratedCommunity
CuratedCommunitiesArgs* = ref object of Args
curatedCommunities*: seq[CuratedCommunity]
CommunitiesArgs* = ref object of Args
communities*: seq[CommunityDto]
@ -138,6 +141,10 @@ const SIGNAL_DISCORD_CATEGORIES_AND_CHANNELS_EXTRACTED* = "discordCategoriesAndC
const SIGNAL_DISCORD_COMMUNITY_IMPORT_FINISHED* = "discordCommunityImportFinished"
const SIGNAL_DISCORD_COMMUNITY_IMPORT_PROGRESS* = "discordCommunityImportProgress"
const SIGNAL_CURATED_COMMUNITIES_LOADING* = "curatedCommunitiesLoading"
const SIGNAL_CURATED_COMMUNITIES_LOADED* = "curatedCommunitiesLoaded"
const SIGNAL_CURATED_COMMUNITIES_LOADING_FAILED* = "curatedCommunitiesLoadingFailed"
QtObject:
type
Service* = ref object of QObject
@ -157,7 +164,7 @@ QtObject:
proc loadCommunityTags(self: Service): string
proc loadAllCommunities(self: Service): seq[CommunityDto]
proc loadJoinedComunities(self: Service): seq[CommunityDto]
proc loadCuratedCommunities(self: Service): seq[CuratedCommunity]
proc asyncLoadCuratedCommunities*(self: Service)
proc loadCommunitiesSettings(self: Service): seq[CommunitySettingsDto]
proc loadMyPendingRequestsToJoin*(self: Service)
proc loadMyCanceledRequestsToJoin*(self: Service)
@ -502,10 +509,6 @@ QtObject:
for community in allCommunities:
self.allCommunities[community.id] = community
let curatedCommunities = self.loadCuratedCommunities()
for curatedCommunity in curatedCommunities:
self.curatedCommunities[curatedCommunity.communityId] = curatedCommunity
let communitiesSettings = self.loadCommunitiesSettings()
for settings in communitiesSettings:
if self.allCommunities.hasKey(settings.id):
@ -539,15 +542,6 @@ QtObject:
error "error: ", errDesription
return @[]
proc loadCuratedCommunities(self: Service): seq[CuratedCommunity] =
try:
let response = status_go.getCuratedCommunities()
return parseCuratedCommunities(response)
except Exception as e:
let errDesription = e.msg
error "error loading curated communities: ", errDesription
return @[]
proc loadCommunitiesSettings(self: Service): seq[CommunitySettingsDto] =
try:
let response = status_go.getCommunitiesSettings()
@ -1246,6 +1240,35 @@ QtObject:
self.events.emit(SIGNAL_COMMUNITY_DATA_IMPORTED, CommunityArgs(community: community))
proc asyncLoadCuratedCommunities*(self: Service) =
self.events.emit(SIGNAL_CURATED_COMMUNITIES_LOADING, Args())
try:
let arg = AsyncLoadCuratedCommunitiesTaskArg(
tptr: cast[ByteAddress](asyncLoadCuratedCommunitiesTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAsyncLoadCuratedCommunitiesDone",
)
self.threadpool.start(arg)
except Exception as e:
error "Error loading curated communities", msg = e.msg
proc onAsyncLoadCuratedCommunitiesDone*(self: Service, response: string) {.slot.} =
try:
let rpcResponseObj = response.parseJson
if (rpcResponseObj{"error"}.kind != JNull):
let error = Json.decode($rpcResponseObj["error"], RpcError)
error "Error requesting community info", msg = error.message
return
let curatedCommunities = parseCuratedCommunities(rpcResponseObj{"result"})
for curatedCommunity in curatedCommunities:
self.curatedCommunities[curatedCommunity.communityId] = curatedCommunity
self.events.emit(SIGNAL_CURATED_COMMUNITIES_LOADED, CuratedCommunitiesArgs(curatedCommunities: self.getCuratedCommunities()))
except Exception as e:
let errMsg = e.msg
error "error: ", errMsg
self.events.emit(SIGNAL_CURATEDCOMMUNITIES_LOADING_FAILED, Args())
proc requestCommunityInfo*(self: Service, communityId: string, importing = false) =
try:

View File

@ -10,6 +10,7 @@ QtObject {
property var mainModuleInst: mainModule
readonly property var curatedCommunitiesModel: root.communitiesModuleInst.curatedCommunities
readonly property bool curatedCommunitiesLoading: root.communitiesModuleInst.curatedCommunitiesLoading
property var discordFileList: root.communitiesModuleInst.discordFileList
property var discordCategoriesModel: root.communitiesModuleInst.discordCategories