Skip to content

Commit

Permalink
Rework the configuration (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
km127pl authored Aug 15, 2023
2 parents 026bd9e + 983b850 commit 8e62d20
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 26 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,7 @@ dist
*.d.ts
.idea


# default config file
config.json
!src/types/*.d.ts
5 changes: 0 additions & 5 deletions config.json

This file was deleted.

6 changes: 3 additions & 3 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import Config from "./src/Config.js";
import { Config, ConfigLoader } from "./src/Config.js";
import Server from "./src/Server.js";
import LoginSuccessPacket from "./src/packet/server/LoginSuccessPacket.js";
import Connection from "./src/Connection.js";

const config: Config = await Config.fromFile("config.json");

const config: Config = await ConfigLoader.fromFile("config.json");
const server = new Server(config);

server.start();
server.on("listening", (port) => server.logger.info(`Listening on port ${port}`));

Expand Down
76 changes: 63 additions & 13 deletions src/Config.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,82 @@
import { open } from "node:fs/promises";
import { open, access, constants, FileHandle } from "node:fs/promises";
import Logger from "./Logger.js";

export default class Config {
public port: number = 25565;
public logLevel: Logger.Level = Logger.Level.INFO;

export interface Config {
/**
* Port to listen on
*/
port: number;

/**
* The level to display logs at
*/
logLevel: Logger.Level;

/**
* Kick reason for when the server is shutting down
*/
public shutdownKickReason: string = "Server closed";
shutdownKickReason: ChatComponent;
}

export class ConfigLoader {
/**
* Get a Config instance from a json file
* @param file The file to read from
* @returns a promise that resolves to a Config instance
* @throws {Error & {CODE: "EACCESS"}} failed to read config
* @throws {SyntaxError} failed to parse config
*/
public static async fromFile(file: string): Promise<Config> {
let config: Config;
if (!(await ConfigLoader.exists(file))) {
await ConfigLoader.createDefault(file);
const config = ConfigLoader.getDefault();
new Logger("Config", config.logLevel).warn("Config does not exist, creating default '%s'", file);
return config;
}
const fd: FileHandle = await open(file, "r");
const data: string = await fd.readFile("utf-8");
fd.close();

return JSON.parse(data) as Config;
}

/**
* Get a default config instance
* @returns a default config instance
*/
public static getDefault(): Config {
return {
port: 25565,
logLevel: Logger.Level.INFO,
shutdownKickReason: {
text: "Server closed"
}
};

}

/**
* Checks if a config exists
* @param file The file to check
* @returns a promise that resolves to a boolean
*/
public static async exists(file: string): Promise<boolean> {
try {
const fd = await open(file, "r");
const data = await fd.readFile("utf-8");
config = JSON.parse(data) as Config;
fd.close();
await access(file, constants.F_OK);
return true;
} catch {
config = new Config();
new Logger("Config", config.logLevel).error("Failed to read config file, using default config");
return false;
}
return config;
}

/**
* Create the default config file
*/
public static async createDefault(file: string): Promise<void> {
const fd = await open(file, "w");
await fd.writeFile(JSON.stringify(ConfigLoader.getDefault(), null, 4));
fd.close();
}
}

9 changes: 5 additions & 4 deletions src/ConnectionPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default class ConnectionPool {
* @param [reason] The reason for the disconnect
* @returns Whether all connections disconnected successfully
*/
public async disconnectAll (reason?: string): Promise<boolean> {
public async disconnectAll (reason?: string | ChatComponent): Promise<boolean> {
const promises: Promise<boolean>[] = [];
for (const connection of this.connections)
promises.push(this.disconnect(connection.id, reason));
Expand All @@ -40,18 +40,19 @@ export default class ConnectionPool {
* @param [reason] The reason for the disconnect
* @returns Whether the connection was found and disconnected
*/
public async disconnect(id: string, reason?: string): Promise<boolean> {
public async disconnect(id: string, reason?: string | ChatComponent): Promise<boolean> {
const connection = this.get(id);
if (!connection) return false;
const index = this.connections.indexOf(connection);
if (index === -1) return false;
const message = typeof reason === "string" ? {text: reason} : reason!;
if (reason) switch (connection.state) {
case Connection.State.LOGIN: {
await new DisconnectLoginPacket({text: reason}).send(connection);
await new DisconnectLoginPacket(message).send(connection);
break;
}
case Connection.State.PLAY: {
await new DisconnectPlayPacket({text: reason}).send(connection);
await new DisconnectPlayPacket(message).send(connection);
break;
}
default: {
Expand Down
2 changes: 1 addition & 1 deletion src/Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import * as net from "node:net";
import EventEmitter from "node:events";
import path from "node:path";
import Packet from "./Packet.js";
import Config from "./Config.js";
import Logger from "./Logger.js";
import {TypedClientPacket} from "./types/TypedPacket";
import TypedEventEmitter from "./types/TypedEventEmitter";
import ConnectionPool from "./ConnectionPool.js";
import Connection from "./Connection.js";
import HandshakePacket from "./packet/client/HandshakePacket";
import LoginPacket from "./packet/client/LoginPacket";
import { Config } from "./Config.js";

type ServerEvents = {
/**
Expand Down

0 comments on commit 8e62d20

Please sign in to comment.