1 /++ 2 A collection of constants used throughout the program. 3 4 This acts as a compile-time configuration file to reduce ad-hoc magic numbers. 5 6 Copyright: [JR](https://github.com/zorael) 7 License: [Boost Software License 1.0](https://www.boost.org/users/license.html) 8 9 Authors: 10 [JR](https://github.com/zorael) 11 +/ 12 module kameloso.constants; 13 14 private: 15 16 import kameloso.semver : KamelosoSemVer, KamelosoSemVerPrerelease; 17 18 19 version(DigitalMars) 20 { 21 /// String of the compiler that was used to compile this binary with. Here: `dmd`. 22 enum compiler = "dmd"; 23 } 24 else version(LDC) 25 { 26 /// String of the compiler that was used to compile this binary with. Here: `ldc`. 27 enum compiler = "ldc"; 28 } 29 else version(GNU) 30 { 31 /// String of the compiler that was used to compile this binary with. Here: `gdc`. 32 enum compiler = "gdc"; 33 } 34 else 35 { 36 /// String of the compiler that was used to compile this binary with. Here: no idea. 37 enum compiler = "<unknown>"; 38 } 39 40 41 // buildCompilerVersionString 42 /++ 43 Replaces the following expression and lowers compilation memory by avoiding 44 use of compile-time [std.format.format|format]. 45 46 --- 47 import std.compiler; 48 enum compilerVersion = format("%d.%03d", version_major, version_minor); 49 --- 50 51 Returns: 52 The compiler version as a string in the format of `{MAJOR}.{MINOR}` (eg. `2.100`). 53 +/ 54 auto buildCompilerVersionString() 55 { 56 import lu.conv : toAlphaInto; 57 import std.array : Appender; 58 59 enum major = cast(uint)(__VERSION__ / 1000); 60 enum minor = cast(uint)(__VERSION__ % 1000); 61 62 Appender!(char[]) sink; 63 sink.reserve(5); // 2.098 64 65 major.toAlphaInto(sink); 66 sink.put('.'); 67 minor.toAlphaInto!(3, 3)(sink); 68 69 return sink.data.idup; 70 } 71 72 73 // buildVersionString 74 /++ 75 Replaces the following expression and lowers compilation memory by avoiding 76 use of compile-time [std.format.format|format]. 77 78 --- 79 enum version_ = "%d.%d.%d%s%s" 80 .format( 81 KamelosoSemVer.majorVersion, 82 KamelosoSemVer.minorVersion, 83 KamelosoSemVer.patchVersion, 84 KamelosoSemVerPrerelease.length ? "-" : string.init, 85 KamelosoSemVerPrerelease); 86 --- 87 88 Returns: 89 The program version as a string in the format of 90 `{MAJOR}.{MINOR}.{PATCH}{-PRERELEASE}` (eg. `3.2.0-alpha.1`). 91 `{-PRERELEASE}` is optional. 92 +/ 93 auto buildVersionString() 94 { 95 import lu.conv : toAlphaInto; 96 import std.array : Appender; 97 98 Appender!(char[]) sink; 99 sink.reserve(16); // 10.10.10-alpha.1 100 101 with (KamelosoSemVer) 102 { 103 majorVersion.toAlphaInto(sink); 104 sink.put('.'); 105 minorVersion.toAlphaInto(sink); 106 sink.put('.'); 107 patchVersion.toAlphaInto(sink); 108 109 if (KamelosoSemVerPrerelease.length) 110 { 111 sink.put('-'); 112 sink.put(cast(string)KamelosoSemVerPrerelease); 113 } 114 } 115 116 return sink.data.idup; 117 } 118 119 120 public: 121 122 123 // KamelosoInfo 124 /++ 125 Meta-information about the program. 126 +/ 127 enum KamelosoInfo 128 { 129 version_ = .buildVersionString(), /// Version as a string. 130 built = __TIMESTAMP__, /// Timestamp of when the binary was built. 131 compiler = .compiler, /// Compiler used to build this binary. 132 compilerVersion = .buildCompilerVersionString(), /// Compiler version used to build this binary. 133 source = "https://github.com/zorael/kameloso", /// GitHub source link. 134 } 135 136 137 // KamelosoDefaults 138 /++ 139 Kameloso defaults, strings version. 140 +/ 141 enum KamelosoDefaults 142 { 143 /++ 144 Default user to use when logging onto a server (the USER command). 145 Additionally becomes the bot's IDENT identifier (prepended with a '~'), 146 if a separate `identd` server is not being run. 147 +/ 148 user = "kameloso", 149 150 /// Default server address. 151 serverAddress = "irc.libera.chat", 152 153 /// The default GEOC/"real name" string. 154 realName = "kameloso IRC bot v$version", 155 156 /// The default quit reason, when the bot exits. Supports some string replacements. 157 quitReason = "kameloso IRC bot v$version @ $source", 158 159 /// The default part reason, when the bot is asked to part a channel. 160 partReason = quitReason, 161 162 /++ 163 When a nickname was already taken during registration, append this followed 164 by some random numbers to it to generate a new one. 165 166 A separator of "|" and a taken nickname of "guest" thus gives nicknames like "guest|1". 167 A separator of "^" gives nicknames like "guest^2". 168 +/ 169 altNickSeparator = "|", 170 } 171 172 173 // KamelosoDefaultIntegers 174 /++ 175 Kameloso defaults, integers version. 176 +/ 177 enum KamelosoDefaultIntegers 178 { 179 /// Default server port. 180 port = 6667, 181 } 182 183 184 // KamelosoFilenames 185 /++ 186 Kameloso filenames. 187 +/ 188 enum KamelosoFilenames 189 { 190 /++ 191 The main configuration file. 192 +/ 193 configuration = "kameloso.conf", 194 195 /++ 196 The file containing user account classifiers, specifying which accounts 197 are whitelisted, operators and/or blacklisted. 198 +/ 199 users = "users.json", 200 201 /++ 202 The file containing user "account" hostmasks, mapping what we still 203 consider accounts to hostmasks, on servers that don't employ services. 204 +/ 205 hostmasks = "hostmasks.json", 206 } 207 208 209 // ConnectionDefaultIntegers 210 /++ 211 Connection defaults, integers version. 212 +/ 213 enum ConnectionDefaultIntegers 214 { 215 /// How many times to attempt to connect to an IP before moving on to the next one. 216 retries = 4, 217 } 218 219 220 // ConnectionDefaultFloats 221 /++ 222 Connection defaults, floating point version. 223 +/ 224 enum ConnectionDefaultFloats : double 225 { 226 /// By what to multiply the connect timeout after failing an attempt. 227 delayIncrementMultiplier = 1.5, 228 229 /// By what to multiply [Timeout.receiveMsecs] with to shorten reads. 230 receiveShorteningMultiplier = 0.25, 231 232 /// How many messages to send per second, maximum. 233 messageRate = 1.2, 234 235 /// How many messages to immediately send in one go, before throttling kicks in. 236 messageBurst = 3.0, 237 238 /++ 239 How many messages to send per second, maximum. For *fast* sends on Twitch servers. 240 241 FIXME: Tweak value. 242 +/ 243 messageRateTwitchFast = 3.0, 244 245 /++ 246 How many messages to immediately send in one go, before throttling kicks in. 247 For *fast* sends on Twitch servers. 248 249 FIXME: Tweak value. 250 +/ 251 messageBurstTwitchFast = 10.0, 252 253 /++ 254 How many messages to send per second, maximum. For *slow* sends on Twitch servers. 255 256 FIXME: Tweak value. 257 +/ 258 messageRateTwitchSlow = 0.5, 259 260 /++ 261 How many messages to immediately send in one go, before throttling kicks in. 262 For *slow* sends on Twitch servers. 263 264 FIXME: Tweak value. 265 +/ 266 messageBurstTwitchSlow = 0.5, 267 } 268 269 270 // BufferSize 271 /++ 272 Buffer sizes in bytes. 273 +/ 274 enum BufferSize 275 { 276 /++ 277 The receive buffer size as set as a [std.socket.SocketOption|SocketOption]. 278 +/ 279 socketOptionReceive = 2048, 280 281 /++ 282 The send buffer size as set as a [std.socket.SocketOption|SocketOption]. 283 +/ 284 socketOptionSend = 1024, 285 286 /++ 287 The actual buffer array size used when reading from the socket. 288 +/ 289 socketReceive = 2048, 290 291 /++ 292 The maximum number of queued outgoing lines to buffer. Anything above 293 this will crash the program with a buffer overrun. It can be arbitrarily big. 294 +/ 295 outbuffer = 512, 296 297 /++ 298 The maximum number of queued priority lines to buffer. These are rare. 299 +/ 300 priorityBuffer = 64, 301 302 /++ 303 How many bytes to preallocate a buffer for when printing objects to 304 screen with the [kameloso.printing] templates. This value times the 305 number of objects to print. 306 +/ 307 printObjectBufferPerObject = 1024, 308 309 /++ 310 How many bytes to allocate for the stdout buffer, when we need to do so explicitly. 311 +/ 312 vbufStdout = 16_384, 313 314 /++ 315 How large to make [core.thread.fiber.Fiber|Fiber] stacks, so they don't 316 overflow (which they seem to have a knack for doing). 317 +/ 318 fiberStack = 131_072, 319 } 320 321 322 // Timeout 323 /++ 324 Various timeouts, in seconds unless specified otherwise. 325 +/ 326 enum Timeout 327 { 328 /++ 329 The send attempt timeout as set as a [std.socket.SocketOption|SocketOption], 330 in milliseconds. 331 +/ 332 sendMsecs = 15_000, 333 334 /++ 335 The receive attempt timeout as set as a [std.socket.SocketOption|SocketOption], 336 in milliseconds. 337 +/ 338 receiveMsecs = 1000, 339 340 /++ 341 The amount of time to spend with a shortened receive timeout, in milliseconds. 342 After this, it reverts to [Timeout.receiveMsecs]. 343 +/ 344 maxShortenDurationMsecs = 2000, 345 346 /++ 347 The maximum amount of time to wait between connection attempts. 348 +/ 349 connectionDelayCap = 300, 350 351 /++ 352 The amount of seconds to wait before retrying after a failed connection attempt. 353 +/ 354 connectionRetry = 5, 355 356 /++ 357 The amount of seconds to wait before retrying to connect after an instant 358 failure to register on Twitch. 359 +/ 360 twitchRegistrationFailConnectionRetryMsecs = 500, 361 362 /++ 363 How long to wait before allowing to re-issue a WHOIS query for a user. 364 365 This is merely to stop us from spamming queries for the same person 366 without hysteresis. 367 +/ 368 whoisRetry = 30, 369 370 /++ 371 How long a replayable event is expected to be relevant. Before this it 372 will be replayed, after this it will be discarded. 373 374 Note: WHOIS-replays will break if the ping toward the server reaches this value. 375 +/ 376 whoisDiscard = 10, 377 378 /++ 379 The length of the window in which replays may be queued before the timer 380 towards [Timeout.whoisRetry] kicks in. 381 +/ 382 whoisGracePeriod = 3, 383 384 /++ 385 How long to wait after encountering an error when reading from the server, 386 before trying anew. 387 388 Not having a small delay could cause it to spam the screen with errors 389 as fast as it can. 390 +/ 391 readErrorGracePeriodMsecs = 100, 392 393 /++ 394 How long to keep trying to read from the sever when not receiving anything 395 at all before the connection is considered lost. 396 +/ 397 connectionLost = 600, 398 399 /++ 400 Timeout for HTTP GET requests. 401 +/ 402 httpGET = 10, 403 404 /++ 405 Timeout for concurrency message reads (in between socket reads). 406 +/ 407 messageReadMsecs = 1500, 408 } 409 410 411 // Periodicals 412 /++ 413 Timings and timeouts of various periodical events. 414 +/ 415 enum Periodicals 416 { 417 /++ 418 How often to rehash plugins' `users` associative arrays for more efficient lookups. 419 +/ 420 userAARehashMinutes = 60, 421 } 422 423 424 // ShellReturnValue 425 /++ 426 Magic number shell exit codes. 427 +/ 428 enum ShellReturnValue 429 { 430 /++ 431 Success. No error encountered. 432 +/ 433 success = 0, 434 435 /++ 436 Generic error. 437 +/ 438 failure = 1, 439 440 /++ 441 Failure encountered during `getopt`. 442 +/ 443 getoptFailure = 2, 444 445 /++ 446 Failure encountered when setting up terminal buffering. 447 +/ 448 terminalSetupFailure = 3, 449 450 /++ 451 Settings verification failed. 452 +/ 453 settingsVerificationFailure = 4, 454 455 /++ 456 `--set` argument syntax error. 457 +/ 458 customConfigSyntaxFailure = 5, 459 460 /++ 461 `--set` other failure. 462 +/ 463 customConfigFailure = 6, 464 465 /++ 466 Failure encountered during host address resolution. 467 +/ 468 resolutionFailure = 21, 469 470 /++ 471 Failure encountered during connection attempt. 472 +/ 473 connectionFailure = 22, 474 475 /++ 476 Failure encountered when a plugin tried to load resources. 477 +/ 478 pluginResourceLoadFailure = 31, 479 480 /++ 481 Generic exception was thrown when a plugin tried to load resources. 482 +/ 483 pluginResourceLoadException = 32, 484 485 /++ 486 Failure encountered during plugin setup. 487 +/ 488 pluginSetupFailure = 33, 489 490 /++ 491 Generic exception was thrown when a plugin tried to setup. 492 +/ 493 pluginSetupException = 34, 494 } 495 496 497 // MagicErrorStrings 498 /++ 499 Hardcoded error strings. 500 +/ 501 enum MagicErrorStrings 502 { 503 /++ 504 Failed to set up an SSL context, original library line ([requests]). 505 +/ 506 sslContextCreationFailure = "can't complete call to TLS_method", 507 508 /++ 509 Could not initialise SSL libraries, original line ([arsd.http2]). 510 +/ 511 sslLibraryNotFound = "libssl library not found", 512 513 /++ 514 Could not initialise SSL libraries, rewritten line. 515 +/ 516 sslLibraryNotFoundRewritten = "SSL libraries not found", 517 518 /++ 519 Wiki link oneliner, tagged. 520 +/ 521 visitWikiOneliner = "Visit <l>https://github.com/zorael/kameloso/wiki/OpenSSL</> for more information.", 522 523 /++ 524 `--get-openssl` suggestion hint oneliner, tagged. 525 +/ 526 getOpenSSLSuggestion = "Suggestion: <l>--get-openssl</> may help.", 527 } 528 529 530 // DefaultColours 531 /++ 532 Default colours gathered in one struct namespace. 533 534 This makes it easier to compile-time customise colours to your liking. 535 +/ 536 version(Colours) 537 struct DefaultColours 538 { 539 private: 540 import kameloso.logger : LogLevel; 541 import kameloso.terminal.colours.defs : TerminalForeground; 542 543 alias TF = TerminalForeground; 544 545 public: 546 /++ 547 Colours for timestamps, shared between event-printing and logging. 548 +/ 549 enum TimestampColour : TerminalForeground 550 { 551 /++ 552 For dark terminal backgrounds. Was 553 [kameloso.terminal.colours.defs.TerminalForeground.white_|TerminalForeground.white_]. 554 +/ 555 dark = TF.default_, 556 557 /++ 558 For bright terminal backgrounds. Was 559 [kameloso.terminal.colours.defs.TerminalForeground.black_|TerminalForeground.black_]. 560 +/ 561 bright = TF.default_, 562 } 563 564 /// Logger colours to use with a dark terminal background. 565 static immutable TerminalForeground[256] logcoloursDark = 566 [ 567 LogLevel.all : TF.white, /// LogLevel.all, or just `log` 568 LogLevel.trace : TF.default_, /// `trace` 569 LogLevel.info : TF.lightgreen, /// `info` 570 LogLevel.warning : TF.lightred, /// `warning` 571 LogLevel.error : TF.red, /// `error` 572 LogLevel.critical : TF.red, /// `critical` 573 LogLevel.fatal : TF.red, /// `fatal` 574 LogLevel.off : TF.default_, /// `off` 575 ]; 576 577 /// Logger colours to use with a bright terminal background. 578 static immutable TerminalForeground[256] logcoloursBright = 579 [ 580 LogLevel.all : TF.black, /// LogLevel.all, or just `log` 581 LogLevel.trace : TF.default_, /// `trace` 582 LogLevel.info : TF.green, /// `info` 583 LogLevel.warning : TF.red, /// `warning` 584 LogLevel.error : TF.red, /// `error` 585 LogLevel.critical : TF.red, /// `critical` 586 LogLevel.fatal : TF.red, /// `fatal` 587 LogLevel.off : TF.default_, /// `off` 588 ]; 589 }