diff --git a/src/fivem/fivem.controller.ts b/src/fivem/fivem.controller.ts index 4bfa328..f47e04f 100644 --- a/src/fivem/fivem.controller.ts +++ b/src/fivem/fivem.controller.ts @@ -5,13 +5,14 @@ import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger'; import { Cache } from 'cache-manager'; import ServerTrackedDto from 'src/dto/serverTrackedDto'; import ServerCfxDto from 'src/dto/serverCfxDto'; -import { fivemCfxResponse, fivemPlayersResponse, fivemResponse } from './fivem.schema'; +import { fivemCfxResponse, fivemInfoResponse, fivemPlayersResponse, fivemResponse } from './fivem.schema'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { CacheKeys } from 'src/utils/enums'; /* CODE CacheKey - FM : FiveM Track server by Address +- FMI : FiveM Track server Info - FMCFX : FiveM Track server by CFX Code - FMP : FiveM Track Players */ @@ -89,4 +90,26 @@ export class FivemController { this.cacheManager.set(`${CacheKeys.FiveMPlayers}:${address.address}`, result, 5 * 60 * 1000); return result; } + + @Get('/info/:address') + @ApiOperation({ + summary: "Track a FiveM Server's info", + description: "Return a JSON response with information about the server", + }) + @ApiOkResponse({ + description: 'Server information', + schema: fivemInfoResponse + }) + async getServerInfo(@Param() address: ServerTrackedDto): Promise { + const cache: any = await this.cacheManager.get(`${CacheKeys.FiveMInfo}:${address.address}`); + let result: any; + + if (cache) + return cache; + result = await this.service.trackInfo(address); + result["cacheTime"] = Math.floor(Date.now() / 1000); + result["cacheExpire"] = Math.floor(Date.now() / 1000) + (5 * 60); + this.cacheManager.set(`${CacheKeys.FiveMInfo}:${address.address}`, result, 5 * 60 * 1000); + return result; + } } diff --git a/src/fivem/fivem.schema.ts b/src/fivem/fivem.schema.ts index b4c967b..408091e 100644 --- a/src/fivem/fivem.schema.ts +++ b/src/fivem/fivem.schema.ts @@ -285,8 +285,70 @@ const fivemCfxResponse: SchemaObject & Partial = { } } +const fivemInfoResponse: SchemaObject & Partial = { + type: 'object', + properties: { + address: { type: 'string', description: "Server's address" }, + online: { type: 'boolean', description: "Server's status. If the bool is true, the server is online" }, + cacheTime: { type: 'number', description: "UNIX timestamp when the response was cached" }, + cacheExpire: { type: 'number', description: "UNIX timestamp when the response will be remove from cache. Around 5 minutes." }, + enhancedHostSupport: { type: 'boolean', description: "Enhanced host support", nullable: true }, + icon: { type: 'string', description: "Server's icon in base64 format", nullable: true }, + resources: { + type: 'array', + description: "List of resources used by the server", + nullable: true, + items: { type: 'string' } + }, + server: { type: 'string', nullable: true, description: "Server's software" }, + version: { type: 'number', nullable: true, description: "Server's version" }, + vars: { + type: 'object', + description: "Server's variables", + nullable: true, + properties: { + sv_disableClientReplays: { type: 'boolean', nullable: true }, + sv_enforceGameBuild: { type: 'number', nullable: true }, + sv_enhancedHostSupport: { type: 'boolean', nullable: true }, + sv_lan: { type: 'boolean', nullable: true }, + sv_licenseKeyToken: { type: 'string', nullable: true }, + sv_maxClients: { type: 'number', nullable: true }, + sv_poolSizesIncrease: { type: 'string', nullable: true }, + sv_projectDesc: { type: 'string', nullable: true }, + sv_projectName: { type: 'string', nullable: true }, + sv_pureLevel: { type: 'number', nullable: true }, + sv_replaceExeToSwitchBuilds: { type: 'boolean', nullable: true }, + sv_scriptHookAllowed: { type: 'boolean', nullable: true }, + } + } + }, + example: { + enhancedHostSupport: true, + icon: "data:image/png;base64,...", + requestSteamTicket: "off", + resources: ["hardcap", "_cfx_internal", "mapmanager"], + server: "FXServer-master SERVER v1.0.0.6228 win32", + version: 123, + vars: { + sv_disableClientReplays: true, + sv_enforceGameBuild: 2802, + sv_enhancedHostSupport: true, + sv_lan: false, + sv_licenseKeyToken: "abcdef123456", + sv_maxClients: 32, + sv_poolSizesIncrease: "2048", + sv_projectDesc: "My FiveM server", + sv_projectName: "My FiveM server description", + sv_pureLevel: 1, + sv_replaceExeToSwitchBuilds: false, + sv_scriptHookAllowed: false + } + } +}; + export { fivemResponse, + fivemInfoResponse, fivemPlayersResponse, fivemCfxResponse }; \ No newline at end of file diff --git a/src/fivem/fivem.service.ts b/src/fivem/fivem.service.ts index 25835c9..67199e8 100644 --- a/src/fivem/fivem.service.ts +++ b/src/fivem/fivem.service.ts @@ -33,6 +33,32 @@ export class FivemService { } } + async trackInfo(serverTracked: ServerTrackedDto): Promise { + try { + const response: Response = await fetch( + `http://${serverTracked.address}/info.json`, + { + method: 'GET', + signal: AbortSignal.timeout(2000), + } + ) + const data = await response.json(); + return { + address: serverTracked.address, + online: true, + ...data, + }; + } catch (err: any) { + Logger.warn( + `[FiveM server | ${serverTracked.address}] ${err.name}: ${err.message}`, + ); + return { + address: serverTracked.address, + online: false, + }; + } + } + async trackServerByCfx(cfx: ServerCfxDto): Promise { try { let response: Response = await fetch( diff --git a/src/utils/enums.ts b/src/utils/enums.ts index 53b5b65..9131712 100644 --- a/src/utils/enums.ts +++ b/src/utils/enums.ts @@ -24,6 +24,7 @@ enum CacheKeys { FiveM = "FM", FiveMCfxCode = "FMCFX", FiveMPlayers = "FMP", + FiveMInfo = "FMI", Minecraft = "MC", MinecraftQuery = "MCQ", MinecraftBedrock = "MCB",