|
@@ -1,11 +1,11 @@
|
|
-import { BehaviorSubject, Observable, Subject } from "rxjs"
|
|
|
|
|
|
+import { BehaviorSubject, catchError, Observable, of, Subject, Subscription, tap, timeout } from "rxjs"
|
|
import { RetransmissionService } from "../../services/retransmission.service"
|
|
import { RetransmissionService } from "../../services/retransmission.service"
|
|
import { BaseMessage } from "../../dependencies/logging/services/logging-service"
|
|
import { BaseMessage } from "../../dependencies/logging/services/logging-service"
|
|
import { v4 as uuidV4 } from 'uuid';
|
|
import { v4 as uuidV4 } from 'uuid';
|
|
-import { Socket } from "socket.io-client";
|
|
|
|
const express = require('express');
|
|
const express = require('express');
|
|
const http = require('http');
|
|
const http = require('http');
|
|
-const { Server } = require('socket.io');
|
|
|
|
|
|
+// const { Server } = require('socket.io');
|
|
|
|
+import { Server } from 'socket.io'
|
|
|
|
|
|
/* This is only for demonstration purposes. Because the actual nestjs socket implementation may differ. */
|
|
/* This is only for demonstration purposes. Because the actual nestjs socket implementation may differ. */
|
|
export class SocketService {
|
|
export class SocketService {
|
|
@@ -15,7 +15,7 @@ export class SocketService {
|
|
private app = express();
|
|
private app = express();
|
|
private server = http.createServer(this.app);
|
|
private server = http.createServer(this.app);
|
|
private io = new Server(this.server);
|
|
private io = new Server(this.server);
|
|
- private responseFromApp: Subject<BaseMessage>
|
|
|
|
|
|
+ private responseFromApp: Subject<BaseMessage | any>
|
|
private incomingRequest: Subject<BaseMessage> = new Subject()
|
|
private incomingRequest: Subject<BaseMessage> = new Subject()
|
|
|
|
|
|
constructor(response: Subject<BaseMessage>) {
|
|
constructor(response: Subject<BaseMessage>) {
|
|
@@ -32,7 +32,6 @@ export class SocketService {
|
|
public async setUpConnection() {
|
|
public async setUpConnection() {
|
|
this.io.on('connection', (socket) => {
|
|
this.io.on('connection', (socket) => {
|
|
this.announcements.next('a client is connected:' + socket.id);
|
|
this.announcements.next('a client is connected:' + socket.id);
|
|
- let clientIsOnline: BehaviorSubject<boolean> = new BehaviorSubject(true)
|
|
|
|
let clientInfo: ClientInfo | null
|
|
let clientInfo: ClientInfo | null
|
|
|
|
|
|
socket.on('connect', (msg) => {
|
|
socket.on('connect', (msg) => {
|
|
@@ -49,7 +48,7 @@ export class SocketService {
|
|
clientConnectionState: new BehaviorSubject<'ONLINE' | 'OFFLINE'>('ONLINE'),
|
|
clientConnectionState: new BehaviorSubject<'ONLINE' | 'OFFLINE'>('ONLINE'),
|
|
requests: [],
|
|
requests: [],
|
|
buffer: new RetransmissionService(),
|
|
buffer: new RetransmissionService(),
|
|
- responseObs: new Subject<BaseMessage>()
|
|
|
|
|
|
+ responseObs: new Subject<any>()
|
|
}
|
|
}
|
|
this.connectedClients.push(clientInfo);
|
|
this.connectedClients.push(clientInfo);
|
|
|
|
|
|
@@ -64,7 +63,7 @@ export class SocketService {
|
|
clientInfo.buffer.retransmission(clientInfo.responseObs, clientInfo.clientConnectionState)
|
|
clientInfo.buffer.retransmission(clientInfo.responseObs, clientInfo.clientConnectionState)
|
|
let subscription = clientInfo.buffer.returnBufferedMessages().subscribe(output => {
|
|
let subscription = clientInfo.buffer.returnBufferedMessages().subscribe(output => {
|
|
// console.log(output)
|
|
// console.log(output)
|
|
- if (clientIsOnline.getValue() === true) {
|
|
|
|
|
|
+ if (clientInfo.clientConnectionState.getValue() === 'ONLINE') {
|
|
socket.emit('response', output)
|
|
socket.emit('response', output)
|
|
} else {
|
|
} else {
|
|
subscription.unsubscribe()
|
|
subscription.unsubscribe()
|
|
@@ -74,12 +73,12 @@ export class SocketService {
|
|
|
|
|
|
if (msg.agenda == 'existingClient') {
|
|
if (msg.agenda == 'existingClient') {
|
|
// check if client exists
|
|
// check if client exists
|
|
- let clientObj = this.connectedClients.find(obj => obj.clientName === msg.data.clientName)
|
|
|
|
|
|
+ let clientObj: ClientInfo = this.connectedClients.find(obj => obj.clientName === msg.data.clientName)
|
|
if (clientObj) {
|
|
if (clientObj) {
|
|
clientInfo = clientObj
|
|
clientInfo = clientObj
|
|
console.log('Existing client found')
|
|
console.log('Existing client found')
|
|
// but also update socketId
|
|
// but also update socketId
|
|
- clientObj.id = socket.id
|
|
|
|
|
|
+ clientInfo.id = socket.id
|
|
|
|
|
|
// Send data over for client to persist
|
|
// Send data over for client to persist
|
|
socket.emit('notification', {
|
|
socket.emit('notification', {
|
|
@@ -91,14 +90,36 @@ export class SocketService {
|
|
// resume operation Release them buffer
|
|
// resume operation Release them buffer
|
|
/* local client isOnline need not be mutated, since this is a new connection. However the previous intance of client Connection State
|
|
/* local client isOnline need not be mutated, since this is a new connection. However the previous intance of client Connection State
|
|
inside the retransmission needs to be updated to release the buffered values.*/
|
|
inside the retransmission needs to be updated to release the buffered values.*/
|
|
- let subscription = clientObj.buffer.returnBufferedMessages().subscribe(output => {
|
|
|
|
- // console.log(output)
|
|
|
|
- if (clientIsOnline.getValue() === true) {
|
|
|
|
- socket.emit('response', output)
|
|
|
|
- } else {
|
|
|
|
- subscription.unsubscribe()
|
|
|
|
- }
|
|
|
|
- })
|
|
|
|
|
|
+ function releaseBufferedItems(clientInfo: ClientInfo) {
|
|
|
|
+ let subscription: Subscription = clientInfo.buffer.returnBufferedMessages().pipe(
|
|
|
|
+ tap(message => {
|
|
|
|
+ if (clientInfo.clientConnectionState.getValue() === 'OFFLINE') {
|
|
|
|
+ clientInfo.responseObs.next(message)
|
|
|
|
+ }
|
|
|
|
+ }),
|
|
|
|
+ timeout(10000), // Unsubscribe if no value is emitted within 10 seconds
|
|
|
|
+ catchError(err => {
|
|
|
|
+ if (err.name === 'TimeoutError') {
|
|
|
|
+ console.log('TimeoutError: No value emitted within 10 seconds.');
|
|
|
|
+ if (clientInfo.clientConnectionState.getValue() === 'ONLINE') {
|
|
|
|
+ releaseBufferedItems(clientInfo); // Call the function if it's still online
|
|
|
|
+ } else {
|
|
|
|
+ subscription.unsubscribe()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return of();
|
|
|
|
+ })
|
|
|
|
+ )
|
|
|
|
+ .subscribe({
|
|
|
|
+ next: output => {
|
|
|
|
+ socket.emit('response', output)
|
|
|
|
+ },
|
|
|
|
+ error: err => console.error(err),
|
|
|
|
+ complete: () => { }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ releaseBufferedItems(clientInfo)
|
|
|
|
+ //signal to release buffered items
|
|
clientObj.clientConnectionState.next('ONLINE')
|
|
clientObj.clientConnectionState.next('ONLINE')
|
|
} else {
|
|
} else {
|
|
console.log(this.connectedClients)
|
|
console.log(this.connectedClients)
|
|
@@ -134,7 +155,6 @@ export class SocketService {
|
|
// Handle disconnection
|
|
// Handle disconnection
|
|
socket.on('disconnect', () => {
|
|
socket.on('disconnect', () => {
|
|
if (clientInfo) {
|
|
if (clientInfo) {
|
|
- clientIsOnline.next(false)
|
|
|
|
clientInfo.clientConnectionState.next('OFFLINE') // signal to start buffering\
|
|
clientInfo.clientConnectionState.next('OFFLINE') // signal to start buffering\
|
|
this.announcements.next(`Client ${clientInfo.id} disconnected`);
|
|
this.announcements.next(`Client ${clientInfo.id} disconnected`);
|
|
// this.deleteClientById(socket.id)
|
|
// this.deleteClientById(socket.id)
|
|
@@ -167,17 +187,17 @@ export class SocketService {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private processRequest(request: BaseMessage): Observable<BaseMessage> {
|
|
|
|
|
|
+ private processRequest(request: BaseMessage): Observable<any> {
|
|
return new Observable((observer) => {
|
|
return new Observable((observer) => {
|
|
this.responseFromApp.subscribe(message => {
|
|
this.responseFromApp.subscribe(message => {
|
|
// console.log(message)
|
|
// console.log(message)
|
|
- if (message.header.messageID === request.header.messageID && message.header.messageName != 'Complete') {
|
|
|
|
- observer.next(message)
|
|
|
|
- }
|
|
|
|
- if (message.header.messageID === request.header.messageID && message.header.messageName == 'Complete') {
|
|
|
|
- observer.next(message)
|
|
|
|
- // console.log(message) // so it does show
|
|
|
|
- observer.complete()
|
|
|
|
|
|
+ if (message.header.messageID === request.header.messageID) {
|
|
|
|
+ if (!message.complete) {
|
|
|
|
+ observer.next(message)
|
|
|
|
+ } else {
|
|
|
|
+ observer.next(message)
|
|
|
|
+ observer.complete()
|
|
|
|
+ }
|
|
}
|
|
}
|
|
})
|
|
})
|
|
})
|
|
})
|
|
@@ -193,5 +213,5 @@ export interface ClientInfo {
|
|
clientConnectionState: BehaviorSubject<'ONLINE' | 'OFFLINE'>,
|
|
clientConnectionState: BehaviorSubject<'ONLINE' | 'OFFLINE'>,
|
|
requests: { message: any, completed: boolean }[],
|
|
requests: { message: any, completed: boolean }[],
|
|
buffer: RetransmissionService,
|
|
buffer: RetransmissionService,
|
|
- responseObs: Subject<BaseMessage>
|
|
|
|
|
|
+ responseObs: Subject<any>
|
|
}
|
|
}
|