From 672aa14ec00dc702330897cc04a421971a92ce5d Mon Sep 17 00:00:00 2001 From: TheBlackParade Date: Fri, 23 Oct 2020 20:11:38 -0500 Subject: [PATCH] Converting byte-buffer package into @runejs/core --- README.md | 9 +++- package-lock.json | 78 +++++++++++++++++++++------------ package.json | 23 +++++----- src/{ => buffer}/byte-buffer.ts | 0 src/index.ts | 5 ++- src/logger/logger.ts | 28 ++++++++++++ src/net/server-config.ts | 51 +++++++++++++++++++++ src/net/socket-server.ts | 48 ++++++++++++++++++++ src/test.ts | 25 +++++++++++ 9 files changed, 226 insertions(+), 41 deletions(-) rename src/{ => buffer}/byte-buffer.ts (100%) create mode 100644 src/logger/logger.ts create mode 100644 src/net/server-config.ts create mode 100644 src/net/socket-server.ts diff --git a/README.md b/README.md index 1e8cea5..0f73493 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ -# RuneJS Byte Buffer +[![RuneJS Discord Server](https://img.shields.io/discord/678751302297059336?label=RuneJS%20Discord&logo=discord)](https://discord.gg/5P74nSh) -A customized implementation of a NodeJS Buffer. + +![RuneJS](https://i.imgur.com/osF9OSD.png) + +# @runejs/core + +Core functionality for RuneJS applications. diff --git a/package-lock.json b/package-lock.json index b5c1383..f6625d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,23 +1,13 @@ { - "name": "@runejs/byte-buffer", - "version": "1.0.8", + "name": "@runejs/core", + "version": "1.0.0-beta.0", "lockfileVersion": 1, "requires": true, "dependencies": { - "@runejs/logger": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@runejs/logger/-/logger-1.0.0.tgz", - "integrity": "sha512-PrxPuHGykErvlIA3YPckDCBstn3Le0xLi5PcCKDtjgj5t9jRqCv6NjPkjpeY0hjNChaRPXCceNQ2aloZzO2UPg==", - "requires": { - "colors": "^1.4.0", - "moment": "^2.24.0", - "typescript": "^3.7.2" - } - }, "@types/node": { - "version": "12.12.30", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.30.tgz", - "integrity": "sha512-sz9MF/zk6qVr3pAnM0BSQvYIBK44tS75QC5N+VbWSE4DjCV/pJ+UzCW/F+vVnl7TkOPcuwQureKNtSSwjBTaMg==", + "version": "14.14.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.2.tgz", + "integrity": "sha512-jeYJU2kl7hL9U5xuI/BhKPZ4vqGM/OmK6whiFAXVhlstzZhVamWhDSmHyGLIp+RVyuF9/d0dqr2P85aFj4BvJg==", "dev": true }, "arg": { @@ -26,6 +16,14 @@ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -43,6 +41,20 @@ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -50,9 +62,9 @@ "dev": true }, "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" }, "source-map": { "version": "0.6.1", @@ -61,32 +73,42 @@ "dev": true }, "source-map-support": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", - "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, "ts-node": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.7.0.tgz", - "integrity": "sha512-s659CsHrsxaRVDEleuOkGvbsA0rWHtszUNEt1r0CgAFN5ZZTQtDzpsluS7W5pOGJIa1xZE8R/zK4dEs+ldFezg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", + "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", "dev": true, "requires": { "arg": "^4.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "source-map-support": "^0.5.6", + "source-map-support": "^0.5.17", "yn": "3.1.1" } }, + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + }, "typescript": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", - "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==" + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.3.tgz", + "integrity": "sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg==" }, "yn": { "version": "3.1.1", diff --git a/package.json b/package.json index 5a84324..ffe9928 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "@runejs/byte-buffer", - "version": "1.0.8", - "description": "A customized implementation of a NodeJS Buffer.", + "name": "@runejs/core", + "version": "1.0.0-beta.0", + "description": "Core functionality for RuneJS applications.", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { @@ -10,20 +10,23 @@ }, "repository": { "type": "git", - "url": "git+ssh://git@github.com/rune-js/byte-buffer.git" + "url": "git+ssh://git@github.com/rune-js/core.git" }, "author": "TheBlackParade", "license": "GPL-3.0", "bugs": { - "url": "https://github.com/rune-js/byte-buffer/issues" + "url": "https://github.com/rune-js/core/issues" }, - "homepage": "https://github.com/rune-js/byte-buffer#readme", + "homepage": "https://github.com/rune-js/core#readme", "dependencies": { - "@runejs/logger": "^1.0.0", - "typescript": "^3.7.2" + "colors": "^1.4.0", + "js-yaml": "^3.14.0", + "moment": "^2.29.1", + "tslib": "^2.0.3", + "typescript": "^4.0.3" }, "devDependencies": { - "@types/node": "^12.12.6", - "ts-node": "^8.5.4" + "@types/node": "^14.14.2", + "ts-node": "^9.0.0" } } diff --git a/src/byte-buffer.ts b/src/buffer/byte-buffer.ts similarity index 100% rename from src/byte-buffer.ts rename to src/buffer/byte-buffer.ts diff --git a/src/index.ts b/src/index.ts index 0fb1031..ba4592a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,4 @@ -export { ByteBuffer } from './byte-buffer'; +export { ByteBuffer } from './buffer/byte-buffer'; +export { logger, setLoggerDateFormat } from './logger/logger'; +export * from './net/socket-server'; +export { parseServerConfig } from './net/server-config'; diff --git a/src/logger/logger.ts b/src/logger/logger.ts new file mode 100644 index 0000000..110cc19 --- /dev/null +++ b/src/logger/logger.ts @@ -0,0 +1,28 @@ +import moment from 'moment'; +import { gray, red, yellow, cyan } from 'colors'; + +let runeJsLoggerDateFormat = 'YYYY-MM-DDTHH:mm:ss'; + +export const setLoggerDateFormat = (format: string) => runeJsLoggerDateFormat = format; + +const log = (consoleType: string, ...args: any[]): void => { + const date = moment().format(runeJsLoggerDateFormat); + args.forEach(msg => { + if(consoleType === 'debug') { + msg = cyan(msg); + } else if(consoleType === 'warn') { + msg = yellow(msg); + } else if(consoleType === 'error') { + msg = red(msg); + } + const str = gray(`[${date}]: `) + msg; + console[consoleType](str); + }); +}; + +export const logger = { + info: (...message: any[]) => log('info', ...message), + debug: (...message: any[]) => log('info', ...message), + warn: (...message: any[]) => log('warn', ...message), + error: (...message: any[]) => log('error', ...message) +}; diff --git a/src/net/server-config.ts b/src/net/server-config.ts new file mode 100644 index 0000000..20928c5 --- /dev/null +++ b/src/net/server-config.ts @@ -0,0 +1,51 @@ +import { logger } from '..'; +import { JSON_SCHEMA, safeLoad } from 'js-yaml'; +import { readFileSync } from 'fs'; + +interface ServerConfigOptions { + useDefault?: boolean; + configDir?: string; + configFileName?: string; +} + +export function parseServerConfig(options?: ServerConfigOptions): T { + if(!options) { + options = { + useDefault: false, + configDir: 'data/config', + configFileName: 'server-config' + }; + } else { + if(!options.configDir) { + options.configDir = 'data/config'; + } + if(!options.configFileName) { + options.configFileName = 'server-config'; + } + } + + try { + const config = safeLoad(readFileSync( + `${options.configDir}/${options.configFileName}${options.useDefault ? '.example' : ''}.yaml`, 'utf8'), + { schema: JSON_SCHEMA }) as T; + + if(!config) { + if(!options.useDefault) { + logger.warn('Server config not provided, using default...'); + return parseServerConfig({ useDefault: true }); + } else { + throw new Error('Syntax Error'); + } + } + + return config; + } catch(error) { + if(!options.useDefault) { + logger.warn('Server config not provided, using default...'); + return parseServerConfig({ useDefault: true }); + } else { + logger.error('Error parsing server config: ' + error); + return null; + } + } +} diff --git a/src/net/socket-server.ts b/src/net/socket-server.ts new file mode 100644 index 0000000..85c3f02 --- /dev/null +++ b/src/net/socket-server.ts @@ -0,0 +1,48 @@ +import { createServer, Socket } from 'net'; +import { ByteBuffer } from '..'; +import { logger } from '..'; + +export abstract class SocketConnectionHandler { + + protected constructor() { + } + + abstract async dataReceived(data: ByteBuffer): Promise; + abstract connectionDestroyed(): void; + +} + +function socketError(socket: Socket, connectionHandler: T, error): void { + connectionHandler.connectionDestroyed(); + logger.error('Socket destroyed due to connection error.'); + logger.error(error?.message || '[no message]'); + socket.destroy(); +} + +export function registerSocket(socket: Socket, connectionHandlerFactory: (socket: Socket) => T): void { + socket.setNoDelay(true); + socket.setKeepAlive(true); + socket.setTimeout(30000); + + const connection: T = connectionHandlerFactory(socket); + + socket.on('data', async data => { + try { + await connection.dataReceived(new ByteBuffer(data)); + } catch(e) { + logger.error(e); + socket.destroy(); + } + }); + + socket.on('close', () => { + // @TODO socket close event + }); + + socket.on('error', error => socketError(socket, connection, error)); +} + +export function openServer(name: string, host: string, port: number, connectionHandlerFactory: (socket: Socket) => T): void { + createServer(socket => registerSocket(socket, connectionHandlerFactory)).listen(port, host); + logger.info(`${ name } listening @ ${ host }:${ port }.`); +} diff --git a/src/test.ts b/src/test.ts index e69de29..0bcf400 100644 --- a/src/test.ts +++ b/src/test.ts @@ -0,0 +1,25 @@ +import { openServer, SocketConnectionHandler, logger, setLoggerDateFormat, ByteBuffer } from './index'; +import { Socket } from 'net'; + +class TestConnectionHandler extends SocketConnectionHandler { + + public constructor(private readonly socket: Socket) { + super(); + } + + async dataReceived(data: ByteBuffer): Promise { + logger.info(`Data received:`, data); + } + + connectionDestroyed(): void { + logger.info(`Connection destroyed.`); + } + +} + +function launchTestServer() { + setLoggerDateFormat('HH:mm:ss'); + openServer('Test Server', '0.0.0.0', 43586, socket => new TestConnectionHandler(socket)); +} + +launchTestServer();