-
Notifications
You must be signed in to change notification settings - Fork 79
/
Copy pathservice.nim
340 lines (276 loc) · 14.8 KB
/
service.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
import NimQml, json, sequtils, chronicles, strutils, strutils, stint, sugar, tables, json_serialization
import ../../../app/core/eventemitter
import ../../../app/core/[main]
import ../../../app/core/tasks/[qt, threadpool]
import web3/ethtypes, web3/conversions, stew/byteutils, nimcrypto
import ../../../backend/backend
import ../../../backend/response_type
import ./dto/notification
import ../../common/activity_center
import ../message/service
import ../message/dto/seen_unseen_messages
import ../chat/service as chat_service
export notification
include async_tasks
logScope:
topics = "activity-center-service"
type
ActivityCenterNotificationsArgs* = ref object of Args
activityCenterNotifications*: seq[ActivityCenterNotificationDto]
ActivityCenterNotificationIdsArgs* = ref object of Args
notificationIds*: seq[string]
ActivityCenterNotificationIdArgs* = ref object of Args
notificationId*: string
# Signals which may be emitted by this service:
const SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_LOADED* = "activityCenterNotificationsLoaded"
const SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_COUNT_MAY_HAVE_CHANGED* = "activityCenterNotificationsCountMayChanged"
const SIGNAL_ACTIVITY_CENTER_MARK_NOTIFICATIONS_AS_READ* = "activityCenterMarkNotificationsAsRead"
const SIGNAL_ACTIVITY_CENTER_MARK_NOTIFICATIONS_AS_UNREAD* = "activityCenterMarkNotificationsAsUnread"
const SIGNAL_ACTIVITY_CENTER_MARK_ALL_NOTIFICATIONS_AS_READ* = "activityCenterMarkAllNotificationsAsRead"
const SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_REMOVED* = "activityCenterNotificationsRemoved"
const SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_ACCEPTED* = "activityCenterNotificationsAccepted"
const SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_DISMISSED* = "activityCenterNotificationsDismissed"
const DEFAULT_LIMIT = 20
# NOTE: temporary disable Transactions and System and we don't count All group
const ACTIVITY_GROUPS = @[
ActivityCenterGroup.Mentions,
ActivityCenterGroup.Replies,
ActivityCenterGroup.Membership,
ActivityCenterGroup.Admin,
ActivityCenterGroup.ContactRequests,
ActivityCenterGroup.IdentityVerification
]
QtObject:
type Service* = ref object of QObject
threadpool: ThreadPool
events: EventEmitter
cursor*: string
activeGroup: ActivityCenterGroup
readType: ActivityCenterReadType
chatService: chat_service.Service
# Forward declaration
proc asyncActivityNotificationLoad*(self: Service)
proc delete*(self: Service) =
self.QObject.delete
proc newService*(
events: EventEmitter,
threadpool: ThreadPool,
chatService: chat_service.Service,
): Service =
new(result, delete)
result.QObject.setup
result.events = events
result.threadpool = threadpool
result.cursor = ""
result.activeGroup = ActivityCenterGroup.All
result.readType = ActivityCenterReadType.All
result.chatService = chatService
proc handleNewNotificationsLoaded(self: Service, activityCenterNotifications: seq[ActivityCenterNotificationDto]) =
# For now status-go notify about every notification update regardless active group so we need filter manulay on the desktop side
let groupTypes = activityCenterNotificationTypesByGroup(self.activeGroup)
let filteredNotifications = filter(activityCenterNotifications, proc(notification: ActivityCenterNotificationDto): bool =
return (self.readType == ActivityCenterReadType.All or not notification.read) and groupTypes.contains(notification.notificationType.int)
)
let removedNotifications = filter(activityCenterNotifications, proc(notification: ActivityCenterNotificationDto): bool =
return notification.deleted
)
if (filteredNotifications.len > 0):
self.events.emit(
SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_LOADED,
ActivityCenterNotificationsArgs(activityCenterNotifications: filteredNotifications)
)
if (removedNotifications.len > 0):
var notificationIds: seq[string] = removedNotifications.map(notification => notification.id)
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_REMOVED, ActivityCenterNotificationIdsArgs(notificationIds: notificationIds))
# NOTE: this signal must fire even we have no new notifications to show
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_COUNT_MAY_HAVE_CHANGED, Args())
proc init*(self: Service) =
self.events.on(SignalType.Message.event) do(e: Args):
let receivedData = MessageSignal(e)
if (receivedData.activityCenterNotifications.len > 0):
self.handleNewNotificationsLoaded(receivedData.activityCenterNotifications)
self.events.on(SIGNAL_PARSE_RAW_ACTIVITY_CENTER_NOTIFICATIONS) do(e: Args):
let raw = RawActivityCenterNotificationsArgs(e)
if raw.activityCenterNotifications.len > 0:
var activityCenterNotifications: seq[ActivityCenterNotificationDto] = @[]
for notificationJson in raw.activityCenterNotifications:
activityCenterNotifications.add(notificationJson.toActivityCenterNotificationDto)
self.handleNewNotificationsLoaded(activityCenterNotifications)
proc setActiveNotificationGroup*(self: Service, group: ActivityCenterGroup) =
self.activeGroup = group
proc getActiveNotificationGroup*(self: Service): ActivityCenterGroup =
return self.activeGroup
proc setActivityCenterReadType*(self: Service, readType: ActivityCenterReadType) =
self.readType = readType
proc getActivityCenterReadType*(self: Service): ActivityCenterReadType =
return self.readType
proc resetCursor*(self: Service) =
self.cursor = ""
proc hasMoreToShow*(self: Service): bool =
return self.cursor != ""
proc asyncActivityNotificationLoad*(self: Service) =
let arg = AsyncActivityNotificationLoadTaskArg(
tptr: asyncActivityNotificationLoadTask,
vptr: cast[ByteAddress](self.vptr),
slot: "asyncActivityNotificationLoaded",
cursor: self.cursor,
limit: DEFAULT_LIMIT,
group: self.activeGroup,
readType: self.readType
)
self.threadpool.start(arg)
proc getActivityCenterNotifications*(self: Service): seq[ActivityCenterNotificationDto] =
try:
let activityTypes = activityCenterNotificationTypesByGroup(self.activeGroup)
let response = backend.activityCenterNotifications(
backend.ActivityCenterNotificationsRequest(
cursor: self.cursor,
limit: DEFAULT_LIMIT,
activityTypes: activityTypes,
readType: self.readType.int
)
)
let activityCenterNotificationsTuple = parseActivityCenterNotifications(response.result)
self.cursor = activityCenterNotificationsTuple[0];
result = activityCenterNotificationsTuple[1]
except Exception as e:
error "Error getting activity center notifications", msg = e.msg
proc getActivityCenterNotificationsCounters(self: Service, activityTypes: seq[int], readType: ActivityCenterReadType): Table[int, int] =
try:
let response = backend.activityCenterNotificationsCount(
backend.ActivityCenterCountRequest(
activityTypes: activityTypes,
readType: readType.int,
)
)
var counters = initTable[int, int]()
if response.result.kind != JNull:
for activityType in activityTypes:
if response.result.contains($activityType):
counters[activityType] = response.result[$activityType].getInt
return counters
except Exception as e:
error "Error getting unread activity center notifications count", msg = e.msg
proc getActivityGroupCounters*(self: Service): Table[ActivityCenterGroup, int] =
let allActivityTypes = activityCenterNotificationTypesByGroup(ActivityCenterGroup.All)
let counters = self.getActivityCenterNotificationsCounters(allActivityTypes, self.readType)
var groupCounters = initTable[ActivityCenterGroup, int]()
for group in ACTIVITY_GROUPS:
var groupTotal = 0
for activityType in activityCenterNotificationTypesByGroup(group):
groupTotal = groupTotal + counters.getOrDefault(activityType, 0)
groupCounters[group] = groupTotal
return groupCounters
proc getUnreadActivityCenterNotificationsCount*(self: Service): int =
let activityTypes = activityCenterNotificationTypesByGroup(ActivityCenterGroup.All)
let counters = self.getActivityCenterNotificationsCounters(activityTypes, ActivityCenterReadType.Unread)
var total = 0
for activityType in activityTypes:
total = total + counters.getOrDefault(activityType, 0)
return total
proc getHasUnseenActivityCenterNotifications*(self: Service): bool =
try:
let response = backend.hasUnseenActivityCenterNotifications()
if response.result.kind != JNull:
return response.result.getBool
except Exception as e:
error "Error getting unseen activity center notifications", msg = e.msg
proc markActivityCenterNotificationRead*(self: Service, notificationId: string) =
try:
let notificationIds = @[notificationId]
let response = backend.markActivityCenterNotificationsRead(notificationIds)
var seenAndUnseenMessagesBatch: JsonNode = newJObject()
discard response.result.getProp("seenAndUnseenMessages", seenAndUnseenMessagesBatch)
if seenAndUnseenMessagesBatch.len > 0:
for seenAndUnseenMessagesRaw in seenAndUnseenMessagesBatch:
let seenAndUnseenMessages = seenAndUnseenMessagesRaw.toSeenUnseenMessagesDto()
let data = MessagesMarkedAsReadArgs(
chatId: seenAndUnseenMessages.chatId,
allMessagesMarked: false,
messagesIds: notificationIds,
messagesCount: seenAndUnseenMessages.count,
messagesWithMentionsCount: seenAndUnseenMessages.countWithMentions)
self.events.emit(SIGNAL_MESSAGES_MARKED_AS_READ, data)
self.events.emit(SIGNAL_ACTIVITY_CENTER_MARK_NOTIFICATIONS_AS_READ, ActivityCenterNotificationIdsArgs(notificationIds: notificationIds))
except Exception as e:
error "Error marking as read", msg = e.msg
proc markActivityCenterNotificationUnread*(self: Service, notificationId: string) =
try:
let notificationIds = @[notificationId]
let response = backend.markActivityCenterNotificationsUnread(notificationIds)
if response.error != nil:
raise newException(RpcException, response.error.message)
self.events.emit(SIGNAL_ACTIVITY_CENTER_MARK_NOTIFICATIONS_AS_UNREAD, ActivityCenterNotificationIdsArgs(notificationIds: notificationIds))
except Exception as e:
error "Error marking as unread", msg = e.msg
proc markAllActivityCenterNotificationsRead*(self: Service) =
try:
let response = backend.markAllActivityCenterNotificationsRead()
var seenAndUnseenMessagesBatch: JsonNode = newJObject()
discard response.result.getProp("seenAndUnseenMessages", seenAndUnseenMessagesBatch)
if seenAndUnseenMessagesBatch.len > 0:
for seenAndUnseenMessagesRaw in seenAndUnseenMessagesBatch:
let seenAndUnseenMessages = seenAndUnseenMessagesRaw.toSeenUnseenMessagesDto()
let data = MessagesMarkedAsReadArgs(chatId: seenAndUnseenMessages.chatId, allMessagesMarked: true)
self.events.emit(SIGNAL_MESSAGES_MARKED_AS_READ, data)
self.events.emit(SIGNAL_ACTIVITY_CENTER_MARK_ALL_NOTIFICATIONS_AS_READ, Args())
except Exception as e:
error "Error marking all as read", msg = e.msg
proc markAsSeenActivityCenterNotifications*(self: Service) =
try:
discard backend.markAsSeenActivityCenterNotifications()
except Exception as e:
error "Error marking as seen", msg = e.msg
proc asyncActivityNotificationLoaded*(self: Service, response: string) {.slot.} =
try:
let responseObj = response.parseJson
if responseObj{"error"}.kind != JNull and responseObj{"error"}.getStr != "":
raise newException(CatchableError, responseObj{"error"}.getStr)
if responseObj["activityNotifications"].kind != JNull:
let activityCenterNotificationsTuple = parseActivityCenterNotifications(responseObj["activityNotifications"])
self.cursor = activityCenterNotificationsTuple[0]
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_LOADED,
ActivityCenterNotificationsArgs(activityCenterNotifications: activityCenterNotificationsTuple[1]))
except Exception as e:
error "Error loading activity notification async", msg = e.msg
proc deleteActivityCenterNotifications*(self: Service, notificationIds: seq[string]): string =
try:
let response = backend.deleteActivityCenterNotifications(notificationIds)
if response.error != nil:
raise newException(RpcException, response.error.message)
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_REMOVED, ActivityCenterNotificationIdsArgs(notificationIds: notificationIds))
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_COUNT_MAY_HAVE_CHANGED, Args())
except Exception as e:
error "Error deleting notifications", msg = e.msg
result = e.msg
proc getNotificationForTypeAndCommunityId*(self: Service, notificationType: ActivityCenterNotificationType, communityId: string): ActivityCenterNotificationDto =
let acNotifications = self.getActivityCenterNotifications()
for acNotification in acNotifications:
if acNotification.notificationType == notificationType and acNotification.communityId == communityId:
return acNotification
proc acceptActivityCenterNotification*(self: Service, notificationId: string) =
try:
let notificationIds = @[notificationId]
let response = backend.acceptActivityCenterNotifications(notificationIds)
if response.error != nil:
raise newException(RpcException, response.error.message)
if response.result.kind != JNull:
if response.result.contains("chats"):
for jsonChat in response.result["chats"]:
let chat = toChatDto(jsonChat)
self.chatService.updateOrAddChat(chat)
self.events.emit(SIGNAL_CHAT_UPDATE, ChatUpdateArgs(chats: @[chat]))
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_ACCEPTED, ActivityCenterNotificationIdArgs(notificationId: notificationId))
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_COUNT_MAY_HAVE_CHANGED, Args())
except Exception as e:
error "Error accepting activity center notification", msg = e.msg
proc dismissActivityCenterNotification*(self: Service, notificationId: string) =
try:
let notificationIds = @[notificationId]
let response = backend.dismissActivityCenterNotifications(notificationIds)
if response.error != nil:
raise newException(RpcException, response.error.message)
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_DISMISSED, ActivityCenterNotificationIdArgs(notificationId: notificationId))
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_COUNT_MAY_HAVE_CHANGED, Args())
except Exception as e:
error "Error dismissing activity center notification", msg = e.msg