Skip to content

Commit

Permalink
Merge remote-tracking branch 'nrk/release52' into bbc-release52
Browse files Browse the repository at this point in the history
  • Loading branch information
Julusian committed Feb 4, 2025
2 parents 31cf76f + c7f5208 commit 51d2ddf
Show file tree
Hide file tree
Showing 23 changed files with 805 additions and 214 deletions.
1 change: 1 addition & 0 deletions meteor/server/api/blueprints/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ async function innerUploadBlueprint(
newBlueprint.showStyleConfigSchema = blueprintManifest.showStyleConfigSchema
newBlueprint.showStyleConfigPresets = blueprintManifest.configPresets
newBlueprint.hasFixUpFunction = !!blueprintManifest.fixUpConfig
newBlueprint.packageStatusMessages = blueprintManifest.packageStatusMessages
} else if (blueprintManifest.blueprintType === BlueprintManifestType.STUDIO) {
newBlueprint.studioConfigSchema = blueprintManifest.studioConfigSchema
newBlueprint.studioConfigPresets = blueprintManifest.configPresets
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { defaultStudio } from '../../../../__mocks__/defaultCollectionObjects'
import { MediaObjects } from '../../../collections'
import { PieceDependencies } from '../common'
import { DEFAULT_MINIMUM_TAKE_SPAN } from '@sofie-automation/shared-lib/dist/core/constants'
import { PieceContentStatusMessageFactory } from '../messageFactory'

const mockMediaObjectsCollection = MongoMock.getInnerMockCollection<MediaObject>(MediaObjects)

Expand Down Expand Up @@ -449,7 +450,9 @@ describe('lib/mediaObjects', () => {
timelineObjectsString: EmptyPieceTimelineObjectsBlob,
})

const status1 = await checkPieceContentStatusAndDependencies(mockStudio, piece1, sourcelayer1)
const messageFactory = new PieceContentStatusMessageFactory(undefined)

const status1 = await checkPieceContentStatusAndDependencies(mockStudio, messageFactory, piece1, sourcelayer1)
expect(status1[0].status).toEqual(PieceStatusCode.OK)
expect(status1[0].messages).toHaveLength(0)
expect(status1[1]).toMatchObject(
Expand All @@ -460,7 +463,7 @@ describe('lib/mediaObjects', () => {
})
)

const status2 = await checkPieceContentStatusAndDependencies(mockStudio, piece2, sourcelayer1)
const status2 = await checkPieceContentStatusAndDependencies(mockStudio, messageFactory, piece2, sourcelayer1)
expect(status2[0].status).toEqual(PieceStatusCode.SOURCE_BROKEN)
expect(status2[0].messages).toHaveLength(1)
expect(status2[0].messages[0]).toMatchObject({
Expand All @@ -474,7 +477,7 @@ describe('lib/mediaObjects', () => {
})
)

const status3 = await checkPieceContentStatusAndDependencies(mockStudio, piece3, sourcelayer1)
const status3 = await checkPieceContentStatusAndDependencies(mockStudio, messageFactory, piece3, sourcelayer1)
expect(status3[0].status).toEqual(PieceStatusCode.SOURCE_MISSING)
expect(status3[0].messages).toHaveLength(1)
expect(status3[0].messages[0]).toMatchObject({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { MongoFieldSpecifierOnesStrict } from '@sofie-automation/corelib/dist/mo
import { BucketAdLibAction } from '@sofie-automation/corelib/dist/dataModel/BucketAdLibAction'
import { BucketAdLib } from '@sofie-automation/corelib/dist/dataModel/BucketAdLibPiece'
import { BlueprintId, ShowStyleBaseId } from '@sofie-automation/corelib/dist/dataModel/Ids'
import { Blueprint } from '@sofie-automation/corelib/dist/dataModel/Blueprint'

export interface SourceLayersDoc {
_id: ShowStyleBaseId
Expand Down Expand Up @@ -53,10 +54,17 @@ export const showStyleBaseFieldSpecifier = literal<
sourceLayersWithOverrides: 1,
})

export type BlueprintFields = '_id' | 'packageStatusMessages'
export const blueprintFieldSpecifier = literal<MongoFieldSpecifierOnesStrict<Pick<Blueprint, BlueprintFields>>>({
_id: 1,
packageStatusMessages: 1,
})

export interface BucketContentCache {
BucketAdLibs: ReactiveCacheCollection<Pick<BucketAdLib, BucketAdLibFields>>
BucketAdLibActions: ReactiveCacheCollection<Pick<BucketAdLibAction, BucketActionFields>>
ShowStyleSourceLayers: ReactiveCacheCollection<SourceLayersDoc>
Blueprints: ReactiveCacheCollection<Pick<Blueprint, BlueprintFields>>
}

export function createReactiveContentCache(): BucketContentCache {
Expand All @@ -66,6 +74,7 @@ export function createReactiveContentCache(): BucketContentCache {
'bucketAdlibActions'
),
ShowStyleSourceLayers: new ReactiveCacheCollection<SourceLayersDoc>('sourceLayers'),
Blueprints: new ReactiveCacheCollection<Pick<Blueprint, BlueprintFields>>('blueprints'),
}

return cache
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { Meteor } from 'meteor/meteor'
import { BucketId, ShowStyleBaseId } from '@sofie-automation/corelib/dist/dataModel/Ids'
import { BlueprintId, BucketId, ShowStyleBaseId } from '@sofie-automation/corelib/dist/dataModel/Ids'
import { logger } from '../../../logging'
import {
blueprintFieldSpecifier,
bucketActionFieldSpecifier,
bucketAdlibFieldSpecifier,
BucketContentCache,
ShowStyleBaseFields,
showStyleBaseFieldSpecifier,
SourceLayersDoc,
} from './bucketContentCache'
import { BucketAdLibActions, BucketAdLibs, ShowStyleBases } from '../../../collections'
import { Blueprints, BucketAdLibActions, BucketAdLibs, ShowStyleBases } from '../../../collections'
import { DBShowStyleBase } from '@sofie-automation/corelib/dist/dataModel/ShowStyleBase'
import { equivalentArrays } from '@sofie-automation/shared-lib/dist/lib/lib'
import { applyAndValidateOverrides } from '@sofie-automation/corelib/dist/settings/objectWithOverrides'
Expand All @@ -33,6 +34,9 @@ export class BucketContentObserver implements Meteor.LiveQueryHandle {
#showStyleBaseIds: ShowStyleBaseId[] = []
#showStyleBaseIdObserver!: ReactiveMongoObserverGroupHandle

#blueprintIds: BlueprintId[] = []
#blueprintIdObserver!: ReactiveMongoObserverGroupHandle

#disposed = false

private constructor(cache: BucketContentCache) {
Expand All @@ -59,13 +63,16 @@ export class BucketContentObserver implements Meteor.LiveQueryHandle {
added: (doc) => {
const newDoc = convertShowStyleBase(doc)
cache.ShowStyleSourceLayers.upsert(doc._id, { $set: newDoc as Partial<Document> })
observer.updateBlueprintIds()
},
changed: (doc) => {
const newDoc = convertShowStyleBase(doc)
cache.ShowStyleSourceLayers.upsert(doc._id, { $set: newDoc as Partial<Document> })
observer.updateBlueprintIds()
},
removed: (doc) => {
cache.ShowStyleSourceLayers.remove(doc._id)
observer.updateBlueprintIds()
},
},
{
Expand All @@ -75,6 +82,27 @@ export class BucketContentObserver implements Meteor.LiveQueryHandle {
]
})

// Run the Blueprint query in a ReactiveMongoObserverGroup, so that it can be restarted whenever
observer.#blueprintIdObserver = await ReactiveMongoObserverGroup(async () => {
// Clear already cached data
cache.Blueprints.remove({})

logger.silly(`optimized observer restarting ${observer.#blueprintIds}`)

return [
Blueprints.observeChanges(
{
// We can use the `this.#blueprintIds` here, as this is restarted every time that property changes
_id: { $in: observer.#blueprintIds },
},
cache.Blueprints.link(),
{
projection: blueprintFieldSpecifier,
}
),
]
})

// Subscribe to the database, and pipe any updates into the ReactiveCacheCollections
// This takes ownership of the #showStyleBaseIdObserver, and will stop it if this throws
observer.#observers = await waitForAllObserversReady([
Expand Down Expand Up @@ -106,6 +134,7 @@ export class BucketContentObserver implements Meteor.LiveQueryHandle {
),

observer.#showStyleBaseIdObserver,
observer.#blueprintIdObserver,
])

return observer
Expand All @@ -132,6 +161,22 @@ export class BucketContentObserver implements Meteor.LiveQueryHandle {
REACTIVITY_DEBOUNCE
)

private updateBlueprintIds = _.debounce(
Meteor.bindEnvironment(() => {
if (this.#disposed) return

const newBlueprintIds = _.uniq(this.#cache.ShowStyleSourceLayers.find({}).map((rd) => rd.blueprintId))

if (!equivalentArrays(newBlueprintIds, this.#blueprintIds)) {
logger.silly(`optimized observer changed ids ${JSON.stringify(newBlueprintIds)} ${this.#blueprintIds}`)
this.#blueprintIds = newBlueprintIds
// trigger the rundown group to restart
this.#blueprintIdObserver.restart()
}
}),
REACTIVITY_DEBOUNCE
)

public get cache(): BucketContentCache {
return this.#cache
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
BucketId,
ExpectedPackageId,
PackageContainerPackageId,
ShowStyleBaseId,
StudioId,
} from '@sofie-automation/corelib/dist/dataModel/Ids'
import { MongoFieldSpecifierOnesStrict } from '@sofie-automation/corelib/dist/mongo'
Expand Down Expand Up @@ -37,6 +38,7 @@ import { regenerateForBucketActionIds, regenerateForBucketAdLibIds } from './reg
import { PieceContentStatusStudio } from '../checkPieceContentStatus'
import { check } from 'meteor/check'
import { triggerWriteAccessBecauseNoCheckNecessary } from '../../../security/securityVerify'
import { PieceContentStatusMessageFactory } from '../messageFactory'

interface UIBucketContentStatusesArgs {
readonly studioId: StudioId
Expand All @@ -48,6 +50,8 @@ interface UIBucketContentStatusesState {

studio: PieceContentStatusStudio

showStyleMessageFactories: Map<ShowStyleBaseId, PieceContentStatusMessageFactory>

adlibDependencies: Map<BucketAdLibId, PieceDependencies>
actionDependencies: Map<BucketAdLibActionId, PieceDependencies>
}
Expand Down Expand Up @@ -111,6 +115,16 @@ async function setupUIBucketContentStatusesPublicationObservers(
changed: (id) => triggerUpdate(trackActionChange(protectString(id))),
removed: (id) => triggerUpdate(trackActionChange(protectString(id))),
}),
contentCache.Blueprints.find({}).observeChanges({
added: () => triggerUpdate({ invalidateAll: true }),
changed: () => triggerUpdate({ invalidateAll: true }),
removed: () => triggerUpdate({ invalidateAll: true }),
}),
contentCache.ShowStyleSourceLayers.find({}).observeChanges({
added: () => triggerUpdate({ invalidateAll: true }),
changed: () => triggerUpdate({ invalidateAll: true }),
removed: () => triggerUpdate({ invalidateAll: true }),
}),

Studios.observeChanges(
{ _id: bucket.studioId },
Expand Down Expand Up @@ -198,14 +212,26 @@ async function manipulateUIBucketContentStatusesPublicationData(

let regenerateActionIds: Set<BucketAdLibActionId>
let regenerateAdlibIds: Set<BucketAdLibId>
if (!state.adlibDependencies || !state.actionDependencies || invalidateAllItems) {
if (
!state.adlibDependencies ||
!state.actionDependencies ||
!state.showStyleMessageFactories ||
invalidateAllItems
) {
state.adlibDependencies = new Map()
state.actionDependencies = new Map()
state.showStyleMessageFactories = new Map()

// force every piece to be regenerated
collection.remove(null)
regenerateAdlibIds = new Set(state.contentCache.BucketAdLibs.find({}).map((p) => p._id))
regenerateActionIds = new Set(state.contentCache.BucketAdLibActions.find({}).map((p) => p._id))

// prepare the message factories
for (const showStyle of state.contentCache.ShowStyleSourceLayers.find({})) {
const blueprint = state.contentCache.Blueprints.findOne(showStyle.blueprintId)
state.showStyleMessageFactories.set(showStyle._id, new PieceContentStatusMessageFactory(blueprint))
}
} else {
regenerateAdlibIds = new Set(updateProps.invalidateBucketAdlibIds)
regenerateActionIds = new Set(updateProps.invalidateBucketActionIds)
Expand All @@ -227,13 +253,15 @@ async function manipulateUIBucketContentStatusesPublicationData(
state.contentCache,
state.studio,
state.adlibDependencies,
state.showStyleMessageFactories,
collection,
regenerateAdlibIds
)
await regenerateForBucketActionIds(
state.contentCache,
state.studio,
state.actionDependencies,
state.showStyleMessageFactories,
collection,
regenerateActionIds
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BucketAdLibActionId, BucketAdLibId } from '@sofie-automation/corelib/dist/dataModel/Ids'
import { BucketAdLibActionId, BucketAdLibId, ShowStyleBaseId } from '@sofie-automation/corelib/dist/dataModel/Ids'
import { ReadonlyDeep } from 'type-fest'
import { UIBucketContentStatus } from '@sofie-automation/meteor-lib/dist/api/rundownNotifications'
import { literal, protectString } from '../../../lib/tempLib'
Expand All @@ -11,6 +11,7 @@ import {
PieceContentStatusPiece,
PieceContentStatusStudio,
} from '../checkPieceContentStatus'
import type { PieceContentStatusMessageFactory } from '../messageFactory'

/**
* Regenerating the status for the provided AdLibActionId
Expand All @@ -20,6 +21,7 @@ export async function regenerateForBucketAdLibIds(
contentCache: ReadonlyDeep<BucketContentCache>,
uiStudio: PieceContentStatusStudio,
dependenciesState: Map<BucketAdLibId, PieceDependencies>,
messageFactories: Map<ShowStyleBaseId, PieceContentStatusMessageFactory>,
collection: CustomPublishCollection<UIBucketContentStatus>,
regenerateIds: Set<BucketAdLibId>
): Promise<void> {
Expand All @@ -45,6 +47,7 @@ export async function regenerateForBucketAdLibIds(
if (sourceLayer) {
const [status, itemDependencies] = await checkPieceContentStatusAndDependencies(
uiStudio,
messageFactories.get(actionDoc.showStyleBaseId),
actionDoc,
sourceLayer
)
Expand Down Expand Up @@ -79,6 +82,7 @@ export async function regenerateForBucketActionIds(
contentCache: ReadonlyDeep<BucketContentCache>,
uiStudio: PieceContentStatusStudio,
dependenciesState: Map<BucketAdLibActionId, PieceDependencies>,
messageFactories: Map<ShowStyleBaseId, PieceContentStatusMessageFactory>,
collection: CustomPublishCollection<UIBucketContentStatus>,
regenerateIds: Set<BucketAdLibActionId>
): Promise<void> {
Expand Down Expand Up @@ -106,11 +110,16 @@ export async function regenerateForBucketActionIds(
const fakedPiece = literal<PieceContentStatusPiece>({
_id: protectString(`${actionDoc._id}`),
content: 'content' in actionDoc.display ? actionDoc.display.content : {},
name:
typeof actionDoc.display.label === 'string'
? actionDoc.display.label
: actionDoc.display.label.key,
expectedPackages: actionDoc.expectedPackages,
})

const [status, itemDependencies] = await checkPieceContentStatusAndDependencies(
uiStudio,
messageFactories.get(actionDoc.showStyleBaseId),
fakedPiece,
sourceLayer
)
Expand Down
Loading

0 comments on commit 51d2ddf

Please sign in to comment.