feat: call getPreviewData (url unfurling) in a separate thread

Fixes #1678
This commit is contained in:
Jonathan Rainville 2021-01-15 15:33:32 -05:00 committed by Iuri Matias
parent 0daf355f54
commit 444072f599
4 changed files with 53 additions and 22 deletions

View File

@ -1,6 +1,7 @@
import NimQml, Tables, json, sequtils, chronicles, times, re, sugar, strutils, os, strformat import NimQml, Tables, json, sequtils, chronicles, times, re, sugar, strutils, os, strformat
import ../../status/status import ../../status/status
import ../../status/mailservers import ../../status/mailservers
import ../../status/libstatus/chat as libstatus_chat
import ../../status/libstatus/accounts/constants import ../../status/libstatus/accounts/constants
import ../../status/libstatus/mailservers as status_mailservers import ../../status/libstatus/mailservers as status_mailservers
import ../../status/libstatus/types import ../../status/libstatus/types
@ -386,11 +387,17 @@ QtObject:
proc copyToClipboard*(self: ChatsView, content: string) {.slot.} = proc copyToClipboard*(self: ChatsView, content: string) {.slot.} =
setClipBoardText(content) setClipBoardText(content)
proc getLinkPreviewData*(self: ChatsView, link: string): string {.slot.} = proc linkPreviewDataWasReceived*(self: ChatsView, previewData: string) {.signal.}
try:
$self.status.chat.getLinkPreviewData(link) proc linkPreviewDataReceived(self: ChatsView, previewData: string) {.slot.} =
except RpcException as e: self.linkPreviewDataWasReceived(previewData)
$ %* { "error": e.msg }
proc getLinkPreviewData*(self: ChatsView, link: string, uuid: string) {.slot.} =
spawnAndSend(self, "linkPreviewDataReceived") do:
var success: bool
# We need to call directly on libstatus because going through the status model is not thread safe
let response = libstatus_chat.getLinkPreviewData(link, success)
$(%* { "result": %response, "success": %success, "uuid": %uuid })
proc joinChat*(self: ChatsView, channel: string, chatTypeInt: int): int {.slot.} = proc joinChat*(self: ChatsView, channel: string, chatTypeInt: int): int {.slot.} =
self.status.chat.join(channel, ChatType(chatTypeInt)) self.status.chat.join(channel, ChatType(chatTypeInt))

View File

@ -218,9 +218,6 @@ proc clearHistory*(self: ChatModel, chatId: string) =
let chat = self.channels[chatId] let chat = self.channels[chatId]
self.events.emit("chatHistoryCleared", ChannelArgs(chat: chat)) self.events.emit("chatHistoryCleared", ChannelArgs(chat: chat))
proc getLinkPreviewData*(self: ChatModel, link: string): JsonNode =
result = status_chat.getLinkPreviewData(link)
proc setActiveChannel*(self: ChatModel, chatId: string) = proc setActiveChannel*(self: ChatModel, chatId: string) =
self.events.emit("activeChannelChanged", ChatIdArg(chatId: chatId)) self.events.emit("activeChannelChanged", ChatIdArg(chatId: chatId))

View File

@ -201,14 +201,16 @@ proc muteChat*(chatId: string): string =
proc unmuteChat*(chatId: string): string = proc unmuteChat*(chatId: string): string =
result = callPrivateRPC("unmuteChat".prefix, %*[chatId]) result = callPrivateRPC("unmuteChat".prefix, %*[chatId])
proc getLinkPreviewData*(link: string): JsonNode = proc getLinkPreviewData*(link: string, success: var bool): JsonNode =
let let
responseStr = callPrivateRPC("getLinkPreviewData".prefix, %*[link]) responseStr = callPrivateRPC("getLinkPreviewData".prefix, %*[link])
response = Json.decode(responseStr, RpcResponseTyped[JsonNode], allowUnknownFields = false) response = Json.decode(responseStr, RpcResponseTyped[JsonNode], allowUnknownFields = false)
if not response.error.isNil: if not response.error.isNil:
raise newException(RpcException, fmt"""Error getting link preview data for '{link}': {response.error.message}""") success = false
return %* { "error": fmt"""Error getting link preview data for '{link}': {response.error.message}""" }
success = true
response.result response.result
proc getAllComunities*(): seq[Community] = proc getAllComunities*(): seq[Community] =

View File

@ -12,6 +12,7 @@ Column {
property string linkUrls: "" property string linkUrls: ""
property var container property var container
property bool isCurrentUser: false property bool isCurrentUser: false
readonly property string uuid: Utils.uuid()
spacing: Style.current.halfPadding spacing: Style.current.halfPadding
ListModel { ListModel {
@ -32,6 +33,7 @@ Column {
delegate: Loader { delegate: Loader {
id: linkMessageLoader id: linkMessageLoader
property bool fetched: false
property var linkData property var linkData
property int linkWidth: linksRepeater.width property int linkWidth: linksRepeater.width
active: true active: true
@ -51,6 +53,37 @@ Column {
linkMessageLoader.sourceComponent = linkMessageLoader.getSourceComponent() linkMessageLoader.sourceComponent = linkMessageLoader.getSourceComponent()
} }
} }
Connections {
target: chatsModel
onLinkPreviewDataWasReceived: {
let response
try {
response = JSON.parse(previewData)
} catch (e) {
console.error(previewData, e)
return
}
if (response.uuid !== root.uuid) return
if (!response.success) {
console.error(response.result.error)
return undefined
}
linkData = response.result
if (linkData.contentType.startsWith("image/")) {
return linkMessageLoader.sourceComponent = unfurledImageComponent
}
if (linkData.site && linkData.title) {
linkData.address = link
return linkMessageLoader.sourceComponent = unfurledLinkComponent
}
}
}
function getSourceComponent() { function getSourceComponent() {
// Reset the height in case we set it to 0 below. See note below // Reset the height in case we set it to 0 below. See note below
@ -75,19 +108,11 @@ Column {
return enableLinkComponent return enableLinkComponent
} }
if (linkWhiteListed) { if (linkWhiteListed) {
const data = chatsModel.getLinkPreviewData(link) if (fetched) {
linkData = JSON.parse(data) return
if (linkData.error) {
console.error(linkData.error)
return undefined
}
if (linkData.contentType.startsWith("image/")) {
return unfurledImageComponent
}
if (linkData.site && linkData.title) {
linkData.address = link
return unfurledLinkComponent
} }
fetched = true
return chatsModel.getLinkPreviewData(link, root.uuid)
} }
// setting the height to 0 allows the "enable link" dialog to // setting the height to 0 allows the "enable link" dialog to
// disappear correctly when appSettings.neverAskAboutUnfurlingAgain // disappear correctly when appSettings.neverAskAboutUnfurlingAgain