@netless/slide 1.4.60-alpha.0 → 1.4.60
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/README.md +11 -0
- package/lib/AliTrackLogger.js +516 -0
- package/lib/FrozenTaskManager.js +59 -0
- package/lib/Lock.js +54 -0
- package/lib/PlayerContextReleaseWait.js +41 -0
- package/lib/PlayerController.js +175 -0
- package/lib/RenderSlideVisibility.js +16 -0
- package/lib/RenderingTaskManager.js +230 -0
- package/lib/Slide.js +1 -1
- package/lib/SyncTaskManager.js +206 -0
- package/lib/global.js +118 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,10 +4,21 @@
|
|
|
4
4
|
|
|
5
5
|
## changelog
|
|
6
6
|
|
|
7
|
+
### 1.4.60 (2026-09-21)
|
|
8
|
+
* 新增 `onPptMediaPermissionRequest(callback)` 与 `playPptMedia()`,支持在浏览器阻止自动播放时通知业务方并由真实用户点击恢复当前媒体
|
|
9
|
+
* 增加 HTML5 音频和视频播放确认,覆盖浏览器静默暂停或未触发 `playerror` 的情况
|
|
10
|
+
* 修复部分移动浏览器播放前 `duration`、`seekable` 为 0 导致 Howler 提前结束且不触发权限回调的问题
|
|
11
|
+
* 修复视频启动时浏览器底层暂停独立音轨,以及用户点击恢复遇到 Howler pending play 无法重新播放的问题
|
|
12
|
+
|
|
7
13
|
### 1.4.60-alpha.0 (2026-09-20)
|
|
8
14
|
* 修复部分移动浏览器中 HTML5 音频播放请求卡住后,用户点击恢复仍无法重新发起播放的问题
|
|
9
15
|
* 避免将媒体加载或缓冲过程误判为自动播放权限错误,并忽略旧播放请求的迟到事件
|
|
10
16
|
|
|
17
|
+
### 1.4.59 (2026-09-18)
|
|
18
|
+
* 优化移动端切页时的 Player 与 WebGL context 生命周期,减少重复创建和资源残留
|
|
19
|
+
* 完善 Player 原地重置、候选 Player 交换和失败回退,避免快速切页后出现白屏或旧画面
|
|
20
|
+
* 加强纹理缓存隔离、取消任务清理和 context 释放超时保护,降低页面切换对 RTC 与其他 WebGL 内容的影响
|
|
21
|
+
|
|
11
22
|
### 1.4.59-alpha.4 (2026-09-17)
|
|
12
23
|
* 增强 PPT 媒体自动播放恢复:为 Howler/HTML5 音频与视频增加播放确认 watchdog,覆盖浏览器静默失败未触发 `playerror` 的场景
|
|
13
24
|
* 修正 Howler `playerror` 在内部状态已变为 playing 但 DOM 仍 paused 时被误过滤的问题
|
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
13
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
14
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
15
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
16
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
17
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
18
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
22
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
23
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
24
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
25
|
+
function step(op) {
|
|
26
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
27
|
+
while (_) try {
|
|
28
|
+
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;
|
|
29
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
30
|
+
switch (op[0]) {
|
|
31
|
+
case 0: case 1: t = op; break;
|
|
32
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
33
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
34
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
35
|
+
default:
|
|
36
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
37
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
38
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
39
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
40
|
+
if (t[2]) _.ops.pop();
|
|
41
|
+
_.trys.pop(); continue;
|
|
42
|
+
}
|
|
43
|
+
op = body.call(thisArg, _);
|
|
44
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
45
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var AliTrackLogger = /** @class */ (function () {
|
|
49
|
+
function AliTrackLogger() {
|
|
50
|
+
var _this = this;
|
|
51
|
+
this.logList = [];
|
|
52
|
+
this.checkTimer = null;
|
|
53
|
+
this.retryTimes = 0;
|
|
54
|
+
this.enable = false;
|
|
55
|
+
this.db = null;
|
|
56
|
+
this.useIndexedDB = false;
|
|
57
|
+
this.DB_NAME = "__slide_logs_report__";
|
|
58
|
+
this.STORE_NAME = "logs";
|
|
59
|
+
this.BATCH_SIZE = 1000;
|
|
60
|
+
this.uploadLoggerGlobalEvent = function (event) {
|
|
61
|
+
if (event.data.type === "@slide/_upload_log_") {
|
|
62
|
+
_this.start();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
this.config = {
|
|
66
|
+
checkTime: 5000,
|
|
67
|
+
buffer: 300,
|
|
68
|
+
};
|
|
69
|
+
window.addEventListener("message", this.uploadLoggerGlobalEvent);
|
|
70
|
+
this.initIndexedDB();
|
|
71
|
+
}
|
|
72
|
+
AliTrackLogger.prototype.initIndexedDB = function () {
|
|
73
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
74
|
+
var request_1;
|
|
75
|
+
var _this = this;
|
|
76
|
+
return __generator(this, function (_a) {
|
|
77
|
+
if (!('indexedDB' in window)) {
|
|
78
|
+
this.useIndexedDB = false;
|
|
79
|
+
this.start();
|
|
80
|
+
return [2 /*return*/];
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
request_1 = indexedDB.open(this.DB_NAME, 1);
|
|
84
|
+
request_1.onerror = function () {
|
|
85
|
+
_this.useIndexedDB = false;
|
|
86
|
+
};
|
|
87
|
+
request_1.onsuccess = function () {
|
|
88
|
+
_this.start();
|
|
89
|
+
_this.db = request_1.result;
|
|
90
|
+
_this.useIndexedDB = true;
|
|
91
|
+
};
|
|
92
|
+
request_1.onupgradeneeded = function (event) {
|
|
93
|
+
var db = event.target.result;
|
|
94
|
+
if (!db.objectStoreNames.contains(_this.STORE_NAME)) {
|
|
95
|
+
var store = db.createObjectStore(_this.STORE_NAME, { keyPath: 'id', autoIncrement: true });
|
|
96
|
+
store.createIndex('timestamp', 'timestamp');
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
this.useIndexedDB = false;
|
|
102
|
+
}
|
|
103
|
+
return [2 /*return*/];
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
AliTrackLogger.prototype.storeLogInIndexedDB = function (log) {
|
|
108
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
109
|
+
var error_1;
|
|
110
|
+
var _this = this;
|
|
111
|
+
return __generator(this, function (_a) {
|
|
112
|
+
switch (_a.label) {
|
|
113
|
+
case 0:
|
|
114
|
+
if (!this.useIndexedDB)
|
|
115
|
+
return [2 /*return*/];
|
|
116
|
+
_a.label = 1;
|
|
117
|
+
case 1:
|
|
118
|
+
_a.trys.push([1, 4, , 5]);
|
|
119
|
+
if (!(!this.db || !this.isDatabaseHealthy())) return [3 /*break*/, 3];
|
|
120
|
+
return [4 /*yield*/, this.recreateDatabase()];
|
|
121
|
+
case 2:
|
|
122
|
+
_a.sent();
|
|
123
|
+
if (!this.db || !this.useIndexedDB) {
|
|
124
|
+
throw new Error('Database not available after recreation attempt');
|
|
125
|
+
}
|
|
126
|
+
_a.label = 3;
|
|
127
|
+
case 3: return [2 /*return*/, new Promise(function (resolve, reject) {
|
|
128
|
+
var transaction = _this.db.transaction([_this.STORE_NAME], 'readwrite');
|
|
129
|
+
var store = transaction.objectStore(_this.STORE_NAME);
|
|
130
|
+
var request = store.add(log);
|
|
131
|
+
transaction.onerror = function () {
|
|
132
|
+
// If transaction fails due to database being deleted, try to recreate
|
|
133
|
+
_this.recreateDatabase().then(function () {
|
|
134
|
+
if (!_this.db || !_this.useIndexedDB) {
|
|
135
|
+
reject(new Error('Database recreation failed'));
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// Retry the operation after recreation
|
|
139
|
+
var retryTransaction = _this.db.transaction([_this.STORE_NAME], 'readwrite');
|
|
140
|
+
var retryStore = retryTransaction.objectStore(_this.STORE_NAME);
|
|
141
|
+
var retryRequest_1 = retryStore.add(log);
|
|
142
|
+
retryRequest_1.onsuccess = function () { return resolve(); };
|
|
143
|
+
retryRequest_1.onerror = function () { return reject(retryRequest_1.error); };
|
|
144
|
+
}
|
|
145
|
+
}).catch(function (error) {
|
|
146
|
+
console.warn('Database recreation failed:', error);
|
|
147
|
+
// Fall back to memory storage and reject
|
|
148
|
+
_this.useIndexedDB = false;
|
|
149
|
+
reject(error);
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
request.onsuccess = function () { return resolve(); };
|
|
153
|
+
request.onerror = function () {
|
|
154
|
+
var _a, _b;
|
|
155
|
+
if (((_a = request.error) === null || _a === void 0 ? void 0 : _a.name) === 'UnknownError' || ((_b = request.error) === null || _b === void 0 ? void 0 : _b.name) === 'NotFoundError') {
|
|
156
|
+
// Database might have been deleted, try to recreate
|
|
157
|
+
_this.recreateDatabase().catch(function (error) {
|
|
158
|
+
console.warn('Database recreation failed:', error);
|
|
159
|
+
_this.useIndexedDB = false;
|
|
160
|
+
}).finally(function () { return reject(request.error); });
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
reject(request.error);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
})];
|
|
167
|
+
case 4:
|
|
168
|
+
error_1 = _a.sent();
|
|
169
|
+
this.useIndexedDB = false;
|
|
170
|
+
throw error_1;
|
|
171
|
+
case 5: return [2 /*return*/];
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
AliTrackLogger.prototype.getLogsFromIndexedDB = function (limit) {
|
|
177
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
178
|
+
var error_2;
|
|
179
|
+
var _this = this;
|
|
180
|
+
return __generator(this, function (_a) {
|
|
181
|
+
switch (_a.label) {
|
|
182
|
+
case 0:
|
|
183
|
+
if (!this.useIndexedDB)
|
|
184
|
+
return [2 /*return*/, []];
|
|
185
|
+
_a.label = 1;
|
|
186
|
+
case 1:
|
|
187
|
+
_a.trys.push([1, 4, , 5]);
|
|
188
|
+
if (!(!this.db || !this.isDatabaseHealthy())) return [3 /*break*/, 3];
|
|
189
|
+
return [4 /*yield*/, this.recreateDatabase()];
|
|
190
|
+
case 2:
|
|
191
|
+
_a.sent();
|
|
192
|
+
if (!this.db || !this.useIndexedDB) {
|
|
193
|
+
return [2 /*return*/, []];
|
|
194
|
+
}
|
|
195
|
+
_a.label = 3;
|
|
196
|
+
case 3: return [2 /*return*/, new Promise(function (resolve, reject) {
|
|
197
|
+
var transaction = _this.db.transaction([_this.STORE_NAME], 'readonly');
|
|
198
|
+
var store = transaction.objectStore(_this.STORE_NAME);
|
|
199
|
+
var index = store.index('timestamp');
|
|
200
|
+
var request = index.openCursor(null, 'next');
|
|
201
|
+
var logs = [];
|
|
202
|
+
transaction.onerror = function () {
|
|
203
|
+
var _a, _b;
|
|
204
|
+
if (((_a = transaction.error) === null || _a === void 0 ? void 0 : _a.name) === 'UnknownError' || ((_b = transaction.error) === null || _b === void 0 ? void 0 : _b.name) === 'NotFoundError') {
|
|
205
|
+
_this.recreateDatabase().catch(function (error) {
|
|
206
|
+
console.warn('Database recreation failed:', error);
|
|
207
|
+
_this.useIndexedDB = false;
|
|
208
|
+
}).finally(function () { return resolve([]); });
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
reject(transaction.error);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
request.onsuccess = function (event) {
|
|
215
|
+
var cursor = event.target.result;
|
|
216
|
+
if (cursor && logs.length < limit) {
|
|
217
|
+
logs.push(cursor.value);
|
|
218
|
+
cursor.continue();
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
resolve(logs.map(function (item) {
|
|
222
|
+
var _a;
|
|
223
|
+
return __assign(__assign({}, item), { id: (_a = item.id) === null || _a === void 0 ? void 0 : _a.toString() });
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
request.onerror = function () {
|
|
228
|
+
var _a, _b;
|
|
229
|
+
if (((_a = request.error) === null || _a === void 0 ? void 0 : _a.name) === 'UnknownError' || ((_b = request.error) === null || _b === void 0 ? void 0 : _b.name) === 'NotFoundError') {
|
|
230
|
+
_this.recreateDatabase().catch(function (error) {
|
|
231
|
+
console.warn('Database recreation failed:', error);
|
|
232
|
+
_this.useIndexedDB = false;
|
|
233
|
+
}).finally(function () { return resolve([]); });
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
reject(request.error);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
})];
|
|
240
|
+
case 4:
|
|
241
|
+
error_2 = _a.sent();
|
|
242
|
+
this.useIndexedDB = false;
|
|
243
|
+
return [2 /*return*/, []];
|
|
244
|
+
case 5: return [2 /*return*/];
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
};
|
|
249
|
+
AliTrackLogger.prototype.deleteLogsFromIndexedDB = function (logsToDelete) {
|
|
250
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
251
|
+
var error_3;
|
|
252
|
+
var _this = this;
|
|
253
|
+
return __generator(this, function (_a) {
|
|
254
|
+
switch (_a.label) {
|
|
255
|
+
case 0:
|
|
256
|
+
if (!this.useIndexedDB || logsToDelete.length === 0)
|
|
257
|
+
return [2 /*return*/];
|
|
258
|
+
_a.label = 1;
|
|
259
|
+
case 1:
|
|
260
|
+
_a.trys.push([1, 4, , 5]);
|
|
261
|
+
if (!(!this.db || !this.isDatabaseHealthy())) return [3 /*break*/, 3];
|
|
262
|
+
return [4 /*yield*/, this.recreateDatabase()];
|
|
263
|
+
case 2:
|
|
264
|
+
_a.sent();
|
|
265
|
+
if (!this.db || !this.useIndexedDB) {
|
|
266
|
+
return [2 /*return*/];
|
|
267
|
+
}
|
|
268
|
+
_a.label = 3;
|
|
269
|
+
case 3: return [2 /*return*/, new Promise(function (resolve, reject) {
|
|
270
|
+
var transaction = _this.db.transaction([_this.STORE_NAME], 'readwrite');
|
|
271
|
+
var store = transaction.objectStore(_this.STORE_NAME);
|
|
272
|
+
var deletePromises = logsToDelete.map(function (log) {
|
|
273
|
+
return new Promise(function (resolveDelete, rejectDelete) {
|
|
274
|
+
var logId = Number(log.id);
|
|
275
|
+
if (logId) {
|
|
276
|
+
var request_2 = store.delete(logId);
|
|
277
|
+
request_2.onsuccess = function () { return resolveDelete(); };
|
|
278
|
+
request_2.onerror = function () {
|
|
279
|
+
var _a, _b;
|
|
280
|
+
if (((_a = request_2.error) === null || _a === void 0 ? void 0 : _a.name) === 'UnknownError' || ((_b = request_2.error) === null || _b === void 0 ? void 0 : _b.name) === 'NotFoundError') {
|
|
281
|
+
// Database might have been deleted, ignore deletion errors
|
|
282
|
+
resolveDelete();
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
rejectDelete(request_2.error);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
resolveDelete();
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
transaction.onerror = function () {
|
|
295
|
+
var _a, _b;
|
|
296
|
+
if (((_a = transaction.error) === null || _a === void 0 ? void 0 : _a.name) === 'UnknownError' || ((_b = transaction.error) === null || _b === void 0 ? void 0 : _b.name) === 'NotFoundError') {
|
|
297
|
+
_this.recreateDatabase().catch(function (error) {
|
|
298
|
+
console.warn('Database recreation failed:', error);
|
|
299
|
+
_this.useIndexedDB = false;
|
|
300
|
+
}).finally(function () { return resolve(); });
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
reject(transaction.error);
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
Promise.all(deletePromises)
|
|
307
|
+
.then(function () { return resolve(); })
|
|
308
|
+
.catch(reject);
|
|
309
|
+
})];
|
|
310
|
+
case 4:
|
|
311
|
+
error_3 = _a.sent();
|
|
312
|
+
this.useIndexedDB = false;
|
|
313
|
+
return [3 /*break*/, 5];
|
|
314
|
+
case 5: return [2 /*return*/];
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
};
|
|
319
|
+
AliTrackLogger.prototype.start = function () {
|
|
320
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
321
|
+
var _this = this;
|
|
322
|
+
return __generator(this, function (_a) {
|
|
323
|
+
clearInterval(this.checkTimer);
|
|
324
|
+
this.checkTimer = setInterval(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
325
|
+
return __generator(this, function (_a) {
|
|
326
|
+
switch (_a.label) {
|
|
327
|
+
case 0: return [4 /*yield*/, this.uploadLog()];
|
|
328
|
+
case 1:
|
|
329
|
+
_a.sent();
|
|
330
|
+
return [2 /*return*/];
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}); }, this.config.checkTime);
|
|
334
|
+
return [2 /*return*/];
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
};
|
|
338
|
+
AliTrackLogger.prototype.pause = function () {
|
|
339
|
+
clearInterval(this.checkTimer);
|
|
340
|
+
};
|
|
341
|
+
AliTrackLogger.prototype.addLog = function (message, level, taskId, randomId) {
|
|
342
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
343
|
+
var log, error_4;
|
|
344
|
+
return __generator(this, function (_a) {
|
|
345
|
+
switch (_a.label) {
|
|
346
|
+
case 0:
|
|
347
|
+
log = { level: level, taskId: taskId, message: message, randomId: randomId, timestamp: Date.now().toString() };
|
|
348
|
+
if (!this.useIndexedDB) return [3 /*break*/, 5];
|
|
349
|
+
_a.label = 1;
|
|
350
|
+
case 1:
|
|
351
|
+
_a.trys.push([1, 3, , 4]);
|
|
352
|
+
return [4 /*yield*/, this.storeLogInIndexedDB(log)];
|
|
353
|
+
case 2:
|
|
354
|
+
_a.sent();
|
|
355
|
+
return [3 /*break*/, 4];
|
|
356
|
+
case 3:
|
|
357
|
+
error_4 = _a.sent();
|
|
358
|
+
this.logList.push(log);
|
|
359
|
+
return [3 /*break*/, 4];
|
|
360
|
+
case 4: return [3 /*break*/, 6];
|
|
361
|
+
case 5:
|
|
362
|
+
this.logList.push(log);
|
|
363
|
+
_a.label = 6;
|
|
364
|
+
case 6: return [2 /*return*/];
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
};
|
|
369
|
+
AliTrackLogger.prototype.isDatabaseHealthy = function () {
|
|
370
|
+
if (!this.db)
|
|
371
|
+
return false;
|
|
372
|
+
try {
|
|
373
|
+
// Check if the database connection is still valid and object store exists
|
|
374
|
+
var transaction = this.db.transaction([this.STORE_NAME], 'readonly');
|
|
375
|
+
var store = transaction.objectStore(this.STORE_NAME);
|
|
376
|
+
// Actually try to access the store to validate it exists and works
|
|
377
|
+
var index = store.index('timestamp');
|
|
378
|
+
return true;
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
console.warn('Database health check failed:', error);
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
AliTrackLogger.prototype.recreateDatabase = function () {
|
|
386
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
387
|
+
var _this = this;
|
|
388
|
+
return __generator(this, function (_a) {
|
|
389
|
+
return [2 /*return*/, new Promise(function (resolve, reject) {
|
|
390
|
+
try {
|
|
391
|
+
// Close existing connection if any
|
|
392
|
+
if (_this.db) {
|
|
393
|
+
_this.db.close();
|
|
394
|
+
_this.db = null;
|
|
395
|
+
}
|
|
396
|
+
var request_3 = indexedDB.open(_this.DB_NAME, 1);
|
|
397
|
+
request_3.onerror = function () {
|
|
398
|
+
_this.useIndexedDB = false;
|
|
399
|
+
reject(request_3.error);
|
|
400
|
+
};
|
|
401
|
+
request_3.onsuccess = function () {
|
|
402
|
+
_this.db = request_3.result;
|
|
403
|
+
_this.useIndexedDB = true;
|
|
404
|
+
resolve();
|
|
405
|
+
};
|
|
406
|
+
request_3.onupgradeneeded = function (event) {
|
|
407
|
+
var db = event.target.result;
|
|
408
|
+
if (!db.objectStoreNames.contains(_this.STORE_NAME)) {
|
|
409
|
+
var store = db.createObjectStore(_this.STORE_NAME, { keyPath: 'id', autoIncrement: true });
|
|
410
|
+
store.createIndex('timestamp', 'timestamp');
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
_this.useIndexedDB = false;
|
|
416
|
+
reject(error);
|
|
417
|
+
}
|
|
418
|
+
})];
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
};
|
|
422
|
+
AliTrackLogger.prototype.destroy = function () {
|
|
423
|
+
clearInterval(this.checkTimer);
|
|
424
|
+
window.removeEventListener("message", this.uploadLoggerGlobalEvent);
|
|
425
|
+
if (this.db) {
|
|
426
|
+
this.db.close();
|
|
427
|
+
this.db = null;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
AliTrackLogger.prototype.uploadLog = function (focus) {
|
|
431
|
+
if (focus === void 0) { focus = false; }
|
|
432
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
433
|
+
var uploadLog, errHandle, res, e_1;
|
|
434
|
+
var _this = this;
|
|
435
|
+
return __generator(this, function (_a) {
|
|
436
|
+
switch (_a.label) {
|
|
437
|
+
case 0:
|
|
438
|
+
uploadLog = [];
|
|
439
|
+
if (!this.useIndexedDB) return [3 /*break*/, 2];
|
|
440
|
+
return [4 /*yield*/, this.getLogsFromIndexedDB(this.BATCH_SIZE)];
|
|
441
|
+
case 1:
|
|
442
|
+
uploadLog = _a.sent();
|
|
443
|
+
if (uploadLog.length === 0) {
|
|
444
|
+
return [2 /*return*/];
|
|
445
|
+
}
|
|
446
|
+
return [3 /*break*/, 3];
|
|
447
|
+
case 2:
|
|
448
|
+
if (!(this.logList.length >= this.config.buffer || focus)) {
|
|
449
|
+
return [2 /*return*/];
|
|
450
|
+
}
|
|
451
|
+
uploadLog = this.logList.splice(0);
|
|
452
|
+
_a.label = 3;
|
|
453
|
+
case 3:
|
|
454
|
+
errHandle = function () {
|
|
455
|
+
if (!_this.useIndexedDB) {
|
|
456
|
+
_this.logList = uploadLog.concat(_this.logList);
|
|
457
|
+
}
|
|
458
|
+
if (_this.retryTimes > 3) {
|
|
459
|
+
_this.pause();
|
|
460
|
+
}
|
|
461
|
+
_this.retryTimes += 1;
|
|
462
|
+
};
|
|
463
|
+
_a.label = 4;
|
|
464
|
+
case 4:
|
|
465
|
+
_a.trys.push([4, 10, , 11]);
|
|
466
|
+
return [4 /*yield*/, fetch("https://netless-ppt-plugin-dev.cn-hangzhou.log.aliyuncs.com/logstores/netless-ppt-plugin-dev/track", {
|
|
467
|
+
method: "POST",
|
|
468
|
+
headers: {
|
|
469
|
+
"x-log-apiversion": "0.6.0",
|
|
470
|
+
"Content-Type": "application/json",
|
|
471
|
+
"Accept": "*/*"
|
|
472
|
+
},
|
|
473
|
+
body: JSON.stringify({
|
|
474
|
+
__topic__: "netless-ppt-plugin-dev",
|
|
475
|
+
__source__: "netless-ppt-plugin-dev",
|
|
476
|
+
__logs__: uploadLog,
|
|
477
|
+
})
|
|
478
|
+
})];
|
|
479
|
+
case 5:
|
|
480
|
+
res = _a.sent();
|
|
481
|
+
if (!res.ok) return [3 /*break*/, 8];
|
|
482
|
+
this.retryTimes = 0;
|
|
483
|
+
if (!this.useIndexedDB) return [3 /*break*/, 7];
|
|
484
|
+
return [4 /*yield*/, this.deleteLogsFromIndexedDB(uploadLog)];
|
|
485
|
+
case 6:
|
|
486
|
+
_a.sent();
|
|
487
|
+
_a.label = 7;
|
|
488
|
+
case 7: return [3 /*break*/, 9];
|
|
489
|
+
case 8:
|
|
490
|
+
errHandle();
|
|
491
|
+
_a.label = 9;
|
|
492
|
+
case 9: return [3 /*break*/, 11];
|
|
493
|
+
case 10:
|
|
494
|
+
e_1 = _a.sent();
|
|
495
|
+
console.warn(e_1);
|
|
496
|
+
errHandle();
|
|
497
|
+
return [3 /*break*/, 11];
|
|
498
|
+
case 11: return [2 /*return*/];
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
};
|
|
503
|
+
AliTrackLogger.prototype.setEnable = function (enable) {
|
|
504
|
+
if (this.enable === enable) {
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
if (enable) {
|
|
508
|
+
this.start();
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
this.pause();
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
return AliTrackLogger;
|
|
515
|
+
}());
|
|
516
|
+
export { AliTrackLogger };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
var FrozenTaskManager = /** @class */ (function () {
|
|
2
|
+
function FrozenTaskManager() {
|
|
3
|
+
var _this = this;
|
|
4
|
+
this.tasks = [];
|
|
5
|
+
this.isDestroy = false;
|
|
6
|
+
this.isScheduling = false;
|
|
7
|
+
this.schedule = function () {
|
|
8
|
+
_this.isScheduling = true;
|
|
9
|
+
var task = _this.tasks.shift();
|
|
10
|
+
if (task && !_this.isDestroy) {
|
|
11
|
+
task.status = "running";
|
|
12
|
+
task.fn.apply(null).then(function () {
|
|
13
|
+
if (_this.tasks.length > 0) {
|
|
14
|
+
setTimeout(_this.schedule);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
_this.isScheduling = false;
|
|
18
|
+
}
|
|
19
|
+
}).catch(function () {
|
|
20
|
+
if (_this.tasks.length > 0) {
|
|
21
|
+
setTimeout(_this.schedule);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
_this.isScheduling = false;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
FrozenTaskManager.prototype.getRunningTask = function () {
|
|
31
|
+
if (this.tasks[0] && this.tasks[0].status === "running") {
|
|
32
|
+
return this.tasks[0];
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
};
|
|
36
|
+
FrozenTaskManager.prototype.addTask = function (type, fn) {
|
|
37
|
+
var task = {
|
|
38
|
+
type: type,
|
|
39
|
+
status: "wait",
|
|
40
|
+
fn: fn,
|
|
41
|
+
};
|
|
42
|
+
var runningTask = this.getRunningTask();
|
|
43
|
+
if (runningTask && type === runningTask.type) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
this.tasks = this.tasks.filter(function (v) { return v.type !== type; });
|
|
48
|
+
this.tasks.push(task);
|
|
49
|
+
if (!this.isScheduling) {
|
|
50
|
+
this.schedule();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
FrozenTaskManager.prototype.destroy = function () {
|
|
55
|
+
this.isDestroy = true;
|
|
56
|
+
};
|
|
57
|
+
return FrozenTaskManager;
|
|
58
|
+
}());
|
|
59
|
+
export { FrozenTaskManager };
|
package/lib/Lock.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
防止信令收发延迟高的时候, 用户狂点, 导致短时间触发多次信令的修改, 按照事件类型加同步锁, 即同一个事件类型仅有第一个事件生效, 多点不生效
|
|
3
|
+
*/
|
|
4
|
+
var Lock = /** @class */ (function () {
|
|
5
|
+
function Lock(available) {
|
|
6
|
+
this.autoUnlock = Object.create(null);
|
|
7
|
+
this.localKeyAutoRemove = Object.create(null);
|
|
8
|
+
this.localKeys = Object.create(null);
|
|
9
|
+
this.locks = Object.create(null);
|
|
10
|
+
this.available = false;
|
|
11
|
+
this.available = available;
|
|
12
|
+
}
|
|
13
|
+
Lock.prototype.addLock = function (type, key) {
|
|
14
|
+
var _this = this;
|
|
15
|
+
if (!this.available) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
this.locks[type] = key;
|
|
19
|
+
this.localKeys[key] = true;
|
|
20
|
+
this.localKeyAutoRemove[key] = window.setTimeout(function () {
|
|
21
|
+
delete _this.localKeys[key];
|
|
22
|
+
delete _this.localKeyAutoRemove[key];
|
|
23
|
+
}, 60 * 1000);
|
|
24
|
+
this.autoUnlock[type] = window.setTimeout(function () {
|
|
25
|
+
delete _this.locks[type];
|
|
26
|
+
delete _this.autoUnlock[type];
|
|
27
|
+
}, 3000);
|
|
28
|
+
};
|
|
29
|
+
Lock.prototype.unlock = function (type, key) {
|
|
30
|
+
if (!this.available) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
var isLocalEvent = !!key && !!this.localKeys[key];
|
|
34
|
+
if (key && isLocalEvent) {
|
|
35
|
+
window.clearTimeout(this.localKeyAutoRemove[key]);
|
|
36
|
+
delete this.localKeys[key];
|
|
37
|
+
delete this.localKeyAutoRemove[key];
|
|
38
|
+
}
|
|
39
|
+
if (key && this.locks[type] && this.locks[type] === key) {
|
|
40
|
+
window.clearTimeout(this.autoUnlock[type]);
|
|
41
|
+
delete this.locks[type];
|
|
42
|
+
delete this.autoUnlock[type];
|
|
43
|
+
}
|
|
44
|
+
return isLocalEvent;
|
|
45
|
+
};
|
|
46
|
+
Lock.prototype.isLocked = function (type) {
|
|
47
|
+
if (!this.available) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return !!this.locks[type];
|
|
51
|
+
};
|
|
52
|
+
return Lock;
|
|
53
|
+
}());
|
|
54
|
+
export { Lock };
|