|
@@ -2,6 +2,7 @@ import { Component, OnInit, ViewChild, ElementRef, Renderer2 } from '@angular/co
|
|
|
import { Router } from '@angular/router';
|
|
import { Router } from '@angular/router';
|
|
|
import { FormsModule, NgForm } from '@angular/forms';
|
|
import { FormsModule, NgForm } from '@angular/forms';
|
|
|
import { HttpErrorResponse } from '@angular/common/http'
|
|
import { HttpErrorResponse } from '@angular/common/http'
|
|
|
|
|
+import * as SparkMD5 from 'spark-md5';
|
|
|
|
|
|
|
|
import { MenuComponent } from '../menu/menu.component';
|
|
import { MenuComponent } from '../menu/menu.component';
|
|
|
import { Production, ProductionEnum, ProductionTypeList } from '../../interfaces/production';
|
|
import { Production, ProductionEnum, ProductionTypeList } from '../../interfaces/production';
|
|
@@ -21,13 +22,13 @@ export class ProductionCreateComponent implements OnInit
|
|
|
|
|
|
|
|
@ViewChild('formRef') productionForm!: NgForm;
|
|
@ViewChild('formRef') productionForm!: NgForm;
|
|
|
@ViewChild('boutonUploader', {static: false}) boutonUploader!: ElementRef;
|
|
@ViewChild('boutonUploader', {static: false}) boutonUploader!: ElementRef;
|
|
|
- @ViewChild('messageUpload', {static: false}) messageUpload!: ElementRef;
|
|
|
|
|
- @ViewChild('messageErreur', {static: false}) messageErreur!: ElementRef;
|
|
|
|
|
|
|
+ @ViewChild('labelMessage', {static: false}) labelMessage!: ElementRef;
|
|
|
|
|
|
|
|
production: Production = new Production();
|
|
production: Production = new Production();
|
|
|
uploaderFichier: boolean = false;
|
|
uploaderFichier: boolean = false;
|
|
|
fichier!: any;
|
|
fichier!: any;
|
|
|
reliquat: number = 0;
|
|
reliquat: number = 0;
|
|
|
|
|
+ digestat: string = "";
|
|
|
chunkIndex = 0;
|
|
chunkIndex = 0;
|
|
|
|
|
|
|
|
constructor(
|
|
constructor(
|
|
@@ -57,8 +58,26 @@ export class ProductionCreateComponent implements OnInit
|
|
|
|
|
|
|
|
this.fichier = et.files[0];
|
|
this.fichier = et.files[0];
|
|
|
this.uploaderFichier = true;
|
|
this.uploaderFichier = true;
|
|
|
|
|
+ this.computeChecksumMd5(this.fichier).then(md5 => { this.digestat = md5 });
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ /** https://dev.to/qortex/compute-md5-checksum-for-a-file-in-typescript-59a4 */
|
|
|
|
|
+ computeChecksumMd5(file: File): Promise<string> {
|
|
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
|
|
+ const chunkSize = 2097152;
|
|
|
|
|
+ const spark = new SparkMD5.ArrayBuffer();
|
|
|
|
|
+ const fileReader = new FileReader();
|
|
|
|
|
+ let cursor = 0;
|
|
|
|
|
+
|
|
|
|
|
+ fileReader.onerror = function(): void { reject('MD5 computation failed - error reading the file'); };
|
|
|
|
|
+
|
|
|
|
|
+ function processChunk(chunk_start: number): void { const chunk_end = Math.min(file.size, chunk_start + chunkSize); fileReader.readAsArrayBuffer(file.slice(chunk_start, chunk_end)); }
|
|
|
|
|
+
|
|
|
|
|
+ fileReader.onload = function(e: any): void { spark.append(e.target.result); cursor += chunkSize; if (cursor < file.size) { processChunk(cursor); } else { resolve(spark.end()); } };
|
|
|
|
|
+
|
|
|
|
|
+ processChunk(0);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
onVignetteSelected(event: any)
|
|
onVignetteSelected(event: any)
|
|
|
{
|
|
{
|
|
@@ -77,6 +96,7 @@ export class ProductionCreateComponent implements OnInit
|
|
|
|
|
|
|
|
async saveArchive(id: number)
|
|
async saveArchive(id: number)
|
|
|
{
|
|
{
|
|
|
|
|
+ const spark = new SparkMD5.ArrayBuffer();
|
|
|
const chunkSize = 1024 * 1024;
|
|
const chunkSize = 1024 * 1024;
|
|
|
let start = 0;
|
|
let start = 0;
|
|
|
|
|
|
|
@@ -87,12 +107,14 @@ export class ProductionCreateComponent implements OnInit
|
|
|
{
|
|
{
|
|
|
while (start < this.fichier.size)
|
|
while (start < this.fichier.size)
|
|
|
{
|
|
{
|
|
|
- const chunk = this.fichier.slice(start, start + chunkSize);
|
|
|
|
|
|
|
+ const end = Math.min(this.fichier.size, start + chunkSize);
|
|
|
|
|
+ const chunk = this.fichier.slice(start, end);
|
|
|
|
|
|
|
|
await this.productionService.uploadChunk(id, chunk, this.chunkIndex, this.fichier.name);
|
|
await this.productionService.uploadChunk(id, chunk, this.chunkIndex, this.fichier.name);
|
|
|
|
|
|
|
|
this.reliquat += chunk.size;
|
|
this.reliquat += chunk.size;
|
|
|
- this.setMessageUpload(' ' + Math.floor((this.reliquat*100)/this.fichier.size) + '%');
|
|
|
|
|
|
|
+ let pourcentage = Math.floor((this.reliquat*100)/this.fichier.size);
|
|
|
|
|
+ this.setMessage('<div class="progress" role="progressbar" aria-valuemin="0" aria-valuemax="100"><div class="progress-bar" style="width:' + pourcentage +'%">' + pourcentage + '%</div></div>', false);
|
|
|
|
|
|
|
|
start += chunkSize;
|
|
start += chunkSize;
|
|
|
this.chunkIndex++;
|
|
this.chunkIndex++;
|
|
@@ -101,9 +123,9 @@ export class ProductionCreateComponent implements OnInit
|
|
|
catch (err:any) { console.error(err); }
|
|
catch (err:any) { console.error(err); }
|
|
|
finally
|
|
finally
|
|
|
{
|
|
{
|
|
|
- this.productionService.mergeChunks(id, this.fichier.name, this.chunkIndex).subscribe({
|
|
|
|
|
- next: (msg) => { this.setBoutonUploadEnd(); if (msg.erreur) { this.setMessageErreur(msg.erreur); } else { this.goToListProduction(); } },
|
|
|
|
|
- error: (e:HttpErrorResponse) => { this.setBoutonUploadEnd(); this.setMessageErreur(e.error.message); },
|
|
|
|
|
|
|
+ this.productionService.mergeChunks(id, this.fichier.name, this.chunkIndex, this.digestat).subscribe({
|
|
|
|
|
+ next: (msg) => { this.setBoutonUploadEnd(); if (msg.erreur) { this.setMessage(msg.erreur, true); } else { this.goToListProduction(); } },
|
|
|
|
|
+ error: (e:HttpErrorResponse) => { this.setBoutonUploadEnd(); this.setMessage(e.error.message, true); },
|
|
|
complete: () => { }
|
|
complete: () => { }
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
@@ -114,12 +136,11 @@ export class ProductionCreateComponent implements OnInit
|
|
|
|
|
|
|
|
this.productionService.createProduction(this.production).subscribe({
|
|
this.productionService.createProduction(this.production).subscribe({
|
|
|
next: async (ret) => { await this.saveArchive(Number('' + ret)); this.setBoutonUploadEnd(); this.goToListProduction(); },
|
|
next: async (ret) => { await this.saveArchive(Number('' + ret)); this.setBoutonUploadEnd(); this.goToListProduction(); },
|
|
|
- error: (e:HttpErrorResponse) => { this.setBoutonUploadEnd(); this.setMessageErreur(e.error.message); },
|
|
|
|
|
|
|
+ error: (e:HttpErrorResponse) => { this.setBoutonUploadEnd(); this.setMessage(e.error.message, true); },
|
|
|
complete: () => { }
|
|
complete: () => { }
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
- private setMessageUpload(m: string) { if (this.messageUpload) { this.renderer.setProperty(this.messageUpload.nativeElement, 'innerHTML', m); } }
|
|
|
|
|
- private setMessageErreur(m: string) { if (this.messageErreur) { this.renderer.setProperty(this.messageErreur.nativeElement, 'innerHTML', m); } }
|
|
|
|
|
|
|
+ private setMessage(m: string, e: boolean) { if (this.labelMessage) { this.renderer.setProperty(this.labelMessage.nativeElement, 'innerHTML', m); if (e) { this.renderer.addClass(this.labelMessage.nativeElement, 'text-danger'); } else { this.renderer.removeClass(this.labelMessage.nativeElement, 'text-danger'); } } }
|
|
|
private setBoutonUploadStart() { if (this.boutonUploader && this.uploaderFichier) { this.renderer.setProperty(this.boutonUploader.nativeElement, 'innerHTML', '<i class="fa-solid fa-upload fa-fade"></i> ' + $localize`Téléversement en cours`); } }
|
|
private setBoutonUploadStart() { if (this.boutonUploader && this.uploaderFichier) { this.renderer.setProperty(this.boutonUploader.nativeElement, 'innerHTML', '<i class="fa-solid fa-upload fa-fade"></i> ' + $localize`Téléversement en cours`); } }
|
|
|
private setBoutonUploadEnd() { if (this.boutonUploader) { this.renderer.setProperty(this.boutonUploader.nativeElement, 'innerHTML', '<i class="fa-solid fa-plus"></i> ' + $localize`Créer`); } }
|
|
private setBoutonUploadEnd() { if (this.boutonUploader) { this.renderer.setProperty(this.boutonUploader.nativeElement, 'innerHTML', '<i class="fa-solid fa-plus"></i> ' + $localize`Créer`); } }
|
|
|
|
|
|