improve socket

This commit is contained in:
Peter Maquiran
2024-01-31 17:12:01 +01:00
parent 76b0046a22
commit 793c861cbf
9 changed files with 758 additions and 671 deletions
@@ -40,19 +40,23 @@
<ion-img *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'image'" [(ngModel)]="capturedImage" <ion-img *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'image'" [(ngModel)]="capturedImage"
name="image" ngDefaultControl [src]="'data:image/jpg;base64,' + seleted.FileBase64" name="image" ngDefaultControl [src]="'data:image/jpg;base64,' + seleted.Base64"
(click)="imageSize(capturedImage)" style="height: 69px;"></ion-img> (click)="imageSize(capturedImage)" style="height: 69px;"></ion-img>
<video *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video'" width="70" height="70" <video *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && publicationTitle == ActionType.edit" width="70" height="70"
controls="controls" preload="metadata" autoplay="autoplay" webkit-playsinline="webkit-playsinline"> controls="controls" preload="metadata" autoplay="autoplay" webkit-playsinline="webkit-playsinline">
<source type="video/mp4" [src]="'data:video/mp4;base64,' + seleted.FileBase64"> <source type="video/mp4" [src]="'data:video/mp4;base64,' + seleted.Base64">
</video> </video>
<video *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && publicationTitle != ActionType.edit" width="70" height="70"
controls="controls" preload="metadata" autoplay="autoplay" webkit-playsinline="webkit-playsinline">
<source type="video/mp4" [src]="seleted.url">
</video>
</div> </div>
<!-- Display the blurred image and count if there are more images --> <!-- Display the blurred image and count if there are more images -->
<ion-thumbnail *ngIf="seletedContent.length > displayLimit" lot="start"> <ion-thumbnail *ngIf="seletedContent.length > displayLimit" lot="start">
<ion-img [src]="'data:image/jpg;base64,' + seletedContent[displayLimit - 1].base64" <ion-img [src]="'data:image/jpg;base64,' + seletedContent[displayLimit - 1].Base64"
style="filter: blur(5px);"></ion-img> style="filter: blur(5px);"></ion-img>
<p>mais {{ seletedContent.length - displayLimit }}</p> <p>mais {{ seletedContent.length - displayLimit }}</p>
@@ -31,6 +31,7 @@ import { File } from '@ionic-native/file/ngx';
import { Media } from '@ionic-native/media/ngx'; import { Media } from '@ionic-native/media/ngx';
import { checkFileTypeService } from 'src/app/services/checkFileType.service'; import { checkFileTypeService } from 'src/app/services/checkFileType.service';
import { FileValidatorService } from "src/app/services/file/file-validator.service" import { FileValidatorService } from "src/app/services/file/file-validator.service"
import { PublicationAttachmentEntity } from 'src/app/shared/publication/upload/upload-streaming.service';
const config = { const config = {
quality: 0.5, quality: 0.5,
maxWidth: 800, maxWidth: 800,
@@ -92,6 +93,13 @@ export class NewPublicationPage implements OnInit {
publicationTitle: string; publicationTitle: string;
imgUrl: any; imgUrl: any;
ActionType = {
newRapid : "1",
new: "2",
edit: "3"
}
Defaultimage: any = ''; Defaultimage: any = '';
photo: SafeResourceUrl; photo: SafeResourceUrl;
@@ -112,7 +120,7 @@ export class NewPublicationPage implements OnInit {
photoOrVideo: boolean = false; photoOrVideo: boolean = false;
fileType = ""; fileType = "";
filecontent: boolean; filecontent: boolean;
seletedContent: any[] = [] seletedContent: PublicationAttachmentEntity[] = []
// Set a limit for the number of images to display // Set a limit for the number of images to display
displayLimit = 4; displayLimit = 4;
filesSizeSum = 0; filesSizeSum = 0;
@@ -142,6 +150,18 @@ export class NewPublicationPage implements OnInit {
if (this.publication) { if (this.publication) {
this.seletedContent = this.publication.Files; this.seletedContent = this.publication.Files;
this.filecontent = true; this.filecontent = true;
this.seletedContent = this.publication.Files.map(e => {
return new PublicationAttachmentEntity(
{
base64: e.FileBase64,
extension: e.FileExtension,
OriginalFileName: e.OriginalFileName,
FileType: this.checkFileType.checkFileType(e.FileExtension) as any
}
)
})
} }
console.log('Edit', this.publication) console.log('Edit', this.publication)
this.publicationTitle = 'Nova Publicação'; this.publicationTitle = 'Nova Publicação';
@@ -161,12 +181,16 @@ export class NewPublicationPage implements OnInit {
recursive: true recursive: true
}); });
document.addEventListener("click", clickOutside, false); try {
function clickOutside(e) { document.addEventListener("click", clickOutside, false);
const inside = document.getElementById('container-multiselect').contains(e.target); function clickOutside(e) {
this.photoOrVideo = false; const inside = document.getElementById('container-multiselect').contains(e.target);
console.log(this.photoOrVideo) this.photoOrVideo = false;
} console.log(this.photoOrVideo)
}
} catch (error) {}
} }
// in use // in use
@@ -193,11 +217,14 @@ export class NewPublicationPage implements OnInit {
console.log('take picture', this.removeTextBeforeSlash(picture, ','),) console.log('take picture', this.removeTextBeforeSlash(picture, ','),)
this.filecontent = true; this.filecontent = true;
this.photoOrVideo = false; this.photoOrVideo = false;
let fileObject = {
FileBase64: this.removeTextBeforeSlash(picture, ','), const fileObject = new PublicationAttachmentEntity({
FileExtension: capturedImage.format, base64: this.removeTextBeforeSlash(picture, ','),
extension: capturedImage.format,
FileType: 'image',
OriginalFileName: 'image' OriginalFileName: 'image'
} })
this.seletedContent.push(fileObject) this.seletedContent.push(fileObject)
@@ -251,11 +278,14 @@ export class NewPublicationPage implements OnInit {
.then(async (content) => { .then(async (content) => {
this.filecontent = true; this.filecontent = true;
let fileObject = { let fileObject = new PublicationAttachmentEntity({
FileBase64: 'data:video/mp4;base64,'+content.data, base64: 'data:video/mp4;base64,'+content.data,
FileExtension: 'mp4', extension: 'mp4',
OriginalFileName: 'video' OriginalFileName: 'record',
} FileType: 'video'
})
this.seletedContent.push(fileObject) this.seletedContent.push(fileObject)
}) })
.catch((err) => console.error(err)); .catch((err) => console.error(err));
@@ -294,17 +324,28 @@ export class NewPublicationPage implements OnInit {
this.filecontent = true; this.filecontent = true;
let fileObject; let fileObject;
if(this.removeTextBeforeSlash(element.mimeType, '/') == "mp4") { if(this.removeTextBeforeSlash(element.mimeType, '/') == "mp4") {
fileObject = {
FileBase64: 'data:video/mp4;base64,'+ content.data, const extension = this.removeTextBeforeSlash(element.mimeType, '/')
FileExtension: this.removeTextBeforeSlash(element.mimeType, '/'),
OriginalFileName: 'video' fileObject = new PublicationAttachmentEntity({
} base64: content.data,
extension: extension,
OriginalFileName: 'video',
FileType: 'video'
})
} else { } else {
fileObject = {
FileBase64: content.data, const extension = this.removeTextBeforeSlash(element.mimeType, '/')
FileExtension: this.removeTextBeforeSlash(element.mimeType, '/'),
OriginalFileName: 'image' fileObject = new PublicationAttachmentEntity({
} base64: content.data,
extension: extension,
OriginalFileName: 'image',
FileType: 'image'
})
} }
this.seletedContent.push(fileObject) this.seletedContent.push(fileObject)
@@ -533,8 +574,6 @@ export class NewPublicationPage implements OnInit {
try { try {
await this.publications.CreatePublication(this.folderId, this.publication).toPromise(); await this.publications.CreatePublication(this.folderId, this.publication).toPromise();
this.close(); this.close();
this.httpErrorHandle.httpsSucessMessagge('Criar publicação') this.httpErrorHandle.httpsSucessMessagge('Criar publicação')
@@ -740,12 +779,16 @@ export class NewPublicationPage implements OnInit {
if (this.checkFileType.checkFileType(FileExtension) == 'image' || this.checkFileType.checkFileType(FileExtension) == 'video') { if (this.checkFileType.checkFileType(FileExtension) == 'image' || this.checkFileType.checkFileType(FileExtension) == 'video') {
let resultUrl = decodeURIComponent(element.url); let resultUrl = decodeURIComponent(element.url);
Filesystem.readFile({ path: resultUrl }).then(async (content) => { Filesystem.readFile({ path: resultUrl }).then(async (content) => {
console.log('shared base', content.data)
let fileObject = { let fileObject = new PublicationAttachmentEntity(
FileBase64: this.removeTextBeforeSlash(content.data, ','), {
FileExtension: FileExtension, base64: this.removeTextBeforeSlash(content.data, ','),
OriginalFileName: 'shared', extension: FileExtension,
} OriginalFileName: "share-content",
FileType: this.checkFileType.checkFileType(FileExtension) as any
}
)
this.seletedContent.push(fileObject) this.seletedContent.push(fileObject)
}) })
} else { } else {
@@ -98,6 +98,7 @@ export class PublicationsPage implements OnInit {
this.hideRefreshButton(); this.hideRefreshButton();
this.intent = window["sharedContent"] this.intent = window["sharedContent"]
window["refreshPublication"] = this.refreshing
} }
@@ -124,7 +125,7 @@ export class PublicationsPage implements OnInit {
} }
} }
refreshing() { refreshing = () => {
setTimeout(() => { setTimeout(() => {
this.getActions(); this.getActions();
}, 1500); }, 1500);
+139 -143
View File
@@ -10,60 +10,60 @@ import { HubConnectionBuilder } from '@microsoft/signalr';
providedIn: 'root' providedIn: 'root'
}) })
export class SocketConnectionMCRService { export class SocketConnectionMCRService {
private callbacks: Function[] = [] // private callbacks: Function[] = []
private onDisconnect: Function[] = [] // private onDisconnect: Function[] = []
private onConnect: Function[] = [] // private onConnect: Function[] = []
constructor(private http: HttpClient,) { // constructor(private http: HttpClient,) {
window["http"] = this.http // window["http"] = this.http
} // }
connect() { // connect() {
var connection = new signalR.HubConnectionBuilder() // var connection = new signalR.HubConnectionBuilder()
.withUrl("https://gdcmapi-dev.dyndns.info/FileHub", { // .withUrl("https://gdcmapi-dev.dyndns.info/FileHub", {
accessTokenFactory: () => "Bearer "+SessionStore.user.Authorization // accessTokenFactory: () => "Bearer "+SessionStore.user.Authorization
}).configureLogging(signalR.LogLevel.Information) // }).configureLogging(signalR.LogLevel.Information)
.build(); // .build();
connection.on("ReceiveMessage", (message) => { // connection.on("ReceiveMessage", (message) => {
console.log("ReceiveMessage", message) // console.log("ReceiveMessage", message)
}) // })
connection.onreconnected((connectionId) => { // connection.onreconnected((connectionId) => {
console.assert(connection.state === signalR.HubConnectionState.Connected); // console.assert(connection.state === signalR.HubConnectionState.Connected);
console.log(`Reconnected with connectionId: ${connectionId}`); // console.log(`Reconnected with connectionId: ${connectionId}`);
}); // });
connection.start() // connection.start()
.then(() => { // .then(() => {
console.log("SignalR connection started."); // console.log("SignalR connection started.");
}) // })
.catch((error) => { // .catch((error) => {
console.error("Error starting SignalR connection:", error); // console.error("Error starting SignalR connection:", error);
}); // });
connection.onclose((error) => { // connection.onclose((error) => {
connection.start() // connection.start()
console.log("SignalR connection closed:", error); // console.log("SignalR connection closed:", error);
}); // });
} // }
subscribe(callback) { // subscribe(callback) {
this.callbacks.push(callback); // this.callbacks.push(callback);
} // }
unsubscribe(callback) { // unsubscribe(callback) {
this.callbacks = this.callbacks.filter(cb => cb !== callback); // this.callbacks = this.callbacks.filter(cb => cb !== callback);
} // }
onDisconnectCallback(callback) { // onDisconnectCallback(callback) {
this.onDisconnect.push(callback) // this.onDisconnect.push(callback)
} // }
onConnectCallback(callback) { // onConnectCallback(callback) {
this.onConnect.push(callback) // this.onConnect.push(callback)
} // }
} }
@@ -74,6 +74,7 @@ class ReconnectingWebSocketSignalR {
private callbacks: Function[] = [] private callbacks: Function[] = []
private onDisconnect: Function[] = [] private onDisconnect: Function[] = []
private onConnect: Function[] = [] private onConnect: Function[] = []
private stop = true
constructor() { constructor() {
this.isOpen = false; this.isOpen = false;
@@ -81,9 +82,13 @@ class ReconnectingWebSocketSignalR {
} }
connect() { connect() {
console.log("try to connect=================================")
this.stop = false
this.connection = new signalR.HubConnectionBuilder() this.connection = new signalR.HubConnectionBuilder()
.withUrl("https://gdcmapi-dev.dyndns.info/FileHub", { .withUrl("https://gdcmapi-dev.dyndns.info/FileHub", {
accessTokenFactory: () => "Bearer "+SessionStore.user.Authorization transport: signalR.HttpTransportType.LongPolling,
accessTokenFactory: () => SessionStore.user.Authorization
}).configureLogging(signalR.LogLevel.Information) }).configureLogging(signalR.LogLevel.Information)
.build(); .build();
@@ -95,16 +100,15 @@ class ReconnectingWebSocketSignalR {
this.onConnect.forEach(callback => callback()); this.onConnect.forEach(callback => callback());
console.log("SignalR connection started.");
}) })
.catch((error) => { .catch((error) => {
console.error("Error starting SignalR connection:", error); console.error("Error starting SignalR connection:", error);
}); });
this.connection.on("ReceiveMessage", (message) => { this.connection.on("ReceiveMessage", (message) => {
const data: any = JSON.parse(message) const data: any = JSON.parse(message)
console.log(data) console.log("ReceiveMessage", data)
this.callbacks.forEach(callback => callback(data)); this.callbacks.forEach(callback => callback(data));
}) })
@@ -113,12 +117,27 @@ class ReconnectingWebSocketSignalR {
this.isOpen = false; this.isOpen = false;
this.onDisconnect.forEach(callback => callback()); this.onDisconnect.forEach(callback => callback());
// Attempt to reconnect after a delay // Attempt to reconnect after a delay
setTimeout(() => { if(this.stop) {
this.connect(); setTimeout(() => {
}, 1000); // Adjust the delay as needed this.connect();
}, 1000); // Adjust the delay as needed
}
}); });
}
disconnect() {
this.stop = true
this.connection.stop()
.then(() => {
console.log('WebSocket connection closed');
this.isOpen = false;
this.onDisconnect.forEach(callback => callback());
console.log("SignalR connection stopped.");
})
.catch((error) => {
console.error("Error stopping SignalR connection:", error);
});
} }
subscribe(callback) { subscribe(callback) {
@@ -143,81 +162,81 @@ interface socketResponse {
Guid: string Guid: string
isCompleted: Boolean isCompleted: Boolean
} }
class ReconnectingWebSocket { // class ReconnectingWebSocket {
private url: string // private url: string
private socket // private socket
isOpen: boolean // isOpen: boolean
private callbacks: Function[] = [] // private callbacks: Function[] = []
private onDisconnect: Function[] = [] // private onDisconnect: Function[] = []
private onConnect: Function[] = [] // private onConnect: Function[] = []
http: HttpClient = window["http"] // http: HttpClient = window["http"]
constructor(url) { // constructor(url) {
this.url = url; // this.url = url;
this.socket = null; // this.socket = null;
this.isOpen = false; // this.isOpen = false;
this.connect(); // this.connect();
} // }
connect() { // connect() {
this.socket = new WebSocket(this.url); // this.socket = new WebSocket(this.url);
this.socket.addEventListener('open', (event) => { // this.socket.addEventListener('open', (event) => {
this.isOpen = true; // this.isOpen = true;
console.log('WebSocket connection established'); // console.log('WebSocket connection established');
// Example: Send a message to the server // // Example: Send a message to the server
this.socket.send('Hello, WebSocket Server!'); // this.socket.send('Hello, WebSocket Server!');
this.onConnect.forEach(callback => callback()); // this.onConnect.forEach(callback => callback());
}); // });
this.socket.addEventListener('message', (event) => { // this.socket.addEventListener('message', (event) => {
const data: socketResponse = JSON.parse(event.data) // const data: socketResponse = JSON.parse(event.data)
this.callbacks.forEach(callback => callback(data)); // this.callbacks.forEach(callback => callback(data));
}); // });
this.socket.addEventListener('close', (event) => { // this.socket.addEventListener('close', (event) => {
console.log('WebSocket connection closed'); // console.log('WebSocket connection closed');
this.isOpen = false; // this.isOpen = false;
this.onDisconnect.forEach(callback => callback()); // this.onDisconnect.forEach(callback => callback());
// Attempt to reconnect after a delay // // Attempt to reconnect after a delay
setTimeout(() => { // setTimeout(() => {
this.connect(); // this.connect();
}, 1000); // Adjust the delay as needed // }, 1000); // Adjust the delay as needed
}); // });
} // }
send(message) { // send(message) {
if (this.isOpen) { // if (this.isOpen) {
this.socket.send(message); // this.socket.send(message);
} else { // } else {
console.error('WebSocket connection is not open. Unable to send message.'); // console.error('WebSocket connection is not open. Unable to send message.');
} // }
} // }
close() { // close() {
if (this.isOpen) { // if (this.isOpen) {
this.socket.close(); // this.socket.close();
} // }
} // }
subscribe(callback) { // subscribe(callback) {
this.callbacks.push(callback); // this.callbacks.push(callback);
} // }
unsubscribe(callback) { // unsubscribe(callback) {
this.callbacks = this.callbacks.filter(cb => cb !== callback); // this.callbacks = this.callbacks.filter(cb => cb !== callback);
} // }
onDisconnectCallback(callback) { // onDisconnectCallback(callback) {
this.onDisconnect.push(callback) // this.onDisconnect.push(callback)
} // }
onConnectCallback(callback) { // onConnectCallback(callback) {
this.onConnect.push(callback) // this.onConnect.push(callback)
} // }
} // }
// export class ObjectMergeNotification{ // export class ObjectMergeNotification{
@@ -294,8 +313,10 @@ export class ObjectMergeNotification{
this.runWatch = false this.runWatch = false
}) })
this.socket.subscribe((data: socketResponse) => { this.socket.subscribe((data: socketResponse) => {
if(data.isCompleted == true) { if(data.isCompleted == true) {
console.log("==================!!!====================")
this.callbacks[data.Guid](data) this.callbacks[data.Guid](data)
delete this.callbacks[data.Guid] delete this.callbacks[data.Guid]
} }
@@ -305,36 +326,9 @@ export class ObjectMergeNotification{
} }
connect() { close() {
console.log("close=============================================")
var connection = new signalR.HubConnectionBuilder() this.socket.disconnect();
.withUrl("https://gdcmapi-dev.dyndns.info/FileHub", {
accessTokenFactory: () => "Bearer "+SessionStore.user.Authorization
}).configureLogging(signalR.LogLevel.Information)
.build();
connection.on("ReceiveMessage", (message) => {
console.log("ReceiveMessage", message)
})
connection.onreconnected((connectionId) => {
console.assert(connection.state === signalR.HubConnectionState.Connected);
console.log(`Reconnected with connectionId: ${connectionId}`);
});
connection.start()
.then(() => {
console.log("SignalR connection started.");
})
.catch((error) => {
console.error("Error starting SignalR connection:", error);
});
connection.onclose((error) => {
connection.start()
console.log("SignalR connection closed:", error);
});
} }
async watch() { async watch() {
@@ -354,6 +348,8 @@ export class ObjectMergeNotification{
}, 1000) }, 1000)
} else {
console.log("end loop============================")
} }
} }
@@ -14,7 +14,7 @@ export class CMAPIAPIService {
getVideoHeader(url: string) { getVideoHeader(url: string) {
// return this.http.head('http://localhost:3001/static/'+url, { observe: 'response' }) //return this.http.head('http://localhost:3001/static/'+url, { observe: 'response' })
return this.http.head(environment.apiURL+'ObjectServer/StreamFiles?path='+url, { observe: 'response' }) return this.http.head(environment.apiURL+'ObjectServer/StreamFiles?path='+url, { observe: 'response' })
} }
} }
@@ -56,34 +56,24 @@
<ion-img *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'image'" <ion-img *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'image'"
name="image" ngDefaultControl [src]="seleted.FileBase64" style="height: 69px;"></ion-img> name="image" ngDefaultControl [src]="seleted.FileBase64" style="height: 69px;"></ion-img>
<!-- <div class="progress-container" *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video'">
<div class="progress-bar" id="myProgressBar"></div>
</div> -->
<div *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && seleted.chucksManager"> <div *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && seleted.chucksManager">
<mat-progress-bar <mat-progress-bar
mode="determinate" mode="determinate"
[style.width]="seleted.chucksManager.uploadPercentage" [style.width]="seleted.chucksManager.uploadPercentage"
></mat-progress-bar> ></mat-progress-bar>
</div> </div>
<video *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && checkDesktop() == true" width="70" height="70" <video *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && checkDesktop() == true" width="70" height="70"
preload="metadata" webkit-playsinline="webkit-playsinline"> preload="metadata" webkit-playsinline="webkit-playsinline">
<source type="video/mp4" [src]="seleted.FileBase64"> <source type="video/mp4" [src]="seleted.url">
</video> </video>
<video *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && checkTableDivice() == true" width="70" height="70" <video *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && checkTableDivice() == true" width="70" height="70"
preload="metadata" webkit-playsinline="webkit-playsinline"> preload="metadata" webkit-playsinline="webkit-playsinline">
<source type="video/mp4" [src]="'data:video/mp4;base64,' +seleted.FileBase64"> <source type="video/mp4" [src]="'data:video/mp4;base64,' +seleted.Base64">
</video> </video>
<ion-icon *ngIf="seleted?.chucksManager?.manualRetry" src="assets/images/retry-svgrepo-com.svg" class="icon-download font-12"> </ion-icon> <ion-icon *ngIf="seleted?.chucksManager?.manualRetry" src="assets/images/retry-svgrepo-com.svg" class="icon-download font-12"> </ion-icon>
@@ -93,7 +83,7 @@
</div> </div>
<!-- Display the blurred image and count if there are more images --> <!-- Display the blurred image and count if there are more images -->
<div *ngIf="seletedContent.length > displayLimit" lot="start"> <div *ngIf="seletedContent.length > displayLimit" lot="start">
<ion-img [src]="'data:image/jpg;base64,' + seletedContent[displayLimit - 1].FileBase64" <ion-img [src]="'data:image/jpg;base64,' + seletedContent[displayLimit - 1].Base64"
style="filter: blur(5px);"></ion-img> style="filter: blur(5px);"></ion-img>
<p>mais {{ seletedContent.length - displayLimit }}</p> <p>mais {{ seletedContent.length - displayLimit }}</p>
@@ -22,6 +22,7 @@ import { CaptureError, CaptureImageOptions, MediaCapture, MediaFile } from '@awe
import { Filesystem, Directory, Encoding, FilesystemDirectory } from '@capacitor/filesystem'; import { Filesystem, Directory, Encoding, FilesystemDirectory } from '@capacitor/filesystem';
import { Platform } from '@ionic/angular'; import { Platform } from '@ionic/angular';
import { Capacitor } from '@capacitor/core'; import { Capacitor } from '@capacitor/core';
import { PublicationAttachmentEntity, PublicationFormMV } from '../upload/upload-streaming.service';
enum ActionType { enum ActionType {
@@ -70,9 +71,9 @@ export class NewPublicationPage implements OnInit {
photoOrVideo: boolean = false; photoOrVideo: boolean = false;
video: any; video: any;
publicationFormMV = new PublicationFormMV() publicationFormMV = new PublicationFormMV()
constructor( constructor(
public photoService: PhotoService, public photoService: PhotoService,
private publications: PublicationsService, private publications: PublicationsService,
@@ -97,7 +98,6 @@ export class NewPublicationPage implements OnInit {
this.filecontent = true; this.filecontent = true;
} }
this.SocketConnectionMCRService.connect()
} }
ngOnInit() { ngOnInit() {
@@ -148,13 +148,15 @@ export class NewPublicationPage implements OnInit {
} }
console.log('edit', this.publication) console.log('edit', this.publication)
this.pub = this.publication; this.pub = this.publication;
console.log("this.publication.Files", this.publication.Files)
this.seletedContent = this.publication.Files.map(e => { this.seletedContent = this.publication.Files.map(e => {
return new PublicationAttachmentEntity( return new PublicationAttachmentEntity(
{ {
base64: e.FileBase64, base64: e.FileBase64,
extension: e.FileExtension, extension: e.FileExtension,
OriginalFileName: e.OriginalFileName, OriginalFileName: e.OriginalFileName,
FileType: this.checkFileType.checkFileType(e.FileExtension) FileType: this.checkFileType.checkFileType(e.FileExtension) as any
} }
) )
}) })
@@ -186,11 +188,6 @@ export class NewPublicationPage implements OnInit {
0.9 // quality 0.9 // quality
).then((picture) => { ).then((picture) => {
this.photoOrVideo = false; this.photoOrVideo = false;
let fileObject = {
FileBase64: picture,
FileExtension: this.removeTextBeforeSlash('jpeg', '/'),
OriginalFileName: 'imagem'
}
const FileExtension = this.removeTextBeforeSlash('jpeg', '/') const FileExtension = this.removeTextBeforeSlash('jpeg', '/')
@@ -231,11 +228,6 @@ export class NewPublicationPage implements OnInit {
800, // maxHeight 800, // maxHeight
0.9 // quality 0.9 // quality
).then((picture) => { ).then((picture) => {
let fileObject = {
FileBase64: picture,
FileExtension: this.removeTextBeforeSlash('jpeg', '/'),
OriginalFileName: 'image'
}
const FileExtension = this.removeTextBeforeSlash('jpeg', '/') const FileExtension = this.removeTextBeforeSlash('jpeg', '/')
@@ -278,7 +270,7 @@ export class NewPublicationPage implements OnInit {
console.log("base64 :data:video/mp4;base64,",this.arrayBufferToBase64(await blob.arrayBuffer())) */ console.log("base64 :data:video/mp4;base64,",this.arrayBufferToBase64(await blob.arrayBuffer())) */
this.convertBlobToBase64(blobFile.blob).then((value) => { this.convertBlobToBase64(blobFile.blob).then((value: string) => {
console.log(value) console.log(value)
@@ -294,7 +286,8 @@ export class NewPublicationPage implements OnInit {
base64: value, base64: value,
extension: FileExtension, extension: FileExtension,
blobFile: file, blobFile: file,
FileType: this.checkFileType.checkFileType(FileExtension) FileType: this.checkFileType.checkFileType(FileExtension) as any,
OriginalFileName: 'load video'
} }
) )
@@ -368,7 +361,7 @@ export class NewPublicationPage implements OnInit {
base64: content.data, base64: content.data,
extension: this.removeTextBeforeSlash(element.mimeType, '/'), extension: this.removeTextBeforeSlash(element.mimeType, '/'),
OriginalFileName: 'video', OriginalFileName: 'video',
FileType: this.checkFileType.checkFileType( this.removeTextBeforeSlash(element.mimeType, '/')) FileType: this.checkFileType.checkFileType( this.removeTextBeforeSlash(element.mimeType, '/')) as any
}) })
this.seletedContent.push(fileObject) this.seletedContent.push(fileObject)
}) })
@@ -468,11 +461,10 @@ export class NewPublicationPage implements OnInit {
console.log("this.publication.Files", this.publication.Files) console.log("this.publication.Files", this.publication.Files)
} }
this.publication.Files = this.publication.Files.map( (e: PublicationAttachmentEntity) => ({
this.publication.Files = this.publication.Files.map(e => ({ FileBase64: e.Base64,
FileBase64: e.FileBase64,
FileExtension: e.FileExtension, FileExtension: e.FileExtension,
OriginalFileName: 'foto' OriginalFileName: e.OriginalFileName || 'foto'
})) }))
try { try {
@@ -523,23 +515,21 @@ export class NewPublicationPage implements OnInit {
if(e.FileType == 'video') { if(e.FileType == 'video') {
e.OriginalFileName = e.chucksManager.path e.OriginalFileName = e.chucksManager.path
e.FileExtension = "mp4" e.FileExtension = "mp4"
e.Base64 = ""
} }
return e return e
}) })
console.log("this.publication.Files", this.publication.Files)
} }
this.publication.Files = this.publication.Files.map(e => ({ this.publication.Files = this.publication.Files.map( (e:PublicationAttachmentEntity) => ({
FileBase64: e.FileBase64, FileBase64: e.Base64,
FileExtension: e.FileExtension, FileExtension: e.FileExtension,
OriginalFileName: 'foto' OriginalFileName: e.OriginalFileName || 'foto'
})) }))
const loader = this.toastService.loading() const loader = this.toastService.loading()
try { try {
@@ -560,12 +550,17 @@ export class NewPublicationPage implements OnInit {
loader.remove() loader.remove()
} }
} else { } else {
this.toastService._badRequest("É necessário adicionar uma imagem ou vídeo") this.toastService._badRequest("É necessário adicionar uma imagem ou vídeo")
} }
} }
this.publicationFormMV.ObjectMergeNotification.close()
}
ngOnDestroy() {
this.publicationFormMV.ObjectMergeNotification.close()
} }
close() { close() {
@@ -1071,444 +1066,3 @@ export class NewPublicationPage implements OnInit {
return true; return true;
} }
} }
class UploadFileUseCase {
CMAPIService: CMAPIService = window["CMAPIAPIRepository"]
constructor() {}
async execute(PublicationAttachmentEntity: PublicationAttachmentEntity): Promise<Result<PublicationAttachmentEntity, PublicationAttachmentEntity>> {
return new Promise(async (resolve, reject) => {
PublicationAttachmentEntity.chucksManager.clearManualRetry()
let path: string;
const length = PublicationAttachmentEntity.chucksManager.chunks.totalChunks.toString()
const readAndUploadChunk = async(index: number) => {
const chunk = await PublicationAttachmentEntity.chucksManager.chunks.getChunks(index)
const blob = new Blob([chunk]);
const blobFile = new File([blob], "test.mp4", { type: blob.type });
return this.CMAPIService.FileContent({length, path: PublicationAttachmentEntity.chucksManager.path, index, blobFile})
}
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 {
PublicationAttachmentEntity.chucksManager.setManualRetry()
return reject(err(PublicationAttachmentEntity))
}
}
const allRequest: Promise<any>[] = []
let connection = true
for (let index = 2; ( (index <= PublicationAttachmentEntity.chucksManager.chunks.totalChunks -1) && connection ); 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()) {
connection = false
PublicationAttachmentEntity.chucksManager.setManualRetry()
return 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)
// }
}
}
if(!connection) {
PublicationAttachmentEntity.chucksManager.setManualRetry()
return reject(err(PublicationAttachmentEntity))
} else {
await Promise.all(allRequest)
const uploadRequest = await readAndUploadChunk(PublicationAttachmentEntity.chucksManager.chunks.totalChunks)
if(uploadRequest.isErr()) {
const pingRequest = await this.CMAPIService.ping()
if( pingRequest.isErr()) {
PublicationAttachmentEntity.chucksManager.setManualRetry()
return reject(err(PublicationAttachmentEntity))
}
} else {
PublicationAttachmentEntity.chucksManager.setResponse(PublicationAttachmentEntity.chucksManager.chunks.totalChunks, uploadRequest)
}
PublicationAttachmentEntity.chucksManager.doneChunkUpload()
resolve(ok(PublicationAttachmentEntity))
}
})
}
}
class PublicationAttachmentEntity {
FileBase64: string
FileExtension: string
FileType: 'image' | 'video'
OriginalFileName: string
blobFile: File
toUpload = false;
chucksManager : ChucksManager
constructor({base64, extension, blobFile = null, OriginalFileName = null, FileType}) {
this.FileBase64 = base64;
this.FileExtension = extension;
this.blobFile = blobFile
this.OriginalFileName = OriginalFileName
this.FileType = FileType
this.fixFileBase64();
}
fixFileBase64() {
if(this.FileType == 'image' ) {
if(!this.FileBase64.startsWith('data:')) {
this.FileBase64 = 'data:image/jpg;base64,' + this.FileBase64
}
} else if (this.FileType == 'video' ) {
if(!this.FileBase64.startsWith('data:') && !this.FileBase64.startsWith('http')) {
this.FileBase64 = 'data:video/mp4;base64,' + this.FileBase64
}
}
}
needUpload() {
this.toUpload = true
}
setChunkManger (chunks: Chunks) {
this.chucksManager = new ChucksManager({chunks})
}
get hasChunkManger() {
return this.chucksManager?.chunks
}
get hasChunkManager() {
return this.chucksManager != null
}
}
interface IPublicationFormModelEntity {
DateIndex: any
DocumentId: any
ProcessId: any
Title: any
Message: any
DatePublication: any
Files: PublicationAttachmentEntity[]
}
class PublicationFormModel implements IPublicationFormModelEntity {
constructor() {}
DateIndex: any;
DocumentId: any;
ProcessId: any;
Title: any;
Message: any;
DatePublication: any;
OriginalFileName: string;
Files: PublicationAttachmentEntity[];
hasSet = false
setData(data: IPublicationFormModelEntity) {
if(!this.hasSet) {
Object.assign(this, data)
}
this.hasSet = true
}
}
class PublicationFormMV {
private UploadFileUseCase = new UploadFileUseCase()
private form = new PublicationFormModel()
private ObjectMergeNotification = new ObjectMergeNotification()
setDataToFrom(data: IPublicationFormModelEntity) {
this.form.setData(data)
}
private getVideoFiles() {
return this.form.Files.filter( x => x.FileType == 'video')
}
private upload(PublicationAttachmentEntity: PublicationAttachmentEntity) {
return new Promise(async (resolve, reject)=> {
if(!PublicationAttachmentEntity.hasChunkManger) {
const fileBlob = PublicationAttachmentEntity.blobFile;
const fileChunks = new Chunks({chunkSize: 500 })
fileChunks.setFile(fileBlob)
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)
}
})
}
uploadVideosFiles(): Promise<Boolean> {
return new Promise((resolve, reject)=> {
const videosFiles = this.getVideoFiles()
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);
});
})
}
}
class Chunks {
chunkSize: number
private file: File
constructor({chunkSize}) {
this.chunkSize = chunkSize * 1024
}
get totalChunks () {
return Math.ceil(this.file.size / this.chunkSize);
}
// Function to read a chunk of the file
readChunk(start: number, end: number): Promise<ArrayBuffer> {
const file = this.file
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
if (reader.result instanceof ArrayBuffer) {
resolve(reader.result);
} else {
reject(new Error("Failed to read chunk"));
}
};
reader.readAsArrayBuffer(file.slice(start, end));
});
}
setFile(file: File) {
this.file = file
}
async getChunks(i: number) {
i--
if(i < this.totalChunks) {
const start = i * this.chunkSize;
const end = Math.min(start + this.chunkSize, this.file.size);
const chunk = await this.readChunk(start, end);
return chunk
}
}
}
interface IUploadResponse {
result: Result<any, Error>
attemp: number
}
class ChucksManager {
chunks: Chunks
uploads: {[key: string]: IUploadResponse } = {}
path: string = undefined
uploadPercentage: string = "0%"
merging = false
onSetPath: Function[] = []
onSetLastChunk: Function[] = []
contentReady = false
manualRetry = 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;
}
setManualRetry() {
this.manualRetry = true
}
clearManualRetry() {
this.manualRetry = false
}
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) {
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
}
}
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { UploadStreamingService } from './upload-streaming.service';
describe('UploadStreamingService', () => {
let service: UploadStreamingService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(UploadStreamingService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,483 @@
import { Injectable } from '@angular/core';
import { ok, err, Result } from 'neverthrow';
import { ObjectMergeNotification } from 'src/app/services/socket-connection-mcr.service';
import { CMAPIService } from "src/app/shared/repository/CMAPI/cmapi.service"
@Injectable({
providedIn: 'root'
})
export class UploadStreamingService {
constructor( private CMAPIService: CMAPIService,) { }
}
class UploadFileUseCase {
CMAPIService: CMAPIService = window["CMAPIAPIRepository"]
constructor() {}
async execute(PublicationAttachmentEntity: PublicationAttachmentEntity): Promise<Result<PublicationAttachmentEntity, PublicationAttachmentEntity>> {
return new Promise(async (resolve, reject) => {
PublicationAttachmentEntity.chucksManager.clearManualRetry()
let path: string;
const length = PublicationAttachmentEntity.chucksManager.chunks.totalChunks.toString()
const readAndUploadChunk = async(index: number) => {
const chunk = await PublicationAttachmentEntity.chucksManager.chunks.getChunks(index)
const blob = new Blob([chunk]);
const blobFile = new File([blob], "test.mp4", { type: blob.type });
return this.CMAPIService.FileContent({length, path: PublicationAttachmentEntity.chucksManager.path, index, blobFile})
}
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 {
PublicationAttachmentEntity.chucksManager.setManualRetry()
return reject(err(PublicationAttachmentEntity))
}
}
const allRequest: Promise<any>[] = []
let connection = true
for (let index = 2; ( (index <= PublicationAttachmentEntity.chucksManager.chunks.totalChunks -1) && connection ); 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()) {
connection = false
PublicationAttachmentEntity.chucksManager.setManualRetry()
return 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)
// }
}
}
if(!connection) {
PublicationAttachmentEntity.chucksManager.setManualRetry()
return reject(err(PublicationAttachmentEntity))
} else {
await Promise.all(allRequest)
const uploadRequest = await readAndUploadChunk(PublicationAttachmentEntity.chucksManager.chunks.totalChunks)
if(uploadRequest.isErr()) {
const pingRequest = await this.CMAPIService.ping()
if( pingRequest.isErr()) {
PublicationAttachmentEntity.chucksManager.setManualRetry()
return reject(err(PublicationAttachmentEntity))
}
} else {
PublicationAttachmentEntity.chucksManager.setResponse(PublicationAttachmentEntity.chucksManager.chunks.totalChunks, uploadRequest)
}
PublicationAttachmentEntity.chucksManager.doneChunkUpload()
resolve(ok(PublicationAttachmentEntity))
}
})
}
}
export class PublicationAttachmentEntity {
url: string
FileExtension: string
FileType: 'image' | 'video'
OriginalFileName: string
blobFile?: File
toUpload = false;
chucksManager : ChucksManager
Base64: string
constructor({base64, extension, blobFile, OriginalFileName, FileType}:PublicationAttachmentEntityParams) {
this.Base64 = base64;
this.FileExtension = extension;
this.blobFile = blobFile
this.OriginalFileName = OriginalFileName
this.FileType = FileType
this.fixFileBase64();
}
fixFileBase64() {
if(this.FileType == 'image' ) {
if(!this.Base64.startsWith('data:')) {
this.url = 'data:image/jpg;base64,' + this.Base64
} else {
this.url = this.Base64
}
} else if (this.FileType == 'video' ) {
if(!this.Base64.startsWith('data:') && !this.Base64.startsWith('http')) {
this.url = 'data:video/mp4;base64,' + this.Base64
} else {
this.url = this.Base64
}
}
}
needUpload() {
this.toUpload = true
}
setChunkManger (chunks: Chunks) {
this.chucksManager = new ChucksManager({chunks})
}
get hasChunkManger() {
return this.chucksManager?.chunks
}
get hasChunkManager() {
return this.chucksManager != null
}
}
interface IPublicationFormModelEntity {
DateIndex: any
DocumentId: any
ProcessId: any
Title: any
Message: any
DatePublication: any
Files: PublicationAttachmentEntity[]
}
interface PublicationAttachmentEntityParams {
base64: string,
blobFile?: File
extension: string,
OriginalFileName: string,
FileType: 'image' | 'video'
}
export class PublicationFormModel implements IPublicationFormModelEntity {
constructor() {}
DateIndex: any;
DocumentId: any;
ProcessId: any;
Title: any;
Message: any;
DatePublication: any;
OriginalFileName: string;
Files: PublicationAttachmentEntity[];
hasSet = false
setData(data: IPublicationFormModelEntity) {
if(!this.hasSet) {
Object.assign(this, data)
}
this.hasSet = true
}
}
export class PublicationFormMV {
private UploadFileUseCase = new UploadFileUseCase()
private form = new PublicationFormModel()
ObjectMergeNotification = new ObjectMergeNotification()
setDataToFrom(data: IPublicationFormModelEntity) {
this.form.setData(data)
}
private getVideoFiles() {
return this.form.Files.filter( x => x.FileType == 'video')
}
private upload(PublicationAttachmentEntity: PublicationAttachmentEntity) {
return new Promise(async (resolve, reject)=> {
if(!PublicationAttachmentEntity.hasChunkManger) {
const fileBlob = PublicationAttachmentEntity.blobFile;
const fileChunks = new Chunks({chunkSize: 500 })
fileChunks.setFile(fileBlob)
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)
}
}
if( PublicationAttachmentEntity.chucksManager.isUploading == false) {
PublicationAttachmentEntity.chucksManager.setUploading()
const result = await this.UploadFileUseCase.execute(PublicationAttachmentEntity)
PublicationAttachmentEntity.chucksManager.clearUploading()
if(result.isErr()) {
reject(false)
}
}
})
}
uploadVideosFiles(): Promise<Boolean> {
return new Promise((resolve, reject)=> {
const videosFiles = this.getVideoFiles()
const videosFilesToUploads = videosFiles.filter( e => e.FileType == "video")
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);
});
})
}
}
export class Chunks {
chunkSize: number
private file: File
constructor({chunkSize}) {
this.chunkSize = chunkSize * 1024
}
get totalChunks () {
return Math.ceil(this.file.size / this.chunkSize);
}
// Function to read a chunk of the file
readChunk(start: number, end: number): Promise<ArrayBuffer> {
const file = this.file
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
if (reader.result instanceof ArrayBuffer) {
resolve(reader.result);
} else {
reject(new Error("Failed to read chunk"));
}
};
reader.readAsArrayBuffer(file.slice(start, end));
});
}
setFile(file: File) {
this.file = file
}
async getChunks(i: number) {
i--
if(i < this.totalChunks) {
const start = i * this.chunkSize;
const end = Math.min(start + this.chunkSize, this.file.size);
const chunk = await this.readChunk(start, end);
return chunk
}
}
}
interface IUploadResponse {
result: Result<any, Error>
attemp: number
}
export class ChucksManager {
chunks: Chunks
uploads: {[key: string]: IUploadResponse } = {}
path: string = undefined
uploadPercentage: string = "0%"
merging = false
onSetPath: Function[] = []
onSetLastChunk: Function[] = []
contentReady = false
manualRetry = false
isUploading = false
subscribeToUseCaseResponse: Function[] = []
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;
}
setManualRetry() {
this.manualRetry = true
}
clearManualRetry() {
this.manualRetry = false
}
setUploading() {
this.isUploading = true
}
clearUploading() {
this.isUploading = false
}
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)
}
registerToUseCaseResponse(a: Function) {
this.subscribeToUseCaseResponse.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) {
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
}
}