Skip to content

Commit adf102d

Browse files
committed
feat(lsg): add notification support to LSG
1 parent 4c316a1 commit adf102d

File tree

11 files changed

+511
-42
lines changed

11 files changed

+511
-42
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
@@ -152,6 +152,7 @@ $defs:
152152
- activePieces
153153
- segments
154154
- adLibs
155+
- notifications
155156
- buckets
156157
- packages
157158
status:

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

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ enum SubscriptionName {
6161
ACTIVE_PIECES = 'activePieces',
6262
SEGMENTS = 'segments',
6363
AD_LIBS = 'adLibs',
64+
NOTIFICATIONS = 'notifications',
6465
BUCKETS = 'buckets',
6566
RESERVED_PACKAGES = 'packages',
6667
}
@@ -732,13 +733,13 @@ interface NotificationsEvent {
732733
/**
733734
* Active notifications in Sofie
734735
*/
735-
activeNotifications: DbNotificationObj[]
736+
activeNotifications: NotificationObj[]
736737
}
737738

738739
/**
739740
* 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
740741
*/
741-
interface DbNotificationObj {
742+
interface NotificationObj {
742743
/**
743744
* Unique identifier for the notification
744745
*/
@@ -755,10 +756,10 @@ interface DbNotificationObj {
755756
* Description of what the notification is related to
756757
*/
757758
relatedTo:
758-
| DbNotificationTargetRundown
759-
| DbNotificationTargetRundownPlaylist
760-
| DbNotificationTargetPartInstance
761-
| DbNotificationTargetPieceInstance
759+
| NotificationTargetRundown
760+
| NotificationTargetRundownPlaylist
761+
| NotificationTargetPartInstance
762+
| NotificationTargetPieceInstance
762763
/**
763764
* Unix timestamp of creation
764765
*/
@@ -778,7 +779,7 @@ enum NotificationSeverity {
778779
INFO = 'info',
779780
}
780781

781-
interface DbNotificationTargetRundown {
782+
interface NotificationTargetRundown {
782783
/**
783784
* Possible NotificationTarget types
784785
*/
@@ -797,7 +798,7 @@ enum NotificationTargetType {
797798
PIECE_INSTANCE = 'pieceInstance',
798799
}
799800

800-
interface DbNotificationTargetRundownPlaylist {
801+
interface NotificationTargetRundownPlaylist {
801802
/**
802803
* Possible NotificationTarget types
803804
*/
@@ -806,7 +807,7 @@ interface DbNotificationTargetRundownPlaylist {
806807
playlistId: string
807808
}
808809

809-
interface DbNotificationTargetPartInstance {
810+
interface NotificationTargetPartInstance {
810811
/**
811812
* Possible NotificationTarget types
812813
*/
@@ -816,7 +817,7 @@ interface DbNotificationTargetPartInstance {
816817
partInstanceId: string
817818
}
818819

819-
interface DbNotificationTargetPieceInstance {
820+
interface NotificationTargetPieceInstance {
820821
/**
821822
* Possible NotificationTarget types
822823
*/
@@ -869,11 +870,11 @@ export {
869870
BucketStatus,
870871
BucketAdLibStatus,
871872
NotificationsEvent,
872-
DbNotificationObj,
873+
NotificationObj,
873874
NotificationSeverity,
874-
DbNotificationTargetRundown,
875+
NotificationTargetRundown,
875876
NotificationTargetType,
876-
DbNotificationTargetRundownPlaylist,
877-
DbNotificationTargetPartInstance,
878-
DbNotificationTargetPieceInstance,
877+
NotificationTargetRundownPlaylist,
878+
NotificationTargetPartInstance,
879+
NotificationTargetPieceInstance,
879880
}
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)