eyevinn-channel-engine 4.3.6 → 4.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ export function handler(req: any, res: any, next: any): any;
@@ -0,0 +1,43 @@
1
+ var constants = {
2
+ ALLOW_HEADERS: [
3
+ 'accept',
4
+ 'accept-version',
5
+ 'content-type',
6
+ 'request-id',
7
+ 'origin',
8
+ 'x-api-version',
9
+ 'x-request-id',
10
+ 'x-requested-with'
11
+ ],
12
+ EXPOSE_HEADERS: [
13
+ 'api-version',
14
+ 'content-length',
15
+ 'content-md5',
16
+ 'content-type',
17
+ 'date',
18
+ 'request-id',
19
+ 'response-time'
20
+ ],
21
+ AC_REQ_METHOD: 'access-control-request-method',
22
+ AC_REQ_HEADERS: 'access-control-request-headers',
23
+ AC_ALLOW_CREDS: 'access-control-allow-credentials',
24
+ AC_ALLOW_ORIGIN: 'access-control-allow-origin',
25
+ AC_ALLOW_HEADERS: 'access-control-allow-headers',
26
+ AC_ALLOW_METHODS: 'access-control-allow-methods',
27
+ AC_EXPOSE_HEADERS: 'access-control-expose-headers',
28
+ AC_MAX_AGE: 'access-control-max-age',
29
+ STR_VARY: 'vary',
30
+ STR_ORIGIN: 'origin',
31
+ HTTP_NO_CONTENT: 204
32
+ };
33
+ exports.handler = function (req, res, next) {
34
+ if (req.method !== 'OPTIONS')
35
+ return next();
36
+ res.once('header', function () {
37
+ res.header(constants.AC_ALLOW_ORIGIN, '*');
38
+ res.header(constants.AC_ALLOW_CREDS, true);
39
+ res.header(constants.AC_ALLOW_METHODS, ['GET', 'OPTIONS']);
40
+ res.header(constants.AC_ALLOW_HEADERS, ['x-health-key']);
41
+ });
42
+ res.send(constants.HTTP_NO_CONTENT);
43
+ };
@@ -33,6 +33,7 @@ export interface ChannelEngineOpts {
33
33
  sessionResetKey?: string;
34
34
  keepAliveTimeout?: number;
35
35
  sessionEventStream?: boolean;
36
+ sessionHealthKey?: string;
36
37
  }
37
38
  export interface VodRequest {
38
39
  sessionId: string;
@@ -153,6 +154,7 @@ export declare class ChannelEngine {
153
154
  private autoCreateSession;
154
155
  private sessionResetKey;
155
156
  private sessionEventStream;
157
+ private sessionHealthKey;
156
158
  constructor(assetMgr: IAssetManager, options?: ChannelEngineOpts);
157
159
  updateStreamSwitchAsync(): Promise<void>;
158
160
  updateChannelsAsync(channelMgr: any, options: any): Promise<void>;
@@ -52,6 +52,7 @@ var SessionStateStore = require('./session_state.js').SessionStateStore;
52
52
  var SessionLiveStateStore = require('./session_live_state.js').SessionLiveStateStore;
53
53
  var PlayheadStateStore = require('./playhead_state.js').PlayheadStateStore;
54
54
  var _a = require('./util.js'), filterQueryParser = _a.filterQueryParser, toHHMMSS = _a.toHHMMSS, WaitTimeGenerator = _a.WaitTimeGenerator;
55
+ var preflight = require('./preflight.js');
55
56
  var version = require('../package.json').version;
56
57
  var AUTO_CREATE_CHANNEL_TIMEOUT = 3000;
57
58
  var sessions = {}; // Should be a persistent store...
@@ -73,6 +74,7 @@ var ChannelEngine = /** @class */ (function () {
73
74
  this.autoCreateSession = false;
74
75
  this.sessionResetKey = "";
75
76
  this.sessionEventStream = false;
77
+ this.sessionHealthKey = "";
76
78
  this.options = options;
77
79
  if (options && options.adCopyMgrUri) {
78
80
  this.adCopyMgrUri = options.adCopyMgrUri;
@@ -92,6 +94,9 @@ var ChannelEngine = /** @class */ (function () {
92
94
  if (options && options.sessionResetKey) {
93
95
  this.sessionResetKey = options.sessionResetKey;
94
96
  }
97
+ if (options && options.sessionHealthKey) {
98
+ this.sessionHealthKey = options.sessionHealthKey;
99
+ }
95
100
  this.alwaysNewSegments = false;
96
101
  if (options && options.alwaysNewSegments) {
97
102
  this.alwaysNewSegments = true;
@@ -245,30 +250,7 @@ var ChannelEngine = /** @class */ (function () {
245
250
  }
246
251
  });
247
252
  }); });
248
- this.server.opts('/live/:file', function (req, res, next) { return __awaiter(_this, void 0, void 0, function () {
249
- return __generator(this, function (_a) {
250
- res.sendRaw(204, "", {
251
- headers: {
252
- "Access-Control-Allow-Origin": "*",
253
- "Access-Control-Allow-Methods": "GET, OPTIONS",
254
- },
255
- });
256
- next();
257
- return [2 /*return*/];
258
- });
259
- }); });
260
- this.server.opts('/channels/:channelId/:file', function (req, res, next) { return __awaiter(_this, void 0, void 0, function () {
261
- return __generator(this, function (_a) {
262
- res.sendRaw(204, "", {
263
- headers: {
264
- "Access-Control-Allow-Origin": "*",
265
- "Access-Control-Allow-Methods": "GET, OPTIONS",
266
- },
267
- });
268
- next();
269
- return [2 /*return*/];
270
- });
271
- }); });
253
+ this.server.pre(preflight.handler);
272
254
  this.server.get('/eventstream/:sessionId', this._handleEventStream.bind(this));
273
255
  this.server.get('/status/:sessionId', this._handleStatus.bind(this));
274
256
  this.server.get('/health', this._handleAggregatedSessionHealth.bind(this));
@@ -1203,6 +1185,15 @@ var ChannelEngine = /** @class */ (function () {
1203
1185
  switch (_b.label) {
1204
1186
  case 0:
1205
1187
  debug("req.url=".concat(req.url));
1188
+ if (this.sessionHealthKey && this.sessionHealthKey !== req.headers['x-health-key']) {
1189
+ res.sendRaw(403, JSON.stringify({ "message": "Invalid Session-Health-Key" }), {
1190
+ "Content-Type": "application/json",
1191
+ "Access-Control-Allow-Origin": "*",
1192
+ "Cache-Control": "no-cache",
1193
+ });
1194
+ next();
1195
+ return [2 /*return*/];
1196
+ }
1206
1197
  failingSessions = [];
1207
1198
  endpoints = [];
1208
1199
  _i = 0, _a = Object.keys(sessions);
@@ -94,7 +94,8 @@ var engineOptions = {
94
94
  defaultSlateUri: "https://maitv-vod.lab.eyevinn.technology/slate-consuo.mp4/master.m3u8",
95
95
  slateRepetitions: 10,
96
96
  redisUrl: process.env.REDIS_URL,
97
- keepAliveTimeout: process.env.KEEP_ALIVE_TIMEOUT ? parseInt(process.env.KEEP_ALIVE_TIMEOUT) * 1000 : undefined
97
+ keepAliveTimeout: process.env.KEEP_ALIVE_TIMEOUT ? parseInt(process.env.KEEP_ALIVE_TIMEOUT) * 1000 : undefined,
98
+ sessionHealthKey: 'eyevinn'
98
99
  };
99
100
  var engine = new index_1.ChannelEngine(refAssetManager, engineOptions);
100
101
  engine.start();
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.3.6",
3
+ "version": "4.3.7",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,44 @@
1
+ const constants = {
2
+ ALLOW_HEADERS: [
3
+ 'accept',
4
+ 'accept-version',
5
+ 'content-type',
6
+ 'request-id',
7
+ 'origin',
8
+ 'x-api-version',
9
+ 'x-request-id',
10
+ 'x-requested-with'
11
+ ],
12
+ EXPOSE_HEADERS: [
13
+ 'api-version',
14
+ 'content-length',
15
+ 'content-md5',
16
+ 'content-type',
17
+ 'date',
18
+ 'request-id',
19
+ 'response-time'
20
+ ],
21
+ AC_REQ_METHOD: 'access-control-request-method',
22
+ AC_REQ_HEADERS: 'access-control-request-headers',
23
+ AC_ALLOW_CREDS: 'access-control-allow-credentials',
24
+ AC_ALLOW_ORIGIN: 'access-control-allow-origin',
25
+ AC_ALLOW_HEADERS: 'access-control-allow-headers',
26
+ AC_ALLOW_METHODS: 'access-control-allow-methods',
27
+ AC_EXPOSE_HEADERS: 'access-control-expose-headers',
28
+ AC_MAX_AGE: 'access-control-max-age',
29
+ STR_VARY: 'vary',
30
+ STR_ORIGIN: 'origin',
31
+ HTTP_NO_CONTENT: 204
32
+ }
33
+
34
+ exports.handler = function (req, res, next) {
35
+ if (req.method !== 'OPTIONS') return next();
36
+ res.once('header', function () {
37
+ res.header(constants.AC_ALLOW_ORIGIN, '*');
38
+ res.header(constants.AC_ALLOW_CREDS, true);
39
+ res.header(constants.AC_ALLOW_METHODS, ['GET', 'OPTIONS']);
40
+ res.header(constants.AC_ALLOW_HEADERS, ['x-health-key']);
41
+ });
42
+
43
+ res.send(constants.HTTP_NO_CONTENT);
44
+ }
package/engine/server.ts CHANGED
@@ -15,6 +15,8 @@ const { SessionLiveStateStore } = require('./session_live_state.js');
15
15
  const { PlayheadStateStore } = require('./playhead_state.js');
16
16
 
17
17
  const { filterQueryParser, toHHMMSS, WaitTimeGenerator } = require('./util.js');
18
+ const preflight = require('./preflight.js');
19
+
18
20
  const { version } = require('../package.json');
19
21
 
20
22
  const AUTO_CREATE_CHANNEL_TIMEOUT = 3000;
@@ -62,6 +64,7 @@ export interface ChannelEngineOpts {
62
64
  sessionResetKey?: string;
63
65
  keepAliveTimeout?: number;
64
66
  sessionEventStream?: boolean;
67
+ sessionHealthKey?: string;
65
68
  }
66
69
 
67
70
  interface StreamerOpts {
@@ -209,6 +212,7 @@ export class ChannelEngine {
209
212
  private autoCreateSession: boolean = false;
210
213
  private sessionResetKey: string = "";
211
214
  private sessionEventStream: boolean = false;
215
+ private sessionHealthKey: string = "";
212
216
 
213
217
  constructor(assetMgr: IAssetManager, options?: ChannelEngineOpts) {
214
218
  this.options = options;
@@ -232,6 +236,9 @@ export class ChannelEngine {
232
236
  if (options && options.sessionResetKey) {
233
237
  this.sessionResetKey = options.sessionResetKey;
234
238
  }
239
+ if (options && options.sessionHealthKey) {
240
+ this.sessionHealthKey = options.sessionHealthKey;
241
+ }
235
242
  this.alwaysNewSegments = false;
236
243
  if (options && options.alwaysNewSegments) {
237
244
  this.alwaysNewSegments = true;
@@ -353,25 +360,8 @@ export class ChannelEngine {
353
360
  this.server.get('/channels/:channelId/:file', async (req, res, next) => {
354
361
  req.query['channel'] = req.params.channelId;
355
362
  await handleMasterRoute(req, res, next);
356
- });
357
- this.server.opts('/live/:file', async (req, res, next) => {
358
- res.sendRaw(204, "", {
359
- headers: {
360
- "Access-Control-Allow-Origin": "*",
361
- "Access-Control-Allow-Methods": "GET, OPTIONS",
362
- },
363
- });
364
- next();
365
- });
366
- this.server.opts('/channels/:channelId/:file', async (req, res, next) => {
367
- res.sendRaw(204, "", {
368
- headers: {
369
- "Access-Control-Allow-Origin": "*",
370
- "Access-Control-Allow-Methods": "GET, OPTIONS",
371
- },
372
- });
373
- next();
374
363
  });
364
+ this.server.pre(preflight.handler);
375
365
  this.server.get('/eventstream/:sessionId', this._handleEventStream.bind(this));
376
366
  this.server.get('/status/:sessionId', this._handleStatus.bind(this));
377
367
  this.server.get('/health', this._handleAggregatedSessionHealth.bind(this));
@@ -957,6 +947,16 @@ export class ChannelEngine {
957
947
 
958
948
  async _handleAggregatedSessionHealth(req, res, next) {
959
949
  debug(`req.url=${req.url}`);
950
+ if (this.sessionHealthKey && this.sessionHealthKey !== req.headers['x-health-key']) {
951
+ res.sendRaw(403, JSON.stringify({ "message": "Invalid Session-Health-Key" }),
952
+ {
953
+ "Content-Type": "application/json",
954
+ "Access-Control-Allow-Origin": "*",
955
+ "Cache-Control": "no-cache",
956
+ });
957
+ next();
958
+ return;
959
+ }
960
960
  let failingSessions = [];
961
961
  let endpoints = [];
962
962
  for (const sessionId of Object.keys(sessions)) {
@@ -106,7 +106,8 @@ const engineOptions: ChannelEngineOpts = {
106
106
  "https://maitv-vod.lab.eyevinn.technology/slate-consuo.mp4/master.m3u8",
107
107
  slateRepetitions: 10,
108
108
  redisUrl: process.env.REDIS_URL,
109
- keepAliveTimeout: process.env.KEEP_ALIVE_TIMEOUT ? parseInt(process.env.KEEP_ALIVE_TIMEOUT) * 1000: undefined
109
+ keepAliveTimeout: process.env.KEEP_ALIVE_TIMEOUT ? parseInt(process.env.KEEP_ALIVE_TIMEOUT) * 1000: undefined,
110
+ sessionHealthKey: 'eyevinn'
110
111
  };
111
112
 
112
113
  const engine = new ChannelEngine(refAssetManager, engineOptions);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyevinn-channel-engine",
3
- "version": "4.3.6",
3
+ "version": "4.3.7",
4
4
  "description": "OTT TV Channel Engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",