Skip to content

Commit

Permalink
refactor: Add NPS data handling and web request handling functions
Browse files Browse the repository at this point in the history
  • Loading branch information
drazisil committed May 31, 2024
1 parent 0c0de58 commit 4d7620c
Show file tree
Hide file tree
Showing 6 changed files with 296 additions and 6 deletions.
11 changes: 5 additions & 6 deletions packages/main/src/MainLoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,13 @@ export class MainLoop {
/** @type {NodeJS.Timeout | undefined} */
_timer = undefined;

/** @typedef {function(): Promise<void> | void | any} Task */
/** @type {Array<Task>} */
/** @type {Array<import("obsidian-main").Task>} */
_startTasks = [];

/** @type {Array<Task>} */
/** @type {Array<import("obsidian-main").Task>} */
_stopTasks = [];

/** @type {Array<Task>} */
/** @type {Array<import("obsidian-main").Task>} */
_loopTasks = [];

/**
Expand All @@ -45,7 +44,7 @@ export class MainLoop {
/**
*
* @param {"start" | "loop" | "stop"} type
* @param {Task} task
* @param {import("obsidian-main").Task} task
*/
addTask(type, task) {
if (type === "start") {
Expand All @@ -58,7 +57,7 @@ export class MainLoop {
}

/**
* @param {Array<Task>} tasks
* @param {Array<import("obsidian-main").Task>} tasks
*/
async _callTasks(tasks) {
tasks.forEach(async (task) => {
Expand Down
119 changes: 119 additions & 0 deletions packages/main/src/ShardService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@

/** @type {Map<number, import("obsidian-main").IShardEntry>} */
const shards = new Map();

class ShardEntry {
/**
* @param {object} values
* @param {number} values.id
* @param {string} values.name
* @param {string} values.description
* @param {string} values.loginServerIP
* @param {number} [values.loginServerPort]
* @param {string} values.lobbyServerIP
* @param {number} [values.lobbyServerPort]
* @param {string} values.mcotsServerIP
* @param {number} [values.statusId]
* @param {string} [values.statusReason]
* @param {string} values.serverGroupName
* @param {number} [values.population]
* @param {number} [values.maxPersonasPerUser]
* @param {string} values.diagServerIP
* @param {number} [values.diagServerPort]
*/
constructor({
id,
name,
description,
loginServerIP,
loginServerPort = 8226,
lobbyServerIP,
lobbyServerPort = 7003,
mcotsServerIP,
statusId = 0,
statusReason = "",
serverGroupName: serverGroupsName,
population = 0,
maxPersonasPerUser = 1,
diagServerIP,
diagServerPort = 80,
}) {
this.id = id;
this.name = name;
this.description = description;
this.loginServerIP = loginServerIP;
this.loginServerPort = loginServerPort;
this.lobbyServerIP = lobbyServerIP;
this.lobbyServerPort = lobbyServerPort;
this.mcotsServerIP = mcotsServerIP;
this.statusId = statusId;
this.statusReason = statusReason;
this.serverGroupName = serverGroupsName;
this.population = population;
this.maxPersonasPerUser = maxPersonasPerUser;
this.diagServerIP = diagServerIP;
this.diagServerPort = diagServerPort;
}

/**
*
* @param {number} population
*/
setPopulation(population) {
this.population = population;
}

/**
* @returns {string}
*/
formatForWeb() {
return `[${this.name}]\n`
+ `\tDescription=${this.id}\n`
+ `\tShardId=${this.id}\n`
+ `\tLoginServerIP=${this.loginServerIP}\n`
+ `\tLoginServerPort=${this.loginServerPort}\n`
+ `\tLobbyServerIP=${this.lobbyServerIP}\n`
+ `\tLobbyServerPort=${this.lobbyServerPort}\n`
+ `\tMCOTSServerIP=${this.mcotsServerIP}\n`
+ `\tStatusId=${this.statusId}\n`
+ `\tStatus_Reason=${this.statusReason}\n`
+ `\tServerGroup_Name=${this.serverGroupName}\n`
+ `\tPopulation=${this.population}\n`
+ `\tMaxPersonasPerUser=${this.maxPersonasPerUser}\n`
+ `\tDiagnosticServerHost=${this.diagServerIP}\n`
+ `\tDiagnosticServerPort=${this.diagServerPort}\n`;
}
}

export class ShardService {

/**
*
* @param {number} id
* @param {string} name
* @param {string} description
* @param {string} ip
* @param {string} serverGroupName
*/
addShard(id, name, description, ip, serverGroupName) {
shards.set(id, new ShardEntry({
id,
name,
description,
loginServerIP: ip,
lobbyServerIP: ip,
serverGroupName: serverGroupName,
mcotsServerIP: ip,
diagServerIP: ip,
}));
}

/**
* @returns {string}
*/
getShardList() {
return Array.from(shards.values())
.map((entry) => entry.formatForWeb())
.join("\n\n");
}
}
62 changes: 62 additions & 0 deletions packages/main/src/UserLoginService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/** @type {Array<{username: string, password: string, customerId: number}>} */
const users = [{ username: "admin", password: "admin", customerId: 1 }];
/** @type {Map<string, number>} */
const tokens = new Map();

export class UserLoginService {
/**
* Returns the customer ID if the user is valid, otherwise -1.
*
* @param {string} username
* @param {string} password
* @returns {number}
*/
checkUser(username, password) {
const user = users.find(
(user) => user.username === username && user.password === password
);

return user ? user.customerId : -1;
}

/**
* Creates a token for the given customer ID.
*
* @param {number} customerId
* @returns {string}
*/
createToken(customerId) {
const token = crypto.randomUUID();
tokens.set(token, customerId);
return token;
}

/**
* Checks if the token is valid and returns the customer ID.
* If the token is invalid, returns -1.
*
* @param {string} token
* @returns {number}
*/
checkToken(token) {
const customerId = tokens.get(token);
return customerId ?? -1;
}

/**
* Deletes the token.
*
* @param {string} token
*/
deleteToken(token) {
tokens.delete(token);
}

async deleteAllTokens() {
return new Promise((resolve) => {
tokens.clear();
console.log("All tokens deleted");
resolve(void 0);
});
}
}
6 changes: 6 additions & 0 deletions packages/main/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,11 @@ declare module "obsidian-main" {
shift: boolean;
}

export type Task = () => Promise<void> | void | any;

export interface IShardEntry {
formatForWeb(): string;
}

export function _atExit(): void;
}
19 changes: 19 additions & 0 deletions packages/main/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

import { MainLoop } from "./MainLoop.js";
import { ShardService } from "./ShardService.js";
import { TCPServer } from "./TCPServer.js";
import { UserLoginService } from "./UserLoginService.js";
import { WebServer } from "./WebServer.js";
import { onNPSData } from "./nps.js";
import { onWebRequest } from "./web.js";
Expand Down Expand Up @@ -125,6 +127,18 @@ export default function main() {
onServerError
);

const shardService = new ShardService();
shardService.addShard(
1,
"Rusty Motors",
"A test shard",
"10.10.5.20",
"Group - 1",
);


const userLoginService = new UserLoginService();

const mainLoop = new MainLoop();
mainLoop.addTask("start", authServer.listen.bind(authServer));
mainLoop.addTask("start", loginServer.listen.bind(loginServer));
Expand All @@ -135,5 +149,10 @@ export default function main() {
"stop",
personaServer.close.bind(personaServer, onServerError)
);
mainLoop.addTask(
"stop",
userLoginService.deleteAllTokens.bind(userLoginService)
);

mainLoop.start();
}
85 changes: 85 additions & 0 deletions packages/main/src/web.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,92 @@
import { ShardService } from "./ShardService.js";
import { UserLoginService } from "./UserLoginService.js";

/**
*
* @param {import("node:http").ServerResponse} res
* @param {string} ticket
*/
function sendTicket(res, ticket) {
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");
res.end(`Valid=TRUE\nTicket=${ticket}`);
}

/**
*
* @param {import("node:http").ServerResponse} res
* @param {number} statusCode
* @param {string} message
*/

function sendError(res, statusCode, message) {
res.statusCode = statusCode;
res.setHeader("Content-Type", "text/plain");
res.end(
`reasoncode=INV-200\nreasontext=${message}\nreasonurl=https://rusty-motors.com`
);
}

/**
* @param {import("node:http").IncomingMessage} req
* @param {import("node:http").ServerResponse} res
*/
function homePage(req, res) {
res.end("Hello, world!");
}

/**
* @param {import("node:http").IncomingMessage} req
* @param {import("node:http").ServerResponse} res
* @param {string} username
* @param {string} password
*/
function authLogin(req, res, username, password) {
const userLoginService = new UserLoginService();
const customerId = userLoginService.checkUser(username, password);

if (customerId === -1) {
return sendError(res, 401, "Invalid username or password");
}

const token = userLoginService.createToken(customerId);
sendTicket(res, token);
}

/**
* @param {import("node:http").IncomingMessage} req
* @param {import("node:http").ServerResponse} res
*/
function getShardList(req, res) {
const shardService = new ShardService();

res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");

res.end(shardService.getShardList());
}

/**
* @param {import("node:http").IncomingMessage} req
* @param {import("node:http").ServerResponse} res
*/
export function onWebRequest(req, res) {
console.log(`Request URL: ${req.url}`);
const url = new URL(`http://${process.env.HOST ?? "localhost"}${req.url}`);

if (url.pathname === "/") {
return homePage(req, res);
}

if (url.pathname === "/AuthLogin") {
const username = url.searchParams.get("username") ?? "";
const password = url.searchParams.get("password") ?? "";

return authLogin(req, res, username, password);
}

if (url.pathname === "/ShardList/") {
return getShardList(req, res);
}
res.end("Hello, world!");
}

0 comments on commit 4d7620c

Please sign in to comment.