|
| 1 | +import { API_VERSION } from "./version.js"; |
1 | 2 | import { BotInfo } from "./BotInfo.js"; |
2 | 3 | import { BotHandshakeFactory } from "./BotHandshakeFactory.js"; |
3 | 4 | import { EnvVars } from "./EnvVars.js"; |
@@ -154,6 +155,8 @@ export class WebSocketHandler { |
154 | 155 | this.serverHandshake = msg; |
155 | 156 | this.callbacks.onServerHandshake?.(msg); |
156 | 157 |
|
| 158 | + this.verifyServerVersionCompatibility(msg.version); |
| 159 | + |
157 | 160 | // Validate required bot info before sending the bot handshake |
158 | 161 | this.validateBotInfo(); |
159 | 162 |
|
@@ -204,6 +207,44 @@ export class WebSocketHandler { |
204 | 207 | // --------------------------------------------------------------------------- |
205 | 208 |
|
206 | 209 | /** Validates that required bot info fields are set before sending the bot handshake. */ |
| 210 | + /** |
| 211 | + * Verifies that the server uses a protocol version compatible with this Bot API. |
| 212 | + * Per SemVer, versions are compatible when the major versions are equal; for the 0.x range |
| 213 | + * anything may change between minor versions, so there the minor versions must be equal as |
| 214 | + * well. Without this check, an incompatible server and Bot API silently misinterpret each |
| 215 | + * other's messages, and the bot appears to join the battle but stands idle without ever |
| 216 | + * scoring. |
| 217 | + */ |
| 218 | + private verifyServerVersionCompatibility(serverVersion?: string): void { |
| 219 | + const api = this.parseMajorMinorVersion(API_VERSION); |
| 220 | + const server = this.parseMajorMinorVersion(serverVersion); |
| 221 | + if (api == null || server == null) { |
| 222 | + return; // a version is unavailable; cannot verify |
| 223 | + } |
| 224 | + const incompatible = api[0] !== server[0] || (api[0] === 0 && api[1] !== server[1]); |
| 225 | + if (incompatible) { |
| 226 | + const message = |
| 227 | + `Protocol version mismatch: Bot API version ${API_VERSION} is not compatible with ` + |
| 228 | + `server version ${serverVersion}. The major versions must be equal ` + |
| 229 | + "(and the minor versions as well for major version 0)."; |
| 230 | + console.error(message); |
| 231 | + throw new BotException(message); |
| 232 | + } |
| 233 | + } |
| 234 | + |
| 235 | + private parseMajorMinorVersion(version?: string): [number, number] | null { |
| 236 | + if (version == null) { |
| 237 | + return null; |
| 238 | + } |
| 239 | + const match = /^\s*(\d+)(?:\.(\d+))?/.exec(version); |
| 240 | + const major = match?.[1]; |
| 241 | + if (major == null) { |
| 242 | + return null; |
| 243 | + } |
| 244 | + const minor = match?.[2]; |
| 245 | + return [parseInt(major, 10), minor == null ? 0 : parseInt(minor, 10)]; |
| 246 | + } |
| 247 | + |
207 | 248 | private validateBotInfo(): void { |
208 | 249 | if (this.isBlank(this.botInfo.name)) { |
209 | 250 | this.throwMissingPropertyException("name"); |
|
0 commit comments