See commit description
* Basic command implementation: - /debug: Sets VerboseLevel - /account: Creates or deletes an account - /exit: Exits the process - /maintenance: Toggle maintenance * Database System * Basic HTTP handling
This commit is contained in:
parent
2317e5cbb5
commit
09b49c52bf
20
config.json
Normal file
20
config.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"VERBOSE_LEVEL": 2,
|
||||||
|
"MONGO_URI": "mongodb://localhost:27017/crepesr",
|
||||||
|
"HTTP": {
|
||||||
|
"HTTP_HOST": "0.0.0.0",
|
||||||
|
"HTTP_PORT": 443
|
||||||
|
},
|
||||||
|
"DISPATCH": [
|
||||||
|
{
|
||||||
|
"DISPATCH_NAME": "CrepeSR",
|
||||||
|
"DISPATCH_URL": "http://localhost/query_gateway"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"GAMESERVER": {
|
||||||
|
"SERVER_IP": "127.0.0.1",
|
||||||
|
"SERVER_PORT": 22102,
|
||||||
|
"MAINTENANCE": true,
|
||||||
|
"MAINTENANCE_MSG": "Server is in maintenance mode."
|
||||||
|
}
|
||||||
|
}
|
1649
package-lock.json
generated
1649
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -4,5 +4,12 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "ts-node-dev src/index.ts --respawn --transpile-only"
|
"start": "ts-node-dev src/index.ts --respawn --transpile-only"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/express": "^4.17.13",
|
||||||
|
"colorts": "^0.1.63",
|
||||||
|
"express": "^4.18.1",
|
||||||
|
"mongodb": "^4.8.0",
|
||||||
|
"protobufjs": "^7.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
51
src/commands/Interface.ts
Normal file
51
src/commands/Interface.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { createInterface } from 'readline';
|
||||||
|
import _alias from './alias.json';
|
||||||
|
import Logger from '../util/Logger';
|
||||||
|
|
||||||
|
const c = new Logger("Command", "blue");
|
||||||
|
const alias: { [key: string]: string } = _alias;
|
||||||
|
|
||||||
|
export class Command {
|
||||||
|
public readonly name: string;
|
||||||
|
public readonly args: string[];
|
||||||
|
|
||||||
|
public constructor(public readonly full: string) {
|
||||||
|
const split = full.split(" ");
|
||||||
|
this.name = split[0];
|
||||||
|
this.args = split.slice(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Interface {
|
||||||
|
public static readonly rl = createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout
|
||||||
|
});
|
||||||
|
|
||||||
|
private constructor() { }
|
||||||
|
|
||||||
|
public static readonly start = () => {
|
||||||
|
Interface.rl.question("", (_command) => {
|
||||||
|
if (!_command) {
|
||||||
|
Interface.start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cmd = new Command(_command);
|
||||||
|
import(`./${alias[cmd.name] || cmd.name}`).then(async module => {
|
||||||
|
await module.default(cmd);
|
||||||
|
}).catch(err => {
|
||||||
|
if (err.code == "MODULE_NOT_FOUND") {
|
||||||
|
c.log(`Command ${cmd.name} not found.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
c.error(err);
|
||||||
|
});
|
||||||
|
Interface.start();
|
||||||
|
});
|
||||||
|
|
||||||
|
Interface.rl.on('close', () => {
|
||||||
|
console.log('Have a great day!');
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
37
src/commands/account.ts
Normal file
37
src/commands/account.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import Account from "../db/Account";
|
||||||
|
import Logger from "../util/Logger";
|
||||||
|
import { Command } from "./Interface";
|
||||||
|
const c = new Logger("/account", "blue");
|
||||||
|
|
||||||
|
export default async function handle(command: Command) {
|
||||||
|
switch (command.args[0]) {
|
||||||
|
case "create":
|
||||||
|
if (!command.args[1]) {
|
||||||
|
c.log(`Usage: account create <name> [uid]`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const acc = await Account.createAccount(command.args[1], command.args[2]);
|
||||||
|
c.log(`Account ${acc.name} with UID ${acc.uid} created.`);
|
||||||
|
} catch (e) {
|
||||||
|
c.error(e as Error);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "delete":
|
||||||
|
if (!command.args[1]) {
|
||||||
|
c.log(`Usage: account delete <uid>`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const acc = await Account.getAccountByUID(command.args[1]);
|
||||||
|
if (!acc) {
|
||||||
|
c.error(`Account with UID ${command.args[1]} does not exist.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Account.deleteAccount(command.args[1]);
|
||||||
|
c.log(`Account ${acc.name} with UID ${acc.uid} deleted successfully.`);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
c.log(`Usage: account create <name> [uid]`);
|
||||||
|
c.log(`Usage: account delete <uid>`);
|
||||||
|
}
|
||||||
|
}
|
3
src/commands/alias.json
Normal file
3
src/commands/alias.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"close": "exit"
|
||||||
|
}
|
19
src/commands/debug.ts
Normal file
19
src/commands/debug.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import Config from "../util/Config";
|
||||||
|
import Logger, { VerboseLevel } from "../util/Logger";
|
||||||
|
import { Command } from "./Interface";
|
||||||
|
const c = new Logger("/debug", "blue");
|
||||||
|
|
||||||
|
export default async function handle(command: Command) {
|
||||||
|
if (!command.args[0]) c.log(`VerboseLevel: ${Config.VERBOSE_LEVEL}`);
|
||||||
|
else {
|
||||||
|
let level = parseInt(command.args[0]);
|
||||||
|
if (!level) level = 0;
|
||||||
|
if (level > 2 || level < 0) {
|
||||||
|
c.log("Invalid verbose level. Must be between 0 and 2.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.VERBOSE_LEVEL = level as unknown as VerboseLevel;
|
||||||
|
c.log(`VerboseLevel set to ${Config.VERBOSE_LEVEL} (${VerboseLevel[level]})`);
|
||||||
|
}
|
||||||
|
}
|
8
src/commands/exit.ts
Normal file
8
src/commands/exit.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import Logger from "../util/Logger";
|
||||||
|
import { Command } from "./Interface";
|
||||||
|
const c = new Logger("/exit", "blue");
|
||||||
|
|
||||||
|
export default async function handle(command: Command) {
|
||||||
|
c.log("Good riddance!");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
23
src/commands/maintenance.ts
Normal file
23
src/commands/maintenance.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import Config from "../util/Config";
|
||||||
|
import Logger, { VerboseLevel } from "../util/Logger";
|
||||||
|
import { Command } from "./Interface";
|
||||||
|
const c = new Logger("/maintenance", "blue");
|
||||||
|
|
||||||
|
export default async function handle(command: Command) {
|
||||||
|
switch (command.args[0]) {
|
||||||
|
case "on":
|
||||||
|
Config.GAMESERVER.MAINTENANCE = true;
|
||||||
|
if (command.args[1]) Config.GAMESERVER.MAINTENANCE_MSG = command.args.slice(1).join(" ");
|
||||||
|
c.log("Maintenance mode enabled.");
|
||||||
|
break;
|
||||||
|
case "off":
|
||||||
|
Config.GAMESERVER.MAINTENANCE = false;
|
||||||
|
c.log("Maintenance mode disabled.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
c.log(`Maintenance mode is ${Config.GAMESERVER.MAINTENANCE ? "enabled" : "disabled"}`);
|
||||||
|
c.log(`Maintenance message: ${Config.GAMESERVER.MAINTENANCE_MSG}`);
|
||||||
|
c.log("Usage: /maintenance [on|off] [message]");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
68
src/db/Account.ts
Normal file
68
src/db/Account.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import Logger from "../util/Logger";
|
||||||
|
import Database from "./Database";
|
||||||
|
const c = new Logger("Account");
|
||||||
|
|
||||||
|
interface AccountI {
|
||||||
|
uid: string | number;
|
||||||
|
name: string;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Account {
|
||||||
|
private constructor(public readonly uid: string | number, public readonly name: string, public readonly token: string) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async getAccountByUID(uid: string | number): Promise<Account | undefined> {
|
||||||
|
const db = Database.getInstance();
|
||||||
|
const account = await db.get("accounts", { _id: Number(uid) });
|
||||||
|
if (!account) return;
|
||||||
|
return new Account(Number(account._id.toString()), account.name, account.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async getAccountByUsername(name: string): Promise<Account | undefined> {
|
||||||
|
const db = Database.getInstance();
|
||||||
|
const account = await db.get("accounts", { name });
|
||||||
|
if (!account) return;
|
||||||
|
return new Account(Number(account._id.toString()), account.name, account.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async createAccount(name: string, uid?: string | number): Promise<Account> {
|
||||||
|
const db = Database.getInstance();
|
||||||
|
let selfAssignedUID = true;
|
||||||
|
if (!uid) {
|
||||||
|
uid = Math.round(Math.random() * 50000);
|
||||||
|
selfAssignedUID = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const account = await db.get("accounts", { uid });
|
||||||
|
if (account) {
|
||||||
|
if (!selfAssignedUID) {
|
||||||
|
return await Account.createAccount(name, uid);
|
||||||
|
} else {
|
||||||
|
throw new Error(`Account with uid ${uid} already exists.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = generateToken();
|
||||||
|
await db.set("accounts", { _id: Number(uid), name, token });
|
||||||
|
return new Account(Number(uid), name, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async deleteAccount(uid: string | number): Promise<void> {
|
||||||
|
const db = Database.getInstance();
|
||||||
|
const account = await Account.getAccountByUID(uid);
|
||||||
|
if (!account) {
|
||||||
|
throw new Error(`Account with uid ${uid} does not exist.`);
|
||||||
|
}
|
||||||
|
await db.delete("accounts", { _id: Number(uid) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateToken(): string {
|
||||||
|
let token = "";
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
token += Math.random().toString(36).substring(2, 15)
|
||||||
|
}
|
||||||
|
return token;
|
||||||
|
}
|
68
src/db/Database.ts
Normal file
68
src/db/Database.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import { MongoClient } from "mongodb";
|
||||||
|
import Config from "../util/Config";
|
||||||
|
import Logger from "../util/Logger";
|
||||||
|
const c = new Logger("Database");
|
||||||
|
|
||||||
|
export default class Database {
|
||||||
|
public static instance: Database;
|
||||||
|
public static client: MongoClient;
|
||||||
|
private constructor() {
|
||||||
|
Database.client = new MongoClient(Config.MONGO_URI);
|
||||||
|
try {
|
||||||
|
Database.client.connect();
|
||||||
|
} catch (e) {
|
||||||
|
c.error(e as Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance(): Database {
|
||||||
|
if (!Database.instance) {
|
||||||
|
Database.instance = new Database();
|
||||||
|
}
|
||||||
|
return Database.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get(collection: string, query?: {}) {
|
||||||
|
try {
|
||||||
|
const db = await Database.client.db();
|
||||||
|
const _collection = db.collection(collection);
|
||||||
|
if (!(await db.listCollections({ name: collection }).toArray()).length) {
|
||||||
|
c.warn(`Collection ${collection} does not exist. Creating...`);
|
||||||
|
await _collection.createIndexes([{ key: { id: 1 }, unique: true }]);
|
||||||
|
}
|
||||||
|
const result = query ? await _collection.findOne(query) : await _collection.findOne();
|
||||||
|
return result;
|
||||||
|
} catch (e) {
|
||||||
|
c.error(e as Error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async set(collection: string, payload: any) {
|
||||||
|
try {
|
||||||
|
const db = await Database.client.db();
|
||||||
|
const _collection = db.collection(collection);
|
||||||
|
if (!(await db.listCollections({ name: collection }).toArray()).length) {
|
||||||
|
c.warn(`Collection ${collection} does not exist. Creating...`);
|
||||||
|
await _collection.createIndexes([{ key: { id: 1 }, unique: true }]);
|
||||||
|
}
|
||||||
|
return await _collection.insertOne(payload);
|
||||||
|
} catch (e) {
|
||||||
|
c.error(e as Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async delete(collection: string, query: {}) {
|
||||||
|
try {
|
||||||
|
const db = await Database.client.db();
|
||||||
|
const _collection = db.collection(collection);
|
||||||
|
if (!(await db.listCollections({ name: collection }).toArray()).length) {
|
||||||
|
c.warn(`Collection ${collection} does not exist. Creating...`);
|
||||||
|
await _collection.createIndexes([{ key: { id: 1 }, unique: true }]);
|
||||||
|
}
|
||||||
|
return await _collection.deleteOne(query);
|
||||||
|
} catch (e) {
|
||||||
|
c.error(e as Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
src/http/HttpServer.ts
Normal file
42
src/http/HttpServer.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import https from 'https';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
import Config from '../util/Config';
|
||||||
|
import Logger, { VerboseLevel } from '../util/Logger';
|
||||||
|
const c = new Logger("HTTP");
|
||||||
|
|
||||||
|
function r(...args: string[]) {
|
||||||
|
return fs.readFileSync(resolve(__dirname, ...args)).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
const HTTPS_CONFIG = {
|
||||||
|
key: r('./cert/cert.key'),
|
||||||
|
cert: r('./cert/cert.crt'),
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class HttpServer {
|
||||||
|
private readonly server;
|
||||||
|
|
||||||
|
public constructor() {
|
||||||
|
this.server = express();
|
||||||
|
this.server.use(express.json());
|
||||||
|
this.server.route('/*').all((req, res) => {
|
||||||
|
if (Logger.VERBOSE_LEVEL > VerboseLevel.WARNS) c.log(`${req.method} ${req.url}`);
|
||||||
|
import(`./routes${req.url.split('?')[0]}`).then(async r => {
|
||||||
|
await r.default(req, res);
|
||||||
|
}).catch(err => {
|
||||||
|
res.send({
|
||||||
|
code: 0
|
||||||
|
});
|
||||||
|
if (err.code === 'MODULE_NOT_FOUND') return;
|
||||||
|
c.error(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
https.createServer(HTTPS_CONFIG, this.server).listen(Config.HTTP.HTTP_PORT, Config.HTTP.HTTP_PORT);
|
||||||
|
this.server.listen(80, Config.HTTP.HTTP_HOST, () => {
|
||||||
|
c.log(`Listening on ${Config.HTTP.HTTP_HOST}:${Config.HTTP.HTTP_PORT}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
23
src/http/cert/cert.crt
Normal file
23
src/http/cert/cert.crt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIID2TCCAsGgAwIBAgIUO4lg/Dj+kZ9fv+AFxQBrMNUJc9cwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwVjESMBAGA1UEAwwJbG9jYWxob3N0MQswCQYDVQQGEwJDWTEOMAwGA1UECAwF
|
||||||
|
Q3JlcGUxDjAMBgNVBAcMBUNyZXBlMRMwEQYDVQQKDApDcmVwZSBJbmMuMB4XDTIx
|
||||||
|
MTIxMjE2NDY0NloXDTMxMTIxMDE2NDY0NlowVjESMBAGA1UEAwwJbG9jYWxob3N0
|
||||||
|
MQswCQYDVQQGEwJDWTEOMAwGA1UECAwFQ3JlcGUxDjAMBgNVBAcMBUNyZXBlMRMw
|
||||||
|
EQYDVQQKDApDcmVwZSBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
|
||||||
|
AQEAnPFIkkIHKJdmWdUdmwja9qENmnmVL7iSFrgMhBRuZadsD1gYb78liWHH/CT4
|
||||||
|
5zmVJ44LiON3DjmCP/gAbFe3epPifB5i6CIh+tolqG8fg9WyyWrP71Z+raaGtlV4
|
||||||
|
NIyybRJI/9Gjysf4aehpCtEKJf4BAy82lrfBhNhmHf16W65c0NCGMJoB9Wr+wZCd
|
||||||
|
R6PzcKgWNa33YVfXTD8PiTOU9cLRvRFgwO870f/8jekxVdHggfTdQmVj9rcNet6X
|
||||||
|
MrWvzUI4LnI2JPyyEpMtlAQnDQ2+aGG5A3GdPPkWeaST+vF6CDCTFkg8Dxw0jQ30
|
||||||
|
jc0uQv/zz0mFuqvvivgpGSXeuwIDAQABo4GeMIGbMB0GA1UdDgQWBBS8E5THWThf
|
||||||
|
TVAwTnGez4druLTacDAfBgNVHSMEGDAWgBS8E5THWThfTVAwTnGez4druLTacDAO
|
||||||
|
BgNVHQ8BAf8EBAMCBaAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
|
||||||
|
MCcGA1UdEQQgMB6CDCoubWlob3lvLmNvbYIOKi55dWFuc2hlbi5jb20wDQYJKoZI
|
||||||
|
hvcNAQELBQADggEBAIVqx99S1DYtyLqsi15KwTUawShW9iJVsvpk59vK6qbbzuGZ
|
||||||
|
L72DrRJVTMxodv4WLaiM+te1TsW0WmdrhUYUBfIi+JpB67QB6aWKkOCP8fYq+mWn
|
||||||
|
Q3vuAEC6KpWH30j+0S58LVV+2iaGVetXYmYDXKoNslyVuJAM4iZSutTZhctO2Fxm
|
||||||
|
Vicp0fiPq/HJzxsmKHxyFJsgsdV0Dl9ElnlhpH77qxi/nXuUz9YlWZwwQI8KSsKm
|
||||||
|
sOzTUpSHHHpDocT24Yx73bR3Hd8CJam2bCEOOIIJG7sPx2lhTEJ+sKHDh4jHmRUI
|
||||||
|
3rVk5R+x1CcIrAgin+8nH28PhZFdOKs+CYMYGk0=
|
||||||
|
-----END CERTIFICATE-----
|
28
src/http/cert/cert.key
Normal file
28
src/http/cert/cert.key
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCc8UiSQgcol2ZZ
|
||||||
|
1R2bCNr2oQ2aeZUvuJIWuAyEFG5lp2wPWBhvvyWJYcf8JPjnOZUnjguI43cOOYI/
|
||||||
|
+ABsV7d6k+J8HmLoIiH62iWobx+D1bLJas/vVn6tpoa2VXg0jLJtEkj/0aPKx/hp
|
||||||
|
6GkK0Qol/gEDLzaWt8GE2GYd/XpbrlzQ0IYwmgH1av7BkJ1Ho/NwqBY1rfdhV9dM
|
||||||
|
Pw+JM5T1wtG9EWDA7zvR//yN6TFV0eCB9N1CZWP2tw163pcyta/NQjgucjYk/LIS
|
||||||
|
ky2UBCcNDb5oYbkDcZ08+RZ5pJP68XoIMJMWSDwPHDSNDfSNzS5C//PPSYW6q++K
|
||||||
|
+CkZJd67AgMBAAECggEBAJv3KQC4f3a2Zu+1XBObTEc2rFcsprbi/MN5Km8EAuYg
|
||||||
|
6MGi8b3zvrD1rJGGiJj5X6IMhqgGLWXEfw1lP75ruZomZzij1fUNHqm1qyDlNfOF
|
||||||
|
JoUGEhiu43tc95kx/SB0Bklgl40rYFQAQH23itRGA4jYEVeBzwUfHkEP8QOyyKtc
|
||||||
|
YKJHa1jCEvE4XHxLqxFC+z7aNmpFonrW8OerVwrDPIkFbXYrC1alzxqMcNBJVeKE
|
||||||
|
LFFc6EK9ppoPSsm600yac5gOX2ima9JkaYkGKhK25D4NXCd511Ea/TJNctA8IkYA
|
||||||
|
QB7mCzLHdapRlhSplDwwwgNRzlrkImbqyS2+768ejYkCgYEAzyatfH62cDSDP5e1
|
||||||
|
oukWI46AqybfIhd9kHzIbIyPjuSb3RvvuxIfNBFjUxRyh+ggCjnRA14HcZzDcGRd
|
||||||
|
6VpApq80LQk6mhklKicJNRrcuEvdmj+kRJ+XtSbNZhJVUkNf7nmHCOoJkEwRsblL
|
||||||
|
kIZCVmfkWAKFjHnCEqH5RHvTbacCgYEAwfObyw0eMD+X23IpyEsCsTKIwIk4Zl8J
|
||||||
|
iTNnR9yp6B9JdwLSdEWQjhXSltkfmNZ3WXYoyh6kr3jp8d5EqWX1P8JrZBaZikTD
|
||||||
|
y526kKIvs/I/iW3obOoE6CX6LJEGob8bAPkvu2u37Rghign57W02fYtzJUuqPAoK
|
||||||
|
b5mtrQ/ycM0CgYBsR8pthgq1Mi3dAt82DeK9qVKGpGYEewTujttxKjQsPEFg3aZ9
|
||||||
|
Qaa/38rsdYa8ldCRp9EikncPoyLh0ATq4nti5bg/RlC0lipAE3GTqbvwNe/bHiMu
|
||||||
|
n8F8NpEtJq4ktwUhMbMtLLDdFXY2USY3oIZyhhHtEzxdxpN0i+gxLQzChwKBgQCG
|
||||||
|
FFztYGIwRKY8hI2x83km+qJjR/l/e8/h03Fg0oF7ALYO2hqXWsf2EcwFkJAxXoIf
|
||||||
|
jHniUJDU5agFFv0shlmm/Ea1aJI4bhVVG/MvrY+AvMWDwkFdmeJOgoKScKe/BZgr
|
||||||
|
chi3Xl5GP9pfzUnEAy4aWF7/t3E2FFLml7zi2RVnOQKBgQCYmzwikvHpR+HRiZL9
|
||||||
|
m0TB6mayGbwQO3xU/naZ1UyCydsRORQnbKaTWSMZgrr7nTAqDhegfUyJXX+uxhGQ
|
||||||
|
cGu9uLENZWrysXROpMZBhgyNUbDPdO0okIMoJ3kUSocC7L7lpWyZGOxgMwi0a4qK
|
||||||
|
nV1QDKXsA3oBZn9MJpkuQ81jCw==
|
||||||
|
-----END PRIVATE KEY-----
|
9
src/http/routes/Handler.ts
Normal file
9
src/http/routes/Handler.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
// Test handler
|
||||||
|
res.send({
|
||||||
|
retcode: -1,
|
||||||
|
message: "Invalid endpoint"
|
||||||
|
});
|
||||||
|
}
|
21
src/http/routes/account/risky/api/check.ts
Normal file
21
src/http/routes/account/risky/api/check.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
|
// Example request:
|
||||||
|
// {
|
||||||
|
// "action_type": "login",
|
||||||
|
// "api_name": "/shield/api/login",
|
||||||
|
// "username": "test"
|
||||||
|
// }
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
// Test handler
|
||||||
|
res.send({
|
||||||
|
retcode: 0,
|
||||||
|
message: "OK",
|
||||||
|
data: {
|
||||||
|
id: "",
|
||||||
|
action: "ACTION_NONE",
|
||||||
|
geetest: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
9
src/http/routes/combo/box/api/config/sdk/combo.ts
Normal file
9
src/http/routes/combo/box/api/config/sdk/combo.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
res.send({
|
||||||
|
data: null,
|
||||||
|
message: "RetCode_NoConfig",
|
||||||
|
retcode: 7
|
||||||
|
});
|
||||||
|
}
|
10
src/http/routes/data_abtest_api/config/experiment/list.ts
Normal file
10
src/http/routes/data_abtest_api/config/experiment/list.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
res.send({
|
||||||
|
retcode: 0,
|
||||||
|
success: true,
|
||||||
|
message: "",
|
||||||
|
data: []
|
||||||
|
});
|
||||||
|
}
|
14
src/http/routes/hkrpg/dataUpload.ts
Normal file
14
src/http/routes/hkrpg/dataUpload.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import Logger, { VerboseLevel } from "../../../util/Logger";
|
||||||
|
const c = new Logger("dataUpload", "green");
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const content = req.body[0].uploadContent;
|
||||||
|
if (content.LogStr) {
|
||||||
|
c.warn(content.LogStr);
|
||||||
|
if (Logger.VERBOSE_LEVEL == VerboseLevel.ALL) c.trail(content.StackTrace);
|
||||||
|
}
|
||||||
|
} catch { }
|
||||||
|
res.send({ code: 0 });
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
// Test handler
|
||||||
|
res.send({
|
||||||
|
retcode: 0,
|
||||||
|
message: "OK",
|
||||||
|
data: {
|
||||||
|
modified: true,
|
||||||
|
protocol: {
|
||||||
|
id: 0,
|
||||||
|
app_id: 11,
|
||||||
|
language: "en",
|
||||||
|
user_proto: "",
|
||||||
|
priv_proto: "",
|
||||||
|
major: 1,
|
||||||
|
minimum: 2,
|
||||||
|
create_time: "0",
|
||||||
|
teenager_proto: "",
|
||||||
|
third_proto: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
17
src/http/routes/hkrpg_global/combo/granter/api/getConfig.ts
Normal file
17
src/http/routes/hkrpg_global/combo/granter/api/getConfig.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
res.send({
|
||||||
|
retcode: 0,
|
||||||
|
message: "OK",
|
||||||
|
data: {
|
||||||
|
protocol: true,
|
||||||
|
qr_enabled: true,
|
||||||
|
log_level: "INFO",
|
||||||
|
announce_url: "https://sdk.hoyoverse.com/hkrpg/announcement/index.html?sdk_presentation_style=fullscreen\u0026sdk_screen_transparent=true\u0026auth_appid=announcement\u0026authkey_ver=1\u0026sign_type=2#/",
|
||||||
|
push_alias_type: 0,
|
||||||
|
disable_ysdk_guard: true,
|
||||||
|
enable_announce_pic_popup: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
17
src/http/routes/hkrpg_global/combo/granter/login/v2/login.ts
Normal file
17
src/http/routes/hkrpg_global/combo/granter/login/v2/login.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
res.send({
|
||||||
|
retcode: 0,
|
||||||
|
message: "OK",
|
||||||
|
data: {
|
||||||
|
combo_id: "0",
|
||||||
|
open_id: "",
|
||||||
|
combo_token: "",
|
||||||
|
data: '{"guest":false}',
|
||||||
|
heartbeat: false,
|
||||||
|
account_type: 1,
|
||||||
|
fatigue_remind: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
res.send({
|
||||||
|
retcode: 0,
|
||||||
|
message: "OK",
|
||||||
|
data: {
|
||||||
|
marketing_agreements: []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
29
src/http/routes/hkrpg_global/mdk/shield/api/loadConfig.ts
Normal file
29
src/http/routes/hkrpg_global/mdk/shield/api/loadConfig.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
res.send({
|
||||||
|
retcode: 0,
|
||||||
|
message: "OK",
|
||||||
|
data: {
|
||||||
|
id: 24,
|
||||||
|
game_key: "hkrpg_global",
|
||||||
|
client: "PC",
|
||||||
|
identity: "I_IDENTITY",
|
||||||
|
guest: false,
|
||||||
|
ignore_versions: "",
|
||||||
|
scene: "S_NORMAL",
|
||||||
|
name: "崩坏RPG",
|
||||||
|
disable_regist: true,
|
||||||
|
enable_email_captcha: false,
|
||||||
|
thirdparty: [],
|
||||||
|
disable_mmt: false,
|
||||||
|
server_guest: true,
|
||||||
|
thirdparty_ignore: {
|
||||||
|
fb: "",
|
||||||
|
tw: ""
|
||||||
|
},
|
||||||
|
enable_ps_bind_account: false,
|
||||||
|
thirdparty_login_configs: {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
32
src/http/routes/hkrpg_global/mdk/shield/api/login.ts
Normal file
32
src/http/routes/hkrpg_global/mdk/shield/api/login.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import Account from "../../../../../../db/Account";
|
||||||
|
import Logger from "../../../../../../util/Logger";
|
||||||
|
|
||||||
|
// Example request:
|
||||||
|
// {
|
||||||
|
// account: "test",
|
||||||
|
// (RSA)password: "BKWPZjqKfKr6ZKuO40ONwV5JxOi4dg71aeBcxPVK/U+8FM8d5kc5EjLdEXyn6McBvUOL67CmT89eo9jrdwp9xpFexA/C1d9BCxen0NQ+zCrQUkSc6AFD9PYkAmdTNnila5L15SrveQQRtbsDwZeZ9owVH7kyoXuDGUOOA6dc4qE=",
|
||||||
|
// is_crypto: true
|
||||||
|
// }
|
||||||
|
|
||||||
|
export default async function handle(req: Request, res: Response) {
|
||||||
|
const c = new Logger(req.ip);
|
||||||
|
const acc = await Account.getAccountByUsername(req.body.account);
|
||||||
|
const dataObj: any = {
|
||||||
|
retcode: 0,
|
||||||
|
message: "OK",
|
||||||
|
data: {
|
||||||
|
account: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!acc) {
|
||||||
|
dataObj.retcode = -202;
|
||||||
|
dataObj.message = "Account not found";
|
||||||
|
c.warn(`[DISPATCH] Player ${req.body.account} not found`);
|
||||||
|
res.send(dataObj);
|
||||||
|
} else {
|
||||||
|
dataObj.data.account = acc;
|
||||||
|
c.log(`[DISPATCH] Player ${req.body.account} logged in`);
|
||||||
|
res.send(dataObj);
|
||||||
|
}
|
||||||
|
}
|
35
src/http/routes/hkrpg_global/mdk/shield/api/verify.ts
Normal file
35
src/http/routes/hkrpg_global/mdk/shield/api/verify.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import Account from "../../../../../../db/Account";
|
||||||
|
import Logger from "../../../../../../util/Logger";
|
||||||
|
|
||||||
|
// Example request:
|
||||||
|
// {"uid":"63884253","token":"ZQmgMdXA1StL9A3aPBUedr8yoiuoLrmV"}
|
||||||
|
|
||||||
|
export default async function handle(req: Request, res: Response) {
|
||||||
|
const c = new Logger(req.ip);
|
||||||
|
const acc = await Account.getAccountByUID(req.body.uid);
|
||||||
|
const dataObj: any = {
|
||||||
|
retcode: 0,
|
||||||
|
message: "OK",
|
||||||
|
data: {
|
||||||
|
account: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!acc) {
|
||||||
|
dataObj.retcode = -202;
|
||||||
|
dataObj.message = "Account not found";
|
||||||
|
res.send(dataObj);
|
||||||
|
c.warn(`[DISPATCH] Player ${req.body.uid} not found`);
|
||||||
|
} else {
|
||||||
|
if (acc.token === req.body.token) {
|
||||||
|
dataObj.data.account = acc;
|
||||||
|
c.log(`[DISPATCH] Player ${req.body.uid} logged in`);
|
||||||
|
res.send(dataObj);
|
||||||
|
} else {
|
||||||
|
dataObj.retcode = -202;
|
||||||
|
dataObj.message = "Invalid token";
|
||||||
|
res.send(dataObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
src/http/routes/query_dispatch.ts
Normal file
27
src/http/routes/query_dispatch.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import Config from "../../util/Config";
|
||||||
|
|
||||||
|
interface Region {
|
||||||
|
dispatch_url: string;
|
||||||
|
env_type: string;
|
||||||
|
name: string;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
const dataObj = {
|
||||||
|
region_list: [] as Region[],
|
||||||
|
retcode: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.DISPATCH.forEach(item => {
|
||||||
|
dataObj.region_list.push({
|
||||||
|
dispatch_url: item.DISPATCH_URL,
|
||||||
|
env_type: "2",
|
||||||
|
name: item.DISPATCH_NAME,
|
||||||
|
title: "CrepeSR"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
res.send(dataObj);
|
||||||
|
}
|
36
src/http/routes/query_gateway.ts
Normal file
36
src/http/routes/query_gateway.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import protobuf from 'protobufjs';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
import Config from "../../util/Config";
|
||||||
|
|
||||||
|
const proto = protobuf.loadSync(resolve(__dirname, '../../proto/QueryCurrRegionHttpRsp.proto')).lookup('QueryCurrRegionHttpRsp') as any;
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
const dataObj = {
|
||||||
|
retcode: 0,
|
||||||
|
msg: "OK",
|
||||||
|
regionName: "CrepeSR",
|
||||||
|
gateserverIp: Config.GAMESERVER.SERVER_IP,
|
||||||
|
gateserverPort: Config.GAMESERVER.SERVER_PORT,
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
if (Config.GAMESERVER.MAINTENANCE) {
|
||||||
|
dataObj.retcode = 2;
|
||||||
|
dataObj.msg = Config.GAMESERVER.MAINTENANCE_MSG;
|
||||||
|
dataObj.stopBeginTime = Date.now();
|
||||||
|
dataObj.stopEndTime = Date.now() * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rsp;
|
||||||
|
try {
|
||||||
|
rsp = proto!.encode(dataObj).finish();
|
||||||
|
} catch {
|
||||||
|
rsp = proto!.encode({
|
||||||
|
retcode: 2,
|
||||||
|
msg: "Internal server error",
|
||||||
|
stopBeginTime: Date.now(),
|
||||||
|
stopEndTime: Date.now() * 2,
|
||||||
|
}).finish();
|
||||||
|
}
|
||||||
|
res.send(Buffer.from(rsp).toString('base64'));
|
||||||
|
}
|
7
src/http/routes/sdk/dataUpload.ts
Normal file
7
src/http/routes/sdk/dataUpload.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { Request, Response } from "express";
|
||||||
|
import Logger from "../../../util/Logger";
|
||||||
|
const c = new Logger("dataUpload", "green");
|
||||||
|
|
||||||
|
export default function handle(req: Request, res: Response) {
|
||||||
|
res.send({ code: 0 });
|
||||||
|
}
|
@ -3,4 +3,11 @@
|
|||||||
* @author Crepe-Inc
|
* @author Crepe-Inc
|
||||||
* @license AGPL-3.0
|
* @license AGPL-3.0
|
||||||
*/
|
*/
|
||||||
|
import Interface from "./commands/Interface";
|
||||||
|
import HttpServer from "./http/HttpServer";
|
||||||
|
import Logger from "./util/Logger";
|
||||||
|
const c = new Logger("CrepeSR");
|
||||||
|
|
||||||
|
c.log(`Starting CrepeSR...`);
|
||||||
|
Interface.start();
|
||||||
|
const http = new HttpServer();
|
38
src/proto/QueryCurrRegionHttpRsp.proto
Normal file
38
src/proto/QueryCurrRegionHttpRsp.proto
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (C) 2022 CrepeSR
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
message QueryCurrRegionHttpRsp {
|
||||||
|
uint32 retcode = 1; // Always present
|
||||||
|
string msg = 2; // Always present
|
||||||
|
string region_name = 3; // Always present
|
||||||
|
string gateserver_ip = 4;
|
||||||
|
uint32 gateserver_port = 5;
|
||||||
|
int64 stop_begin_time = 6;
|
||||||
|
int64 stop_end_time = 7;
|
||||||
|
bool unknown_boolean_one = 8;
|
||||||
|
bool unknown_boolean_two = 9;
|
||||||
|
string resource_url = 10;
|
||||||
|
string data_url = 11;
|
||||||
|
string lua_url = 12;
|
||||||
|
uint32 unknown_int_one = 15;
|
||||||
|
string client_secret_key = 17;
|
||||||
|
string region_config = 18;
|
||||||
|
string feedback_url = 20;
|
||||||
|
string beta_text = 24; // "当前版本为测试版本,不代表游戏最终品质"
|
||||||
|
bool unknown_boolean_three = 25;
|
||||||
|
bool unknown_boolean_four = 26;
|
||||||
|
}
|
85
src/util/Config.ts
Normal file
85
src/util/Config.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
import { VerboseLevel } from './Logger';
|
||||||
|
|
||||||
|
const DEFAULT_CONFIG = {
|
||||||
|
// General
|
||||||
|
VERBOSE_LEVEL: 1,
|
||||||
|
|
||||||
|
// MongoDB
|
||||||
|
MONGO_URI: "mongodb://localhost:27017/crepesr",
|
||||||
|
|
||||||
|
// HTTP
|
||||||
|
HTTP: {
|
||||||
|
HTTP_HOST: "0.0.0.0",
|
||||||
|
HTTP_PORT: 443
|
||||||
|
},
|
||||||
|
|
||||||
|
// Dispatch
|
||||||
|
DISPATCH: [{
|
||||||
|
DISPATCH_NAME: "CrepeSR",
|
||||||
|
DISPATCH_URL: "http://localhost/query_gateway"
|
||||||
|
}],
|
||||||
|
|
||||||
|
// GameServer
|
||||||
|
GAMESERVER: {
|
||||||
|
SERVER_IP: "0.0.0.0",
|
||||||
|
SERVER_PORT: 22102,
|
||||||
|
MAINTENANCE: false,
|
||||||
|
MAINTENANCE_MSG: "Server is in maintenance mode."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type DefaultConfig = typeof DEFAULT_CONFIG;
|
||||||
|
|
||||||
|
function r(...args: string[]) {
|
||||||
|
return fs.readFileSync(resolve(__dirname, ...args)).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function readConfig(): any {
|
||||||
|
let config: DefaultConfig;
|
||||||
|
try {
|
||||||
|
config = JSON.parse(r('../../config.json'));
|
||||||
|
// Check if config object.keys is the same as DEFAULT_CONFIG.keys
|
||||||
|
const missing = Object.keys(DEFAULT_CONFIG).filter(key => !config.hasOwnProperty(key));
|
||||||
|
|
||||||
|
if (missing.length > 0) {
|
||||||
|
missing.forEach(key => {
|
||||||
|
// @ts-ignore
|
||||||
|
config[key] = DEFAULT_CONFIG[key];
|
||||||
|
});
|
||||||
|
updateConfig(config);
|
||||||
|
console.log(`Added missing config keys: ${missing.join(', ')}`);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
console.error("Could not read config file. Creating one for you...");
|
||||||
|
config = DEFAULT_CONFIG;
|
||||||
|
updateConfig(config);
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateConfig(config: any) {
|
||||||
|
fs.writeFileSync('./config.json', JSON.stringify(config, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Config {
|
||||||
|
public static config = readConfig();
|
||||||
|
public static VERBOSE_LEVEL: VerboseLevel = Config.config.VERBOSE_LEVEL;
|
||||||
|
public static MONGO_URI: string = Config.config.MONGO_URI;
|
||||||
|
public static HTTP: {
|
||||||
|
HTTP_HOST: string,
|
||||||
|
HTTP_PORT: number
|
||||||
|
} = Config.config.HTTP;
|
||||||
|
public static DISPATCH: {
|
||||||
|
DISPATCH_NAME: string;
|
||||||
|
DISPATCH_URL: string;
|
||||||
|
}[] = Config.config.DISPATCH;
|
||||||
|
public static GAMESERVER: {
|
||||||
|
SERVER_IP: string;
|
||||||
|
SERVER_PORT: number;
|
||||||
|
MAINTENANCE: boolean;
|
||||||
|
MAINTENANCE_MSG: string;
|
||||||
|
} = Config.config.GAMESERVER;
|
||||||
|
|
||||||
|
private constructor() { }
|
||||||
|
}
|
53
src/util/Logger.ts
Normal file
53
src/util/Logger.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import 'colorts/lib/string';
|
||||||
|
import Config from './Config';
|
||||||
|
|
||||||
|
export enum VerboseLevel {
|
||||||
|
NONE = 0, // No logging except for errors
|
||||||
|
WARNS = 1, // Log warns
|
||||||
|
ALL = 2, // Warns and (useless) debug
|
||||||
|
}
|
||||||
|
|
||||||
|
type Color = 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white' | 'gray' | 'black' | 'italic' | 'bold' | 'underline' | 'strikethrough' | 'inverse' | 'bgRed' | 'bgGreen' | 'bgYellow' | 'bgBlue' | 'bgMagenta' | 'bgCyan' | 'bgWhite' | 'bgBlack' | 'bgGray' | 'bgItalic';
|
||||||
|
|
||||||
|
export default class Logger {
|
||||||
|
public static VERBOSE_LEVEL: VerboseLevel = Config.VERBOSE_LEVEL || 1;
|
||||||
|
|
||||||
|
constructor(public name: string, public color: Color = 'cyan') {
|
||||||
|
this.name = name;
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getDate(): string {
|
||||||
|
return new Date().toLocaleTimeString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private raw(...args: string[]) {
|
||||||
|
// @ts-ignore - Element implicitly has an 'any' type because index expression is not of type 'number'
|
||||||
|
console.log(`[${this.getDate().white.bold}] <${this.name[this.color].bold}>`, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public log(...args: string[]) {
|
||||||
|
this.raw(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public trail(...args: any[]) {
|
||||||
|
console.log(`\t↳ ${args.join(' ').gray}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public error(e: Error | string) {
|
||||||
|
if (typeof e === 'string') e = new Error(e);
|
||||||
|
console.log(`[${this.getDate().white.bold}] ${`ERROR<${this.name}>`.bgRed.bold}`, e.message);
|
||||||
|
if (e.stack) this.trail(e.stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
public warn(...args: string[]) {
|
||||||
|
if (Logger.VERBOSE_LEVEL < VerboseLevel.WARNS) return;
|
||||||
|
console.log(`[${this.getDate().white.bold}] ${`WARN<${this.name}>`.bgYellow.bold}`, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public debug(...args: any) {
|
||||||
|
if (Logger.VERBOSE_LEVEL < VerboseLevel.ALL) return;
|
||||||
|
console.log(`[${this.getDate().white.bold}] ${`DEBUG<${this.name}>`.bgBlue.bold}`, ...args);
|
||||||
|
this.trail(new Error().stack!.split('\n').slice(2).join('\n'));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user