eyevinn-channel-engine 3.3.11 → 3.4.0
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.
- package/.github/workflows/publish.yml +5 -3
- package/dist/engine/ad_request.d.ts +14 -0
- package/dist/engine/ad_request.js +121 -0
- package/dist/engine/chaos_monkey.d.ts +1 -0
- package/dist/engine/chaos_monkey.js +55 -0
- package/dist/engine/event_stream.d.ts +6 -0
- package/dist/engine/event_stream.js +20 -0
- package/dist/engine/index.d.ts +0 -0
- package/dist/engine/index.js +0 -0
- package/dist/engine/memcached_state_store.d.ts +12 -0
- package/dist/engine/memcached_state_store.js +164 -0
- package/dist/engine/memory_state_store.d.ts +11 -0
- package/dist/engine/memory_state_store.js +105 -0
- package/dist/engine/playhead_state.d.ts +26 -0
- package/dist/engine/playhead_state.js +156 -0
- package/dist/engine/redis_state_store.d.ts +12 -0
- package/dist/engine/redis_state_store.js +236 -0
- package/dist/engine/server.d.ts +125 -0
- package/dist/engine/server.js +1113 -0
- package/dist/engine/session.d.ts +109 -0
- package/dist/engine/session.js +2194 -0
- package/dist/engine/session_live.d.ts +119 -0
- package/dist/engine/session_live.js +1723 -0
- package/dist/engine/session_live_state.d.ts +24 -0
- package/dist/engine/session_live_state.js +231 -0
- package/dist/engine/session_state.d.ts +45 -0
- package/dist/engine/session_state.js +365 -0
- package/dist/engine/shared_state_store.d.ts +21 -0
- package/dist/engine/shared_state_store.js +170 -0
- package/dist/engine/stream_switcher.d.ts +29 -0
- package/dist/engine/stream_switcher.js +813 -0
- package/dist/engine/util.d.ts +19 -0
- package/dist/engine/util.js +281 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/package.json +47 -0
- package/dist/server-demux.d.ts +1 -0
- package/dist/server-demux.js +103 -0
- package/dist/server-livemix.d.ts +1 -0
- package/dist/server-livemix.js +196 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +101 -0
- package/engine/index.ts +0 -0
- package/engine/{server.js → server.ts} +128 -6
- package/index.ts +12 -0
- package/package.json +11 -7
- package/{server-demux.js → server-demux.ts} +16 -10
- package/{server-livemix.js → server-livemix.ts} +21 -13
- package/{server.js → server.ts} +13 -8
- package/spec/engine/engine_spec.js +1 -1
- package/spec/engine/interface_spec.js +1 -1
- package/tsconfig.json +10 -0
- package/index.js +0 -3
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export class SessionLiveStateStore extends SharedStateStore {
|
|
2
|
+
constructor(opts: any);
|
|
3
|
+
cache: {
|
|
4
|
+
leader: {
|
|
5
|
+
ts: number;
|
|
6
|
+
value: any;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
ping(instanceId: any): Promise<void>;
|
|
10
|
+
setLeader(instanceId: any): Promise<any>;
|
|
11
|
+
isLeader(instanceId: any): Promise<boolean>;
|
|
12
|
+
create(sessionId: any, instanceId: any): Promise<SharedSessionLiveState>;
|
|
13
|
+
}
|
|
14
|
+
import SharedStateStore = require("./shared_state_store.js");
|
|
15
|
+
declare class SharedSessionLiveState {
|
|
16
|
+
constructor(store: any, sessionId: any, instanceId: any, opts: any);
|
|
17
|
+
sessionId: any;
|
|
18
|
+
instanceId: any;
|
|
19
|
+
store: any;
|
|
20
|
+
get(key: any): Promise<any>;
|
|
21
|
+
set(key: any, value: any): Promise<any>;
|
|
22
|
+
remove(key: any): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
var __extends = (this && this.__extends) || (function () {
|
|
2
|
+
var extendStatics = function (d, b) {
|
|
3
|
+
extendStatics = Object.setPrototypeOf ||
|
|
4
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
5
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
6
|
+
return extendStatics(d, b);
|
|
7
|
+
};
|
|
8
|
+
return function (d, b) {
|
|
9
|
+
if (typeof b !== "function" && b !== null)
|
|
10
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
11
|
+
extendStatics(d, b);
|
|
12
|
+
function __() { this.constructor = d; }
|
|
13
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
14
|
+
};
|
|
15
|
+
})();
|
|
16
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
17
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
18
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
19
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
20
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
21
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
22
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
26
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
27
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
28
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
29
|
+
function step(op) {
|
|
30
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
31
|
+
while (_) try {
|
|
32
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
33
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
34
|
+
switch (op[0]) {
|
|
35
|
+
case 0: case 1: t = op; break;
|
|
36
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
37
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
38
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
39
|
+
default:
|
|
40
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
41
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
42
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
43
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
44
|
+
if (t[2]) _.ops.pop();
|
|
45
|
+
_.trys.pop(); continue;
|
|
46
|
+
}
|
|
47
|
+
op = body.call(thisArg, _);
|
|
48
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
49
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var SharedStateStore = require('./shared_state_store.js');
|
|
53
|
+
var debug = require("debug")("session-live-state-store");
|
|
54
|
+
var SharedSessionLiveState = /** @class */ (function () {
|
|
55
|
+
function SharedSessionLiveState(store, sessionId, instanceId, opts) {
|
|
56
|
+
this.sessionId = sessionId;
|
|
57
|
+
this.instanceId = instanceId;
|
|
58
|
+
this.store = store;
|
|
59
|
+
}
|
|
60
|
+
SharedSessionLiveState.prototype.get = function (key) {
|
|
61
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
62
|
+
return __generator(this, function (_a) {
|
|
63
|
+
switch (_a.label) {
|
|
64
|
+
case 0: return [4 /*yield*/, this.store.get(this.sessionId, key)];
|
|
65
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
SharedSessionLiveState.prototype.set = function (key, value) {
|
|
71
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
72
|
+
return __generator(this, function (_a) {
|
|
73
|
+
switch (_a.label) {
|
|
74
|
+
case 0: return [4 /*yield*/, this.store.isLeader(this.instanceId)];
|
|
75
|
+
case 1:
|
|
76
|
+
if (!_a.sent()) return [3 /*break*/, 3];
|
|
77
|
+
return [4 /*yield*/, this.store.set(this.sessionId, key, value)];
|
|
78
|
+
case 2: return [2 /*return*/, _a.sent()];
|
|
79
|
+
case 3: return [4 /*yield*/, this.store.get(this.sessionId, key)];
|
|
80
|
+
case 4: return [2 /*return*/, _a.sent()];
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
SharedSessionLiveState.prototype.remove = function (key) {
|
|
86
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
87
|
+
return __generator(this, function (_a) {
|
|
88
|
+
switch (_a.label) {
|
|
89
|
+
case 0: return [4 /*yield*/, this.store.remove(this.sessionId, key)];
|
|
90
|
+
case 1:
|
|
91
|
+
_a.sent();
|
|
92
|
+
return [2 /*return*/];
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
return SharedSessionLiveState;
|
|
98
|
+
}());
|
|
99
|
+
var SessionLiveStateStore = /** @class */ (function (_super) {
|
|
100
|
+
__extends(SessionLiveStateStore, _super);
|
|
101
|
+
function SessionLiveStateStore(opts) {
|
|
102
|
+
var _this = _super.call(this, "sessionLive", opts, {
|
|
103
|
+
firstCounts: {
|
|
104
|
+
liveSourceMseqCount: null,
|
|
105
|
+
mediaSeqCount: null,
|
|
106
|
+
discSeqCount: null,
|
|
107
|
+
},
|
|
108
|
+
lastRequestedMediaSeqRaw: null,
|
|
109
|
+
liveSegsForFollowers: null,
|
|
110
|
+
transitSegs: null,
|
|
111
|
+
}) || this;
|
|
112
|
+
if (opts && opts.cacheTTL) {
|
|
113
|
+
_this.cacheTTL = opts.cacheTTL;
|
|
114
|
+
}
|
|
115
|
+
_this.cache = {
|
|
116
|
+
leader: {
|
|
117
|
+
ts: 0,
|
|
118
|
+
value: null
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
return _this;
|
|
122
|
+
}
|
|
123
|
+
SessionLiveStateStore.prototype.ping = function (instanceId) {
|
|
124
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
125
|
+
var t;
|
|
126
|
+
return __generator(this, function (_a) {
|
|
127
|
+
switch (_a.label) {
|
|
128
|
+
case 0:
|
|
129
|
+
t = Date.now();
|
|
130
|
+
return [4 /*yield*/, this.setVolatile("", instanceId, t)];
|
|
131
|
+
case 1:
|
|
132
|
+
_a.sent();
|
|
133
|
+
return [2 /*return*/];
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
// Should only be called when Channel Engine starts.
|
|
139
|
+
// This is due to the fact that we want to sync leaders between Session and SessionLive.
|
|
140
|
+
SessionLiveStateStore.prototype.setLeader = function (instanceId) {
|
|
141
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
142
|
+
return __generator(this, function (_a) {
|
|
143
|
+
switch (_a.label) {
|
|
144
|
+
case 0:
|
|
145
|
+
if (!instanceId) {
|
|
146
|
+
throw new Error("Cannot set leader without instance id");
|
|
147
|
+
}
|
|
148
|
+
debug("[".concat(instanceId, "]: Taking the lead! ").concat(instanceId));
|
|
149
|
+
return [4 /*yield*/, this.set("", "leader", instanceId)];
|
|
150
|
+
case 1:
|
|
151
|
+
_a.sent();
|
|
152
|
+
this.cache.leader.ts = Date.now();
|
|
153
|
+
this.cache.leader.value = instanceId;
|
|
154
|
+
return [2 /*return*/, instanceId];
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
SessionLiveStateStore.prototype.isLeader = function (instanceId) {
|
|
160
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
161
|
+
var leader, lastSeen;
|
|
162
|
+
return __generator(this, function (_a) {
|
|
163
|
+
switch (_a.label) {
|
|
164
|
+
case 0:
|
|
165
|
+
if (!instanceId) {
|
|
166
|
+
throw new Error("Cannot determine leader without instance id");
|
|
167
|
+
}
|
|
168
|
+
if (this.cache.leader.value && Date.now() < this.cache.leader.ts + this.cacheTTL) {
|
|
169
|
+
leader = this.cache.leader.value;
|
|
170
|
+
debug("[".concat(instanceId, "]: reading 'leader' from cache: I am ").concat(leader === instanceId ? "" : "NOT", " the leader!"));
|
|
171
|
+
return [2 /*return*/, leader === instanceId];
|
|
172
|
+
}
|
|
173
|
+
return [4 /*yield*/, this.get("", "leader")];
|
|
174
|
+
case 1:
|
|
175
|
+
leader = _a.sent();
|
|
176
|
+
if (!!leader) return [3 /*break*/, 3];
|
|
177
|
+
leader = instanceId;
|
|
178
|
+
debug("[".concat(instanceId, "]: We have a new leader! ").concat(instanceId));
|
|
179
|
+
return [4 /*yield*/, this.set("", "leader", instanceId)];
|
|
180
|
+
case 2:
|
|
181
|
+
_a.sent();
|
|
182
|
+
_a.label = 3;
|
|
183
|
+
case 3:
|
|
184
|
+
if (!(leader !== instanceId)) return [3 /*break*/, 8];
|
|
185
|
+
debug("[".concat(instanceId, "]: Checking whether leader ").concat(leader, " is alive"));
|
|
186
|
+
return [4 /*yield*/, this.get("", leader)];
|
|
187
|
+
case 4:
|
|
188
|
+
lastSeen = _a.sent();
|
|
189
|
+
if (!!lastSeen) return [3 /*break*/, 6];
|
|
190
|
+
leader = instanceId;
|
|
191
|
+
debug("[".concat(instanceId, "]: Current leader is missing, taking the lead! ").concat(leader));
|
|
192
|
+
return [4 /*yield*/, this.set("", "leader", leader)];
|
|
193
|
+
case 5:
|
|
194
|
+
_a.sent();
|
|
195
|
+
return [3 /*break*/, 8];
|
|
196
|
+
case 6:
|
|
197
|
+
if (!(Date.now() - lastSeen > 30000)) return [3 /*break*/, 8];
|
|
198
|
+
leader = instanceId;
|
|
199
|
+
debug("[".concat(instanceId, "]: Current leader hasn't been seen for the last 30 sec, taking the lead! ").concat(leader));
|
|
200
|
+
return [4 /*yield*/, this.set("", "leader", leader)];
|
|
201
|
+
case 7:
|
|
202
|
+
_a.sent();
|
|
203
|
+
_a.label = 8;
|
|
204
|
+
case 8:
|
|
205
|
+
debug("[".concat(instanceId, "]: I am ").concat(leader === instanceId ? "" : "NOT", " the leader!"));
|
|
206
|
+
this.cache.leader.ts = Date.now();
|
|
207
|
+
this.cache.leader.value = leader;
|
|
208
|
+
return [2 /*return*/, leader === instanceId];
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
};
|
|
213
|
+
SessionLiveStateStore.prototype.create = function (sessionId, instanceId) {
|
|
214
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
215
|
+
return __generator(this, function (_a) {
|
|
216
|
+
switch (_a.label) {
|
|
217
|
+
case 0:
|
|
218
|
+
debug("[".concat(sessionId, "][").concat(instanceId, "]: creating SharedSessionLiveState"));
|
|
219
|
+
return [4 /*yield*/, this.init(sessionId)];
|
|
220
|
+
case 1:
|
|
221
|
+
_a.sent();
|
|
222
|
+
return [2 /*return*/, new SharedSessionLiveState(this, sessionId, instanceId, { cacheTTL: this.cacheTTL || 5000 })];
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
return SessionLiveStateStore;
|
|
228
|
+
}(SharedStateStore));
|
|
229
|
+
module.exports = {
|
|
230
|
+
SessionLiveStateStore: SessionLiveStateStore
|
|
231
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const SessionState: Readonly<{
|
|
2
|
+
VOD_INIT: 1;
|
|
3
|
+
VOD_PLAYING: 2;
|
|
4
|
+
VOD_NEXT_INIT: 3;
|
|
5
|
+
VOD_NEXT_INITIATING: 4;
|
|
6
|
+
VOD_RELOAD_INIT: 5;
|
|
7
|
+
VOD_RELOAD_INITIATING: 6;
|
|
8
|
+
}>;
|
|
9
|
+
export class SessionStateStore extends SharedStateStore {
|
|
10
|
+
constructor(opts: any);
|
|
11
|
+
cache: {
|
|
12
|
+
leader: {
|
|
13
|
+
ts: number;
|
|
14
|
+
value: any;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
ping(instanceId: any): Promise<void>;
|
|
18
|
+
clearLeaderCache(): Promise<void>;
|
|
19
|
+
isLeader(instanceId: any): Promise<boolean>;
|
|
20
|
+
create(sessionId: any, instanceId: any): Promise<SharedSessionState>;
|
|
21
|
+
}
|
|
22
|
+
import SharedStateStore = require("./shared_state_store.js");
|
|
23
|
+
declare class SharedSessionState {
|
|
24
|
+
constructor(store: any, sessionId: any, instanceId: any, opts: any);
|
|
25
|
+
sessionId: any;
|
|
26
|
+
instanceId: any;
|
|
27
|
+
cache: {
|
|
28
|
+
currentVod: {
|
|
29
|
+
ts: number;
|
|
30
|
+
ttl: number;
|
|
31
|
+
value: any;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
cacheTTL: any;
|
|
35
|
+
store: any;
|
|
36
|
+
clearCurrentVodCache(): Promise<void>;
|
|
37
|
+
getCurrentVod(): Promise<any>;
|
|
38
|
+
setCurrentVod(hlsVod: any, opts: any): Promise<any>;
|
|
39
|
+
get(key: any): Promise<any>;
|
|
40
|
+
getValues(keys: any): Promise<any>;
|
|
41
|
+
set(key: any, value: any): Promise<any>;
|
|
42
|
+
remove(key: any): Promise<void>;
|
|
43
|
+
increment(key: any, inc: any): Promise<any>;
|
|
44
|
+
}
|
|
45
|
+
export {};
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
var __extends = (this && this.__extends) || (function () {
|
|
2
|
+
var extendStatics = function (d, b) {
|
|
3
|
+
extendStatics = Object.setPrototypeOf ||
|
|
4
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
5
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
6
|
+
return extendStatics(d, b);
|
|
7
|
+
};
|
|
8
|
+
return function (d, b) {
|
|
9
|
+
if (typeof b !== "function" && b !== null)
|
|
10
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
11
|
+
extendStatics(d, b);
|
|
12
|
+
function __() { this.constructor = d; }
|
|
13
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
14
|
+
};
|
|
15
|
+
})();
|
|
16
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
17
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
18
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
19
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
20
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
21
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
22
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
26
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
27
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
28
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
29
|
+
function step(op) {
|
|
30
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
31
|
+
while (_) try {
|
|
32
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
33
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
34
|
+
switch (op[0]) {
|
|
35
|
+
case 0: case 1: t = op; break;
|
|
36
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
37
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
38
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
39
|
+
default:
|
|
40
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
41
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
42
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
43
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
44
|
+
if (t[2]) _.ops.pop();
|
|
45
|
+
_.trys.pop(); continue;
|
|
46
|
+
}
|
|
47
|
+
op = body.call(thisArg, _);
|
|
48
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
49
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var HLSVod = require('@eyevinn/hls-vodtolive');
|
|
53
|
+
var SharedStateStore = require('./shared_state_store.js');
|
|
54
|
+
var debug = require("debug")("session-state-store");
|
|
55
|
+
var SessionState = Object.freeze({
|
|
56
|
+
VOD_INIT: 1,
|
|
57
|
+
VOD_PLAYING: 2,
|
|
58
|
+
VOD_NEXT_INIT: 3,
|
|
59
|
+
VOD_NEXT_INITIATING: 4,
|
|
60
|
+
VOD_RELOAD_INIT: 5,
|
|
61
|
+
VOD_RELOAD_INITIATING: 6
|
|
62
|
+
});
|
|
63
|
+
var CURRENTVOD_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
64
|
+
var SharedSessionState = /** @class */ (function () {
|
|
65
|
+
function SharedSessionState(store, sessionId, instanceId, opts) {
|
|
66
|
+
this.sessionId = sessionId;
|
|
67
|
+
this.instanceId = instanceId;
|
|
68
|
+
this.cache = {
|
|
69
|
+
currentVod: {
|
|
70
|
+
ts: 0,
|
|
71
|
+
ttl: CURRENTVOD_CACHE_TTL,
|
|
72
|
+
value: null
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
if (opts && opts.cacheTTL) {
|
|
76
|
+
this.cacheTTL = opts.cacheTTL;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
throw new Error("need to specify cache TTL");
|
|
80
|
+
}
|
|
81
|
+
this.store = store;
|
|
82
|
+
}
|
|
83
|
+
SharedSessionState.prototype.clearCurrentVodCache = function () {
|
|
84
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
85
|
+
return __generator(this, function (_a) {
|
|
86
|
+
debug("[".concat(this.sessionId, "]: clearing 'currentVod' cache"));
|
|
87
|
+
this.cache.currentVod.value = null;
|
|
88
|
+
return [2 /*return*/];
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
SharedSessionState.prototype.getCurrentVod = function () {
|
|
93
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
94
|
+
var currentVod, hlsVod;
|
|
95
|
+
return __generator(this, function (_a) {
|
|
96
|
+
switch (_a.label) {
|
|
97
|
+
case 0:
|
|
98
|
+
if (!this.sessionId) {
|
|
99
|
+
throw new Error("shared session state store has not been initialized");
|
|
100
|
+
}
|
|
101
|
+
if (this.cache.currentVod.value && Date.now() < this.cache.currentVod.ts + this.cache.currentVod.ttl) {
|
|
102
|
+
debug("[".concat(this.sessionId, "]: reading 'currentVod' from cache"));
|
|
103
|
+
return [2 /*return*/, this.cache.currentVod.value];
|
|
104
|
+
}
|
|
105
|
+
return [4 /*yield*/, this.get("currentVod")];
|
|
106
|
+
case 1:
|
|
107
|
+
currentVod = _a.sent();
|
|
108
|
+
hlsVod = null;
|
|
109
|
+
if (currentVod) {
|
|
110
|
+
if (this.store.isShared()) {
|
|
111
|
+
debug("[".concat(this.sessionId, "]: reading ").concat(currentVod.length, " characters from shared store (").concat(Date.now(), " < ").concat(this.cache.currentVod.ts + this.cache.currentVod.ttl, ")"));
|
|
112
|
+
hlsVod = new HLSVod();
|
|
113
|
+
hlsVod.fromJSON(currentVod);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
hlsVod = currentVod;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
this.cache.currentVod.ts = Date.now();
|
|
120
|
+
this.cache.currentVod.value = hlsVod;
|
|
121
|
+
return [2 /*return*/, hlsVod];
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
SharedSessionState.prototype.setCurrentVod = function (hlsVod, opts) {
|
|
127
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
128
|
+
var newHlsVodJson, isLeader;
|
|
129
|
+
return __generator(this, function (_a) {
|
|
130
|
+
switch (_a.label) {
|
|
131
|
+
case 0:
|
|
132
|
+
if (!this.sessionId) {
|
|
133
|
+
throw new Error("shared session state store has not been initialized");
|
|
134
|
+
}
|
|
135
|
+
if (!this.store.isShared()) return [3 /*break*/, 3];
|
|
136
|
+
return [4 /*yield*/, this.set("currentVod", hlsVod.toJSON())];
|
|
137
|
+
case 1:
|
|
138
|
+
newHlsVodJson = _a.sent();
|
|
139
|
+
return [4 /*yield*/, this.store.isLeader(this.instanceId)];
|
|
140
|
+
case 2:
|
|
141
|
+
isLeader = _a.sent();
|
|
142
|
+
if (!isLeader) {
|
|
143
|
+
debug("[".concat(this.sessionId, "]: not a leader, will not overwrite currentVod in shared store"));
|
|
144
|
+
hlsVod = new HLSVod();
|
|
145
|
+
hlsVod.fromJSON(newHlsVodJson);
|
|
146
|
+
}
|
|
147
|
+
return [3 /*break*/, 5];
|
|
148
|
+
case 3: return [4 /*yield*/, this.set("currentVod", hlsVod)];
|
|
149
|
+
case 4:
|
|
150
|
+
_a.sent();
|
|
151
|
+
_a.label = 5;
|
|
152
|
+
case 5:
|
|
153
|
+
if (this.cache.currentVod) {
|
|
154
|
+
this.cache.currentVod.ts = Date.now();
|
|
155
|
+
this.cache.currentVod.ttl = CURRENTVOD_CACHE_TTL;
|
|
156
|
+
if (opts && opts.ttl) {
|
|
157
|
+
this.cache.currentVod.ttl = opts.ttl;
|
|
158
|
+
}
|
|
159
|
+
debug("[".concat(this.sessionId, "]: TTL for current VOD is ").concat(this.cache.currentVod.ttl, "ms"));
|
|
160
|
+
this.cache.currentVod.value = hlsVod;
|
|
161
|
+
}
|
|
162
|
+
return [2 /*return*/, this.cache.currentVod.value];
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
SharedSessionState.prototype.get = function (key) {
|
|
168
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
169
|
+
return __generator(this, function (_a) {
|
|
170
|
+
switch (_a.label) {
|
|
171
|
+
case 0: return [4 /*yield*/, this.store.get(this.sessionId, key)];
|
|
172
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
SharedSessionState.prototype.getValues = function (keys) {
|
|
178
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
179
|
+
var values;
|
|
180
|
+
return __generator(this, function (_a) {
|
|
181
|
+
switch (_a.label) {
|
|
182
|
+
case 0: return [4 /*yield*/, this.store.getValues(this.sessionId, keys)];
|
|
183
|
+
case 1:
|
|
184
|
+
values = _a.sent();
|
|
185
|
+
//debug(values);
|
|
186
|
+
return [2 /*return*/, values];
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
SharedSessionState.prototype.set = function (key, value) {
|
|
192
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
193
|
+
return __generator(this, function (_a) {
|
|
194
|
+
switch (_a.label) {
|
|
195
|
+
case 0: return [4 /*yield*/, this.store.isLeader(this.instanceId)];
|
|
196
|
+
case 1:
|
|
197
|
+
if (!_a.sent()) return [3 /*break*/, 3];
|
|
198
|
+
return [4 /*yield*/, this.store.set(this.sessionId, key, value)];
|
|
199
|
+
case 2: return [2 /*return*/, _a.sent()];
|
|
200
|
+
case 3: return [4 /*yield*/, this.store.get(this.sessionId, key)];
|
|
201
|
+
case 4: return [2 /*return*/, _a.sent()];
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
};
|
|
206
|
+
SharedSessionState.prototype.remove = function (key) {
|
|
207
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
208
|
+
return __generator(this, function (_a) {
|
|
209
|
+
switch (_a.label) {
|
|
210
|
+
case 0: return [4 /*yield*/, this.store.remove(this.sessionId, key)];
|
|
211
|
+
case 1:
|
|
212
|
+
_a.sent();
|
|
213
|
+
return [2 /*return*/];
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
};
|
|
218
|
+
SharedSessionState.prototype.increment = function (key, inc) {
|
|
219
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
220
|
+
var value, valueToIncrement;
|
|
221
|
+
return __generator(this, function (_a) {
|
|
222
|
+
switch (_a.label) {
|
|
223
|
+
case 0: return [4 /*yield*/, this.get(key)];
|
|
224
|
+
case 1:
|
|
225
|
+
value = _a.sent();
|
|
226
|
+
return [4 /*yield*/, this.store.isLeader(this.instanceId)];
|
|
227
|
+
case 2:
|
|
228
|
+
if (!_a.sent()) return [3 /*break*/, 4];
|
|
229
|
+
valueToIncrement = inc || 1;
|
|
230
|
+
debug("[".concat(this.sessionId, "]: I am incrementing key ").concat(key, " with ").concat(valueToIncrement));
|
|
231
|
+
value += valueToIncrement;
|
|
232
|
+
return [4 /*yield*/, this.store.set(this.sessionId, key, value)];
|
|
233
|
+
case 3: return [2 /*return*/, _a.sent()];
|
|
234
|
+
case 4: return [2 /*return*/, value];
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
return SharedSessionState;
|
|
240
|
+
}());
|
|
241
|
+
var SessionStateStore = /** @class */ (function (_super) {
|
|
242
|
+
__extends(SessionStateStore, _super);
|
|
243
|
+
function SessionStateStore(opts) {
|
|
244
|
+
var _this = _super.call(this, "session", opts, {
|
|
245
|
+
mediaSeq: 0,
|
|
246
|
+
discSeq: 0,
|
|
247
|
+
vodMediaSeqVideo: 0,
|
|
248
|
+
vodMediaSeqAudio: 0,
|
|
249
|
+
state: SessionState.VOD_INIT,
|
|
250
|
+
lastM3u8: {},
|
|
251
|
+
tsLastRequestVideo: null,
|
|
252
|
+
tsLastRequestMaster: null,
|
|
253
|
+
tsLastRequestAudio: null,
|
|
254
|
+
currentVod: null,
|
|
255
|
+
slateCount: 0,
|
|
256
|
+
assetId: "",
|
|
257
|
+
vodReloaded: 0,
|
|
258
|
+
}) || this;
|
|
259
|
+
if (opts && opts.cacheTTL) {
|
|
260
|
+
_this.cacheTTL = opts.cacheTTL;
|
|
261
|
+
}
|
|
262
|
+
_this.cache = {
|
|
263
|
+
leader: {
|
|
264
|
+
ts: 0,
|
|
265
|
+
value: null
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
return _this;
|
|
269
|
+
}
|
|
270
|
+
SessionStateStore.prototype.ping = function (instanceId) {
|
|
271
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
272
|
+
var t;
|
|
273
|
+
return __generator(this, function (_a) {
|
|
274
|
+
switch (_a.label) {
|
|
275
|
+
case 0:
|
|
276
|
+
t = Date.now();
|
|
277
|
+
return [4 /*yield*/, this.setVolatile("", instanceId, t)];
|
|
278
|
+
case 1:
|
|
279
|
+
_a.sent();
|
|
280
|
+
return [2 /*return*/];
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
};
|
|
285
|
+
SessionStateStore.prototype.clearLeaderCache = function () {
|
|
286
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
287
|
+
return __generator(this, function (_a) {
|
|
288
|
+
debug("[".concat(this.instanceId, "]: clearing 'leader' cache"));
|
|
289
|
+
this.cache.leader.value = null;
|
|
290
|
+
return [2 /*return*/];
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
};
|
|
294
|
+
SessionStateStore.prototype.isLeader = function (instanceId) {
|
|
295
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
296
|
+
var leader, lastSeen;
|
|
297
|
+
return __generator(this, function (_a) {
|
|
298
|
+
switch (_a.label) {
|
|
299
|
+
case 0:
|
|
300
|
+
if (!instanceId) {
|
|
301
|
+
throw new Error("Cannot determine leader without instance id");
|
|
302
|
+
}
|
|
303
|
+
if (this.cache.leader.value && Date.now() < this.cache.leader.ts + this.cacheTTL) {
|
|
304
|
+
leader = this.cache.leader.value;
|
|
305
|
+
debug("[".concat(instanceId, "]: reading 'leader' from cache: I am").concat(leader === instanceId ? "" : " NOT", " the leader!"));
|
|
306
|
+
return [2 /*return*/, leader === instanceId];
|
|
307
|
+
}
|
|
308
|
+
return [4 /*yield*/, this.get("", "leader")];
|
|
309
|
+
case 1:
|
|
310
|
+
leader = _a.sent();
|
|
311
|
+
if (!!leader) return [3 /*break*/, 3];
|
|
312
|
+
leader = instanceId;
|
|
313
|
+
debug("[".concat(instanceId, "]: We have a new leader! ").concat(instanceId));
|
|
314
|
+
return [4 /*yield*/, this.set("", "leader", instanceId)];
|
|
315
|
+
case 2:
|
|
316
|
+
_a.sent();
|
|
317
|
+
_a.label = 3;
|
|
318
|
+
case 3:
|
|
319
|
+
if (!(leader !== instanceId)) return [3 /*break*/, 8];
|
|
320
|
+
debug("[".concat(instanceId, "]: Checking whether leader ").concat(leader, " is alive"));
|
|
321
|
+
return [4 /*yield*/, this.get("", leader)];
|
|
322
|
+
case 4:
|
|
323
|
+
lastSeen = _a.sent();
|
|
324
|
+
if (!!lastSeen) return [3 /*break*/, 6];
|
|
325
|
+
leader = instanceId;
|
|
326
|
+
debug("[".concat(instanceId, "]: Current leader is missing, taking the lead! ").concat(leader));
|
|
327
|
+
return [4 /*yield*/, this.set("", "leader", leader)];
|
|
328
|
+
case 5:
|
|
329
|
+
_a.sent();
|
|
330
|
+
return [3 /*break*/, 8];
|
|
331
|
+
case 6:
|
|
332
|
+
if (!(Date.now() - lastSeen > 30000)) return [3 /*break*/, 8];
|
|
333
|
+
leader = instanceId;
|
|
334
|
+
debug("[".concat(instanceId, "]: Current leader hasn't been seen for the last 30 sec, taking the lead! ").concat(leader));
|
|
335
|
+
return [4 /*yield*/, this.set("", "leader", leader)];
|
|
336
|
+
case 7:
|
|
337
|
+
_a.sent();
|
|
338
|
+
_a.label = 8;
|
|
339
|
+
case 8:
|
|
340
|
+
debug("[".concat(instanceId, "]: I am").concat(leader === instanceId ? "" : " NOT", " the leader!"));
|
|
341
|
+
this.cache.leader.ts = Date.now();
|
|
342
|
+
this.cache.leader.value = leader;
|
|
343
|
+
return [2 /*return*/, leader === instanceId];
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
};
|
|
348
|
+
SessionStateStore.prototype.create = function (sessionId, instanceId) {
|
|
349
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
350
|
+
return __generator(this, function (_a) {
|
|
351
|
+
switch (_a.label) {
|
|
352
|
+
case 0: return [4 /*yield*/, this.init(sessionId)];
|
|
353
|
+
case 1:
|
|
354
|
+
_a.sent();
|
|
355
|
+
return [2 /*return*/, new SharedSessionState(this, sessionId, instanceId, { cacheTTL: this.cacheTTL || 5000 })];
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
return SessionStateStore;
|
|
361
|
+
}(SharedStateStore));
|
|
362
|
+
module.exports = {
|
|
363
|
+
SessionState: SessionState,
|
|
364
|
+
SessionStateStore: SessionStateStore
|
|
365
|
+
};
|