@babylonjs-toolkit/server 0.0.0-stage → 9.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CUSTOM.md +1690 -0
- package/DEPLOY.md +2012 -0
- package/README.md +1081 -2
- package/lib/AbuseLimits.d.ts +64 -0
- package/lib/AbuseLimits.js +121 -0
- package/lib/Authentication.d.ts +86 -0
- package/lib/Authentication.js +272 -0
- package/lib/BootSessionOwner.d.ts +86 -0
- package/lib/BootSessionOwner.js +116 -0
- package/lib/ColyseusLoggerAdapter.d.ts +32 -0
- package/lib/ColyseusLoggerAdapter.js +73 -0
- package/lib/DedicatedSceneRegistry.d.ts +52 -0
- package/lib/DedicatedSceneRegistry.js +74 -0
- package/lib/DedicatedSession.d.ts +152 -0
- package/lib/DedicatedSession.js +173 -0
- package/lib/DualTransport.d.ts +112 -0
- package/lib/DualTransport.js +197 -0
- package/lib/GameServer.d.ts +64 -0
- package/lib/GameServer.js +647 -0
- package/lib/GameServerConfig.d.ts +387 -0
- package/lib/GameServerConfig.js +1059 -0
- package/lib/GameServerLobbyRoom.d.ts +33 -0
- package/lib/GameServerLobbyRoom.js +56 -0
- package/lib/GameServerLogger.d.ts +111 -0
- package/lib/GameServerLogger.js +190 -0
- package/lib/GameServerMetrics.d.ts +158 -0
- package/lib/GameServerMetrics.js +276 -0
- package/lib/GameServerState.d.ts +164 -0
- package/lib/GameServerState.js +26 -0
- package/lib/HeadlessRuntime.d.ts +316 -0
- package/lib/HeadlessRuntime.js +380 -0
- package/lib/JoinGate.d.ts +34 -0
- package/lib/JoinGate.js +221 -0
- package/lib/NetworkAddresses.d.ts +33 -0
- package/lib/NetworkAddresses.js +90 -0
- package/lib/PlayerTokens.d.ts +17 -0
- package/lib/PlayerTokens.js +24 -0
- package/lib/RoomServerTransport.d.ts +73 -0
- package/lib/RoomServerTransport.js +90 -0
- package/lib/ServerEndpoints.d.ts +133 -0
- package/lib/ServerEndpoints.js +247 -0
- package/lib/ServerInit.d.ts +28 -0
- package/lib/ServerInit.js +113 -0
- package/lib/SessionRoom.d.ts +391 -0
- package/lib/SessionRoom.js +930 -0
- package/lib/TlsCertificates.d.ts +35 -0
- package/lib/TlsCertificates.js +130 -0
- package/lib/admin/AccountRoutes.d.ts +8 -0
- package/lib/admin/AccountRoutes.js +502 -0
- package/lib/admin/AdminAccounts.d.ts +329 -0
- package/lib/admin/AdminAccounts.js +607 -0
- package/lib/admin/AdminApiRouter.d.ts +202 -0
- package/lib/admin/AdminApiRouter.js +465 -0
- package/lib/admin/AdminApiTypes.d.ts +1782 -0
- package/lib/admin/AdminApiTypes.js +4 -0
- package/lib/admin/AdminAudit.d.ts +113 -0
- package/lib/admin/AdminAudit.js +266 -0
- package/lib/admin/AdminCli.d.ts +7 -0
- package/lib/admin/AdminCli.js +351 -0
- package/lib/admin/AdminClock.d.ts +51 -0
- package/lib/admin/AdminClock.js +10 -0
- package/lib/admin/AdminConsole.d.ts +39 -0
- package/lib/admin/AdminConsole.js +325 -0
- package/lib/admin/AdminConstants.d.ts +147 -0
- package/lib/admin/AdminConstants.js +167 -0
- package/lib/admin/AdminCrypto.d.ts +19 -0
- package/lib/admin/AdminCrypto.js +29 -0
- package/lib/admin/AdminExtensionsHost.d.ts +176 -0
- package/lib/admin/AdminExtensionsHost.js +307 -0
- package/lib/admin/AdminPasswords.d.ts +33 -0
- package/lib/admin/AdminPasswords.js +92 -0
- package/lib/admin/AdminPermissions.d.ts +28 -0
- package/lib/admin/AdminPermissions.js +74 -0
- package/lib/admin/AdminRecords.d.ts +196 -0
- package/lib/admin/AdminRecords.js +3 -0
- package/lib/admin/AdminRequestBodies.d.ts +47 -0
- package/lib/admin/AdminRequestBodies.js +84 -0
- package/lib/admin/AdminRequestGate.d.ts +38 -0
- package/lib/admin/AdminRequestGate.js +59 -0
- package/lib/admin/AdminResponses.d.ts +103 -0
- package/lib/admin/AdminResponses.js +164 -0
- package/lib/admin/AdminServices.d.ts +99 -0
- package/lib/admin/AdminServices.js +4 -0
- package/lib/admin/AdminStaticFiles.d.ts +29 -0
- package/lib/admin/AdminStaticFiles.js +97 -0
- package/lib/admin/AdminStore.d.ts +152 -0
- package/lib/admin/AdminStore.js +46 -0
- package/lib/admin/AlertChannels.d.ts +43 -0
- package/lib/admin/AlertChannels.js +120 -0
- package/lib/admin/AlertEngine.d.ts +231 -0
- package/lib/admin/AlertEngine.js +681 -0
- package/lib/admin/AlertRoutes.d.ts +8 -0
- package/lib/admin/AlertRoutes.js +180 -0
- package/lib/admin/ApiKeyRoutes.d.ts +8 -0
- package/lib/admin/ApiKeyRoutes.js +53 -0
- package/lib/admin/ApiKeys.d.ts +63 -0
- package/lib/admin/ApiKeys.js +167 -0
- package/lib/admin/AuditRoutes.d.ts +8 -0
- package/lib/admin/AuditRoutes.js +106 -0
- package/lib/admin/AuthToolRoutes.d.ts +13 -0
- package/lib/admin/AuthToolRoutes.js +164 -0
- package/lib/admin/BanList.d.ts +87 -0
- package/lib/admin/BanList.js +152 -0
- package/lib/admin/CborDecoder.d.ts +18 -0
- package/lib/admin/CborDecoder.js +201 -0
- package/lib/admin/ColyseusCloudClient.d.ts +313 -0
- package/lib/admin/ColyseusCloudClient.js +272 -0
- package/lib/admin/ColyseusCloudRoutes.d.ts +8 -0
- package/lib/admin/ColyseusCloudRoutes.js +91 -0
- package/lib/admin/ColyseusCloudService.d.ts +180 -0
- package/lib/admin/ColyseusCloudService.js +476 -0
- package/lib/admin/ColyseusCloudSettings.d.ts +16 -0
- package/lib/admin/ColyseusCloudSettings.js +29 -0
- package/lib/admin/ColyseusCloudViews.d.ts +105 -0
- package/lib/admin/ColyseusCloudViews.js +371 -0
- package/lib/admin/CommonPasswords.d.ts +6 -0
- package/lib/admin/CommonPasswords.js +19 -0
- package/lib/admin/ConfigOverrides.d.ts +174 -0
- package/lib/admin/ConfigOverrides.js +406 -0
- package/lib/admin/ConfigRoutes.d.ts +8 -0
- package/lib/admin/ConfigRoutes.js +91 -0
- package/lib/admin/ConsoleSessions.d.ts +112 -0
- package/lib/admin/ConsoleSessions.js +201 -0
- package/lib/admin/DedicatedRoutes.d.ts +21 -0
- package/lib/admin/DedicatedRoutes.js +254 -0
- package/lib/admin/ExtensionRoutes.d.ts +8 -0
- package/lib/admin/ExtensionRoutes.js +145 -0
- package/lib/admin/FileAdminStore.d.ts +157 -0
- package/lib/admin/FileAdminStore.js +349 -0
- package/lib/admin/FleetDirectory.d.ts +323 -0
- package/lib/admin/FleetDirectory.js +489 -0
- package/lib/admin/FleetLeader.d.ts +43 -0
- package/lib/admin/FleetLeader.js +89 -0
- package/lib/admin/FleetRoutes.d.ts +55 -0
- package/lib/admin/FleetRoutes.js +465 -0
- package/lib/admin/HealthWarnings.d.ts +10 -0
- package/lib/admin/HealthWarnings.js +95 -0
- package/lib/admin/LeaderboardRoutes.d.ts +8 -0
- package/lib/admin/LeaderboardRoutes.js +569 -0
- package/lib/admin/LogBuffer.d.ts +60 -0
- package/lib/admin/LogBuffer.js +92 -0
- package/lib/admin/LogRedaction.d.ts +15 -0
- package/lib/admin/LogRedaction.js +72 -0
- package/lib/admin/LogRoutes.d.ts +45 -0
- package/lib/admin/LogRoutes.js +307 -0
- package/lib/admin/MaintenanceMode.d.ts +41 -0
- package/lib/admin/MaintenanceMode.js +74 -0
- package/lib/admin/MaintenanceWindows.d.ts +91 -0
- package/lib/admin/MaintenanceWindows.js +207 -0
- package/lib/admin/MetricsRoutes.d.ts +8 -0
- package/lib/admin/MetricsRoutes.js +209 -0
- package/lib/admin/MetricsSampler.d.ts +124 -0
- package/lib/admin/MetricsSampler.js +211 -0
- package/lib/admin/OneTimeCodes.d.ts +60 -0
- package/lib/admin/OneTimeCodes.js +162 -0
- package/lib/admin/OpenIdConnect.d.ts +146 -0
- package/lib/admin/OpenIdConnect.js +335 -0
- package/lib/admin/Passkeys.d.ts +130 -0
- package/lib/admin/Passkeys.js +432 -0
- package/lib/admin/PlayerRoutes.d.ts +20 -0
- package/lib/admin/PlayerRoutes.js +676 -0
- package/lib/admin/RedisAdminStore.d.ts +114 -0
- package/lib/admin/RedisAdminStore.js +258 -0
- package/lib/admin/RolloutCoordinator.d.ts +99 -0
- package/lib/admin/RolloutCoordinator.js +321 -0
- package/lib/admin/ServerEvents.d.ts +57 -0
- package/lib/admin/ServerEvents.js +89 -0
- package/lib/admin/SessionRoutes.d.ts +113 -0
- package/lib/admin/SessionRoutes.js +386 -0
- package/lib/admin/UserRoutes.d.ts +8 -0
- package/lib/admin/UserRoutes.js +214 -0
- package/lib/cli.d.ts +2 -0
- package/lib/cli.js +221 -0
- package/lib/console/assets/index-CI5N7c-T.js +21 -0
- package/lib/console/assets/index-DPitvzLp.css +1 -0
- package/lib/console/favicon.svg +1 -0
- package/lib/console/index.html +16 -0
- package/lib/discord/DiscordOAuth.d.ts +57 -0
- package/lib/discord/DiscordOAuth.js +127 -0
- package/lib/discord/DiscordSessions.d.ts +79 -0
- package/lib/discord/DiscordSessions.js +135 -0
- package/lib/discord/DiscordSignInConstants.d.ts +54 -0
- package/lib/discord/DiscordSignInConstants.js +55 -0
- package/lib/discord/DiscordSignInRoutes.d.ts +51 -0
- package/lib/discord/DiscordSignInRoutes.js +359 -0
- package/lib/index.d.ts +24 -0
- package/lib/index.js +18 -0
- package/lib/leaderboards/FileLeaderboardRankStore.d.ts +293 -0
- package/lib/leaderboards/FileLeaderboardRankStore.js +808 -0
- package/lib/leaderboards/LeaderboardConstants.d.ts +63 -0
- package/lib/leaderboards/LeaderboardConstants.js +70 -0
- package/lib/leaderboards/LeaderboardError.d.ts +15 -0
- package/lib/leaderboards/LeaderboardError.js +20 -0
- package/lib/leaderboards/LeaderboardIdentity.d.ts +44 -0
- package/lib/leaderboards/LeaderboardIdentity.js +72 -0
- package/lib/leaderboards/LeaderboardPublicApi.d.ts +17 -0
- package/lib/leaderboards/LeaderboardPublicApi.js +389 -0
- package/lib/leaderboards/LeaderboardRankStore.d.ts +296 -0
- package/lib/leaderboards/LeaderboardRankStore.js +18 -0
- package/lib/leaderboards/LeaderboardRules.d.ts +122 -0
- package/lib/leaderboards/LeaderboardRules.js +472 -0
- package/lib/leaderboards/LeaderboardScheduler.d.ts +43 -0
- package/lib/leaderboards/LeaderboardScheduler.js +103 -0
- package/lib/leaderboards/LeaderboardService.d.ts +669 -0
- package/lib/leaderboards/LeaderboardService.js +1667 -0
- package/lib/leaderboards/LeaderboardTransfer.d.ts +35 -0
- package/lib/leaderboards/LeaderboardTransfer.js +580 -0
- package/lib/leaderboards/RedisLeaderboardRankStore.d.ts +282 -0
- package/lib/leaderboards/RedisLeaderboardRankStore.js +691 -0
- package/package.json +64 -4
- package/templates/init/Caddyfile +6 -0
- package/templates/init/DEPLOY.md +233 -0
- package/templates/init/Dockerfile +12 -0
- package/templates/init/app.json +21 -0
- package/templates/init/aws/README.md +118 -0
- package/templates/init/aws/ecs-fargate-alb.yml +207 -0
- package/templates/init/aws/ecs-fargate-nlb-quic.yml +210 -0
- package/templates/init/babylon-game-server.config.mjs +158 -0
- package/templates/init/colyseus-cloud/README.md +133 -0
- package/templates/init/colyseus-cloud/babylon-game-server.config.mjs +36 -0
- package/templates/init/colyseus-cloud/ecosystem.config.cjs +35 -0
- package/templates/init/colyseus-cloud/gitignore +6 -0
- package/templates/init/colyseus-cloud/package.json +15 -0
- package/templates/init/digitalocean-app.yaml +30 -0
- package/templates/init/docker-compose.full.yml +45 -0
- package/templates/init/docker-compose.websocket.yml +41 -0
- package/templates/init/fly.toml +56 -0
- package/templates/init/heroku.yml +11 -0
- package/templates/init/kubernetes/deployment.yaml +71 -0
- package/templates/init/kubernetes/redis.yaml +73 -0
- package/templates/init/kubernetes/service.yaml +24 -0
- package/templates/init/monitoring/grafana-dashboard.json +539 -0
- package/templates/init/monitoring/prometheus-alerts.yml +51 -0
- package/templates/init/monitoring/prometheus-scrape.yml +17 -0
- package/templates/init/railway.json +13 -0
- package/templates/init/render.yaml +19 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { collectDefaultMetrics, Counter, Gauge, Histogram, Registry } from "prom-client";
|
|
2
|
+
/** Prefix of every metric name (D16). */
|
|
3
|
+
const METRIC_PREFIX = "babylon_game_server_";
|
|
4
|
+
/**
|
|
5
|
+
* Bucket bounds of the dedicated frame histogram, in seconds: from well under a 60 Hz tick (16.7 ms) to frames long
|
|
6
|
+
* enough to stall a session.
|
|
7
|
+
*/
|
|
8
|
+
const DEDICATED_FRAME_BUCKETS_SECONDS = [0.001, 0.0025, 0.005, 0.01, 0.0167, 0.025, 0.05, 0.1, 0.25, 0.5, 1];
|
|
9
|
+
/**
|
|
10
|
+
* How long a counter snapshot is reused, in milliseconds (game-server-admin-console R22): just under one metrics sample
|
|
11
|
+
* interval, so the registry's JSON is built about once per sample however many readers there are.
|
|
12
|
+
*/
|
|
13
|
+
const SNAPSHOT_CACHE_MS = 14000;
|
|
14
|
+
/**
|
|
15
|
+
* The Prometheus metrics of a game server (D16), on a private registry with the process defaults (event-loop lag,
|
|
16
|
+
* memory). The player, session and dedicated-session gauges are computed when Prometheus scrapes, from the live session
|
|
17
|
+
* rooms, so nothing polls; the counters and the frame histogram are fed by the rooms and the join gate through
|
|
18
|
+
* GameServerMetricsSink.
|
|
19
|
+
*/
|
|
20
|
+
export class GameServerMetrics {
|
|
21
|
+
/** The registry every metric of this server is on. */
|
|
22
|
+
registry = new Registry();
|
|
23
|
+
/** Reads the running server's state at scrape time. */
|
|
24
|
+
readState;
|
|
25
|
+
/** Join decisions by result. */
|
|
26
|
+
joinsTotal;
|
|
27
|
+
/** Refused joins by ShutdownReason name. */
|
|
28
|
+
refusalsTotal;
|
|
29
|
+
/** Failed token checks by auth mode. */
|
|
30
|
+
authFailuresTotal;
|
|
31
|
+
/** Simulation frames by direction, transport and channel. */
|
|
32
|
+
framesTotal;
|
|
33
|
+
/** Simulation frame bytes by direction and transport. */
|
|
34
|
+
bytesTotal;
|
|
35
|
+
/** Room messages (frames and controls) by direction: the room message rate. */
|
|
36
|
+
messagesTotal;
|
|
37
|
+
/** Leaderboard scores by result (game-server-leaderboards D21). */
|
|
38
|
+
leaderboardScoresTotal;
|
|
39
|
+
/** Refused leaderboard scores and requests by reason (game-server-leaderboards D19). */
|
|
40
|
+
leaderboardRefusalsTotal;
|
|
41
|
+
/** Dedicated frames that took longer than one simulation tick. */
|
|
42
|
+
dedicatedTickOverrunsTotal;
|
|
43
|
+
/** How long dedicated runners' frames take. */
|
|
44
|
+
dedicatedFrameSeconds;
|
|
45
|
+
/** The last counter snapshot, reused for SNAPSHOT_CACHE_MS. */
|
|
46
|
+
cachedSnapshot = null;
|
|
47
|
+
/**
|
|
48
|
+
* Creates the metrics and registers the process defaults.
|
|
49
|
+
* @param state Reads the running server's state (the gauges read its session rooms at scrape time).
|
|
50
|
+
*/
|
|
51
|
+
constructor(state) {
|
|
52
|
+
this.readState = state;
|
|
53
|
+
collectDefaultMetrics({ register: this.registry, prefix: METRIC_PREFIX });
|
|
54
|
+
this.registerGauges();
|
|
55
|
+
const registers = [this.registry];
|
|
56
|
+
this.joinsTotal = new Counter({ name: METRIC_PREFIX + "joins_total", help: "Session and lobby join decisions, by result.", labelNames: ["result"], registers: registers });
|
|
57
|
+
this.refusalsTotal = new Counter({ name: METRIC_PREFIX + "refusals_total", help: "Refused joins, by ShutdownReason name.", labelNames: ["reason"], registers: registers });
|
|
58
|
+
this.authFailuresTotal = new Counter({ name: METRIC_PREFIX + "auth_failures_total", help: "Failed token checks, by auth mode.", labelNames: ["mode"], registers: registers });
|
|
59
|
+
this.framesTotal = new Counter({ name: METRIC_PREFIX + "frames_total", help: "Simulation frames, by direction, transport and channel.", labelNames: ["direction", "transport", "channel"], registers: registers });
|
|
60
|
+
this.bytesTotal = new Counter({ name: METRIC_PREFIX + "bytes_total", help: "Simulation frame bytes, by direction and transport.", labelNames: ["direction", "transport"], registers: registers });
|
|
61
|
+
this.messagesTotal = new Counter({ name: METRIC_PREFIX + "messages_total", help: "Room messages (simulation frames and controls), by direction.", labelNames: ["direction"], registers: registers });
|
|
62
|
+
this.dedicatedTickOverrunsTotal = new Counter({ name: METRIC_PREFIX + "dedicated_tick_overruns_total", help: "Dedicated runner frames longer than one simulation tick.", registers: registers });
|
|
63
|
+
this.leaderboardScoresTotal = new Counter({ name: METRIC_PREFIX + "leaderboard_scores_total", help: "Leaderboard scores, by result.", labelNames: ["result"], registers: registers });
|
|
64
|
+
this.leaderboardRefusalsTotal = new Counter({ name: METRIC_PREFIX + "leaderboard_refusals_total", help: "Refused leaderboard scores and requests, by reason.", labelNames: ["reason"], registers: registers });
|
|
65
|
+
this.dedicatedFrameSeconds = new Histogram({ name: METRIC_PREFIX + "dedicated_frame_seconds", help: "Duration of dedicated runner frames, in seconds.", buckets: DEDICATED_FRAME_BUCKETS_SECONDS, registers: registers });
|
|
66
|
+
}
|
|
67
|
+
/** The Content-Type of the Prometheus text the metrics endpoint answers with. */
|
|
68
|
+
get contentType() {
|
|
69
|
+
return this.registry.contentType;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Counts a join decision; a refusal is also counted by its reason.
|
|
73
|
+
* @param result "accepted" or "refused".
|
|
74
|
+
* @param reasonName The ShutdownReason name of a refusal, or null.
|
|
75
|
+
*/
|
|
76
|
+
countJoin(result, reasonName) {
|
|
77
|
+
this.joinsTotal.inc({ result: result });
|
|
78
|
+
if (result === "refused" && reasonName != null)
|
|
79
|
+
this.refusalsTotal.inc({ reason: reasonName });
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Counts a failed token check.
|
|
83
|
+
* @param mode The auth mode that refused it.
|
|
84
|
+
*/
|
|
85
|
+
countAuthFailure(mode) {
|
|
86
|
+
this.authFailuresTotal.inc({ mode: mode });
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Counts one simulation frame and its bytes.
|
|
90
|
+
* @param direction "in" from a client, "out" to a client.
|
|
91
|
+
* @param transport The client's connection.
|
|
92
|
+
* @param channel The delivery channel.
|
|
93
|
+
* @param byteLength The frame size in bytes.
|
|
94
|
+
*/
|
|
95
|
+
countFrame(direction, transport, channel, byteLength) {
|
|
96
|
+
this.framesTotal.inc({ direction: direction, transport: transport, channel: channel });
|
|
97
|
+
this.bytesTotal.inc({ direction: direction, transport: transport }, byteLength);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Counts one room message (a simulation frame or a control).
|
|
101
|
+
* @param direction "in" from a client, "out" to a client.
|
|
102
|
+
*/
|
|
103
|
+
countMessage(direction) {
|
|
104
|
+
this.messagesTotal.inc({ direction: direction });
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Counts one leaderboard score; a refused score is also counted by its reason (game-server-leaderboards D19).
|
|
108
|
+
* @param result What happened to the score.
|
|
109
|
+
* @param reason The refusal reason, or null.
|
|
110
|
+
*/
|
|
111
|
+
countLeaderboardScore(result, reason) {
|
|
112
|
+
this.leaderboardScoresTotal.inc({ result: result });
|
|
113
|
+
if (reason != null)
|
|
114
|
+
this.leaderboardRefusalsTotal.inc({ reason: reason });
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Counts one refused leaderboard request (rate limit, auth, ban, bad request; game-server-leaderboards D19).
|
|
118
|
+
* @param reason The refusal reason.
|
|
119
|
+
*/
|
|
120
|
+
countLeaderboardRequestRefusal(reason) {
|
|
121
|
+
this.leaderboardRefusalsTotal.inc({ reason: reason });
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Records how long a dedicated runner's frame took, counting an overrun when it did not fit in one tick.
|
|
125
|
+
* @param seconds The frame's duration, in seconds.
|
|
126
|
+
* @param tickSeconds The simulation tick length, in seconds.
|
|
127
|
+
*/
|
|
128
|
+
observeDedicatedFrame(seconds, tickSeconds) {
|
|
129
|
+
this.dedicatedFrameSeconds.observe(seconds);
|
|
130
|
+
if (seconds > tickSeconds)
|
|
131
|
+
this.dedicatedTickOverrunsTotal.inc();
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Renders every metric as Prometheus text (computing the gauges from the live session rooms).
|
|
135
|
+
* @returns The exposition text.
|
|
136
|
+
*/
|
|
137
|
+
render() {
|
|
138
|
+
return this.registry.metrics();
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The counter totals the admin console reads (game-server-admin-console R22): a snapshot younger than the allowed
|
|
142
|
+
* age is returned as it is, so the registry's JSON is built at most about once per metrics sample (building it also
|
|
143
|
+
* restarts the event-loop histogram of the process defaults).
|
|
144
|
+
* @param maxAgeMilliseconds The oldest cached snapshot accepted (default SNAPSHOT_CACHE_MS; the metrics sampler
|
|
145
|
+
* passes less, so each of its samples reads fresh counters).
|
|
146
|
+
* @returns The totals since start.
|
|
147
|
+
*/
|
|
148
|
+
async snapshot(maxAgeMilliseconds = SNAPSHOT_CACHE_MS) {
|
|
149
|
+
const now = Date.now();
|
|
150
|
+
if (this.cachedSnapshot != null && now - this.cachedSnapshot.takenAt < maxAgeMilliseconds)
|
|
151
|
+
return this.cachedSnapshot.snapshot;
|
|
152
|
+
const metrics = await this.registry.getMetricsAsJSON();
|
|
153
|
+
const snapshot = buildCounterSnapshot(metrics);
|
|
154
|
+
this.cachedSnapshot = { takenAt: now, snapshot: snapshot };
|
|
155
|
+
return snapshot;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Registers the scrape-time gauges: players and sessions by game mode, and dedicated sessions.
|
|
159
|
+
*/
|
|
160
|
+
registerGauges() {
|
|
161
|
+
const metrics = this;
|
|
162
|
+
const registers = [this.registry];
|
|
163
|
+
new Gauge({
|
|
164
|
+
name: METRIC_PREFIX + "players",
|
|
165
|
+
help: "Players connected to sessions, by game mode.",
|
|
166
|
+
labelNames: ["game_mode"],
|
|
167
|
+
registers: registers,
|
|
168
|
+
collect() {
|
|
169
|
+
this.reset();
|
|
170
|
+
for (const [gameMode, totals] of metrics.totalsByGameMode())
|
|
171
|
+
this.set({ game_mode: gameMode }, totals.players);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
new Gauge({
|
|
175
|
+
name: METRIC_PREFIX + "sessions",
|
|
176
|
+
help: "Live sessions, by game mode.",
|
|
177
|
+
labelNames: ["game_mode"],
|
|
178
|
+
registers: registers,
|
|
179
|
+
collect() {
|
|
180
|
+
this.reset();
|
|
181
|
+
for (const [gameMode, totals] of metrics.totalsByGameMode())
|
|
182
|
+
this.set({ game_mode: gameMode }, totals.sessions);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
new Gauge({
|
|
186
|
+
name: METRIC_PREFIX + "dedicated_sessions",
|
|
187
|
+
help: "Live sessions a dedicated Server-mode runner hosts.",
|
|
188
|
+
registers: registers,
|
|
189
|
+
collect() {
|
|
190
|
+
this.set(metrics.liveRooms().filter((room) => room.isDedicated).length);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Sums players and sessions of the live session rooms by game mode name.
|
|
196
|
+
* @returns The totals, keyed by game mode name ("Pending" before a session's first join).
|
|
197
|
+
*/
|
|
198
|
+
totalsByGameMode() {
|
|
199
|
+
const totals = new Map();
|
|
200
|
+
for (const room of this.liveRooms()) {
|
|
201
|
+
const modeTotals = totals.get(room.gameModeName) ?? { players: 0, sessions: 0 };
|
|
202
|
+
modeTotals.players += room.playerCount;
|
|
203
|
+
modeTotals.sessions += 1;
|
|
204
|
+
totals.set(room.gameModeName, modeTotals);
|
|
205
|
+
}
|
|
206
|
+
return totals;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* The live session rooms of the running server.
|
|
210
|
+
* @returns The rooms.
|
|
211
|
+
*/
|
|
212
|
+
liveRooms() {
|
|
213
|
+
return Array.from(this.readState().sessionRooms);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Sums the registry's JSON into the counter snapshot (DR §6.7).
|
|
218
|
+
* @param metrics The registry's metrics as JSON.
|
|
219
|
+
* @returns The snapshot.
|
|
220
|
+
*/
|
|
221
|
+
function buildCounterSnapshot(metrics) {
|
|
222
|
+
const sum = (name, filter = () => true) => sumMetric(metrics, METRIC_PREFIX + name, filter);
|
|
223
|
+
const withLabel = (label, expected) => (value) => value.labels[label] === expected;
|
|
224
|
+
const named = (metricName) => (value) => value.metricName === METRIC_PREFIX + metricName;
|
|
225
|
+
return {
|
|
226
|
+
joinsAccepted: sum("joins_total", withLabel("result", "accepted")),
|
|
227
|
+
joinsRefused: sum("joins_total", withLabel("result", "refused")),
|
|
228
|
+
refusalsByReason: sumByLabel(metrics, METRIC_PREFIX + "refusals_total", "reason"),
|
|
229
|
+
authFailures: sum("auth_failures_total"),
|
|
230
|
+
framesIn: sum("frames_total", withLabel("direction", "in")),
|
|
231
|
+
framesOut: sum("frames_total", withLabel("direction", "out")),
|
|
232
|
+
bytesIn: sum("bytes_total", withLabel("direction", "in")),
|
|
233
|
+
bytesOut: sum("bytes_total", withLabel("direction", "out")),
|
|
234
|
+
framesByTransport: { websocket: sum("frames_total", withLabel("transport", "websocket")), webtransport: sum("frames_total", withLabel("transport", "webtransport")) },
|
|
235
|
+
messagesIn: sum("messages_total", withLabel("direction", "in")),
|
|
236
|
+
messagesOut: sum("messages_total", withLabel("direction", "out")),
|
|
237
|
+
dedicatedTickOverruns: sum("dedicated_tick_overruns_total"),
|
|
238
|
+
dedicatedFrameSecondsSum: sum("dedicated_frame_seconds", named("dedicated_frame_seconds_sum")),
|
|
239
|
+
dedicatedFrameCount: sum("dedicated_frame_seconds", named("dedicated_frame_seconds_count")),
|
|
240
|
+
cpuSecondsTotal: sum("process_cpu_seconds_total"),
|
|
241
|
+
residentMemoryBytes: sum("process_resident_memory_bytes"),
|
|
242
|
+
heapUsedBytes: sum("nodejs_heap_size_used_bytes"),
|
|
243
|
+
gcSecondsTotal: sum("nodejs_gc_duration_seconds", named("nodejs_gc_duration_seconds_sum")),
|
|
244
|
+
leaderboardScoresAccepted: sum("leaderboard_scores_total", withLabel("result", "accepted")),
|
|
245
|
+
leaderboardScoresRefused: sum("leaderboard_scores_total", withLabel("result", "refused"))
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Sums the values of one metric that pass a filter.
|
|
250
|
+
* @param metrics The registry's metrics as JSON.
|
|
251
|
+
* @param name The full metric name.
|
|
252
|
+
* @param filter Picks the values to add.
|
|
253
|
+
* @returns The sum, or 0 when the metric is missing.
|
|
254
|
+
*/
|
|
255
|
+
function sumMetric(metrics, name, filter) {
|
|
256
|
+
const metric = metrics.find((candidate) => candidate.name === name);
|
|
257
|
+
if (metric == null)
|
|
258
|
+
return 0;
|
|
259
|
+
return metric.values.filter(filter).reduce((total, value) => total + value.value, 0);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Sums the values of one metric per value of a label.
|
|
263
|
+
* @param metrics The registry's metrics as JSON.
|
|
264
|
+
* @param name The full metric name.
|
|
265
|
+
* @param label The label to group by.
|
|
266
|
+
* @returns The sums, keyed by label value.
|
|
267
|
+
*/
|
|
268
|
+
function sumByLabel(metrics, name, label) {
|
|
269
|
+
const totals = {};
|
|
270
|
+
const metric = metrics.find((candidate) => candidate.name === name);
|
|
271
|
+
for (const value of metric?.values ?? []) {
|
|
272
|
+
const key = String(value.labels[label] ?? "");
|
|
273
|
+
totals[key] = (totals[key] ?? 0) + value.value;
|
|
274
|
+
}
|
|
275
|
+
return totals;
|
|
276
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import type { JoinRateLimiter } from "./AbuseLimits.js";
|
|
2
|
+
import type { AuthIdentity, AuthRequest, ManagedTokenVerifier } from "./Authentication.js";
|
|
3
|
+
import type { DedicatedSceneRegistry } from "./DedicatedSceneRegistry.js";
|
|
4
|
+
import type { AuthMode, ConfigSourceMap, GameServerConfig } from "./GameServerConfig.js";
|
|
5
|
+
import type { SessionRoom } from "./SessionRoom.js";
|
|
6
|
+
import type { DiscordSessions } from "./discord/DiscordSessions.js";
|
|
7
|
+
import type { TlsMaterial } from "./TlsCertificates.js";
|
|
8
|
+
import type { GameServerLobbyRoom } from "./GameServerLobbyRoom.js";
|
|
9
|
+
import type { MaintenanceState } from "./admin/AdminApiTypes.js";
|
|
10
|
+
import type { BanList, KickBlockList } from "./admin/BanList.js";
|
|
11
|
+
import type { LogBuffer } from "./admin/LogBuffer.js";
|
|
12
|
+
import type { PlayerSessionEvent } from "./admin/AdminRecords.js";
|
|
13
|
+
/** A session's description, passed to the session hooks. */
|
|
14
|
+
export interface SessionEvent {
|
|
15
|
+
/** The Colyseus room id. */
|
|
16
|
+
roomId: string;
|
|
17
|
+
/** The session name players join by. */
|
|
18
|
+
sessionName: string;
|
|
19
|
+
/** The TOOLKIT.GameMode of the joiner that created the session (Server for a dedicated session), or null. */
|
|
20
|
+
gameMode: number | null;
|
|
21
|
+
/** True when a dedicated Server-mode runner hosts the session. */
|
|
22
|
+
isDedicated: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** A player of a session, passed to the player hooks. */
|
|
25
|
+
export interface PlayerEvent extends SessionEvent {
|
|
26
|
+
/** The player id in the session. */
|
|
27
|
+
playerId: number;
|
|
28
|
+
/** The identity the server verified from the player's token, or null when auth is off. */
|
|
29
|
+
identity: AuthIdentity | null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Lifecycle and custom-auth hooks of a game server. A hook that throws is logged with its name and the server carries on.
|
|
33
|
+
*/
|
|
34
|
+
export interface GameServerHooks {
|
|
35
|
+
/**
|
|
36
|
+
* The verifier of auth mode "custom" (D13).
|
|
37
|
+
* @param request The token and what the server knows about the join.
|
|
38
|
+
* @returns The verified identity, or null to refuse with CustomAuthenticationFailed.
|
|
39
|
+
*/
|
|
40
|
+
verifyToken?(request: AuthRequest): Promise<AuthIdentity | null>;
|
|
41
|
+
/**
|
|
42
|
+
* A session room was created.
|
|
43
|
+
* @param event The session.
|
|
44
|
+
*/
|
|
45
|
+
onSessionCreated?(event: SessionEvent): void;
|
|
46
|
+
/**
|
|
47
|
+
* A player was admitted to a session.
|
|
48
|
+
* @param event The player and its session.
|
|
49
|
+
*/
|
|
50
|
+
onPlayerJoined?(event: PlayerEvent): void;
|
|
51
|
+
/**
|
|
52
|
+
* A player left a session for good.
|
|
53
|
+
* @param event The player and its session.
|
|
54
|
+
*/
|
|
55
|
+
onPlayerLeft?(event: PlayerEvent): void;
|
|
56
|
+
/**
|
|
57
|
+
* A session room closed.
|
|
58
|
+
* @param event The session.
|
|
59
|
+
*/
|
|
60
|
+
onSessionClosed?(event: SessionEvent): void;
|
|
61
|
+
}
|
|
62
|
+
/** What the rooms and the gate record; GameServerMetrics (T7) implements it. */
|
|
63
|
+
export interface GameServerMetricsSink {
|
|
64
|
+
/**
|
|
65
|
+
* Counts a join decision.
|
|
66
|
+
* @param result "accepted" or "refused".
|
|
67
|
+
* @param reasonName The ShutdownReason name of a refusal, or null.
|
|
68
|
+
*/
|
|
69
|
+
countJoin(result: "accepted" | "refused", reasonName: string | null): void;
|
|
70
|
+
/**
|
|
71
|
+
* Counts a failed token check.
|
|
72
|
+
* @param mode The auth mode that refused it.
|
|
73
|
+
*/
|
|
74
|
+
countAuthFailure(mode: AuthMode): void;
|
|
75
|
+
/**
|
|
76
|
+
* Counts one simulation frame.
|
|
77
|
+
* @param direction "in" from a client, "out" to a client.
|
|
78
|
+
* @param transport The client's connection.
|
|
79
|
+
* @param channel The delivery channel.
|
|
80
|
+
* @param byteLength The frame size in bytes.
|
|
81
|
+
*/
|
|
82
|
+
countFrame(direction: "in" | "out", transport: "websocket" | "webtransport", channel: "reliable" | "unreliable", byteLength: number): void;
|
|
83
|
+
/**
|
|
84
|
+
* Records how long a dedicated runner's frame took.
|
|
85
|
+
* @param seconds The frame's duration.
|
|
86
|
+
* @param tickSeconds The simulation tick length the frame must fit in.
|
|
87
|
+
*/
|
|
88
|
+
observeDedicatedFrame(seconds: number, tickSeconds: number): void;
|
|
89
|
+
/**
|
|
90
|
+
* Counts one room message, frame or control (the room message rate, game-server-admin-console T10). Optional, so
|
|
91
|
+
* custom sinks written before it keep compiling.
|
|
92
|
+
* @param direction "in" from a client, "out" to a client.
|
|
93
|
+
*/
|
|
94
|
+
countMessage?(direction: "in" | "out"): void;
|
|
95
|
+
/**
|
|
96
|
+
* Counts one leaderboard score or refused request (game-server-leaderboards D21). Optional, so older custom sinks
|
|
97
|
+
* keep compiling.
|
|
98
|
+
* @param result What happened to the score.
|
|
99
|
+
* @param reason The refusal reason, or null.
|
|
100
|
+
*/
|
|
101
|
+
countLeaderboardScore?(result: "accepted" | "duplicate" | "refused", reason: string | null): void;
|
|
102
|
+
/**
|
|
103
|
+
* Counts one refused leaderboard request (rate limit, auth, ban, bad request; game-server-leaderboards D19).
|
|
104
|
+
* @param reason The refusal reason.
|
|
105
|
+
*/
|
|
106
|
+
countLeaderboardRequestRefusal?(reason: string): void;
|
|
107
|
+
}
|
|
108
|
+
/** The process-wide state of the running game server, which the static join gate and the rooms read (D10). */
|
|
109
|
+
export interface GameServerStateValues {
|
|
110
|
+
/** The resolved config. */
|
|
111
|
+
config: GameServerConfig;
|
|
112
|
+
/** The hooks the server was created with (possibly none). */
|
|
113
|
+
hooks: GameServerHooks;
|
|
114
|
+
/** The token verifier, or null when auth is off. */
|
|
115
|
+
verifier: ManagedTokenVerifier | null;
|
|
116
|
+
/** This server's Discord player sessions, or null while Discord sign-in is off (discord-sign-in D10). */
|
|
117
|
+
discordSessions: DiscordSessions | null;
|
|
118
|
+
/** Where each option's value came from (game-server-admin-console D20); every path is "code" for a server made from code. */
|
|
119
|
+
configSources: ConfigSourceMap;
|
|
120
|
+
/** The per-address join rate limiter (D14). */
|
|
121
|
+
rateLimiter: JoinRateLimiter;
|
|
122
|
+
/** The Prometheus metrics, or null when metrics.enabled is false (D16). */
|
|
123
|
+
metrics: GameServerMetricsSink | null;
|
|
124
|
+
/** The dedicated scenes this server may run (D19). */
|
|
125
|
+
registry: DedicatedSceneRegistry;
|
|
126
|
+
/** True once a drain started: the gate refuses new joins with GameClosed (D17). */
|
|
127
|
+
draining: boolean;
|
|
128
|
+
/** Maintenance in force on this instance, or null; the admin console sets it (game-server-admin-console D14). */
|
|
129
|
+
maintenance: MaintenanceState | null;
|
|
130
|
+
/** Live session rooms of this process. */
|
|
131
|
+
sessionRooms: Set<SessionRoom>;
|
|
132
|
+
/** Live lobby rooms of this process (lobby kick, game-server-admin-console R15). */
|
|
133
|
+
lobbyRooms: Set<GameServerLobbyRoom>;
|
|
134
|
+
/** Bans enforced by the join gate, or null while the console is off (game-server-admin-console D15). */
|
|
135
|
+
banList: BanList | null;
|
|
136
|
+
/** Recently kicked players per session name, kept in presence (game-server-admin-console D12, R19). */
|
|
137
|
+
kickBlocks: KickBlockList;
|
|
138
|
+
/** Receives every player join and leave of a session; the admin console sets it to keep player history, else null. */
|
|
139
|
+
onPlayerSessionEvent: ((event: PlayerSessionEvent) => void) | null;
|
|
140
|
+
/** Called with every session join and leave for leaderboard session presence (game-server-leaderboards D10), or null. */
|
|
141
|
+
onLeaderboardSessionPresence: ((event: PlayerSessionEvent) => void) | null;
|
|
142
|
+
/** The recent log lines the console tails and searches, or null while the console is off (game-server-admin-console D21). */
|
|
143
|
+
logBuffer: LogBuffer | null;
|
|
144
|
+
/** The TLS material served now, for certificate expiry (null without TLS). */
|
|
145
|
+
tlsMaterial: TlsMaterial | null;
|
|
146
|
+
/** ISO time the process started. */
|
|
147
|
+
startedAt: string;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The running game server's state.
|
|
151
|
+
* @returns The state.
|
|
152
|
+
* @throws Error("no Babylon Game Server is running in this process") before createGameServer or after close.
|
|
153
|
+
*/
|
|
154
|
+
export declare function getGameServerState(): GameServerStateValues;
|
|
155
|
+
/**
|
|
156
|
+
* The running game server's state, for code that also runs without one (DedicatedSession, HeadlessRuntime).
|
|
157
|
+
* @returns The state, or null when no game server runs.
|
|
158
|
+
*/
|
|
159
|
+
export declare function findGameServerState(): GameServerStateValues | null;
|
|
160
|
+
/**
|
|
161
|
+
* Sets or clears the process's game server state. createGameServer sets it; close and the end of a drain clear it.
|
|
162
|
+
* @param state The state, or null.
|
|
163
|
+
*/
|
|
164
|
+
export declare function setGameServerState(state: GameServerStateValues | null): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** The running game server's state, or null when none runs in this process. */
|
|
2
|
+
let currentState = null;
|
|
3
|
+
/**
|
|
4
|
+
* The running game server's state.
|
|
5
|
+
* @returns The state.
|
|
6
|
+
* @throws Error("no Babylon Game Server is running in this process") before createGameServer or after close.
|
|
7
|
+
*/
|
|
8
|
+
export function getGameServerState() {
|
|
9
|
+
if (currentState == null)
|
|
10
|
+
throw new Error("no Babylon Game Server is running in this process");
|
|
11
|
+
return currentState;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The running game server's state, for code that also runs without one (DedicatedSession, HeadlessRuntime).
|
|
15
|
+
* @returns The state, or null when no game server runs.
|
|
16
|
+
*/
|
|
17
|
+
export function findGameServerState() {
|
|
18
|
+
return currentState;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Sets or clears the process's game server state. createGameServer sets it; close and the end of a drain clear it.
|
|
22
|
+
* @param state The state, or null.
|
|
23
|
+
*/
|
|
24
|
+
export function setGameServerState(state) {
|
|
25
|
+
currentState = state;
|
|
26
|
+
}
|