Skip to content

Commit ad82bdb

Browse files
committed
feat(lsg): add notification support to LSG
1 parent ca10c38 commit ad82bdb

File tree

10 files changed

+511
-39
lines changed

10 files changed

+511
-39
lines changed

packages/live-status-gateway-api/api/schemas/notifications.yaml

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@ $defs:
1313
description: Active notifications in Sofie
1414
type: array
1515
items:
16-
$ref: '#/$defs/DBNotificationObj'
16+
$ref: '#/$defs/NotificationObj'
1717
required: [event, activeNotifications]
1818
additionalProperties: false
1919
examples:
2020
- event: notifications
2121
activeNotifications:
22-
- $ref: '#/$defs/DBNotificationObj/examples/0'
22+
- $ref: '#/$defs/NotificationObj/examples/0'
2323

24-
DBNotificationObj:
24+
NotificationObj:
2525
type: object
26-
title: DBNotificationObj
26+
title: NotificationObj
2727
description: This describes a notification that should be shown to a user. These can come from various sources, and are added and removed dynamically during system usage
2828
required:
2929
- _id
@@ -41,7 +41,7 @@ $defs:
4141
type: string
4242
description: The message of the notification
4343
relatedTo:
44-
$ref: '#/$defs/DBNotificationTarget'
44+
$ref: '#/$defs/NotificationTarget'
4545
created:
4646
type: integer
4747
format: int64
@@ -56,7 +56,7 @@ $defs:
5656
severity: error
5757
message: 'disk.space.low'
5858
relatedTo:
59-
$ref: '#/$defs/DBNotificationTarget/examples/0'
59+
$ref: '#/$defs/NotificationTarget/examples/0'
6060
created: 1694784932
6161
modified: 1694784950
6262

@@ -71,19 +71,19 @@ $defs:
7171
examples:
7272
- info
7373

74-
DBNotificationTarget:
75-
title: DBNotificationTarget
74+
NotificationTarget:
75+
title: NotificationTarget
7676
description: Description of what the notification is related to
7777
oneOf:
78-
- $ref: '#/$defs/DBNotificationTargetRundown'
79-
- $ref: '#/$defs/DBNotificationTargetRundownPlaylist'
80-
- $ref: '#/$defs/DBNotificationTargetPartInstance'
81-
- $ref: '#/$defs/DBNotificationTargetPieceInstance'
78+
- $ref: '#/$defs/NotificationTargetRundown'
79+
- $ref: '#/$defs/NotificationTargetRundownPlaylist'
80+
- $ref: '#/$defs/NotificationTargetPartInstance'
81+
- $ref: '#/$defs/NotificationTargetPieceInstance'
8282
examples:
83-
- $ref: '#/$defs/DBNotificationTargetRundown/examples/0'
84-
- $ref: '#/$defs/DBNotificationTargetRundownPlaylist/examples/0'
85-
- $ref: '#/$defs/DBNotificationTargetPartInstance/examples/0'
86-
- $ref: '#/$defs/DBNotificationTargetPieceInstance/examples/0'
83+
- $ref: '#/$defs/NotificationTargetRundown/examples/0'
84+
- $ref: '#/$defs/NotificationTargetRundownPlaylist/examples/0'
85+
- $ref: '#/$defs/NotificationTargetPartInstance/examples/0'
86+
- $ref: '#/$defs/NotificationTargetPieceInstance/examples/0'
8787

8888
NotificationTargetType:
8989
type: string
@@ -95,9 +95,9 @@ $defs:
9595
- partInstance
9696
- pieceInstance
9797

98-
DBNotificationTargetRundown:
98+
NotificationTargetRundown:
9999
type: object
100-
title: DBNotificationTargetRundown
100+
title: NotificationTargetRundown
101101
required: [type, studioId, rundownId]
102102
properties:
103103
type:
@@ -113,9 +113,9 @@ $defs:
113113
studioId: studio01
114114
rundownId: rd123
115115

116-
DBNotificationTargetRundownPlaylist:
116+
NotificationTargetRundownPlaylist:
117117
type: object
118-
title: DBNotificationTargetRundownPlaylist
118+
title: NotificationTargetRundownPlaylist
119119
required: [type, studioId, playlistId]
120120
properties:
121121
type:
@@ -131,9 +131,9 @@ $defs:
131131
studioId: studio01
132132
playlistId: pl456
133133

134-
DBNotificationTargetPartInstance:
134+
NotificationTargetPartInstance:
135135
type: object
136-
title: DBNotificationTargetPartInstance
136+
title: NotificationTargetPartInstance
137137
required: [type, studioId, rundownId, partInstanceId]
138138
properties:
139139
type:
@@ -152,9 +152,9 @@ $defs:
152152
rundownId: rd123
153153
partInstanceId: pi789
154154

155-
DBNotificationTargetPieceInstance:
155+
NotificationTargetPieceInstance:
156156
type: object
157-
title: DBNotificationTargetPieceInstance
157+
title: NotificationTargetPieceInstance
158158
required: [type, studioId, rundownId, partInstanceId, pieceInstanceId]
159159
properties:
160160
type:

packages/live-status-gateway-api/api/schemas/root.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ $defs:
153153
- activePieces
154154
- segments
155155
- adLibs
156+
- notifications
156157
- buckets
157158
- packages
158159
status:

packages/live-status-gateway-api/src/generated/schema.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ enum SubscriptionName {
6363
ACTIVE_PIECES = 'activePieces',
6464
SEGMENTS = 'segments',
6565
AD_LIBS = 'adLibs',
66+
NOTIFICATIONS = 'notifications',
6667
BUCKETS = 'buckets',
6768
RESERVED_PACKAGES = 'packages',
6869
}
@@ -828,13 +829,13 @@ interface NotificationsEvent {
828829
/**
829830
* Active notifications in Sofie
830831
*/
831-
activeNotifications: DbNotificationObj[]
832+
activeNotifications: NotificationObj[]
832833
}
833834

834835
/**
835836
* This describes a notification that should be shown to a user. These can come from various sources, and are added and removed dynamically during system usage
836837
*/
837-
interface DbNotificationObj {
838+
interface NotificationObj {
838839
/**
839840
* Unique identifier for the notification
840841
*/
@@ -851,10 +852,10 @@ interface DbNotificationObj {
851852
* Description of what the notification is related to
852853
*/
853854
relatedTo:
854-
| DbNotificationTargetRundown
855-
| DbNotificationTargetRundownPlaylist
856-
| DbNotificationTargetPartInstance
857-
| DbNotificationTargetPieceInstance
855+
| NotificationTargetRundown
856+
| NotificationTargetRundownPlaylist
857+
| NotificationTargetPartInstance
858+
| NotificationTargetPieceInstance
858859
/**
859860
* Unix timestamp of creation
860861
*/
@@ -874,7 +875,7 @@ enum NotificationSeverity {
874875
INFO = 'info',
875876
}
876877

877-
interface DbNotificationTargetRundown {
878+
interface NotificationTargetRundown {
878879
/**
879880
* Possible NotificationTarget types
880881
*/
@@ -893,7 +894,7 @@ enum NotificationTargetType {
893894
PIECE_INSTANCE = 'pieceInstance',
894895
}
895896

896-
interface DbNotificationTargetRundownPlaylist {
897+
interface NotificationTargetRundownPlaylist {
897898
/**
898899
* Possible NotificationTarget types
899900
*/
@@ -902,7 +903,7 @@ interface DbNotificationTargetRundownPlaylist {
902903
playlistId: string
903904
}
904905

905-
interface DbNotificationTargetPartInstance {
906+
interface NotificationTargetPartInstance {
906907
/**
907908
* Possible NotificationTarget types
908909
*/
@@ -912,7 +913,7 @@ interface DbNotificationTargetPartInstance {
912913
partInstanceId: string
913914
}
914915

915-
interface DbNotificationTargetPieceInstance {
916+
interface NotificationTargetPieceInstance {
916917
/**
917918
* Possible NotificationTarget types
918919
*/
@@ -968,11 +969,11 @@ export {
968969
BucketStatus,
969970
BucketAdLibStatus,
970971
NotificationsEvent,
971-
DbNotificationObj,
972+
NotificationObj,
972973
NotificationSeverity,
973-
DbNotificationTargetRundown,
974+
NotificationTargetRundown,
974975
NotificationTargetType,
975-
DbNotificationTargetRundownPlaylist,
976-
DbNotificationTargetPartInstance,
977-
DbNotificationTargetPieceInstance,
976+
NotificationTargetRundownPlaylist,
977+
NotificationTargetPartInstance,
978+
NotificationTargetPieceInstance,
978979
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { CollectionName } from '@sofie-automation/corelib/dist/dataModel/Collections'
2+
import { CorelibPubSub } from '@sofie-automation/corelib/dist/pubsub'
3+
import { Logger } from 'winston'
4+
import { CoreHandler } from '../../coreHandler.js'
5+
import { CollectionHandlers } from '../../liveStatusServer.js'
6+
import { PublicationCollection } from '../../publicationCollection.js'
7+
import { DBNotificationObj } from '@sofie-automation/corelib/dist/dataModel/Notifications'
8+
import { PlaylistNotificationsHandler } from './playlistNotificationsHandler.js'
9+
import { RundownNotificationsHandler } from './rundownNotificationsHandler.js'
10+
import _ from 'underscore'
11+
import { unprotectString } from '@sofie-automation/server-core-integration'
12+
13+
const THROTTLE_PERIOD_MS = 100
14+
15+
/**
16+
* NotificationsHandler
17+
* Combines playlist-level and rundown-level notifications into a single collection
18+
*
19+
* This handler listens to the two lower-level handlers (playlist & rundown notifications)
20+
* and merges their collection contents on change.
21+
*/
22+
export class NotificationsHandler extends PublicationCollection<
23+
DBNotificationObj[],
24+
CorelibPubSub.notificationsForRundownPlaylist | CorelibPubSub.notificationsForRundown,
25+
CollectionName.Notifications
26+
> {
27+
private throttledNotify: (data: DBNotificationObj[]) => void
28+
29+
private _playlistNotificationsHandler?: PlaylistNotificationsHandler
30+
private _rundownNotificationsHandler?: RundownNotificationsHandler
31+
32+
constructor(logger: Logger, coreHandler: CoreHandler) {
33+
super(CollectionName.Notifications, CorelibPubSub.notificationsForRundownPlaylist, logger, coreHandler)
34+
35+
this.throttledNotify = _.throttle(this.notify.bind(this), THROTTLE_PERIOD_MS, {
36+
leading: false,
37+
trailing: true,
38+
})
39+
}
40+
41+
init(handlers: CollectionHandlers): void {
42+
super.init(handlers)
43+
44+
this._playlistNotificationsHandler =
45+
handlers.playlistNotificationsHandler as unknown as PlaylistNotificationsHandler
46+
this._rundownNotificationsHandler =
47+
handlers.rundownNotificationsHandler as unknown as RundownNotificationsHandler
48+
49+
if (this._playlistNotificationsHandler) {
50+
this._playlistNotificationsHandler.subscribe(this.onSourceUpdated)
51+
}
52+
if (this._rundownNotificationsHandler) {
53+
this._rundownNotificationsHandler.subscribe(this.onSourceUpdated)
54+
}
55+
}
56+
57+
protected changed(): void {
58+
this.updateAndNotify()
59+
}
60+
61+
private onSourceUpdated = (): void => {
62+
this.changed()
63+
}
64+
65+
private updateCollectionData(): boolean {
66+
const merged = new Map<string, DBNotificationObj>()
67+
68+
// Pull data from the playlist notifications handler's collection
69+
if (this._playlistNotificationsHandler) {
70+
const playlistDocs = this._playlistNotificationsHandler.getPublishedDocs()
71+
for (const d of playlistDocs) {
72+
if (d._id && !merged.has(unprotectString(d._id))) {
73+
merged.set(unprotectString(d._id), d)
74+
}
75+
}
76+
}
77+
78+
// Pull data from the rundown notifications handler's collection
79+
if (this._rundownNotificationsHandler) {
80+
const rundownDocs = this._rundownNotificationsHandler.getPublishedDocs()
81+
for (const d of rundownDocs) {
82+
if (d._id && !merged.has(unprotectString(d._id))) {
83+
merged.set(unprotectString(d._id), d)
84+
}
85+
}
86+
}
87+
88+
const newNotifications = Array.from(merged.values())
89+
90+
const hasAnythingChanged = !_.isEqual(this._collectionData, newNotifications)
91+
if (hasAnythingChanged) {
92+
this._collectionData = newNotifications
93+
}
94+
95+
return hasAnythingChanged
96+
}
97+
98+
private updateAndNotify() {
99+
if (this.updateCollectionData()) this.throttledNotify(this._collectionData ?? [])
100+
}
101+
}

0 commit comments

Comments
 (0)