implement TCP server, reimplement maxConnections except it now kicks the oldest connection
This commit is contained in:
@@ -10,8 +10,6 @@ proxyAllowedIps = ["127.0.0.1"]
|
|||||||
origin = false
|
origin = false
|
||||||
# Origins to accept connections from.
|
# Origins to accept connections from.
|
||||||
originAllowedDomains = ["computernewb.com"]
|
originAllowedDomains = ["computernewb.com"]
|
||||||
# Maximum amount of active connections allowed from the same IP.
|
|
||||||
maxConnections = 3
|
|
||||||
|
|
||||||
[auth]
|
[auth]
|
||||||
enabled = false
|
enabled = false
|
||||||
@@ -39,6 +37,8 @@ qmpSockDir = "/tmp/"
|
|||||||
node = "acoolvm"
|
node = "acoolvm"
|
||||||
displayname = "A <b>Really</b> Cool CollabVM Instance"
|
displayname = "A <b>Really</b> Cool CollabVM Instance"
|
||||||
motd = "welcome!"
|
motd = "welcome!"
|
||||||
|
# Maximum amount of active connections allowed from the same IP.
|
||||||
|
maxConnections = 3
|
||||||
# Command used to ban an IP.
|
# Command used to ban an IP.
|
||||||
# Use $IP to specify an ip and (optionally) use $NAME to specify a username
|
# Use $IP to specify an ip and (optionally) use $NAME to specify a username
|
||||||
bancmd = "iptables -A INPUT -s $IP -j REJECT"
|
bancmd = "iptables -A INPUT -s $IP -j REJECT"
|
||||||
|
|||||||
@@ -119,6 +119,12 @@ export default class CollabVMServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public addUser(user: User) {
|
public addUser(user: User) {
|
||||||
|
let sameip = this.clients.filter(c => c.IP.address === user.IP.address);
|
||||||
|
if (sameip.length >= this.Config.collabvm.maxConnections) {
|
||||||
|
// Kick the oldest client
|
||||||
|
// I think this is a better solution than just rejecting the connection
|
||||||
|
sameip[0].kick();
|
||||||
|
}
|
||||||
this.clients.push(user);
|
this.clients.push(user);
|
||||||
user.socket.on('msg', (msg: string) => this.onMessage(user, msg));
|
user.socket.on('msg', (msg: string) => this.onMessage(user, msg));
|
||||||
user.socket.on('disconnect', () => this.connectionClosed(user));
|
user.socket.on('disconnect', () => this.connectionClosed(user));
|
||||||
|
|||||||
@@ -6,8 +6,12 @@ export default interface IConfig {
|
|||||||
proxyAllowedIps: string[];
|
proxyAllowedIps: string[];
|
||||||
origin: boolean;
|
origin: boolean;
|
||||||
originAllowedDomains: string[];
|
originAllowedDomains: string[];
|
||||||
maxConnections: number;
|
|
||||||
};
|
};
|
||||||
|
tcp: {
|
||||||
|
enabled: boolean;
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
}
|
||||||
auth: {
|
auth: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
apiEndpoint: string;
|
apiEndpoint: string;
|
||||||
@@ -31,6 +35,7 @@ export default interface IConfig {
|
|||||||
node: string;
|
node: string;
|
||||||
displayname: string;
|
displayname: string;
|
||||||
motd: string;
|
motd: string;
|
||||||
|
maxConnections: number;
|
||||||
bancmd: string | string[];
|
bancmd: string | string[];
|
||||||
moderatorEnabled: boolean;
|
moderatorEnabled: boolean;
|
||||||
usernameblacklist: string[];
|
usernameblacklist: string[];
|
||||||
|
|||||||
55
cvmts/src/TCP/TCPClient.ts
Normal file
55
cvmts/src/TCP/TCPClient.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import EventEmitter from "events";
|
||||||
|
import NetworkClient from "../NetworkClient.js";
|
||||||
|
import { Socket } from "net";
|
||||||
|
|
||||||
|
export default class TCPClient extends EventEmitter implements NetworkClient {
|
||||||
|
private socket: Socket;
|
||||||
|
private cache: string;
|
||||||
|
|
||||||
|
constructor(socket: Socket) {
|
||||||
|
super();
|
||||||
|
this.socket = socket;
|
||||||
|
this.cache = '';
|
||||||
|
this.socket.on('end', () => {
|
||||||
|
this.emit('disconnect');
|
||||||
|
})
|
||||||
|
this.socket.on('data', (data) => {
|
||||||
|
var msg = data.toString('utf-8');
|
||||||
|
if (msg[msg.length - 1] === '\n') msg = msg.slice(0, -1);
|
||||||
|
this.cache += msg;
|
||||||
|
this.readCache();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private readCache() {
|
||||||
|
for (var index = this.cache.indexOf(';'); index !== -1; index = this.cache.indexOf(';')) {
|
||||||
|
this.emit('msg', this.cache.slice(0, index + 1));
|
||||||
|
this.cache = this.cache.slice(index + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getIP(): string {
|
||||||
|
return this.socket.remoteAddress!;
|
||||||
|
}
|
||||||
|
|
||||||
|
send(msg: string): Promise<void> {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
this.socket.write(msg, (err) => {
|
||||||
|
if (err) {
|
||||||
|
rej(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
close(): void {
|
||||||
|
this.emit('disconnect');
|
||||||
|
this.socket.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
isOpen(): boolean {
|
||||||
|
return this.socket.writable;
|
||||||
|
}
|
||||||
|
}
|
||||||
39
cvmts/src/TCP/TCPServer.ts
Normal file
39
cvmts/src/TCP/TCPServer.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import EventEmitter from "events";
|
||||||
|
import NetworkServer from "../NetworkServer.js";
|
||||||
|
import { Server, Socket } from "net";
|
||||||
|
import IConfig from "../IConfig.js";
|
||||||
|
import { Logger } from "@cvmts/shared";
|
||||||
|
import TCPClient from "./TCPClient.js";
|
||||||
|
import { IPDataManager } from "../IPData.js";
|
||||||
|
import { User } from "../User.js";
|
||||||
|
|
||||||
|
export default class TCPServer extends EventEmitter implements NetworkServer {
|
||||||
|
listener: Server;
|
||||||
|
Config: IConfig;
|
||||||
|
logger: Logger;
|
||||||
|
clients: TCPClient[];
|
||||||
|
|
||||||
|
constructor(config: IConfig) {
|
||||||
|
super();
|
||||||
|
this.logger = new Logger("CVMTS.TCPServer");
|
||||||
|
this.Config = config;
|
||||||
|
this.listener = new Server();
|
||||||
|
this.clients = [];
|
||||||
|
this.listener.on('connection', socket => this.onConnection(socket));
|
||||||
|
}
|
||||||
|
|
||||||
|
private onConnection(socket: Socket) {
|
||||||
|
var client = new TCPClient(socket);
|
||||||
|
this.clients.push(client);
|
||||||
|
this.emit('connect', new User(client, IPDataManager.GetIPData(client.getIP()), this.Config));
|
||||||
|
}
|
||||||
|
|
||||||
|
start(): void {
|
||||||
|
this.listener.listen(this.Config.tcp.port, this.Config.tcp.host, () => {
|
||||||
|
this.logger.Info(`TCP server listening on ${this.Config.tcp.host}:${this.Config.tcp.port}`);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
stop(): void {
|
||||||
|
this.listener.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,13 +6,11 @@ import { Logger } from "@cvmts/shared";
|
|||||||
export default class WSClient extends EventEmitter implements NetworkClient {
|
export default class WSClient extends EventEmitter implements NetworkClient {
|
||||||
socket: WebSocket;
|
socket: WebSocket;
|
||||||
ip: string;
|
ip: string;
|
||||||
logger: Logger;
|
|
||||||
|
|
||||||
constructor(ws: WebSocket, ip: string) {
|
constructor(ws: WebSocket, ip: string) {
|
||||||
super();
|
super();
|
||||||
this.socket = ws;
|
this.socket = ws;
|
||||||
this.ip = ip;
|
this.ip = ip;
|
||||||
this.logger = new Logger("CVMTS.WSClient");
|
|
||||||
this.socket.on('message', (buf: Buffer, isBinary: boolean) => {
|
this.socket.on('message', (buf: Buffer, isBinary: boolean) => {
|
||||||
// Close the user's connection if they send a non-string message
|
// Close the user's connection if they send a non-string message
|
||||||
if (isBinary) {
|
if (isBinary) {
|
||||||
@@ -25,7 +23,6 @@ export default class WSClient extends EventEmitter implements NetworkClient {
|
|||||||
|
|
||||||
this.socket.on('close', () => {
|
this.socket.on('close', () => {
|
||||||
this.emit('disconnect');
|
this.emit('disconnect');
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import * as Shared from '@cvmts/shared';
|
|||||||
import AuthManager from './AuthManager.js';
|
import AuthManager from './AuthManager.js';
|
||||||
import WSServer from './WebSocket/WSServer.js';
|
import WSServer from './WebSocket/WSServer.js';
|
||||||
import { User } from './User.js';
|
import { User } from './User.js';
|
||||||
|
import TCPServer from './TCP/TCPServer.js';
|
||||||
|
|
||||||
let logger = new Shared.Logger('CVMTS.Init');
|
let logger = new Shared.Logger('CVMTS.Init');
|
||||||
|
|
||||||
@@ -58,5 +59,11 @@ async function start() {
|
|||||||
var WS = new WSServer(Config);
|
var WS = new WSServer(Config);
|
||||||
WS.on('connect', (client: User) => CVM.addUser(client));
|
WS.on('connect', (client: User) => CVM.addUser(client));
|
||||||
WS.start();
|
WS.start();
|
||||||
|
|
||||||
|
if (Config.tcp.enabled) {
|
||||||
|
var TCP = new TCPServer(Config);
|
||||||
|
TCP.on('connect', (client: User) => CVM.addUser(client));
|
||||||
|
TCP.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
start();
|
start();
|
||||||
|
|||||||
Reference in New Issue
Block a user