Skip to content

Commit

Permalink
Bug fixes and rc.3 bump
Browse files Browse the repository at this point in the history
  • Loading branch information
Tynarus committed Oct 1, 2021
1 parent a7e78a2 commit 2da72d5
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 27 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@runejs/common",
"version": "2.0.0-rc.1",
"version": "2.0.0-rc.3",
"description": "Common logging, networking, compression, and other functionality for RuneJS applications.",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand Down
35 changes: 24 additions & 11 deletions src/buffer/byte-buffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,11 @@ export class ByteBuffer extends Uint8Array {
return Buffer.from(this);
}

public get(type: 'string' | 'STRING'): string;
public get(type: DataType, signed?: Signedness, endian?: Endianness): number;
public get(type: DataType = 'byte', signed: Signedness = 'signed', endian: Endianness = 'be'): number | string {
public get(): number;
public get(type: Extract<DataType, 'string' | 'STRING'>): string;
public get(type: Extract<DataType, 'long' | 'LONG'>, signed?: Signedness, endian?: Endianness): bigint;
public get(type: Exclude<DataType, 'string' | 'STRING' | 'long' | 'LONG'>, signed?: Signedness, endian?: Endianness): number;
public get(type: DataType = 'byte', signed: Signedness = 'signed', endian: Endianness = 'be'): number | bigint | string {
type = ByteBuffer.getType(type);
signed = ByteBuffer.getSignage(signed);
endian = ByteBuffer.getEndianness(endian);
Expand All @@ -111,18 +113,24 @@ export class ByteBuffer extends Uint8Array {
const smol = type === 'long' ? 'Big' : '';

this._readerIndex += size;
const methodName = `read${signedChar}${smol}Int${bitLength}${suffix}`;
const methodName = `read${smol}${signedChar}Int${bitLength}${suffix}`;

try {
return this[methodName](readerIndex) as number;
if(type === 'long') {
return this[methodName](readerIndex) as bigint;
} else {
return this[methodName](readerIndex) as number;
}
} catch(error) {
logger.error(`Error reading ${methodName}:`, error);
return null;
}
}
}

public put(value: string, type: 'string' | 'STRING'): ByteBuffer;
public put(value: number): ByteBuffer;
public put(value: string, type: Extract<DataType, 'string' | 'STRING'>): ByteBuffer;
public put(value: bigint, type: Extract<DataType, 'long' | 'LONG'>): ByteBuffer;
public put(value: number | bigint, type?: DataType, endian?: Endianness): ByteBuffer
public put(value: number | bigint | string, type: DataType = 'byte', endian: Endianness = 'be'): ByteBuffer {
const writerIndex = this._writerIndex;
Expand All @@ -132,10 +140,8 @@ export class ByteBuffer extends Uint8Array {

if(type === 'smart') {
return this.putSmart(value as number);
} else if(type === 'string') {
if(typeof value === 'string') {
return this.putString(value);
}
} else if(type === 'string' || typeof value === 'string') {
return this.putString(typeof value !== 'string' ? String(value) : value);
} else {
const maxSignedLength = MAX_SIGNED_LENGTHS[type];
const size = BYTE_LENGTH[type];
Expand Down Expand Up @@ -253,7 +259,7 @@ export class ByteBuffer extends Uint8Array {
return this;
}

public getSmart(offset: number, signed: Signedness = 'SIGNED'): number {
public getSmart(offset: number, signed: Signedness = 'signed'): number {
const peek = this[offset];

const signedString = ByteBuffer.getSignage(signed);
Expand All @@ -265,6 +271,13 @@ export class ByteBuffer extends Uint8Array {
}
}

public clone(): ByteBuffer {
const dataCopy = new ByteBuffer(this.length);
this.copy(dataCopy, 0, 0);
dataCopy.readerIndex = this.readerIndex;
return dataCopy;
}

public readUInt24BE(offset: number): number {
return ((this[offset] & 0xff) << 16) + ((this[offset + 1] & 0xff) << 8) + (this[offset + 2] & 0xff);
}
Expand Down
42 changes: 34 additions & 8 deletions src/net/socket-server.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,46 @@
import { createServer, Socket } from 'net';
import { createServer, Server, Socket } from 'net';
import { ByteBuffer } from '../buffer';
import { logger } from '../logger';
import { ConnectionStatus } from './connection-status';
import { setObjectProps } from '../util';


export class SocketServerOptions {

public handshakeRequired: boolean = true;
public noDelay: boolean = true;
public keepAlive: boolean = true;
public timeout: number = 30000;

public constructor(props?: Partial<SocketServerOptions>) {
setObjectProps<SocketServerOptions>(this, props);
}

}


export abstract class SocketServer<T = undefined> {

public readonly socket: Socket;
public readonly options: SocketServerOptions;

protected _connectionStatus: ConnectionStatus | T = ConnectionStatus.HANDSHAKE;

public constructor(socket: Socket) {
public constructor(socket: Socket);
public constructor(socket: Socket, options: Partial<SocketServerOptions>);
public constructor(socket: Socket, options: SocketServerOptions);
public constructor(socket: Socket, options: Partial<SocketServerOptions> | SocketServerOptions | undefined);
public constructor(socket: Socket, options?: Partial<SocketServerOptions> | SocketServerOptions | undefined) {
this.socket = socket;
this.options = new SocketServerOptions(options);

socket.setNoDelay(true);
socket.setKeepAlive(true);
socket.setTimeout(30000);
socket.setNoDelay(this.options.noDelay);
socket.setKeepAlive(this.options.keepAlive);
socket.setTimeout(this.options.timeout);

if(!this.options.handshakeRequired) {
this._connectionStatus = ConnectionStatus.ACTIVE;
}

socket.on('data', data => {
try {
Expand All @@ -41,12 +66,13 @@ export abstract class SocketServer<T = undefined> {
hostName: string,
port: number,
socketServerFactory: (socket: Socket) => T
): void {
createServer(socket => {
): Server {
const server = createServer(socket => {
socketServerFactory(socket);
}).listen(port, hostName);

logger.info(`${ serverName } listening @ ${ hostName }:${ port }.`);
return server;
}

public dataReceived(data: Buffer): void {
Expand All @@ -56,7 +82,7 @@ export abstract class SocketServer<T = undefined> {

const byteBuffer = ByteBuffer.fromNodeBuffer(data);

if(this.connectionStatus === ConnectionStatus.HANDSHAKE) {
if(this.options.handshakeRequired && this.connectionStatus === ConnectionStatus.HANDSHAKE) {
if(this.initialHandshake(byteBuffer)) {
this._connectionStatus = ConnectionStatus.ACTIVE;
} else {
Expand Down
27 changes: 20 additions & 7 deletions src/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import { Socket } from 'net';
class TestConnectionHandler extends SocketServer {

public decodeMessage(data: ByteBuffer): void {
logger.info(`Data received:`, data.getString());
logger.info(`Data received:`, data.get('string'));
logger.info(data.get('long').toString());
}

public initialHandshake(data: ByteBuffer): boolean {
logger.info(`Initial handshake:`, data.getString());
logger.info(`Initial handshake:`, data.get('string'));
logger.info(data.get('long').toString());
return true;
}

Expand All @@ -24,23 +26,34 @@ class TestConnectionHandler extends SocketServer {
function launchTestServer() {
logger.info('Starting server...');

SocketServer.launch('Test Server', '0.0.0.0', 43594, socket =>
new TestConnectionHandler(socket));
const TEST_PORT = 8000;

const server = SocketServer.launch('Test Server', '0.0.0.0', TEST_PORT, socket =>
new TestConnectionHandler(socket, {
timeout: 300,
keepAlive: false,
handshakeRequired: false
}));

const speakySocket = new Socket();
speakySocket.connect(43594);
speakySocket.connect(TEST_PORT);

setTimeout(() => {
const buffer = new ByteBuffer(200);
buffer.put('hi', 'string');
buffer.put(BigInt('12345'), 'long');
speakySocket.write(buffer.flipWriter());
}, 3000);
}, 1000);

setTimeout(() => {
const buffer = new ByteBuffer(200);
buffer.put('how are you?', 'string');
buffer.put(BigInt('67890'), 'long');
speakySocket.write(buffer.flipWriter());
}, 6000);
}, 2000);

setTimeout(() => speakySocket.destroy(), 3000);
setTimeout(() => server.close(), 4000);
}

launchTestServer();
1 change: 1 addition & 0 deletions src/util/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './strings';
export * from './numbers';
export * from './objects';
30 changes: 30 additions & 0 deletions src/util/objects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export function setObjectProps<T>(object: T,
objectProps: Map<string, unknown> | Partial<T> | undefined,
ignoreFieldNameCase: boolean = false): void {
if(!objectProps) {
return;
}

const dataKeys = objectProps instanceof Map ? Array.from(objectProps.keys()) :
Object.keys(objectProps ?? {});
const objectKeys = Object.keys(object);

dataKeys.forEach(key => {
const existingKey = objectKeys.find(k => {
if(ignoreFieldNameCase) {
return k.toLowerCase() === key.toLowerCase();
} else {
return k === key;
}
});

if(existingKey) {
const value = objectProps instanceof Map ? objectProps.get(key) : objectProps[key];
if(typeof object[existingKey] === 'number' || /^\d*$/.test(value)) {
object[existingKey] = Number(value);
} else {
object[existingKey] = value;
}
}
});
}

0 comments on commit 2da72d5

Please sign in to comment.