video uploader

This commit is contained in:
Peter Maquiran
2024-01-29 13:49:53 +01:00
parent 892bdbe5cf
commit 2605d73baa
11 changed files with 757 additions and 179 deletions
@@ -14,8 +14,10 @@ import { FileValidatorService } from "src/app/services/file/file-validator.servi
import { MiddlewareServiceService } from "src/app/shared/API/middleware/middleware-service.service";
import { LakefsRepositoryService } from '../../repository/lakefs/lakefs-repository.service';
import { ok, err, Result } from 'neverthrow';
import { SocketConnectionMCRService } from "src/app/services/socket-connection-mcr.service"
import { CMAPIService } from "src/app/shared/repository/CMAPI/cmapi.service";
import { ObjectMergeNotification, SocketConnectionMCRService } from "src/app/services/socket-connection-mcr.service"
import { CMAPIService } from '../../repository/CMAPI/cmapi.service';
import { environment } from 'src/environments/environment';
enum ActionType {
newRapid = "1",
@@ -338,6 +340,7 @@ export class NewPublicationPage implements OnInit {
}
if(this.seletedContent.length == 0) {
const newAttachment = new PublicationAttachmentEntity(
@@ -356,6 +359,7 @@ export class NewPublicationPage implements OnInit {
if (this.publicationType == ActionType.edit) {
if (this.seletedContent.length >= 1) {
const loader = this.toastService.loading()
@@ -370,6 +374,22 @@ export class NewPublicationPage implements OnInit {
}
this.publicationFormMV.setDataToFrom(this.publication)
const upload = await this.publicationFormMV.uploadVideosFiles()
if(upload) {
this.publication.Files = this.publication.Files.map((e:PublicationAttachmentEntity)=> {
if(e.FileType == 'video') {
e.FileBase64 = environment.apiURL + "/ObjectServer/StreamFiles?path="+ e.chucksManager.path
}
return e
})
console.log("this.publication.Files", this.publication.Files)
}
this.publication.Files = this.publication.Files.map( e => ({
FileBase64: e.FileBase64,
FileExtension: e.FileExtension,
@@ -416,6 +436,20 @@ export class NewPublicationPage implements OnInit {
}
this.publicationFormMV.setDataToFrom(this.publication)
const upload = await this.publicationFormMV.uploadVideosFiles()
if(upload) {
this.publication.Files = this.publication.Files.map((e:PublicationAttachmentEntity)=> {
if(e.FileType == 'video') {
e.FileBase64 = environment.apiURL + "/ObjectServer/StreamFiles?path="+ e.chucksManager.path
}
return e
})
console.log("this.publication.Files", this.publication.Files)
}
this.publication.Files = this.publication.Files.map( e => ({
FileBase64: e.FileBase64,
@@ -871,7 +905,7 @@ export class NewPublicationPage implements OnInit {
uploadChunk() {
async uploadChunk() {
let time = new Date()
this.publication = {
@@ -886,162 +920,95 @@ export class NewPublicationPage implements OnInit {
}
this.publicationFormMV.setDataToFrom(this.publication)
this.publicationFormMV.uploadVideosFiles()
}
}
// class UploadFileUseCase {
// LakefsRepositoryService: LakefsRepositoryService = window["LakefsRepositoryService"]
// constructor() {}
// execute(attachment: PublicationAttachmentEntity) {
// const file: File = attachment.blob
// const chunkSize = 1024 * 100; // Adjust the chunk size as needed
// const fileSize = file.size;
// let uploadedSize = 0
// const totalChunks = Math.ceil(fileSize / chunkSize);
// let offset = 0;
// let i = 1;
// let j = 0;
// let path;
// function count () {
// j++
// return j
// }
// const readAndUploadChunk = async(index: number) => {
// return new Promise<void>((resolve, reject) => {
// const chunk = file.slice(offset, offset + chunkSize);
// const reader = new FileReader();
// reader.onload = async () => {
// const blob = new Blob([reader.result as ArrayBuffer]);
// const formData = new FormData();
// const file = new File([blob], "test.mp4", { type: blob.type });
// uploadedSize =+ file.size
// formData.append("blobFile", file);
// formData.append("length", totalChunks.toString());
// formData.append("index", index.toString());
// formData.append("path", path);
// try {
// const response = await this.LakefsRepositoryService.uploadFile(formData).toPromise()
// console.log({response})
// resolve()
// } catch (erro) {
// reject()
// }
// };
// reader.readAsArrayBuffer(chunk);
// offset += chunkSize;
// });
// }
// const loop = async() => {
// for (let index = 2; index <= totalChunks; index++) {
// await readAndUploadChunk(index);
// }
// }
// const startUpload = async() => {
// const index = count();
// const chunk = file.slice(offset, offset + chunkSize);
// const reader = new FileReader();
// reader.onload = async () => {
// const blob = new Blob([reader.result as ArrayBuffer]);
// const formData = new FormData();
// const file = new File([blob], "test.mp4", { type: blob.type });
// uploadedSize =+ file.size
// formData.append("blobFile", file);
// formData.append("length", totalChunks.toString());
// formData.append("index", index.toString());
// const response: any = await this.LakefsRepositoryService.uploadFile(formData).toPromise()
// console.log({ response, index });
// if (index === 1) {
// path = response.path;
// }
// await loop();
// };
// reader.readAsArrayBuffer(chunk);
// offset += chunkSize;
// }
// startUpload();
// }
// }
class UploadFileUseCase {
CMAPIService: CMAPIService = window["CMAPIService"]
CMAPIService: CMAPIService = window["CMAPIAPIRepository"]
constructor() {}
async execute(ChucksManager: ChucksManager): Promise<Result<ChucksManager, ChucksManager>> {
async execute(PublicationAttachmentEntity: PublicationAttachmentEntity): Promise<Result<PublicationAttachmentEntity, PublicationAttachmentEntity>> {
return new Promise(async (resolve, reject) => {
let path: string;
const length = ChucksManager.chunks.totalChunks.toString()
const readAndUploadChunk = async(index: number) => {
let path: string;
const length = PublicationAttachmentEntity.chucksManager.chunks.totalChunks.toString()
const chunk = await ChucksManager.chunks.getChunks(index)
const blob = new Blob([chunk]);
const blobFile = new File([blob], "test.mp4", { type: blob.type });
const readAndUploadChunk = async(index: number) => {
return await this.CMAPIService.FileContent({length, path: ChucksManager.path, index, blobFile})
}
const chunk = await PublicationAttachmentEntity.chucksManager.chunks.getChunks(index)
const blob = new Blob([chunk]);
const blobFile = new File([blob], "test.mp4", { type: blob.type });
if(!ChucksManager.hasPath()) {
const initIndex = ChucksManager.uploadsCount + 1
const chuck = await ChucksManager.chunks.getChunks(initIndex)
const blob = new Blob([chuck]);
const blobFile = new File([blob], "test.mp4", { type: blob.type });
const uploadRequest = await this.CMAPIService.FileContent({length, path:ChucksManager.path, index: initIndex, blobFile})
if(uploadRequest.isOk()) {
path = uploadRequest.value.data
ChucksManager.setPath(path)
ChucksManager.setResponse(initIndex, uploadRequest.value as any)
} else {
return err(ChucksManager)
return await this.CMAPIService.FileContent({length, path: PublicationAttachmentEntity.chucksManager.path, index, blobFile})
}
}
const indexContinuation = ChucksManager.uploadsCount + 1
for (let index = indexContinuation; index <= ChucksManager.chunks.totalChunks; index++) {
const uploadRequest = await readAndUploadChunk(index)
if(!PublicationAttachmentEntity.chucksManager.hasPath()) {
const initIndex = 1
const uploadRequest = await readAndUploadChunk(initIndex)
if(uploadRequest.isOk()) {
path = uploadRequest.value.data
PublicationAttachmentEntity.chucksManager.setPath(path)
PublicationAttachmentEntity.chucksManager.setResponse(initIndex, uploadRequest)
} else {
reject(err(PublicationAttachmentEntity))
}
}
const allRequest: Promise<any>[] = []
for (let index = 2; index <= PublicationAttachmentEntity.chucksManager.chunks.totalChunks -1; index++) {
const needUpload = PublicationAttachmentEntity.chucksManager.needToUploadChunkIndex(index)
if(needUpload) {
const request = readAndUploadChunk(index).then(async(uploadRequest) => {
if(uploadRequest.isErr()) {
const pingRequest = await this.CMAPIService.ping()
if( pingRequest.isErr()) {
reject(err(PublicationAttachmentEntity))
}
} else {
PublicationAttachmentEntity.chucksManager.setResponse(index, uploadRequest)
}
})
allRequest.push(request)
// const request = readAndUploadChunk(index)
// const uploadRequest = await request
// allRequest.push(request)
// if(uploadRequest.isErr()) {
// const pingRequest = await this.CMAPIService.ping()
// if( pingRequest.isErr()) {
// reject(err(PublicationAttachmentEntity))
// }
// } else {
// PublicationAttachmentEntity.chucksManager.setResponse(index, uploadRequest)
// }
}
}
await Promise.all(allRequest)
const uploadRequest = await readAndUploadChunk(PublicationAttachmentEntity.chucksManager.chunks.totalChunks)
if(uploadRequest.isErr()) {
return err(ChucksManager)
const pingRequest = await this.CMAPIService.ping()
if( pingRequest.isErr()) {
reject(err(PublicationAttachmentEntity))
}
} else {
ChucksManager.setResponse(index, uploadRequest.value as any)
PublicationAttachmentEntity.chucksManager.setResponse(PublicationAttachmentEntity.chucksManager.chunks.totalChunks, uploadRequest)
}
}
return ok(ChucksManager)
PublicationAttachmentEntity.chucksManager.doneChunkUpload()
resolve(ok(PublicationAttachmentEntity))
})
}
}
@@ -1084,6 +1051,9 @@ class PublicationAttachmentEntity {
setChunkManger (chunks: Chunks) {
this.chucksManager = new ChucksManager({chunks})
}
get hasChunkManger() {
return this.chucksManager?.chunks
}
get hasChunkManager() {
return this.chucksManager != null
@@ -1111,8 +1081,14 @@ class PublicationFormModel implements IPublicationFormModelEntity {
OriginalFileName: string;
Files: PublicationAttachmentEntity[];
hasSet = false
setData(data: IPublicationFormModelEntity) {
Object.assign(this, data)
if(!this.hasSet) {
Object.assign(this, data)
}
this.hasSet = true
}
}
@@ -1120,6 +1096,7 @@ class PublicationFormMV {
private UploadFileUseCase = new UploadFileUseCase()
private form = new PublicationFormModel()
private ObjectMergeNotification = new ObjectMergeNotification()
setDataToFrom(data: IPublicationFormModelEntity) {
this.form.setData(data)
@@ -1129,30 +1106,76 @@ class PublicationFormMV {
return this.form.Files.filter( x => x.FileType == 'video')
}
private async upload(PublicationAttachmentEntity: PublicationAttachmentEntity) {
private upload(PublicationAttachmentEntity: PublicationAttachmentEntity) {
const fileBlob = PublicationAttachmentEntity.blobFile;
const fileChunks = new Chunks({chunkSize: 100 })
fileChunks.setFile(fileBlob)
return new Promise(async (resolve, reject)=> {
PublicationAttachmentEntity.setChunkManger(fileChunks)
if(!PublicationAttachmentEntity.hasChunkManger) {
const fileBlob = PublicationAttachmentEntity.blobFile;
const fileChunks = new Chunks({chunkSize: 500 })
fileChunks.setFile(fileBlob)
const ChucksManagers = new ChucksManager({chunks: fileChunks})
PublicationAttachmentEntity.setChunkManger(fileChunks)
PublicationAttachmentEntity.chucksManager.registerOnLastChunk(()=> {
const guid = PublicationAttachmentEntity.chucksManager.path
this.ObjectMergeNotification.subscribe(guid, (data) => {
// console.log("data", data)
PublicationAttachmentEntity
resolve(true)
})
})
} else {
if(PublicationAttachmentEntity.chucksManager.doneUpload) {
return resolve(true)
}
}
const result = await this.UploadFileUseCase.execute(PublicationAttachmentEntity)
if(result.isErr()) {
reject(false)
}
})
this.UploadFileUseCase.execute(ChucksManagers)
}
uploadVideosFiles() {
uploadVideosFiles(): Promise<Boolean> {
return new Promise((resolve, reject)=> {
const videosFiles = this.getVideoFiles()
const videosFiles = this.getVideoFiles()
const videosFilesToUploads = videosFiles.filter( e => e.toUpload == true)
const videosFilesToUploads = videosFiles.filter( e => e.toUpload == true)
const Promises: Promise<any>[] = []
for(const file of videosFilesToUploads) {
const promise = this.upload(file)
Promises.push(promise)
}
// Use Promise.all to wait for all promises to resolve
Promise.all(Promises)
.then((results) => {
// Check if every promise resolved successfully
const allPromisesResolvedSuccessfully = results.every((result) => result == true);
if (allPromisesResolvedSuccessfully) {
console.log('All promises resolved successfully.');
resolve(true)
} else {
reject(false)
console.log('Some promises failed to resolve successfully.');
}
})
.catch((error) => {
reject(false)
console.error('An error occurred while resolving promises:', error);
});
})
for(const file of videosFilesToUploads) {
this.upload(file)
}
}
}
@@ -1205,7 +1228,7 @@ class Chunks {
}
interface IUploadResponse {
result: Result<string, Error>
result: Result<any, Error>
attemp: number
}
@@ -1213,25 +1236,110 @@ class ChucksManager {
chunks: Chunks
uploads: {[key: string]: IUploadResponse } = {}
path: string = undefined
uploadPercentage: string = "0%"
merging = false
onSetPath: Function[] = []
onSetLastChunk: Function[] = []
contentReady = false
getUploadPercentage() {
return this.uploadPercentage
}
get uploadsCount() {
return Object.entries(this.uploads).length
}
get uploadWithSuccessCount() {
const uploadWithSuccess = Object.entries(this.uploads).filter(([index, data])=> data.result.isOk())
return uploadWithSuccess.length
}
get doneUpload() {
return this.chunks.totalChunks == this.uploadWithSuccessCount
}
uploadFunc: Function
constructor({chunks}) {
this.chunks = chunks
}
calculatePercentage(): number {
/**
* Calculate the percentage based on the total and current values.
*
* @param total - The total value.
* @param current - The current value.
* @returns The percentage calculated as (current / total) * 100.
*/
const total = this.chunks.totalChunks
const current = this.uploadWithSuccessCount
if (total === 0) {
return 0; // To avoid division by zero error
}
const percentage: number = (current / total) * 100;
return percentage;
}
setPercentage() {
const percentage: number = this.calculatePercentage()
console.log({percentage})
this.uploadPercentage = percentage.toString()+"%"
}
setPath(path: string) {
this.path = path
this.onSetPath.forEach(callback => callback());
}
registerOnSetPath(a: Function) {
this.onSetPath.push(a)
}
registerOnLastChunk(a: Function) {
this.onSetPath.push(a)
}
hasPath() {
return this.path != undefined
}
isIndexRegistered(index) {
if(!this.uploads[index]) {
return false
}
return true
}
needToUploadChunkIndex(index) {
return !this.uploads?.[index]?.result?.isOk()
}
setResponse(index, UploadResponse) {
this.uploads[index] = UploadResponse
if(!this.isIndexRegistered(index)) {
this.uploads[index] = {
attemp: 1,
result: UploadResponse
}
console.log({UploadResponse})
} else {
this.uploads[index].attemp++;
this.uploads[index].result = UploadResponse
}
this.setPercentage()
}
doneChunkUpload() {
this.merging = true
this.onSetLastChunk.forEach(callback => callback());
}
contentSetReady() {
this.merging = false
this.contentReady = true
}
}