Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions DEVELOPER.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ However, one usage by AdlibActions for their userDataManifest remains as this is
In R49, a replacement flow was added consisting of `validateConfig` and `applyConfig`.
It is no longer recommended to use the old migrations flow for showstyle and studio blueprints.

## Blueprint Migrations

In R52, the replacement flow of `validateConfig` and `applyConfig` was extended to the system blueprint
It is no longer recommended to use the old migrations flow for system blueprints.

### ExpectedMediaItems

These are used for Media-manager which is no longer being developed.
Expand Down
4 changes: 2 additions & 2 deletions meteor/__mocks__/defaultCollectionObjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,15 @@ export function defaultStudio(_id: StudioId): DBStudio {
mappingsWithOverrides: wrapDefaultObject({}),
supportedShowStyleBase: [],
blueprintConfigWithOverrides: wrapDefaultObject({}),
settings: {
settingsWithOverrides: wrapDefaultObject({
frameRate: 25,
mediaPreviewsUrl: '',
minimumTakeSpan: DEFAULT_MINIMUM_TAKE_SPAN,
fallbackPartDuration: DEFAULT_FALLBACK_PART_DURATION,
allowHold: false,
allowPieceDirectPlay: false,
enableBuckets: false,
},
}),
_rundownVersionHash: '',
routeSetsWithOverrides: wrapDefaultObject({}),
routeSetExclusivityGroupsWithOverrides: wrapDefaultObject({}),
Expand Down
19 changes: 19 additions & 0 deletions meteor/__mocks__/helpers/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,25 @@ export async function setupMockCore(doc?: Partial<ICoreSystem>): Promise<ICoreSy
version: '0.0.0',
previousVersion: '0.0.0',
serviceMessages: {},
settingsWithOverrides: wrapDefaultObject({
cron: {
casparCGRestart: {
enabled: true,
},
storeRundownSnapshots: {
enabled: false,
},
},
support: {
message: '',
},
evaluationsMessage: {
enabled: false,
heading: '',
message: '',
},
}),
lastBlueprintConfig: undefined,
}
const coreSystem = _.extend(defaultCore, doc)
await CoreSystem.removeAsync(SYSTEM_ID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '@sofie-automation/meteor-lib/dist/collections/CoreSystem'
import { CoreSystem } from '../../../collections'
import { SupressLogMessages } from '../../../../__mocks__/suppressLogging'
import { wrapDefaultObject } from '@sofie-automation/corelib/dist/settings/objectWithOverrides'

function convertExternalToServiceMessage(message: ExternalServiceMessage): ServiceMessage {
return {
Expand Down Expand Up @@ -42,6 +43,8 @@ const fakeCoreSystem: ICoreSystem = {
version: '3',
previousVersion: null,
serviceMessages: {},
settingsWithOverrides: wrapDefaultObject({} as any),
lastBlueprintConfig: undefined,
}

describe('Service messages internal API', () => {
Expand Down
38 changes: 20 additions & 18 deletions meteor/server/__tests__/cronjobs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import '../../__mocks__/_extendJest'
import { testInFiber, runAllTimers, beforeAllInFiber, waitUntil } from '../../__mocks__/helpers/jest'
import { MeteorMock } from '../../__mocks__/meteor'
import { logger } from '../logging'
import { getRandomId, getRandomString, protectString } from '../lib/tempLib'
import { getRandomId, getRandomString, literal, protectString } from '../lib/tempLib'
import { SnapshotType } from '@sofie-automation/meteor-lib/dist/collections/Snapshots'
import { IBlueprintPieceType, PieceLifespan, StatusCode, TSR } from '@sofie-automation/blueprints-integration'
import {
Expand Down Expand Up @@ -64,26 +64,36 @@ import {
import { DBSegment } from '@sofie-automation/corelib/dist/dataModel/Segment'
import { Settings } from '../Settings'
import { SofieIngestCacheType } from '@sofie-automation/corelib/dist/dataModel/SofieIngestDataCache'
import { ObjectOverrideSetOp } from '@sofie-automation/corelib/dist/settings/objectWithOverrides'

describe('cronjobs', () => {
let env: DefaultEnvironment
let rundownId: RundownId

beforeAllInFiber(async () => {
env = await setupDefaultStudioEnvironment()

const o = await setupDefaultRundownPlaylist(env)
rundownId = o.rundownId

async function setCasparCGCronEnabled(enabled: boolean) {
await CoreSystem.updateAsync(
{},
{
$set: {
'cron.casparCGRestart.enabled': true,
// This is a little bit of a hack, as it will result in duplicate ops, but it's fine for unit tests
$push: {
'settingsWithOverrides.overrides': literal<ObjectOverrideSetOp>({
op: 'set',
path: 'cron.casparCGRestart.enabled',
value: enabled,
}),
},
},
{ multi: true }
)
}

beforeAllInFiber(async () => {
env = await setupDefaultStudioEnvironment()

const o = await setupDefaultRundownPlaylist(env)
rundownId = o.rundownId

await setCasparCGCronEnabled(true)

jest.useFakeTimers()
// set time to 2020/07/19 00:00 Local Time
Expand Down Expand Up @@ -589,15 +599,7 @@ describe('cronjobs', () => {
})
testInFiber('Does not attempt to restart CasparCG when job is disabled', async () => {
await createMockPlayoutGatewayAndDevices(Date.now()) // Some time after the threshold
await CoreSystem.updateAsync(
{},
{
$set: {
'cron.casparCGRestart.enabled': false,
},
},
{ multi: true }
)
await setCasparCGCronEnabled(false)
;(logger.info as jest.Mock).mockClear()
// set time to 2020/07/{date} 04:05 Local Time, should be more than 24 hours after 2020/07/19 00:00 UTC
mockCurrentTime = new Date(2020, 6, date++, 4, 5, 0).getTime()
Expand Down
4 changes: 3 additions & 1 deletion meteor/server/api/evaluations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import { OrganizationId, UserId } from '@sofie-automation/corelib/dist/dataModel/Ids'
import { DBRundownPlaylist } from '@sofie-automation/corelib/dist/dataModel/RundownPlaylist'
import { Evaluations, RundownPlaylists } from '../collections'
import { applyAndValidateOverrides } from '@sofie-automation/corelib/dist/settings/objectWithOverrides'

export async function saveEvaluation(
credentials: {
Expand All @@ -33,8 +34,9 @@
deferAsync(async () => {
const studio = await fetchStudioLight(evaluation.studioId)
if (!studio) throw new Meteor.Error(500, `Studio ${evaluation.studioId} not found!`)
const studioSettings = applyAndValidateOverrides(studio.settingsWithOverrides).obj

Check warning on line 37 in meteor/server/api/evaluations.ts

View check run for this annotation

Codecov / codecov/patch

meteor/server/api/evaluations.ts#L37

Added line #L37 was not covered by tests

const webhookUrls = _.compact((studio.settings.slackEvaluationUrls || '').split(','))
const webhookUrls = _.compact((studioSettings.slackEvaluationUrls || '').split(','))

Check warning on line 39 in meteor/server/api/evaluations.ts

View check run for this annotation

Codecov / codecov/patch

meteor/server/api/evaluations.ts#L39

Added line #L39 was not covered by tests

if (webhookUrls.length) {
// Only send notes if not everything is OK
Expand Down
10 changes: 7 additions & 3 deletions meteor/server/api/rest/v1/typeConversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
DEFAULT_FALLBACK_PART_DURATION,
} from '@sofie-automation/shared-lib/dist/core/constants'
import { Bucket } from '@sofie-automation/meteor-lib/dist/collections/Buckets'
import { ForceQuickLoopAutoNext } from '@sofie-automation/corelib/dist/dataModel/RundownPlaylist'
import { ForceQuickLoopAutoNext } from '@sofie-automation/shared-lib/dist/core/model/StudioSettings'

Check warning on line 56 in meteor/server/api/rest/v1/typeConversion.ts

View check run for this annotation

Codecov / codecov/patch

meteor/server/api/rest/v1/typeConversion.ts#L56

Added line #L56 was not covered by tests

/*
This file contains functions that convert between the internal Sofie-Core types and types exposed to the external API.
Expand Down Expand Up @@ -307,13 +307,17 @@
: convertObjectIntoOverrides(await StudioBlueprintConfigFromAPI(apiStudio, blueprintManifest))
}

const studioSettings = studioSettingsFrom(apiStudio.settings)

Check warning on line 311 in meteor/server/api/rest/v1/typeConversion.ts

View check run for this annotation

Codecov / codecov/patch

meteor/server/api/rest/v1/typeConversion.ts#L310-L311

Added lines #L310 - L311 were not covered by tests
return {
_id: existingId ?? getRandomId(),
name: apiStudio.name,
blueprintId: blueprint?._id,
blueprintConfigPresetId: apiStudio.blueprintConfigPresetId,
blueprintConfigWithOverrides: blueprintConfig,
settings: studioSettingsFrom(apiStudio.settings),
settingsWithOverrides: studio
? updateOverrides(studio.settingsWithOverrides, studioSettings)
: wrapDefaultObject(studioSettings),

Check warning on line 320 in meteor/server/api/rest/v1/typeConversion.ts

View check run for this annotation

Codecov / codecov/patch

meteor/server/api/rest/v1/typeConversion.ts#L318-L320

Added lines #L318 - L320 were not covered by tests
supportedShowStyleBase: apiStudio.supportedShowStyleBase?.map((id) => protectString<ShowStyleBaseId>(id)) ?? [],
organizationId: null,
mappingsWithOverrides: wrapDefaultObject({}),
Expand All @@ -334,7 +338,7 @@
}

export async function APIStudioFrom(studio: DBStudio): Promise<Complete<APIStudio>> {
const studioSettings = APIStudioSettingsFrom(studio.settings)
const studioSettings = APIStudioSettingsFrom(applyAndValidateOverrides(studio.settingsWithOverrides).obj)

Check warning on line 341 in meteor/server/api/rest/v1/typeConversion.ts

View check run for this annotation

Codecov / codecov/patch

meteor/server/api/rest/v1/typeConversion.ts#L341

Added line #L341 was not covered by tests

return {
name: studio.name,
Expand Down
4 changes: 2 additions & 2 deletions meteor/server/api/studio/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@
supportedShowStyleBase: [],
blueprintConfigWithOverrides: wrapDefaultObject({}),
// testToolsConfig?: ITestToolsConfig
settings: {
settingsWithOverrides: wrapDefaultObject({

Check warning on line 47 in meteor/server/api/studio/api.ts

View check run for this annotation

Codecov / codecov/patch

meteor/server/api/studio/api.ts#L47

Added line #L47 was not covered by tests
frameRate: 25,
mediaPreviewsUrl: '',
minimumTakeSpan: DEFAULT_MINIMUM_TAKE_SPAN,
allowHold: false,
allowPieceDirectPlay: false,
enableBuckets: true,
},
}),

Check warning on line 54 in meteor/server/api/studio/api.ts

View check run for this annotation

Codecov / codecov/patch

meteor/server/api/studio/api.ts#L54

Added line #L54 was not covered by tests
_rundownVersionHash: '',
routeSetsWithOverrides: wrapDefaultObject({}),
routeSetExclusivityGroupsWithOverrides: wrapDefaultObject({}),
Expand Down
5 changes: 2 additions & 3 deletions meteor/server/collections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,13 @@
if (!access.update) return logNotAllowed('CoreSystem', access.reason)

return allowOnlyFields(doc, fields, [
'support',
'systemInfo',
'name',
'logLevel',
'apm',
'cron',
'logo',
'evaluations',
'blueprintId',
'settingsWithOverrides',

Check warning on line 76 in meteor/server/collections/index.ts

View check run for this annotation

Codecov / codecov/patch

meteor/server/collections/index.ts#L75-L76

Added lines #L75 - L76 were not covered by tests
])
},
})
Expand Down
25 changes: 20 additions & 5 deletions meteor/server/coreSystem/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import { getEnvLogLevel, logger, LogLevel, setLogLevel } from '../logging'
const PackageInfo = require('../../package.json')
import Agent from 'meteor/julusian:meteor-elastic-apm'
import { profiler } from '../api/profiler'
import { TMP_TSR_VERSION } from '@sofie-automation/blueprints-integration'
import { ICoreSystemSettings, TMP_TSR_VERSION } from '@sofie-automation/blueprints-integration'
import { getAbsolutePath } from '../lib'
import * as fs from 'fs/promises'
import path from 'path'
import { checkDatabaseVersions } from './checkDatabaseVersions'
import PLazy from 'p-lazy'
import { getCoreSystemAsync } from './collection'
import { wrapDefaultObject } from '@sofie-automation/corelib/dist/settings/objectWithOverrides'

export { PackageInfo }

Expand Down Expand Up @@ -60,11 +61,25 @@ async function initializeCoreSystem() {
enabled: false,
transactionSampleRate: -1,
},
cron: {
casparCGRestart: {
enabled: true,
settingsWithOverrides: wrapDefaultObject<ICoreSystemSettings>({
cron: {
casparCGRestart: {
enabled: true,
},
storeRundownSnapshots: {
enabled: false,
},
},
},
support: {
message: '',
},
evaluationsMessage: {
enabled: false,
heading: '',
message: '',
},
}),
lastBlueprintConfig: undefined,
})

if (!isRunningInJest()) {
Expand Down
21 changes: 12 additions & 9 deletions meteor/server/cronjobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ import { deferAsync, normalizeArrayToMap } from '@sofie-automation/corelib/dist/
import { getCoreSystemAsync } from './coreSystem/collection'
import { cleanupOldDataInner } from './api/cleanup'
import { CollectionCleanupResult } from '@sofie-automation/meteor-lib/dist/api/system'
import { ICoreSystem } from '@sofie-automation/meteor-lib/dist/collections/CoreSystem'
import { ICoreSystemSettings } from '@sofie-automation/shared-lib/dist/core/model/CoreSystemSettings'
import { executePeripheralDeviceFunctionWithCustomTimeout } from './api/peripheralDevice/executeFunction'
import {
interpollateTranslation,
isTranslatableMessage,
translateMessage,
} from '@sofie-automation/corelib/dist/TranslatableMessage'
import { applyAndValidateOverrides } from '@sofie-automation/corelib/dist/settings/objectWithOverrides'

const lowPrioFcn = (fcn: () => any) => {
// Do it at a random time in the future:
Expand All @@ -49,15 +50,17 @@ export async function nightlyCronjobInner(): Promise<void> {
logger.info('Nightly cronjob: starting...')
const system = await getCoreSystemAsync()

const systemSettings = system && applyAndValidateOverrides(system.settingsWithOverrides).obj

await Promise.allSettled([
cleanupOldDataCronjob().catch((error) => {
logger.error(`Cronjob: Error when cleaning up old data: ${stringifyError(error)}`)
logger.error(error)
}),
restartCasparCG(system, previousLastNightlyCronjob).catch((e) => {
restartCasparCG(systemSettings, previousLastNightlyCronjob).catch((e) => {
logger.error(`Cron: Restart CasparCG error: ${stringifyError(e)}`)
}),
storeSnapshots(system).catch((e) => {
storeSnapshots(systemSettings).catch((e) => {
logger.error(`Cron: Rundown Snapshots error: ${stringifyError(e)}`)
}),
])
Expand All @@ -81,8 +84,8 @@ async function cleanupOldDataCronjob() {

const CASPARCG_LAST_SEEN_PERIOD_MS = 3 * 60 * 1000 // Note: this must be higher than the ping interval used by playout-gateway

async function restartCasparCG(system: ICoreSystem | undefined, previousLastNightlyCronjob: number) {
if (!system?.cron?.casparCGRestart?.enabled) return
async function restartCasparCG(systemSettings: ICoreSystemSettings | undefined, previousLastNightlyCronjob: number) {
if (!systemSettings?.cron?.casparCGRestart?.enabled) return

let shouldRetryAttempt = false
const ps: Array<Promise<any>> = []
Expand Down Expand Up @@ -176,10 +179,10 @@ async function restartCasparCG(system: ICoreSystem | undefined, previousLastNigh
}
}

async function storeSnapshots(system: ICoreSystem | undefined) {
if (system?.cron?.storeRundownSnapshots?.enabled) {
const filter = system.cron.storeRundownSnapshots.rundownNames?.length
? { name: { $in: system.cron.storeRundownSnapshots.rundownNames } }
async function storeSnapshots(systemSettings: ICoreSystemSettings | undefined) {
if (systemSettings?.cron?.storeRundownSnapshots?.enabled) {
const filter = systemSettings.cron.storeRundownSnapshots.rundownNames?.length
? { name: { $in: systemSettings.cron.storeRundownSnapshots.rundownNames } }
: {}

const playlists = await RundownPlaylists.findFetchAsync(filter)
Expand Down
2 changes: 1 addition & 1 deletion meteor/server/logo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
const logo = core?.logo ?? SofieLogo.Default

const paths: Record<SofieLogo, string> = {
[SofieLogo.Default]: '/images/sofie-logo.svg',
[SofieLogo.Default]: '/images/sofie-logo-default.svg',

Check warning on line 16 in meteor/server/logo.ts

View check run for this annotation

Codecov / codecov/patch

meteor/server/logo.ts#L16

Added line #L16 was not covered by tests
[SofieLogo.Pride]: '/images/sofie-logo-pride.svg',
[SofieLogo.Norway]: '/images/sofie-logo-norway.svg',
[SofieLogo.Christmas]: '/images/sofie-logo-christmas.svg',
Expand Down
Loading
Loading