fix(PortProxy): Refactor connection tracking to utilize unified records in PortProxy
This commit is contained in:
parent
3de35f3b2c
commit
a53e6f1019
@ -1,5 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-02-23 - 3.10.4 - fix(PortProxy)
|
||||||
|
Refactor connection tracking to utilize unified records in PortProxy
|
||||||
|
|
||||||
|
- Implemented a unified record system for tracking incoming and outgoing connections.
|
||||||
|
- Replaced individual connection tracking sets with a Set of IConnectionRecord.
|
||||||
|
- Improved logging of connection activities and statistics.
|
||||||
|
|
||||||
## 2025-02-23 - 3.10.3 - fix(PortProxy)
|
## 2025-02-23 - 3.10.3 - fix(PortProxy)
|
||||||
Refactor and optimize PortProxy for improved readability and maintainability
|
Refactor and optimize PortProxy for improved readability and maintainability
|
||||||
|
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartproxy',
|
name: '@push.rocks/smartproxy',
|
||||||
version: '3.10.3',
|
version: '3.10.4',
|
||||||
description: 'a proxy for handling high workloads of proxying'
|
description: 'a proxy for handling high workloads of proxying'
|
||||||
}
|
}
|
||||||
|
@ -79,12 +79,19 @@ function extractSNI(buffer: Buffer): string | undefined {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IConnectionRecord {
|
||||||
|
incoming: plugins.net.Socket;
|
||||||
|
outgoing: plugins.net.Socket | null;
|
||||||
|
incomingStartTime: number;
|
||||||
|
outgoingStartTime?: number;
|
||||||
|
connectionClosed: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export class PortProxy {
|
export class PortProxy {
|
||||||
netServer: plugins.net.Server;
|
netServer: plugins.net.Server;
|
||||||
settings: IProxySettings;
|
settings: IProxySettings;
|
||||||
private activeConnections: Set<plugins.net.Socket> = new Set();
|
// Unified record tracking each connection pair.
|
||||||
private incomingConnectionTimes: Map<plugins.net.Socket, number> = new Map();
|
private connectionRecords: Set<IConnectionRecord> = new Set();
|
||||||
private outgoingConnectionTimes: Map<plugins.net.Socket, number> = new Map();
|
|
||||||
private connectionLogger: NodeJS.Timeout | null = null;
|
private connectionLogger: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
private terminationStats: {
|
private terminationStats: {
|
||||||
@ -140,29 +147,26 @@ export class PortProxy {
|
|||||||
|
|
||||||
this.netServer = plugins.net.createServer((socket: plugins.net.Socket) => {
|
this.netServer = plugins.net.createServer((socket: plugins.net.Socket) => {
|
||||||
const remoteIP = socket.remoteAddress || '';
|
const remoteIP = socket.remoteAddress || '';
|
||||||
this.activeConnections.add(socket);
|
const connectionRecord: IConnectionRecord = {
|
||||||
this.incomingConnectionTimes.set(socket, Date.now());
|
incoming: socket,
|
||||||
console.log(`New connection from ${remoteIP}. Active connections: ${this.activeConnections.size}`);
|
outgoing: null,
|
||||||
|
incomingStartTime: Date.now(),
|
||||||
|
connectionClosed: false,
|
||||||
|
};
|
||||||
|
this.connectionRecords.add(connectionRecord);
|
||||||
|
console.log(`New connection from ${remoteIP}. Active connections: ${this.connectionRecords.size}`);
|
||||||
|
|
||||||
let initialDataReceived = false;
|
let initialDataReceived = false;
|
||||||
let incomingTerminationReason: string | null = null;
|
let incomingTerminationReason: string | null = null;
|
||||||
let outgoingTerminationReason: string | null = null;
|
let outgoingTerminationReason: string | null = null;
|
||||||
let targetSocket: plugins.net.Socket | null = null;
|
|
||||||
let connectionClosed = false;
|
|
||||||
|
|
||||||
// Ensure cleanup happens only once.
|
// Ensure cleanup happens only once for the entire connection record.
|
||||||
const cleanupOnce = () => {
|
const cleanupOnce = () => {
|
||||||
if (!connectionClosed) {
|
if (!connectionRecord.connectionClosed) {
|
||||||
connectionClosed = true;
|
connectionRecord.connectionClosed = true;
|
||||||
cleanUpSockets(socket, targetSocket || undefined);
|
cleanUpSockets(connectionRecord.incoming, connectionRecord.outgoing || undefined);
|
||||||
this.incomingConnectionTimes.delete(socket);
|
this.connectionRecords.delete(connectionRecord);
|
||||||
if (targetSocket) {
|
console.log(`Connection from ${remoteIP} terminated. Active connections: ${this.connectionRecords.size}`);
|
||||||
this.outgoingConnectionTimes.delete(targetSocket);
|
|
||||||
}
|
|
||||||
if (this.activeConnections.has(socket)) {
|
|
||||||
this.activeConnections.delete(socket);
|
|
||||||
console.log(`Connection from ${remoteIP} terminated. Active connections: ${this.activeConnections.size}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -242,10 +246,10 @@ export class PortProxy {
|
|||||||
connectionOptions.localAddress = remoteIP.replace('::ffff:', '');
|
connectionOptions.localAddress = remoteIP.replace('::ffff:', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
targetSocket = plugins.net.connect(connectionOptions);
|
const targetSocket = plugins.net.connect(connectionOptions);
|
||||||
if (targetSocket) {
|
connectionRecord.outgoing = targetSocket;
|
||||||
this.outgoingConnectionTimes.set(targetSocket, Date.now());
|
connectionRecord.outgoingStartTime = Date.now();
|
||||||
}
|
|
||||||
console.log(
|
console.log(
|
||||||
`Connection established: ${remoteIP} -> ${targetHost}:${this.settings.toPort}` +
|
`Connection established: ${remoteIP} -> ${targetHost}:${this.settings.toPort}` +
|
||||||
`${serverName ? ` (SNI: ${serverName})` : ''}`
|
`${serverName ? ` (SNI: ${serverName})` : ''}`
|
||||||
@ -314,20 +318,19 @@ export class PortProxy {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Log active connection count, longest running connection durations,
|
// Every 10 seconds log active connection count and longest running durations.
|
||||||
// and termination statistics every 10 seconds.
|
|
||||||
this.connectionLogger = setInterval(() => {
|
this.connectionLogger = setInterval(() => {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
let maxIncoming = 0;
|
let maxIncoming = 0;
|
||||||
for (const startTime of this.incomingConnectionTimes.values()) {
|
|
||||||
maxIncoming = Math.max(maxIncoming, now - startTime);
|
|
||||||
}
|
|
||||||
let maxOutgoing = 0;
|
let maxOutgoing = 0;
|
||||||
for (const startTime of this.outgoingConnectionTimes.values()) {
|
for (const record of this.connectionRecords) {
|
||||||
maxOutgoing = Math.max(maxOutgoing, now - startTime);
|
maxIncoming = Math.max(maxIncoming, now - record.incomingStartTime);
|
||||||
|
if (record.outgoingStartTime) {
|
||||||
|
maxOutgoing = Math.max(maxOutgoing, now - record.outgoingStartTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
console.log(
|
console.log(
|
||||||
`(Interval Log) Active connections: ${this.activeConnections.size}. ` +
|
`(Interval Log) Active connections: ${this.connectionRecords.size}. ` +
|
||||||
`Longest running incoming: ${plugins.prettyMs(maxIncoming)}, outgoing: ${plugins.prettyMs(maxOutgoing)}. ` +
|
`Longest running incoming: ${plugins.prettyMs(maxIncoming)}, outgoing: ${plugins.prettyMs(maxOutgoing)}. ` +
|
||||||
`Termination stats (incoming): ${JSON.stringify(this.terminationStats.incoming)}, ` +
|
`Termination stats (incoming): ${JSON.stringify(this.terminationStats.incoming)}, ` +
|
||||||
`(outgoing): ${JSON.stringify(this.terminationStats.outgoing)}`
|
`(outgoing): ${JSON.stringify(this.terminationStats.outgoing)}`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user