@@ -20,6 +20,8 @@ import { registerRoutes as registerSystemRoutes } from './system'
20
20
import { registerRoutes as registerBucketsRoutes } from './buckets'
21
21
import { registerRoutes as registerSnapshotRoutes } from './snapshots'
22
22
import { APIFactory , ServerAPIContext } from './types'
23
+ import { getSystemStatus } from '../../../systemStatus/systemStatus'
24
+ import { Component , ExternalStatus } from '@sofie-automation/meteor-lib/dist/api/systemStatus'
23
25
24
26
function restAPIUserEvent (
25
27
ctx : Koa . ParameterizedContext <
@@ -193,6 +195,82 @@ koaRouter.get('/', async (ctx, next) => {
193
195
await next ( )
194
196
} )
195
197
198
+ koaRouter . get ( '/health' , async ( ctx , next ) => {
199
+ ctx . type = 'application/json'
200
+ const systemStatus = await getSystemStatus ( null )
201
+ const coreVersion = systemStatus . _internal . versions [ 'core' ] ?? 'unknown'
202
+ const blueprint = Object . keys ( systemStatus . _internal . versions ) . find ( ( component ) =>
203
+ component . startsWith ( 'blueprint' )
204
+ )
205
+ const blueprintsVersion = blueprint ? systemStatus . _internal . versions [ blueprint ] : 'unknown'
206
+
207
+ interface ComponentStatus {
208
+ name : string
209
+ updated : string
210
+ status : ExternalStatus
211
+ version ?: string
212
+ components ?: ComponentStatus [ ]
213
+ statusMessage ?: string
214
+ }
215
+
216
+ // Array of all devices that have a parentId
217
+ const subComponents =
218
+ systemStatus . components ?. filter ( ( c ) => c . instanceId !== undefined && c . parentId !== undefined ) ?? [ ]
219
+
220
+ function mapComponents ( components ?: Component [ ] ) : ComponentStatus [ ] | undefined {
221
+ return (
222
+ components ?. map ( ( c ) => {
223
+ const version = c . _internal . versions [ '_process' ]
224
+ const children = subComponents . filter ( ( sub ) => sub . parentId === c . instanceId )
225
+ return {
226
+ name : c . name ,
227
+ updated : c . updated ,
228
+ status : c . status ,
229
+ version : version ?? undefined ,
230
+ components : children . length ? mapComponents ( children ) : undefined ,
231
+ statusMessage : c . statusMessage ?. length ? c . statusMessage : undefined ,
232
+ }
233
+ } ) ?? undefined
234
+ )
235
+ }
236
+
237
+ // Patch the component statusMessage to be from the _internal field if required
238
+ const allComponentsPatched = systemStatus . components ?. map ( ( c ) => {
239
+ return {
240
+ ...c ,
241
+ statusMessage : c . statusMessage ?? ( c . status !== 'OK' ? c . _internal . messages . join ( ', ' ) : undefined ) ,
242
+ }
243
+ } )
244
+
245
+ // Report status for all devices that are not children and any non-devices that are not OK
246
+ const componentStatus =
247
+ mapComponents (
248
+ allComponentsPatched ?. filter (
249
+ ( c ) => ( c . instanceId !== undefined || c . status !== 'OK' ) && c . parentId === undefined
250
+ )
251
+ ) ?? [ ]
252
+
253
+ const allStatusMessages =
254
+ allComponentsPatched // include children by not using componentStatus here
255
+ ?. filter ( ( c ) => c . statusMessage !== undefined )
256
+ . map ( ( c ) => `${ c . name } : ${ c . statusMessage } ` )
257
+ . join ( '; ' ) ?? ''
258
+
259
+ const response = ClientAPI . responseSuccess ( {
260
+ name : systemStatus . name ,
261
+ updated : systemStatus . updated ,
262
+ status : systemStatus . status ,
263
+ version : coreVersion ,
264
+ blueprintsVersion : blueprintsVersion ,
265
+ components : componentStatus ,
266
+ statusMessage : allStatusMessages ,
267
+ } )
268
+
269
+ ctx . body = JSON . stringify ( { status : response . success , result : response . result } )
270
+ ctx . status = response . success
271
+ await next ( )
272
+ } )
273
+
196
274
registerBlueprintsRoutes ( sofieAPIRequest )
197
275
registerDevicesRoutes ( sofieAPIRequest )
198
276
registerPlaylistsRoutes ( sofieAPIRequest )
0 commit comments