From e0aff8a2caa9d1eb3eae34f0a07c3c02f48b9fb3 Mon Sep 17 00:00:00 2001 From: alekswilc Date: Sat, 3 Aug 2024 16:12:05 +0200 Subject: [PATCH] feat: more servers --- package-lock.json | 10 ++++ package.json | 4 +- src/http/api.ts | 30 ++++++++++- src/http/views/details.ejs | 13 +++-- src/http/views/index.ejs | 36 ++++++++----- src/http/views/search.ejs | 18 +++---- src/index.ts | 10 ++-- src/modules/stations.ts | 6 +-- src/mongo/logs.ts | 2 +- src/util/SimrailClient.ts | 105 ++++++++++++++++++++----------------- 10 files changed, 150 insertions(+), 84 deletions(-) diff --git a/package-lock.json b/package-lock.json index c7c5e0a..145cade 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "@simrail/types": "^0.0.4", + "@types/mongoose": "^5.11.97", "dayjs": "^1.11.12", "ejs": "^3.1.10", "express": "^4.19.2", @@ -146,6 +147,15 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true }, + "node_modules/@types/mongoose": { + "version": "5.11.97", + "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.11.97.tgz", + "integrity": "sha512-cqwOVYT3qXyLiGw7ueU2kX9noE8DPGRY6z8eUxudhXY8NZ7DMKYAxyZkLSevGfhCX3dO/AoX5/SO9lAzfjon0Q==", + "deprecated": "Mongoose publishes its own types, so you do not need to install this package.", + "dependencies": { + "mongoose": "*" + } + }, "node_modules/@types/node": { "version": "22.0.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.0.0.tgz", diff --git a/package.json b/package.json index dd97a16..57be037 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "main": "index.js", "scripts": { "build": "tsc", - "postbuild": "copyfiles --error --up 1 src/http/views/*.* dist" + "postbuild": "copyfiles --error --up 1 src/http/views/*.* dist", + "dev": "npm run build && doppler run node dist" }, "keywords": [], "author": "", @@ -20,6 +21,7 @@ "type": "module", "dependencies": { "@simrail/types": "^0.0.4", + "@types/mongoose": "^5.11.97", "dayjs": "^1.11.12", "ejs": "^3.1.10", "express": "^4.19.2", diff --git a/src/http/api.ts b/src/http/api.ts index 6970714..87fc996 100644 --- a/src/http/api.ts +++ b/src/http/api.ts @@ -26,9 +26,37 @@ export class ApiModule { }); }) + const generateSearch = (regex: RegExp) => [ + { + stationName: { $regex: regex }, + }, + { + userUsername: { $regex: regex }, + }, + { + stationShort: { $regex: regex }, + }, + { + userSteamId: { $regex: regex }, + }, + { + server: { $regex: regex }, + } + ] + app.get('/search', async (req, res) => { if (!req.query.q) return res.redirect('/'); - const records = await MLog.find({ $text: { $search: req.query.q as string } }) + const s = req.query.q.toString().split(',').map(x => new RegExp(x, "i")); + + const records = await MLog.aggregate([ + { + $match: { + $and: [ + ...s.map(x => ({ $or: generateSearch(x) })) + ] + } + } + ]) .sort({ leftDate: -1 }) .limit(30) res.render('search.ejs', { diff --git a/src/http/views/details.ejs b/src/http/views/details.ejs index 20d430a..2e15fe1 100644 --- a/src/http/views/details.ejs +++ b/src/http/views/details.ejs @@ -44,8 +44,8 @@
-

SimRail Logs [PL2]

+

SimRail Logs

+

Dokumentacja

@@ -55,8 +55,10 @@

Stacja: <%= record.stationName %>

-

Data wejścia: <%= dayjs(record.joinedDate).format('HH:mm DD/MM/YYYY') %> (<%= - dayjs(record.joinedDate).fromNow() %>)

+

Serwer: <%= record.server.toUpperCase() %> +

+

Data wejścia: <%= record.joinedDate ? dayjs(record.joinedDate).format('HH:mm DD/MM/YYYY') : '--:-- --/--/--' %> (<%= + record.joinedDate ? dayjs(record.joinedDate).fromNow() : '--' %>)

Data wyjścia: <%= dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %> (<%= dayjs(record.leftDate).fromNow() %>)

@@ -65,8 +67,9 @@
;station: <%= record.stationName %> ;steam: <%= record.userSteamId %> + ;server: <%= record.server %> ;name: <%= record.userUsername %> - ;joined: <%=dayjs(record.joinedDate).format()%> + ;joined: <%=record.joinedDate ? dayjs(record.joinedDate).format() : 'no-data'%> ;left: <%=dayjs(record.leftDate).format()%> ;url: https://simrail.alekswilc.dev/details/<%= record.id %>/ diff --git a/src/http/views/index.ejs b/src/http/views/index.ejs index 8d41ea2..79a1377 100644 --- a/src/http/views/index.ejs +++ b/src/http/views/index.ejs @@ -22,33 +22,45 @@
-

SimRail Logs [PL2]

+

SimRail Logs

+

Dokumentacja

-

Wyszukaj posterunek lub osobe

+

Wyszukaj posterunek, osobe lub serwer

+

Użyj przecinka, aby wyszukać wiele wartości: pl2,Łazy

Ostatnie opuszczenia posterunków

diff --git a/src/http/views/search.ejs b/src/http/views/search.ejs index 80dc5e5..568d1bf 100644 --- a/src/http/views/search.ejs +++ b/src/http/views/search.ejs @@ -23,16 +23,17 @@
-

SimRail Logs [PL2]

+

SimRail Logs

+

Dokumentacja

-

Wyszukaj posterunek lub osobe

+

Wyszukaj posterunek, osobe lub serwer

+

Użyj przecinka, aby wyszukać wiele wartości: pl2,Łazy

Wyniki wyszukiwania

@@ -41,9 +42,8 @@ <% records.forEach(record=> { %>
  • - [ - <%= record.stationShort %> + <%= record.server.toUpperCase() %> ] <%= record.stationName %> - @@ -53,8 +53,8 @@ <%= dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %>

    -

    Data dołączenia: <%= dayjs(record.joinedDate).format('HH:mm DD/MM/YYYY') %> (<%= - dayjs(record.joinedDate).fromNow() %>)

    +

    Data dołączenia: <%= record.joinedDate ? dayjs(record.joinedDate).format('HH:mm DD/MM/YYYY') : '--:-- --/--/--' %> (<%= + record.joinedDate ? dayjs(record.joinedDate).fromNow() : '--' %>)

    Data wyjścia: <%= dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %> (<%= dayjs(record.leftDate).fromNow() %>)

    @@ -70,9 +70,9 @@ location.href = '/search?q=' + document.getElementById('search').value } document.getElementById('search').addEventListener("keyup", (event) => { - if (event.key === "Enter") + if (event.key === "Enter") search(); - + }); diff --git a/src/index.ts b/src/index.ts index 923fb42..8e9df41 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,8 +5,8 @@ import dayjs from 'dayjs'; import { StationsModule } from './modules/stations.js'; import { ApiModule } from './http/api.js'; import mongoose from 'mongoose'; -import { IStation } from './types/station.js'; import { IPlayer } from './types/player.js'; +import { Station, Server } from '@simrail/types'; ; (async () => { @@ -22,12 +22,12 @@ import { IPlayer } from './types/player.js'; console.log('MongoDB connected'); global.client = new SimrailClient(); - client.on(SimrailClientEvents.StationJoined, (station: IStation, player: IPlayer) => { - console.log(`${station.Name} | ${player.personaname} joined`); + client.on(SimrailClientEvents.StationJoined, (server: Server, station: Station, player: IPlayer) => { + console.log(`${server.ServerCode} |${station.Name} | ${player.personaname} joined`); }); - client.on(SimrailClientEvents.StationLeft, (station: IStation, player: IPlayer, joinedAt: number) => { - console.log(`${station.Name} | ${player.personaname} left. | ${joinedAt ? dayjs(joinedAt).fromNow() : 'no time data.'}`); + client.on(SimrailClientEvents.StationLeft, (server: Server, station: Station, player: IPlayer, joinedAt: number) => { + console.log(`${server.ServerCode} | ${station.Name} | ${player.personaname} left. | ${joinedAt ? dayjs(joinedAt).fromNow() : 'no time data.'}`); }); StationsModule.load(); diff --git a/src/modules/stations.ts b/src/modules/stations.ts index 945ca12..093b166 100644 --- a/src/modules/stations.ts +++ b/src/modules/stations.ts @@ -1,13 +1,13 @@ +import { Server, Station } from '@simrail/types'; import { MLog } from '../mongo/logs.js'; import { IPlayer } from '../types/player.js'; -import { IStation } from '../types/station.js'; import { SimrailClientEvents } from '../util/SimrailClient.js'; import { v4 } from 'uuid'; export class StationsModule { public static load() { - client.on(SimrailClientEvents.StationLeft, (station: IStation, player: IPlayer, joinedAt: number) => { + client.on(SimrailClientEvents.StationLeft, (server: Server, station: Station, player: IPlayer, joinedAt: number) => { const date = new Date(); MLog.create({ @@ -19,7 +19,7 @@ export class StationsModule { leftDate: date.getTime(), stationName: station.Name, stationShort: station.Prefix, - server: 'pl2' + server: server.ServerCode }); }) } diff --git a/src/mongo/logs.ts b/src/mongo/logs.ts index b813832..9555162 100644 --- a/src/mongo/logs.ts +++ b/src/mongo/logs.ts @@ -42,7 +42,7 @@ const schema = new Schema( }, } ); -schema.index({ stationName: 'text', userUsername: 'text', stationShort: 'text', userSteamId: 'text' }) +schema.index({ stationName: 'text', userUsername: 'text', stationShort: 'text', userSteamId: 'text', server: 'text' }) export type TMLog = Model diff --git a/src/util/SimrailClient.ts b/src/util/SimrailClient.ts index d48cc06..957e0d6 100644 --- a/src/util/SimrailClient.ts +++ b/src/util/SimrailClient.ts @@ -2,7 +2,7 @@ import { EventEmitter } from 'node:events'; import { IPlayer } from '../types/player.js'; import { PlayerUtil } from './PlayerUtil.js'; -import { Station, ApiResponse } from '@simrail/types'; +import { Station, ApiResponse, Server } from '@simrail/types'; export enum SimrailClientEvents { StationJoined = 'stationJoined', @@ -10,16 +10,20 @@ export enum SimrailClientEvents { } export declare interface SimrailClient { - on(event: SimrailClientEvents.StationJoined, listener: (station: Station, player: IPlayer) => void): this; - on(event: SimrailClientEvents.StationLeft, listener: (station: Station, player: IPlayer, joinedAt: number) => void): this; + on(event: SimrailClientEvents.StationJoined, listener: (server: Server, station: Station, player: IPlayer) => void): this; + on(event: SimrailClientEvents.StationLeft, listener: (server: Server, station: Station, player: IPlayer, joinedAt: number) => void): this; - on(event: string, listener: Function): this; + //on(event: string, listener: Function): this; } +export type OccupiedStation = { + SteamId: string; + JoinedAt: number; +} export class SimrailClient extends EventEmitter { - public stations: Station[] = []; - public stationsOccupied: Record = {}; + public stations: Record = {}; + public stationsOccupied: Record> = {}; public constructor() { super(); @@ -27,13 +31,13 @@ export class SimrailClient extends EventEmitter { setTimeout(() => setInterval(() => this.update(), 500), 1000) } - public getStation(name: string) { - if (!this.stationsOccupied[name]) return null; - const player = PlayerUtil.getPlayer(this.stationsOccupied[name].steamId); + public getStation(server: Server['ServerCode'], name: string) { + if (!this.stationsOccupied[server] || !this.stationsOccupied[server][name]) return null; + const player = PlayerUtil.getPlayer(this.stationsOccupied[server][name].SteamId); return { player, joinedAt: this.stationsOccupied[name].joinedAt }; } - + private async setup() { if (!await redis.json.get('stations')) redis.json.set('stations', '$', []); @@ -41,55 +45,62 @@ export class SimrailClient extends EventEmitter { if (!await redis.json.get('stations_occupied')) redis.json.set('stations_occupied', '$', {}); - this.stations = (await redis.json.get('stations') as unknown as Station[]); - this.stationsOccupied = (await redis.json.get('stations_occupied') as unknown as Record); + this.stations = (await redis.json.get('stations') as unknown as SimrailClient['stations']); + this.stationsOccupied = (await redis.json.get('stations_occupied') as unknown as SimrailClient['stationsOccupied']); } private async update() { - const servers = (await fetch('https://panel.simrail.eu:8084/stations-open?serverCode=pl2').then(x => x.json())) as ApiResponse; - if (!servers.result) return + const servers = (await fetch('https://panel.simrail.eu:8084/servers-open').then(x => x.json()) as ApiResponse) + .data?.filter(x => x.ServerName.includes('Polski')) ?? []; // no plans to support other servers + + // TODO: maybe node:worker_threads? + // TODO: check performance + servers.forEach(async (server) => { + const stations = (await fetch('https://panel.simrail.eu:8084/stations-open?serverCode=' + server.ServerCode).then(x => x.json())) as ApiResponse; + if (!stations.result) return; - if (!this.stations.length) { - this.stations = servers.data; - redis.json.set('list', '$', this.stations); - return - } - - - servers.data.forEach(async (x) => { - const data = this.stations.find(y => y.Name === x.Name); - if (!data) return; - - - if (data.DispatchedBy[0]?.SteamId !== x.DispatchedBy[0]?.SteamId) { - - if (!data.DispatchedBy[0]?.SteamId) { - // join - const date = new Date(); - const player = await PlayerUtil.getPlayer(x.DispatchedBy[0]?.SteamId); - - this.emit(SimrailClientEvents.StationJoined, x, player); - this.stationsOccupied[data.Prefix] = { - steamId: x.DispatchedBy[0]?.SteamId, - joinedAt: date.getTime() - } - redis.json.set('stations_occupied', '$', this.stationsOccupied); + if (!this.stations[server.ServerCode]) this.stations[server.ServerCode] = []; + if (!this.stationsOccupied[server.ServerCode]) this.stationsOccupied[server.ServerCode] = {}; + if (!this.stations[server.ServerCode].length) { + this.stations[server.ServerCode] = stations.data; + redis.json.set('stations', '$', this.stations); return; } - const player = await PlayerUtil.getPlayer(data.DispatchedBy[0]?.SteamId) + stations.data.forEach(async (x) => { + const data = this.stations[server.ServerCode].find(y => y.Name === x.Name); + if (!data) return; - this.emit(SimrailClientEvents.StationLeft, x, player, this.stationsOccupied[data.Prefix]?.joinedAt); - delete this.stationsOccupied[data.Prefix]; - redis.json.set('stations_occupied', '$', this.stationsOccupied); - } - }) + if (data.DispatchedBy[0]?.SteamId !== x.DispatchedBy[0]?.SteamId) { + if (!data.DispatchedBy[0]?.SteamId) { + // join + const date = new Date(); + const player = await PlayerUtil.getPlayer(x.DispatchedBy[0]?.SteamId); + + this.emit(SimrailClientEvents.StationJoined, server, x, player); + this.stationsOccupied[server.ServerCode][data.Prefix] = { + SteamId: x.DispatchedBy[0]?.SteamId, + JoinedAt: date.getTime() + }; + redis.json.set('stations_occupied', '$', this.stationsOccupied); + + return; + } + // leave + const player = await PlayerUtil.getPlayer(data.DispatchedBy[0]?.SteamId) + + this.emit(SimrailClientEvents.StationLeft, server, x, player, this.stationsOccupied[server.ServerCode][data.Prefix]?.JoinedAt); + delete this.stationsOccupied[server.ServerCode][data.Prefix]; + redis.json.set('stations_occupied', '$', this.stationsOccupied); + } + }) - this.stations = servers.data; - redis.json.set('stations', '$', this.stations); + this.stations[server.ServerCode] = stations.data; + redis.json.set('stations', '$', this.stations); + }); } } \ No newline at end of file