222 lines
7.4 KiB
Nim
222 lines
7.4 KiB
Nim
{.used.}
|
|
|
|
import json, strutils, sequtils, sugar, chronicles, tables
|
|
import json_serialization
|
|
import ../utils
|
|
import ../wallet/account
|
|
import ../statusgo_backend/accounts/constants as constants
|
|
import ../statusgo_backend/accounts as status_accounts
|
|
import ../statusgo_backend/settings as status_settings
|
|
import ../statusgo_backend/tokens as status_tokens
|
|
import ../eth/contracts as status_contracts
|
|
import web3/conversions
|
|
from ../utils import parseAddress, wei2Eth
|
|
import setting, network
|
|
import chronicles
|
|
|
|
include message_command_parameters
|
|
include message_reaction
|
|
include message_text_item
|
|
|
|
type ContentType* {.pure.} = enum
|
|
FetchMoreMessagesButton = -2
|
|
ChatIdentifier = -1,
|
|
Unknown = 0,
|
|
Message = 1,
|
|
Sticker = 2,
|
|
Status = 3,
|
|
Emoji = 4,
|
|
Transaction = 5,
|
|
Group = 6,
|
|
Image = 7,
|
|
Audio = 8
|
|
Community = 9
|
|
Gap = 10
|
|
Edit = 11
|
|
|
|
type Message* = object
|
|
alias*: string
|
|
userName*: string
|
|
localName*: string
|
|
chatId*: string
|
|
clock*: int
|
|
gapFrom*: int
|
|
gapTo*: int
|
|
commandParameters*: CommandParameters
|
|
contentType*: ContentType
|
|
ensName*: string
|
|
fromAuthor*: string
|
|
id*: string
|
|
identicon*: string
|
|
lineCount*: int
|
|
localChatId*: string
|
|
messageType*: string # ???
|
|
parsedText*: seq[TextItem]
|
|
# quotedMessage: # ???
|
|
replace*: string
|
|
responseTo*: string
|
|
rtl*: bool # ???
|
|
seen*: bool # ???
|
|
sticker*: string
|
|
stickerPackId*: int
|
|
text*: string
|
|
timestamp*: string
|
|
editedAt*: string
|
|
whisperTimestamp*: string
|
|
isCurrentUser*: bool
|
|
stickerHash*: string
|
|
outgoingStatus*: string
|
|
linkUrls*: string
|
|
image*: string
|
|
audio*: string
|
|
communityId*: string
|
|
audioDurationMs*: int
|
|
hasMention*: bool
|
|
isPinned*: bool
|
|
pinnedBy*: string
|
|
deleted*: bool
|
|
hide*: bool
|
|
|
|
proc `$`*(self: Message): string =
|
|
result = fmt"Message(id:{self.id}, chatId:{self.chatId}, clock:{self.clock}, from:{self.fromAuthor}, contentType:{self.contentType})"
|
|
|
|
proc currentUserWalletContainsAddress(address: string): bool =
|
|
if (address.len == 0):
|
|
return false
|
|
|
|
let accounts = status_accounts.getWalletAccounts()
|
|
for acc in accounts:
|
|
if (acc.address == address):
|
|
return true
|
|
|
|
return false
|
|
|
|
|
|
var identiconIndex = initTable[string, string]()
|
|
var aliasIndex = initTable[string, string]()
|
|
|
|
|
|
proc toMessage*(jsonMsg: JsonNode, logMessage: bool = false): Message =
|
|
let publicChatKey = status_settings.getSetting[string](Setting.PublicKey, "0x0")
|
|
|
|
var contentType: ContentType
|
|
try:
|
|
contentType = ContentType(jsonMsg{"contentType"}.getInt)
|
|
except:
|
|
warn "Unknown content type received", type = jsonMsg{"contentType"}.getInt
|
|
contentType = ContentType.Message
|
|
|
|
let publicKey = jsonMsg{"from"}.getStr
|
|
|
|
# TODO: THIS IIS A TEMPORARY SOLUTION.
|
|
# IDENTICONS ARE GOING TO BE HANDLED VIA AN HTTP SERVER
|
|
# AND ALIAS ARE GOING TO BE REMOVED
|
|
var identicon = ""
|
|
if identiconIndex.hasKey(publicKey):
|
|
identicon = identiconIndex[publicKey]
|
|
else:
|
|
identicon = generateIdenticon(publicKey)
|
|
|
|
var alias = ""
|
|
if aliasIndex.hasKey(publicKey):
|
|
alias = aliasIndex[publicKey]
|
|
else:
|
|
alias = generateAlias(publicKey)
|
|
|
|
if logMessage:
|
|
debug "message received: ", messageId=jsonMsg{"id"}.getStr
|
|
|
|
var message = Message(
|
|
alias: alias,
|
|
userName: "",
|
|
localName: "",
|
|
chatId: jsonMsg{"localChatId"}.getStr,
|
|
clock: jsonMsg{"clock"}.getInt,
|
|
contentType: contentType,
|
|
ensName: jsonMsg{"ensName"}.getStr,
|
|
fromAuthor: publicKey,
|
|
id: jsonMsg{"id"}.getStr,
|
|
identicon: identicon,
|
|
lineCount: jsonMsg{"lineCount"}.getInt,
|
|
localChatId: jsonMsg{"localChatId"}.getStr,
|
|
messageType: jsonMsg{"messageType"}.getStr,
|
|
replace: jsonMsg{"replace"}.getStr,
|
|
editedAt: $jsonMsg{"editedAt"}.getInt,
|
|
responseTo: jsonMsg{"responseTo"}.getStr,
|
|
rtl: jsonMsg{"rtl"}.getBool,
|
|
seen: jsonMsg{"seen"}.getBool,
|
|
text: jsonMsg{"text"}.getStr,
|
|
timestamp: $jsonMsg{"timestamp"}.getInt,
|
|
whisperTimestamp: $jsonMsg{"whisperTimestamp"}.getInt,
|
|
outgoingStatus: $jsonMsg{"outgoingStatus"}.getStr,
|
|
isCurrentUser: publicChatKey == jsonMsg{"from"}.getStr,
|
|
stickerHash: "",
|
|
stickerPackId: -1,
|
|
parsedText: @[],
|
|
linkUrls: "",
|
|
image: $jsonMsg{"image"}.getStr,
|
|
audio: $jsonMsg{"audio"}.getStr,
|
|
communityId: $jsonMsg{"communityId"}.getStr,
|
|
audioDurationMs: jsonMsg{"audioDurationMs"}.getInt,
|
|
deleted: jsonMsg{"deleted"}.getBool,
|
|
hasMention: false,
|
|
hide: false
|
|
)
|
|
|
|
if contentType == ContentType.Gap:
|
|
message.gapFrom = jsonMsg["gapParameters"]["from"].getInt
|
|
message.gapTo = jsonMsg["gapParameters"]["to"].getInt
|
|
|
|
if jsonMsg.contains("parsedText") and jsonMsg{"parsedText"}.kind != JNull:
|
|
for text in jsonMsg{"parsedText"}:
|
|
message.parsedText.add(text.toTextItem)
|
|
|
|
message.linkUrls = concat(message.parsedText.map(t => t.children.filter(c => c.textType == "link")))
|
|
.filter(t => t.destination.startsWith("http") or t.destination.startsWith("statusim://"))
|
|
.map(t => t.destination)
|
|
.join(" ")
|
|
|
|
if message.contentType == ContentType.Sticker:
|
|
message.stickerHash = jsonMsg["sticker"]["hash"].getStr
|
|
message.stickerPackId = jsonMsg["sticker"]["pack"].getInt
|
|
|
|
if message.contentType == ContentType.Transaction:
|
|
let
|
|
allContracts = allErc20Contracts().concat(getCustomTokens())
|
|
ethereum = newErc20Contract("Ethereum", Mainnet, parseAddress(constants.ZERO_ADDRESS), "ETH", 18, true)
|
|
tokenAddress = jsonMsg["commandParameters"]["contract"].getStr
|
|
tokenContract = if tokenAddress == "": ethereum else: allContracts.findByAddress(parseAddress(tokenAddress))
|
|
tokenContractStr = if tokenContract == nil: "{}" else: $(Json.encode(tokenContract))
|
|
var weiStr = if tokenContract == nil: "0" else: wei2Eth(jsonMsg["commandParameters"]["value"].getStr, tokenContract.decimals)
|
|
weiStr.trimZeros()
|
|
|
|
# TODO find a way to use json_seralization for this. When I try, I get an error
|
|
message.commandParameters = CommandParameters(
|
|
id: jsonMsg["commandParameters"]["id"].getStr,
|
|
fromAddress: jsonMsg["commandParameters"]["from"].getStr,
|
|
address: jsonMsg["commandParameters"]["address"].getStr,
|
|
contract: tokenContractStr,
|
|
value: weiStr,
|
|
transactionHash: jsonMsg["commandParameters"]["transactionHash"].getStr,
|
|
commandState: jsonMsg["commandParameters"]["commandState"].getInt,
|
|
signature: jsonMsg["commandParameters"]["signature"].getStr
|
|
)
|
|
|
|
# This is kind of a workaround in case we're processing a transaction message. The reason for
|
|
# that is a message where a recipient accepted to share his address with sender. In that message
|
|
# a recipient's public key is set as a "from" property of a "Message" object and we cannot
|
|
# determine which of two users has initiated transaction actually.
|
|
#
|
|
# To overcome this we're checking if the "from" address from the "commandParameters" object of
|
|
# the "Message" is contained as an address in the wallet of logged in user. If yes, means that
|
|
# currently logged in user has initiated a transaction (he is a sender), otherwise currently
|
|
# logged in user is a recipient.
|
|
if message.commandParameters.fromAddress != "":
|
|
message.isCurrentUser = currentUserWalletContainsAddress(message.commandParameters.fromAddress)
|
|
|
|
message.hasMention = concat(message.parsedText.map(
|
|
t => t.children.filter(
|
|
c => c.textType == "mention" and c.literal == publicChatKey))).len > 0
|
|
|
|
result = message
|