network chunk v19
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
import { ParsedMessage } from '../message_handler';
|
import { ParsedMessage } from '../message_handler';
|
||||||
import { OperationHandler } from '../operations_base/operation_handler';
|
import { OperationHandler } from '../operations_base/operation_handler';
|
||||||
import ping from "ping";
|
|
||||||
import {
|
import {
|
||||||
constants,
|
constants,
|
||||||
createCipheriv,
|
createCipheriv,
|
||||||
@@ -16,16 +15,16 @@ export abstract class SocketCommunicatorBase {
|
|||||||
protected readonly port: number;
|
protected readonly port: number;
|
||||||
protected readonly operationHandler: OperationHandler;
|
protected readonly operationHandler: OperationHandler;
|
||||||
protected handlerResult: ParsedMessage | null;
|
protected handlerResult: ParsedMessage | null;
|
||||||
protected networkSpeed: number | null = null;
|
|
||||||
|
|
||||||
protected chunkBuffers: { [messageId: string]: string[] };
|
protected chunkBuffers: { [messageId: string]: string[] };
|
||||||
protected readonly EOP = '<EOP>';
|
|
||||||
|
|
||||||
protected privateKey: string | null;
|
protected privateKey: string | null;
|
||||||
protected publicKey: string | null;
|
protected publicKey: string | null;
|
||||||
protected aesKey: Buffer | null;
|
protected aesKey: Buffer | null;
|
||||||
protected aesIv: Buffer | null;
|
protected aesIv: Buffer | null;
|
||||||
|
|
||||||
|
protected readonly EOP = '<EOP>';
|
||||||
|
protected readonly CHUNK_SIZE = 1024;
|
||||||
private incompleteChunkBuffer: string = '';
|
private incompleteChunkBuffer: string = '';
|
||||||
|
|
||||||
protected constructor(ip: string, port: number, operationHandler: OperationHandler) {
|
protected constructor(ip: string, port: number, operationHandler: OperationHandler) {
|
||||||
@@ -113,40 +112,6 @@ export abstract class SocketCommunicatorBase {
|
|||||||
).toString('base64');
|
).toString('base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async scanNetworkLatency(): Promise<number> {
|
|
||||||
const targetIp = this.ip; // Use the IP from the superclass
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await ping.promise.probe(targetIp);
|
|
||||||
|
|
||||||
if (!response.alive || response.time === "unknown") {
|
|
||||||
console.warn(`Ping failed to reach ${targetIp}. Using default network speed.`);
|
|
||||||
return 200; // Default latency in ms if ping fails
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.time; // Latency in ms from ping response
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error(`Ping error: ${error.message}. Using default network speed.`);
|
|
||||||
return 200; // Default latency in ms if an error occurs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate optimal chunk size based on network latency, with fallback if necessary
|
|
||||||
protected async calculateOptimalChunkSize(messageLength: number): Promise<number> {
|
|
||||||
const latency = await this.scanNetworkLatency();
|
|
||||||
this.networkSpeed = latency > 0 ? 1000 / latency : 1; // Speed in bytes/ms based on latency
|
|
||||||
|
|
||||||
// Calculate initial chunk size based on latency (bounded between 512 and 1024 bytes)
|
|
||||||
let chunkSize = Math.min(Math.max(512, Math.floor(5000 / this.networkSpeed)), 1024);
|
|
||||||
|
|
||||||
// Adjust chunk size for base64 alignment (multiple of 4)
|
|
||||||
while (messageLength % chunkSize !== 0 && chunkSize > 0) {
|
|
||||||
chunkSize -= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return chunkSize || 1024; // Fallback to 1024 if alignment adjustment results in 0
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleIncomingChunk(data: Buffer): Promise<void> {
|
async handleIncomingChunk(data: Buffer): Promise<void> {
|
||||||
// Append incoming data to the incomplete buffer
|
// Append incoming data to the incomplete buffer
|
||||||
this.incompleteChunkBuffer += data.toString();
|
this.incompleteChunkBuffer += data.toString();
|
||||||
|
|||||||
@@ -58,29 +58,29 @@ export class TcpClientCommunicator extends SocketCommunicatorBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise<void> {
|
async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise<void> {
|
||||||
if (!this.networkSpeed) {
|
|
||||||
this.networkSpeed = await this.scanNetworkLatency();
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = MessageHandler.formatMessage(operationCode, metaInfo, fileContent);
|
const message = MessageHandler.formatMessage(operationCode, metaInfo, fileContent);
|
||||||
|
|
||||||
const outgoingMessage = this.encryptWithAes(message);
|
const outgoingMessage = this.encryptWithAes(message);
|
||||||
|
|
||||||
// Calculate optimal chunk size based on network latency
|
// Calculate optimal chunk size based on network latency
|
||||||
const optimalChunkSize = await this.calculateOptimalChunkSize(outgoingMessage.length);
|
const totalChunks = Math.ceil(outgoingMessage.length / this.CHUNK_SIZE);
|
||||||
const totalChunks = Math.ceil(outgoingMessage.length / optimalChunkSize);
|
|
||||||
const messageId = Date.now().toString();
|
const messageId = Date.now().toString();
|
||||||
|
|
||||||
// Send each chunk with a delay between them
|
// Send each chunk with a delay between them
|
||||||
for (let i = 0; i < totalChunks; i++) {
|
for (let i = 0; i < totalChunks; i++) {
|
||||||
const chunk = outgoingMessage.slice(i * optimalChunkSize, (i + 1) * optimalChunkSize);
|
const chunk = outgoingMessage.slice(i * this.CHUNK_SIZE, (i + 1) * this.CHUNK_SIZE);
|
||||||
const chunkHeader = JSON.stringify({
|
const chunkHeader = JSON.stringify({
|
||||||
messageId,
|
messageId,
|
||||||
sequenceNumber: i + 1,
|
sequenceNumber: i + 1,
|
||||||
totalChunks,
|
totalChunks,
|
||||||
});
|
});
|
||||||
const chunkWithHeader = `${chunkHeader}|${chunk}${this.EOP}`;
|
const chunkWithHeader = `${chunkHeader}|${chunk}${this.EOP}`;
|
||||||
while(!this.socket.write(chunkWithHeader));
|
|
||||||
|
if (!this.socket.write(chunkWithHeader)) {
|
||||||
|
// Wait for the 'drain' event before writing the next chunk
|
||||||
|
await new Promise((resolve) => this.socket.once('drain', resolve));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,10 +38,6 @@ export class TcpServerCommunicator extends SocketCommunicatorBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise<void> {
|
async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise<void> {
|
||||||
if (!this.networkSpeed) {
|
|
||||||
this.networkSpeed = await this.scanNetworkLatency();
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = MessageHandler.formatMessage(operationCode, metaInfo, fileContent);
|
const message = MessageHandler.formatMessage(operationCode, metaInfo, fileContent);
|
||||||
|
|
||||||
let outgoingMessage: string;
|
let outgoingMessage: string;
|
||||||
@@ -56,21 +52,23 @@ export class TcpServerCommunicator extends SocketCommunicatorBase {
|
|||||||
outgoingMessage = this.encryptWithAes(message);
|
outgoingMessage = this.encryptWithAes(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate optimal chunk size based on network latency
|
const totalChunks = Math.ceil(outgoingMessage.length / this.CHUNK_SIZE);
|
||||||
const optimalChunkSize = await this.calculateOptimalChunkSize(outgoingMessage.length);
|
|
||||||
const totalChunks = Math.ceil(outgoingMessage.length / optimalChunkSize);
|
|
||||||
const messageId = Date.now().toString();
|
const messageId = Date.now().toString();
|
||||||
|
|
||||||
// Send each chunk with a delay between them
|
// Send each chunk with a delay between them
|
||||||
for (let i = 0; i < totalChunks; i++) {
|
for (let i = 0; i < totalChunks; i++) {
|
||||||
const chunk = outgoingMessage.slice(i * optimalChunkSize, (i + 1) * optimalChunkSize);
|
const chunk = outgoingMessage.slice(i * this.CHUNK_SIZE, (i + 1) * this.CHUNK_SIZE);
|
||||||
const chunkHeader = JSON.stringify({
|
const chunkHeader = JSON.stringify({
|
||||||
messageId,
|
messageId,
|
||||||
sequenceNumber: i + 1,
|
sequenceNumber: i + 1,
|
||||||
totalChunks,
|
totalChunks,
|
||||||
});
|
});
|
||||||
const chunkWithHeader = `${chunkHeader}|${chunk}${this.EOP}`;
|
const chunkWithHeader = `${chunkHeader}|${chunk}${this.EOP}`;
|
||||||
while(!this.socket.write(chunkWithHeader));
|
|
||||||
|
if (!this.socket.write(chunkWithHeader)) {
|
||||||
|
// Wait for the 'drain' event before writing the next chunk
|
||||||
|
await new Promise((resolve) => this.socket.once('drain', resolve));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user