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"
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>
<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">
<source type="video/mp4" [src]="'data:video/mp4;base64,' + seleted.FileBase64">
<source type="video/mp4" [src]="'data:video/mp4;base64,' + seleted.Base64">
</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>
<!-- Display the blurred image and count if there are more images -->
<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>
<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 { checkFileTypeService } from 'src/app/services/checkFileType.service';
import { FileValidatorService } from "src/app/services/file/file-validator.service"
import { PublicationAttachmentEntity } from 'src/app/shared/publication/upload/upload-streaming.service';
const config = {
quality: 0.5,
maxWidth: 800,
@@ -92,6 +93,13 @@ export class NewPublicationPage implements OnInit {
publicationTitle: string;
imgUrl: any;
ActionType = {
newRapid : "1",
new: "2",
edit: "3"
}
Defaultimage: any = '';
photo: SafeResourceUrl;
@@ -112,7 +120,7 @@ export class NewPublicationPage implements OnInit {
photoOrVideo: boolean = false;
fileType = "";
filecontent: boolean;
seletedContent: any[] = []
seletedContent: PublicationAttachmentEntity[] = []
// Set a limit for the number of images to display
displayLimit = 4;
filesSizeSum = 0;
@@ -142,6 +150,18 @@ export class NewPublicationPage implements OnInit {
if (this.publication) {
this.seletedContent = this.publication.Files;
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)
this.publicationTitle = 'Nova Publicação';
@@ -161,12 +181,16 @@ export class NewPublicationPage implements OnInit {
recursive: true
});
document.addEventListener("click", clickOutside, false);
function clickOutside(e) {
const inside = document.getElementById('container-multiselect').contains(e.target);
this.photoOrVideo = false;
console.log(this.photoOrVideo)
}
try {
document.addEventListener("click", clickOutside, false);
function clickOutside(e) {
const inside = document.getElementById('container-multiselect').contains(e.target);
this.photoOrVideo = false;
console.log(this.photoOrVideo)
}
} catch (error) {}
}
// in use
@@ -193,11 +217,14 @@ export class NewPublicationPage implements OnInit {
console.log('take picture', this.removeTextBeforeSlash(picture, ','),)
this.filecontent = true;
this.photoOrVideo = false;
let fileObject = {
FileBase64: this.removeTextBeforeSlash(picture, ','),
FileExtension: capturedImage.format,
const fileObject = new PublicationAttachmentEntity({
base64: this.removeTextBeforeSlash(picture, ','),
extension: capturedImage.format,
FileType: 'image',
OriginalFileName: 'image'
}
})
this.seletedContent.push(fileObject)
@@ -251,11 +278,14 @@ export class NewPublicationPage implements OnInit {
.then(async (content) => {
this.filecontent = true;
let fileObject = {
FileBase64: 'data:video/mp4;base64,'+content.data,
FileExtension: 'mp4',
OriginalFileName: 'video'
}
let fileObject = new PublicationAttachmentEntity({
base64: 'data:video/mp4;base64,'+content.data,
extension: 'mp4',
OriginalFileName: 'record',
FileType: 'video'
})
this.seletedContent.push(fileObject)
})
.catch((err) => console.error(err));
@@ -294,19 +324,30 @@ export class NewPublicationPage implements OnInit {
this.filecontent = true;
let fileObject;
if(this.removeTextBeforeSlash(element.mimeType, '/') == "mp4") {
fileObject = {
FileBase64: 'data:video/mp4;base64,'+ content.data,
FileExtension: this.removeTextBeforeSlash(element.mimeType, '/'),
OriginalFileName: 'video'
}
const extension = this.removeTextBeforeSlash(element.mimeType, '/')
fileObject = new PublicationAttachmentEntity({
base64: content.data,
extension: extension,
OriginalFileName: 'video',
FileType: 'video'
})
} else {
fileObject = {
FileBase64: content.data,
FileExtension: this.removeTextBeforeSlash(element.mimeType, '/'),
OriginalFileName: 'image'
}
const extension = this.removeTextBeforeSlash(element.mimeType, '/')
fileObject = new PublicationAttachmentEntity({
base64: content.data,
extension: extension,
OriginalFileName: 'image',
FileType: 'image'
})
}
this.seletedContent.push(fileObject)
})
.catch((err) => console.error(err));
@@ -353,24 +394,24 @@ export class NewPublicationPage implements OnInit {
/* // in use
async laodPicture() {
const capturedImage = await Camera.getPhoto({
quality: 90,
// allowEditing: true,
resultType: CameraResultType.Uri,
source: CameraSource.Photos
});
const response = await fetch(capturedImage.webPath!);
const blob = await response.blob();
this.convertBlobToBase64Worker.postMessage(blob);
this.convertBlobToBase64Worker.onmessage = async (oEvent)=> {
this.capturedImage = oEvent.data
this.capturedImageTitle = 'foto'
}
} */
@@ -497,7 +538,7 @@ export class NewPublicationPage implements OnInit {
OriginalFileName: "video",
}
}
return e
}) */
@@ -533,8 +574,6 @@ export class NewPublicationPage implements OnInit {
try {
await this.publications.CreatePublication(this.folderId, this.publication).toPromise();
this.close();
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') {
let resultUrl = decodeURIComponent(element.url);
Filesystem.readFile({ path: resultUrl }).then(async (content) => {
console.log('shared base', content.data)
let fileObject = {
FileBase64: this.removeTextBeforeSlash(content.data, ','),
FileExtension: FileExtension,
OriginalFileName: 'shared',
}
let fileObject = new PublicationAttachmentEntity(
{
base64: this.removeTextBeforeSlash(content.data, ','),
extension: FileExtension,
OriginalFileName: "share-content",
FileType: this.checkFileType.checkFileType(FileExtension) as any
}
)
this.seletedContent.push(fileObject)
})
} else {
@@ -98,6 +98,7 @@ export class PublicationsPage implements OnInit {
this.hideRefreshButton();
this.intent = window["sharedContent"]
window["refreshPublication"] = this.refreshing
}
@@ -124,7 +125,7 @@ export class PublicationsPage implements OnInit {
}
}
refreshing() {
refreshing = () => {
setTimeout(() => {
this.getActions();
}, 1500);
+139 -143
View File
@@ -10,60 +10,60 @@ import { HubConnectionBuilder } from '@microsoft/signalr';
providedIn: 'root'
})
export class SocketConnectionMCRService {
private callbacks: Function[] = []
private onDisconnect: Function[] = []
private onConnect: Function[] = []
// private callbacks: Function[] = []
// private onDisconnect: Function[] = []
// private onConnect: Function[] = []
constructor(private http: HttpClient,) {
window["http"] = this.http
}
// constructor(private http: HttpClient,) {
// window["http"] = this.http
// }
connect() {
// connect() {
var connection = new signalR.HubConnectionBuilder()
.withUrl("https://gdcmapi-dev.dyndns.info/FileHub", {
accessTokenFactory: () => "Bearer "+SessionStore.user.Authorization
}).configureLogging(signalR.LogLevel.Information)
.build();
// var connection = new signalR.HubConnectionBuilder()
// .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.on("ReceiveMessage", (message) => {
// console.log("ReceiveMessage", message)
// })
connection.onreconnected((connectionId) => {
console.assert(connection.state === signalR.HubConnectionState.Connected);
console.log(`Reconnected with connectionId: ${connectionId}`);
});
// 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.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);
});
// connection.onclose((error) => {
// connection.start()
// console.log("SignalR connection closed:", error);
// });
}
// }
subscribe(callback) {
this.callbacks.push(callback);
}
// subscribe(callback) {
// this.callbacks.push(callback);
// }
unsubscribe(callback) {
this.callbacks = this.callbacks.filter(cb => cb !== callback);
}
// unsubscribe(callback) {
// this.callbacks = this.callbacks.filter(cb => cb !== callback);
// }
onDisconnectCallback(callback) {
this.onDisconnect.push(callback)
}
onConnectCallback(callback) {
this.onConnect.push(callback)
}
// onDisconnectCallback(callback) {
// this.onDisconnect.push(callback)
// }
// onConnectCallback(callback) {
// this.onConnect.push(callback)
// }
}
@@ -74,6 +74,7 @@ class ReconnectingWebSocketSignalR {
private callbacks: Function[] = []
private onDisconnect: Function[] = []
private onConnect: Function[] = []
private stop = true
constructor() {
this.isOpen = false;
@@ -81,9 +82,13 @@ class ReconnectingWebSocketSignalR {
}
connect() {
console.log("try to connect=================================")
this.stop = false
this.connection = new signalR.HubConnectionBuilder()
.withUrl("https://gdcmapi-dev.dyndns.info/FileHub", {
accessTokenFactory: () => "Bearer "+SessionStore.user.Authorization
transport: signalR.HttpTransportType.LongPolling,
accessTokenFactory: () => SessionStore.user.Authorization
}).configureLogging(signalR.LogLevel.Information)
.build();
@@ -95,16 +100,15 @@ class ReconnectingWebSocketSignalR {
this.onConnect.forEach(callback => callback());
console.log("SignalR connection started.");
})
.catch((error) => {
console.error("Error starting SignalR connection:", error);
console.error("Error starting SignalR connection:", error);
});
this.connection.on("ReceiveMessage", (message) => {
const data: any = JSON.parse(message)
console.log(data)
console.log("ReceiveMessage", data)
this.callbacks.forEach(callback => callback(data));
})
@@ -113,12 +117,27 @@ class ReconnectingWebSocketSignalR {
this.isOpen = false;
this.onDisconnect.forEach(callback => callback());
// Attempt to reconnect after a delay
setTimeout(() => {
this.connect();
}, 1000); // Adjust the delay as needed
if(this.stop) {
setTimeout(() => {
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) {
@@ -143,81 +162,81 @@ interface socketResponse {
Guid: string
isCompleted: Boolean
}
class ReconnectingWebSocket {
// class ReconnectingWebSocket {
private url: string
private socket
isOpen: boolean
private callbacks: Function[] = []
private onDisconnect: Function[] = []
private onConnect: Function[] = []
// private url: string
// private socket
// isOpen: boolean
// private callbacks: Function[] = []
// private onDisconnect: Function[] = []
// private onConnect: Function[] = []
http: HttpClient = window["http"]
// http: HttpClient = window["http"]
constructor(url) {
this.url = url;
this.socket = null;
this.isOpen = false;
this.connect();
}
// constructor(url) {
// this.url = url;
// this.socket = null;
// this.isOpen = false;
// this.connect();
// }
connect() {
this.socket = new WebSocket(this.url);
// connect() {
// this.socket = new WebSocket(this.url);
this.socket.addEventListener('open', (event) => {
this.isOpen = true;
console.log('WebSocket connection established');
// this.socket.addEventListener('open', (event) => {
// this.isOpen = true;
// console.log('WebSocket connection established');
// Example: Send a message to the server
this.socket.send('Hello, WebSocket Server!');
this.onConnect.forEach(callback => callback());
});
// // Example: Send a message to the server
// this.socket.send('Hello, WebSocket Server!');
// this.onConnect.forEach(callback => callback());
// });
this.socket.addEventListener('message', (event) => {
const data: socketResponse = JSON.parse(event.data)
this.callbacks.forEach(callback => callback(data));
});
// this.socket.addEventListener('message', (event) => {
// const data: socketResponse = JSON.parse(event.data)
// this.callbacks.forEach(callback => callback(data));
// });
this.socket.addEventListener('close', (event) => {
console.log('WebSocket connection closed');
this.isOpen = false;
this.onDisconnect.forEach(callback => callback());
// Attempt to reconnect after a delay
setTimeout(() => {
this.connect();
}, 1000); // Adjust the delay as needed
});
}
// this.socket.addEventListener('close', (event) => {
// console.log('WebSocket connection closed');
// this.isOpen = false;
// this.onDisconnect.forEach(callback => callback());
// // Attempt to reconnect after a delay
// setTimeout(() => {
// this.connect();
// }, 1000); // Adjust the delay as needed
// });
// }
send(message) {
if (this.isOpen) {
this.socket.send(message);
} else {
console.error('WebSocket connection is not open. Unable to send message.');
}
}
// send(message) {
// if (this.isOpen) {
// this.socket.send(message);
// } else {
// console.error('WebSocket connection is not open. Unable to send message.');
// }
// }
close() {
if (this.isOpen) {
this.socket.close();
}
}
// close() {
// if (this.isOpen) {
// this.socket.close();
// }
// }
subscribe(callback) {
this.callbacks.push(callback);
}
// subscribe(callback) {
// this.callbacks.push(callback);
// }
unsubscribe(callback) {
this.callbacks = this.callbacks.filter(cb => cb !== callback);
}
// unsubscribe(callback) {
// this.callbacks = this.callbacks.filter(cb => cb !== callback);
// }
onDisconnectCallback(callback) {
this.onDisconnect.push(callback)
}
onConnectCallback(callback) {
this.onConnect.push(callback)
}
}
// onDisconnectCallback(callback) {
// this.onDisconnect.push(callback)
// }
// onConnectCallback(callback) {
// this.onConnect.push(callback)
// }
// }
// export class ObjectMergeNotification{
@@ -293,9 +312,11 @@ export class ObjectMergeNotification{
this.socket.onConnectCallback(()=> {
this.runWatch = false
})
this.socket.subscribe((data: socketResponse) => {
if(data.isCompleted == true) {
console.log("==================!!!====================")
this.callbacks[data.Guid](data)
delete this.callbacks[data.Guid]
}
@@ -305,36 +326,9 @@ export class ObjectMergeNotification{
}
connect() {
var connection = new signalR.HubConnectionBuilder()
.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);
});
close() {
console.log("close=============================================")
this.socket.disconnect();
}
async watch() {
@@ -354,6 +348,8 @@ export class ObjectMergeNotification{
}, 1000)
} else {
console.log("end loop============================")
}
}
@@ -14,7 +14,7 @@ export class CMAPIAPIService {
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' })
}
}
@@ -56,34 +56,24 @@
<ion-img *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'image'"
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">
<mat-progress-bar
mode="determinate"
[style.width]="seleted.chucksManager.uploadPercentage"
></mat-progress-bar>
</div>
<video *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && checkDesktop() == true" width="70" height="70"
preload="metadata" webkit-playsinline="webkit-playsinline">
<source type="video/mp4" [src]="seleted.FileBase64">
<source type="video/mp4" [src]="seleted.url">
</video>
<video *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && checkTableDivice() == true" width="70" height="70"
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>
<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>
<!-- Display the blurred image and count if there are more images -->
<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>
<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 { Platform } from '@ionic/angular';
import { Capacitor } from '@capacitor/core';
import { PublicationAttachmentEntity, PublicationFormMV } from '../upload/upload-streaming.service';
enum ActionType {
@@ -70,9 +71,9 @@ export class NewPublicationPage implements OnInit {
photoOrVideo: boolean = false;
video: any;
publicationFormMV = new PublicationFormMV()
constructor(
public photoService: PhotoService,
private publications: PublicationsService,
@@ -97,7 +98,6 @@ export class NewPublicationPage implements OnInit {
this.filecontent = true;
}
this.SocketConnectionMCRService.connect()
}
ngOnInit() {
@@ -148,13 +148,15 @@ export class NewPublicationPage implements OnInit {
}
console.log('edit', this.publication)
this.pub = this.publication;
console.log("this.publication.Files", this.publication.Files)
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)
FileType: this.checkFileType.checkFileType(e.FileExtension) as any
}
)
})
@@ -186,11 +188,6 @@ export class NewPublicationPage implements OnInit {
0.9 // quality
).then((picture) => {
this.photoOrVideo = false;
let fileObject = {
FileBase64: picture,
FileExtension: this.removeTextBeforeSlash('jpeg', '/'),
OriginalFileName: 'imagem'
}
const FileExtension = this.removeTextBeforeSlash('jpeg', '/')
@@ -231,11 +228,6 @@ export class NewPublicationPage implements OnInit {
800, // maxHeight
0.9 // quality
).then((picture) => {
let fileObject = {
FileBase64: picture,
FileExtension: this.removeTextBeforeSlash('jpeg', '/'),
OriginalFileName: 'image'
}
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())) */
this.convertBlobToBase64(blobFile.blob).then((value) => {
this.convertBlobToBase64(blobFile.blob).then((value: string) => {
console.log(value)
@@ -294,7 +286,8 @@ export class NewPublicationPage implements OnInit {
base64: value,
extension: FileExtension,
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,
extension: this.removeTextBeforeSlash(element.mimeType, '/'),
OriginalFileName: 'video',
FileType: this.checkFileType.checkFileType( this.removeTextBeforeSlash(element.mimeType, '/'))
FileType: this.checkFileType.checkFileType( this.removeTextBeforeSlash(element.mimeType, '/')) as any
})
this.seletedContent.push(fileObject)
})
@@ -468,11 +461,10 @@ export class NewPublicationPage implements OnInit {
console.log("this.publication.Files", this.publication.Files)
}
this.publication.Files = this.publication.Files.map(e => ({
FileBase64: e.FileBase64,
this.publication.Files = this.publication.Files.map( (e: PublicationAttachmentEntity) => ({
FileBase64: e.Base64,
FileExtension: e.FileExtension,
OriginalFileName: 'foto'
OriginalFileName: e.OriginalFileName || 'foto'
}))
try {
@@ -523,23 +515,21 @@ export class NewPublicationPage implements OnInit {
if(e.FileType == 'video') {
e.OriginalFileName = e.chucksManager.path
e.FileExtension = "mp4"
e.Base64 = ""
}
return e
})
console.log("this.publication.Files", this.publication.Files)
}
this.publication.Files = this.publication.Files.map(e => ({
FileBase64: e.FileBase64,
this.publication.Files = this.publication.Files.map( (e:PublicationAttachmentEntity) => ({
FileBase64: e.Base64,
FileExtension: e.FileExtension,
OriginalFileName: 'foto'
OriginalFileName: e.OriginalFileName || 'foto'
}))
const loader = this.toastService.loading()
try {
@@ -560,12 +550,17 @@ export class NewPublicationPage implements OnInit {
loader.remove()
}
} else {
this.toastService._badRequest("É necessário adicionar uma imagem ou vídeo")
}
}
this.publicationFormMV.ObjectMergeNotification.close()
}
ngOnDestroy() {
this.publicationFormMV.ObjectMergeNotification.close()
}
close() {
@@ -1071,444 +1066,3 @@ export class NewPublicationPage implements OnInit {
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
}
}