socket-client.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import { Observable, Subject, takeWhile } from "rxjs";
  2. import { prepareResponseMessages } from "../../services/utility/prepareFISmessage";
  3. import { BaseMessage } from "../../dependencies/logging/interface/export";
  4. import { io, Socket } from "socket.io-client";
  5. import { WrappedMessage } from "../../interfaces/general.interface";
  6. import * as fs from 'fs'
  7. import { ClientInfo } from "./socket.service";
  8. import { MongoService } from "./temp-log-service";
  9. let onHoldMessagesSubject: Subject<WrappedMessage> = new Subject()
  10. let toBePassedOverToApp: Subject<BaseMessage> = new Subject()
  11. // Serve static files (optional)
  12. let sender: Subject<BaseMessage> = prepareResponseMessages(2, 1000)
  13. let serverSocketUrl: string = 'http://192.168.100.96:3000'
  14. // let serverSocketUrl: string = 'http://192.168.100.96:4047'
  15. let socket: Socket
  16. let client: string = 'client1'
  17. let mongoService: MongoService = new MongoService(client)
  18. establishSocketConnection(serverSocketUrl).then(() => {
  19. // sender.sub`scribe({
  20. // next: (message: BaseMessage) => {
  21. // makeRequest(message).subscribe({
  22. // next: (message: BaseMessage) => {
  23. // },
  24. // complete: () => console.log(`Request ${message.header.messageID} has acquired all responses.`)
  25. // })
  26. // }
  27. // })`
  28. })
  29. // the interface the client Program will make without having to decide transport protocol
  30. function makeRequest(request: BaseMessage): Observable<BaseMessage> {
  31. return new Observable((response) => {
  32. sendMessage(request)
  33. toBePassedOverToApp.subscribe({
  34. next: (message: BaseMessage | any) => {
  35. // console.log(message.header.messageName)
  36. // The identification of responses mapping to the request be adjusted accordingly
  37. // For now it's a simple demulti-plexing
  38. if (message.complete) {
  39. response.complete()
  40. } else {
  41. response.next(message)
  42. }
  43. },
  44. error: err => console.error(err),
  45. complete: () => { }
  46. })
  47. })
  48. }
  49. // socket util: Assuming that the client program would already have something like this in place
  50. async function establishSocketConnection(serverUrl: string): Promise<any> {
  51. return new Promise((resolve, reject) => {
  52. try {
  53. socket = io(serverUrl, {
  54. reconnection: true, // Enable automatic reconnections
  55. reconnectionAttempts: 100, // Retry up to 10 times
  56. reconnectionDelay: 500, // Start with a 500ms delay
  57. reconnectionDelayMax: 10000, // Delay can grow to a max of 10 seconds
  58. randomizationFactor: 0.3,
  59. })
  60. // Check if it's a previuos client.
  61. let data: ClientInfo | null = checkOwnClientInfo(client)
  62. if (data) {
  63. socket.emit('notification', { agenda: 'existingClient', data: data })
  64. } else {
  65. socket.emit('notification', { agenda: 'newClient' })
  66. }
  67. // Listen for a connection event
  68. socket.on('connect', () => {
  69. // socket.emit('Hello from the client!')
  70. console.log('Connected to the server:', socket.id)
  71. });
  72. // Listen for messages from the server
  73. socket.on('response', (msg: WrappedMessage) => {
  74. console.log('Message from server:', msg.payload.header.messageName ?? 'null', ' for ', msg.payload.header.messageID ?? 'complete');
  75. if (!msg.payload.complete) {
  76. mongoService.write(msg.payload, msg.payload.header.messageID, () => console.log(`Error function doesn't exist.`))
  77. }
  78. // Check the sequence by ensuring the message value before the current message exists, then pass them over to "App"
  79. // onHoldMessagesSubject.next(msg)
  80. // checkMessage(msg, onHoldMessageSubject).then(() => [
  81. // toBePassedOverToApp.next(msg.payload as BaseMessage)
  82. // ]).catch((err) => console.error(err))
  83. toBePassedOverToApp.next(msg.payload)
  84. })
  85. socket.on('notification', (msg: any) => {
  86. if (msg.notification == 'Your credentials') {
  87. console.log(`Assigned client Name: ${msg.socketInfo.clientName}`)
  88. writeFile(msg.socketInfo as ClientInfo, client)
  89. }
  90. if (msg.notification == 'Your updated credentials') {
  91. console.log(`Updated socket ID: `, msg)
  92. // writeFile(msg.socketInfo as ClientInfo)
  93. }
  94. if (msg.notification == 'Failed Request') {
  95. console.log(`Resending request...`, msg.data.header.messageID)
  96. setTimeout(() => {
  97. sender.next(msg.data)
  98. }, 1000)
  99. }
  100. })
  101. resolve('')
  102. // Handle disconnection
  103. socket.on('disconnect', () => {
  104. console.log('Disconnected from the server');
  105. // receiverConnectionState.next('OFFLINE')
  106. });
  107. }
  108. catch (error) {
  109. reject(error)
  110. }
  111. })
  112. }
  113. function checkOwnClientInfo(filename: string): ClientInfo | null {
  114. // Check if the file exists
  115. if (fs.existsSync(`${filename}.json`)) {
  116. try {
  117. // Read the file contents
  118. const fileData = fs.readFileSync(`${filename}.json`, 'utf8');
  119. // If the file is empty, return an error
  120. if (fileData.trim() === "") {
  121. throw new Error("File is empty");
  122. }
  123. // Parse and return the data if present
  124. const jsonData = JSON.parse(fileData);
  125. return jsonData;
  126. } catch (err) {
  127. // Handle parsing errors or other file-related errors
  128. console.error("Error reading or parsing file:", err.message);
  129. return null;
  130. }
  131. } else {
  132. console.error("File does not exist");
  133. return null;
  134. }
  135. }
  136. function writeFile(data: ClientInfo, filename: string) {
  137. // Write JSON data to a file
  138. fs.writeFile(`${filename}.json`, JSON.stringify(data, null, 2), (err) => {
  139. if (err) {
  140. console.error('Error writing file', err);
  141. } else {
  142. console.log('File has been written');
  143. }
  144. });
  145. }
  146. async function sendMessage(message: BaseMessage): Promise<any> {
  147. return new Promise((resolve, reject) => {
  148. try {
  149. // extra precaution: According to chatgpt, if disconnected, then the payload will be loaded back in event queue whilst the socket will try to reestablish connection
  150. // https://socket.io/docs/v4/client-offline-behavior/
  151. socket.emit('request', message); // inherently an aysnc
  152. console.log(`SocketEmit() for message to event queue ${message.header.messageID}`)
  153. resolve('')
  154. } catch (error) {
  155. console.error('Error emitting message:', error);
  156. sender.next(message)
  157. reject(error)
  158. }
  159. })
  160. }