From 2605d73baa0b760868bc7d041a25df04747d9cd5 Mon Sep 17 00:00:00 2001 From: Peter Maquiran Date: Mon, 29 Jan 2024 13:49:53 +0100 Subject: [PATCH 01/16] video uploader --- src/app/models/publication.ts | 2 +- .../services/socket-connection-mcr.service.ts | 330 +++++++++++++- .../API/CMAPI/cmapi-api.service.spec.ts | 16 + src/app/shared/API/CMAPI/cmapi-api.service.ts | 18 + .../shared/API/CMAPI/cmapi.service.spec.ts | 16 + src/app/shared/API/CMAPI/cmapi.service.ts | 21 + .../middleware/middleware-service.service.ts | 38 +- .../new-publication/new-publication.page.html | 18 +- .../new-publication/new-publication.page.ts | 422 +++++++++++------- .../view-publications.page.ts | 19 +- .../shared/repository/CMAPI/cmapi.service.ts | 36 +- 11 files changed, 757 insertions(+), 179 deletions(-) create mode 100644 src/app/shared/API/CMAPI/cmapi-api.service.spec.ts create mode 100644 src/app/shared/API/CMAPI/cmapi-api.service.ts create mode 100644 src/app/shared/API/CMAPI/cmapi.service.spec.ts create mode 100644 src/app/shared/API/CMAPI/cmapi.service.ts diff --git a/src/app/models/publication.ts b/src/app/models/publication.ts index 64c328a1c..3e48e5214 100644 --- a/src/app/models/publication.ts +++ b/src/app/models/publication.ts @@ -11,4 +11,4 @@ export class Publication{ Files:any = []; FileExtension?: string; OrganicEntityId?: number; -} \ No newline at end of file +} diff --git a/src/app/services/socket-connection-mcr.service.ts b/src/app/services/socket-connection-mcr.service.ts index 9d8e440c7..2028c3b52 100644 --- a/src/app/services/socket-connection-mcr.service.ts +++ b/src/app/services/socket-connection-mcr.service.ts @@ -1,24 +1,31 @@ import { Injectable } from '@angular/core'; import * as signalR from "@microsoft/signalr" import { SessionStore } from '../store/session.service'; - +import { v4 as uuidv4 } from 'uuid' +import { HttpClient, HttpHeaders, HttpEventType } from '@angular/common/http'; +import { CMAPIService } from '../shared/repository/CMAPI/cmapi.service'; +import { HubConnectionBuilder } from '@microsoft/signalr'; @Injectable({ providedIn: 'root' }) export class SocketConnectionMCRService { + private callbacks: Function[] = [] + private onDisconnect: Function[] = [] + private onConnect: Function[] = [] - constructor() { } + constructor(private http: HttpClient,) { + window["http"] = this.http + } connect() { var connection = new signalR.HubConnectionBuilder() .withUrl("https://gdcmapi-dev.dyndns.info/FileHub", { - accessTokenFactory: () => SessionStore.user.Authorization + accessTokenFactory: () => "Bearer "+SessionStore.user.Authorization }).configureLogging(signalR.LogLevel.Information) .build(); - connection.on("ReceiveMessage", (message) => { console.log("ReceiveMessage", message) }) @@ -43,4 +50,319 @@ export class SocketConnectionMCRService { } + subscribe(callback) { + this.callbacks.push(callback); + } + + unsubscribe(callback) { + this.callbacks = this.callbacks.filter(cb => cb !== callback); + } + + onDisconnectCallback(callback) { + this.onDisconnect.push(callback) + } + onConnectCallback(callback) { + this.onConnect.push(callback) + } + +} + +class ReconnectingWebSocketSignalR { + + private connection: any + isOpen: boolean + private callbacks: Function[] = [] + private onDisconnect: Function[] = [] + private onConnect: Function[] = [] + + constructor() { + this.isOpen = false; + this.connect(); + } + + connect() { + this.connection = new signalR.HubConnectionBuilder() + .withUrl("https://gdcmapi-dev.dyndns.info/FileHub", { + accessTokenFactory: () => "Bearer "+SessionStore.user.Authorization + }).configureLogging(signalR.LogLevel.Information) + .build(); + + + this.connection.start() + .then(() => { + this.isOpen = true; + console.log('WebSocket connection established'); + + + this.onConnect.forEach(callback => callback()); + console.log("SignalR connection started."); + }) + .catch((error) => { + console.error("Error starting SignalR connection:", error); + }); + + + this.connection.on("ReceiveMessage", (message) => { + const data: any = JSON.parse(message) + console.log(data) + this.callbacks.forEach(callback => callback(data)); + }) + + this.connection.onclose((error) => { + 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 + }); + + + } + + subscribe(callback) { + this.callbacks.push(callback); + } + + unsubscribe(callback) { + this.callbacks = this.callbacks.filter(cb => cb !== callback); + } + + onDisconnectCallback(callback) { + this.onDisconnect.push(callback) + } + onConnectCallback(callback) { + this.onConnect.push(callback) + } +} + +interface socketResponse { + + index: string + Guid: string + isCompleted: Boolean +} +class ReconnectingWebSocket { + + private url: string + private socket + isOpen: boolean + private callbacks: Function[] = [] + private onDisconnect: Function[] = [] + private onConnect: Function[] = [] + + http: HttpClient = window["http"] + + constructor(url) { + this.url = url; + this.socket = null; + this.isOpen = false; + this.connect(); + } + + connect() { + this.socket = new WebSocket(this.url); + + 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()); + }); + + 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 + }); + } + + 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(); + } + } + + subscribe(callback) { + this.callbacks.push(callback); + } + + unsubscribe(callback) { + this.callbacks = this.callbacks.filter(cb => cb !== callback); + } + + onDisconnectCallback(callback) { + this.onDisconnect.push(callback) + } + onConnectCallback(callback) { + this.onConnect.push(callback) + } +} + +// export class ObjectMergeNotification{ + +// //socket = new ReconnectingWebSocket('ws://localhost:3002'); +// callbacks: {[GUID: string]: Function} = {} +// runWatch = true +// CMAPIService: CMAPIService = window["CMAPIAPIRepository"] + +// constructor() { +// // this.socket.onDisconnectCallback(()=> { +// // this.runWatch = true +// // this.watch() +// // }) + +// // this.socket.onConnectCallback(()=> { +// // this.runWatch = false +// // }) + +// // this.socket.subscribe((data: socketResponse) => { +// // if(data.isCompleted == true) { +// // this.callbacks[data.Guid](data) +// // delete this.callbacks[data.Guid] +// // } +// // }) + +// this.watch() +// } + +// async watch() { +// if(this.runWatch) { +// setTimeout(async ()=> { +// for(const [key, funx] of Object.entries(this.callbacks)) { + +// const request = await this.CMAPIService.getVideoHeader(key) + +// if(request.isOk()) { +// funx() +// delete this.callbacks[key] +// } +// } + +// this.watch() +// }, 1000) + + +// } +// } + +// subscribe(GUID, callback:Function) { +// this.callbacks[GUID] = callback; +// } + +// unsubscribe(GUID) { +// delete this.callbacks[GUID] +// } + +// } + + +export class ObjectMergeNotification{ + + socket = new ReconnectingWebSocketSignalR() + callbacks: {[GUID: string]: Function} = {} + runWatch = true + CMAPIService: CMAPIService = window["CMAPIAPIRepository"] + + constructor() { + this.socket.onDisconnectCallback(()=> { + this.runWatch = true + this.watch() + }) + + this.socket.onConnectCallback(()=> { + this.runWatch = false + }) + + this.socket.subscribe((data: socketResponse) => { + if(data.isCompleted == true) { + this.callbacks[data.Guid](data) + delete this.callbacks[data.Guid] + } + }) + + this.watch() + } + + + 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); + }); + + } + + async watch() { + if(this.runWatch) { + setTimeout(async ()=> { + for(const [key, funx] of Object.entries(this.callbacks)) { + + const request = await this.CMAPIService.getVideoHeader(key) + + if(request.isOk()) { + funx() + delete this.callbacks[key] + } + } + + this.watch() + }, 1000) + + + } + } + + subscribe(GUID, callback:Function) { + this.callbacks[GUID] = callback; + } + + unsubscribe(GUID) { + delete this.callbacks[GUID] + } + } diff --git a/src/app/shared/API/CMAPI/cmapi-api.service.spec.ts b/src/app/shared/API/CMAPI/cmapi-api.service.spec.ts new file mode 100644 index 000000000..b50b8ad56 --- /dev/null +++ b/src/app/shared/API/CMAPI/cmapi-api.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { CMAPIAPIService } from './cmapi-api.service'; + +describe('CMAPIAPIService', () => { + let service: CMAPIAPIService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(CMAPIAPIService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/shared/API/CMAPI/cmapi-api.service.ts b/src/app/shared/API/CMAPI/cmapi-api.service.ts new file mode 100644 index 000000000..289afcb7d --- /dev/null +++ b/src/app/shared/API/CMAPI/cmapi-api.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { HttpServiceService } from 'src/app/services/http/http-service.service'; +import { HttpClient, HttpEvent, HttpHeaders, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class CMAPIAPIService { + + constructor( private HttpServiceService: HttpServiceService, + private http: HttpClient,) { } + + + getVideoHeader(url: string) { + return this.http.head('http://localhost:3001/static/'+url, { observe: 'response' }) + } +} diff --git a/src/app/shared/API/CMAPI/cmapi.service.spec.ts b/src/app/shared/API/CMAPI/cmapi.service.spec.ts new file mode 100644 index 000000000..09602502b --- /dev/null +++ b/src/app/shared/API/CMAPI/cmapi.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { CMAPIService } from './cmapi.service'; + +describe('CMAPIService', () => { + let service: CMAPIService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(CMAPIService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/shared/API/CMAPI/cmapi.service.ts b/src/app/shared/API/CMAPI/cmapi.service.ts new file mode 100644 index 000000000..e9519cddf --- /dev/null +++ b/src/app/shared/API/CMAPI/cmapi.service.ts @@ -0,0 +1,21 @@ +import { Injectable } from '@angular/core'; +import { HttpServiceService } from 'src/app/services/http/http-service.service'; +import { HttpClient, HttpEvent, HttpHeaders, HttpParams } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class CMAPIService { + + constructor( private HttpServiceService: HttpServiceService, + private http: HttpClient,) { + window["CMAPIService"] = this + } + + getVideoHeader(url: string): Observable { + return this.http.head(url, { observe: 'response' }) + .map(response => response.status === 200) + .catch(() => Observable.of(false)); + } +} diff --git a/src/app/shared/API/middleware/middleware-service.service.ts b/src/app/shared/API/middleware/middleware-service.service.ts index 4e58739d6..4a0db190c 100644 --- a/src/app/shared/API/middleware/middleware-service.service.ts +++ b/src/app/shared/API/middleware/middleware-service.service.ts @@ -158,7 +158,7 @@ export class MiddlewareServiceService { // =========================================================================== - CMAPIFileContent({length, path, index, blobFile}) { + CMAPIPing() { const headers = new HttpHeaders(); headers.set('Authorization', 'Bearer ' + SessionStore.user.Authorization); @@ -170,6 +170,31 @@ export class MiddlewareServiceService { }; + const formData = new FormData(); + + formData.append("blobFile", "blobFile"); + formData.append("length", "length"); + formData.append("index", "index.toString("); + + + return this.http.post(`${geturl}`, formData, options) + } + + + + CMAPIFileContent({length, path, index, blobFile}) { + const headers = new HttpHeaders(); + headers.set('Authorization', 'Bearer ' + SessionStore.user.Authorization); + + // const geturl = 'http://localhost:3001/FileHub'; + // const geturl = environment.apiURL + 'Tasks/DelegateTask'; + const geturl = environment.apiPCURL + 'FileContent'; + + let options = { + headers: headers + }; + + const formData = new FormData(); formData.append("blobFile", blobFile); @@ -182,4 +207,15 @@ export class MiddlewareServiceService { return this.http.post(`${geturl}`, formData, options) } + + + + tryToReachTheServer() { + let opts = { + headers: {}, + } + + return this.http.post(environment.apiURL + "UserAuthentication/Login", '', opts) + } + } diff --git a/src/app/shared/publication/new-publication/new-publication.page.html b/src/app/shared/publication/new-publication/new-publication.page.html index 47516404b..d7df35fe8 100644 --- a/src/app/shared/publication/new-publication/new-publication.page.html +++ b/src/app/shared/publication/new-publication/new-publication.page.html @@ -62,13 +62,19 @@
--> - + + mode="determinate" + [style.width]="seleted.chucksManager.uploadPercentage" + > + + + + +