1- import { TriggersContext } from '@sofie-automation/meteor-lib/dist/triggers/triggersContext'
1+ import {
2+ TriggersAsyncCollection ,
3+ TriggersContext ,
4+ TriggerTrackerComputation ,
5+ } from '@sofie-automation/meteor-lib/dist/triggers/triggersContext'
26import { SINGLE_USE_TOKEN_SALT } from '@sofie-automation/meteor-lib/dist/api/userActions'
3- import { assertNever , getHash , Time } from '../../lib/tempLib'
7+ import { assertNever , getHash , ProtectedString , Time } from '../../lib/tempLib'
48import { getCurrentTime } from '../../lib/lib'
59import { MeteorCall } from '../methods'
610import { ClientAPI } from '@sofie-automation/meteor-lib/dist/api/client'
711import { UserAction } from '@sofie-automation/meteor-lib/dist/userAction'
812import { TFunction } from 'i18next'
9- import { Tracker } from 'meteor/tracker'
10-
1113import { logger } from '../../logging'
1214import { IBaseFilterLink , IRundownPlaylistFilterLink } from '@sofie-automation/blueprints-integration'
1315import { PartId , StudioId } from '@sofie-automation/corelib/dist/dataModel/Ids'
1416import { DummyReactiveVar } from '@sofie-automation/meteor-lib/dist/triggers/reactive-var'
1517import { ReactivePlaylistActionContext } from '@sofie-automation/meteor-lib/dist/triggers/actionFactory'
16- import { MongoQuery } from '@sofie-automation/corelib/dist/mongo'
17- import { CollectionName } from '@sofie-automation/corelib/dist/dataModel/Collections'
18- import { AdLibAction } from '@sofie-automation/corelib/dist/dataModel/AdlibAction'
19- import { AdLibPiece } from '@sofie-automation/corelib/dist/dataModel/AdLibPiece'
20- import { PartInstance } from '@sofie-automation/meteor-lib/dist/collections/PartInstances'
18+ import { FindOneOptions , FindOptions , MongoQuery } from '@sofie-automation/corelib/dist/mongo'
19+ import { DBRundownPlaylist , SelectedPartInstance } from '@sofie-automation/corelib/dist/dataModel/RundownPlaylist'
20+ import {
21+ AdLibActions ,
22+ AdLibPieces ,
23+ PartInstances ,
24+ Parts ,
25+ RundownBaselineAdLibActions ,
26+ RundownBaselineAdLibPieces ,
27+ RundownPlaylists ,
28+ Rundowns ,
29+ Segments ,
30+ } from '../../collections'
2131import { DBPart } from '@sofie-automation/corelib/dist/dataModel/Part'
22- import { RundownBaselineAdLibAction } from '@sofie-automation/corelib/dist/dataModel/RundownBaselineAdLibAction'
23- import { RundownBaselineAdLibItem } from '@sofie-automation/corelib/dist/dataModel/RundownBaselineAdLibPiece'
24- import { DBRundownPlaylist } from '@sofie-automation/corelib/dist/dataModel/RundownPlaylist'
25- import { DBRundown } from '@sofie-automation/corelib/dist/dataModel/Rundown'
26- import { DBSegment } from '@sofie-automation/corelib/dist/dataModel/Segment'
27- import { createSyncReadOnlyMongoCollection } from './triggersContextCollection'
32+ import { DBPartInstance } from '@sofie-automation/corelib/dist/dataModel/PartInstance'
33+ import { AsyncOnlyReadOnlyMongoCollection } from '../../collections/collection'
2834
2935export function hashSingleUseToken ( token : string ) : string {
3036 return getHash ( SINGLE_USE_TOKEN_SALT + token )
3137}
3238
33- /**
34- * Some synchronous read-only collections to satisfy the TriggersContext interface
35- */
36- const AdLibActions = createSyncReadOnlyMongoCollection < AdLibAction > ( CollectionName . AdLibActions )
37- const AdLibPieces = createSyncReadOnlyMongoCollection < AdLibPiece > ( CollectionName . AdLibPieces )
38- const PartInstances = createSyncReadOnlyMongoCollection < PartInstance > ( CollectionName . PartInstances )
39- const Parts = createSyncReadOnlyMongoCollection < DBPart > ( CollectionName . Parts )
40- const RundownBaselineAdLibActions = createSyncReadOnlyMongoCollection < RundownBaselineAdLibAction > (
41- CollectionName . RundownBaselineAdLibActions
42- )
43- const RundownBaselineAdLibPieces = createSyncReadOnlyMongoCollection < RundownBaselineAdLibItem > (
44- CollectionName . RundownBaselineAdLibPieces
45- )
46- const RundownPlaylists = createSyncReadOnlyMongoCollection < DBRundownPlaylist > ( CollectionName . RundownPlaylists )
47- const Rundowns = createSyncReadOnlyMongoCollection < DBRundown > ( CollectionName . Rundowns )
48- const Segments = createSyncReadOnlyMongoCollection < DBSegment > ( CollectionName . Segments )
39+ class MeteorTriggersCollectionWrapper < DBInterface extends { _id : ProtectedString < any > } >
40+ implements TriggersAsyncCollection < DBInterface >
41+ {
42+ readonly #collection: AsyncOnlyReadOnlyMongoCollection < DBInterface >
43+
44+ constructor ( collection : AsyncOnlyReadOnlyMongoCollection < DBInterface > ) {
45+ this . #collection = collection
46+ }
47+
48+ async findFetchAsync (
49+ _computation : TriggerTrackerComputation | null ,
50+ selector : MongoQuery < DBInterface > ,
51+ options ?: FindOptions < DBInterface >
52+ ) : Promise < Array < DBInterface > > {
53+ return this . #collection. findFetchAsync ( selector , options )
54+ }
55+
56+ async findOneAsync (
57+ _computation : TriggerTrackerComputation | null ,
58+ selector : MongoQuery < DBInterface > | DBInterface [ '_id' ] ,
59+ options ?: FindOneOptions < DBInterface >
60+ ) : Promise < DBInterface | undefined > {
61+ return this . #collection. findOneAsync ( selector , options )
62+ }
63+ }
4964
5065export const MeteorTriggersContext : TriggersContext = {
5166 MeteorCall,
@@ -54,14 +69,14 @@ export const MeteorTriggersContext: TriggersContext = {
5469
5570 isClient : false ,
5671
57- AdLibActions,
58- AdLibPieces,
59- Parts,
60- RundownBaselineAdLibActions,
61- RundownBaselineAdLibPieces,
62- RundownPlaylists,
63- Rundowns,
64- Segments,
72+ AdLibActions : new MeteorTriggersCollectionWrapper ( AdLibActions ) ,
73+ AdLibPieces : new MeteorTriggersCollectionWrapper ( AdLibPieces ) ,
74+ Parts : new MeteorTriggersCollectionWrapper ( Parts ) ,
75+ RundownBaselineAdLibActions : new MeteorTriggersCollectionWrapper ( RundownBaselineAdLibActions ) ,
76+ RundownBaselineAdLibPieces : new MeteorTriggersCollectionWrapper ( RundownBaselineAdLibPieces ) ,
77+ RundownPlaylists : new MeteorTriggersCollectionWrapper ( RundownPlaylists ) ,
78+ Rundowns : new MeteorTriggersCollectionWrapper ( Rundowns ) ,
79+ Segments : new MeteorTriggersCollectionWrapper ( Segments ) ,
6580
6681 hashSingleUseToken,
6782
@@ -81,73 +96,91 @@ export const MeteorTriggersContext: TriggersContext = {
8196 )
8297 } ,
8398
84- nonreactiveTracker : Tracker . nonreactive ,
99+ withComputation : async ( _computation , func ) => {
100+ return func ( )
101+ } ,
85102
86- memoizedIsolatedAutorun : < T extends ( ...args : any ) => any > (
87- fnc : T ,
103+ memoizedIsolatedAutorun : async < TArgs extends any [ ] , TRes > (
104+ computation : TriggerTrackerComputation | null ,
105+ fnc : ( computation : TriggerTrackerComputation | null , ...args : TArgs ) => Promise < TRes > ,
88106 _functionName : string ,
89- ...params : Parameters < T >
90- ) : ReturnType < T > => {
91- return fnc ( ...( params as any ) )
107+ ...params : TArgs
108+ ) : Promise < TRes > => {
109+ return fnc ( computation , ...params )
92110 } ,
93111
94112 createContextForRundownPlaylistChain,
95113}
96114
97- function createContextForRundownPlaylistChain (
115+ async function createContextForRundownPlaylistChain (
98116 studioId : StudioId ,
99117 filterChain : IBaseFilterLink [ ]
100- ) : ReactivePlaylistActionContext | undefined {
101- const playlist = rundownPlaylistFilter (
118+ ) : Promise < ReactivePlaylistActionContext | undefined > {
119+ const playlist = await rundownPlaylistFilter (
102120 studioId ,
103121 filterChain . filter ( ( link ) => link . object === 'rundownPlaylist' ) as IRundownPlaylistFilterLink [ ]
104122 )
105123
106124 if ( ! playlist ) return undefined
107125
108- let currentPartId : PartId | null = null ,
109- nextPartId : PartId | null = null ,
110- currentPartInstance : PartInstance | null = null ,
111- currentSegmentPartIds : PartId [ ] = [ ] ,
112- nextSegmentPartIds : PartId [ ] = [ ]
113-
114- if ( playlist . currentPartInfo ) {
115- currentPartInstance = PartInstances . findOne ( playlist . currentPartInfo . partInstanceId ) ?? null
116- const currentPart = currentPartInstance ?. part ?? null
117- if ( currentPart ) {
118- currentPartId = currentPart . _id
119- currentSegmentPartIds = Parts . find ( {
120- segmentId : currentPart . segmentId ,
121- } ) . map ( ( part ) => part . _id )
122- }
123- }
124- if ( playlist . nextPartInfo ) {
125- const nextPart = PartInstances . findOne ( playlist . nextPartInfo . partInstanceId ) ?. part ?? null
126- if ( nextPart ) {
127- nextPartId = nextPart . _id
128- nextSegmentPartIds = Parts . find ( {
129- segmentId : nextPart . segmentId ,
130- } ) . map ( ( part ) => part . _id )
131- }
132- }
126+ const [ currentPartInfo , nextPartInfo ] = await Promise . all ( [
127+ fetchInfoForSelectedPart ( playlist . currentPartInfo ) ,
128+ fetchInfoForSelectedPart ( playlist . nextPartInfo ) ,
129+ ] )
133130
134131 return {
135132 studioId : new DummyReactiveVar ( studioId ) ,
136133 rundownPlaylistId : new DummyReactiveVar ( playlist ?. _id ) ,
137134 rundownPlaylist : new DummyReactiveVar ( playlist ) ,
138- currentRundownId : new DummyReactiveVar ( currentPartInstance ?. rundownId ?? playlist . rundownIdsInOrder [ 0 ] ?? null ) ,
139- currentPartId : new DummyReactiveVar ( currentPartId ) ,
140- currentSegmentPartIds : new DummyReactiveVar ( currentSegmentPartIds ) ,
141- nextPartId : new DummyReactiveVar ( nextPartId ) ,
142- nextSegmentPartIds : new DummyReactiveVar ( nextSegmentPartIds ) ,
135+ currentRundownId : new DummyReactiveVar (
136+ playlist . currentPartInfo ?. rundownId ?? playlist . rundownIdsInOrder [ 0 ] ?? null
137+ ) ,
138+ currentPartId : new DummyReactiveVar ( currentPartInfo ?. partId ?? null ) ,
139+ currentSegmentPartIds : new DummyReactiveVar ( currentPartInfo ?. segmentPartIds ?? [ ] ) ,
140+ nextPartId : new DummyReactiveVar ( nextPartInfo ?. partId ?? null ) ,
141+ nextSegmentPartIds : new DummyReactiveVar ( nextPartInfo ?. segmentPartIds ?? [ ] ) ,
143142 currentPartInstanceId : new DummyReactiveVar ( playlist . currentPartInfo ?. partInstanceId ?? null ) ,
144143 }
145144}
146145
147- function rundownPlaylistFilter (
146+ async function fetchInfoForSelectedPart ( partInfo : SelectedPartInstance | null ) : Promise < {
147+ partId : PartId
148+ segmentPartIds : PartId [ ]
149+ } | null > {
150+ if ( ! partInfo ) return null
151+
152+ const partInstance = ( await PartInstances . findOneAsync ( partInfo . partInstanceId , {
153+ projection : {
154+ // @ts -expect-error deep property
155+ 'part._id' : 1 ,
156+ segmentId : 1 ,
157+ } ,
158+ } ) ) as ( Pick < DBPartInstance , 'segmentId' > & { part : Pick < DBPart , '_id' > } ) | null
159+
160+ if ( ! partInstance ) return null
161+
162+ const partId = partInstance . part . _id
163+ const segmentPartIds = await Parts . findFetchAsync (
164+ {
165+ segmentId : partInstance . segmentId ,
166+ } ,
167+ {
168+ projection : {
169+ _id : 1 ,
170+ } ,
171+ }
172+ ) . then ( ( parts ) => parts . map ( ( part ) => part . _id ) )
173+
174+ return {
175+ partId,
176+ segmentPartIds,
177+ }
178+ }
179+
180+ async function rundownPlaylistFilter (
148181 studioId : StudioId ,
149182 filterChain : IRundownPlaylistFilterLink [ ]
150- ) : DBRundownPlaylist | undefined {
183+ ) : Promise < DBRundownPlaylist | undefined > {
151184 const selector : MongoQuery < DBRundownPlaylist > = {
152185 $and : [
153186 {
@@ -181,5 +214,5 @@ function rundownPlaylistFilter(
181214 }
182215 } )
183216
184- return RundownPlaylists . findOne ( selector )
217+ return RundownPlaylists . findOneAsync ( selector )
185218}
0 commit comments