diff --git a/packages/mos-gateway/src/connector.ts b/packages/mos-gateway/src/connector.ts index 82ccb6f035..6f39dc7a1c 100644 --- a/packages/mos-gateway/src/connector.ts +++ b/packages/mos-gateway/src/connector.ts @@ -5,6 +5,10 @@ import { PeripheralDeviceId, loadCertificatesFromDisk, CertificatesConfig, + stringifyError, + HealthConfig, + HealthEndpoints, + IConnector, } from '@sofie-automation/server-core-integration' export interface Config { @@ -12,12 +16,16 @@ export interface Config { device: DeviceConfig core: CoreConfig mos: MosConfig + health: HealthConfig } export interface DeviceConfig { deviceId: PeripheralDeviceId deviceToken: string } -export class Connector { +export class Connector implements IConnector { + public initialized = false + public initializedError: string | undefined = undefined + private mosHandler: MosHandler | undefined private coreHandler: CoreHandler | undefined private _config: Config | undefined @@ -38,11 +46,18 @@ export class Connector { this._logger.info('Initializing Core...') await this.initCore(certificates) + if (!this.coreHandler) throw Error('coreHandler is undefined!') + + new HealthEndpoints(this, this.coreHandler, config.health) + this._logger.info('Initializing Mos...') await this.initMos() this._logger.info('Initialization done') + this.initialized = true } catch (e: any) { + this.initializedError = stringifyError(e) + this._logger.error('Error during initialization:', e, e.stack) this._logger.info('Shutting down in 10 seconds!') diff --git a/packages/mos-gateway/src/coreHandler.ts b/packages/mos-gateway/src/coreHandler.ts index 8111a2e4ba..0a7179e88b 100644 --- a/packages/mos-gateway/src/coreHandler.ts +++ b/packages/mos-gateway/src/coreHandler.ts @@ -10,6 +10,7 @@ import { stringifyError, PeripheralDevicePubSub, PeripheralDevicePubSubCollectionsNames, + ICoreHandler, } from '@sofie-automation/server-core-integration' import * as Winston from 'winston' @@ -29,14 +30,16 @@ export interface CoreConfig { /** * Represents a connection between mos-integration and Core */ -export class CoreHandler { +export class CoreHandler implements ICoreHandler { core: CoreConnection | undefined logger: Winston.Logger public _observers: Array> = [] + public connectedToCore = false private _deviceOptions: DeviceConfig private _coreMosHandlers: Array = [] private _onConnected?: () => any private _isInitialized = false + private _isDestroyed = false private _executedFunctions = new Set() private _coreConfig?: CoreConfig private _certificates?: Buffer[] @@ -54,10 +57,12 @@ export class CoreHandler { this.core.onConnected(() => { this.logger.info('Core Connected!') + this.connectedToCore = true if (this._isInitialized) this.onConnectionRestored() }) this.core.onDisconnected(() => { this.logger.info('Core Disconnected!') + this.connectedToCore = false }) this.core.onError((err) => { this.logger.error('Core Error: ' + (typeof err === 'string' ? err : err.message || err.toString())) @@ -74,31 +79,45 @@ export class CoreHandler { } await this.core.init(ddpConfig) - if (!this.core) { - throw Error('core is undefined!') - } - - this.core - .setStatus({ - statusCode: StatusCode.GOOD, - // messages: [] - }) - .catch((e) => this.logger.warn('Error when setting status:' + e)) - // nothing - await this.setupSubscriptionsAndObservers() this._isInitialized = true + + await this.updateCoreStatus() } + getCoreStatus(): { + statusCode: StatusCode + messages: string[] + } { + let statusCode = StatusCode.GOOD + const messages: string[] = [] + + if (!this._isInitialized) { + statusCode = StatusCode.BAD + messages.push('Starting up...') + } + if (this._isDestroyed) { + statusCode = StatusCode.FATAL + messages.push('Shut down') + } + return { + statusCode, + messages, + } + } + async updateCoreStatus(): Promise { + if (!this.core) throw Error('core is undefined!') + + await this.core.setStatus(this.getCoreStatus()) + } + async dispose(): Promise { + this._isDestroyed = true if (!this.core) { throw Error('core is undefined!') } - await this.core.setStatus({ - statusCode: StatusCode.FATAL, - messages: ['Shutting down'], - }) + await this.updateCoreStatus() await Promise.all( this._coreMosHandlers.map(async (cmh: CoreMosDeviceHandler) => { diff --git a/packages/mos-gateway/src/index.ts b/packages/mos-gateway/src/index.ts index ae2cb9547b..ced998eb48 100644 --- a/packages/mos-gateway/src/index.ts +++ b/packages/mos-gateway/src/index.ts @@ -14,6 +14,7 @@ let deviceToken: string = process.env.DEVICE_TOKEN || '' let disableWatchdog: boolean = process.env.DISABLE_WATCHDOG === '1' || false let unsafeSSL: boolean = process.env.UNSAFE_SSL === '1' || false const certs: string[] = (process.env.CERTIFICATES || '').split(';') || [] +let healthPort: number | undefined = parseInt(process.env.HEALTH_PORT + '') || undefined let debug = false let printHelp = false @@ -46,6 +47,8 @@ process.argv.forEach((val) => { } else if (val.match(/-unsafeSSL/i)) { // Will cause the Node applocation to blindly accept all certificates. Not recommenced unless in local, controlled networks. unsafeSSL = true + } else if (prevProcessArg.match(/-healthPort/i)) { + healthPort = parseInt(val) } prevProcessArg = nextPrevProcessArg + '' }) @@ -207,6 +210,9 @@ const config: Config = { port: port, watchdog: !disableWatchdog, }, + health: { + port: healthPort, + }, mos: { self: { debug: debug, diff --git a/packages/playout-gateway/src/connector.ts b/packages/playout-gateway/src/connector.ts index bf1195634b..f5a574f02a 100644 --- a/packages/playout-gateway/src/connector.ts +++ b/packages/playout-gateway/src/connector.ts @@ -7,8 +7,10 @@ import { PeripheralDeviceId, loadCertificatesFromDisk, stringifyError, + HealthConfig, + HealthEndpoints, + IConnector, } from '@sofie-automation/server-core-integration' -import { HealthConfig, HealthEndpoints } from './health' export interface Config { certificates: CertificatesConfig @@ -23,7 +25,7 @@ export interface DeviceConfig { deviceId: PeripheralDeviceId deviceToken: string } -export class Connector { +export class Connector implements IConnector { public initialized = false public initializedError: string | undefined = undefined diff --git a/packages/playout-gateway/src/coreHandler.ts b/packages/playout-gateway/src/coreHandler.ts index 599a432cff..a452f5edc9 100644 --- a/packages/playout-gateway/src/coreHandler.ts +++ b/packages/playout-gateway/src/coreHandler.ts @@ -11,6 +11,7 @@ import { stringifyError, PeripheralDevicePubSub, PeripheralDevicePubSubCollectionsNames, + ICoreHandler, } from '@sofie-automation/server-core-integration' import { MediaObject, DeviceOptionsAny, ActionExecutionResult } from 'timeline-state-resolver' import * as _ from 'underscore' @@ -40,7 +41,7 @@ export interface MemoryUsageReport { /** * Represents a connection between the Gateway and Core */ -export class CoreHandler { +export class CoreHandler implements ICoreHandler { core!: CoreConnection logger: Logger public _observers: Array> = [] diff --git a/packages/server-core-integration/package.json b/packages/server-core-integration/package.json index 2d09a2ab9e..c098507b25 100644 --- a/packages/server-core-integration/package.json +++ b/packages/server-core-integration/package.json @@ -69,11 +69,17 @@ "rundown", "production" ], + "devDependencies": { + "@types/koa": "^3.0.0", + "@types/koa__router": "^12.0.4" + }, "dependencies": { + "@koa/router": "^14.0.0", "@sofie-automation/shared-lib": "1.52.9-nrk", "ejson": "^2.2.3", "faye-websocket": "^0.11.4", "got": "^11.8.6", + "koa": "^3.0.1", "tslib": "^2.8.1", "underscore": "^1.13.7" }, diff --git a/packages/server-core-integration/src/index.ts b/packages/server-core-integration/src/index.ts index 9666b98a8e..a6c867fe59 100644 --- a/packages/server-core-integration/src/index.ts +++ b/packages/server-core-integration/src/index.ts @@ -1,6 +1,8 @@ export * from './lib/coreConnection' export * from './lib/configManifest' export * from './lib/ddpClient' +export * from './lib/gateway-types' +export * from './lib/health' export * from './lib/methods' export * from './lib/process' export { SubscriptionId } from './lib/subscriptions' diff --git a/packages/server-core-integration/src/lib/gateway-types.ts b/packages/server-core-integration/src/lib/gateway-types.ts new file mode 100644 index 0000000000..e2745a6aa8 --- /dev/null +++ b/packages/server-core-integration/src/lib/gateway-types.ts @@ -0,0 +1,11 @@ +import { StatusCode } from '@sofie-automation/shared-lib/dist/lib/status' + +export interface IConnector { + initialized: boolean + initializedError: string | undefined +} + +export interface ICoreHandler { + getCoreStatus: () => { statusCode: StatusCode; messages: string[] } + connectedToCore: boolean +} diff --git a/packages/playout-gateway/src/health.ts b/packages/server-core-integration/src/lib/health.ts similarity index 85% rename from packages/playout-gateway/src/health.ts rename to packages/server-core-integration/src/lib/health.ts index d872f396af..f5e7d6ad01 100644 --- a/packages/playout-gateway/src/health.ts +++ b/packages/server-core-integration/src/lib/health.ts @@ -1,9 +1,8 @@ import * as Koa from 'koa' import * as Router from '@koa/router' -import { StatusCode } from 'timeline-state-resolver' -import { assertNever } from '@sofie-automation/server-core-integration' -import { CoreHandler } from './coreHandler' -import { Connector } from './connector' +import { StatusCode } from '@sofie-automation/shared-lib/dist/lib/status' +import { assertNever } from '@sofie-automation/shared-lib/dist/lib/lib' +import { IConnector, ICoreHandler } from './gateway-types' export interface HealthConfig { /** If set, exposes health HTTP endpoints on the given port */ @@ -16,7 +15,7 @@ export interface HealthConfig { */ export class HealthEndpoints { private app = new Koa() - constructor(private connector: Connector, private coreHandler: CoreHandler, private config: HealthConfig) { + constructor(private connector: IConnector, private coreHandler: ICoreHandler, private config: HealthConfig) { if (!config.port) return // disabled const router = new Router() diff --git a/packages/yarn.lock b/packages/yarn.lock index c15e67e1f8..31903816a5 100644 --- a/packages/yarn.lock +++ b/packages/yarn.lock @@ -6064,10 +6064,14 @@ __metadata: version: 0.0.0-use.local resolution: "@sofie-automation/server-core-integration@workspace:server-core-integration" dependencies: + "@koa/router": "npm:^14.0.0" "@sofie-automation/shared-lib": "npm:1.52.9-nrk" + "@types/koa": "npm:^3.0.0" + "@types/koa__router": "npm:^12.0.4" ejson: "npm:^2.2.3" faye-websocket: "npm:^0.11.4" got: "npm:^11.8.6" + koa: "npm:^3.0.1" tslib: "npm:^2.8.1" underscore: "npm:^1.13.7" languageName: unknown