feat: remove all remaining spawnAndSends
refactor: move threadpool task declarations inline with views Co-authored-by: Michael Bradley Jr. <michaelsbradleyjr@gmail.com> Co-authored-by: Eric Mastro <eric.mastro@gmail.com>
This commit is contained in:
parent
686cbc7f54
commit
1200632989
|
@ -14,18 +14,87 @@ import ../../status/ens as status_ens
|
||||||
import ../../status/chat/[chat, message]
|
import ../../status/chat/[chat, message]
|
||||||
import ../../status/profile/profile
|
import ../../status/profile/profile
|
||||||
import web3/[conversions, ethtypes]
|
import web3/[conversions, ethtypes]
|
||||||
import ../../status/threads
|
|
||||||
import views/[channels_list, message_list, chat_item, suggestions_list, reactions, stickers, groups, transactions, communities, community_list, community_item]
|
import views/[channels_list, message_list, chat_item, suggestions_list, reactions, stickers, groups, transactions, communities, community_list, community_item]
|
||||||
import json_serialization
|
|
||||||
import ../utils/image_utils
|
import ../utils/image_utils
|
||||||
|
import ../../status/tasks/[qt, task_runner_impl]
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "chats-view"
|
topics = "chats-view"
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
ChatViewRoles {.pure.} = enum
|
ChatViewRoles {.pure.} = enum
|
||||||
MessageList = UserRole + 1
|
MessageList = UserRole + 1
|
||||||
|
GetLinkPreviewDataTaskArg = ref object of QObjectTaskArg
|
||||||
|
link: string
|
||||||
|
uuid: string
|
||||||
|
AsyncMessageLoadTaskArg = ref object of QObjectTaskArg
|
||||||
|
chatId: string
|
||||||
|
ResolveEnsTaskArg = ref object of QObjectTaskArg
|
||||||
|
ens: string
|
||||||
|
|
||||||
|
const getLinkPreviewDataTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[GetLinkPreviewDataTaskArg](argEncoded)
|
||||||
|
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(arg.link, success)
|
||||||
|
responseJson = %* { "result": %response, "success": %success, "uuid": %arg.uuid }
|
||||||
|
arg.finish(responseJson)
|
||||||
|
|
||||||
|
proc getLinkPreviewData[T](self: T, slot: string, link: string, uuid: string) =
|
||||||
|
let arg = GetLinkPreviewDataTaskArg(
|
||||||
|
tptr: cast[ByteAddress](getLinkPreviewDataTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
link: link,
|
||||||
|
uuid: uuid
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
|
const asyncMessageLoadTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[AsyncMessageLoadTaskArg](argEncoded)
|
||||||
|
var messages: JsonNode
|
||||||
|
var msgCallSuccess: bool
|
||||||
|
let msgCallResult = rpcChatMessages(arg.chatId, newJString(""), 20, msgCallSuccess)
|
||||||
|
if(msgCallSuccess):
|
||||||
|
messages = msgCallResult.parseJson()["result"]
|
||||||
|
|
||||||
|
var reactions: JsonNode
|
||||||
|
var reactionsCallSuccess: bool
|
||||||
|
let reactionsCallResult = rpcReactions(arg.chatId, newJString(""), 20, reactionsCallSuccess)
|
||||||
|
if(reactionsCallSuccess):
|
||||||
|
reactions = reactionsCallResult.parseJson()["result"]
|
||||||
|
|
||||||
|
let responseJson = %*{
|
||||||
|
"chatId": arg.chatId,
|
||||||
|
"messages": messages,
|
||||||
|
"reactions": reactions
|
||||||
|
}
|
||||||
|
arg.finish(responseJson)
|
||||||
|
|
||||||
|
proc asyncMessageLoad[T](self: T, slot: string, chatId: string) =
|
||||||
|
let arg = AsyncMessageLoadTaskArg(
|
||||||
|
tptr: cast[ByteAddress](asyncMessageLoadTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
chatId: chatId
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
|
const resolveEnsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let
|
||||||
|
arg = decode[ResolveEnsTaskArg](argEncoded)
|
||||||
|
result = status_ens.pubkey(arg.ens)
|
||||||
|
arg.finish(result)
|
||||||
|
|
||||||
|
proc resolveEns[T](self: T, slot: string, ens: string) =
|
||||||
|
let arg = ResolveEnsTaskArg(
|
||||||
|
tptr: cast[ByteAddress](asyncMessageLoadTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
ens: ens
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type
|
type
|
||||||
|
@ -487,11 +556,7 @@ QtObject:
|
||||||
self.linkPreviewDataWasReceived(previewData)
|
self.linkPreviewDataWasReceived(previewData)
|
||||||
|
|
||||||
proc getLinkPreviewData*(self: ChatsView, link: string, uuid: string) {.slot.} =
|
proc getLinkPreviewData*(self: ChatsView, link: string, uuid: string) {.slot.} =
|
||||||
spawnAndSend(self, "linkPreviewDataReceived") do:
|
self.getLinkPreviewData("linkPreviewDataReceived", link, uuid)
|
||||||
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))
|
||||||
|
@ -524,26 +589,7 @@ QtObject:
|
||||||
proc loadingMessagesChanged*(self: ChatsView, value: bool) {.signal.}
|
proc loadingMessagesChanged*(self: ChatsView, value: bool) {.signal.}
|
||||||
|
|
||||||
proc asyncMessageLoad*(self: ChatsView, chatId: string) {.slot.} =
|
proc asyncMessageLoad*(self: ChatsView, chatId: string) {.slot.} =
|
||||||
spawnAndSend(self, "asyncMessageLoaded") do: # Call self.ensResolved(string) when ens is resolved
|
self.asyncMessageLoad("asyncMessageLoaded", chatId)
|
||||||
|
|
||||||
var messages: JsonNode
|
|
||||||
var msgCallSuccess: bool
|
|
||||||
let msgCallResult = rpcChatMessages(chatId, newJString(""), 20, msgCallSuccess)
|
|
||||||
if(msgCallSuccess):
|
|
||||||
messages = msgCallResult.parseJson()["result"]
|
|
||||||
|
|
||||||
var reactions: JsonNode
|
|
||||||
var reactionsCallSuccess: bool
|
|
||||||
let reactionsCallResult = rpcReactions(chatId, newJString(""), 20, reactionsCallSuccess)
|
|
||||||
if(reactionsCallSuccess):
|
|
||||||
reactions = reactionsCallResult.parseJson()["result"]
|
|
||||||
|
|
||||||
|
|
||||||
$(%*{
|
|
||||||
"chatId": chatId,
|
|
||||||
"messages": messages,
|
|
||||||
"reactions": reactions
|
|
||||||
})
|
|
||||||
|
|
||||||
proc asyncMessageLoaded*(self: ChatsView, rpcResponse: string) {.slot.} =
|
proc asyncMessageLoaded*(self: ChatsView, rpcResponse: string) {.slot.} =
|
||||||
let rpcResponseObj = rpcResponse.parseJson
|
let rpcResponseObj = rpcResponse.parseJson
|
||||||
|
@ -677,8 +723,7 @@ QtObject:
|
||||||
|
|
||||||
# Resolving a ENS name
|
# Resolving a ENS name
|
||||||
proc resolveENS*(self: ChatsView, ens: string) {.slot.} =
|
proc resolveENS*(self: ChatsView, ens: string) {.slot.} =
|
||||||
spawnAndSend(self, "ensResolved") do: # Call self.ensResolved(string) when ens is resolved
|
self.resolveEns("ensResolved", ens) # Call self.ensResolved(string) when ens is resolved
|
||||||
status_ens.pubkey(ens)
|
|
||||||
|
|
||||||
proc ensWasResolved*(self: ChatsView, resolvedPubKey: string) {.signal.}
|
proc ensWasResolved*(self: ChatsView, resolvedPubKey: string) {.signal.}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,67 @@
|
||||||
import NimQml, tables, json, chronicles, sets, strutils
|
import NimQml, tables, json, chronicles, sets, strutils
|
||||||
import ../../../status/[status, stickers, threads]
|
import ../../../status/[status, stickers]
|
||||||
import ../../../status/libstatus/[types, utils]
|
import ../../../status/libstatus/[types, utils]
|
||||||
import ../../../status/libstatus/stickers as status_stickers
|
import ../../../status/libstatus/stickers as status_stickers
|
||||||
import ../../../status/libstatus/wallet as status_wallet
|
import ../../../status/libstatus/wallet as status_wallet
|
||||||
import sticker_pack_list, sticker_list, chat_item
|
import sticker_pack_list, sticker_list, chat_item
|
||||||
import json_serialization
|
import ../../../status/tasks/[qt, task_runner_impl]
|
||||||
import ../../../status/tasks/task_manager
|
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "stickers-view"
|
topics = "stickers-view"
|
||||||
|
|
||||||
|
type
|
||||||
|
EstimateTaskArg = ref object of QObjectTaskArg
|
||||||
|
packId: int
|
||||||
|
address: string
|
||||||
|
price: string
|
||||||
|
uuid: string
|
||||||
|
ObtainAvailableStickerPacksTaskArg = ref object of QObjectTaskArg
|
||||||
|
|
||||||
|
# The pragmas `{.gcsafe, nimcall.}` in this context do not force the compiler
|
||||||
|
# to accept unsafe code, rather they work in conjunction with the proc
|
||||||
|
# signature for `type Task` in tasks/common.nim to ensure that the proc really
|
||||||
|
# is gcsafe and that a helpful error message is displayed
|
||||||
|
const estimateTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[EstimateTaskArg](argEncoded)
|
||||||
|
var success: bool
|
||||||
|
var estimate = estimateGas(arg.packId, arg.address, arg.price,
|
||||||
|
success)
|
||||||
|
if not success:
|
||||||
|
estimate = 325000
|
||||||
|
let tpl: tuple[estimate: int, uuid: string] = (estimate, arg.uuid)
|
||||||
|
arg.finish(tpl)
|
||||||
|
|
||||||
|
# the [T] here is annoying but the QtObject template only allows for one type
|
||||||
|
# definition so we'll need to setup the type, task, and helper outside of body
|
||||||
|
# passed to `QtObject:`
|
||||||
|
proc estimate[T](self: T, slot: string, packId: int, address: string, price: string,
|
||||||
|
uuid: string) =
|
||||||
|
let arg = EstimateTaskArg(
|
||||||
|
tptr: cast[ByteAddress](estimateTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
packId: packId,
|
||||||
|
address: address,
|
||||||
|
price: price,
|
||||||
|
uuid: uuid
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
|
const obtainAvailableStickerPacksTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[ObtainAvailableStickerPacksTaskArg](argEncoded)
|
||||||
|
let availableStickerPacks = status_stickers.getAvailableStickerPacks()
|
||||||
|
var packs: seq[StickerPack] = @[]
|
||||||
|
for packId, stickerPack in availableStickerPacks.pairs:
|
||||||
|
packs.add(stickerPack)
|
||||||
|
arg.finish(%*(packs))
|
||||||
|
|
||||||
|
proc obtainAvailableStickerPacks[T](self: T, slot: string) =
|
||||||
|
let arg = ObtainAvailableStickerPacksTaskArg(
|
||||||
|
tptr: cast[ByteAddress](obtainAvailableStickerPacksTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type StickersView* = ref object of QObject
|
type StickersView* = ref object of QObject
|
||||||
status: Status
|
status: Status
|
||||||
|
@ -46,7 +98,7 @@ QtObject:
|
||||||
proc transactionCompleted*(self: StickersView, success: bool, txHash: string, revertReason: string = "") {.signal.}
|
proc transactionCompleted*(self: StickersView, success: bool, txHash: string, revertReason: string = "") {.signal.}
|
||||||
|
|
||||||
proc estimate*(self: StickersView, packId: int, address: string, price: string, uuid: string) {.slot.} =
|
proc estimate*(self: StickersView, packId: int, address: string, price: string, uuid: string) {.slot.} =
|
||||||
self.status.taskManager.threadPool.stickers.stickerPackPurchaseGasEstimate(cast[pointer](self.vptr), "setGasEstimate", packId, address, price, uuid)
|
self.estimate("setGasEstimate", packId, address, price, uuid)
|
||||||
|
|
||||||
proc gasEstimateReturned*(self: StickersView, estimate: int, uuid: string) {.signal.}
|
proc gasEstimateReturned*(self: StickersView, estimate: int, uuid: string) {.signal.}
|
||||||
|
|
||||||
|
@ -65,7 +117,7 @@ QtObject:
|
||||||
self.transactionWasSent(response)
|
self.transactionWasSent(response)
|
||||||
|
|
||||||
proc obtainAvailableStickerPacks*(self: StickersView) =
|
proc obtainAvailableStickerPacks*(self: StickersView) =
|
||||||
self.status.taskManager.threadPool.stickers.obtainAvailableStickerPacks(cast[pointer](self.vptr), "setAvailableStickerPacks")
|
self.obtainAvailableStickerPacks("setAvailableStickerPacks")
|
||||||
|
|
||||||
proc stickerPacksLoaded*(self: StickersView) {.signal.}
|
proc stickerPacksLoaded*(self: StickersView) {.signal.}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import ../../status/libstatus/settings as status_settings
|
||||||
import ../../status/status
|
import ../../status/status
|
||||||
import ../../status/ens as status_ens
|
import ../../status/ens as status_ens
|
||||||
import ../../status/chat/chat
|
import ../../status/chat/chat
|
||||||
import ../../status/threads
|
|
||||||
import ../../status/libstatus/types
|
import ../../status/libstatus/types
|
||||||
import ../../status/libstatus/accounts/constants as accountConstants
|
import ../../status/libstatus/accounts/constants as accountConstants
|
||||||
import qrcode/qrcode
|
import qrcode/qrcode
|
||||||
|
|
|
@ -1,15 +1,35 @@
|
||||||
import NimQml, chronicles, sequtils, sugar, strutils
|
import NimQml, chronicles, sequtils, sugar, strutils
|
||||||
import ../../../status/libstatus/utils as status_utils
|
import ../../../status/libstatus/utils as status_utils
|
||||||
import ../../../status/status
|
import ../../../status/status
|
||||||
import ../../../status/threads
|
|
||||||
import ../../../status/chat/chat
|
import ../../../status/chat/chat
|
||||||
import contact_list
|
import contact_list
|
||||||
import ../../../status/profile/profile
|
import ../../../status/profile/profile
|
||||||
import ../../../status/ens as status_ens
|
import ../../../status/ens as status_ens
|
||||||
|
import ../../../status/tasks/[qt, task_runner_impl]
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "contacts-view"
|
topics = "contacts-view"
|
||||||
|
|
||||||
|
type
|
||||||
|
LookupContactTaskArg = ref object of QObjectTaskArg
|
||||||
|
value: string
|
||||||
|
|
||||||
|
const lookupContactTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[LookupContactTaskArg](argEncoded)
|
||||||
|
var id = arg.value
|
||||||
|
if not id.startsWith("0x"):
|
||||||
|
id = status_ens.pubkey(id)
|
||||||
|
arg.finish(id)
|
||||||
|
|
||||||
|
proc lookupContact[T](self: T, slot: string, value: string) =
|
||||||
|
let arg = LookupContactTaskArg(
|
||||||
|
tptr: cast[ByteAddress](lookupContactTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
value: value
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type ContactsView* = ref object of QObject
|
type ContactsView* = ref object of QObject
|
||||||
status: Status
|
status: Status
|
||||||
|
@ -113,11 +133,7 @@ QtObject:
|
||||||
if value == "":
|
if value == "":
|
||||||
return
|
return
|
||||||
|
|
||||||
spawnAndSend(self, "ensResolved") do: # Call self.ensResolved(string) when ens is resolved
|
self.lookupContact("ensResolved", value)
|
||||||
var id = value
|
|
||||||
if not id.startsWith("0x"):
|
|
||||||
id = status_ens.pubkey(id)
|
|
||||||
id
|
|
||||||
|
|
||||||
proc ensWasResolved*(self: ContactsView, resolvedPubKey: string) {.signal.}
|
proc ensWasResolved*(self: ContactsView, resolvedPubKey: string) {.signal.}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import NimQml
|
import NimQml
|
||||||
import Tables
|
import Tables
|
||||||
import json
|
import json
|
||||||
import json_serialization
|
|
||||||
import sequtils
|
import sequtils
|
||||||
import strutils
|
import strutils
|
||||||
from ../../../status/libstatus/types import Setting, PendingTransactionType, RpcException
|
from ../../../status/libstatus/types import Setting, PendingTransactionType, RpcException
|
||||||
import ../../../status/threads
|
|
||||||
import ../../../status/ens as status_ens
|
import ../../../status/ens as status_ens
|
||||||
import ../../../status/libstatus/wallet as status_wallet
|
import ../../../status/libstatus/wallet as status_wallet
|
||||||
import ../../../status/libstatus/settings as status_settings
|
import ../../../status/libstatus/settings as status_settings
|
||||||
|
@ -14,11 +12,78 @@ import ../../../status/status
|
||||||
import ../../../status/wallet
|
import ../../../status/wallet
|
||||||
import sets
|
import sets
|
||||||
import web3/ethtypes
|
import web3/ethtypes
|
||||||
|
import ../../../status/tasks/[qt, task_runner_impl]
|
||||||
|
|
||||||
type
|
type
|
||||||
EnsRoles {.pure.} = enum
|
EnsRoles {.pure.} = enum
|
||||||
UserName = UserRole + 1
|
UserName = UserRole + 1
|
||||||
IsPending = UserRole + 2
|
IsPending = UserRole + 2
|
||||||
|
ValidateTaskArg = ref object of QObjectTaskArg
|
||||||
|
ens: string
|
||||||
|
isStatus: bool
|
||||||
|
usernames: seq[string]
|
||||||
|
DetailsTaskArg = ref object of QObjectTaskArg
|
||||||
|
username: string
|
||||||
|
|
||||||
|
const validateTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let
|
||||||
|
arg = decode[ValidateTaskArg](argEncoded)
|
||||||
|
username = arg.ens & (if(arg.isStatus): status_ens.domain else: "")
|
||||||
|
var output = ""
|
||||||
|
if arg.usernames.filter(proc(x: string):bool = x == username).len > 0:
|
||||||
|
output = "already-connected"
|
||||||
|
else:
|
||||||
|
let ownerAddr = status_ens.owner(username)
|
||||||
|
if ownerAddr == "" and arg.isStatus:
|
||||||
|
output = "available"
|
||||||
|
else:
|
||||||
|
let userPubKey = status_settings.getSetting[string](Setting.PublicKey, "0x0")
|
||||||
|
let userWallet = status_wallet.getWalletAccounts()[0].address
|
||||||
|
let pubkey = status_ens.pubkey(arg.ens)
|
||||||
|
if ownerAddr != "":
|
||||||
|
if pubkey == "" and ownerAddr == userWallet:
|
||||||
|
output = "owned" # "Continuing will connect this username with your chat key."
|
||||||
|
elif pubkey == userPubkey:
|
||||||
|
output = "connected"
|
||||||
|
elif ownerAddr == userWallet:
|
||||||
|
output = "connected-different-key" # "Continuing will require a transaction to connect the username with your current chat key.",
|
||||||
|
else:
|
||||||
|
output = "taken"
|
||||||
|
else:
|
||||||
|
output = "taken"
|
||||||
|
arg.finish(output)
|
||||||
|
|
||||||
|
proc validate[T](self: T, slot: string, ens: string, isStatus: bool, usernames: seq[string]) =
|
||||||
|
let arg = ValidateTaskArg(
|
||||||
|
tptr: cast[ByteAddress](validateTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
ens: ens,
|
||||||
|
isStatus: isStatus,
|
||||||
|
usernames: usernames
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
|
const detailsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let
|
||||||
|
arg = decode[DetailsTaskArg](argEncoded)
|
||||||
|
address = status_ens.address(arg.username)
|
||||||
|
pubkey = status_ens.pubkey(arg.username)
|
||||||
|
json = %* {
|
||||||
|
"ensName": arg.username,
|
||||||
|
"address": address,
|
||||||
|
"pubkey": pubkey
|
||||||
|
}
|
||||||
|
arg.finish(json)
|
||||||
|
|
||||||
|
proc details[T](self: T, slot: string, username: string) =
|
||||||
|
let arg = DetailsTaskArg(
|
||||||
|
tptr: cast[ByteAddress](detailsTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
username: username
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type EnsManager* = ref object of QAbstractListModel
|
type EnsManager* = ref object of QAbstractListModel
|
||||||
|
@ -58,31 +123,7 @@ QtObject:
|
||||||
self.ensWasResolved(ensResult)
|
self.ensWasResolved(ensResult)
|
||||||
|
|
||||||
proc validate*(self: EnsManager, ens: string, isStatus: bool) {.slot.} =
|
proc validate*(self: EnsManager, ens: string, isStatus: bool) {.slot.} =
|
||||||
let username = ens & (if(isStatus): status_ens.domain else: "")
|
self.validate("ensResolved", ens, isStatus, self.usernames)
|
||||||
if self.usernames.filter(proc(x: string):bool = x == username).len > 0:
|
|
||||||
self.ensResolved("already-connected")
|
|
||||||
else:
|
|
||||||
spawnAndSend(self, "ensResolved") do:
|
|
||||||
let ownerAddr = status_ens.owner(username)
|
|
||||||
var output = ""
|
|
||||||
if ownerAddr == "" and isStatus:
|
|
||||||
output = "available"
|
|
||||||
else:
|
|
||||||
let userPubKey = status_settings.getSetting[string](Setting.PublicKey, "0x0")
|
|
||||||
let userWallet = status_wallet.getWalletAccounts()[0].address
|
|
||||||
let pubkey = status_ens.pubkey(ens)
|
|
||||||
if ownerAddr != "":
|
|
||||||
if pubkey == "" and ownerAddr == userWallet:
|
|
||||||
output = "owned" # "Continuing will connect this username with your chat key."
|
|
||||||
elif pubkey == userPubkey:
|
|
||||||
output = "connected"
|
|
||||||
elif ownerAddr == userWallet:
|
|
||||||
output = "connected-different-key" # "Continuing will require a transaction to connect the username with your current chat key.",
|
|
||||||
else:
|
|
||||||
output = "taken"
|
|
||||||
else:
|
|
||||||
output = "taken"
|
|
||||||
output
|
|
||||||
|
|
||||||
proc add*(self: EnsManager, username: string) =
|
proc add*(self: EnsManager, username: string) =
|
||||||
self.beginInsertRows(newQModelIndex(), self.usernames.len, self.usernames.len)
|
self.beginInsertRows(newQModelIndex(), self.usernames.len, self.usernames.len)
|
||||||
|
@ -119,14 +160,7 @@ QtObject:
|
||||||
|
|
||||||
proc details(self: EnsManager, username: string) {.slot.} =
|
proc details(self: EnsManager, username: string) {.slot.} =
|
||||||
self.loading(true)
|
self.loading(true)
|
||||||
spawnAndSend(self, "setDetails") do:
|
self.details("setDetails", username)
|
||||||
let address = status_ens.address(username)
|
|
||||||
let pubkey = status_ens.pubkey(username)
|
|
||||||
$(%* {
|
|
||||||
"ensName": username,
|
|
||||||
"address": address,
|
|
||||||
"pubkey": pubkey
|
|
||||||
})
|
|
||||||
|
|
||||||
proc detailsObtained(self: EnsManager, ensName: string, address: string, pubkey: string) {.signal.}
|
proc detailsObtained(self: EnsManager, ensName: string, address: string, pubkey: string) {.signal.}
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ QtObject:
|
||||||
|
|
||||||
var success: bool
|
var success: bool
|
||||||
# TODO make this async
|
# TODO make this async
|
||||||
let response = status.wallet.sendTransaction(fromAddress, to, value, selectedGasLimit, selectedGasPrice, password, success, txData)
|
let response = wallet.sendTransaction(fromAddress, to, value, selectedGasLimit, selectedGasPrice, password, success, txData)
|
||||||
let errorMessage = if not success:
|
let errorMessage = if not success:
|
||||||
if response == "":
|
if response == "":
|
||||||
"web3-response-error"
|
"web3-response-error"
|
||||||
|
|
|
@ -71,7 +71,7 @@ proc init*(self: WalletController) =
|
||||||
self.view.transactionCompleted(tx.success, tx.transactionHash, tx.revertReason)
|
self.view.transactionCompleted(tx.success, tx.transactionHash, tx.revertReason)
|
||||||
|
|
||||||
proc checkPendingTransactions*(self: WalletController) =
|
proc checkPendingTransactions*(self: WalletController) =
|
||||||
self.status.wallet.checkPendingTransactions() # TODO: consider doing this in a spawnAndSend
|
self.status.wallet.checkPendingTransactions() # TODO: consider doing this in a threadpool task
|
||||||
|
|
||||||
proc start*(self: WalletController) =
|
proc start*(self: WalletController) =
|
||||||
status_wallet.startWallet(false)
|
status_wallet.startWallet(false)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import NimQml, Tables, strformat, strutils, chronicles, sequtils, json, std/wrapnils, parseUtils, stint, tables, json_serialization
|
import NimQml, Tables, strformat, strutils, chronicles, sequtils, json, std/wrapnils, parseUtils, stint, tables
|
||||||
import ../../status/[status, wallet, threads]
|
import ../../status/[status, wallet]
|
||||||
import ../../status/wallet/collectibles as status_collectibles
|
import ../../status/wallet/collectibles as status_collectibles
|
||||||
import ../../status/libstatus/accounts/constants
|
import ../../status/libstatus/accounts/constants
|
||||||
import ../../status/libstatus/wallet as status_wallet
|
import ../../status/libstatus/wallet as status_wallet
|
||||||
|
@ -10,6 +10,160 @@ import ../../status/libstatus/utils as status_utils
|
||||||
import ../../status/libstatus/eth/contracts
|
import ../../status/libstatus/eth/contracts
|
||||||
import ../../status/ens as status_ens
|
import ../../status/ens as status_ens
|
||||||
import views/[asset_list, account_list, account_item, token_list, transaction_list, collectibles_list]
|
import views/[asset_list, account_list, account_item, token_list, transaction_list, collectibles_list]
|
||||||
|
import ../../status/tasks/[qt, task_runner_impl]
|
||||||
|
|
||||||
|
type
|
||||||
|
SendTransactionTaskArg = ref object of QObjectTaskArg
|
||||||
|
from_addr: string
|
||||||
|
to: string
|
||||||
|
assetAddress: string
|
||||||
|
value: string
|
||||||
|
gas: string
|
||||||
|
gasPrice: string
|
||||||
|
password: string
|
||||||
|
uuid: string
|
||||||
|
InitBalancesTaskArg = ref object of QObjectTaskArg
|
||||||
|
address: string
|
||||||
|
tokenList: seq[string]
|
||||||
|
LoadCollectiblesTaskArg = ref object of QObjectTaskArg
|
||||||
|
address: string
|
||||||
|
collectiblesType: string
|
||||||
|
GasPredictionsTaskArg = ref object of QObjectTaskArg
|
||||||
|
LoadTransactionsTaskArg = ref object of QObjectTaskArg
|
||||||
|
address: string
|
||||||
|
blockNumber: string
|
||||||
|
ResolveEnsTaskArg = ref object of QObjectTaskArg
|
||||||
|
ens: string
|
||||||
|
uuid: string
|
||||||
|
|
||||||
|
const sendTransactionTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[SendTransactionTaskArg](argEncoded)
|
||||||
|
var
|
||||||
|
success: bool
|
||||||
|
response: string
|
||||||
|
if arg.assetAddress != ZERO_ADDRESS and not arg.assetAddress.isEmptyOrWhitespace:
|
||||||
|
response = wallet.sendTokenTransaction(arg.from_addr, arg.to, arg.assetAddress, arg.value, arg.gas, arg.gasPrice, arg.password, success)
|
||||||
|
else:
|
||||||
|
response = wallet.sendTransaction(arg.from_addr, arg.to, arg.value, arg.gas, arg.gasPrice, arg.password, success)
|
||||||
|
let output = %* { "result": %response, "success": %success, "uuid": %arg.uuid }
|
||||||
|
arg.finish(output)
|
||||||
|
|
||||||
|
proc sendTransaction[T](self: T, slot: string, from_addr: string, to: string, assetAddress: string, value: string, gas: string, gasPrice: string, password: string, uuid: string) =
|
||||||
|
let arg = SendTransactionTaskArg(
|
||||||
|
tptr: cast[ByteAddress](sendTransactionTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
from_addr: from_addr,
|
||||||
|
to: to,
|
||||||
|
assetAddress: assetAddress,
|
||||||
|
value: value,
|
||||||
|
gas: gas,
|
||||||
|
gasPrice: gasPrice,
|
||||||
|
password: password,
|
||||||
|
uuid: uuid
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
|
const initBalancesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[InitBalancesTaskArg](argEncoded)
|
||||||
|
var tokenBalances = initTable[string, string]()
|
||||||
|
for token in arg.tokenList:
|
||||||
|
tokenBalances[token] = getTokenBalance(token, arg.address)
|
||||||
|
let output = %* {
|
||||||
|
"address": arg.address,
|
||||||
|
"eth": getEthBalance(arg.address),
|
||||||
|
"tokens": tokenBalances
|
||||||
|
}
|
||||||
|
arg.finish(output)
|
||||||
|
|
||||||
|
proc initBalances[T](self: T, slot: string, address: string, tokenList: seq[string]) =
|
||||||
|
let arg = InitBalancesTaskArg(
|
||||||
|
tptr: cast[ByteAddress](initBalancesTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
address: address,
|
||||||
|
tokenList: tokenList
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
|
const loadCollectiblesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let arg = decode[LoadCollectiblesTaskArg](argEncoded)
|
||||||
|
var collectiblesOrError = ""
|
||||||
|
case arg.collectiblesType:
|
||||||
|
of status_collectibles.CRYPTOKITTY:
|
||||||
|
collectiblesOrError = status_collectibles.getCryptoKitties(arg.address)
|
||||||
|
of status_collectibles.KUDO:
|
||||||
|
collectiblesOrError = status_collectibles.getKudos(arg.address)
|
||||||
|
of status_collectibles.ETHERMON:
|
||||||
|
collectiblesOrError = status_collectibles.getEthermons(arg.address)
|
||||||
|
of status_collectibles.STICKER:
|
||||||
|
collectiblesOrError = status_collectibles.getStickers(arg.address)
|
||||||
|
|
||||||
|
let output = %*{
|
||||||
|
"address": arg.address,
|
||||||
|
"collectibleType": arg.collectiblesType,
|
||||||
|
"collectiblesOrError": collectiblesOrError
|
||||||
|
}
|
||||||
|
arg.finish(output)
|
||||||
|
|
||||||
|
proc loadCollectibles[T](self: T, slot: string, address: string, collectiblesType: string) =
|
||||||
|
let arg = LoadCollectiblesTaskArg(
|
||||||
|
tptr: cast[ByteAddress](loadCollectiblesTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
address: address,
|
||||||
|
collectiblesType: collectiblesType,
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
|
const getGasPredictionsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let
|
||||||
|
arg = decode[GasPredictionsTaskArg](argEncoded)
|
||||||
|
output = %getGasPricePredictions()
|
||||||
|
arg.finish(output)
|
||||||
|
|
||||||
|
proc getGasPredictions[T](self: T, slot: string) =
|
||||||
|
let arg = GasPredictionsTaskArg(
|
||||||
|
tptr: cast[ByteAddress](getGasPredictionsTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
|
const loadTransactionsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let
|
||||||
|
arg = decode[LoadTransactionsTaskArg](argEncoded)
|
||||||
|
output = %*{
|
||||||
|
"address": arg.address,
|
||||||
|
"history": getTransfersByAddress(arg.address, arg.blockNumber)
|
||||||
|
}
|
||||||
|
arg.finish(output)
|
||||||
|
|
||||||
|
proc loadTransactions[T](self: T, slot: string, address: string, blockNumber: string) =
|
||||||
|
let arg = LoadTransactionsTaskArg(
|
||||||
|
tptr: cast[ByteAddress](loadTransactionsTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
address: address,
|
||||||
|
blockNumber: blockNumber
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
|
const resolveEnsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let
|
||||||
|
arg = decode[ResolveEnsTaskArg](argEncoded)
|
||||||
|
output = %* { "address": status_ens.address(arg.ens), "uuid": arg.uuid }
|
||||||
|
arg.finish(output)
|
||||||
|
|
||||||
|
proc resolveEns[T](self: T, slot: string, ens: string, uuid: string) =
|
||||||
|
let arg = ResolveEnsTaskArg(
|
||||||
|
tptr: cast[ByteAddress](resolveEnsTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
ens: ens,
|
||||||
|
uuid: uuid
|
||||||
|
)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type
|
type
|
||||||
|
@ -60,8 +214,8 @@ QtObject:
|
||||||
result.currentAssetList = newAssetList()
|
result.currentAssetList = newAssetList()
|
||||||
result.currentTransactions = newTransactionList()
|
result.currentTransactions = newTransactionList()
|
||||||
result.currentCollectiblesLists = newCollectiblesList()
|
result.currentCollectiblesLists = newCollectiblesList()
|
||||||
result.defaultTokenList = newTokenList()
|
result.defaultTokenList = newTokenList(status)
|
||||||
result.customTokenList = newTokenList()
|
result.customTokenList = newTokenList(status)
|
||||||
result.totalFiatBalance = ""
|
result.totalFiatBalance = ""
|
||||||
result.etherscanLink = ""
|
result.etherscanLink = ""
|
||||||
result.safeLowGasPrice = "0"
|
result.safeLowGasPrice = "0"
|
||||||
|
@ -292,17 +446,7 @@ QtObject:
|
||||||
self.transactionWasSent(txResult)
|
self.transactionWasSent(txResult)
|
||||||
|
|
||||||
proc sendTransaction*(self: WalletView, from_addr: string, to: string, assetAddress: string, value: string, gas: string, gasPrice: string, password: string, uuid: string) {.slot.} =
|
proc sendTransaction*(self: WalletView, from_addr: string, to: string, assetAddress: string, value: string, gas: string, gasPrice: string, password: string, uuid: string) {.slot.} =
|
||||||
let wallet = self.status.wallet
|
self.sendTransaction("transactionSent", from_addr, to, assetAddress, value, gas, gasPrice, password, uuid)
|
||||||
if assetAddress != ZERO_ADDRESS and not assetAddress.isEmptyOrWhitespace:
|
|
||||||
spawnAndSend(self, "transactionSent") do:
|
|
||||||
var success: bool
|
|
||||||
let response = wallet.sendTokenTransaction(from_addr, to, assetAddress, value, gas, gasPrice, password, success)
|
|
||||||
$(%* { "result": %response, "success": %success, "uuid": %uuid })
|
|
||||||
else:
|
|
||||||
spawnAndSend(self, "transactionSent") do:
|
|
||||||
var success: bool
|
|
||||||
let response = wallet.sendTransaction(from_addr, to, value, gas, gasPrice, password, success)
|
|
||||||
$(%* { "result": %response, "success": %success, "uuid": %uuid })
|
|
||||||
|
|
||||||
proc getDefaultAccount*(self: WalletView): string {.slot.} =
|
proc getDefaultAccount*(self: WalletView): string {.slot.} =
|
||||||
self.currentAccount.address
|
self.currentAccount.address
|
||||||
|
@ -364,15 +508,7 @@ QtObject:
|
||||||
for acc in self.status.wallet.accounts:
|
for acc in self.status.wallet.accounts:
|
||||||
let accountAddress = acc.address
|
let accountAddress = acc.address
|
||||||
let tokenList = acc.assetList.filter(proc(x:Asset): bool = x.address != "").map(proc(x: Asset): string = x.address)
|
let tokenList = acc.assetList.filter(proc(x:Asset): bool = x.address != "").map(proc(x: Asset): string = x.address)
|
||||||
spawnAndSend(self, "getAccountBalanceSuccess") do:
|
self.initBalances("getAccountBalanceSuccess", accountAddress, tokenList)
|
||||||
var tokenBalances = initTable[string, string]()
|
|
||||||
for token in tokenList:
|
|
||||||
tokenBalances[token] = getTokenBalance(token, accountAddress)
|
|
||||||
$ %* {
|
|
||||||
"address": accountAddress,
|
|
||||||
"eth": getEthBalance(accountAddress),
|
|
||||||
"tokens": tokenBalances
|
|
||||||
}
|
|
||||||
|
|
||||||
proc getAccountBalanceSuccess*(self: WalletView, jsonResponse: string) {.slot.} =
|
proc getAccountBalanceSuccess*(self: WalletView, jsonResponse: string) {.slot.} =
|
||||||
let jsonObj = jsonResponse.parseJson()
|
let jsonObj = jsonResponse.parseJson()
|
||||||
|
@ -396,31 +532,11 @@ QtObject:
|
||||||
))
|
))
|
||||||
|
|
||||||
# TODO find a way to use a loop to streamline this code
|
# TODO find a way to use a loop to streamline this code
|
||||||
# Spawn for each collectible. They can end in whichever order
|
# Create a thread in the threadpool for each collectible. They can end in whichever order
|
||||||
spawnAndSend(self, "setCollectiblesResult") do:
|
self.loadCollectibles("setCollectiblesResult", address, status_collectibles.CRYPTOKITTY)
|
||||||
$(%*{
|
self.loadCollectibles("setCollectiblesResult", address, status_collectibles.KUDO)
|
||||||
"address": address,
|
self.loadCollectibles("setCollectiblesResult", address, status_collectibles.ETHERMON)
|
||||||
"collectibleType": status_collectibles.CRYPTOKITTY,
|
self.loadCollectibles("setCollectiblesResult", address, status_collectibles.STICKER)
|
||||||
"collectiblesOrError": status_collectibles.getCryptoKitties(address)
|
|
||||||
})
|
|
||||||
spawnAndSend(self, "setCollectiblesResult") do:
|
|
||||||
$(%*{
|
|
||||||
"address": address,
|
|
||||||
"collectibleType": status_collectibles.KUDO,
|
|
||||||
"collectiblesOrError": status_collectibles.getKudos(address)
|
|
||||||
})
|
|
||||||
spawnAndSend(self, "setCollectiblesResult") do:
|
|
||||||
$(%*{
|
|
||||||
"address": address,
|
|
||||||
"collectibleType": status_collectibles.ETHERMON,
|
|
||||||
"collectiblesOrError": status_collectibles.getEthermons(address)
|
|
||||||
})
|
|
||||||
spawnAndSend(self, "setCollectiblesResult") do:
|
|
||||||
$(%*{
|
|
||||||
"address": address,
|
|
||||||
"collectibleType": status_collectibles.STICKER,
|
|
||||||
"collectiblesOrError": status_collectibles.getStickers(address)
|
|
||||||
})
|
|
||||||
|
|
||||||
proc setCollectiblesResult(self: WalletView, collectiblesJSON: string) {.slot.} =
|
proc setCollectiblesResult(self: WalletView, collectiblesJSON: string) {.slot.} =
|
||||||
let collectibleData = parseJson(collectiblesJSON)
|
let collectibleData = parseJson(collectiblesJSON)
|
||||||
|
@ -452,47 +568,13 @@ QtObject:
|
||||||
|
|
||||||
proc reloadCollectible*(self: WalletView, collectibleType: string) {.slot.} =
|
proc reloadCollectible*(self: WalletView, collectibleType: string) {.slot.} =
|
||||||
let address = self.currentAccount.address
|
let address = self.currentAccount.address
|
||||||
# TODO find a cooler way to do this
|
self.loadCollectibles("setCollectiblesResult", address, collectibleType)
|
||||||
case collectibleType:
|
|
||||||
of CRYPTOKITTY:
|
|
||||||
spawnAndSend(self, "setCollectiblesResult") do:
|
|
||||||
$(%*{
|
|
||||||
"address": address,
|
|
||||||
"collectibleType": status_collectibles.CRYPTOKITTY,
|
|
||||||
"collectiblesOrError": status_collectibles.getCryptoKitties(address)
|
|
||||||
})
|
|
||||||
of KUDO:
|
|
||||||
spawnAndSend(self, "setCollectiblesResult") do:
|
|
||||||
$(%*{
|
|
||||||
"address": address,
|
|
||||||
"collectibleType": status_collectibles.KUDO,
|
|
||||||
"collectiblesOrError": status_collectibles.getKudos(address)
|
|
||||||
})
|
|
||||||
of ETHERMON:
|
|
||||||
spawnAndSend(self, "setCollectiblesResult") do:
|
|
||||||
$(%*{
|
|
||||||
"address": address,
|
|
||||||
"collectibleType": status_collectibles.ETHERMON,
|
|
||||||
"collectiblesOrError": status_collectibles.getEthermons(address)
|
|
||||||
})
|
|
||||||
of status_collectibles.STICKER:
|
|
||||||
spawnAndSend(self, "setCollectiblesResult") do:
|
|
||||||
$(%*{
|
|
||||||
"address": address,
|
|
||||||
"collectibleType": status_collectibles.STICKER,
|
|
||||||
"collectiblesOrError": status_collectibles.getStickers(address)
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
error "Unrecognized collectible"
|
|
||||||
return
|
|
||||||
|
|
||||||
self.currentCollectiblesLists.setLoadingByType(collectibleType, 1)
|
self.currentCollectiblesLists.setLoadingByType(collectibleType, 1)
|
||||||
|
|
||||||
proc gasPricePredictionsChanged*(self: WalletView) {.signal.}
|
proc gasPricePredictionsChanged*(self: WalletView) {.signal.}
|
||||||
|
|
||||||
proc getGasPricePredictions*(self: WalletView) {.slot.} =
|
proc getGasPricePredictions*(self: WalletView) {.slot.} =
|
||||||
spawnAndSend(self, "getGasPricePredictionsResult") do:
|
self.getGasPredictions("getGasPricePredictionsResult")
|
||||||
$ %getGasPricePredictions2()
|
|
||||||
|
|
||||||
proc getGasPricePredictionsResult(self: WalletView, gasPricePredictionsJson: string) {.slot.} =
|
proc getGasPricePredictionsResult(self: WalletView, gasPricePredictionsJson: string) {.slot.} =
|
||||||
let prediction = Json.decode(gasPricePredictionsJson, GasPricePrediction)
|
let prediction = Json.decode(gasPricePredictionsJson, GasPricePrediction)
|
||||||
|
@ -586,11 +668,7 @@ QtObject:
|
||||||
# spawn'ed function cannot have a 'var' parameter
|
# spawn'ed function cannot have a 'var' parameter
|
||||||
let blockNumber = bn
|
let blockNumber = bn
|
||||||
self.loadingTrxHistoryChanged(true)
|
self.loadingTrxHistoryChanged(true)
|
||||||
spawnAndSend(self, "setTrxHistoryResult") do:
|
self.loadTransactions("setTrxHistoryResult", address, bn)
|
||||||
$(%*{
|
|
||||||
"address": address,
|
|
||||||
"history": getTransfersByAddress(address, blockNumber)
|
|
||||||
})
|
|
||||||
|
|
||||||
proc setTrxHistoryResult(self: WalletView, historyJSON: string) {.slot.} =
|
proc setTrxHistoryResult(self: WalletView, historyJSON: string) {.slot.} =
|
||||||
let historyData = parseJson(historyJSON)
|
let historyData = parseJson(historyJSON)
|
||||||
|
@ -605,8 +683,7 @@ QtObject:
|
||||||
self.loadingTrxHistoryChanged(false)
|
self.loadingTrxHistoryChanged(false)
|
||||||
|
|
||||||
proc resolveENS*(self: WalletView, ens: string, uuid: string) {.slot.} =
|
proc resolveENS*(self: WalletView, ens: string, uuid: string) {.slot.} =
|
||||||
spawnAndSend(self, "ensResolved") do:
|
self.resolveEns("ensResolved", ens, uuid)
|
||||||
$ %* { "address": status_ens.address(ens), "uuid": uuid }
|
|
||||||
|
|
||||||
proc ensWasResolved*(self: WalletView, resolvedAddress: string, uuid: string) {.signal.}
|
proc ensWasResolved*(self: WalletView, resolvedAddress: string, uuid: string) {.signal.}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
import NimQml, tables, json
|
import # nim libs
|
||||||
import ../../../status/libstatus/[tokens, settings, utils, eth/contracts]
|
tables, json
|
||||||
|
|
||||||
|
import # vendor libs
|
||||||
|
NimQml
|
||||||
|
|
||||||
|
import # status-desktop libs
|
||||||
|
../../../status/libstatus/[tokens, settings, utils, eth/contracts],
|
||||||
|
../../../status/tasks/[qt, task_runner_impl], ../../../status/status
|
||||||
from web3/conversions import `$`
|
from web3/conversions import `$`
|
||||||
import ../../../status/threads
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TokenRoles {.pure.} = enum
|
TokenRoles {.pure.} = enum
|
||||||
|
@ -11,9 +17,34 @@ type
|
||||||
Address = UserRole + 4,
|
Address = UserRole + 4,
|
||||||
Decimals = UserRole + 5
|
Decimals = UserRole + 5
|
||||||
IsCustom = UserRole + 6
|
IsCustom = UserRole + 6
|
||||||
|
GetTokenDetailsTaskArg = ref object of QObjectTaskArg
|
||||||
|
address: string
|
||||||
|
|
||||||
|
const getTokenDetailsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||||
|
let
|
||||||
|
arg = decode[GetTokenDetailsTaskArg](argEncoded)
|
||||||
|
tkn = newErc20Contract(getCurrentNetwork(), arg.address.parseAddress)
|
||||||
|
decimals = tkn.tokenDecimals()
|
||||||
|
|
||||||
|
let output = %* {
|
||||||
|
"address": arg.address,
|
||||||
|
"name": tkn.tokenName(),
|
||||||
|
"symbol": tkn.tokenSymbol(),
|
||||||
|
"decimals": (if decimals == 0: "" else: $decimals)
|
||||||
|
}
|
||||||
|
arg.finish(output)
|
||||||
|
|
||||||
|
proc getTokenDetails[T](self: T, slot: string, address: string) =
|
||||||
|
let arg = GetTokenDetailsTaskArg(
|
||||||
|
tptr: cast[ByteAddress](getTokenDetailsTask),
|
||||||
|
vptr: cast[ByteAddress](self.vptr),
|
||||||
|
slot: slot,
|
||||||
|
address: address)
|
||||||
|
self.status.tasks.threadpool.start(arg)
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
type TokenList* = ref object of QAbstractListModel
|
type TokenList* = ref object of QAbstractListModel
|
||||||
|
status*: Status
|
||||||
tokens*: seq[Erc20Contract]
|
tokens*: seq[Erc20Contract]
|
||||||
isCustom*: bool
|
isCustom*: bool
|
||||||
|
|
||||||
|
@ -39,9 +70,10 @@ QtObject:
|
||||||
self.isCustom = true
|
self.isCustom = true
|
||||||
self.endResetModel()
|
self.endResetModel()
|
||||||
|
|
||||||
proc newTokenList*(): TokenList =
|
proc newTokenList*(status: Status): TokenList =
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
result.tokens = @[]
|
result.tokens = @[]
|
||||||
|
result.status = status
|
||||||
result.setup
|
result.setup
|
||||||
|
|
||||||
proc rowData(self: TokenList, index: int, column: string): string {.slot.} =
|
proc rowData(self: TokenList, index: int, column: string): string {.slot.} =
|
||||||
|
@ -82,17 +114,7 @@ QtObject:
|
||||||
TokenRoles.IsCustom.int:"isCustom"}.toTable
|
TokenRoles.IsCustom.int:"isCustom"}.toTable
|
||||||
|
|
||||||
proc getTokenDetails*(self: TokenList, address: string) {.slot.} =
|
proc getTokenDetails*(self: TokenList, address: string) {.slot.} =
|
||||||
spawnAndSend(self, "tokenDetailsResolved") do:
|
self.getTokenDetails("tokenDetailsResolved", address)
|
||||||
let tkn = newErc20Contract(getCurrentNetwork(), address.parseAddress)
|
|
||||||
|
|
||||||
let decimals = tkn.tokenDecimals()
|
|
||||||
|
|
||||||
$ (%* {
|
|
||||||
"address": address,
|
|
||||||
"name": tkn.tokenName(),
|
|
||||||
"symbol": tkn.tokenSymbol(),
|
|
||||||
"decimals": (if decimals == 0: "" else: $decimals)
|
|
||||||
})
|
|
||||||
|
|
||||||
proc tokenDetailsWereResolved*(self: TokenList, tokenDetails: string) {.signal.}
|
proc tokenDetailsWereResolved*(self: TokenList, tokenDetails: string) {.signal.}
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,11 @@ import app/onboarding/core as onboarding
|
||||||
import app/login/core as login
|
import app/login/core as login
|
||||||
import app/provider/core as provider
|
import app/provider/core as provider
|
||||||
import status/signals/core as signals
|
import status/signals/core as signals
|
||||||
import status/tasks/task_manager
|
|
||||||
import status/libstatus/types
|
import status/libstatus/types
|
||||||
import status/libstatus/accounts/constants
|
import status/libstatus/accounts/constants
|
||||||
import status_go
|
import status_go
|
||||||
import status/status as statuslib
|
import status/status as statuslib
|
||||||
import ./eventemitter
|
import ./eventemitter
|
||||||
import chronos, task_runner
|
|
||||||
|
|
||||||
var signalsQObjPointer: pointer
|
var signalsQObjPointer: pointer
|
||||||
|
|
||||||
|
@ -30,9 +28,7 @@ proc mainProc() =
|
||||||
else:
|
else:
|
||||||
"/../fleets.json"
|
"/../fleets.json"
|
||||||
|
|
||||||
let taskManager = newTaskManager()
|
let status = statuslib.newStatusInstance(readFile(joinPath(getAppDir(), fleets)))
|
||||||
taskManager.init()
|
|
||||||
let status = statuslib.newStatusInstance(taskManager, readFile(joinPath(getAppDir(), fleets)))
|
|
||||||
status.initNode()
|
status.initNode()
|
||||||
|
|
||||||
enableHDPI()
|
enableHDPI()
|
||||||
|
@ -157,7 +153,7 @@ proc mainProc() =
|
||||||
profile.delete()
|
profile.delete()
|
||||||
utilsController.delete()
|
utilsController.delete()
|
||||||
browserController.delete()
|
browserController.delete()
|
||||||
taskManager.teardown()
|
status.tasks.teardown()
|
||||||
|
|
||||||
|
|
||||||
# Initialize only controllers whose init functions
|
# Initialize only controllers whose init functions
|
||||||
|
@ -205,4 +201,3 @@ proc mainProc() =
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
mainProc()
|
mainProc()
|
||||||
GC_fullcollect()
|
|
||||||
|
|
|
@ -4,9 +4,9 @@ import libstatus/settings as libstatus_settings
|
||||||
import libstatus/types as libstatus_types
|
import libstatus/types as libstatus_types
|
||||||
import chat, accounts, wallet, node, network, mailservers, messages, contacts, profile, stickers, permissions, fleet
|
import chat, accounts, wallet, node, network, mailservers, messages, contacts, profile, stickers, permissions, fleet
|
||||||
import ../eventemitter
|
import ../eventemitter
|
||||||
import tasks/task_manager
|
import ./tasks/task_runner_impl
|
||||||
|
|
||||||
export chat, accounts, node, mailservers, messages, contacts, profile, network, permissions, fleet
|
export chat, accounts, node, mailservers, messages, contacts, profile, network, permissions, fleet, task_runner_impl
|
||||||
|
|
||||||
type Status* = ref object
|
type Status* = ref object
|
||||||
events*: EventEmitter
|
events*: EventEmitter
|
||||||
|
@ -22,11 +22,11 @@ type Status* = ref object
|
||||||
network*: NetworkModel
|
network*: NetworkModel
|
||||||
stickers*: StickersModel
|
stickers*: StickersModel
|
||||||
permissions*: PermissionsModel
|
permissions*: PermissionsModel
|
||||||
taskManager*: TaskManager
|
tasks*: TaskRunner
|
||||||
|
|
||||||
proc newStatusInstance*(taskManager: TaskManager, fleetConfig: string): Status =
|
proc newStatusInstance*(fleetConfig: string): Status =
|
||||||
result = Status()
|
result = Status()
|
||||||
result.taskManager = taskManager
|
result.tasks = newTaskRunner()
|
||||||
result.events = createEventEmitter()
|
result.events = createEventEmitter()
|
||||||
result.fleet = fleet.newFleetModel(result.events, fleetConfig)
|
result.fleet = fleet.newFleetModel(result.events, fleetConfig)
|
||||||
result.chat = chat.newChatModel(result.events)
|
result.chat = chat.newChatModel(result.events)
|
||||||
|
@ -43,6 +43,7 @@ proc newStatusInstance*(taskManager: TaskManager, fleetConfig: string): Status =
|
||||||
result.permissions = permissions.newPermissionsModel(result.events)
|
result.permissions = permissions.newPermissionsModel(result.events)
|
||||||
|
|
||||||
proc initNode*(self: Status) =
|
proc initNode*(self: Status) =
|
||||||
|
self.tasks.init()
|
||||||
libstatus_accounts.initNode()
|
libstatus_accounts.initNode()
|
||||||
|
|
||||||
proc startMessenger*(self: Status) =
|
proc startMessenger*(self: Status) =
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
import
|
import # vendor libs
|
||||||
json_serialization, NimQml, task_runner
|
json_serialization, NimQml, task_runner
|
||||||
|
|
||||||
type
|
type
|
||||||
BaseTasks* = ref object of RootObj
|
Task* = proc(arg: string): void {.gcsafe, nimcall.}
|
||||||
chanSendToPool*: AsyncChannel[ThreadSafeString]
|
TaskArg* = ref object of RootObj
|
||||||
BaseTask* = ref object of RootObj
|
tptr*: ByteAddress
|
||||||
vptr*: ByteAddress
|
|
||||||
slot*: string
|
|
||||||
|
|
||||||
proc start*[T: BaseTask](self: BaseTasks, task: T) =
|
proc decode*[T](arg: string): T =
|
||||||
let payload = task.toJson(typeAnnotations = true)
|
Json.decode(arg, T, allowUnknownFields = true)
|
||||||
self.chanSendToPool.sendSync(payload.safe)
|
|
||||||
|
|
||||||
proc finish*[T](task: BaseTask, payload: T) =
|
proc encode*[T](arg: T): string =
|
||||||
let resultPayload = Json.encode(payload)
|
arg.toJson(typeAnnotations = true)
|
||||||
signal_handler(cast[pointer](task.vptr), resultPayload, task.slot)
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import # vendor libs
|
||||||
|
NimQml, json_serialization
|
||||||
|
|
||||||
|
import # status-desktop libs
|
||||||
|
./common
|
||||||
|
|
||||||
|
type
|
||||||
|
QObjectTaskArg* = ref object of TaskArg
|
||||||
|
vptr*: ByteAddress
|
||||||
|
slot*: string
|
||||||
|
|
||||||
|
proc finish*[T](arg: QObjectTaskArg, payload: T) =
|
||||||
|
signal_handler(cast[pointer](arg.vptr), Json.encode(payload), arg.slot)
|
||||||
|
|
||||||
|
proc finish*(arg: QObjectTaskArg, payload: string) =
|
||||||
|
signal_handler(cast[pointer](arg.vptr), payload, arg.slot)
|
|
@ -1,50 +0,0 @@
|
||||||
import # nim libs
|
|
||||||
tables
|
|
||||||
|
|
||||||
import # vendor libs
|
|
||||||
chronos, NimQml, json, json_serialization, task_runner
|
|
||||||
|
|
||||||
import # status-desktop libs
|
|
||||||
./common, ../libstatus/types, ../stickers
|
|
||||||
|
|
||||||
type
|
|
||||||
StickerPackPurchaseGasEstimate* = ref object of BaseTask
|
|
||||||
packId*: int
|
|
||||||
address*: string
|
|
||||||
price*: string
|
|
||||||
uuid*: string
|
|
||||||
ObtainAvailableStickerPacks* = ref object of BaseTask
|
|
||||||
StickersTasks* = ref object of BaseTasks
|
|
||||||
|
|
||||||
proc newStickersTasks*(chanSendToPool: AsyncChannel[ThreadSafeString]): StickersTasks =
|
|
||||||
new(result)
|
|
||||||
result.chanSendToPool = chanSendToPool
|
|
||||||
|
|
||||||
proc run*(task: StickerPackPurchaseGasEstimate) =
|
|
||||||
var success: bool
|
|
||||||
var estimate = estimateGas(
|
|
||||||
task.packId,
|
|
||||||
task.address,
|
|
||||||
task.price,
|
|
||||||
success
|
|
||||||
)
|
|
||||||
if not success:
|
|
||||||
estimate = 325000
|
|
||||||
let result: tuple[estimate: int, uuid: string] = (estimate, task.uuid)
|
|
||||||
task.finish(result)
|
|
||||||
|
|
||||||
proc run*(task: ObtainAvailableStickerPacks) =
|
|
||||||
var success: bool
|
|
||||||
let availableStickerPacks = getAvailableStickerPacks()
|
|
||||||
var packs: seq[StickerPack] = @[]
|
|
||||||
for packId, stickerPack in availableStickerPacks.pairs:
|
|
||||||
packs.add(stickerPack)
|
|
||||||
task.finish(%*(packs))
|
|
||||||
|
|
||||||
proc stickerPackPurchaseGasEstimate*(self: StickersTasks, vptr: pointer, slot: string, packId: int, address: string, price: string, uuid: string) =
|
|
||||||
let task = StickerPackPurchaseGasEstimate(vptr: cast[ByteAddress](vptr), slot: slot, packId: packId, address: address, price: price, uuid: uuid)
|
|
||||||
self.start(task)
|
|
||||||
|
|
||||||
proc obtainAvailableStickerPacks*(self: StickersTasks, vptr: pointer, slot: string) =
|
|
||||||
let task = ObtainAvailableStickerPacks(vptr: cast[ByteAddress](vptr), slot: slot)
|
|
||||||
self.start(task)
|
|
|
@ -1,27 +0,0 @@
|
||||||
import # vendor libs
|
|
||||||
chronicles, task_runner
|
|
||||||
|
|
||||||
import # status-desktop libs
|
|
||||||
./threadpool
|
|
||||||
|
|
||||||
export threadpool
|
|
||||||
|
|
||||||
logScope:
|
|
||||||
topics = "task-manager"
|
|
||||||
|
|
||||||
type
|
|
||||||
TaskManager* = ref object
|
|
||||||
threadPool*: ThreadPool
|
|
||||||
|
|
||||||
proc newTaskManager*(): TaskManager =
|
|
||||||
new(result)
|
|
||||||
result.threadPool = newThreadPool()
|
|
||||||
|
|
||||||
proc init*(self: TaskManager) =
|
|
||||||
self.threadPool.init()
|
|
||||||
|
|
||||||
proc teardown*(self: TaskManager) =
|
|
||||||
self.threadPool.teardown()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import # vendor libs
|
||||||
|
chronicles, task_runner
|
||||||
|
|
||||||
|
import # status-desktop libs
|
||||||
|
./threadpool
|
||||||
|
|
||||||
|
export task_runner, threadpool
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
topics = "task-runner"
|
||||||
|
|
||||||
|
type
|
||||||
|
TaskRunner* = ref object
|
||||||
|
threadpool*: ThreadPool
|
||||||
|
|
||||||
|
proc newTaskRunner*(): TaskRunner =
|
||||||
|
new(result)
|
||||||
|
result.threadpool = newThreadPool()
|
||||||
|
|
||||||
|
proc init*(self: TaskRunner) =
|
||||||
|
self.threadpool.init()
|
||||||
|
|
||||||
|
proc teardown*(self: TaskRunner) =
|
||||||
|
self.threadpool.teardown()
|
|
@ -1,26 +1,28 @@
|
||||||
import
|
import # std libs
|
||||||
chronicles, chronos, json, json_serialization, NimQml, sequtils, tables,
|
json, sequtils, tables
|
||||||
task_runner
|
|
||||||
|
import # vendor libs
|
||||||
|
chronicles, chronos, json_serialization, NimQml, task_runner
|
||||||
|
|
||||||
|
import # status-desktop libs
|
||||||
|
./common
|
||||||
|
|
||||||
import
|
|
||||||
./common, ./stickers
|
|
||||||
export
|
export
|
||||||
stickers
|
chronos, common, json_serialization
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "task-threadpool"
|
topics = "task-threadpool"
|
||||||
|
|
||||||
type
|
type
|
||||||
ThreadPool* = ref object
|
ThreadPool* = ref object
|
||||||
chanRecvFromPool*: AsyncChannel[ThreadSafeString]
|
chanRecvFromPool: AsyncChannel[ThreadSafeString]
|
||||||
chanSendToPool*: AsyncChannel[ThreadSafeString]
|
chanSendToPool: AsyncChannel[ThreadSafeString]
|
||||||
thread: Thread[PoolThreadArg]
|
thread: Thread[PoolThreadArg]
|
||||||
size: int
|
size: int
|
||||||
stickers*: StickersTasks
|
PoolThreadArg = object
|
||||||
PoolThreadArg* = object
|
chanSendToMain: AsyncChannel[ThreadSafeString]
|
||||||
chanSendToMain*: AsyncChannel[ThreadSafeString]
|
chanRecvFromMain: AsyncChannel[ThreadSafeString]
|
||||||
chanRecvFromMain*: AsyncChannel[ThreadSafeString]
|
size: int
|
||||||
size*: int
|
|
||||||
TaskThreadArg = object
|
TaskThreadArg = object
|
||||||
id: int
|
id: int
|
||||||
chanRecvFromPool: AsyncChannel[ThreadSafeString]
|
chanRecvFromPool: AsyncChannel[ThreadSafeString]
|
||||||
|
@ -29,7 +31,6 @@ type
|
||||||
id: int
|
id: int
|
||||||
notice: string
|
notice: string
|
||||||
|
|
||||||
|
|
||||||
# forward declarations
|
# forward declarations
|
||||||
proc poolThread(arg: PoolThreadArg) {.thread.}
|
proc poolThread(arg: PoolThreadArg) {.thread.}
|
||||||
|
|
||||||
|
@ -41,7 +42,6 @@ proc newThreadPool*(size: int = MaxThreadPoolSize): ThreadPool =
|
||||||
result.chanSendToPool = newAsyncChannel[ThreadSafeString](-1)
|
result.chanSendToPool = newAsyncChannel[ThreadSafeString](-1)
|
||||||
result.thread = Thread[PoolThreadArg]()
|
result.thread = Thread[PoolThreadArg]()
|
||||||
result.size = size
|
result.size = size
|
||||||
result.stickers = newStickersTasks(result.chanSendToPool)
|
|
||||||
|
|
||||||
proc init*(self: ThreadPool) =
|
proc init*(self: ThreadPool) =
|
||||||
self.chanRecvFromPool.open()
|
self.chanRecvFromPool.open()
|
||||||
|
@ -52,64 +52,60 @@ proc init*(self: ThreadPool) =
|
||||||
size: self.size
|
size: self.size
|
||||||
)
|
)
|
||||||
createThread(self.thread, poolThread, arg)
|
createThread(self.thread, poolThread, arg)
|
||||||
|
|
||||||
# block until we receive "ready"
|
# block until we receive "ready"
|
||||||
let received = $(self.chanRecvFromPool.recvSync())
|
discard $(self.chanRecvFromPool.recvSync())
|
||||||
|
|
||||||
proc teardown*(self: ThreadPool) =
|
proc teardown*(self: ThreadPool) =
|
||||||
self.chanSendToPool.sendSync("shutdown".safe)
|
self.chanSendToPool.sendSync("shutdown".safe)
|
||||||
self.chanRecvFromPool.close()
|
self.chanRecvFromPool.close()
|
||||||
self.chanSendToPool.close()
|
self.chanSendToPool.close()
|
||||||
|
debug "[threadpool] waiting for the control thread to stop"
|
||||||
joinThread(self.thread)
|
joinThread(self.thread)
|
||||||
|
|
||||||
proc task(arg: TaskThreadArg) {.async.} =
|
proc start*[T: TaskArg](self: Threadpool, arg: T) =
|
||||||
|
self.chanSendToPool.sendSync(arg.encode.safe)
|
||||||
|
|
||||||
|
proc runner(arg: TaskThreadArg) {.async.} =
|
||||||
arg.chanRecvFromPool.open()
|
arg.chanRecvFromPool.open()
|
||||||
arg.chanSendToPool.open()
|
arg.chanSendToPool.open()
|
||||||
|
|
||||||
let noticeToPool = ThreadNotification(id: arg.id, notice: "ready")
|
let noticeToPool = ThreadNotification(id: arg.id, notice: "ready")
|
||||||
info "[threadpool task thread] sending 'ready'", threadid=arg.id
|
debug "[threadpool task thread] sending 'ready'", threadid=arg.id
|
||||||
await arg.chanSendToPool.send(noticeToPool.toJson(typeAnnotations = true).safe)
|
await arg.chanSendToPool.send(noticeToPool.encode.safe)
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
info "[threadpool task thread] waiting for message"
|
debug "[threadpool task thread] waiting for message"
|
||||||
let received = $(await arg.chanRecvFromPool.recv())
|
let received = $(await arg.chanRecvFromPool.recv())
|
||||||
|
|
||||||
if received == "shutdown":
|
if received == "shutdown":
|
||||||
info "[threadpool task thread] received 'shutdown'"
|
debug "[threadpool task thread] received 'shutdown'"
|
||||||
info "[threadpool task thread] breaking while loop"
|
|
||||||
break
|
break
|
||||||
|
|
||||||
let
|
let
|
||||||
jsonNode = parseJson(received)
|
parsed = parseJson(received)
|
||||||
messageType = jsonNode{"$type"}.getStr
|
messageType = parsed{"$type"}.getStr
|
||||||
|
debug "[threadpool task thread] initiating task", messageType=messageType,
|
||||||
info "[threadpool task thread] received task", messageType=messageType
|
|
||||||
info "[threadpool task thread] initiating task", messageType=messageType,
|
|
||||||
threadid=arg.id
|
threadid=arg.id
|
||||||
|
|
||||||
try:
|
try:
|
||||||
case messageType
|
let task = cast[Task](parsed{"tptr"}.getInt)
|
||||||
of "StickerPackPurchaseGasEstimate:ObjectType":
|
try:
|
||||||
let decoded = Json.decode(received, StickerPackPurchaseGasEstimate, allowUnknownFields = true)
|
task(received)
|
||||||
decoded.run()
|
|
||||||
of "ObtainAvailableStickerPacks:ObjectType":
|
|
||||||
let decoded = Json.decode(received, ObtainAvailableStickerPacks, allowUnknownFields = true)
|
|
||||||
decoded.run()
|
|
||||||
else:
|
|
||||||
error "[threadpool task thread] unknown message", message=received
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error "[threadpool task thread] exception", error=e.msg
|
error "[threadpool task thread] exception", error=e.msg
|
||||||
|
except Exception as e:
|
||||||
|
error "[threadpool task thread] unknown message", message=received
|
||||||
|
|
||||||
let noticeToPool = ThreadNotification(id: arg.id, notice: "done")
|
let noticeToPool = ThreadNotification(id: arg.id, notice: "done")
|
||||||
info "[threadpool task thread] sending 'done' notice to pool",
|
debug "[threadpool task thread] sending 'done' notice to pool",
|
||||||
threadid=arg.id
|
threadid=arg.id
|
||||||
await arg.chanSendToPool.send(noticeToPool.toJson(typeAnnotations = true).safe)
|
await arg.chanSendToPool.send(noticeToPool.encode.safe)
|
||||||
|
|
||||||
arg.chanRecvFromPool.close()
|
arg.chanRecvFromPool.close()
|
||||||
arg.chanSendToPool.close()
|
arg.chanSendToPool.close()
|
||||||
|
|
||||||
proc taskThread(arg: TaskThreadArg) {.thread.} =
|
proc taskThread(arg: TaskThreadArg) {.thread.} =
|
||||||
waitFor task(arg)
|
waitFor runner(arg)
|
||||||
|
|
||||||
proc pool(arg: PoolThreadArg) {.async.} =
|
proc pool(arg: PoolThreadArg) {.async.} =
|
||||||
let
|
let
|
||||||
|
@ -124,14 +120,14 @@ proc pool(arg: PoolThreadArg) {.async.} =
|
||||||
chanSendToMain.open()
|
chanSendToMain.open()
|
||||||
chanRecvFromMainOrTask.open()
|
chanRecvFromMainOrTask.open()
|
||||||
|
|
||||||
info "[threadpool] sending 'ready' to main thread"
|
debug "[threadpool] sending 'ready' to main thread"
|
||||||
await chanSendToMain.send("ready".safe)
|
await chanSendToMain.send("ready".safe)
|
||||||
|
|
||||||
for i in 0..<arg.size:
|
for i in 0..<arg.size:
|
||||||
let id = i + 1
|
let id = i + 1
|
||||||
let chanSendToTask = newAsyncChannel[ThreadSafeString](-1)
|
let chanSendToTask = newAsyncChannel[ThreadSafeString](-1)
|
||||||
chanSendToTask.open()
|
chanSendToTask.open()
|
||||||
info "[threadpool] adding to threadsIdle", threadid=id
|
debug "[threadpool] adding to threadsIdle", threadid=id
|
||||||
threadsIdle[i].id = id
|
threadsIdle[i].id = id
|
||||||
createThread(
|
createThread(
|
||||||
threadsIdle[i].thr,
|
threadsIdle[i].thr,
|
||||||
|
@ -153,55 +149,53 @@ proc pool(arg: PoolThreadArg) {.async.} =
|
||||||
# push thread into threadsIdle
|
# push thread into threadsIdle
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
info "[threadpool] waiting for message"
|
debug "[threadpool] waiting for message"
|
||||||
var task = $(await chanRecvFromMainOrTask.recv())
|
var task = $(await chanRecvFromMainOrTask.recv())
|
||||||
info "[threadpool] received message", msg=task
|
|
||||||
|
|
||||||
if task == "shutdown":
|
if task == "shutdown":
|
||||||
info "[threadpool] sending 'shutdown' to all task threads"
|
debug "[threadpool] sending 'shutdown' to all task threads"
|
||||||
for tpl in threadsIdle:
|
for tpl in threadsIdle:
|
||||||
await tpl.chanSendToTask.send("shutdown".safe)
|
await tpl.chanSendToTask.send("shutdown".safe)
|
||||||
for tpl in threadsBusy.values:
|
for tpl in threadsBusy.values:
|
||||||
await tpl.chanSendToTask.send("shutdown".safe)
|
await tpl.chanSendToTask.send("shutdown".safe)
|
||||||
info "[threadpool] breaking while loop"
|
|
||||||
break
|
break
|
||||||
|
|
||||||
let
|
let
|
||||||
jsonNode = parseJson(task)
|
jsonNode = parseJson(task)
|
||||||
messageType = jsonNode{"$type"}.getStr
|
messageType = jsonNode{"$type"}.getStr
|
||||||
info "[threadpool] determined message type", messageType=messageType
|
debug "[threadpool] determined message type", messageType=messageType
|
||||||
|
|
||||||
case messageType
|
case messageType
|
||||||
of "ThreadNotification":
|
of "ThreadNotification":
|
||||||
try:
|
try:
|
||||||
let notification = Json.decode(task, ThreadNotification, allowUnknownFields = true)
|
let notification = decode[ThreadNotification](task)
|
||||||
info "[threadpool] received notification",
|
debug "[threadpool] received notification",
|
||||||
notice=notification.notice, threadid=notification.id
|
notice=notification.notice, threadid=notification.id
|
||||||
|
|
||||||
if notification.notice == "ready":
|
if notification.notice == "ready":
|
||||||
info "[threadpool] received 'ready' from a task thread"
|
debug "[threadpool] received 'ready' from a task thread"
|
||||||
allReady = allReady + 1
|
allReady = allReady + 1
|
||||||
|
|
||||||
elif notification.notice == "done":
|
elif notification.notice == "done":
|
||||||
let tpl = threadsBusy[notification.id]
|
let tpl = threadsBusy[notification.id]
|
||||||
info "[threadpool] adding to threadsIdle",
|
debug "[threadpool] adding to threadsIdle",
|
||||||
newlength=(threadsIdle.len + 1)
|
newlength=(threadsIdle.len + 1)
|
||||||
threadsIdle.add (notification.id, tpl.thr, tpl.chanSendToTask)
|
threadsIdle.add (notification.id, tpl.thr, tpl.chanSendToTask)
|
||||||
info "[threadpool] removing from threadsBusy",
|
debug "[threadpool] removing from threadsBusy",
|
||||||
newlength=(threadsBusy.len - 1), threadid=notification.id
|
newlength=(threadsBusy.len - 1), threadid=notification.id
|
||||||
threadsBusy.del notification.id
|
threadsBusy.del notification.id
|
||||||
|
|
||||||
if taskQueue.len > 0:
|
if taskQueue.len > 0:
|
||||||
info "[threadpool] removing from taskQueue",
|
debug "[threadpool] removing from taskQueue",
|
||||||
newlength=(taskQueue.len - 1)
|
newlength=(taskQueue.len - 1)
|
||||||
task = taskQueue[0]
|
task = taskQueue[0]
|
||||||
taskQueue.delete 0, 0
|
taskQueue.delete 0, 0
|
||||||
|
|
||||||
info "[threadpool] removing from threadsIdle",
|
debug "[threadpool] removing from threadsIdle",
|
||||||
newlength=(threadsIdle.len - 1)
|
newlength=(threadsIdle.len - 1)
|
||||||
let tpl = threadsIdle[0]
|
let tpl = threadsIdle[0]
|
||||||
threadsIdle.delete 0, 0
|
threadsIdle.delete 0, 0
|
||||||
info "[threadpool] adding to threadsBusy",
|
debug "[threadpool] adding to threadsBusy",
|
||||||
newlength=(threadsBusy.len + 1), threadid=tpl.id
|
newlength=(threadsBusy.len + 1), threadid=tpl.id
|
||||||
threadsBusy.add tpl.id, (tpl.thr, tpl.chanSendToTask)
|
threadsBusy.add tpl.id, (tpl.thr, tpl.chanSendToTask)
|
||||||
await tpl.chanSendToTask.send(task.safe)
|
await tpl.chanSendToTask.send(task.safe)
|
||||||
|
@ -214,7 +208,7 @@ proc pool(arg: PoolThreadArg) {.async.} =
|
||||||
else: # must be a request to do task work
|
else: # must be a request to do task work
|
||||||
if allReady < arg.size or threadsBusy.len == arg.size:
|
if allReady < arg.size or threadsBusy.len == arg.size:
|
||||||
# add to queue
|
# add to queue
|
||||||
info "[threadpool] adding to taskQueue",
|
debug "[threadpool] adding to taskQueue",
|
||||||
newlength=(taskQueue.len + 1)
|
newlength=(taskQueue.len + 1)
|
||||||
taskQueue.add task
|
taskQueue.add task
|
||||||
|
|
||||||
|
@ -223,24 +217,23 @@ proc pool(arg: PoolThreadArg) {.async.} =
|
||||||
# check if we have tasks waiting on queue
|
# check if we have tasks waiting on queue
|
||||||
if taskQueue.len > 0:
|
if taskQueue.len > 0:
|
||||||
# remove first element from the task queue
|
# remove first element from the task queue
|
||||||
info "[threadpool] adding to taskQueue",
|
debug "[threadpool] adding to taskQueue",
|
||||||
newlength=(taskQueue.len + 1)
|
newlength=(taskQueue.len + 1)
|
||||||
taskQueue.add task
|
taskQueue.add task
|
||||||
info "[threadpool] removing from taskQueue",
|
debug "[threadpool] removing from taskQueue",
|
||||||
newlength=(taskQueue.len - 1)
|
newlength=(taskQueue.len - 1)
|
||||||
task = taskQueue[0]
|
task = taskQueue[0]
|
||||||
taskQueue.delete 0, 0
|
taskQueue.delete 0, 0
|
||||||
|
|
||||||
info "[threadpool] removing from threadsIdle",
|
debug "[threadpool] removing from threadsIdle",
|
||||||
newlength=(threadsIdle.len - 1)
|
newlength=(threadsIdle.len - 1)
|
||||||
let tpl = threadsIdle[0]
|
let tpl = threadsIdle[0]
|
||||||
threadsIdle.delete 0, 0
|
threadsIdle.delete 0, 0
|
||||||
info "[threadpool] adding to threadsBusy",
|
debug "[threadpool] adding to threadsBusy",
|
||||||
newlength=(threadsBusy.len + 1), threadid=tpl.id
|
newlength=(threadsBusy.len + 1), threadid=tpl.id
|
||||||
threadsBusy.add tpl.id, (tpl.thr, tpl.chanSendToTask)
|
threadsBusy.add tpl.id, (tpl.thr, tpl.chanSendToTask)
|
||||||
await tpl.chanSendToTask.send(task.safe)
|
await tpl.chanSendToTask.send(task.safe)
|
||||||
|
|
||||||
|
|
||||||
var allTaskThreads: seq[Thread[TaskThreadArg]] = @[]
|
var allTaskThreads: seq[Thread[TaskThreadArg]] = @[]
|
||||||
|
|
||||||
for tpl in threadsIdle:
|
for tpl in threadsIdle:
|
||||||
|
@ -253,6 +246,7 @@ proc pool(arg: PoolThreadArg) {.async.} =
|
||||||
chanSendToMain.close()
|
chanSendToMain.close()
|
||||||
chanRecvFromMainOrTask.close()
|
chanRecvFromMainOrTask.close()
|
||||||
|
|
||||||
|
debug "[threadpool] waiting for all task threads to stop"
|
||||||
joinThreads(allTaskThreads)
|
joinThreads(allTaskThreads)
|
||||||
|
|
||||||
proc poolThread(arg: PoolThreadArg) {.thread.} =
|
proc poolThread(arg: PoolThreadArg) {.thread.} =
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
import nimqml
|
|
||||||
import threadpool
|
|
||||||
import stew/faux_closures
|
|
||||||
|
|
||||||
export fauxClosure
|
|
||||||
|
|
||||||
template spawnAndSend*(view: untyped, signalName: string, exprBlock: untyped) =
|
|
||||||
let viewPtr = cast[pointer](view.vptr)
|
|
||||||
proc backgroundTask() {.fauxClosure.} =
|
|
||||||
let data = exprBlock
|
|
||||||
signal_handler(viewPtr, data, signalName)
|
|
||||||
spawn backgroundTask()
|
|
|
@ -63,7 +63,7 @@ proc initEvents*(self: WalletModel) =
|
||||||
proc delete*(self: WalletModel) =
|
proc delete*(self: WalletModel) =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc buildTokenTransaction(self: WalletModel, source, to, assetAddress: Address, value: float, transfer: var Transfer, contract: var Erc20Contract, gas = "", gasPrice = ""): EthSend =
|
proc buildTokenTransaction(source, to, assetAddress: Address, value: float, transfer: var Transfer, contract: var Erc20Contract, gas = "", gasPrice = ""): EthSend =
|
||||||
contract = getErc20Contract(assetAddress)
|
contract = getErc20Contract(assetAddress)
|
||||||
if contract == nil:
|
if contract == nil:
|
||||||
raise newException(ValueError, fmt"Could not find ERC-20 contract with address '{assetAddress}' for the current network")
|
raise newException(ValueError, fmt"Could not find ERC-20 contract with address '{assetAddress}' for the current network")
|
||||||
|
@ -114,7 +114,7 @@ proc estimateTokenGas*(self: WalletModel, source, to, assetAddress, value: strin
|
||||||
var
|
var
|
||||||
transfer: Transfer
|
transfer: Transfer
|
||||||
contract: Erc20Contract
|
contract: Erc20Contract
|
||||||
tx = self.buildTokenTransaction(
|
tx = buildTokenTransaction(
|
||||||
parseAddress(source),
|
parseAddress(source),
|
||||||
parseAddress(to),
|
parseAddress(to),
|
||||||
parseAddress(assetAddress),
|
parseAddress(assetAddress),
|
||||||
|
@ -125,7 +125,7 @@ proc estimateTokenGas*(self: WalletModel, source, to, assetAddress, value: strin
|
||||||
|
|
||||||
result = contract.methods["transfer"].estimateGas(tx, transfer, success)
|
result = contract.methods["transfer"].estimateGas(tx, transfer, success)
|
||||||
|
|
||||||
proc sendTransaction*(self: WalletModel, source, to, value, gas, gasPrice, password: string, success: var bool, data = ""): string =
|
proc sendTransaction*(source, to, value, gas, gasPrice, password: string, success: var bool, data = ""): string =
|
||||||
var tx = transactions.buildTransaction(
|
var tx = transactions.buildTransaction(
|
||||||
parseAddress(source),
|
parseAddress(source),
|
||||||
eth2Wei(parseFloat(value), 18), gas, gasPrice, data
|
eth2Wei(parseFloat(value), 18), gas, gasPrice, data
|
||||||
|
@ -138,11 +138,11 @@ proc sendTransaction*(self: WalletModel, source, to, value, gas, gasPrice, passw
|
||||||
if success:
|
if success:
|
||||||
trackPendingTransaction(result, $source, $to, PendingTransactionType.WalletTransfer, "")
|
trackPendingTransaction(result, $source, $to, PendingTransactionType.WalletTransfer, "")
|
||||||
|
|
||||||
proc sendTokenTransaction*(self: WalletModel, source, to, assetAddress, value, gas, gasPrice, password: string, success: var bool): string =
|
proc sendTokenTransaction*(source, to, assetAddress, value, gas, gasPrice, password: string, success: var bool): string =
|
||||||
var
|
var
|
||||||
transfer: Transfer
|
transfer: Transfer
|
||||||
contract: Erc20Contract
|
contract: Erc20Contract
|
||||||
tx = self.buildTokenTransaction(
|
tx = buildTokenTransaction(
|
||||||
parseAddress(source),
|
parseAddress(source),
|
||||||
parseAddress(to),
|
parseAddress(to),
|
||||||
parseAddress(assetAddress),
|
parseAddress(assetAddress),
|
||||||
|
@ -333,22 +333,7 @@ proc getTransfersByAddress*(self: WalletModel, address: string): seq[Transaction
|
||||||
proc validateMnemonic*(self: WalletModel, mnemonic: string): string =
|
proc validateMnemonic*(self: WalletModel, mnemonic: string): string =
|
||||||
result = status_wallet.validateMnemonic(mnemonic).parseJSON()["error"].getStr
|
result = status_wallet.validateMnemonic(mnemonic).parseJSON()["error"].getStr
|
||||||
|
|
||||||
proc getGasPricePredictions*(self: WalletModel): GasPricePrediction =
|
proc getGasPricePredictions*(): GasPricePrediction =
|
||||||
if status_settings.getCurrentNetwork() != Network.Mainnet:
|
|
||||||
# TODO: what about other chains like xdai?
|
|
||||||
return GasPricePrediction(safeLow: 1.0, standard: 2.0, fast: 3.0, fastest: 4.0)
|
|
||||||
try:
|
|
||||||
let url: string = fmt"https://etherchain.org/api/gasPriceOracle"
|
|
||||||
let secureSSLContext = newContext()
|
|
||||||
let client = newHttpClient(sslContext = secureSSLContext)
|
|
||||||
client.headers = newHttpHeaders({ "Content-Type": "application/json" })
|
|
||||||
let response = client.request(url)
|
|
||||||
result = Json.decode(response.body, GasPricePrediction)
|
|
||||||
except Exception as e:
|
|
||||||
echo "error getting gas price predictions"
|
|
||||||
echo e.msg
|
|
||||||
|
|
||||||
proc getGasPricePredictions2*(): GasPricePrediction =
|
|
||||||
if status_settings.getCurrentNetwork() != Network.Mainnet:
|
if status_settings.getCurrentNetwork() != Network.Mainnet:
|
||||||
# TODO: what about other chains like xdai?
|
# TODO: what about other chains like xdai?
|
||||||
return GasPricePrediction(safeLow: 1.0, standard: 2.0, fast: 3.0, fastest: 4.0)
|
return GasPricePrediction(safeLow: 1.0, standard: 2.0, fast: 3.0, fastest: 4.0)
|
||||||
|
|
Loading…
Reference in New Issue