Skip to content

Commit df7ed0c

Browse files
authored
feat: support packageinfo update flow for buckets and studio baseline SOFIE-2655 (Sofie-Automation#1051)
1 parent ea6c343 commit df7ed0c

File tree

15 files changed

+262
-77
lines changed

15 files changed

+262
-77
lines changed

meteor/server/api/__tests__/cleanup.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ async function setDefaultDatatoDB(env: DefaultEnvironment, now: number) {
221221
actionId: '',
222222
display: {} as any,
223223
importVersions: {} as any,
224+
ingestInfo: undefined,
224225
showStyleVariantId,
225226
userData: {} as any,
226227
userDataManifest: {} as any,
@@ -232,6 +233,7 @@ async function setDefaultDatatoDB(env: DefaultEnvironment, now: number) {
232233
studioId,
233234
showStyleBaseId: env.showStyleBaseId,
234235
importVersions: {} as any,
236+
ingestInfo: undefined,
235237
showStyleVariantId,
236238
_rank: 0,
237239
content: {} as any,

meteor/server/api/buckets.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as _ from 'underscore'
22
import { Meteor } from 'meteor/meteor'
33
import { Bucket } from '../../lib/collections/Buckets'
4-
import { getRandomId, literal } from '../../lib/lib'
4+
import { getRandomId, getRandomString, literal } from '../../lib/lib'
55
import { BucketSecurity } from '../security/buckets'
66
import { BucketAdLib } from '@sofie-automation/corelib/dist/dataModel/BucketAdLibPiece'
77
import { AdLibAction, AdLibActionCommon } from '@sofie-automation/corelib/dist/dataModel/AdlibAction'
@@ -165,12 +165,13 @@ export namespace BucketsAPI {
165165
adLibAction = {
166166
...(_.omit(action, ['partId', 'rundownId']) as Omit<AdLibAction, 'partId' | 'rundownId'>),
167167
_id: getRandomId(),
168-
externalId: '', // TODO - is this ok?
168+
externalId: getRandomString(), // This needs to be something unique, so that the regenerate logic doesn't get it mixed up with something else
169169
bucketId: access.bucket._id,
170170
studioId: access.studioId,
171171
showStyleBaseId: rundown.showStyleBaseId,
172172
showStyleVariantId: action.allVariants ? null : rundown.showStyleVariantId,
173173
importVersions: rundown.importVersions,
174+
ingestInfo: undefined,
174175
}
175176
}
176177

Lines changed: 85 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1-
import { ExpectedPackageDBType } from '@sofie-automation/corelib/dist/dataModel/ExpectedPackages'
1+
import {
2+
ExpectedPackageDBFromBucketAdLib,
3+
ExpectedPackageDBFromBucketAdLibAction,
4+
ExpectedPackageDBFromRundownBaselineObjects,
5+
ExpectedPackageDBFromStudioBaselineObjects,
6+
ExpectedPackageDBType,
7+
ExpectedPackageFromRundown,
8+
} from '@sofie-automation/corelib/dist/dataModel/ExpectedPackages'
29
import { PackageInfoDB } from '@sofie-automation/corelib/dist/dataModel/PackageInfos'
310
import { ExpectedPackages, Rundowns } from '../../collections'
411
import { assertNever, lazyIgnore } from '../../../lib/lib'
512
import { logger } from '../../logging'
613
import { runIngestOperation } from './lib'
714
import { IngestJobs } from '@sofie-automation/corelib/dist/worker/ingest'
815
import { ExpectedPackageId, RundownId } from '@sofie-automation/corelib/dist/dataModel/Ids'
16+
import { Rundown } from '@sofie-automation/corelib/dist/dataModel/Rundown'
17+
import { QueueStudioJob } from '../../worker/worker'
18+
import { StudioJobs } from '@sofie-automation/corelib/dist/worker/studio'
919

1020
export async function onUpdatedPackageInfo(packageId: ExpectedPackageId, _doc: PackageInfoDB | null): Promise<void> {
1121
logger.info(`PackageInfo updated "${packageId}"`)
@@ -23,35 +33,15 @@ export async function onUpdatedPackageInfo(packageId: ExpectedPackageId, _doc: P
2333
case ExpectedPackageDBType.ADLIB_ACTION:
2434
case ExpectedPackageDBType.BASELINE_ADLIB_PIECE:
2535
case ExpectedPackageDBType.BASELINE_ADLIB_ACTION:
26-
case ExpectedPackageDBType.RUNDOWN_BASELINE_OBJECTS: {
27-
const existingEntry = pendingPackageUpdates.get(pkg.rundownId)
28-
if (existingEntry) {
29-
// already queued, add to the batch
30-
existingEntry.push(pkg._id)
31-
} else {
32-
pendingPackageUpdates.set(pkg.rundownId, [pkg._id])
33-
}
34-
35-
// TODO: Scaling - this won't batch correctly if package manager directs calls to multiple instances
36-
lazyIgnore(
37-
`onUpdatedPackageInfoForRundown_${pkg.rundownId}`,
38-
() => {
39-
const packageIds = pendingPackageUpdates.get(pkg.rundownId)
40-
if (packageIds) {
41-
pendingPackageUpdates.delete(pkg.rundownId)
42-
onUpdatedPackageInfoForRundown(pkg.rundownId, packageIds).catch((e) => {
43-
logger.error(`Updating ExpectedPackages for Rundown "${pkg.rundownId}" failed: ${e}`)
44-
})
45-
}
46-
},
47-
1000
48-
)
36+
case ExpectedPackageDBType.RUNDOWN_BASELINE_OBJECTS:
37+
onUpdatedPackageInfoForRundownDebounce(pkg)
4938
break
50-
}
5139
case ExpectedPackageDBType.BUCKET_ADLIB:
5240
case ExpectedPackageDBType.BUCKET_ADLIB_ACTION:
41+
onUpdatedPackageInfoForBucketItemDebounce(pkg)
42+
break
5343
case ExpectedPackageDBType.STUDIO_BASELINE_OBJECTS:
54-
// Ignore, as we can't handle that for now
44+
onUpdatedPackageInfoForStudioBaselineDebounce(pkg)
5545
break
5646
default:
5747
assertNever(pkg)
@@ -60,7 +50,33 @@ export async function onUpdatedPackageInfo(packageId: ExpectedPackageId, _doc: P
6050
}
6151
}
6252

63-
const pendingPackageUpdates = new Map<RundownId, Array<ExpectedPackageId>>()
53+
const pendingRundownPackageUpdates = new Map<RundownId, Array<ExpectedPackageId>>()
54+
function onUpdatedPackageInfoForRundownDebounce(
55+
pkg: ExpectedPackageFromRundown | ExpectedPackageDBFromRundownBaselineObjects
56+
) {
57+
const existingEntry = pendingRundownPackageUpdates.get(pkg.rundownId)
58+
if (existingEntry) {
59+
// already queued, add to the batch
60+
existingEntry.push(pkg._id)
61+
} else {
62+
pendingRundownPackageUpdates.set(pkg.rundownId, [pkg._id])
63+
}
64+
65+
// TODO: Scaling - this won't batch correctly if package manager directs calls to multiple instances
66+
lazyIgnore(
67+
`onUpdatedPackageInfoForRundown_${pkg.rundownId}`,
68+
() => {
69+
const packageIds = pendingRundownPackageUpdates.get(pkg.rundownId)
70+
if (packageIds) {
71+
pendingRundownPackageUpdates.delete(pkg.rundownId)
72+
onUpdatedPackageInfoForRundown(pkg.rundownId, packageIds).catch((e) => {
73+
logger.error(`Updating ExpectedPackages for Rundown "${pkg.rundownId}" failed: ${e}`)
74+
})
75+
}
76+
},
77+
1000
78+
)
79+
}
6480

6581
async function onUpdatedPackageInfoForRundown(
6682
rundownId: RundownId,
@@ -70,17 +86,57 @@ async function onUpdatedPackageInfoForRundown(
7086
return
7187
}
7288

73-
const tmpRundown = await Rundowns.findOneAsync(rundownId)
89+
const tmpRundown = (await Rundowns.findOneAsync(rundownId, {
90+
projection: {
91+
studioId: 1,
92+
externalId: 1,
93+
},
94+
})) as Pick<Rundown, 'studioId' | 'externalId'> | undefined
7495
if (!tmpRundown) {
7596
logger.error(
7697
`onUpdatedPackageInfoForRundown: Missing rundown "${rundownId}" for packages "${packageIds.join(', ')}"`
7798
)
7899
return
79100
}
80101

81-
await runIngestOperation(tmpRundown.studioId, IngestJobs.PackageInfosUpdated, {
102+
await runIngestOperation(tmpRundown.studioId, IngestJobs.PackageInfosUpdatedRundown, {
82103
rundownExternalId: tmpRundown.externalId,
83104
peripheralDeviceId: null,
84105
packageIds,
85106
})
86107
}
108+
109+
function onUpdatedPackageInfoForBucketItemDebounce(
110+
pkg: ExpectedPackageDBFromBucketAdLib | ExpectedPackageDBFromBucketAdLibAction
111+
) {
112+
lazyIgnore(
113+
`onUpdatedPackageInfoForBucket_${pkg.studioId}_${pkg.bucketId}_${pkg.pieceExternalId}`,
114+
() => {
115+
runIngestOperation(pkg.studioId, IngestJobs.BucketItemRegenerate, {
116+
bucketId: pkg.bucketId,
117+
externalId: pkg.pieceExternalId,
118+
}).catch((err) => {
119+
logger.error(
120+
`Updating ExpectedPackages for Bucket "${pkg.bucketId}" Item "${pkg.pieceExternalId}" failed: ${err}`
121+
)
122+
})
123+
},
124+
1000
125+
)
126+
}
127+
128+
function onUpdatedPackageInfoForStudioBaselineDebounce(pkg: ExpectedPackageDBFromStudioBaselineObjects) {
129+
lazyIgnore(
130+
`onUpdatedPackageInfoForStudioBaseline_${pkg.studioId}`,
131+
() => {
132+
QueueStudioJob(StudioJobs.UpdateStudioBaseline, pkg.studioId, undefined)
133+
.then(async (job) => {
134+
await job.complete
135+
})
136+
.catch((err) => {
137+
logger.error(`Updating ExpectedPackages for StudioBaseline "${pkg.studioId}" failed: ${err}`)
138+
})
139+
},
140+
1000
141+
)
142+
}

meteor/server/publications/buckets.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ meteorPublish(
4545
meteorPublish(PubSub.bucketAdLibPieces, async function (selector: MongoQuery<BucketAdLib>, _token: string | undefined) {
4646
if (!selector) throw new Meteor.Error(400, 'selector argument missing')
4747
const modifier: FindOptions<BucketAdLib> = {
48-
fields: {},
48+
fields: {
49+
ingestInfo: 0, // This is a large blob, and is not of interest to the UI
50+
},
4951
}
5052
if (isProtectedString(selector.bucketId) && (await BucketSecurity.allowReadAccess(this, selector.bucketId))) {
5153
return BucketAdLibs.findWithCursor(selector, modifier)
@@ -58,7 +60,9 @@ meteorPublish(
5860
async function (selector: MongoQuery<BucketAdLibAction>, _token: string | undefined) {
5961
if (!selector) throw new Meteor.Error(400, 'selector argument missing')
6062
const modifier: FindOptions<BucketAdLibAction> = {
61-
fields: {},
63+
fields: {
64+
ingestInfo: 0, // This is a large blob, and is not of interest to the UI
65+
},
6266
}
6367
if (isProtectedString(selector.bucketId) && (await BucketSecurity.allowReadAccess(this, selector.bucketId))) {
6468
return BucketAdLibActions.findWithCursor(selector, modifier)

packages/blueprints-integration/src/api/showStyle.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,11 @@ export interface ShowStyleBlueprintManifest<TRawConfig = IBlueprintConfig, TProc
125125
getAdlibItem?: (
126126
context: IShowStyleUserContext,
127127
ingestItem: IngestAdlib
128-
) => IBlueprintAdLibPiece | IBlueprintActionManifest | null
128+
) =>
129+
| Promise<IBlueprintAdLibPiece | IBlueprintActionManifest | null>
130+
| IBlueprintAdLibPiece
131+
| IBlueprintActionManifest
132+
| null
129133

130134
/**
131135
* Apply automatic upgrades to the structure of user specified config overrides

packages/corelib/src/dataModel/BucketAdLibAction.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { BucketAdLibActionId, BucketId, StudioId, ShowStyleVariantId, ShowStyleBaseId } from './Ids'
22
import { RundownImportVersions } from './Rundown'
33
import { AdLibActionCommon } from './AdlibAction'
4+
import { BucketAdLibIngestInfo } from './BucketAdLibPiece'
45

56
export interface BucketAdLibAction extends Omit<AdLibActionCommon, 'rundownId'> {
67
_id: BucketAdLibActionId
@@ -18,6 +19,8 @@ export interface BucketAdLibAction extends Omit<AdLibActionCommon, 'rundownId'>
1819
/** if showStyleVariantId is null, the adlibAction can be used with any variant */
1920
showStyleVariantId: ShowStyleVariantId | null
2021
importVersions: RundownImportVersions // TODO - is this good?
22+
/** Information used to generate the adlib. If set, this adlib can be regenerated */
23+
ingestInfo: BucketAdLibIngestInfo | undefined
2124

2225
/** The following extended interface allows assigning namespace information to the actions as they are stored in the
2326
* database after being emitted from the blueprints

packages/corelib/src/dataModel/BucketAdLibPiece.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
1-
import { IBlueprintAdLibPiece, SomeContent } from '@sofie-automation/blueprints-integration'
1+
import { IBlueprintAdLibPiece, IngestAdlib, SomeContent } from '@sofie-automation/blueprints-integration'
22
import { BucketAdLibId, BucketId, StudioId, ShowStyleVariantId, ShowStyleBaseId } from './Ids'
33
import { PieceTimelineObjectsBlob } from './Piece'
44
import { RundownImportVersions } from './Rundown'
55

6+
/**
7+
* Information used to 'ingest' a Bucket Adlib item
8+
*/
9+
export interface BucketAdLibIngestInfo {
10+
/**
11+
* If set, the adlib should be limited to the specified ShowStyleVariants.
12+
* If undefined, the adlib will be generated for all Variants of the ShowStyleBase.
13+
*/
14+
limitToShowStyleVariantIds: ShowStyleVariantId[] | undefined
15+
/**
16+
* The ingest payload the Adlib was generated from
17+
*/
18+
payload: IngestAdlib
19+
}
20+
621
export interface BucketAdLib extends Omit<IBlueprintAdLibPiece, 'content'> {
722
_id: BucketAdLibId
823
bucketId: BucketId
@@ -20,6 +35,8 @@ export interface BucketAdLib extends Omit<IBlueprintAdLibPiece, 'content'> {
2035
showStyleVariantId: ShowStyleVariantId | null
2136

2237
importVersions: RundownImportVersions // TODO - is this good?
38+
/** Information used to generate the adlib. If set, this adlib can be regenerated */
39+
ingestInfo: BucketAdLibIngestInfo | undefined
2340

2441
/** Stringified timelineObjects */
2542
timelineObjectsString: PieceTimelineObjectsBlob

packages/corelib/src/dataModel/ExpectedPackages.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,16 @@ export interface ExpectedPackageDBFromBucketAdLib extends ExpectedPackageDBBase
114114
bucketId: BucketId
115115
/** The Bucket adlib this package belongs to */
116116
pieceId: BucketAdLibId
117+
/** The `externalId` of the Bucket adlib this package belongs to */
118+
pieceExternalId: string
117119
}
118120
export interface ExpectedPackageDBFromBucketAdLibAction extends ExpectedPackageDBBase {
119121
fromPieceType: ExpectedPackageDBType.BUCKET_ADLIB_ACTION
120122
bucketId: BucketId
121123
/** The Bucket adlib-action this package belongs to */
122124
pieceId: BucketAdLibActionId
125+
/** The `externalId` of the Bucket adlib-action this package belongs to */
126+
pieceExternalId: string
123127
}
124128

125129
export function getContentVersionHash(expectedPackage: Omit<ExpectedPackage.Any, '_id'>): string {

packages/corelib/src/worker/ingest.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ export enum IngestJobs {
106106
/**
107107
* Some PackageInfos have been updated, regenerate any Parts which depend on these PackageInfos
108108
*/
109-
PackageInfosUpdated = 'packageInfosUpdated',
109+
PackageInfosUpdatedRundown = 'packageInfosUpdatedRundown',
110110

111111
/**
112112
* User requested removing a rundown
@@ -119,6 +119,7 @@ export enum IngestJobs {
119119

120120
// For now these are in this queue, but if this gets split up to be per rundown, then a single bucket queue will be needed
121121
BucketItemImport = 'bucketItemImport',
122+
BucketItemRegenerate = 'bucketItemRegenerate',
122123
BucketActionRegenerateExpectedPackages = 'bucketActionRegenerateExpectedPackages',
123124
BucketActionModify = 'bucketActionModify',
124125
BucketPieceModify = 'bucketPieceModify',
@@ -210,7 +211,7 @@ export interface MosSwapStoryProps extends IngestPropsBase {
210211
export interface ExpectedPackagesRegenerateProps {
211212
rundownId: RundownId
212213
}
213-
export interface PackageInfosUpdatedProps extends IngestPropsBase {
214+
export interface PackageInfosUpdatedRundownProps extends IngestPropsBase {
214215
packageIds: ExpectedPackageId[]
215216
}
216217

@@ -228,6 +229,10 @@ export interface BucketItemImportProps {
228229
showStyleVariantIds?: ShowStyleVariantId[]
229230
payload: IngestAdlib
230231
}
232+
export interface BucketItemRegenerateProps {
233+
bucketId: BucketId
234+
externalId: string
235+
}
231236
export interface BucketActionRegenerateExpectedPackagesProps {
232237
actionId: BucketAdLibActionId
233238
}
@@ -278,12 +283,13 @@ export type IngestJobFunc = {
278283
[IngestJobs.MosSwapStory]: (data: MosSwapStoryProps) => void
279284

280285
[IngestJobs.ExpectedPackagesRegenerate]: (data: ExpectedPackagesRegenerateProps) => void
281-
[IngestJobs.PackageInfosUpdated]: (data: PackageInfosUpdatedProps) => void
286+
[IngestJobs.PackageInfosUpdatedRundown]: (data: PackageInfosUpdatedRundownProps) => void
282287

283288
[IngestJobs.UserRemoveRundown]: (data: UserRemoveRundownProps) => void
284289
[IngestJobs.UserUnsyncRundown]: (data: UserUnsyncRundownProps) => void
285290

286291
[IngestJobs.BucketItemImport]: (data: BucketItemImportProps) => void
292+
[IngestJobs.BucketItemRegenerate]: (data: BucketItemRegenerateProps) => void
287293
[IngestJobs.BucketActionModify]: (data: BucketActionModifyProps) => void
288294
[IngestJobs.BucketPieceModify]: (data: BucketPieceModifyProps) => void
289295
[IngestJobs.BucketActionRegenerateExpectedPackages]: (data: BucketActionRegenerateExpectedPackagesProps) => void

0 commit comments

Comments
 (0)