easyproctor-hml 2.7.5 → 2.7.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.
- package/esm/index.js +42 -103
- package/index.js +42 -103
- package/new-flow/chunk/BackgroundUploadService.d.ts +1 -0
- package/package.json +1 -1
- package/unpkg/easyproctor.min.js +57 -56
- package/unpkg/easyproctor.min.js.map +0 -7
package/esm/index.js
CHANGED
|
@@ -13476,13 +13476,8 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
13476
13476
|
async clearAllChunks(proctoringId2) {
|
|
13477
13477
|
const db = await this.connect();
|
|
13478
13478
|
return new Promise((resolve, reject) => {
|
|
13479
|
-
const transaction = db.transaction(
|
|
13480
|
-
|
|
13481
|
-
"readwrite"
|
|
13482
|
-
);
|
|
13483
|
-
const store = transaction.objectStore(
|
|
13484
|
-
_ChunkStorageService.STORE_NAME
|
|
13485
|
-
);
|
|
13479
|
+
const transaction = db.transaction(_ChunkStorageService.STORE_NAME, "readwrite");
|
|
13480
|
+
const store = transaction.objectStore(_ChunkStorageService.STORE_NAME);
|
|
13486
13481
|
const index = store.index("proctoringId");
|
|
13487
13482
|
const range = IDBKeyRange.only(proctoringId2);
|
|
13488
13483
|
const request = index.openCursor(range);
|
|
@@ -13491,34 +13486,13 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
13491
13486
|
if (cursor) {
|
|
13492
13487
|
cursor.delete();
|
|
13493
13488
|
cursor.continue();
|
|
13489
|
+
} else {
|
|
13490
|
+
resolve();
|
|
13494
13491
|
}
|
|
13495
13492
|
};
|
|
13496
13493
|
request.onerror = () => {
|
|
13497
13494
|
var _a2;
|
|
13498
|
-
reject(
|
|
13499
|
-
new Error(
|
|
13500
|
-
`Erro ao limpar chunks: ${(_a2 = request.error) == null ? void 0 : _a2.message}`
|
|
13501
|
-
)
|
|
13502
|
-
);
|
|
13503
|
-
};
|
|
13504
|
-
transaction.oncomplete = () => {
|
|
13505
|
-
resolve();
|
|
13506
|
-
};
|
|
13507
|
-
transaction.onerror = () => {
|
|
13508
|
-
var _a2;
|
|
13509
|
-
reject(
|
|
13510
|
-
new Error(
|
|
13511
|
-
`Transaction error: ${(_a2 = transaction.error) == null ? void 0 : _a2.message}`
|
|
13512
|
-
)
|
|
13513
|
-
);
|
|
13514
|
-
};
|
|
13515
|
-
transaction.onabort = () => {
|
|
13516
|
-
var _a2;
|
|
13517
|
-
reject(
|
|
13518
|
-
new Error(
|
|
13519
|
-
`Transaction aborted: ${(_a2 = transaction.error) == null ? void 0 : _a2.message}`
|
|
13520
|
-
)
|
|
13521
|
-
);
|
|
13495
|
+
return reject(new Error(`Erro ao limpar todos os chunks: ${(_a2 = request.error) == null ? void 0 : _a2.message}`));
|
|
13522
13496
|
};
|
|
13523
13497
|
});
|
|
13524
13498
|
}
|
|
@@ -13577,7 +13551,7 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
13577
13551
|
}
|
|
13578
13552
|
};
|
|
13579
13553
|
_ChunkStorageService.DB_NAME = "EasyProctorChunksDb";
|
|
13580
|
-
/** v2: índices numéricos; v3: payload
|
|
13554
|
+
/** v2: índices numéricos; v3: payload em ArrayBuffer (Safari/iOS com Blob no IDB) */
|
|
13581
13555
|
_ChunkStorageService.DB_VERSION = 3;
|
|
13582
13556
|
_ChunkStorageService.STORE_NAME = "chunks";
|
|
13583
13557
|
var ChunkStorageService = _ChunkStorageService;
|
|
@@ -13738,7 +13712,7 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
13738
13712
|
* @param isFinal Se true, não alinha a 256KB e fecha a sessão com /TOTAL no header.
|
|
13739
13713
|
*/
|
|
13740
13714
|
async processQueue(isFinal = false) {
|
|
13741
|
-
var _a2, _b;
|
|
13715
|
+
var _a2, _b, _c2, _d, _e3, _f;
|
|
13742
13716
|
if (this.isProcessing) return;
|
|
13743
13717
|
this.isProcessing = true;
|
|
13744
13718
|
try {
|
|
@@ -13760,41 +13734,32 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
13760
13734
|
console.log(`[BackgroundUpload] ${pendingChunks.length} chunks pendentes encontrados. Modo final: ${isFinal}`);
|
|
13761
13735
|
let virtualStart = this.totalBytesPurged;
|
|
13762
13736
|
const chunksWithMeta = allChunks.map((c3) => {
|
|
13763
|
-
const byteLen = c3.arrayBuffer.byteLength;
|
|
13764
13737
|
const start = virtualStart;
|
|
13765
|
-
const end = start +
|
|
13766
|
-
virtualStart +=
|
|
13738
|
+
const end = start + c3.arrayBuffer.byteLength - 1;
|
|
13739
|
+
virtualStart += c3.arrayBuffer.byteLength;
|
|
13767
13740
|
return { chunk: c3, start, end };
|
|
13768
13741
|
});
|
|
13769
|
-
const
|
|
13742
|
+
const combinedBufferParts = [];
|
|
13770
13743
|
let lastProcessedChunkId = null;
|
|
13771
13744
|
let finalChunkIndex = 0;
|
|
13772
|
-
|
|
13745
|
+
const mimeType = (_d = (_c2 = (_a2 = pendingChunks[0]) == null ? void 0 : _a2.mimeType) != null ? _c2 : (_b = allChunks[allChunks.length - 1]) == null ? void 0 : _b.mimeType) != null ? _d : "video/webm";
|
|
13773
13746
|
for (const meta of chunksWithMeta) {
|
|
13774
13747
|
if (this.currentOffset > meta.end) continue;
|
|
13775
13748
|
const sliceStart = Math.max(0, this.currentOffset - meta.start);
|
|
13776
|
-
const
|
|
13777
|
-
|
|
13749
|
+
const chunkSlice = meta.chunk.arrayBuffer.slice(sliceStart);
|
|
13750
|
+
combinedBufferParts.push(chunkSlice);
|
|
13778
13751
|
lastProcessedChunkId = meta.chunk.id;
|
|
13779
13752
|
finalChunkIndex = meta.chunk.chunkIndex;
|
|
13780
13753
|
}
|
|
13781
|
-
if (
|
|
13754
|
+
if (combinedBufferParts.length === 0 && !isFinal) {
|
|
13782
13755
|
this.isProcessing = false;
|
|
13783
13756
|
return;
|
|
13784
13757
|
}
|
|
13785
|
-
const
|
|
13786
|
-
|
|
13787
|
-
{
|
|
13788
|
-
let off = 0;
|
|
13789
|
-
for (const p3 of sliceParts) {
|
|
13790
|
-
combined.set(p3, off);
|
|
13791
|
-
off += p3.length;
|
|
13792
|
-
}
|
|
13793
|
-
}
|
|
13794
|
-
let sendableSize = combined.byteLength;
|
|
13758
|
+
const fullBuffer = _BackgroundUploadService.concatArrayBuffers(combinedBufferParts);
|
|
13759
|
+
let sendableSize = fullBuffer.byteLength;
|
|
13795
13760
|
let totalSizeForHeader = void 0;
|
|
13796
13761
|
if (!isFinal) {
|
|
13797
|
-
sendableSize = Math.floor(
|
|
13762
|
+
sendableSize = Math.floor(fullBuffer.byteLength / this.GCS_CHUNK_SIZE) * this.GCS_CHUNK_SIZE;
|
|
13798
13763
|
if (sendableSize === 0) {
|
|
13799
13764
|
console.log("[BackgroundUpload] Dados insuficientes para atingir 256KB. Aguardando novo chunk...");
|
|
13800
13765
|
this.isProcessing = false;
|
|
@@ -13803,19 +13768,14 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
13803
13768
|
} else {
|
|
13804
13769
|
totalSizeForHeader = virtualStart;
|
|
13805
13770
|
}
|
|
13806
|
-
const
|
|
13771
|
+
const bufferToSend = sendableSize < fullBuffer.byteLength ? fullBuffer.slice(0, sendableSize) : fullBuffer;
|
|
13807
13772
|
try {
|
|
13808
|
-
await this.uploadData(
|
|
13809
|
-
payload.byteLength > 0 ? payload : null,
|
|
13810
|
-
mimeType,
|
|
13811
|
-
finalChunkIndex,
|
|
13812
|
-
totalSizeForHeader
|
|
13813
|
-
);
|
|
13773
|
+
await this.uploadData(bufferToSend, mimeType, finalChunkIndex, totalSizeForHeader);
|
|
13814
13774
|
for (const meta of chunksWithMeta) {
|
|
13815
13775
|
if (meta.chunk.uploaded === 0 && meta.end < this.currentOffset) {
|
|
13816
13776
|
await this.chunkStorage.markAsUploaded(meta.chunk.id);
|
|
13817
13777
|
this.retryCount.delete(meta.chunk.id);
|
|
13818
|
-
(
|
|
13778
|
+
(_e3 = this.onChunkUploaded) == null ? void 0 : _e3.call(this, meta.chunk.id, meta.chunk.chunkIndex);
|
|
13819
13779
|
console.log(`[BackgroundUpload] Chunk ${meta.chunk.chunkIndex} marcado como enviado.`);
|
|
13820
13780
|
}
|
|
13821
13781
|
}
|
|
@@ -13837,7 +13797,7 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
13837
13797
|
}
|
|
13838
13798
|
} catch (error) {
|
|
13839
13799
|
console.error("[BackgroundUpload] Falha no upload:", error);
|
|
13840
|
-
(
|
|
13800
|
+
(_f = this.onUploadError) == null ? void 0 : _f.call(this, lastProcessedChunkId || 0, error);
|
|
13841
13801
|
}
|
|
13842
13802
|
} catch (error) {
|
|
13843
13803
|
console.error("[BackgroundUpload] Erro ao processar fila:", error);
|
|
@@ -13848,8 +13808,18 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
13848
13808
|
/**
|
|
13849
13809
|
* Faz o upload bruto de dados para a sessão GCS.
|
|
13850
13810
|
*/
|
|
13851
|
-
|
|
13852
|
-
|
|
13811
|
+
static concatArrayBuffers(parts) {
|
|
13812
|
+
if (parts.length === 0) return new ArrayBuffer(0);
|
|
13813
|
+
const total = parts.reduce((sum, p3) => sum + p3.byteLength, 0);
|
|
13814
|
+
const merged = new Uint8Array(total);
|
|
13815
|
+
let offset = 0;
|
|
13816
|
+
for (const p3 of parts) {
|
|
13817
|
+
merged.set(new Uint8Array(p3), offset);
|
|
13818
|
+
offset += p3.byteLength;
|
|
13819
|
+
}
|
|
13820
|
+
return merged.buffer.byteLength === total ? merged.buffer : merged.buffer.slice(merged.byteOffset, merged.byteOffset + merged.byteLength);
|
|
13821
|
+
}
|
|
13822
|
+
async uploadData(data, mimeType, chunkIndex, totalSize) {
|
|
13853
13823
|
const fileName = `EP_${this.proctoringId}_camera_0.webm`;
|
|
13854
13824
|
if (!this.sessionUrl) {
|
|
13855
13825
|
const initiateUrl = await this.backend.initiateUpload(this.token, `${this.proctoringId}/${fileName}`, mimeType);
|
|
@@ -13880,28 +13850,17 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
13880
13850
|
} else {
|
|
13881
13851
|
console.log(`[BackgroundUpload] Usando sess\xE3o GCS existente: ${this.sessionUrl}`);
|
|
13882
13852
|
}
|
|
13883
|
-
const size = (_a2 = body == null ? void 0 : body.byteLength) != null ? _a2 : 0;
|
|
13884
13853
|
const start = this.currentOffset;
|
|
13885
|
-
const end = start +
|
|
13854
|
+
const end = start + data.byteLength - 1;
|
|
13886
13855
|
const totalHeader = totalSize !== void 0 ? totalSize.toString() : "*";
|
|
13887
|
-
const contentRangeHeader =
|
|
13856
|
+
const contentRangeHeader = data.byteLength === 0 && totalSize !== void 0 ? `bytes */${totalHeader}` : `bytes ${start}-${end}/${totalHeader}`;
|
|
13888
13857
|
console.log(
|
|
13889
|
-
`[BackgroundUpload] Enviando ${
|
|
13858
|
+
`[BackgroundUpload] Enviando ${data.byteLength > 0 ? "dados" : "finaliza\xE7\xE3o"}: ${contentRangeHeader} (Size: ${data.byteLength})`
|
|
13890
13859
|
);
|
|
13891
|
-
let uploadBody = null;
|
|
13892
|
-
if (size > 0 && body) {
|
|
13893
|
-
const raw = body.buffer;
|
|
13894
|
-
if (raw instanceof ArrayBuffer) {
|
|
13895
|
-
uploadBody = body.byteOffset === 0 && body.byteLength === raw.byteLength ? raw : raw.slice(body.byteOffset, body.byteOffset + body.byteLength);
|
|
13896
|
-
} else {
|
|
13897
|
-
uploadBody = new ArrayBuffer(body.byteLength);
|
|
13898
|
-
new Uint8Array(uploadBody).set(body);
|
|
13899
|
-
}
|
|
13900
|
-
}
|
|
13901
13860
|
const response = await fetch(this.sessionUrl, {
|
|
13902
13861
|
method: "PUT",
|
|
13903
13862
|
headers: { "Content-Range": contentRangeHeader },
|
|
13904
|
-
body:
|
|
13863
|
+
body: data.byteLength > 0 ? data : null
|
|
13905
13864
|
});
|
|
13906
13865
|
console.log(`[BackgroundUpload] Resposta GCS (uploadData): ${response.status}`);
|
|
13907
13866
|
if (response.status !== 200 && response.status !== 201 && response.status !== 308) {
|
|
@@ -13914,13 +13873,13 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
13914
13873
|
const lastByte = parseInt(rangeHeader.split("-")[1], 10);
|
|
13915
13874
|
this.currentOffset = lastByte + 1;
|
|
13916
13875
|
} else {
|
|
13917
|
-
this.currentOffset +=
|
|
13876
|
+
this.currentOffset += data.byteLength;
|
|
13918
13877
|
}
|
|
13919
13878
|
this.saveSessionState();
|
|
13920
13879
|
trackers.registerUploadFile(
|
|
13921
13880
|
this.proctoringId,
|
|
13922
13881
|
`GCS Stream Upload
|
|
13923
|
-
Size: ${
|
|
13882
|
+
Size: ${data.byteLength}
|
|
13924
13883
|
Range: ${start}-${end}
|
|
13925
13884
|
Last Index: ${chunkIndex}`,
|
|
13926
13885
|
"CameraChunk"
|
|
@@ -14439,23 +14398,19 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
14439
14398
|
}
|
|
14440
14399
|
if (this.isChunkEnabled) {
|
|
14441
14400
|
if (this.backgroundUpload) {
|
|
14442
|
-
trackers.registerError(this.proctoringId, `Flush e parada do background upload`);
|
|
14443
14401
|
try {
|
|
14444
14402
|
if (this.pendingChunkSaves.length > 0) {
|
|
14445
14403
|
console.log(`[CameraRecorder] Aguardando ${this.pendingChunkSaves.length} salvamentos de chunks pendentes...`);
|
|
14446
14404
|
await Promise.all(this.pendingChunkSaves);
|
|
14447
14405
|
}
|
|
14448
14406
|
await this.backgroundUpload.flush();
|
|
14449
|
-
this.backgroundUpload.stop();
|
|
14450
14407
|
} catch (e3) {
|
|
14451
14408
|
console.warn("[CameraRecorder] Erro ao fazer flush dos chunks:", e3);
|
|
14452
|
-
trackers.registerError(this.proctoringId, `Flush Chunks
|
|
14453
|
-
Error: ${e3}`);
|
|
14454
14409
|
}
|
|
14410
|
+
this.backgroundUpload.stop();
|
|
14455
14411
|
}
|
|
14456
14412
|
this.removeLifecycleListeners();
|
|
14457
14413
|
this.persistSessionState("FINISHED");
|
|
14458
|
-
trackers.registerError(this.proctoringId, `Finalizando flush e parada do background upload`);
|
|
14459
14414
|
}
|
|
14460
14415
|
}
|
|
14461
14416
|
/**
|
|
@@ -14479,8 +14434,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
14479
14434
|
this.chunkIndex++;
|
|
14480
14435
|
console.log(`[CameraRecorder] Chunk ${this.chunkIndex - 1} salvo no IndexedDB.`);
|
|
14481
14436
|
} catch (error) {
|
|
14482
|
-
trackers.registerError(this.proctoringId, `Save Chunk
|
|
14483
|
-
Error: ${error}`);
|
|
14484
14437
|
console.error("[CameraRecorder] Erro ao salvar chunk no IndexedDB:", error);
|
|
14485
14438
|
}
|
|
14486
14439
|
})();
|
|
@@ -14629,7 +14582,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
14629
14582
|
const settingsAudio = this.cameraStream.getAudioTracks()[0].getSettings();
|
|
14630
14583
|
if (this.options.proctoringType == "VIDEO" || this.options.proctoringType == "REALTIME" || this.options.proctoringType == "IMAGE" && ((_a2 = this.paramsConfig.imageBehaviourParameters) == null ? void 0 : _a2.saveVideo)) {
|
|
14631
14584
|
let videoFile;
|
|
14632
|
-
trackers.registerError(this.proctoringId, `saveOnSession iniciando`);
|
|
14633
14585
|
if (this.isChunkEnabled) {
|
|
14634
14586
|
const isStable = await this.checkInternetStability();
|
|
14635
14587
|
if (isStable) {
|
|
@@ -14638,19 +14590,13 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
14638
14590
|
const fileName = `EP_${this.proctoringId}_camera_0.webm`;
|
|
14639
14591
|
const objectName = `${this.proctoringId}/${fileName}`;
|
|
14640
14592
|
const isUploaded = await this.backend.checkUpload(this.backendToken, objectName, "video/webm");
|
|
14641
|
-
trackers.registerError(this.proctoringId, `Limpa o armazenamento local pois o v\xEDdeo j\xE1 est\xE1 no servidor`);
|
|
14642
14593
|
if (isUploaded) {
|
|
14643
|
-
|
|
14644
|
-
this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
|
|
14645
|
-
} catch (e3) {
|
|
14646
|
-
trackers.registerError(this.proctoringId, `Erro ao limpar o armazenamento local: ${e3}`);
|
|
14647
|
-
}
|
|
14594
|
+
this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
|
|
14648
14595
|
return;
|
|
14649
14596
|
}
|
|
14650
14597
|
}
|
|
14651
14598
|
}
|
|
14652
14599
|
}
|
|
14653
|
-
trackers.registerError(this.proctoringId, `saveOnSession gerando v\xEDdeo a partir do buffer em mem\xF3ria (\xEDntegra)`);
|
|
14654
14600
|
const rawBlob = new Blob(this.blobs, {
|
|
14655
14601
|
type: ((_b = this.recorderOptions) == null ? void 0 : _b.mimeType) || "video/webm"
|
|
14656
14602
|
});
|
|
@@ -14671,7 +14617,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
14671
14617
|
origin: "Camera" /* Camera */
|
|
14672
14618
|
});
|
|
14673
14619
|
}
|
|
14674
|
-
trackers.registerError(this.proctoringId, `saveOnSession finalizado`);
|
|
14675
14620
|
}
|
|
14676
14621
|
async getFile(file, name, type) {
|
|
14677
14622
|
return new Promise((resolve, reject) => {
|
|
@@ -23801,14 +23746,11 @@ Error: ${error}`
|
|
|
23801
23746
|
await this.recorder.stopAll();
|
|
23802
23747
|
this.spyCam && this.spyCam.stopCheckSpyCam();
|
|
23803
23748
|
this.appChecker && await this.appChecker.disconnectWebSocket();
|
|
23804
|
-
trackers.registerError(this.proctoringId, `finish saveAllOnSession`);
|
|
23805
23749
|
await this.recorder.saveAllOnSession();
|
|
23806
|
-
trackers.registerError(this.proctoringId, `finish sendPendingRealtimeAlerts`);
|
|
23807
23750
|
await this.sendPendingRealtimeAlerts();
|
|
23808
|
-
|
|
23751
|
+
await this.repository.save(this.proctoringSession);
|
|
23809
23752
|
let uploader;
|
|
23810
23753
|
let uploaderServices;
|
|
23811
|
-
trackers.registerError(this.proctoringId, `finish uploader`);
|
|
23812
23754
|
if (versionVerify() !== "1.0.0.0") {
|
|
23813
23755
|
uploader = new ProctoringUploader(
|
|
23814
23756
|
this.proctoringSession,
|
|
@@ -23882,7 +23824,6 @@ Upload Services: ${uploaderServices}`,
|
|
|
23882
23824
|
this.serviceType
|
|
23883
23825
|
);
|
|
23884
23826
|
}
|
|
23885
|
-
trackers.registerError(this.proctoringId, `finish uploader success`);
|
|
23886
23827
|
if (this.proctoringSession.alerts.length > 0) {
|
|
23887
23828
|
await this.backend.saveAlerts(this.context, this.proctoringSession).catch((err) => {
|
|
23888
23829
|
trackers.registerFinish(
|
|
@@ -23892,7 +23833,6 @@ Upload Services: ${uploaderServices}`,
|
|
|
23892
23833
|
);
|
|
23893
23834
|
});
|
|
23894
23835
|
}
|
|
23895
|
-
trackers.registerError(this.proctoringId, `finish saveAlerts ok`);
|
|
23896
23836
|
await this.backend.finishAndSendUrls(this.context).then((finishResponse) => {
|
|
23897
23837
|
var _a2, _b, _c2, _d;
|
|
23898
23838
|
trackers.registerFinish(this.proctoringSession.id, true, "");
|
|
@@ -23904,7 +23844,6 @@ Upload Services: ${uploaderServices}`,
|
|
|
23904
23844
|
"finish error: " + error
|
|
23905
23845
|
);
|
|
23906
23846
|
});
|
|
23907
|
-
trackers.registerError(this.proctoringId, `finish call`);
|
|
23908
23847
|
if (this.appChecker) {
|
|
23909
23848
|
const externalSessionId = this.appChecker.getExternalCameraSessionId();
|
|
23910
23849
|
if (externalSessionId != "null") {
|
package/index.js
CHANGED
|
@@ -31573,13 +31573,8 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
31573
31573
|
async clearAllChunks(proctoringId2) {
|
|
31574
31574
|
const db = await this.connect();
|
|
31575
31575
|
return new Promise((resolve, reject) => {
|
|
31576
|
-
const transaction = db.transaction(
|
|
31577
|
-
|
|
31578
|
-
"readwrite"
|
|
31579
|
-
);
|
|
31580
|
-
const store = transaction.objectStore(
|
|
31581
|
-
_ChunkStorageService.STORE_NAME
|
|
31582
|
-
);
|
|
31576
|
+
const transaction = db.transaction(_ChunkStorageService.STORE_NAME, "readwrite");
|
|
31577
|
+
const store = transaction.objectStore(_ChunkStorageService.STORE_NAME);
|
|
31583
31578
|
const index = store.index("proctoringId");
|
|
31584
31579
|
const range = IDBKeyRange.only(proctoringId2);
|
|
31585
31580
|
const request = index.openCursor(range);
|
|
@@ -31588,34 +31583,13 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
31588
31583
|
if (cursor) {
|
|
31589
31584
|
cursor.delete();
|
|
31590
31585
|
cursor.continue();
|
|
31586
|
+
} else {
|
|
31587
|
+
resolve();
|
|
31591
31588
|
}
|
|
31592
31589
|
};
|
|
31593
31590
|
request.onerror = () => {
|
|
31594
31591
|
var _a2;
|
|
31595
|
-
reject(
|
|
31596
|
-
new Error(
|
|
31597
|
-
`Erro ao limpar chunks: ${(_a2 = request.error) == null ? void 0 : _a2.message}`
|
|
31598
|
-
)
|
|
31599
|
-
);
|
|
31600
|
-
};
|
|
31601
|
-
transaction.oncomplete = () => {
|
|
31602
|
-
resolve();
|
|
31603
|
-
};
|
|
31604
|
-
transaction.onerror = () => {
|
|
31605
|
-
var _a2;
|
|
31606
|
-
reject(
|
|
31607
|
-
new Error(
|
|
31608
|
-
`Transaction error: ${(_a2 = transaction.error) == null ? void 0 : _a2.message}`
|
|
31609
|
-
)
|
|
31610
|
-
);
|
|
31611
|
-
};
|
|
31612
|
-
transaction.onabort = () => {
|
|
31613
|
-
var _a2;
|
|
31614
|
-
reject(
|
|
31615
|
-
new Error(
|
|
31616
|
-
`Transaction aborted: ${(_a2 = transaction.error) == null ? void 0 : _a2.message}`
|
|
31617
|
-
)
|
|
31618
|
-
);
|
|
31592
|
+
return reject(new Error(`Erro ao limpar todos os chunks: ${(_a2 = request.error) == null ? void 0 : _a2.message}`));
|
|
31619
31593
|
};
|
|
31620
31594
|
});
|
|
31621
31595
|
}
|
|
@@ -31674,7 +31648,7 @@ var _ChunkStorageService = class _ChunkStorageService {
|
|
|
31674
31648
|
}
|
|
31675
31649
|
};
|
|
31676
31650
|
_ChunkStorageService.DB_NAME = "EasyProctorChunksDb";
|
|
31677
|
-
/** v2: índices numéricos; v3: payload
|
|
31651
|
+
/** v2: índices numéricos; v3: payload em ArrayBuffer (Safari/iOS com Blob no IDB) */
|
|
31678
31652
|
_ChunkStorageService.DB_VERSION = 3;
|
|
31679
31653
|
_ChunkStorageService.STORE_NAME = "chunks";
|
|
31680
31654
|
var ChunkStorageService = _ChunkStorageService;
|
|
@@ -31835,7 +31809,7 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31835
31809
|
* @param isFinal Se true, não alinha a 256KB e fecha a sessão com /TOTAL no header.
|
|
31836
31810
|
*/
|
|
31837
31811
|
async processQueue(isFinal = false) {
|
|
31838
|
-
var _a2, _b;
|
|
31812
|
+
var _a2, _b, _c2, _d, _e3, _f;
|
|
31839
31813
|
if (this.isProcessing) return;
|
|
31840
31814
|
this.isProcessing = true;
|
|
31841
31815
|
try {
|
|
@@ -31857,41 +31831,32 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31857
31831
|
console.log(`[BackgroundUpload] ${pendingChunks.length} chunks pendentes encontrados. Modo final: ${isFinal}`);
|
|
31858
31832
|
let virtualStart = this.totalBytesPurged;
|
|
31859
31833
|
const chunksWithMeta = allChunks.map((c3) => {
|
|
31860
|
-
const byteLen = c3.arrayBuffer.byteLength;
|
|
31861
31834
|
const start = virtualStart;
|
|
31862
|
-
const end = start +
|
|
31863
|
-
virtualStart +=
|
|
31835
|
+
const end = start + c3.arrayBuffer.byteLength - 1;
|
|
31836
|
+
virtualStart += c3.arrayBuffer.byteLength;
|
|
31864
31837
|
return { chunk: c3, start, end };
|
|
31865
31838
|
});
|
|
31866
|
-
const
|
|
31839
|
+
const combinedBufferParts = [];
|
|
31867
31840
|
let lastProcessedChunkId = null;
|
|
31868
31841
|
let finalChunkIndex = 0;
|
|
31869
|
-
|
|
31842
|
+
const mimeType = (_d = (_c2 = (_a2 = pendingChunks[0]) == null ? void 0 : _a2.mimeType) != null ? _c2 : (_b = allChunks[allChunks.length - 1]) == null ? void 0 : _b.mimeType) != null ? _d : "video/webm";
|
|
31870
31843
|
for (const meta of chunksWithMeta) {
|
|
31871
31844
|
if (this.currentOffset > meta.end) continue;
|
|
31872
31845
|
const sliceStart = Math.max(0, this.currentOffset - meta.start);
|
|
31873
|
-
const
|
|
31874
|
-
|
|
31846
|
+
const chunkSlice = meta.chunk.arrayBuffer.slice(sliceStart);
|
|
31847
|
+
combinedBufferParts.push(chunkSlice);
|
|
31875
31848
|
lastProcessedChunkId = meta.chunk.id;
|
|
31876
31849
|
finalChunkIndex = meta.chunk.chunkIndex;
|
|
31877
31850
|
}
|
|
31878
|
-
if (
|
|
31851
|
+
if (combinedBufferParts.length === 0 && !isFinal) {
|
|
31879
31852
|
this.isProcessing = false;
|
|
31880
31853
|
return;
|
|
31881
31854
|
}
|
|
31882
|
-
const
|
|
31883
|
-
|
|
31884
|
-
{
|
|
31885
|
-
let off = 0;
|
|
31886
|
-
for (const p3 of sliceParts) {
|
|
31887
|
-
combined.set(p3, off);
|
|
31888
|
-
off += p3.length;
|
|
31889
|
-
}
|
|
31890
|
-
}
|
|
31891
|
-
let sendableSize = combined.byteLength;
|
|
31855
|
+
const fullBuffer = _BackgroundUploadService.concatArrayBuffers(combinedBufferParts);
|
|
31856
|
+
let sendableSize = fullBuffer.byteLength;
|
|
31892
31857
|
let totalSizeForHeader = void 0;
|
|
31893
31858
|
if (!isFinal) {
|
|
31894
|
-
sendableSize = Math.floor(
|
|
31859
|
+
sendableSize = Math.floor(fullBuffer.byteLength / this.GCS_CHUNK_SIZE) * this.GCS_CHUNK_SIZE;
|
|
31895
31860
|
if (sendableSize === 0) {
|
|
31896
31861
|
console.log("[BackgroundUpload] Dados insuficientes para atingir 256KB. Aguardando novo chunk...");
|
|
31897
31862
|
this.isProcessing = false;
|
|
@@ -31900,19 +31865,14 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31900
31865
|
} else {
|
|
31901
31866
|
totalSizeForHeader = virtualStart;
|
|
31902
31867
|
}
|
|
31903
|
-
const
|
|
31868
|
+
const bufferToSend = sendableSize < fullBuffer.byteLength ? fullBuffer.slice(0, sendableSize) : fullBuffer;
|
|
31904
31869
|
try {
|
|
31905
|
-
await this.uploadData(
|
|
31906
|
-
payload.byteLength > 0 ? payload : null,
|
|
31907
|
-
mimeType,
|
|
31908
|
-
finalChunkIndex,
|
|
31909
|
-
totalSizeForHeader
|
|
31910
|
-
);
|
|
31870
|
+
await this.uploadData(bufferToSend, mimeType, finalChunkIndex, totalSizeForHeader);
|
|
31911
31871
|
for (const meta of chunksWithMeta) {
|
|
31912
31872
|
if (meta.chunk.uploaded === 0 && meta.end < this.currentOffset) {
|
|
31913
31873
|
await this.chunkStorage.markAsUploaded(meta.chunk.id);
|
|
31914
31874
|
this.retryCount.delete(meta.chunk.id);
|
|
31915
|
-
(
|
|
31875
|
+
(_e3 = this.onChunkUploaded) == null ? void 0 : _e3.call(this, meta.chunk.id, meta.chunk.chunkIndex);
|
|
31916
31876
|
console.log(`[BackgroundUpload] Chunk ${meta.chunk.chunkIndex} marcado como enviado.`);
|
|
31917
31877
|
}
|
|
31918
31878
|
}
|
|
@@ -31934,7 +31894,7 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31934
31894
|
}
|
|
31935
31895
|
} catch (error) {
|
|
31936
31896
|
console.error("[BackgroundUpload] Falha no upload:", error);
|
|
31937
|
-
(
|
|
31897
|
+
(_f = this.onUploadError) == null ? void 0 : _f.call(this, lastProcessedChunkId || 0, error);
|
|
31938
31898
|
}
|
|
31939
31899
|
} catch (error) {
|
|
31940
31900
|
console.error("[BackgroundUpload] Erro ao processar fila:", error);
|
|
@@ -31945,8 +31905,18 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31945
31905
|
/**
|
|
31946
31906
|
* Faz o upload bruto de dados para a sessão GCS.
|
|
31947
31907
|
*/
|
|
31948
|
-
|
|
31949
|
-
|
|
31908
|
+
static concatArrayBuffers(parts) {
|
|
31909
|
+
if (parts.length === 0) return new ArrayBuffer(0);
|
|
31910
|
+
const total = parts.reduce((sum, p3) => sum + p3.byteLength, 0);
|
|
31911
|
+
const merged = new Uint8Array(total);
|
|
31912
|
+
let offset = 0;
|
|
31913
|
+
for (const p3 of parts) {
|
|
31914
|
+
merged.set(new Uint8Array(p3), offset);
|
|
31915
|
+
offset += p3.byteLength;
|
|
31916
|
+
}
|
|
31917
|
+
return merged.buffer.byteLength === total ? merged.buffer : merged.buffer.slice(merged.byteOffset, merged.byteOffset + merged.byteLength);
|
|
31918
|
+
}
|
|
31919
|
+
async uploadData(data, mimeType, chunkIndex, totalSize) {
|
|
31950
31920
|
const fileName = `EP_${this.proctoringId}_camera_0.webm`;
|
|
31951
31921
|
if (!this.sessionUrl) {
|
|
31952
31922
|
const initiateUrl = await this.backend.initiateUpload(this.token, `${this.proctoringId}/${fileName}`, mimeType);
|
|
@@ -31977,28 +31947,17 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
31977
31947
|
} else {
|
|
31978
31948
|
console.log(`[BackgroundUpload] Usando sess\xE3o GCS existente: ${this.sessionUrl}`);
|
|
31979
31949
|
}
|
|
31980
|
-
const size = (_a2 = body == null ? void 0 : body.byteLength) != null ? _a2 : 0;
|
|
31981
31950
|
const start = this.currentOffset;
|
|
31982
|
-
const end = start +
|
|
31951
|
+
const end = start + data.byteLength - 1;
|
|
31983
31952
|
const totalHeader = totalSize !== void 0 ? totalSize.toString() : "*";
|
|
31984
|
-
const contentRangeHeader =
|
|
31953
|
+
const contentRangeHeader = data.byteLength === 0 && totalSize !== void 0 ? `bytes */${totalHeader}` : `bytes ${start}-${end}/${totalHeader}`;
|
|
31985
31954
|
console.log(
|
|
31986
|
-
`[BackgroundUpload] Enviando ${
|
|
31955
|
+
`[BackgroundUpload] Enviando ${data.byteLength > 0 ? "dados" : "finaliza\xE7\xE3o"}: ${contentRangeHeader} (Size: ${data.byteLength})`
|
|
31987
31956
|
);
|
|
31988
|
-
let uploadBody = null;
|
|
31989
|
-
if (size > 0 && body) {
|
|
31990
|
-
const raw = body.buffer;
|
|
31991
|
-
if (raw instanceof ArrayBuffer) {
|
|
31992
|
-
uploadBody = body.byteOffset === 0 && body.byteLength === raw.byteLength ? raw : raw.slice(body.byteOffset, body.byteOffset + body.byteLength);
|
|
31993
|
-
} else {
|
|
31994
|
-
uploadBody = new ArrayBuffer(body.byteLength);
|
|
31995
|
-
new Uint8Array(uploadBody).set(body);
|
|
31996
|
-
}
|
|
31997
|
-
}
|
|
31998
31957
|
const response = await fetch(this.sessionUrl, {
|
|
31999
31958
|
method: "PUT",
|
|
32000
31959
|
headers: { "Content-Range": contentRangeHeader },
|
|
32001
|
-
body:
|
|
31960
|
+
body: data.byteLength > 0 ? data : null
|
|
32002
31961
|
});
|
|
32003
31962
|
console.log(`[BackgroundUpload] Resposta GCS (uploadData): ${response.status}`);
|
|
32004
31963
|
if (response.status !== 200 && response.status !== 201 && response.status !== 308) {
|
|
@@ -32011,13 +31970,13 @@ var BackgroundUploadService = class _BackgroundUploadService {
|
|
|
32011
31970
|
const lastByte = parseInt(rangeHeader.split("-")[1], 10);
|
|
32012
31971
|
this.currentOffset = lastByte + 1;
|
|
32013
31972
|
} else {
|
|
32014
|
-
this.currentOffset +=
|
|
31973
|
+
this.currentOffset += data.byteLength;
|
|
32015
31974
|
}
|
|
32016
31975
|
this.saveSessionState();
|
|
32017
31976
|
trackers.registerUploadFile(
|
|
32018
31977
|
this.proctoringId,
|
|
32019
31978
|
`GCS Stream Upload
|
|
32020
|
-
Size: ${
|
|
31979
|
+
Size: ${data.byteLength}
|
|
32021
31980
|
Range: ${start}-${end}
|
|
32022
31981
|
Last Index: ${chunkIndex}`,
|
|
32023
31982
|
"CameraChunk"
|
|
@@ -32536,23 +32495,19 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
32536
32495
|
}
|
|
32537
32496
|
if (this.isChunkEnabled) {
|
|
32538
32497
|
if (this.backgroundUpload) {
|
|
32539
|
-
trackers.registerError(this.proctoringId, `Flush e parada do background upload`);
|
|
32540
32498
|
try {
|
|
32541
32499
|
if (this.pendingChunkSaves.length > 0) {
|
|
32542
32500
|
console.log(`[CameraRecorder] Aguardando ${this.pendingChunkSaves.length} salvamentos de chunks pendentes...`);
|
|
32543
32501
|
await Promise.all(this.pendingChunkSaves);
|
|
32544
32502
|
}
|
|
32545
32503
|
await this.backgroundUpload.flush();
|
|
32546
|
-
this.backgroundUpload.stop();
|
|
32547
32504
|
} catch (e3) {
|
|
32548
32505
|
console.warn("[CameraRecorder] Erro ao fazer flush dos chunks:", e3);
|
|
32549
|
-
trackers.registerError(this.proctoringId, `Flush Chunks
|
|
32550
|
-
Error: ${e3}`);
|
|
32551
32506
|
}
|
|
32507
|
+
this.backgroundUpload.stop();
|
|
32552
32508
|
}
|
|
32553
32509
|
this.removeLifecycleListeners();
|
|
32554
32510
|
this.persistSessionState("FINISHED");
|
|
32555
|
-
trackers.registerError(this.proctoringId, `Finalizando flush e parada do background upload`);
|
|
32556
32511
|
}
|
|
32557
32512
|
}
|
|
32558
32513
|
/**
|
|
@@ -32576,8 +32531,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
32576
32531
|
this.chunkIndex++;
|
|
32577
32532
|
console.log(`[CameraRecorder] Chunk ${this.chunkIndex - 1} salvo no IndexedDB.`);
|
|
32578
32533
|
} catch (error) {
|
|
32579
|
-
trackers.registerError(this.proctoringId, `Save Chunk
|
|
32580
|
-
Error: ${error}`);
|
|
32581
32534
|
console.error("[CameraRecorder] Erro ao salvar chunk no IndexedDB:", error);
|
|
32582
32535
|
}
|
|
32583
32536
|
})();
|
|
@@ -32726,7 +32679,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
32726
32679
|
const settingsAudio = this.cameraStream.getAudioTracks()[0].getSettings();
|
|
32727
32680
|
if (this.options.proctoringType == "VIDEO" || this.options.proctoringType == "REALTIME" || this.options.proctoringType == "IMAGE" && ((_a2 = this.paramsConfig.imageBehaviourParameters) == null ? void 0 : _a2.saveVideo)) {
|
|
32728
32681
|
let videoFile;
|
|
32729
|
-
trackers.registerError(this.proctoringId, `saveOnSession iniciando`);
|
|
32730
32682
|
if (this.isChunkEnabled) {
|
|
32731
32683
|
const isStable = await this.checkInternetStability();
|
|
32732
32684
|
if (isStable) {
|
|
@@ -32735,19 +32687,13 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
32735
32687
|
const fileName = `EP_${this.proctoringId}_camera_0.webm`;
|
|
32736
32688
|
const objectName = `${this.proctoringId}/${fileName}`;
|
|
32737
32689
|
const isUploaded = await this.backend.checkUpload(this.backendToken, objectName, "video/webm");
|
|
32738
|
-
trackers.registerError(this.proctoringId, `Limpa o armazenamento local pois o v\xEDdeo j\xE1 est\xE1 no servidor`);
|
|
32739
32690
|
if (isUploaded) {
|
|
32740
|
-
|
|
32741
|
-
this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
|
|
32742
|
-
} catch (e3) {
|
|
32743
|
-
trackers.registerError(this.proctoringId, `Erro ao limpar o armazenamento local: ${e3}`);
|
|
32744
|
-
}
|
|
32691
|
+
this.chunkStorage && await this.chunkStorage.clearAllChunks(session.id);
|
|
32745
32692
|
return;
|
|
32746
32693
|
}
|
|
32747
32694
|
}
|
|
32748
32695
|
}
|
|
32749
32696
|
}
|
|
32750
|
-
trackers.registerError(this.proctoringId, `saveOnSession gerando v\xEDdeo a partir do buffer em mem\xF3ria (\xEDntegra)`);
|
|
32751
32697
|
const rawBlob = new Blob(this.blobs, {
|
|
32752
32698
|
type: ((_b = this.recorderOptions) == null ? void 0 : _b.mimeType) || "video/webm"
|
|
32753
32699
|
});
|
|
@@ -32768,7 +32714,6 @@ Setting: ${JSON.stringify(settings, null, 2)}`
|
|
|
32768
32714
|
origin: "Camera" /* Camera */
|
|
32769
32715
|
});
|
|
32770
32716
|
}
|
|
32771
|
-
trackers.registerError(this.proctoringId, `saveOnSession finalizado`);
|
|
32772
32717
|
}
|
|
32773
32718
|
async getFile(file, name, type) {
|
|
32774
32719
|
return new Promise((resolve, reject) => {
|
|
@@ -39050,14 +38995,11 @@ Error: ${error}`
|
|
|
39050
38995
|
await this.recorder.stopAll();
|
|
39051
38996
|
this.spyCam && this.spyCam.stopCheckSpyCam();
|
|
39052
38997
|
this.appChecker && await this.appChecker.disconnectWebSocket();
|
|
39053
|
-
trackers.registerError(this.proctoringId, `finish saveAllOnSession`);
|
|
39054
38998
|
await this.recorder.saveAllOnSession();
|
|
39055
|
-
trackers.registerError(this.proctoringId, `finish sendPendingRealtimeAlerts`);
|
|
39056
38999
|
await this.sendPendingRealtimeAlerts();
|
|
39057
|
-
|
|
39000
|
+
await this.repository.save(this.proctoringSession);
|
|
39058
39001
|
let uploader;
|
|
39059
39002
|
let uploaderServices;
|
|
39060
|
-
trackers.registerError(this.proctoringId, `finish uploader`);
|
|
39061
39003
|
if (versionVerify() !== "1.0.0.0") {
|
|
39062
39004
|
uploader = new ProctoringUploader(
|
|
39063
39005
|
this.proctoringSession,
|
|
@@ -39131,7 +39073,6 @@ Upload Services: ${uploaderServices}`,
|
|
|
39131
39073
|
this.serviceType
|
|
39132
39074
|
);
|
|
39133
39075
|
}
|
|
39134
|
-
trackers.registerError(this.proctoringId, `finish uploader success`);
|
|
39135
39076
|
if (this.proctoringSession.alerts.length > 0) {
|
|
39136
39077
|
await this.backend.saveAlerts(this.context, this.proctoringSession).catch((err) => {
|
|
39137
39078
|
trackers.registerFinish(
|
|
@@ -39141,7 +39082,6 @@ Upload Services: ${uploaderServices}`,
|
|
|
39141
39082
|
);
|
|
39142
39083
|
});
|
|
39143
39084
|
}
|
|
39144
|
-
trackers.registerError(this.proctoringId, `finish saveAlerts ok`);
|
|
39145
39085
|
await this.backend.finishAndSendUrls(this.context).then((finishResponse) => {
|
|
39146
39086
|
var _a2, _b, _c2, _d;
|
|
39147
39087
|
trackers.registerFinish(this.proctoringSession.id, true, "");
|
|
@@ -39153,7 +39093,6 @@ Upload Services: ${uploaderServices}`,
|
|
|
39153
39093
|
"finish error: " + error
|
|
39154
39094
|
);
|
|
39155
39095
|
});
|
|
39156
|
-
trackers.registerError(this.proctoringId, `finish call`);
|
|
39157
39096
|
if (this.appChecker) {
|
|
39158
39097
|
const externalSessionId = this.appChecker.getExternalCameraSessionId();
|
|
39159
39098
|
if (externalSessionId != "null") {
|
|
@@ -32,6 +32,7 @@ export declare class BackgroundUploadService {
|
|
|
32
32
|
flush(): Promise<void>;
|
|
33
33
|
private syncOffset;
|
|
34
34
|
private processQueue;
|
|
35
|
+
private static concatArrayBuffers;
|
|
35
36
|
private uploadData;
|
|
36
37
|
static recoverPendingUploads(backend: BackendService, token: string): Promise<string[]>;
|
|
37
38
|
private sleep;
|