refactor: load gifs asynchronously
Instead of loading recent gifs right on startup eagerly, we postpone the task to when it's actually needed (when the gif popup is opened and the recent gifs tab is activated), and on top of that we also load the data asynchronously to keep the amount of work that needs to be done in a single tick as short as possible. This needs: status-im/status-go#3170 Closes #9437
This commit is contained in:
parent
2ac1216b68
commit
919f3dc6f7
|
@ -209,7 +209,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
|
||||||
result.mailserversService = mailservers_service.newService(statusFoundation.events, statusFoundation.threadpool,
|
result.mailserversService = mailservers_service.newService(statusFoundation.events, statusFoundation.threadpool,
|
||||||
result.settingsService, result.nodeConfigurationService, statusFoundation.fleetConfiguration)
|
result.settingsService, result.nodeConfigurationService, statusFoundation.fleetConfiguration)
|
||||||
result.nodeService = node_service.newService(statusFoundation.events, result.settingsService, result.nodeConfigurationService)
|
result.nodeService = node_service.newService(statusFoundation.events, result.settingsService, result.nodeConfigurationService)
|
||||||
result.gifService = gif_service.newService(result.settingsService)
|
result.gifService = gif_service.newService(result.settingsService, statusFoundation.events, statusFoundation.threadpool)
|
||||||
result.ensService = ens_service.newService(statusFoundation.events, statusFoundation.threadpool,
|
result.ensService = ens_service.newService(statusFoundation.events, statusFoundation.threadpool,
|
||||||
result.settingsService, result.walletAccountService, result.transactionService,
|
result.settingsService, result.walletAccountService, result.transactionService,
|
||||||
result.networkService, result.tokenService)
|
result.networkService, result.tokenService)
|
||||||
|
|
|
@ -4,11 +4,13 @@ import ../../../../../../app_service/service/community/service as community_serv
|
||||||
import ../../../../../../app_service/service/chat/service as chat_service
|
import ../../../../../../app_service/service/chat/service as chat_service
|
||||||
import ../../../../../../app_service/service/gif/service as gif_service
|
import ../../../../../../app_service/service/gif/service as gif_service
|
||||||
import ../../../../../../app_service/service/gif/dto
|
import ../../../../../../app_service/service/gif/dto
|
||||||
|
import ../../../../../core/eventemitter
|
||||||
|
|
||||||
type
|
type
|
||||||
Controller* = ref object of RootObj
|
Controller* = ref object of RootObj
|
||||||
delegate: io_interface.AccessInterface
|
delegate: io_interface.AccessInterface
|
||||||
sectionId: string
|
sectionId: string
|
||||||
|
events: EventEmitter
|
||||||
chatId: string
|
chatId: string
|
||||||
belongsToCommunity: bool
|
belongsToCommunity: bool
|
||||||
communityService: community_service.Service
|
communityService: community_service.Service
|
||||||
|
@ -17,6 +19,7 @@ type
|
||||||
|
|
||||||
proc newController*(
|
proc newController*(
|
||||||
delegate: io_interface.AccessInterface,
|
delegate: io_interface.AccessInterface,
|
||||||
|
events: EventEmitter,
|
||||||
sectionId: string,
|
sectionId: string,
|
||||||
chatId: string,
|
chatId: string,
|
||||||
belongsToCommunity: bool,
|
belongsToCommunity: bool,
|
||||||
|
@ -26,6 +29,7 @@ proc newController*(
|
||||||
): Controller =
|
): Controller =
|
||||||
result = Controller()
|
result = Controller()
|
||||||
result.delegate = delegate
|
result.delegate = delegate
|
||||||
|
result.events = events
|
||||||
result.sectionId = chatId
|
result.sectionId = chatId
|
||||||
result.chatId = chatId
|
result.chatId = chatId
|
||||||
result.belongsToCommunity = belongsToCommunity
|
result.belongsToCommunity = belongsToCommunity
|
||||||
|
@ -37,7 +41,13 @@ proc delete*(self: Controller) =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc init*(self: Controller) =
|
proc init*(self: Controller) =
|
||||||
discard
|
self.events.on(SIGNAL_LOAD_RECENT_GIFS_DONE) do(e:Args):
|
||||||
|
let args = GifsArgs(e)
|
||||||
|
self.delegate.loadRecentGifsDone(args.gifs)
|
||||||
|
|
||||||
|
self.events.on(SIGNAL_LOAD_FAVORITE_GIFS_DONE) do(e:Args):
|
||||||
|
let args = GifsArgs(e)
|
||||||
|
self.delegate.loadFavoriteGifsDone(args.gifs)
|
||||||
|
|
||||||
proc getChatId*(self: Controller): string =
|
proc getChatId*(self: Controller): string =
|
||||||
return self.chatId
|
return self.chatId
|
||||||
|
@ -84,6 +94,12 @@ proc getTrendingsGifs*(self: Controller): seq[GifDto] =
|
||||||
proc getRecentsGifs*(self: Controller): seq[GifDto] =
|
proc getRecentsGifs*(self: Controller): seq[GifDto] =
|
||||||
return self.gifService.getRecents()
|
return self.gifService.getRecents()
|
||||||
|
|
||||||
|
proc loadRecentGifs*(self: Controller) =
|
||||||
|
self.gifService.asyncLoadRecentGifs()
|
||||||
|
|
||||||
|
proc loadFavoriteGifs*(self: Controller) =
|
||||||
|
self.gifService.asyncLoadFavoriteGifs()
|
||||||
|
|
||||||
proc getFavoritesGifs*(self: Controller): seq[GifDto] =
|
proc getFavoritesGifs*(self: Controller): seq[GifDto] =
|
||||||
return self.gifService.getFavorites()
|
return self.gifService.getFavorites()
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,21 @@ method getTrendingsGifs*(self: AccessInterface): seq[GifDto] {.base.} =
|
||||||
method getRecentsGifs*(self: AccessInterface): seq[GifDto] {.base.} =
|
method getRecentsGifs*(self: AccessInterface): seq[GifDto] {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method loadRecentGifs*(self: AccessInterface) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method loadRecentGifsDone*(self: AccessInterface, gifs: seq[GifDto]) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method getFavoritesGifs*(self: AccessInterface): seq[GifDto] {.base.} =
|
method getFavoritesGifs*(self: AccessInterface): seq[GifDto] {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method loadFavoriteGifs*(self: AccessInterface) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method loadFavoriteGifsDone*(self: AccessInterface, gifs: seq[GifDto]) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method toggleFavoriteGif*(self: AccessInterface, item: GifDto) {.base.} =
|
method toggleFavoriteGif*(self: AccessInterface, item: GifDto) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import io_interface
|
||||||
import ../io_interface as delegate_interface
|
import ../io_interface as delegate_interface
|
||||||
import view, controller
|
import view, controller
|
||||||
import ../../../../../global/global_singleton
|
import ../../../../../global/global_singleton
|
||||||
|
import ../../../../../core/eventemitter
|
||||||
|
|
||||||
import ../../../../../../app_service/service/chat/service as chat_service
|
import ../../../../../../app_service/service/chat/service as chat_service
|
||||||
import ../../../../../../app_service/service/community/service as community_service
|
import ../../../../../../app_service/service/community/service as community_service
|
||||||
|
@ -21,6 +22,7 @@ type
|
||||||
|
|
||||||
proc newModule*(
|
proc newModule*(
|
||||||
delegate: delegate_interface.AccessInterface,
|
delegate: delegate_interface.AccessInterface,
|
||||||
|
events: EventEmitter,
|
||||||
sectionId: string,
|
sectionId: string,
|
||||||
chatId: string,
|
chatId: string,
|
||||||
belongsToCommunity: bool,
|
belongsToCommunity: bool,
|
||||||
|
@ -33,7 +35,7 @@ proc newModule*(
|
||||||
result.delegate = delegate
|
result.delegate = delegate
|
||||||
result.view = view.newView(result)
|
result.view = view.newView(result)
|
||||||
result.viewVariant = newQVariant(result.view)
|
result.viewVariant = newQVariant(result.view)
|
||||||
result.controller = controller.newController(result, sectionId, chatId, belongsToCommunity, chatService, communityService, gifService)
|
result.controller = controller.newController(result, events, sectionId, chatId, belongsToCommunity, chatService, communityService, gifService)
|
||||||
result.moduleLoaded = false
|
result.moduleLoaded = false
|
||||||
|
|
||||||
method delete*(self: Module) =
|
method delete*(self: Module) =
|
||||||
|
@ -98,9 +100,21 @@ method getTrendingsGifs*(self: Module): seq[GifDto] =
|
||||||
method getRecentsGifs*(self: Module): seq[GifDto] =
|
method getRecentsGifs*(self: Module): seq[GifDto] =
|
||||||
return self.controller.getRecentsGifs()
|
return self.controller.getRecentsGifs()
|
||||||
|
|
||||||
|
method loadRecentGifs*(self: Module) =
|
||||||
|
self.controller.loadRecentGifs()
|
||||||
|
|
||||||
|
method loadRecentGifsDone*(self: Module, gifs: seq[GifDto]) =
|
||||||
|
self.view.updateGifColumns(gifs)
|
||||||
|
|
||||||
method getFavoritesGifs*(self: Module): seq[GifDto] =
|
method getFavoritesGifs*(self: Module): seq[GifDto] =
|
||||||
return self.controller.getFavoritesGifs()
|
return self.controller.getFavoritesGifs()
|
||||||
|
|
||||||
|
method loadFavoriteGifs*(self: Module) =
|
||||||
|
self.controller.loadFavoriteGifs()
|
||||||
|
|
||||||
|
method loadFavoriteGifsDone*(self: Module, gifs: seq[GifDto]) =
|
||||||
|
self.view.updateGifColumns(gifs)
|
||||||
|
|
||||||
method toggleFavoriteGif*(self: Module, item: GifDto) =
|
method toggleFavoriteGif*(self: Module, item: GifDto) =
|
||||||
self.controller.toggleFavoriteGif(item)
|
self.controller.toggleFavoriteGif(item)
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ QtObject:
|
||||||
read = getGifColumnC
|
read = getGifColumnC
|
||||||
notify = gifLoaded
|
notify = gifLoaded
|
||||||
|
|
||||||
proc updateGifColumns(self: View, data: seq[GifDto]) =
|
proc updateGifColumns*(self: View, data: seq[GifDto]) =
|
||||||
var columnAData: seq[GifDto] = @[]
|
var columnAData: seq[GifDto] = @[]
|
||||||
var columnAHeight = 0
|
var columnAHeight = 0
|
||||||
var columnBData: seq[GifDto] = @[]
|
var columnBData: seq[GifDto] = @[]
|
||||||
|
@ -115,11 +115,21 @@ QtObject:
|
||||||
|
|
||||||
proc getRecentsGifs*(self: View) {.slot.} =
|
proc getRecentsGifs*(self: View) {.slot.} =
|
||||||
let data = self.delegate.getRecentsGifs()
|
let data = self.delegate.getRecentsGifs()
|
||||||
|
if data.len > 0:
|
||||||
self.updateGifColumns(data)
|
self.updateGifColumns(data)
|
||||||
|
return
|
||||||
|
|
||||||
|
# recent gifs were not loaded yet, so we do it now
|
||||||
|
self.delegate.loadRecentGifs()
|
||||||
|
|
||||||
proc getFavoritesGifs*(self: View) {.slot.} =
|
proc getFavoritesGifs*(self: View) {.slot.} =
|
||||||
let data = self.delegate.getFavoritesGifs()
|
let data = self.delegate.getFavoritesGifs()
|
||||||
|
if data.len > 0:
|
||||||
self.updateGifColumns(data)
|
self.updateGifColumns(data)
|
||||||
|
return
|
||||||
|
|
||||||
|
# favorite gifs were not loaded yet, so we do it now
|
||||||
|
self.delegate.loadFavoriteGifs()
|
||||||
|
|
||||||
proc findGifDto(self: View, id: string): GifDto =
|
proc findGifDto(self: View, id: string): GifDto =
|
||||||
for item in self.gifColumnAModel.gifs:
|
for item in self.gifColumnAModel.gifs:
|
||||||
|
|
|
@ -52,7 +52,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitt
|
||||||
isUsersListAvailable, settingsService, nodeConfigurationService, contactService, chatService, communityService, messageService)
|
isUsersListAvailable, settingsService, nodeConfigurationService, contactService, chatService, communityService, messageService)
|
||||||
result.moduleLoaded = false
|
result.moduleLoaded = false
|
||||||
|
|
||||||
result.inputAreaModule = input_area_module.newModule(result, sectionId, chatId, belongsToCommunity, chatService, communityService, gifService)
|
result.inputAreaModule = input_area_module.newModule(result, events, sectionId, chatId, belongsToCommunity, chatService, communityService, gifService)
|
||||||
result.messagesModule = messages_module.newModule(result, events, sectionId, chatId, belongsToCommunity,
|
result.messagesModule = messages_module.newModule(result, events, sectionId, chatId, belongsToCommunity,
|
||||||
contactService, communityService, chatService, messageService, mailserversService)
|
contactService, communityService, chatService, messageService, mailserversService)
|
||||||
result.usersModule =
|
result.usersModule =
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
include ../../common/json_utils
|
||||||
|
include ../../../app/core/tasks/common
|
||||||
|
import ../../../backend/gifs as status_go
|
||||||
|
|
||||||
|
type
|
||||||
|
AsyncGetRecentGifsTaskArg = ref object of QObjectTaskArg
|
||||||
|
|
||||||
|
const asyncGetRecentGifsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[AsyncGetRecentGifsTaskArg](argEncoded)
|
||||||
|
let response = status_go.getRecentGifs()
|
||||||
|
arg.finish(response)
|
||||||
|
|
||||||
|
type
|
||||||
|
AsyncGetFavoriteGifsTaskArg = ref object of QObjectTaskArg
|
||||||
|
|
||||||
|
const asyncGetFavoriteGifsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[AsyncGetFavoriteGifsTaskArg](argEncoded)
|
||||||
|
let response = status_go.getFavoriteGifs()
|
||||||
|
arg.finish(response)
|
|
@ -4,11 +4,17 @@ import os
|
||||||
import uri
|
import uri
|
||||||
import chronicles
|
import chronicles
|
||||||
import sequtils
|
import sequtils
|
||||||
|
import NimQml
|
||||||
|
|
||||||
import ../settings/service as settings_service
|
import ../settings/service as settings_service
|
||||||
|
import ../../../app/core/eventemitter
|
||||||
import ../../../backend/backend
|
import ../../../backend/backend
|
||||||
|
import ../../../app/core/tasks/[qt, threadpool]
|
||||||
|
import ../../../app/core/[main]
|
||||||
import ./dto
|
import ./dto
|
||||||
|
|
||||||
|
include ./async_tasks
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "gif-service"
|
topics = "gif-service"
|
||||||
|
|
||||||
|
@ -23,18 +29,35 @@ let TENOR_API_KEY_RESOLVED =
|
||||||
else:
|
else:
|
||||||
TENOR_API_KEY
|
TENOR_API_KEY
|
||||||
|
|
||||||
|
const SIGNAL_LOAD_RECENT_GIFS_STARTED* = "loadRecentGifsStarted"
|
||||||
|
const SIGNAL_LOAD_RECENT_GIFS_DONE* = "loadRecentGifsDone"
|
||||||
|
|
||||||
|
const SIGNAL_LOAD_FAVORITE_GIFS_STARTED* = "loadFavoriteGifsStarted"
|
||||||
|
const SIGNAL_LOAD_FAVORITE_GIFS_DONE* = "loadFavoriteGifsDone"
|
||||||
|
|
||||||
type
|
type
|
||||||
Service* = ref object of RootObj
|
GifsArgs* = ref object of Args
|
||||||
|
gifs*: seq[GifDto]
|
||||||
|
error*: string
|
||||||
|
|
||||||
|
QtObject:
|
||||||
|
type
|
||||||
|
Service* = ref object of QObject
|
||||||
|
threadpool: ThreadPool
|
||||||
settingsService: settings_service.Service
|
settingsService: settings_service.Service
|
||||||
favorites: seq[GifDto]
|
favorites: seq[GifDto]
|
||||||
recents: seq[GifDto]
|
recents: seq[GifDto]
|
||||||
|
events: EventEmitter
|
||||||
|
|
||||||
proc delete*(self: Service) =
|
proc delete*(self: Service) =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc newService*(settingsService: settings_service.Service): Service =
|
proc newService*(settingsService: settings_service.Service, events: EventEmitter, threadpool: ThreadPool): Service =
|
||||||
result = Service()
|
result = Service()
|
||||||
|
result.QObject.setup
|
||||||
result.settingsService = settingsService
|
result.settingsService = settingsService
|
||||||
|
result.events = events
|
||||||
|
result.threadpool = threadpool
|
||||||
result.favorites = @[]
|
result.favorites = @[]
|
||||||
result.recents = @[]
|
result.recents = @[]
|
||||||
|
|
||||||
|
@ -71,14 +94,62 @@ proc getFavoriteGifs(self: Service) =
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error "error: ", procName="getFavoriteGifs", errName = e.name, errDesription = e.msg
|
error "error: ", procName="getFavoriteGifs", errName = e.name, errDesription = e.msg
|
||||||
|
|
||||||
|
proc asyncLoadRecentGifs*(self: Service) =
|
||||||
|
self.events.emit(SIGNAL_LOAD_RECENT_GIFS_STARTED, Args())
|
||||||
|
try:
|
||||||
|
let arg = AsyncGetRecentGifsTaskArg(
|
||||||
|
tptr: cast[ByteAddress](asyncGetRecentGifsTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: "onAsyncGetRecentGifsDone"
|
||||||
|
)
|
||||||
|
self.threadpool.start(arg)
|
||||||
|
except Exception as e:
|
||||||
|
error "Error loading recent gifs", msg = e.msg
|
||||||
|
|
||||||
|
proc onAsyncGetRecentGifsDone*(self: Service, response: string) {.slot.} =
|
||||||
|
try:
|
||||||
|
let rpcResponseObj = response.parseJson
|
||||||
|
if (rpcResponseObj{"error"}.kind != JNull):
|
||||||
|
let error = Json.decode($rpcResponseObj["error"], RpcError)
|
||||||
|
error "error loading recent gifs", msg = error.message
|
||||||
|
return
|
||||||
|
|
||||||
|
self.recents = map(rpcResponseObj{"result"}.getElems(), settingToGifDto)
|
||||||
|
self.events.emit(SIGNAL_LOAD_RECENT_GIFS_DONE, GifsArgs(gifs: self.recents))
|
||||||
|
except Exception as e:
|
||||||
|
let errMsg = e.msg
|
||||||
|
error "error: ", errMsg
|
||||||
|
|
||||||
|
proc asyncLoadFavoriteGifs*(self: Service) =
|
||||||
|
self.events.emit(SIGNAL_LOAD_FAVORITE_GIFS_STARTED, Args())
|
||||||
|
try:
|
||||||
|
let arg = AsyncGetFavoriteGifsTaskArg(
|
||||||
|
tptr: cast[ByteAddress](asyncGetFavoriteGifsTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: "onAsyncGetFavoriteGifsDone"
|
||||||
|
)
|
||||||
|
self.threadpool.start(arg)
|
||||||
|
except Exception as e:
|
||||||
|
error "Error loading favorite gifs", msg = e.msg
|
||||||
|
|
||||||
|
proc onAsyncGetFavoriteGifsDone*(self: Service, response: string) {.slot.} =
|
||||||
|
try:
|
||||||
|
let rpcResponseObj = response.parseJson
|
||||||
|
if (rpcResponseObj{"error"}.kind != JNull):
|
||||||
|
let error = Json.decode($rpcResponseObj["error"], RpcError)
|
||||||
|
error "error loading favorite gifs", msg = error.message
|
||||||
|
return
|
||||||
|
|
||||||
|
self.favorites = map(rpcResponseObj{"result"}.getElems(), settingToGifDto)
|
||||||
|
self.events.emit(SIGNAL_LOAD_FAVORITE_GIFS_DONE, GifsArgs(gifs: self.favorites))
|
||||||
|
except Exception as e:
|
||||||
|
let errMsg = e.msg
|
||||||
|
error "error: ", errMsg
|
||||||
|
|
||||||
proc init*(self: Service) =
|
proc init*(self: Service) =
|
||||||
# set Tenor API Key
|
# set Tenor API Key
|
||||||
self.setTenorAPIKey()
|
self.setTenorAPIKey()
|
||||||
|
|
||||||
# get recent and favorite gifs on the database
|
|
||||||
self.getRecentGifs()
|
|
||||||
self.getFavoriteGifs()
|
|
||||||
|
|
||||||
proc tenorQuery(self: Service, path: string): seq[GifDto] =
|
proc tenorQuery(self: Service, path: string): seq[GifDto] =
|
||||||
try:
|
try:
|
||||||
let response = backend.fetchGifs(path)
|
let response = backend.fetchGifs(path)
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import json, strutils
|
||||||
|
import core
|
||||||
|
import response_type
|
||||||
|
|
||||||
|
export response_type
|
||||||
|
|
||||||
|
proc getRecentGifs*(): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||||
|
let payload = %* []
|
||||||
|
result = callPrivateRPC("gif_getRecentGifs", payload)
|
||||||
|
|
||||||
|
proc getFavoriteGifs*(): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||||
|
let payload = %* []
|
||||||
|
result = callPrivateRPC("gif_getFavoriteGifs", payload)
|
Loading…
Reference in New Issue