Skip to content

Commit 6ced6ca

Browse files
committed
Локальное сохранение вместе с отправкой на сервер
1 parent 83f2c6f commit 6ced6ca

File tree

3 files changed

+57
-82
lines changed

3 files changed

+57
-82
lines changed

client/scripts/common.js

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -92,25 +92,21 @@ export async function requestClearLogs() {
9292
});
9393
}
9494

95-
export function saveBlobToFile(blob, name) {
96-
try {
97-
const url = URL.createObjectURL(blob);
98-
99-
const link = document.createElement('a');
100-
link.href = url;
101-
link.download = name;
102-
103-
document.body.appendChild(link);
104-
link.click();
105-
document.body.removeChild(link);
106-
107-
URL.revokeObjectURL(url);
95+
export async function saveBlobToFile(blob, filename) {
96+
const url = URL.createObjectURL(blob);
97+
filename = filename.replaceAll(":", "_");
10898

109-
console.log(`Файл ${name} сохранен`);
110-
logClientAction({ action: "Save file", fileName: name });
99+
try {
100+
await chrome.downloads.download({
101+
url: url,
102+
filename: filename,
103+
saveAs: true
104+
});
105+
106+
setTimeout(() => URL.revokeObjectURL(url), 1000);
111107
} catch (error) {
112-
console.error(`Ошибка при сохранении файла ${name}:`, error);
113-
logClientAction({ action: "Fail to save file", fileName: name, error: error.message });
108+
console.error('Download failed:', error);
109+
URL.revokeObjectURL(url);
114110
}
115111
}
116112

client/scripts/index.js

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -395,38 +395,32 @@ buttonElements.permissions.addEventListener('click', async () => {
395395
activateMediaTab: true
396396
});
397397
logClientAction({ action: "Send message", messageType: "getPermissions" });
398-
399-
// invalidStop = (await chrome.storage.local.get('invalidStop'))['invalidStop'] || false;
400-
// if (server_connection && !invalidStop && bState == "failedUpload") { // ?
401-
// inputElements.link.value = "";
402-
// saveInputValues();
403-
// logClientAction("Clear link field");
404-
// // TODO: Общий сброс. Например, когда прерванный прокторинг пользователь не захочет продолжать.
405-
// // chrome.storage.local.set({ 'sessionId': null });
406-
// }
407398
});
408399

409400
buttonElements.upload.addEventListener('click', async () => {
410-
console.log("upload button click");
411401
logClientAction({ action: "Click upload button" });
402+
412403
if (!server_connection) return;
413-
const files = (await chrome.storage.local.get('tempFiles'))['tempFiles'];
414-
if (!files) {
415-
buttonsStatesSave('needPermissions');
416-
updateButtonsStates();
417-
// ? Возможно требуется лог об ошибке
418-
} // ? Зачем мы идем дальше
419-
logClientAction({ action: "Start uploading video" });
420-
uploadVideo()
421-
.then(() => {
404+
405+
const files = (await chrome.storage.local.get('tempFiles'))['tempFiles'];
406+
407+
if (!files) {
408+
logClientAction({ action: "No files have found to upload" });
422409
buttonsStatesSave('needPermissions');
423410
updateButtonsStates();
424-
//await showModalNotify(["Запись успешно отправлена на сервер."], "Запись отправлена");
425-
})
426-
.catch(() => {
427-
buttonsStatesSave('failedUpload');
428-
updateButtonsStates();
429-
});
411+
412+
} else {
413+
logClientAction({ action: "Start uploading video" });
414+
uploadVideo(files)
415+
.then(() => {
416+
buttonsStatesSave('needPermissions');
417+
updateButtonsStates();
418+
})
419+
.catch(() => {
420+
buttonsStatesSave('failedUpload');
421+
updateButtonsStates();
422+
});
423+
}
430424
});
431425

432426
async function startRecCallback() {
@@ -561,15 +555,14 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
561555
}
562556
});
563557

564-
async function uploadVideo() {
558+
async function uploadVideo(files) {
565559
chrome.storage.local.get(['sessionId', 'extension_logs'], async ({ sessionId, extension_logs }) => {
566560
if (!sessionId) {
567561
console.error("Session ID не найден в хранилище");
568562
logClientAction({ action: `Upload fails due to missing session ID ${sessionId}` });
569563
return;
570564
}
571565

572-
const files = (await chrome.storage.local.get('tempFiles'))['tempFiles'] || [];
573566
console.log(files);
574567
if (!files.length) {
575568
logClientAction("Ошибка при поиске записей");
@@ -580,11 +573,17 @@ async function uploadVideo() {
580573
const rootDirectory = await navigator.storage.getDirectory();
581574

582575
for (const filename of files) {
576+
const blob = await (await rootDirectory.getFileHandle(filename, {create: false})).getFile();
577+
583578
if (filename.includes('screen')) {
584-
formData.append('screen_video', await (await rootDirectory.getFileHandle(filename, {create: false})).getFile(), filename);
579+
formData.append('screen_video', blob, filename);
585580
} else {
586-
formData.append('camera_video', await (await rootDirectory.getFileHandle(filename, {create: false})).getFile(), filename);
581+
formData.append('camera_video', blob, filename);
587582
}
583+
584+
logClientAction(`File ${filename} saved localy`);
585+
586+
await saveBlobToFile(blob, filename);
588587
}
589588

590589
formData.append("id", sessionId);
@@ -599,7 +598,7 @@ async function uploadVideo() {
599598
formData.append("logs", logsBlob, "extension_logs.json");
600599

601600
const logsFileName = `extension_logs_${sessionId}_${getCurrentDateString(new Date())}.json`;
602-
saveBlobToFile(logsBlob, logsFileName);
601+
await saveBlobToFile(logsBlob, logsFileName);
603602

604603
logClientAction({ action: "Download logs file", fileName: logsFileName });
605604
}

client/scripts/media.js

Lines changed: 15 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { showModalNotify, waitForNotificationSuppression, getBrowserFingerprint, generateObjectId, requestClearLogs, getDifferenceInTime, getFormattedDateString, getAvailableDiskSpace, saveBlobToFile } from './common.js';
2-
import { getCurrentDateString, setReadyToUploadContainer, parseDateString, deleteFiles } from "./common.js";
2+
import { getCurrentDateString, setReadyToUploadContainer, parseDateString } from "./common.js";
33
import { logClientAction, flushLogs, checkAndCleanLogs, prepareLogs } from './logger.js';
44

55
var streams = {
@@ -23,13 +23,10 @@ var previewButton = document.getElementById('preview-toggle-btn');
2323
var isRecording = false;
2424
var isPreviewEnabled = false;
2525

26-
// var rootDirectory = null;
2726
var combinedFileName = null;
2827
var cameraFileName = null;
2928
var combinedFileHandle = null;
3029
var cameraFileHandle = null;
31-
// var combinedWritableStream = null;
32-
// var cameraWritableStream = null;
3330
var forceTimeout = null;
3431
var startTime = undefined;
3532
var endTime = undefined;
@@ -314,9 +311,6 @@ async function getMediaDevices() {
314311

315312
logClientAction({ action: "Prompt permission settings" });
316313

317-
// alert('Не предоставлен доступ к камере или микрофону.\n' +
318-
// 'Сейчас откроется вкладка с настройками доступа для этого расширения.\n' +
319-
// 'Пожалуйста, убедитесь, что камера и микрофон разрешены.');
320314
await showModalNotify(['Не предоставлен доступ к камере или микрофону.',
321315
'Сейчас откроется вкладка с настройками доступа для этого расширения.',
322316
'Пожалуйста, убедитесь, что камера и микрофон разрешены, а затем нажмите во всплывающем окне расширения кнопку Разрешения.']);
@@ -350,7 +344,7 @@ async function getMediaDevices() {
350344
stopStreams();
351345
} else {
352346
stopDuration(startTime);
353-
await sendButtonsStates('needPermissions');
347+
await sendButtonsStates('failedUpload');
354348
await showModalNotify(["Текущие записи завершатся. Чтобы продолжить запись заново, выдайте разрешения во всплывающем окне по кнопке Разрешения и начните запись."], "Доступ к камере потерян!");
355349
// updateInvalidStopValue(true);
356350
stopRecord();
@@ -370,7 +364,7 @@ async function getMediaDevices() {
370364
stopStreams();
371365
} else {
372366
stopDuration(startTime);
373-
await sendButtonsStates('needPermissions');
367+
await sendButtonsStates('failedUpload');
374368
await showModalNotify(["Текущие записи завершатся. Чтобы продолжить запись заново, выдайте разрешения в расширении во всплывающем окне по кнопке Разрешения и начните запись."], "Доступ к экрану потерян!");
375369
// updateInvalidStopValue(true);
376370
stopRecord();
@@ -389,7 +383,7 @@ async function getMediaDevices() {
389383
stopStreams();
390384
} else {
391385
stopDuration(startTime);
392-
await sendButtonsStates('needPermissions');
386+
await sendButtonsStates('failedUpload');
393387
await showModalNotify(["Текущие записи завершатся. Чтобы продолжить запись заново, выдайте разрешения в расширении во всплывающем окне по кнопке Разрешения и начните запись."], "Доступ к микрофону потерян!");
394388
// updateInvalidStopValue(true);
395389
stopRecord();
@@ -551,7 +545,7 @@ async function addFileToTempList(fileName) {
551545
if (!tempFiles.includes(fileName)) {
552546
logClientAction({ action: "Add file to temp list", fileName });
553547
const updatedFiles = [ ...tempFiles, fileName ];
554-
return chrome.storage.local.set({ 'tempFiles': updatedFiles });
548+
return (await chrome.storage.local.set({ 'tempFiles': updatedFiles }));
555549
} else {
556550
logClientAction({ action: "File already exists in temp list", fileName });
557551
}
@@ -608,25 +602,14 @@ window.addEventListener('load', async () => {
608602
const tempFiles = (await chrome.storage.local.get('tempFiles'))['tempFiles'] || [];
609603
setReadyToUploadContainer(readyToUploadContainer, tempFiles);
610604

611-
if (invalidStop) { // по сути мы скачиваем файлы для дебага, пользователю они не сильно нужны
612-
// если нужны -> показать сообщение (найдены файлы: восстановить)
605+
if (invalidStop) {
613606
metadata = new Metadata();
614607
await metadata.useSaved();
615608
const recordingStart = (await chrome.storage.local.get("recording_start"))["recording_start"];
616609
const recordingEnd = (await chrome.storage.local.get("recording_end"))["recording_end"];
617610
metadata.appendRecordingSession(recordingStart, recordingEnd);
618611
metadata.save();
619612

620-
// const rootDirectory = await navigator.storage.getDirectory();
621-
622-
// tempFiles.forEach(async fileName => {
623-
// const fileFandle = await rootDirectory.getFileHandle(fileName);
624-
// const fileBlob = await fileFandle.getFile();
625-
// saveBlobToFile(fileBlob, fileName);
626-
627-
// logClientAction({ action: "Saved temp file", fileName: fileName });
628-
// });
629-
630613
console.log("invalid_stop:", metadata.metadata);
631614
console.log(tempFiles);
632615

@@ -635,6 +618,7 @@ window.addEventListener('load', async () => {
635618
});
636619

637620
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
621+
if (sender.id !== chrome.runtime.id) return;
638622
if (message.action === 'stopRecording') {
639623
logClientAction({ action: "Receive message", messageType: "stopRecording" });
640624
if (recorders.combined || recorders.camera) {
@@ -733,6 +717,7 @@ chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
733717

734718

735719
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
720+
if (sender.id !== chrome.runtime.id) return;
736721
if (message.action === 'suppressModalNotifyAT') {
737722
notifications_flag = false;
738723
console.log('notifications_flag = ', notifications_flag);
@@ -823,8 +808,8 @@ async function stopRecord() {
823808
recorders.combined.stop();
824809
}
825810

826-
saveBlobToFile(file, combinedFileName);
827-
logClientAction({ action: "Save recorded file", fileType: "screen", fileName: combinedFileName });
811+
// saveBlobToFile(file, combinedFileName);
812+
// logClientAction({ action: "Save recorded file", fileType: "screen", fileName: combinedFileName });
828813
}
829814

830815
if (recorders.camera) {
@@ -835,8 +820,8 @@ async function stopRecord() {
835820
recorders.camera.stop();
836821
}
837822

838-
saveBlobToFile(file, cameraFileName);
839-
logClientAction({ action: "Save recorded file", fileType: "camera", fileName: cameraFileName });
823+
// saveBlobToFile(file, cameraFileName);
824+
// logClientAction({ action: "Save recorded file", fileType: "camera", fileName: cameraFileName });
840825
}
841826

842827
metadata.appendRecordingSession(startTime, endTime);
@@ -858,12 +843,6 @@ async function stopRecord() {
858843
`Начало записи: ${getFormattedDateString(startTime)}`,
859844
`Конец записи: ${getFormattedDateString(endTime)}`,
860845
`Длительность записи: ${duration}`,
861-
"Файлы записи экрана и камеры сохранены в папку загрузок по умолчанию.",
862-
"Файл записи экрана:",
863-
`${combinedFileName} (${(combinedFileSize / 1024 / 1024).toFixed(1)} MB)`,
864-
"Файл записи камеры:",
865-
`${cameraFileName} (${(cameraFileSize / 1024 / 1024).toFixed(1)} MB)`,
866-
"Файл с логами сохранен в папку загрузок по умолчанию."
867846
];
868847
logClientAction(stats);
869848

@@ -877,7 +856,7 @@ async function stopRecord() {
877856

878857
if (server_connection) {
879858
await showModalNotify(
880-
["Для отправки записи необходимо нажать кнопку «Отправить» во всплывающем окне расширения прокторинга."],
859+
["Для сохранения и отправки записи необходимо нажать кнопку «Отправить» во всплывающем окне расширения прокторинга."],
881860
"Отправка записи",
882861
true
883862
);
@@ -1004,7 +983,7 @@ async function downloadLogs(fileName) {
1004983

1005984
const logsBlob = new Blob([JSON.stringify(logsToSave, null, 2)], { type: 'application/json' });
1006985

1007-
saveBlobToFile(logsBlob, fileName);
986+
await saveBlobToFile(logsBlob, fileName);
1008987

1009988
await requestClearLogs();
1010989
}
@@ -1041,6 +1020,7 @@ async function showModalNotifyMedia(messages, title) {
10411020
}
10421021

10431022
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
1023+
if (sender.id !== chrome.runtime.id) return;
10441024
if (message.type === 'showModalNotifyOnMedia') {
10451025
showModalNotifyMedia(message.messages, message.title).then(() => {
10461026
sendResponse({ confirmed: true });

0 commit comments

Comments
 (0)