refactor(gifs): lazy load tenor api key + make search async
Fixes #9949 Only calls `setTenorAPIKey` once we need it (when doing a search or getting trending). Also caches the trending gifs so that they are only fetched once. Makes the search and trending calls async by create an async tenor query async task.
This commit is contained in:
parent
21d2c00b40
commit
2f3f8f4e03
|
@ -50,6 +50,26 @@ proc init*(self: Controller) =
|
|||
let args = GifsArgs(e)
|
||||
self.delegate.loadFavoriteGifsDone(args.gifs)
|
||||
|
||||
self.events.on(SIGNAL_LOAD_TRENDING_GIFS_STARTED) do(e:Args):
|
||||
self.delegate.loadTrendingGifsStarted()
|
||||
|
||||
self.events.on(SIGNAL_LOAD_TRENDING_GIFS_DONE) do(e:Args):
|
||||
let args = GifsArgs(e)
|
||||
self.delegate.loadTrendingGifsDone(args.gifs)
|
||||
|
||||
self.events.on(SIGNAL_LOAD_TRENDING_GIFS_ERROR) do(e:Args):
|
||||
self.delegate.loadTrendingGifsError()
|
||||
|
||||
self.events.on(SIGNAL_SEARCH_GIFS_STARTED) do(e:Args):
|
||||
self.delegate.searchGifsStarted()
|
||||
|
||||
self.events.on(SIGNAL_SEARCH_GIFS_DONE) do(e:Args):
|
||||
let args = GifsArgs(e)
|
||||
self.delegate.serachGifsDone(args.gifs)
|
||||
|
||||
self.events.on(SIGNAL_SEARCH_GIFS_ERROR) do(e:Args):
|
||||
self.delegate.searchGifsError()
|
||||
|
||||
proc getChatId*(self: Controller): string =
|
||||
return self.chatId
|
||||
|
||||
|
@ -86,11 +106,11 @@ proc acceptRequestAddressForTransaction*(self: Controller, messageId: string, ad
|
|||
proc acceptRequestTransaction*(self: Controller, transactionHash: string, messageId: string, signature: string) =
|
||||
self.chatService.acceptRequestTransaction(transactionHash, messageId, signature)
|
||||
|
||||
proc searchGifs*(self: Controller, query: string): seq[GifDto] =
|
||||
return self.gifService.search(query)
|
||||
proc searchGifs*(self: Controller, query: string) =
|
||||
self.gifService.search(query)
|
||||
|
||||
proc getTrendingsGifs*(self: Controller): seq[GifDto] =
|
||||
return self.gifService.getTrendings()
|
||||
proc getTrendingsGifs*(self: Controller) =
|
||||
self.gifService.getTrending()
|
||||
|
||||
proc getRecentsGifs*(self: Controller): seq[GifDto] =
|
||||
return self.gifService.getRecents()
|
||||
|
|
|
@ -41,10 +41,10 @@ method acceptRequestAddressForTransaction*(self: AccessInterface, messageId: str
|
|||
method acceptRequestTransaction*(self: AccessInterface, transactionHash: string, messageId: string, signature: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method searchGifs*(self: AccessInterface, query: string): seq[GifDto] {.base.} =
|
||||
method searchGifs*(self: AccessInterface, query: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getTrendingsGifs*(self: AccessInterface): seq[GifDto] {.base.} =
|
||||
method getTrendingsGifs*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getRecentsGifs*(self: AccessInterface): seq[GifDto] {.base.} =
|
||||
|
@ -56,6 +56,24 @@ method loadRecentGifs*(self: AccessInterface) {.base.} =
|
|||
method loadRecentGifsDone*(self: AccessInterface, gifs: seq[GifDto]) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method loadTrendingGifsStarted*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method loadTrendingGifsError*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method loadTrendingGifsDone*(self: AccessInterface, gifs: seq[GifDto]) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method searchGifsStarted*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method searchGifsError*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method serachGifsDone*(self: AccessInterface, gifs: seq[GifDto]) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getFavoritesGifs*(self: AccessInterface): seq[GifDto] {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
|
|
|
@ -91,11 +91,11 @@ method acceptRequestAddressForTransaction*(self: Module, messageId: string, addr
|
|||
method acceptRequestTransaction*(self: Module, transactionHash: string, messageId: string, signature: string) =
|
||||
self.controller.acceptRequestTransaction(transactionHash, messageId, signature)
|
||||
|
||||
method searchGifs*(self: Module, query: string): seq[GifDto] =
|
||||
return self.controller.searchGifs(query)
|
||||
method searchGifs*(self: Module, query: string) =
|
||||
self.controller.searchGifs(query)
|
||||
|
||||
method getTrendingsGifs*(self: Module): seq[GifDto] =
|
||||
return self.controller.getTrendingsGifs()
|
||||
method getTrendingsGifs*(self: Module) =
|
||||
self.controller.getTrendingsGifs()
|
||||
|
||||
method getRecentsGifs*(self: Module): seq[GifDto] =
|
||||
return self.controller.getRecentsGifs()
|
||||
|
@ -106,6 +106,30 @@ method loadRecentGifs*(self: Module) =
|
|||
method loadRecentGifsDone*(self: Module, gifs: seq[GifDto]) =
|
||||
self.view.updateGifColumns(gifs)
|
||||
|
||||
method loadTrendingGifsStarted*(self: Module) =
|
||||
self.view.updateGifColumns(@[])
|
||||
self.view.setGifLoading(true)
|
||||
|
||||
method loadTrendingGifsError*(self: Module) =
|
||||
# Just setting loading to false works because the UI shows an error when there are no gifs
|
||||
self.view.setGifLoading(false)
|
||||
|
||||
method loadTrendingGifsDone*(self: Module, gifs: seq[GifDto]) =
|
||||
self.view.setGifLoading(false)
|
||||
self.view.updateGifColumns(gifs)
|
||||
|
||||
method searchGifsStarted*(self: Module) =
|
||||
self.view.updateGifColumns(@[])
|
||||
self.view.setGifLoading(true)
|
||||
|
||||
method searchGifsError*(self: Module) =
|
||||
# Just setting loading to false works because the UI shows an error when there are no gifs
|
||||
self.view.setGifLoading(false)
|
||||
|
||||
method serachGifsDone*(self: Module, gifs: seq[GifDto]) =
|
||||
self.view.setGifLoading(false)
|
||||
self.view.updateGifColumns(gifs)
|
||||
|
||||
method getFavoritesGifs*(self: Module): seq[GifDto] =
|
||||
return self.controller.getFavoritesGifs()
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ QtObject:
|
|||
gifColumnAModel: GifColumnModel
|
||||
gifColumnBModel: GifColumnModel
|
||||
gifColumnCModel: GifColumnModel
|
||||
gifLoading: bool
|
||||
|
||||
proc delete*(self: View) =
|
||||
self.model.delete
|
||||
|
@ -25,6 +26,7 @@ QtObject:
|
|||
result.gifColumnAModel = newGifColumnModel()
|
||||
result.gifColumnBModel = newGifColumnModel()
|
||||
result.gifColumnCModel = newGifColumnModel()
|
||||
result.gifLoading = false
|
||||
|
||||
proc load*(self: View) =
|
||||
self.delegate.viewDidLoad()
|
||||
|
@ -105,13 +107,22 @@ QtObject:
|
|||
self.gifColumnCModel.setNewData(columnCData)
|
||||
self.gifLoaded()
|
||||
|
||||
proc gifLoadingChanged*(self: View) {.signal.}
|
||||
proc setGifLoading*(self: View, value: bool) =
|
||||
self.gifLoading = value
|
||||
self.gifLoadingChanged()
|
||||
proc getGifLoading*(self: View): bool {.slot.} =
|
||||
result = self.gifLoading
|
||||
|
||||
QtProperty[bool] gifLoading:
|
||||
read = getGifLoading
|
||||
notify = gifLoadingChanged
|
||||
|
||||
proc searchGifs*(self: View, query: string) {.slot.} =
|
||||
let data = self.delegate.searchGifs(query)
|
||||
self.updateGifColumns(data)
|
||||
self.delegate.searchGifs(query)
|
||||
|
||||
proc getTrendingsGifs*(self: View) {.slot.} =
|
||||
let data = self.delegate.getTrendingsGifs()
|
||||
self.updateGifColumns(data)
|
||||
self.delegate.getTrendingsGifs()
|
||||
|
||||
proc getRecentsGifs*(self: View) {.slot.} =
|
||||
let data = self.delegate.getRecentsGifs()
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
include ../../common/json_utils
|
||||
include ../../../app/core/tasks/common
|
||||
import ../../../backend/gifs as status_go
|
||||
|
||||
type
|
||||
AsyncGetRecentGifsTaskArg = ref object of QObjectTaskArg
|
||||
|
@ -17,3 +16,43 @@ const asyncGetFavoriteGifsTask: Task = proc(argEncoded: string) {.gcsafe, nimcal
|
|||
let arg = decode[AsyncGetFavoriteGifsTaskArg](argEncoded)
|
||||
let response = status_go.getFavoriteGifs()
|
||||
arg.finish(response)
|
||||
|
||||
type
|
||||
AsyncTenorQueryArg = ref object of QObjectTaskArg
|
||||
apiKeySet: bool
|
||||
apiKey: string
|
||||
query: string
|
||||
event: string
|
||||
errorEvent: string
|
||||
|
||||
const asyncTenorQuery: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[AsyncTenorQueryArg](argEncoded)
|
||||
try:
|
||||
|
||||
if not arg.apiKeySet:
|
||||
let response = status_go.setTenorAPIKey(arg.apiKey)
|
||||
if(not response.error.isNil):
|
||||
raise newException(RpcException, response.error.message)
|
||||
|
||||
let response = status_go.fetchGifs(arg.query)
|
||||
let doc = response.result.str.parseJson()
|
||||
|
||||
var items: seq[GifDto] = @[]
|
||||
for json in doc["results"]:
|
||||
items.add(tenorToGifDto(json))
|
||||
|
||||
arg.finish(%* {
|
||||
"items": items,
|
||||
"event": arg.event,
|
||||
"errorEvent": arg.errorEvent,
|
||||
"error": "",
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
error "error: ", procName="asyncTenorQuery", query = arg.query, errDesription = e.msg
|
||||
|
||||
arg.finish(%* {
|
||||
"error": e.msg,
|
||||
"event": arg.event,
|
||||
"errorEvent": arg.errorEvent
|
||||
})
|
||||
|
|
|
@ -8,7 +8,7 @@ import NimQml
|
|||
|
||||
import ../settings/service as settings_service
|
||||
import ../../../app/core/eventemitter
|
||||
import ../../../backend/backend
|
||||
import ../../../backend/backend as status_go
|
||||
import ../../../app/core/tasks/[qt, threadpool]
|
||||
import ../../../app/core/[main]
|
||||
import ./dto
|
||||
|
@ -35,6 +35,14 @@ const SIGNAL_LOAD_RECENT_GIFS_DONE* = "loadRecentGifsDone"
|
|||
const SIGNAL_LOAD_FAVORITE_GIFS_STARTED* = "loadFavoriteGifsStarted"
|
||||
const SIGNAL_LOAD_FAVORITE_GIFS_DONE* = "loadFavoriteGifsDone"
|
||||
|
||||
const SIGNAL_LOAD_TRENDING_GIFS_STARTED* = "loadTrendingGifsStarted"
|
||||
const SIGNAL_LOAD_TRENDING_GIFS_DONE* = "loadTrendingGifsDone"
|
||||
const SIGNAL_LOAD_TRENDING_GIFS_ERROR* = "loadTrendingGifsError"
|
||||
|
||||
const SIGNAL_SEARCH_GIFS_STARTED* = "searchGifsStarted"
|
||||
const SIGNAL_SEARCH_GIFS_DONE* = "searchGifsDone"
|
||||
const SIGNAL_SEARCH_GIFS_ERROR* = "searchGifsError"
|
||||
|
||||
type
|
||||
GifsArgs* = ref object of Args
|
||||
gifs*: seq[GifDto]
|
||||
|
@ -47,7 +55,9 @@ QtObject:
|
|||
settingsService: settings_service.Service
|
||||
favorites: seq[GifDto]
|
||||
recents: seq[GifDto]
|
||||
trending: seq[GifDto]
|
||||
events: EventEmitter
|
||||
apiKeySet: bool
|
||||
|
||||
proc delete*(self: Service) =
|
||||
discard
|
||||
|
@ -60,39 +70,7 @@ QtObject:
|
|||
result.threadpool = threadpool
|
||||
result.favorites = @[]
|
||||
result.recents = @[]
|
||||
|
||||
proc setTenorAPIKey(self: Service) =
|
||||
try:
|
||||
let response = backend.setTenorAPIKey(TENOR_API_KEY_RESOLVED)
|
||||
if(not response.error.isNil):
|
||||
error "error setTenorAPIKey: ", errDescription = response.error.message
|
||||
|
||||
except Exception as e:
|
||||
error "error: ", procName="setTenorAPIKey", errName = e.name, errDesription = e.msg
|
||||
|
||||
proc getRecentGifs(self: Service) =
|
||||
try:
|
||||
let response = backend.getRecentGifs()
|
||||
|
||||
if(not response.error.isNil):
|
||||
error "error getRecentGifs: ", errDescription = response.error.message
|
||||
|
||||
self.recents = map(response.result.getElems(), settingToGifDto)
|
||||
|
||||
except Exception as e:
|
||||
error "error: ", procName="getRecentGifs", errName = e.name, errDesription = e.msg
|
||||
|
||||
proc getFavoriteGifs(self: Service) =
|
||||
try:
|
||||
let response = backend.getFavoriteGifs()
|
||||
|
||||
if(not response.error.isNil):
|
||||
error "error getFavoriteGifs: ", errDescription = response.error.message
|
||||
|
||||
self.favorites = map(response.result.getElems(), settingToGifDto)
|
||||
|
||||
except Exception as e:
|
||||
error "error: ", procName="getFavoriteGifs", errName = e.name, errDesription = e.msg
|
||||
result.apiKeySet = false
|
||||
|
||||
proc asyncLoadRecentGifs*(self: Service) =
|
||||
self.events.emit(SIGNAL_LOAD_RECENT_GIFS_STARTED, Args())
|
||||
|
@ -147,27 +125,68 @@ QtObject:
|
|||
error "error: ", errMsg
|
||||
|
||||
proc init*(self: Service) =
|
||||
# set Tenor API Key
|
||||
self.setTenorAPIKey()
|
||||
discard
|
||||
|
||||
proc tenorQuery(self: Service, path: string): seq[GifDto] =
|
||||
proc search*(self: Service, query: string) =
|
||||
try:
|
||||
let response = backend.fetchGifs(path)
|
||||
let doc = response.result.str.parseJson()
|
||||
self.events.emit(SIGNAL_SEARCH_GIFS_STARTED, Args())
|
||||
let arg = AsyncTenorQueryArg(
|
||||
tptr: cast[ByteAddress](asyncTenorQuery),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "onAsyncTenorQueryDone",
|
||||
apiKeySet: self.apiKeySet,
|
||||
apiKey: TENOR_API_KEY_RESOLVED,
|
||||
query: fmt("search?q={encodeUrl(query)}"),
|
||||
event: SIGNAL_SEARCH_GIFS_DONE,
|
||||
errorEvent: SIGNAL_SEARCH_GIFS_ERROR,
|
||||
)
|
||||
self.threadpool.start(arg)
|
||||
except Exception as e:
|
||||
error "Error getting trending gifs", msg = e.msg
|
||||
|
||||
proc getTrending*(self: Service) =
|
||||
if self.trending.len > 0:
|
||||
self.events.emit(SIGNAL_LOAD_TRENDING_GIFS_DONE, GifsArgs(gifs: self.trending))
|
||||
return
|
||||
try:
|
||||
self.events.emit(SIGNAL_LOAD_TRENDING_GIFS_STARTED, Args())
|
||||
let arg = AsyncTenorQueryArg(
|
||||
tptr: cast[ByteAddress](asyncTenorQuery),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "onAsyncTenorQueryDone",
|
||||
apiKeySet: self.apiKeySet,
|
||||
apiKey: TENOR_API_KEY_RESOLVED,
|
||||
query: "trending?",
|
||||
event: SIGNAL_LOAD_TRENDING_GIFS_DONE,
|
||||
errorEvent: SIGNAL_LOAD_TRENDING_GIFS_ERROR,
|
||||
)
|
||||
self.threadpool.start(arg)
|
||||
except Exception as e:
|
||||
error "Error getting trending gifs", msg = e.msg
|
||||
|
||||
proc onAsyncTenorQueryDone*(self: Service, response: string) {.slot.} =
|
||||
let rpcResponseObj = response.parseJson
|
||||
try:
|
||||
if (rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != ""):
|
||||
raise newException(RpcException, rpcResponseObj{"error"}.getStr)
|
||||
|
||||
self.apiKeySet = true
|
||||
|
||||
let itemsJson = rpcResponseObj["items"]
|
||||
|
||||
var items: seq[GifDto] = @[]
|
||||
for json in doc["results"]:
|
||||
items.add(tenorToGifDto(json))
|
||||
for itemJson in itemsJson.items:
|
||||
items.add(itemJson.settingToGifDto)
|
||||
|
||||
return items
|
||||
except:
|
||||
return @[]
|
||||
|
||||
proc search*(self: Service, query: string): seq[GifDto] =
|
||||
return self.tenorQuery(fmt("search?q={encodeUrl(query)}"))
|
||||
|
||||
proc getTrendings*(self: Service): seq[GifDto] =
|
||||
return self.tenorQuery("trending?")
|
||||
if rpcResponseObj["event"].getStr == SIGNAL_LOAD_TRENDING_GIFS_DONE:
|
||||
# Save trending gifs in a local cache to not have to fetch them multiple times
|
||||
self.trending = items
|
||||
|
||||
self.events.emit(rpcResponseObj["event"].getStr, GifsArgs(gifs: items))
|
||||
except Exception as e:
|
||||
let errMsg = e.msg
|
||||
error "Error requesting sending query to Tenor", msg = errMsg
|
||||
self.events.emit(rpcResponseObj["errorEvent"].getStr, GifsArgs(error: errMsg))
|
||||
|
||||
proc getRecents*(self: Service): seq[GifDto] =
|
||||
return self.recents
|
||||
|
@ -190,7 +209,7 @@ QtObject:
|
|||
|
||||
self.recents = newRecents
|
||||
let recent = %*{"items": map(newRecents, toJsonNode)}
|
||||
discard backend.updateRecentGifs(recent)
|
||||
discard status_go.updateRecentGifs(recent)
|
||||
|
||||
proc getFavorites*(self: Service): seq[GifDto] =
|
||||
return self.favorites
|
||||
|
@ -217,4 +236,4 @@ QtObject:
|
|||
|
||||
self.favorites = newFavorites
|
||||
let favorites = %*{"items": map(newFavorites, toJsonNode)}
|
||||
discard backend.updateFavoriteGifs(favorites)
|
||||
discard status_go.updateFavoriteGifs(favorites)
|
||||
|
|
|
@ -39,6 +39,7 @@ Popup {
|
|||
property alias searchString: searchBox.text
|
||||
property int currentCategory: GifPopupDefinitions.Category.Trending
|
||||
property int previousCategory: GifPopupDefinitions.Category.Trending
|
||||
property bool loading: RootStore.gifLoading
|
||||
|
||||
modal: false
|
||||
width: 360
|
||||
|
@ -264,6 +265,7 @@ Popup {
|
|||
|
||||
EmptyPlaceholder {
|
||||
currentCategory: root.currentCategory
|
||||
loading: root.loading
|
||||
onDoRetry: searchBox.text === ""
|
||||
? RootStore.getTrendingsGifs()
|
||||
: searchGif(searchBox.text)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
|
@ -10,7 +10,8 @@ import utils 1.0
|
|||
Rectangle {
|
||||
id: root
|
||||
|
||||
/*required*/ property int currentCategory: GifPopupDefinitions.Category.Trending
|
||||
required property int currentCategory;
|
||||
property bool loading: false
|
||||
|
||||
signal doRetry()
|
||||
|
||||
|
@ -20,9 +21,13 @@ Rectangle {
|
|||
id: emptyText
|
||||
anchors.centerIn: parent
|
||||
text: {
|
||||
if(root.currentCategory === GifPopupDefinitions.Category.Favorite) {
|
||||
if (root.loading) {
|
||||
return qsTr("Loading gifs...")
|
||||
}
|
||||
if (root.currentCategory === GifPopupDefinitions.Category.Favorite) {
|
||||
return qsTr("Favorite GIFs will appear here")
|
||||
} else if(root.currentCategory === GifPopupDefinitions.Category.Recent) {
|
||||
}
|
||||
if (root.currentCategory === GifPopupDefinitions.Category.Recent) {
|
||||
return qsTr("Recent GIFs will appear here")
|
||||
}
|
||||
|
||||
|
@ -35,7 +40,9 @@ Rectangle {
|
|||
StatusButton {
|
||||
text: qsTr("Retry")
|
||||
|
||||
visible: root.currentCategory === GifPopupDefinitions.Category.Trending || root.currentCategory === GifPopupDefinitions.Category.Search
|
||||
visible: !root.loading &&
|
||||
(root.currentCategory === GifPopupDefinitions.Category.Trending ||
|
||||
root.currentCategory === GifPopupDefinitions.Category.Search)
|
||||
|
||||
anchors.top: emptyText.bottom
|
||||
anchors.topMargin: Style.current.padding
|
||||
|
|
|
@ -108,6 +108,8 @@ QtObject {
|
|||
: null
|
||||
property var gifColumnC: chatSectionChatContentInputAreaInst ? chatSectionChatContentInputArea.gifColumnC
|
||||
: null
|
||||
property bool gifLoading: chatSectionChatContentInputAreaInst ? chatSectionChatContentInputArea.gifLoading
|
||||
: false
|
||||
|
||||
function searchGifs(query) {
|
||||
if (chatSectionChatContentInputAreaInst)
|
||||
|
|
Loading…
Reference in New Issue