Skip to content

Commit

Permalink
feat: routeset config defined in blueprints
Browse files Browse the repository at this point in the history
  • Loading branch information
olzzon authored and Julusian committed Sep 27, 2024
1 parent 8c154af commit e839b97
Show file tree
Hide file tree
Showing 62 changed files with 1,970 additions and 1,224 deletions.
4 changes: 2 additions & 2 deletions meteor/__mocks__/defaultCollectionObjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ export function defaultStudio(_id: StudioId): DBStudio {
fallbackPartDuration: DEFAULT_FALLBACK_PART_DURATION,
},
_rundownVersionHash: '',
routeSets: {},
routeSetExclusivityGroups: {},
routeSetsWithOverrides: wrapDefaultObject({}),
routeSetExclusivityGroupsWithOverrides: wrapDefaultObject({}),
packageContainers: {},
previewContainerIds: [],
thumbnailContainerIds: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class StudioDeviceTriggerManager {
return
}

const context = createCurrentContextFromCache(cache)
const context = createCurrentContextFromCache(cache, studioId)
const actionManager = StudioActionManagers.get(studioId)
if (!actionManager)
throw new Meteor.Error(
Expand Down Expand Up @@ -271,7 +271,7 @@ function convertDocument(doc: ReadonlyObjectDeep<DBTriggeredActions>): UITrigger
})
}

function createCurrentContextFromCache(cache: ContentCache): ReactivePlaylistActionContext {
function createCurrentContextFromCache(cache: ContentCache, studioId: StudioId): ReactivePlaylistActionContext {
const rundownPlaylist = cache.RundownPlaylists.findOne({
activationId: {
$exists: true,
Expand Down Expand Up @@ -301,6 +301,7 @@ function createCurrentContextFromCache(cache: ContentCache): ReactivePlaylistAct
: []

return {
studioId: new DummyReactiveVar(studioId),
currentPartInstanceId: new DummyReactiveVar(currentPartInstance?._id ?? null),
currentPartId: new DummyReactiveVar(currentPartInstance?.part._id ?? null),
nextPartId: new DummyReactiveVar(nextPartInstance?.part._id ?? null),
Expand Down
1 change: 1 addition & 0 deletions meteor/server/api/deviceTriggers/triggersContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ function createContextForRundownPlaylistChain(
}

return {
studioId: new DummyReactiveVar(studioId),
rundownPlaylistId: new DummyReactiveVar(playlist?._id),
rundownPlaylist: new DummyReactiveVar(playlist),
currentRundownId: new DummyReactiveVar(currentPartInstance?.rundownId ?? playlist.rundownIdsInOrder[0] ?? null),
Expand Down
5 changes: 2 additions & 3 deletions meteor/server/api/ingest/mosDevice/actions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { MOS } from '@sofie-automation/corelib'
import { logger } from '../../../logging'
import { Rundown } from '@sofie-automation/corelib/dist/dataModel/Rundown'
import { Meteor } from 'meteor/meteor'
Expand All @@ -13,7 +12,7 @@ import { generateRundownSource, getPeripheralDeviceFromRundown, runIngestOperati
import { IngestJobs } from '@sofie-automation/corelib/dist/worker/ingest'
import { DEFAULT_MOS_TIMEOUT_TIME } from '@sofie-automation/shared-lib/dist/core/constants'
import { executePeripheralDeviceFunctionWithCustomTimeout } from '../../peripheralDevice/executeFunction'
import { getMosTypes } from '@mos-connection/helper'
import { MOS } from '@sofie-automation/meteor-lib/dist/mos'

export namespace MOSDeviceActions {
export async function reloadRundown(
Expand Down Expand Up @@ -73,7 +72,7 @@ export namespace MOSDeviceActions {
if (!mosPayload.Body)
throw new Meteor.Error(500, `Part Cache for "${partCache.externalId}" missing FullStory content!`)

const mosTypes = getMosTypes(false)
const mosTypes = MOS.getMosTypes(false)

const story = mosPayload.Body.find(
(item) =>
Expand Down
38 changes: 8 additions & 30 deletions meteor/server/api/playout/playout.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
/* tslint:disable:no-use-before-declare */
import { Meteor } from 'meteor/meteor'
import * as _ from 'underscore'
import { StudioRouteBehavior } from '@sofie-automation/corelib/dist/dataModel/Studio'
import { PackageInfo } from '../../coreSystem'
import { StudioContentAccess } from '../../security/studio'
import { shouldUpdateStudioBaselineInner } from '@sofie-automation/corelib/dist/studio/baseline'
import { logger } from '../../logging'
import { Blueprints, RundownPlaylists, Studios, Timeline } from '../../collections'
import { Blueprints, RundownPlaylists, Timeline } from '../../collections'
import { StudioJobs } from '@sofie-automation/corelib/dist/worker/studio'
import { QueueStudioJob } from '../../worker/worker'

export namespace ServerPlayoutAPI {
export async function shouldUpdateStudioBaseline(access: StudioContentAccess): Promise<string | false> {
Expand Down Expand Up @@ -38,32 +36,12 @@ export namespace ServerPlayoutAPI {
export async function switchRouteSet(
access: StudioContentAccess,
routeSetId: string,
state: boolean
state: boolean | 'toggle'
): Promise<void> {
logger.debug(`switchRouteSet "${access.studioId}" "${routeSetId}"=${state}`)

const studio = access.studio

if (studio.routeSets[routeSetId] === undefined)
throw new Meteor.Error(404, `RouteSet "${routeSetId}" not found!`)
const routeSet = studio.routeSets[routeSetId]
if (routeSet.behavior === StudioRouteBehavior.ACTIVATE_ONLY && state === false)
throw new Meteor.Error(400, `RouteSet "${routeSetId}" is ACTIVATE_ONLY`)

const modification: Record<string, any> = {}
modification[`routeSets.${routeSetId}.active`] = state

if (studio.routeSets[routeSetId].exclusivityGroup && state === true) {
_.each(studio.routeSets, (otherRouteSet, otherRouteSetId) => {
if (otherRouteSetId === routeSetId) return
if (otherRouteSet.exclusivityGroup === routeSet.exclusivityGroup) {
modification[`routeSets.${otherRouteSetId}.active`] = false
}
})
}

await Studios.updateAsync(studio._id, {
$set: modification,
const queuedJob = await QueueStudioJob(StudioJobs.SwitchRouteSet, access.studioId, {
routeSetId,
state,
})
await queuedJob.complete
}
}
4 changes: 2 additions & 2 deletions meteor/server/api/rest/v1/typeConversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,9 @@ export async function studioFrom(apiStudio: APIStudio, existingId?: StudioId): P
supportedShowStyleBase: apiStudio.supportedShowStyleBase?.map((id) => protectString<ShowStyleBaseId>(id)) ?? [],
organizationId: null,
mappingsWithOverrides: wrapDefaultObject({}),
routeSets: {},
routeSetsWithOverrides: wrapDefaultObject({}),
_rundownVersionHash: '',
routeSetExclusivityGroups: {},
routeSetExclusivityGroupsWithOverrides: wrapDefaultObject({}),
packageContainers: {},
previewContainerIds: [],
thumbnailContainerIds: [],
Expand Down
6 changes: 3 additions & 3 deletions meteor/server/api/studio/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ export async function insertStudioInner(organizationId: OrganizationId | null, n
minimumTakeSpan: DEFAULT_MINIMUM_TAKE_SPAN,
},
_rundownVersionHash: '',
routeSets: {},
routeSetExclusivityGroups: {},
routeSetsWithOverrides: wrapDefaultObject({}),
routeSetExclusivityGroupsWithOverrides: wrapDefaultObject({}),
packageContainers: {},
thumbnailContainerIds: [],
previewContainerIds: [],
Expand Down Expand Up @@ -141,7 +141,7 @@ Studios.observeChanges(
{
fields: {
mappingsWithOverrides: 1,
routeSets: 1,
routeSetsWithOverrides: 1,
},
}
)
2 changes: 1 addition & 1 deletion meteor/server/api/userActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,7 @@ class ServerUserActionAPI
eventTime: Time,
studioId: StudioId,
routeSetId: string,
state: boolean
state: boolean | 'toggle'
): Promise<ClientAPI.ClientResponse<void>> {
return ServerClientAPI.runUserActionInLog(
this,
Expand Down
4 changes: 2 additions & 2 deletions meteor/server/migration/0_1_0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,8 @@ export const addSteps = addMigrationSteps('0.1.0', [
mappingsWithOverrides: wrapDefaultObject({}),
blueprintConfigWithOverrides: wrapDefaultObject({}),
_rundownVersionHash: '',
routeSets: {},
routeSetExclusivityGroups: {},
routeSetsWithOverrides: wrapDefaultObject({}),
routeSetExclusivityGroupsWithOverrides: wrapDefaultObject({}),
packageContainers: {},
thumbnailContainerIds: [],
previewContainerIds: [],
Expand Down
15 changes: 14 additions & 1 deletion meteor/server/migration/1_42_0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ export const addSteps = addMigrationSteps('1.42.0', [
id: 'Add new routeType property to routeSets where missing',
canBeRunAutomatically: true,
validate: async () => {
// If routeSets has been converted to ObjectWithOverrides,
// it will have a defaults property, and shouln't be migrated
if (
(await Studios.countDocuments({
routeSetsWithOverrides: { $exists: true },
})) > 0
) {
return false
}
return (
(await Studios.countDocuments({
routeSets: { $exists: false },
Expand All @@ -19,8 +28,12 @@ export const addSteps = addMigrationSteps('1.42.0', [
const studios = await Studios.findFetchAsync({})

for (const studio of studios) {
const routeSets = studio.routeSets
// If routeSets has been converted to ObjectWithOverrides,
// it will have a defaults property, and shouln't be migrated
if (studio.routeSetsWithOverrides) return

//@ts-expect-error routeSets is not typed as ObjectWithOverrides
const routeSets = studio.routeSets as any as Record<string, StudioRouteSet>
Object.entries<StudioRouteSet>(routeSets).forEach(([routeSetId, routeSet]) => {
routeSet.routes.forEach((route) => {
if (!route.routeType) {
Expand Down
22 changes: 15 additions & 7 deletions meteor/server/migration/1_50_0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ function convertMappingsOverrideOps(studio: DBStudio) {
return changed && newOverrides
}

function convertRouteSetMappings(studio: DBStudio) {
function convertRouteSetMappings(routeSets: Record<string, StudioRouteSet>) {
let changed = false

const newRouteSets = clone(studio.routeSets || {})
const newRouteSets = clone(routeSets || {})
for (const routeSet of Object.values<StudioRouteSet>(newRouteSets)) {
for (const route of routeSet.routes) {
if (route.remapping && !route.remapping.options) {
Expand All @@ -95,7 +95,7 @@ function convertRouteSetMappings(studio: DBStudio) {
..._.pick(route.remapping, ...mappingBaseOptions),
options: _.omit(route.remapping, ...mappingBaseOptions),
}
console.log('new route', route)
// console.log('new route', route)
changed = true
}
}
Expand Down Expand Up @@ -247,10 +247,13 @@ export const addSteps = addMigrationSteps('1.50.0', [
canBeRunAutomatically: true,
validate: async () => {
const studios = await Studios.findFetchAsync({ routeSets: { $exists: true } })

for (const studio of studios) {
const newOverrides = convertRouteSetMappings(studio)
if (newOverrides) {
// Ignore this if the routeSets has been converted into an OverrideWithObjects:
if (studio.routeSetsWithOverrides) continue
//@ts-expect-error routeSets are not part of the typings:
const plainRouteSets = studio.routeSets as any as Record<string, StudioRouteSet>
const newRouteSets = convertRouteSetMappings(plainRouteSets)
if (newRouteSets) {
return `object needs to be updated`
}
}
Expand All @@ -261,7 +264,12 @@ export const addSteps = addMigrationSteps('1.50.0', [
const studios = await Studios.findFetchAsync({ routeSets: { $exists: true } })

for (const studio of studios) {
const newRouteSets = convertRouteSetMappings(studio)
// Ignore this if the routeSets already has been converted into an OverrideWithObjects:
if (studio.routeSetsWithOverrides) continue
//@ts-expect-error routeSets are not part of the typings:
const plainRouteSets = studio.routeSets as any as Record<string, StudioRouteSet>

const newRouteSets = convertRouteSetMappings(plainRouteSets)

if (newRouteSets) {
await Studios.updateAsync(studio._id, {
Expand Down
81 changes: 80 additions & 1 deletion meteor/server/migration/X_X_X.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { addMigrationSteps } from './databaseMigration'
import { CURRENT_SYSTEM_VERSION } from './currentSystemVersion'
import { Studios } from '../collections'
import { convertObjectIntoOverrides } from '@sofie-automation/corelib/dist/settings/objectWithOverrides'
import { StudioRouteSet, StudioRouteSetExclusivityGroup } from '@sofie-automation/corelib/dist/dataModel/Studio'

/*
* **************************************************************************************
Expand All @@ -12,5 +15,81 @@ import { CURRENT_SYSTEM_VERSION } from './currentSystemVersion'
*/

export const addSteps = addMigrationSteps(CURRENT_SYSTEM_VERSION, [
// Add some migrations here:
{
id: `convert routesets to ObjectWithOverrides`,
canBeRunAutomatically: true,
validate: async () => {
const studios = await Studios.findFetchAsync({ routeSets: { $exists: true } })

for (const studio of studios) {
//@ts-expect-error routeSets is not typed as ObjectWithOverrides
if (studio.routeSets) {
return 'routesets must be converted to an ObjectWithOverrides'
}
}

return false
},
migrate: async () => {
const studios = await Studios.findFetchAsync({ routeSets: { $exists: true } })

for (const studio of studios) {
//@ts-expect-error routeSets is not typed as ObjectWithOverrides
if (!studio.routeSets) continue
//@ts-expect-error routeSets is not typed as ObjectWithOverrides
const oldRouteSets = studio.routeSets as any as Record<string, StudioRouteSet>

const newRouteSets = convertObjectIntoOverrides(oldRouteSets)

await Studios.updateAsync(studio._id, {
$set: {
routeSetsWithOverrides: newRouteSets,
},
$unset: {
routeSets: 1,
},
})
}
},
},
{
id: `convert routeSetExclusivityGroups to ObjectWithOverrides`,
canBeRunAutomatically: true,
validate: async () => {
const studios = await Studios.findFetchAsync({ routeSetExclusivityGroups: { $exists: true } })

for (const studio of studios) {
//@ts-expect-error routeSetExclusivityGroups is not typed as ObjectWithOverrides
if (studio.routeSetExclusivityGroups) {
return 'routesets must be converted to an ObjectWithOverrides'
}
}

return false
},
migrate: async () => {
const studios = await Studios.findFetchAsync({ routeSetExclusivityGroups: { $exists: true } })

for (const studio of studios) {
//@ts-expect-error routeSetExclusivityGroups is not typed as ObjectWithOverrides
if (!studio.routeSetExclusivityGroups) return
//@ts-expect-error routeSetExclusivityGroups is not typed as ObjectWithOverrides
const oldRouteSetExclusivityGroups = studio.routeSetExclusivityGroups as any as Record<
string,
StudioRouteSetExclusivityGroup
>

const newRouteSetExclusivityGroups = convertObjectIntoOverrides(oldRouteSetExclusivityGroups)

await Studios.updateAsync(studio._id, {
$set: {
routeSetExclusivityGroupsWithOverrides: newRouteSetExclusivityGroups,
},
$unset: {
routeSetExclusivityGroups: 1,
},
})
}
},
},
])
12 changes: 6 additions & 6 deletions meteor/server/migration/__tests__/migrations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ describe('Migrations', () => {
mappingsWithOverrides: wrapDefaultObject({}),
blueprintConfigWithOverrides: wrapDefaultObject({}),
_rundownVersionHash: '',
routeSets: {},
routeSetExclusivityGroups: {},
routeSetsWithOverrides: wrapDefaultObject({}),
routeSetExclusivityGroupsWithOverrides: wrapDefaultObject({}),
packageContainers: {},
previewContainerIds: [],
thumbnailContainerIds: [],
Expand Down Expand Up @@ -168,8 +168,8 @@ describe('Migrations', () => {
mappingsWithOverrides: wrapDefaultObject({}),
blueprintConfigWithOverrides: wrapDefaultObject({}),
_rundownVersionHash: '',
routeSets: {},
routeSetExclusivityGroups: {},
routeSetsWithOverrides: wrapDefaultObject({}),
routeSetExclusivityGroupsWithOverrides: wrapDefaultObject({}),
packageContainers: {},
previewContainerIds: [],
thumbnailContainerIds: [],
Expand Down Expand Up @@ -206,8 +206,8 @@ describe('Migrations', () => {
mappingsWithOverrides: wrapDefaultObject({}),
blueprintConfigWithOverrides: wrapDefaultObject({}),
_rundownVersionHash: '',
routeSets: {},
routeSetExclusivityGroups: {},
routeSetsWithOverrides: wrapDefaultObject({}),
routeSetExclusivityGroupsWithOverrides: wrapDefaultObject({}),
packageContainers: {},
previewContainerIds: [],
thumbnailContainerIds: [],
Expand Down
Loading

0 comments on commit e839b97

Please sign in to comment.