status-lib/status/types/chat.nim

170 lines
5.7 KiB
Nim

{.used.}
import strutils, random, strformat, json
import ../libstatus/accounts as status_accounts
import message
include chat_member
include chat_membership_event
type ChatType* {.pure.}= enum
Unknown = 0,
OneToOne = 1,
Public = 2,
PrivateGroupChat = 3,
Profile = 4,
Timeline = 5
CommunityChat = 6
proc isOneToOne*(self: ChatType): bool = self == ChatType.OneToOne
proc isTimeline*(self: ChatType): bool = self == ChatType.Timeline
type Chat* = ref object
id*: string # ID is the id of the chat, for public chats it is the name e.g. status, for one-to-one is the hex encoded public key and for group chats is a random uuid appended with the hex encoded pk of the creator of the chat
communityId*: string
private*: bool
categoryId*: string
name*: string
description*: string
color*: string
identicon*: string
isActive*: bool # indicates whether the chat has been soft deleted
chatType*: ChatType
timestamp*: int64 # indicates the last time this chat has received/sent a message
joined*: int64 # indicates when the user joined the chat last time
lastClockValue*: int64 # indicates the last clock value to be used when sending messages
deletedAtClockValue*: int64 # indicates the clock value at time of deletion, messages with lower clock value of this should be discarded
unviewedMessagesCount*: int
unviewedMentionsCount*: int
lastMessage*: Message
members*: seq[ChatMember]
membershipUpdateEvents*: seq[ChatMembershipEvent]
mentionsCount*: int # Using this is not a good approach, we should instead use unviewedMentionsCount and refer to it always.
muted*: bool
canPost*: bool
ensName*: string
position*: int
proc `$`*(self: Chat): string =
result = fmt"Chat(id:{self.id}, name:{self.name}, active:{self.isActive}, type:{self.chatType})"
proc toJsonNode*(self: Chat): JsonNode =
result = %* {
"active": self.isActive,
"chatType": self.chatType.int,
"color": self.color,
"deletedAtClockValue": self.deletedAtClockValue,
"id": self.id,
"lastClockValue": self.lastClockValue,
"lastMessage": nil,
"members": self.members.toJsonNode,
"membershipUpdateEvents": self.membershipUpdateEvents.toJsonNode,
"name": (if self.ensName != "": self.ensName else: self.name),
"timestamp": self.timestamp,
"unviewedMessagesCount": self.unviewedMessagesCount,
"joined": self.joined,
"position": self.position
}
proc toChatMember*(jsonMember: JsonNode): ChatMember =
let pubkey = jsonMember["id"].getStr
result = ChatMember(
admin: jsonMember["admin"].getBool,
id: pubkey,
joined: jsonMember["joined"].getBool,
identicon: generateIdenticon(pubkey),
userName: generateAlias(pubkey)
)
proc toChatMembershipEvent*(jsonMembership: JsonNode): ChatMembershipEvent =
result = ChatMembershipEvent(
chatId: jsonMembership["chatId"].getStr,
clockValue: jsonMembership["clockValue"].getBiggestInt,
fromKey: jsonMembership["from"].getStr,
rawPayload: jsonMembership["rawPayload"].getStr,
signature: jsonMembership["signature"].getStr,
eventType: jsonMembership["type"].getInt,
name: jsonMembership{"name"}.getStr,
members: @[]
)
if jsonMembership{"members"} != nil:
for member in jsonMembership["members"]:
result.members.add(member.getStr)
proc toChat*(jsonChat: JsonNode): Chat =
let chatTypeInt = jsonChat{"chatType"}.getInt
let chatType: ChatType = if chatTypeInt >= ord(low(ChatType)) or chatTypeInt <= ord(high(ChatType)): ChatType(chatTypeInt) else: ChatType.Unknown
result = Chat(
id: jsonChat{"id"}.getStr,
communityId: jsonChat{"communityId"}.getStr,
name: jsonChat{"name"}.getStr,
description: jsonChat{"description"}.getStr,
identicon: "",
color: jsonChat{"color"}.getStr,
isActive: jsonChat{"active"}.getBool,
chatType: chatType,
timestamp: jsonChat{"timestamp"}.getBiggestInt,
lastClockValue: jsonChat{"lastClockValue"}.getBiggestInt,
deletedAtClockValue: jsonChat{"deletedAtClockValue"}.getBiggestInt,
unviewedMessagesCount: jsonChat{"unviewedMessagesCount"}.getInt,
unviewedMentionsCount: jsonChat{"unviewedMentionsCount"}.getInt,
mentionsCount: 0,
muted: false,
ensName: "",
joined: 0,
private: jsonChat{"private"}.getBool
)
if jsonChat.hasKey("muted") and jsonChat["muted"].kind != JNull:
result.muted = jsonChat["muted"].getBool
if jsonChat["lastMessage"].kind != JNull:
result.lastMessage = jsonChat{"lastMessage"}.toMessage()
if jsonChat.hasKey("joined") and jsonChat["joined"].kind != JNull:
result.joined = jsonChat{"joined"}.getInt
if result.chatType == ChatType.OneToOne:
result.identicon = generateIdenticon(result.id)
if result.name.endsWith(".eth"):
result.ensName = result.name
if result.name == "":
result.name = generateAlias(result.id)
if jsonChat["members"].kind != JNull:
result.members = @[]
for jsonMember in jsonChat["members"]:
result.members.add(jsonMember.toChatMember)
if jsonChat["membershipUpdateEvents"].kind != JNull:
result.membershipUpdateEvents = @[]
for jsonMember in jsonChat["membershipUpdateEvents"]:
result.membershipUpdateEvents.add(jsonMember.toChatMembershipEvent)
const channelColors* = ["#fa6565", "#7cda00", "#887af9", "#51d0f0", "#FE8F59", "#d37ef4"]
proc newChat*(id: string, chatType: ChatType): Chat =
randomize()
result = Chat(
id: id,
color: channelColors[rand(channelColors.len - 1)],
isActive: true,
chatType: chatType,
timestamp: 0,
lastClockValue: 0,
deletedAtClockValue: 0,
unviewedMessagesCount: 0,
mentionsCount: 0,
members: @[]
)
if chatType == ChatType.OneToOne:
result.identicon = generateIdenticon(id)
result.name = generateAlias(id)
else:
result.name = id