├── .cargo └── config ├── .dockerignore ├── .gitignore ├── .gitlab-ci.yml ├── .vscode └── settings.json ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── README.md ├── USER_GUIDE.md ├── client_example ├── consumer.py ├── request_cache.py └── update_presence.py ├── rustfmt.toml └── src ├── config.rs ├── main.rs ├── model.rs ├── reader.rs └── worker.rs /.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-C", "link-arg=-fuse-ld=lld", "-C", "target-cpu=haswell"] 3 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .vscode/ 3 | Dockerfile 4 | LICENSE 5 | README.md 6 | .gitignore 7 | .dockerignore 8 | client_example/ 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | rateway.toml 3 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: "quay.io/podman/stable" 2 | 3 | before_script: 4 | - sed -i "s:# runtime = \"runc\":runtime = \"crun\":g" /usr/share/containers/containers.conf 5 | - sed -i "s:driver = \"overlay\":driver = \"vfs\":g" /etc/containers/storage.conf 6 | - podman --version 7 | 8 | stages: 9 | - Static analysis 10 | - Compile 11 | 12 | rustfmt: 13 | stage: Static analysis 14 | script: 15 | - curl -sSf https://sh.rustup.rs | sh -s -- -y 16 | - source $HOME/.cargo/env 17 | - cargo fmt -- --check 18 | 19 | compile: 20 | stage: Compile 21 | script: 22 | - podman build --format docker -t rateway:latest . 23 | - if [ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ] && [ "$DOCKERHUB_USERNAME" != "" ] && [ "$DOCKERHUB_PASSWORD" != "" ]; then 24 | podman login docker.io --username $DOCKERHUB_USERNAME --password $DOCKERHUB_PASSWORD && 25 | podman push rateway:latest docker.io/$DOCKERHUB_USERNAME/rateway:latest; 26 | fi 27 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust.rustflags": "-C link-arg=-fuse-ld=lld -C target-cpu=native", 3 | "python.pythonPath": "/usr/bin/python", 4 | } -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.3.8" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" 10 | 11 | [[package]] 12 | name = "amq-protocol" 13 | version = "6.0.3" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "3c222de30b345b19470d9091414c5bda68cd845c44e8dde2f874373e0b247a54" 16 | dependencies = [ 17 | "amq-protocol-tcp", 18 | "amq-protocol-types", 19 | "amq-protocol-uri", 20 | "cookie-factory", 21 | "nom", 22 | ] 23 | 24 | [[package]] 25 | name = "amq-protocol-tcp" 26 | version = "6.0.3" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "bee3c947a2c5b40b6e506453eeff96998bb2caa2ea616ed028ba1bafbc2b16ce" 29 | dependencies = [ 30 | "amq-protocol-uri", 31 | "tcp-stream", 32 | "tracing", 33 | ] 34 | 35 | [[package]] 36 | name = "amq-protocol-types" 37 | version = "6.0.3" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "d198cde4bde0eadf1a946e4f0d113ff471bf8abe4ef728181d7320461da8a3e4" 40 | dependencies = [ 41 | "cookie-factory", 42 | "nom", 43 | "serde", 44 | "serde_json", 45 | ] 46 | 47 | [[package]] 48 | name = "amq-protocol-uri" 49 | version = "6.0.3" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "9f843ece1f9a66cebbccf4162b5505e96e93598d3b2678ac56ad19d60642bd45" 52 | dependencies = [ 53 | "percent-encoding", 54 | "url", 55 | ] 56 | 57 | [[package]] 58 | name = "arrayvec" 59 | version = "0.5.2" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 62 | 63 | [[package]] 64 | name = "async-task" 65 | version = "4.0.3" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" 68 | 69 | [[package]] 70 | name = "atty" 71 | version = "0.2.14" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 74 | dependencies = [ 75 | "hermit-abi", 76 | "libc", 77 | "winapi", 78 | ] 79 | 80 | [[package]] 81 | name = "autocfg" 82 | version = "1.0.1" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 85 | 86 | [[package]] 87 | name = "base64" 88 | version = "0.13.0" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 91 | 92 | [[package]] 93 | name = "bitflags" 94 | version = "1.2.1" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 97 | 98 | [[package]] 99 | name = "bitvec" 100 | version = "0.19.5" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" 103 | dependencies = [ 104 | "funty", 105 | "radium", 106 | "tap", 107 | "wyz", 108 | ] 109 | 110 | [[package]] 111 | name = "block-buffer" 112 | version = "0.9.0" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 115 | dependencies = [ 116 | "generic-array", 117 | ] 118 | 119 | [[package]] 120 | name = "bumpalo" 121 | version = "3.6.1" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" 124 | 125 | [[package]] 126 | name = "byteorder" 127 | version = "1.4.3" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 130 | 131 | [[package]] 132 | name = "bytes" 133 | version = "1.0.1" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" 136 | 137 | [[package]] 138 | name = "cc" 139 | version = "1.0.67" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" 142 | 143 | [[package]] 144 | name = "cfg-if" 145 | version = "1.0.0" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 148 | 149 | [[package]] 150 | name = "cookie-factory" 151 | version = "0.3.2" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" 154 | 155 | [[package]] 156 | name = "cpuid-bool" 157 | version = "0.1.2" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" 160 | 161 | [[package]] 162 | name = "crossbeam-channel" 163 | version = "0.5.1" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" 166 | dependencies = [ 167 | "cfg-if", 168 | "crossbeam-utils", 169 | ] 170 | 171 | [[package]] 172 | name = "crossbeam-utils" 173 | version = "0.8.3" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" 176 | dependencies = [ 177 | "autocfg", 178 | "cfg-if", 179 | "lazy_static", 180 | ] 181 | 182 | [[package]] 183 | name = "ct-logs" 184 | version = "0.8.0" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" 187 | dependencies = [ 188 | "sct", 189 | ] 190 | 191 | [[package]] 192 | name = "dashmap" 193 | version = "4.0.2" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" 196 | dependencies = [ 197 | "cfg-if", 198 | "num_cpus", 199 | ] 200 | 201 | [[package]] 202 | name = "digest" 203 | version = "0.9.0" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 206 | dependencies = [ 207 | "generic-array", 208 | ] 209 | 210 | [[package]] 211 | name = "doc-comment" 212 | version = "0.3.3" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" 215 | 216 | [[package]] 217 | name = "env_logger" 218 | version = "0.8.3" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" 221 | dependencies = [ 222 | "atty", 223 | "humantime", 224 | "log", 225 | "termcolor", 226 | ] 227 | 228 | [[package]] 229 | name = "float-cmp" 230 | version = "0.8.0" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4" 233 | dependencies = [ 234 | "num-traits", 235 | ] 236 | 237 | [[package]] 238 | name = "fnv" 239 | version = "1.0.7" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 242 | 243 | [[package]] 244 | name = "form_urlencoded" 245 | version = "1.0.1" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 248 | dependencies = [ 249 | "matches", 250 | "percent-encoding", 251 | ] 252 | 253 | [[package]] 254 | name = "funty" 255 | version = "1.1.0" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" 258 | 259 | [[package]] 260 | name = "futures-channel" 261 | version = "0.3.14" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25" 264 | dependencies = [ 265 | "futures-core", 266 | ] 267 | 268 | [[package]] 269 | name = "futures-core" 270 | version = "0.3.14" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815" 273 | 274 | [[package]] 275 | name = "futures-sink" 276 | version = "0.3.14" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23" 279 | 280 | [[package]] 281 | name = "futures-task" 282 | version = "0.3.14" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc" 285 | 286 | [[package]] 287 | name = "futures-util" 288 | version = "0.3.14" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025" 291 | dependencies = [ 292 | "futures-core", 293 | "futures-sink", 294 | "futures-task", 295 | "pin-project-lite", 296 | "pin-utils", 297 | "slab", 298 | ] 299 | 300 | [[package]] 301 | name = "generic-array" 302 | version = "0.14.4" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 305 | dependencies = [ 306 | "typenum", 307 | "version_check", 308 | ] 309 | 310 | [[package]] 311 | name = "getrandom" 312 | version = "0.2.2" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" 315 | dependencies = [ 316 | "cfg-if", 317 | "libc", 318 | "wasi", 319 | ] 320 | 321 | [[package]] 322 | name = "h2" 323 | version = "0.3.2" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "fc018e188373e2777d0ef2467ebff62a08e66c3f5857b23c8fbec3018210dc00" 326 | dependencies = [ 327 | "bytes", 328 | "fnv", 329 | "futures-core", 330 | "futures-sink", 331 | "futures-util", 332 | "http", 333 | "indexmap", 334 | "slab", 335 | "tokio", 336 | "tokio-util", 337 | "tracing", 338 | ] 339 | 340 | [[package]] 341 | name = "halfbrown" 342 | version = "0.1.11" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "c12499524b5585419ab2f51545a19b842263a373580a83c0eb98a0142a260a10" 345 | dependencies = [ 346 | "hashbrown 0.7.2", 347 | "serde", 348 | ] 349 | 350 | [[package]] 351 | name = "hashbrown" 352 | version = "0.7.2" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf" 355 | dependencies = [ 356 | "ahash", 357 | "autocfg", 358 | ] 359 | 360 | [[package]] 361 | name = "hashbrown" 362 | version = "0.9.1" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" 365 | 366 | [[package]] 367 | name = "hermit-abi" 368 | version = "0.1.18" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 371 | dependencies = [ 372 | "libc", 373 | ] 374 | 375 | [[package]] 376 | name = "http" 377 | version = "0.2.4" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" 380 | dependencies = [ 381 | "bytes", 382 | "fnv", 383 | "itoa", 384 | ] 385 | 386 | [[package]] 387 | name = "http-body" 388 | version = "0.4.1" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "5dfb77c123b4e2f72a2069aeae0b4b4949cc7e966df277813fc16347e7549737" 391 | dependencies = [ 392 | "bytes", 393 | "http", 394 | "pin-project-lite", 395 | ] 396 | 397 | [[package]] 398 | name = "httparse" 399 | version = "1.4.0" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "4a1ce40d6fc9764887c2fdc7305c3dcc429ba11ff981c1509416afd5697e4437" 402 | 403 | [[package]] 404 | name = "httpdate" 405 | version = "0.3.2" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" 408 | 409 | [[package]] 410 | name = "humantime" 411 | version = "2.1.0" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 414 | 415 | [[package]] 416 | name = "hyper" 417 | version = "0.14.5" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | checksum = "8bf09f61b52cfcf4c00de50df88ae423d6c02354e385a86341133b5338630ad1" 420 | dependencies = [ 421 | "bytes", 422 | "futures-channel", 423 | "futures-core", 424 | "futures-util", 425 | "h2", 426 | "http", 427 | "http-body", 428 | "httparse", 429 | "httpdate", 430 | "itoa", 431 | "pin-project", 432 | "socket2", 433 | "tokio", 434 | "tower-service", 435 | "tracing", 436 | "want", 437 | ] 438 | 439 | [[package]] 440 | name = "hyper-rustls" 441 | version = "0.22.1" 442 | source = "git+https://github.com/ctz/hyper-rustls#3f16ac4c36d1133883073b7d6eacf8c09339e87f" 443 | dependencies = [ 444 | "ct-logs", 445 | "hyper", 446 | "log", 447 | "rustls", 448 | "tokio", 449 | "tokio-rustls", 450 | "webpki", 451 | "webpki-roots", 452 | ] 453 | 454 | [[package]] 455 | name = "idna" 456 | version = "0.2.3" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 459 | dependencies = [ 460 | "matches", 461 | "unicode-bidi", 462 | "unicode-normalization", 463 | ] 464 | 465 | [[package]] 466 | name = "indexmap" 467 | version = "1.6.2" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" 470 | dependencies = [ 471 | "autocfg", 472 | "hashbrown 0.9.1", 473 | ] 474 | 475 | [[package]] 476 | name = "input_buffer" 477 | version = "0.4.0" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413" 480 | dependencies = [ 481 | "bytes", 482 | ] 483 | 484 | [[package]] 485 | name = "instant" 486 | version = "0.1.9" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" 489 | dependencies = [ 490 | "cfg-if", 491 | ] 492 | 493 | [[package]] 494 | name = "itoa" 495 | version = "0.4.7" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" 498 | 499 | [[package]] 500 | name = "js-sys" 501 | version = "0.3.50" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" 504 | dependencies = [ 505 | "wasm-bindgen", 506 | ] 507 | 508 | [[package]] 509 | name = "lapin" 510 | version = "1.7.0" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "f6633c37ab4f89b855f255d4b8a29a95f92d0ab7724d0b5576d3b6363dea60f7" 513 | dependencies = [ 514 | "amq-protocol", 515 | "async-task", 516 | "crossbeam-channel", 517 | "futures-core", 518 | "log", 519 | "mio", 520 | "parking_lot", 521 | "pinky-swear", 522 | "serde", 523 | ] 524 | 525 | [[package]] 526 | name = "lazy_static" 527 | version = "1.4.0" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 530 | 531 | [[package]] 532 | name = "lexical-core" 533 | version = "0.7.5" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" 536 | dependencies = [ 537 | "arrayvec", 538 | "bitflags", 539 | "cfg-if", 540 | "ryu", 541 | "static_assertions", 542 | ] 543 | 544 | [[package]] 545 | name = "libc" 546 | version = "0.2.93" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" 549 | 550 | [[package]] 551 | name = "lock_api" 552 | version = "0.4.3" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" 555 | dependencies = [ 556 | "scopeguard", 557 | ] 558 | 559 | [[package]] 560 | name = "log" 561 | version = "0.4.14" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 564 | dependencies = [ 565 | "cfg-if", 566 | ] 567 | 568 | [[package]] 569 | name = "matches" 570 | version = "0.1.8" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 573 | 574 | [[package]] 575 | name = "memchr" 576 | version = "2.3.4" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 579 | 580 | [[package]] 581 | name = "mio" 582 | version = "0.7.11" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956" 585 | dependencies = [ 586 | "libc", 587 | "log", 588 | "miow", 589 | "ntapi", 590 | "winapi", 591 | ] 592 | 593 | [[package]] 594 | name = "miow" 595 | version = "0.3.7" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 598 | dependencies = [ 599 | "winapi", 600 | ] 601 | 602 | [[package]] 603 | name = "nom" 604 | version = "6.1.2" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" 607 | dependencies = [ 608 | "bitvec", 609 | "funty", 610 | "lexical-core", 611 | "memchr", 612 | "version_check", 613 | ] 614 | 615 | [[package]] 616 | name = "ntapi" 617 | version = "0.3.6" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 620 | dependencies = [ 621 | "winapi", 622 | ] 623 | 624 | [[package]] 625 | name = "num-traits" 626 | version = "0.2.14" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 629 | dependencies = [ 630 | "autocfg", 631 | ] 632 | 633 | [[package]] 634 | name = "num_cpus" 635 | version = "1.13.0" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 638 | dependencies = [ 639 | "hermit-abi", 640 | "libc", 641 | ] 642 | 643 | [[package]] 644 | name = "once_cell" 645 | version = "1.7.2" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" 648 | 649 | [[package]] 650 | name = "opaque-debug" 651 | version = "0.3.0" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 654 | 655 | [[package]] 656 | name = "ordered-float" 657 | version = "2.1.1" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "766f840da25490628d8e63e529cd21c014f6600c6b8517add12a6fa6167a6218" 660 | dependencies = [ 661 | "num-traits", 662 | ] 663 | 664 | [[package]] 665 | name = "parking_lot" 666 | version = "0.11.1" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" 669 | dependencies = [ 670 | "instant", 671 | "lock_api", 672 | "parking_lot_core", 673 | ] 674 | 675 | [[package]] 676 | name = "parking_lot_core" 677 | version = "0.8.3" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" 680 | dependencies = [ 681 | "cfg-if", 682 | "instant", 683 | "libc", 684 | "redox_syscall", 685 | "smallvec", 686 | "winapi", 687 | ] 688 | 689 | [[package]] 690 | name = "percent-encoding" 691 | version = "2.1.0" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 694 | 695 | [[package]] 696 | name = "pin-project" 697 | version = "1.0.7" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "c7509cc106041c40a4518d2af7a61530e1eed0e6285296a3d8c5472806ccc4a4" 700 | dependencies = [ 701 | "pin-project-internal", 702 | ] 703 | 704 | [[package]] 705 | name = "pin-project-internal" 706 | version = "1.0.7" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "48c950132583b500556b1efd71d45b319029f2b71518d979fcc208e16b42426f" 709 | dependencies = [ 710 | "proc-macro2", 711 | "quote", 712 | "syn", 713 | ] 714 | 715 | [[package]] 716 | name = "pin-project-lite" 717 | version = "0.2.6" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" 720 | 721 | [[package]] 722 | name = "pin-utils" 723 | version = "0.1.0" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 726 | 727 | [[package]] 728 | name = "pinky-swear" 729 | version = "4.4.0" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "9bf8cda6f8e1500338634e4e3ce90ac59eb7929a1e088b6946c742be1cc44dc1" 732 | dependencies = [ 733 | "doc-comment", 734 | "parking_lot", 735 | "tracing", 736 | ] 737 | 738 | [[package]] 739 | name = "ppv-lite86" 740 | version = "0.2.10" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" 743 | 744 | [[package]] 745 | name = "proc-macro2" 746 | version = "1.0.26" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" 749 | dependencies = [ 750 | "unicode-xid", 751 | ] 752 | 753 | [[package]] 754 | name = "quote" 755 | version = "1.0.9" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 758 | dependencies = [ 759 | "proc-macro2", 760 | ] 761 | 762 | [[package]] 763 | name = "radium" 764 | version = "0.5.3" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" 767 | 768 | [[package]] 769 | name = "rand" 770 | version = "0.8.3" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" 773 | dependencies = [ 774 | "libc", 775 | "rand_chacha", 776 | "rand_core", 777 | "rand_hc", 778 | ] 779 | 780 | [[package]] 781 | name = "rand_chacha" 782 | version = "0.3.0" 783 | source = "registry+https://github.com/rust-lang/crates.io-index" 784 | checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" 785 | dependencies = [ 786 | "ppv-lite86", 787 | "rand_core", 788 | ] 789 | 790 | [[package]] 791 | name = "rand_core" 792 | version = "0.6.2" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" 795 | dependencies = [ 796 | "getrandom", 797 | ] 798 | 799 | [[package]] 800 | name = "rand_hc" 801 | version = "0.3.0" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" 804 | dependencies = [ 805 | "rand_core", 806 | ] 807 | 808 | [[package]] 809 | name = "rateway" 810 | version = "0.2.0" 811 | dependencies = [ 812 | "env_logger", 813 | "futures-util", 814 | "lapin", 815 | "log", 816 | "serde", 817 | "simd-json", 818 | "tokio", 819 | "tokio-amqp", 820 | "toml", 821 | "twilight-cache-inmemory", 822 | "twilight-gateway", 823 | "twilight-http", 824 | "twilight-model", 825 | ] 826 | 827 | [[package]] 828 | name = "redox_syscall" 829 | version = "0.2.6" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" 832 | dependencies = [ 833 | "bitflags", 834 | ] 835 | 836 | [[package]] 837 | name = "ring" 838 | version = "0.16.20" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 841 | dependencies = [ 842 | "cc", 843 | "libc", 844 | "once_cell", 845 | "spin", 846 | "untrusted", 847 | "web-sys", 848 | "winapi", 849 | ] 850 | 851 | [[package]] 852 | name = "rustls" 853 | version = "0.19.1" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" 856 | dependencies = [ 857 | "base64", 858 | "log", 859 | "ring", 860 | "sct", 861 | "webpki", 862 | ] 863 | 864 | [[package]] 865 | name = "ryu" 866 | version = "1.0.5" 867 | source = "registry+https://github.com/rust-lang/crates.io-index" 868 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 869 | 870 | [[package]] 871 | name = "scopeguard" 872 | version = "1.1.0" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 875 | 876 | [[package]] 877 | name = "sct" 878 | version = "0.6.1" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" 881 | dependencies = [ 882 | "ring", 883 | "untrusted", 884 | ] 885 | 886 | [[package]] 887 | name = "serde" 888 | version = "1.0.125" 889 | source = "registry+https://github.com/rust-lang/crates.io-index" 890 | checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" 891 | dependencies = [ 892 | "serde_derive", 893 | ] 894 | 895 | [[package]] 896 | name = "serde-value" 897 | version = "0.7.0" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" 900 | dependencies = [ 901 | "ordered-float", 902 | "serde", 903 | ] 904 | 905 | [[package]] 906 | name = "serde_derive" 907 | version = "1.0.125" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" 910 | dependencies = [ 911 | "proc-macro2", 912 | "quote", 913 | "syn", 914 | ] 915 | 916 | [[package]] 917 | name = "serde_json" 918 | version = "1.0.64" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" 921 | dependencies = [ 922 | "itoa", 923 | "ryu", 924 | "serde", 925 | ] 926 | 927 | [[package]] 928 | name = "serde_repr" 929 | version = "0.1.6" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76" 932 | dependencies = [ 933 | "proc-macro2", 934 | "quote", 935 | "syn", 936 | ] 937 | 938 | [[package]] 939 | name = "sha-1" 940 | version = "0.9.4" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" 943 | dependencies = [ 944 | "block-buffer", 945 | "cfg-if", 946 | "cpuid-bool", 947 | "digest", 948 | "opaque-debug", 949 | ] 950 | 951 | [[package]] 952 | name = "simd-json" 953 | version = "0.4.3" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "635678c30cb728c83105ee02f9d9556213815c6c5aa01091523de2d203928e86" 956 | dependencies = [ 957 | "halfbrown", 958 | "serde", 959 | "serde_json", 960 | "value-trait", 961 | ] 962 | 963 | [[package]] 964 | name = "slab" 965 | version = "0.4.2" 966 | source = "registry+https://github.com/rust-lang/crates.io-index" 967 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 968 | 969 | [[package]] 970 | name = "smallvec" 971 | version = "1.6.1" 972 | source = "registry+https://github.com/rust-lang/crates.io-index" 973 | checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" 974 | 975 | [[package]] 976 | name = "socket2" 977 | version = "0.4.0" 978 | source = "registry+https://github.com/rust-lang/crates.io-index" 979 | checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" 980 | dependencies = [ 981 | "libc", 982 | "winapi", 983 | ] 984 | 985 | [[package]] 986 | name = "spin" 987 | version = "0.5.2" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 990 | 991 | [[package]] 992 | name = "static_assertions" 993 | version = "1.1.0" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 996 | 997 | [[package]] 998 | name = "syn" 999 | version = "1.0.69" 1000 | source = "registry+https://github.com/rust-lang/crates.io-index" 1001 | checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb" 1002 | dependencies = [ 1003 | "proc-macro2", 1004 | "quote", 1005 | "unicode-xid", 1006 | ] 1007 | 1008 | [[package]] 1009 | name = "tap" 1010 | version = "1.0.1" 1011 | source = "registry+https://github.com/rust-lang/crates.io-index" 1012 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 1013 | 1014 | [[package]] 1015 | name = "tcp-stream" 1016 | version = "0.20.6" 1017 | source = "registry+https://github.com/rust-lang/crates.io-index" 1018 | checksum = "04c180af0da0f0a75ca080465175892fcdaa750076f125cb953127721e676413" 1019 | dependencies = [ 1020 | "cfg-if", 1021 | "mio", 1022 | ] 1023 | 1024 | [[package]] 1025 | name = "termcolor" 1026 | version = "1.1.2" 1027 | source = "registry+https://github.com/rust-lang/crates.io-index" 1028 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 1029 | dependencies = [ 1030 | "winapi-util", 1031 | ] 1032 | 1033 | [[package]] 1034 | name = "thiserror" 1035 | version = "1.0.24" 1036 | source = "registry+https://github.com/rust-lang/crates.io-index" 1037 | checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" 1038 | dependencies = [ 1039 | "thiserror-impl", 1040 | ] 1041 | 1042 | [[package]] 1043 | name = "thiserror-impl" 1044 | version = "1.0.24" 1045 | source = "registry+https://github.com/rust-lang/crates.io-index" 1046 | checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" 1047 | dependencies = [ 1048 | "proc-macro2", 1049 | "quote", 1050 | "syn", 1051 | ] 1052 | 1053 | [[package]] 1054 | name = "tinyvec" 1055 | version = "1.2.0" 1056 | source = "registry+https://github.com/rust-lang/crates.io-index" 1057 | checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" 1058 | dependencies = [ 1059 | "tinyvec_macros", 1060 | ] 1061 | 1062 | [[package]] 1063 | name = "tinyvec_macros" 1064 | version = "0.1.0" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1067 | 1068 | [[package]] 1069 | name = "tokio" 1070 | version = "1.5.0" 1071 | source = "registry+https://github.com/rust-lang/crates.io-index" 1072 | checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5" 1073 | dependencies = [ 1074 | "autocfg", 1075 | "bytes", 1076 | "libc", 1077 | "memchr", 1078 | "mio", 1079 | "num_cpus", 1080 | "pin-project-lite", 1081 | "tokio-macros", 1082 | ] 1083 | 1084 | [[package]] 1085 | name = "tokio-amqp" 1086 | version = "1.0.0" 1087 | source = "registry+https://github.com/rust-lang/crates.io-index" 1088 | checksum = "4a236324e1e84931e62c22e2ee47688e077aa33a2a95f14d29ab8ec4dbaf9845" 1089 | dependencies = [ 1090 | "lapin", 1091 | "parking_lot", 1092 | "tokio", 1093 | ] 1094 | 1095 | [[package]] 1096 | name = "tokio-macros" 1097 | version = "1.1.0" 1098 | source = "registry+https://github.com/rust-lang/crates.io-index" 1099 | checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" 1100 | dependencies = [ 1101 | "proc-macro2", 1102 | "quote", 1103 | "syn", 1104 | ] 1105 | 1106 | [[package]] 1107 | name = "tokio-rustls" 1108 | version = "0.22.0" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" 1111 | dependencies = [ 1112 | "rustls", 1113 | "tokio", 1114 | "webpki", 1115 | ] 1116 | 1117 | [[package]] 1118 | name = "tokio-tungstenite" 1119 | version = "0.14.0" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | checksum = "1e96bb520beab540ab664bd5a9cfeaa1fcd846fa68c830b42e2c8963071251d2" 1122 | dependencies = [ 1123 | "futures-util", 1124 | "log", 1125 | "pin-project", 1126 | "rustls", 1127 | "tokio", 1128 | "tokio-rustls", 1129 | "tungstenite", 1130 | "webpki", 1131 | "webpki-roots", 1132 | ] 1133 | 1134 | [[package]] 1135 | name = "tokio-util" 1136 | version = "0.6.6" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "940a12c99365c31ea8dd9ba04ec1be183ffe4920102bb7122c2f515437601e8e" 1139 | dependencies = [ 1140 | "bytes", 1141 | "futures-core", 1142 | "futures-sink", 1143 | "log", 1144 | "pin-project-lite", 1145 | "tokio", 1146 | ] 1147 | 1148 | [[package]] 1149 | name = "toml" 1150 | version = "0.5.8" 1151 | source = "registry+https://github.com/rust-lang/crates.io-index" 1152 | checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" 1153 | dependencies = [ 1154 | "serde", 1155 | ] 1156 | 1157 | [[package]] 1158 | name = "tower-service" 1159 | version = "0.3.1" 1160 | source = "registry+https://github.com/rust-lang/crates.io-index" 1161 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" 1162 | 1163 | [[package]] 1164 | name = "tracing" 1165 | version = "0.1.25" 1166 | source = "registry+https://github.com/rust-lang/crates.io-index" 1167 | checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" 1168 | dependencies = [ 1169 | "cfg-if", 1170 | "pin-project-lite", 1171 | "tracing-attributes", 1172 | "tracing-core", 1173 | ] 1174 | 1175 | [[package]] 1176 | name = "tracing-attributes" 1177 | version = "0.1.15" 1178 | source = "registry+https://github.com/rust-lang/crates.io-index" 1179 | checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" 1180 | dependencies = [ 1181 | "proc-macro2", 1182 | "quote", 1183 | "syn", 1184 | ] 1185 | 1186 | [[package]] 1187 | name = "tracing-core" 1188 | version = "0.1.17" 1189 | source = "registry+https://github.com/rust-lang/crates.io-index" 1190 | checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" 1191 | dependencies = [ 1192 | "lazy_static", 1193 | ] 1194 | 1195 | [[package]] 1196 | name = "try-lock" 1197 | version = "0.2.3" 1198 | source = "registry+https://github.com/rust-lang/crates.io-index" 1199 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1200 | 1201 | [[package]] 1202 | name = "tungstenite" 1203 | version = "0.13.0" 1204 | source = "registry+https://github.com/rust-lang/crates.io-index" 1205 | checksum = "5fe8dada8c1a3aeca77d6b51a4f1314e0f4b8e438b7b1b71e3ddaca8080e4093" 1206 | dependencies = [ 1207 | "base64", 1208 | "byteorder", 1209 | "bytes", 1210 | "http", 1211 | "httparse", 1212 | "input_buffer", 1213 | "log", 1214 | "rand", 1215 | "rustls", 1216 | "sha-1", 1217 | "thiserror", 1218 | "url", 1219 | "utf-8", 1220 | "webpki", 1221 | "webpki-roots", 1222 | ] 1223 | 1224 | [[package]] 1225 | name = "twilight-cache-inmemory" 1226 | version = "0.3.5" 1227 | source = "git+https://github.com/Gelbpunkt/twilight?branch=local-changes#c1618f673408ed8596a2ce172a34d42bf1925c44" 1228 | dependencies = [ 1229 | "bitflags", 1230 | "dashmap", 1231 | "serde", 1232 | "tracing", 1233 | "twilight-model", 1234 | ] 1235 | 1236 | [[package]] 1237 | name = "twilight-gateway" 1238 | version = "0.3.4" 1239 | source = "git+https://github.com/Gelbpunkt/twilight?branch=local-changes#c1618f673408ed8596a2ce172a34d42bf1925c44" 1240 | dependencies = [ 1241 | "bitflags", 1242 | "dashmap", 1243 | "futures-util", 1244 | "once_cell", 1245 | "serde", 1246 | "serde_json", 1247 | "simd-json", 1248 | "tokio", 1249 | "tokio-tungstenite", 1250 | "tracing", 1251 | "twilight-gateway-queue", 1252 | "twilight-http", 1253 | "twilight-model", 1254 | "url", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "twilight-gateway-queue" 1259 | version = "0.3.0" 1260 | source = "git+https://github.com/Gelbpunkt/twilight?branch=local-changes#c1618f673408ed8596a2ce172a34d42bf1925c44" 1261 | dependencies = [ 1262 | "tokio", 1263 | "tracing", 1264 | "twilight-http", 1265 | ] 1266 | 1267 | [[package]] 1268 | name = "twilight-http" 1269 | version = "0.3.6" 1270 | source = "git+https://github.com/Gelbpunkt/twilight?branch=local-changes#c1618f673408ed8596a2ce172a34d42bf1925c44" 1271 | dependencies = [ 1272 | "bytes", 1273 | "futures-util", 1274 | "hyper", 1275 | "hyper-rustls", 1276 | "percent-encoding", 1277 | "rand", 1278 | "serde", 1279 | "serde_json", 1280 | "serde_repr", 1281 | "simd-json", 1282 | "tokio", 1283 | "tracing", 1284 | "twilight-model", 1285 | ] 1286 | 1287 | [[package]] 1288 | name = "twilight-model" 1289 | version = "0.3.5" 1290 | source = "git+https://github.com/Gelbpunkt/twilight?branch=local-changes#c1618f673408ed8596a2ce172a34d42bf1925c44" 1291 | dependencies = [ 1292 | "bitflags", 1293 | "serde", 1294 | "serde-value", 1295 | "serde_repr", 1296 | "tracing", 1297 | ] 1298 | 1299 | [[package]] 1300 | name = "typenum" 1301 | version = "1.13.0" 1302 | source = "registry+https://github.com/rust-lang/crates.io-index" 1303 | checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" 1304 | 1305 | [[package]] 1306 | name = "unicode-bidi" 1307 | version = "0.3.5" 1308 | source = "registry+https://github.com/rust-lang/crates.io-index" 1309 | checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" 1310 | dependencies = [ 1311 | "matches", 1312 | ] 1313 | 1314 | [[package]] 1315 | name = "unicode-normalization" 1316 | version = "0.1.17" 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" 1318 | checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" 1319 | dependencies = [ 1320 | "tinyvec", 1321 | ] 1322 | 1323 | [[package]] 1324 | name = "unicode-xid" 1325 | version = "0.2.1" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 1328 | 1329 | [[package]] 1330 | name = "untrusted" 1331 | version = "0.7.1" 1332 | source = "registry+https://github.com/rust-lang/crates.io-index" 1333 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 1334 | 1335 | [[package]] 1336 | name = "url" 1337 | version = "2.2.1" 1338 | source = "registry+https://github.com/rust-lang/crates.io-index" 1339 | checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" 1340 | dependencies = [ 1341 | "form_urlencoded", 1342 | "idna", 1343 | "matches", 1344 | "percent-encoding", 1345 | ] 1346 | 1347 | [[package]] 1348 | name = "utf-8" 1349 | version = "0.7.6" 1350 | source = "registry+https://github.com/rust-lang/crates.io-index" 1351 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1352 | 1353 | [[package]] 1354 | name = "value-trait" 1355 | version = "0.2.4" 1356 | source = "registry+https://github.com/rust-lang/crates.io-index" 1357 | checksum = "6034fb7710bdb0f90669eb6b1ba37a15186872d61926dcf447f92c440a034f9b" 1358 | dependencies = [ 1359 | "float-cmp", 1360 | "halfbrown", 1361 | "itoa", 1362 | "ryu", 1363 | ] 1364 | 1365 | [[package]] 1366 | name = "version_check" 1367 | version = "0.9.3" 1368 | source = "registry+https://github.com/rust-lang/crates.io-index" 1369 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 1370 | 1371 | [[package]] 1372 | name = "want" 1373 | version = "0.3.0" 1374 | source = "registry+https://github.com/rust-lang/crates.io-index" 1375 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1376 | dependencies = [ 1377 | "log", 1378 | "try-lock", 1379 | ] 1380 | 1381 | [[package]] 1382 | name = "wasi" 1383 | version = "0.10.2+wasi-snapshot-preview1" 1384 | source = "registry+https://github.com/rust-lang/crates.io-index" 1385 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 1386 | 1387 | [[package]] 1388 | name = "wasm-bindgen" 1389 | version = "0.2.73" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" 1392 | dependencies = [ 1393 | "cfg-if", 1394 | "wasm-bindgen-macro", 1395 | ] 1396 | 1397 | [[package]] 1398 | name = "wasm-bindgen-backend" 1399 | version = "0.2.73" 1400 | source = "registry+https://github.com/rust-lang/crates.io-index" 1401 | checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" 1402 | dependencies = [ 1403 | "bumpalo", 1404 | "lazy_static", 1405 | "log", 1406 | "proc-macro2", 1407 | "quote", 1408 | "syn", 1409 | "wasm-bindgen-shared", 1410 | ] 1411 | 1412 | [[package]] 1413 | name = "wasm-bindgen-macro" 1414 | version = "0.2.73" 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" 1416 | checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" 1417 | dependencies = [ 1418 | "quote", 1419 | "wasm-bindgen-macro-support", 1420 | ] 1421 | 1422 | [[package]] 1423 | name = "wasm-bindgen-macro-support" 1424 | version = "0.2.73" 1425 | source = "registry+https://github.com/rust-lang/crates.io-index" 1426 | checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" 1427 | dependencies = [ 1428 | "proc-macro2", 1429 | "quote", 1430 | "syn", 1431 | "wasm-bindgen-backend", 1432 | "wasm-bindgen-shared", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "wasm-bindgen-shared" 1437 | version = "0.2.73" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" 1440 | 1441 | [[package]] 1442 | name = "web-sys" 1443 | version = "0.3.50" 1444 | source = "registry+https://github.com/rust-lang/crates.io-index" 1445 | checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" 1446 | dependencies = [ 1447 | "js-sys", 1448 | "wasm-bindgen", 1449 | ] 1450 | 1451 | [[package]] 1452 | name = "webpki" 1453 | version = "0.21.4" 1454 | source = "registry+https://github.com/rust-lang/crates.io-index" 1455 | checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" 1456 | dependencies = [ 1457 | "ring", 1458 | "untrusted", 1459 | ] 1460 | 1461 | [[package]] 1462 | name = "webpki-roots" 1463 | version = "0.21.1" 1464 | source = "registry+https://github.com/rust-lang/crates.io-index" 1465 | checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" 1466 | dependencies = [ 1467 | "webpki", 1468 | ] 1469 | 1470 | [[package]] 1471 | name = "winapi" 1472 | version = "0.3.9" 1473 | source = "registry+https://github.com/rust-lang/crates.io-index" 1474 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1475 | dependencies = [ 1476 | "winapi-i686-pc-windows-gnu", 1477 | "winapi-x86_64-pc-windows-gnu", 1478 | ] 1479 | 1480 | [[package]] 1481 | name = "winapi-i686-pc-windows-gnu" 1482 | version = "0.4.0" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1485 | 1486 | [[package]] 1487 | name = "winapi-util" 1488 | version = "0.1.5" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1491 | dependencies = [ 1492 | "winapi", 1493 | ] 1494 | 1495 | [[package]] 1496 | name = "winapi-x86_64-pc-windows-gnu" 1497 | version = "0.4.0" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1500 | 1501 | [[package]] 1502 | name = "wyz" 1503 | version = "0.2.0" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" 1506 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rateway" 3 | version = "0.2.0" 4 | authors = ["Jens Reidel "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | [dependencies] 9 | twilight-gateway = { git = "https://github.com/Gelbpunkt/twilight", branch = "local-changes", default-features = false, features = [ 10 | "rustls-webpki-roots", 11 | "simd-json", 12 | ] } 13 | twilight-model = { git = "https://github.com/Gelbpunkt/twilight", branch = "local-changes" } 14 | twilight-http = { git = "https://github.com/Gelbpunkt/twilight", branch = "local-changes", default-features = false, features = [ 15 | "rustls-webpki-roots", 16 | "simd-json" 17 | ] } 18 | twilight-cache-inmemory = { git = "https://github.com/Gelbpunkt/twilight", branch = "local-changes" } 19 | tokio-amqp = { version = "1.0", default-features = false } 20 | lapin = { version = "1.7", default-features = false } 21 | tokio = { version = "1", default-features = false, features = ["macros", "rt-multi-thread"] } 22 | futures-util = { version = "0.3", default-features = false } 23 | serde = { version = "1", features = ["derive", "rc"] } 24 | toml = "0.5" 25 | simd-json = { version = "0.4", default-features = false, features = [ 26 | "serde_impl", 27 | "swar-number-parsing" 28 | ] } 29 | env_logger = { version = "0.8", default-features = false, features = ["termcolor", "atty", "humantime"] } 30 | log = "0.4" 31 | 32 | [patch.crates-io] 33 | hyper-rustls = { git = "https://github.com/ctz/hyper-rustls" } 34 | 35 | [profile.release] 36 | codegen-units = 1 37 | debug = false 38 | incremental = false 39 | lto = true 40 | opt-level = 3 41 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/library/alpine:edge AS builder 2 | 3 | RUN apk add --no-cache curl clang gcc musl-dev lld make && \ 4 | curl -sSf https://sh.rustup.rs | sh -s -- --profile minimal --default-toolchain nightly -y 5 | 6 | ENV CC clang 7 | ENV CFLAGS "-I/usr/lib/gcc/x86_64-alpine-linux-musl/10.2.1/ -L/usr/lib/gcc/x86_64-alpine-linux-musl/10.2.1/" 8 | 9 | RUN rm /usr/bin/ld && \ 10 | rm /usr/bin/cc && \ 11 | ln -s /usr/bin/lld /usr/bin/ld && \ 12 | ln -s /usr/bin/clang /usr/bin/cc && \ 13 | ln -s /usr/lib/gcc/x86_64-alpine-linux-musl/10.2.1/crtbeginS.o /usr/lib/crtbeginS.o && \ 14 | ln -s /usr/lib/gcc/x86_64-alpine-linux-musl/10.2.1/crtendS.o /usr/lib/crtendS.o 15 | 16 | WORKDIR /build 17 | 18 | COPY ./Cargo.lock ./Cargo.lock 19 | COPY ./Cargo.toml ./Cargo.toml 20 | COPY ./.cargo ./.cargo 21 | 22 | RUN mkdir src/ 23 | RUN echo 'fn main() {}' > ./src/main.rs 24 | RUN source $HOME/.cargo/env && \ 25 | cargo build --release 26 | 27 | RUN rm -f target/release/deps/rateway* 28 | 29 | COPY ./src ./src 30 | 31 | RUN source $HOME/.cargo/env && \ 32 | cargo build --release && \ 33 | strip /build/target/release/rateway 34 | 35 | FROM docker.io/library/alpine:edge AS dumb-init 36 | 37 | RUN apk update && \ 38 | VERSION=$(apk search dumb-init) && \ 39 | mkdir out && \ 40 | cd out && \ 41 | echo "Downloading from https://dl-cdn.alpinelinux.org/alpine/edge/community/x86_64/$VERSION.apk" && \ 42 | wget "https://dl-cdn.alpinelinux.org/alpine/edge/community/x86_64/$VERSION.apk" -O dumb-init.apk && \ 43 | tar xf dumb-init.apk && \ 44 | mv usr/bin/dumb-init /dumb-init 45 | 46 | FROM scratch 47 | 48 | COPY --from=dumb-init /dumb-init /dumb-init 49 | COPY --from=builder /build/target/release/rateway /rateway 50 | 51 | ENTRYPOINT ["./dumb-init", "--"] 52 | CMD ["./rateway"] 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | rateway 633 | Copyright (C) 2020 Kenvyra 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rateway 2 | 3 | A stateful gateway for Discord Bots, especially with Travitia in mind. 4 | 5 | Scaling well, it processes messages from the Discord gateway and puts them in AMQP exchanges. 6 | 7 | ## Why yet another one? 8 | 9 | I am aware that there are projects like [spectacles](https://github.com/spec-tacles/) which try to solve this easily. rateway tries to solve a lot of the issues we had when trying to move an existing bot codebase to a seperate gateway. 10 | 11 | - rateway is highly multi-threaded (parallelism) and concurrent (asynchronous) 12 | - rateway is written in Rust and therefore safe, performant and well-optimized 13 | - rateway keeps events grouped per cluster, where each gateway cluster should equal one worker on your client side. This allows for not worrying about your REACTION_ADD events arriving on a different worker while you're paginating a help menu 14 | - rateway keeps a shared cache, so you don't have to. Querying it can be done via AMQP 15 | 16 | ## Docker Image 17 | 18 | Can be found [here](https://hub.docker.com/r/gelbpunkt/rateway). 19 | 20 | ## Documentation 21 | 22 | Please check [the user guide](USER_GUIDE.md) on specifics how to implement a client for rateway. 23 | 24 | ## Configuration 25 | 26 | Configuration is preferably done in enviroment variables, alternatively, a config file can be passed with `rateway /path/to/rateway.toml`. 27 | 28 | ### Enviroment Variables 29 | 30 | `DISCORD_TOKEN` (**required**): Bot Token 31 | 32 | `INTENTS` (**required**): Intents value ([from here](https://ziad87.net/intents/)) 33 | 34 | `AMQP_URI` (**required**): AMQP URI to push events to 35 | 36 | `SHARDS_PER_CLUSTER` (optional, defaults to 8): Shards per cluster 37 | 38 | `EXTRA_SHARDS` (optional, defaults to 8): Extra shards to spawn for reserve 39 | 40 | `CACHE_ENABLED` (optional, defaults to true): Toggle caching in rateway 41 | 42 | ### Configuration File 43 | 44 | ```toml 45 | token = "token" 46 | intents = 19553 47 | amqp = "amqp://guest:guest@localhost" 48 | cache_enabled = true 49 | 50 | [shards] 51 | per_cluster = 8 52 | extra = 8 53 | ``` 54 | 55 | ## Scalability and Performance 56 | 57 | rateway utilizes [simd-json](https://github.com/simd-lite/simd-json) and [zlib-ng](https://github.com/zlib-ng/zlib-ng) for extremely fast gateway parsing. It supports gateway intents and queues connections over the gateway and its HTTP calls properly, making it practically impossible to hit ratelimits. 58 | 59 | rateway puts shards into clusters and spawns a new task for each. Tasks are accelerated in threads across all CPU cores based on their load, using the work-stealing concept. This makes it highly efficient and very scalable, across high and low core count CPUs alike. 60 | -------------------------------------------------------------------------------- /USER_GUIDE.md: -------------------------------------------------------------------------------- 1 | # User Guide to using rateway 2 | 3 | This aims to explain how to implement a client library for rateway properly. It is subject to change as rateway reaches a 1.0.0 release, after that we will aim to be backwards compatible. 4 | 5 | ## AMQP Connections 6 | 7 | As rateway exposes its entire API over AMQP, it is important to notice that you will need to connect to an AMQP server just like you connect rateway. 8 | 9 | rateway uses a worker concept, which means that you will have to identify each of your workers with a specific ID that equals a number (hereby called _i_) from 1 to _n_, where _n_ is the number of rateway clusters, which itself is _(total_shard_count + extra_shards) / shards_per_cluster_ as specified in the configuration. We recommend the extra shards to be able to spawn extra workers in advance. 10 | 11 | Each worker then should connect to the AMQP exchange created by rateway called rateway-_i_. 12 | 13 | ## Receiving gateway events 14 | 15 | Normal gateway events that you subscribed to with intents from rateway will be sent with a routing key of _DISCORD_EVENT_NAME_, please refer [to Discord's docs](https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-events) for the specifics (rateway uses the **gateway v8**). The content of the message will be the according payload JSON. 16 | 17 | To implement reading a consumer, you could do: 18 | 19 | - Connect to AMQP 20 | - Declare the rateway-_i_ exchange 21 | - Declare a queue for your worker 22 | - Bind all the events you want (e.g. `MESSAGE_CREATE`) to the queue 23 | - Loop the queue receiving and dispatch your events 24 | 25 | ## Sending gateway commands 26 | 27 | To send commands to the gateway, you can send a message to the rateway-_i_ exchange. The routing key **must** be `gateway` and it expects a header in the message called `shard_id` (an integer) that equals the shard to send a command to. The message body should be JSON and will be forwarded to Discord, refer [to their Documentation for the JSON format](https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-commands). 28 | 29 | ## Querying the cache 30 | 31 | rateway will keep a cache of all entities except messages by default to make seamless worker restarts without wiping cache possible. 32 | Querying it can be done via AMQP as well. 33 | 34 | Right now, querying can only be done via IDs (which are required to be integers). To query an entity cache by ID, send a message to the exchange with the routing key `cache` and a JSON body of the following format: 35 | 36 | ```json 37 | { 38 | "type": "EntityType", 39 | "arguments": [0123456789], 40 | "return_routing_key": "abcdef" 41 | } 42 | ``` 43 | 44 | The arguments should be an array of IDs with 1 or 2 members, the order and amount expected following below in brackets. 45 | 46 | All supported entities are: 47 | 48 | - CurrentUser (No arguments, empty array) 49 | - GuildChannel (ChannelID) 50 | - Emoji (EmojiID) 51 | - Group (GroupID) 52 | - Guild (GuildID) 53 | - Member (GuildID, UserID) 54 | - Message (ChannelID, MessageID) 55 | - Presence (GuildID, UserID) 56 | - PrivateChannel (ChannelID) 57 | - Role (RoleID) 58 | - User (UserID) 59 | - VoiceChannelStates (ChannelID) 60 | - VoiceState (UserID, ChannelID) 61 | 62 | The resulting object will be sent in JSON with the routing key **as specified in the request payload**. 63 | 64 | For example, `{"type": "Guild", "arguments": [430017996304678923], "return_routing_key": "guild-430017996304678923"}` will send the JSON data of the guild with the ID 430017996304678923 over the exchange with the routing key `guild-430017996304678923`. 65 | -------------------------------------------------------------------------------- /client_example/consumer.py: -------------------------------------------------------------------------------- 1 | """ 2 | To run this example, fire up rateway and execute it. 3 | This will listen to the events specified and print them to stdout 4 | """ 5 | import asyncio 6 | 7 | import aio_pika 8 | 9 | # Anything you like and need 10 | LIST_OF_EVENTS_WE_WANT_TO_GET = ["MESSAGE_CREATE", "REACTION_ADD"] 11 | 12 | 13 | async def main(): 14 | # Connect to the AMQP server. Change this to your username and password 15 | connection = await aio_pika.connect_robust("amqp://guest:guest@127.0.0.1/") 16 | 17 | # This will close the connection when leaving the context manager 18 | async with connection: 19 | # Every connection has a channel that we use to perform operations 20 | channel = await connection.channel() 21 | 22 | # Declare the rateway exchange that we will connect to 23 | # This is worker 1 so we use rateway-1 24 | # 25 | # Ignore the parameters, those are the ones used by rateway internally 26 | # Anything else would error 27 | exchange = await channel.declare_exchange( 28 | "rateway-1", 29 | type="direct", 30 | auto_delete=False, 31 | durable=True, 32 | ) 33 | 34 | # Declare a queue to send all the events that we want in 35 | queue = await channel.declare_queue( 36 | "consumer-dispatch", 37 | auto_delete=False, 38 | ) 39 | # Put all events with the events we want to get in the queue from the exchange 40 | for event in LIST_OF_EVENTS_WE_WANT_TO_GET: 41 | await queue.bind(exchange, event) 42 | 43 | # Iterate over all incoming messages in the queue 44 | # that means all events 45 | async with queue.iterator() as queue_iter: 46 | async for message in queue_iter: 47 | async with message.process(): 48 | # message.routing_key is the event name, e.g. MESSAGE_CREATE 49 | # message.body is the raw JSON from Discord 50 | print(message.routing_key.upper(), message.body) 51 | 52 | 53 | if __name__ == "__main__": 54 | asyncio.run(main()) 55 | -------------------------------------------------------------------------------- /client_example/request_cache.py: -------------------------------------------------------------------------------- 1 | """ 2 | To run this example, fire up rateway and execute it. 3 | This will send a request to get a guild entity from cache 4 | and listen for the reply 5 | """ 6 | import asyncio 7 | 8 | import aio_pika 9 | 10 | 11 | async def main(): 12 | # Connect to the AMQP server. Change this to your username and password 13 | connection = await aio_pika.connect_robust("amqp://guest:guest@127.0.0.1/") 14 | 15 | # This will close the connection when leaving the context manager 16 | async with connection: 17 | # Every connection has a channel that we use to perform operations 18 | channel = await connection.channel() 19 | 20 | # Declare the rateway exchange that we will connect to 21 | # This is worker 1 so we use rateway-1 22 | # 23 | # Ignore the parameters, those are the ones used by rateway internally 24 | # Anything else would error 25 | exchange = await channel.declare_exchange( 26 | "rateway-1", 27 | type="direct", 28 | auto_delete=False, 29 | durable=True, 30 | ) 31 | 32 | # Declare a queue to send all the events that we want in 33 | # In this case, we would ideally make one queue for all cache stuff 34 | # and bind to it when we wait for a reply 35 | queue = await channel.declare_queue( 36 | "consumer-queue", 37 | auto_delete=False, 38 | ) 39 | # Make the queue listen to the returned value 40 | await queue.bind(exchange, "guild-430017996304678923") 41 | 42 | # Send a request for a cache entity to rateway 43 | # return_routing_key is the same that we bind to in the line above 44 | await exchange.publish( 45 | aio_pika.Message( 46 | b'{"type": "Guild", "arguments": [430017996304678923], "return_routing_key": "guild-430017996304678923"}' 47 | ), 48 | routing_key="cache", 49 | ) 50 | 51 | # Iterate over all incoming messages in the cache queue 52 | async with queue.iterator() as queue_iter: 53 | async for message in queue_iter: 54 | async with message.process(): 55 | # the message.body will be the discord entity 56 | print(message.routing_key.upper(), message.body) 57 | # we only listen to one so stop here 58 | break 59 | 60 | 61 | if __name__ == "__main__": 62 | asyncio.run(main()) 63 | -------------------------------------------------------------------------------- /client_example/update_presence.py: -------------------------------------------------------------------------------- 1 | """ 2 | To run this example, fire up rateway and execute it. 3 | This will send a payload to Discord via rateway 4 | Here, we change the playing status of the bot 5 | """ 6 | import asyncio 7 | 8 | import aio_pika 9 | 10 | # The payload used by Discord to change a playing status for a bot. 11 | # Here it's "Playing rawr" 12 | PAYLOAD = b'{"d":{"afk":false,"activities":[{"type":0,"name":"rawr"}],"since":null,"status":"online"},"op":3}' 13 | 14 | 15 | async def main(): 16 | # Connect to the AMQP server. Change this to your username and password 17 | connection = await aio_pika.connect_robust("amqp://guest:guest@127.0.0.1/") 18 | 19 | # This will close the connection when leaving the context manager 20 | async with connection: 21 | # Every connection has a channel that we use to perform operations 22 | channel = await connection.channel() 23 | 24 | # Declare the rateway exchange that we will connect to 25 | # This is worker 1 so we use rateway-1 26 | # 27 | # Ignore the parameters, those are the ones used by rateway internally 28 | # Anything else would error 29 | exchange = await channel.declare_exchange( 30 | "rateway-1", 31 | type="direct", 32 | auto_delete=False, 33 | durable=True, 34 | ) 35 | 36 | # Send a request to rateway 37 | # to relay this payload to Discord 38 | # via the shard 0 39 | await exchange.publish( 40 | aio_pika.Message(PAYLOAD, headers={"shard_id": 0}), 41 | routing_key="gateway", 42 | ) 43 | 44 | 45 | if __name__ == "__main__": 46 | asyncio.run(main()) 47 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | imports_granularity = "crate" 2 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | use std::fs; 3 | use toml::from_str; 4 | 5 | #[derive(Debug, Deserialize)] 6 | pub struct Config { 7 | pub token: String, 8 | pub amqp: String, 9 | pub intents: u64, 10 | pub cache_enabled: bool, 11 | pub message_cache_size: usize, 12 | pub shards: ConfigShards, 13 | } 14 | 15 | #[derive(Debug, Deserialize)] 16 | pub struct ConfigShards { 17 | pub per_cluster: usize, 18 | pub extra: u64, 19 | } 20 | 21 | pub fn load_config(p: String) -> Config { 22 | let file = fs::read_to_string(p).unwrap(); 23 | let config: Config = from_str(&file).unwrap(); 24 | config 25 | } 26 | 27 | pub fn load_env() -> Config { 28 | let token = std::env::var("DISCORD_TOKEN").expect("DISCORD_TOKEN not set"); 29 | let intents: u64 = std::env::var("INTENTS") 30 | .expect("INTENTS not set") 31 | .parse() 32 | .expect("Cannot parse intents"); 33 | let per_cluster: usize = std::env::var("SHARDS_PER_CLUSTER") 34 | .unwrap_or_else(|_| String::from("8")) 35 | .parse() 36 | .expect("Cannot parse shards per cluster"); 37 | let extra: u64 = std::env::var("EXTRA_SHARDS") 38 | .unwrap_or_else(|_| String::from("8")) 39 | .parse() 40 | .expect("Cannot parse extra shards"); 41 | let amqp = std::env::var("AMQP_URI").expect("AMQP_URI not set"); 42 | let cache_enabled: bool = std::env::var("CACHE_ENABLED") 43 | .unwrap_or_else(|_| String::from("true")) 44 | .parse() 45 | .expect("Cannot parse cache enabled"); 46 | let message_cache_size: usize = std::env::var("MESSAGE_CACHE_SIZE") 47 | .unwrap_or_else(|_| String::from("0")) 48 | .parse() 49 | .expect("Cannot parse message cache size"); 50 | Config { 51 | token, 52 | amqp, 53 | intents, 54 | cache_enabled, 55 | message_cache_size, 56 | shards: ConfigShards { per_cluster, extra }, 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use twilight_cache_inmemory::InMemoryCacheBuilder; 2 | use twilight_gateway::{ 3 | cluster::ShardScheme, 4 | queue::{LargeBotQueue, Queue}, 5 | }; 6 | use twilight_http::Client; 7 | use twilight_model::gateway::Intents; 8 | 9 | use log::info; 10 | use tokio::task::{spawn, JoinHandle}; 11 | 12 | use std::{ 13 | convert::{TryFrom, TryInto}, 14 | env, 15 | error::Error, 16 | iter::Iterator, 17 | sync::Arc, 18 | }; 19 | 20 | mod config; 21 | mod model; 22 | mod reader; 23 | mod worker; 24 | 25 | #[tokio::main] 26 | async fn main() -> Result<(), Box> { 27 | env::set_var("RUST_LOG", "info"); 28 | env_logger::init(); 29 | 30 | // Try to read config file from CLI, else use env 31 | let mut args = std::env::args(); 32 | let config = match args.nth(1) { 33 | Some(file) => config::load_config(file), 34 | None => config::load_env(), 35 | }; 36 | 37 | // Set up a HTTPClient 38 | let client = Client::new(config.token.clone()); 39 | 40 | // Check total shards required 41 | let gateway = client 42 | .gateway() 43 | .authed() 44 | .await 45 | .expect("Cannot fetch shard information"); 46 | 47 | // Set up a cache 48 | let cache = InMemoryCacheBuilder::new() 49 | .message_cache_size(config.message_cache_size) 50 | .build(); 51 | 52 | let total_shards = gateway.shards + config.shards.extra; 53 | 54 | let intents = Intents::from_bits_truncate(config.intents); 55 | 56 | // Set up a queue for syncing the auth 57 | // This uses the max_concurrency from the gateway automatically 58 | let queue: Arc> = Arc::new(Box::new( 59 | LargeBotQueue::new( 60 | gateway 61 | .session_start_limit 62 | .max_concurrency 63 | .try_into() 64 | .unwrap(), 65 | &client, 66 | ) 67 | .await, 68 | )); 69 | 70 | info!("Starting up rateway with {} shards", total_shards); 71 | info!("Intents: {:?}", intents); 72 | 73 | let mut all_handles: Vec> = Vec::new(); 74 | 75 | // Spawn a thread for each cluster 76 | // Tokio will use a new thread due to rt-threaded 77 | for (idx, shard_range) in (0..total_shards) 78 | .collect::>() 79 | .chunks(config.shards.per_cluster) 80 | .enumerate() 81 | { 82 | let shard_start = shard_range[0]; 83 | let shard_end = shard_range[shard_range.len() - 1]; 84 | let new_queue = queue.clone(); 85 | let new_cache = cache.clone(); 86 | let new_client = client.clone(); 87 | let new_token = config.token.clone(); 88 | let new_amqp_uri = config.amqp.clone(); 89 | let cache_enabled = config.cache_enabled; 90 | let scheme = ShardScheme::try_from((shard_start..=shard_end, total_shards))?; 91 | 92 | let worker_config = worker::WorkerConfig { 93 | amqp_uri: new_amqp_uri, 94 | cache: new_cache, 95 | cluster_id: idx + 1, 96 | http_client: new_client, 97 | intents, 98 | queue: new_queue, 99 | scheme, 100 | token: &new_token, 101 | cache_enabled, 102 | }; 103 | 104 | let worker = worker_config.build().await?; 105 | worker.initialize().await?; 106 | 107 | let handle = spawn(async move { 108 | worker.run().await.unwrap(); 109 | }); 110 | 111 | all_handles.push(handle); 112 | 113 | info!( 114 | "Spawned cluster #{} (shards {}-{})", 115 | idx + 1, 116 | shard_start, 117 | shard_end 118 | ); 119 | } 120 | 121 | for handle in all_handles { 122 | handle.await.expect("Task failed"); 123 | } 124 | 125 | Ok(()) 126 | } 127 | -------------------------------------------------------------------------------- /src/model.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | 3 | #[derive(Deserialize, Debug)] 4 | pub enum CacheEntity { 5 | CurrentUser, 6 | GuildChannel, 7 | Emoji, 8 | Group, 9 | Guild, 10 | Member, 11 | Message, 12 | Presence, 13 | PrivateChannel, 14 | Role, 15 | User, 16 | VoiceChannelStates, 17 | VoiceState, 18 | } 19 | 20 | #[derive(Deserialize, Debug)] 21 | pub struct CacheRequest { 22 | pub r#type: CacheEntity, 23 | pub arguments: Vec, 24 | pub return_routing_key: String, 25 | } 26 | -------------------------------------------------------------------------------- /src/reader.rs: -------------------------------------------------------------------------------- 1 | use crate::model::{CacheEntity, CacheRequest}; 2 | use futures_util::StreamExt; 3 | use lapin::{ 4 | options::{BasicAckOptions, BasicPublishOptions}, 5 | types::AMQPValue, 6 | BasicProperties, Channel, Consumer, Error, 7 | }; 8 | use log::error; 9 | use serde::Serialize; 10 | use simd_json::{from_slice, to_vec}; 11 | use twilight_cache_inmemory::InMemoryCache; 12 | use twilight_gateway::{shard::raw_message::Message, Cluster}; 13 | 14 | fn serialize_item(item: T) -> Option> { 15 | to_vec(&item).ok() 16 | } 17 | 18 | pub async fn amqp_reader( 19 | cluster_id: usize, 20 | mut consumer: Consumer, 21 | amqp_channel: Channel, 22 | cluster: Cluster, 23 | cache: InMemoryCache, 24 | ) -> Result<(), Error> { 25 | let exchange_name = format!("rateway-{}", cluster_id); 26 | while let Some(delivery) = consumer.next().await { 27 | let (channel, mut delivery) = delivery.expect("error in consumer"); 28 | channel 29 | .basic_ack(delivery.delivery_tag, BasicAckOptions::default()) 30 | .await?; 31 | match delivery.routing_key.as_str() { 32 | "cache" => { 33 | let data = match from_slice::(&mut delivery.data) { 34 | Ok(d) => d, 35 | Err(e) => { 36 | error!("Error deserializing cache request: {}", e); 37 | continue; 38 | } 39 | }; 40 | // Rust can be annoying 41 | let send_data = match data.r#type { 42 | CacheEntity::CurrentUser => cache.current_user().and_then(serialize_item), 43 | CacheEntity::GuildChannel => cache 44 | .guild_channel(data.arguments[0].into()) 45 | .and_then(serialize_item), 46 | CacheEntity::Emoji => cache 47 | .emoji(data.arguments[0].into()) 48 | .and_then(serialize_item), 49 | CacheEntity::Group => cache 50 | .group(data.arguments[0].into()) 51 | .and_then(serialize_item), 52 | CacheEntity::Guild => cache 53 | .guild(data.arguments[0].into()) 54 | .and_then(serialize_item), 55 | CacheEntity::Member => cache 56 | .member(data.arguments[0].into(), data.arguments[1].into()) 57 | .and_then(serialize_item), 58 | CacheEntity::Message => cache 59 | .message(data.arguments[0].into(), data.arguments[1].into()) 60 | .and_then(serialize_item), 61 | CacheEntity::Presence => cache 62 | .presence(data.arguments[0].into(), data.arguments[1].into()) 63 | .and_then(serialize_item), 64 | CacheEntity::PrivateChannel => cache 65 | .private_channel(data.arguments[0].into()) 66 | .and_then(serialize_item), 67 | CacheEntity::Role => cache 68 | .role(data.arguments[0].into()) 69 | .and_then(serialize_item), 70 | CacheEntity::User => cache 71 | .user(data.arguments[0].into()) 72 | .and_then(serialize_item), 73 | CacheEntity::VoiceChannelStates => cache 74 | .voice_channel_states(data.arguments[0].into()) 75 | .and_then(serialize_item), 76 | CacheEntity::VoiceState => cache 77 | .voice_state(data.arguments[0].into(), data.arguments[1].into()) 78 | .and_then(serialize_item), 79 | }; 80 | amqp_channel 81 | .basic_publish( 82 | &exchange_name, 83 | &data.return_routing_key, 84 | BasicPublishOptions::default(), 85 | send_data.unwrap_or_default(), 86 | BasicProperties::default(), 87 | ) 88 | .await?; 89 | } 90 | "gateway" => { 91 | if let Some(headers) = delivery.properties.headers() { 92 | if let Some(shard_id) = headers.inner().get("shard_id") { 93 | // Sometimes Rust sucks 94 | let actual_id = match shard_id { 95 | AMQPValue::LongInt(val) => *val as u64, 96 | AMQPValue::LongLongInt(val) => *val as u64, 97 | AMQPValue::LongUInt(val) => *val as u64, 98 | AMQPValue::ShortInt(val) => *val as u64, 99 | AMQPValue::ShortShortInt(val) => *val as u64, 100 | AMQPValue::ShortShortUInt(val) => *val as u64, 101 | AMQPValue::ShortUInt(val) => *val as u64, 102 | _ => continue, 103 | }; 104 | if let Err(e) = cluster 105 | .send(actual_id, Message::Binary(delivery.data)) 106 | .await 107 | { 108 | error!("Error sending gateway command: {}", e); 109 | }; 110 | } 111 | } 112 | } 113 | _ => continue, 114 | }; 115 | } 116 | 117 | Ok(()) 118 | } 119 | -------------------------------------------------------------------------------- /src/worker.rs: -------------------------------------------------------------------------------- 1 | use crate::reader::amqp_reader; 2 | use twilight_cache_inmemory::InMemoryCache; 3 | use twilight_gateway::{ 4 | cluster::{Cluster, ShardScheme}, 5 | queue::Queue, 6 | }; 7 | use twilight_http::Client; 8 | use twilight_model::gateway::{event::DispatchEvent, Intents}; 9 | 10 | use futures_util::StreamExt; 11 | use lapin::{ 12 | options::{ 13 | BasicConsumeOptions, BasicPublishOptions, ExchangeDeclareOptions, QueueBindOptions, 14 | QueueDeclareOptions, 15 | }, 16 | types::FieldTable, 17 | BasicProperties, Channel, Connection, ConnectionProperties, ExchangeKind, 18 | }; 19 | use simd_json::to_vec; 20 | use tokio::spawn; 21 | use tokio_amqp::LapinTokioExt; 22 | 23 | use std::{convert::TryFrom, error::Error, sync::Arc}; 24 | 25 | pub struct WorkerConfig<'a> { 26 | pub token: &'a str, 27 | pub http_client: Client, 28 | pub queue: Arc>, 29 | pub cache: InMemoryCache, 30 | pub intents: Intents, 31 | pub scheme: ShardScheme, 32 | pub cluster_id: usize, 33 | pub amqp_uri: String, 34 | pub cache_enabled: bool, 35 | } 36 | 37 | impl WorkerConfig<'_> { 38 | pub async fn build(self) -> Result> { 39 | let cluster = Cluster::builder(self.token, self.intents) 40 | .shard_scheme(self.scheme) 41 | .http_client(self.http_client) 42 | .queue(self.queue) 43 | .build() 44 | .await?; 45 | 46 | let amqp_conn = 47 | Connection::connect(&self.amqp_uri, ConnectionProperties::default().with_tokio()) 48 | .await?; 49 | let send_channel = amqp_conn.create_channel().await?; 50 | 51 | Ok(Worker { 52 | amqp_channel: send_channel, 53 | cluster, 54 | cache: self.cache, 55 | cluster_id: self.cluster_id, 56 | cache_enabled: self.cache_enabled, 57 | }) 58 | } 59 | } 60 | 61 | pub struct Worker { 62 | amqp_channel: Channel, 63 | cluster: Cluster, 64 | cache: InMemoryCache, 65 | cluster_id: usize, 66 | cache_enabled: bool, 67 | } 68 | 69 | impl Worker { 70 | pub async fn initialize(&self) -> Result<(), Box> { 71 | let exchange_name = format!("rateway-{}", self.cluster_id); 72 | let incoming_queue = format!("rateway-incoming-{}", self.cluster_id); 73 | self.amqp_channel 74 | .exchange_declare( 75 | &exchange_name, 76 | ExchangeKind::Direct, 77 | ExchangeDeclareOptions { 78 | passive: false, 79 | durable: true, 80 | auto_delete: false, 81 | internal: false, 82 | nowait: false, 83 | }, 84 | FieldTable::default(), 85 | ) 86 | .await?; 87 | self.amqp_channel 88 | .queue_declare( 89 | &incoming_queue, 90 | QueueDeclareOptions::default(), 91 | FieldTable::default(), 92 | ) 93 | .await?; 94 | self.amqp_channel 95 | .queue_bind( 96 | &incoming_queue, 97 | &exchange_name, 98 | "cache", 99 | QueueBindOptions::default(), 100 | FieldTable::default(), 101 | ) 102 | .await?; 103 | self.amqp_channel 104 | .queue_bind( 105 | &incoming_queue, 106 | &exchange_name, 107 | "gateway", 108 | QueueBindOptions::default(), 109 | FieldTable::default(), 110 | ) 111 | .await?; 112 | Ok(()) 113 | } 114 | 115 | pub async fn run(&self) -> Result<(), Box> { 116 | let exchange_name = format!("rateway-{}", self.cluster_id); 117 | let incoming_queue = format!("rateway-incoming-{}", self.cluster_id); 118 | let mut events = self.cluster.events(); 119 | 120 | let cluster_spawn = self.cluster.clone(); 121 | let cluster_amqp = self.cluster.clone(); 122 | let cluster_cache = self.cache.clone(); 123 | let cluster_channel = self.amqp_channel.clone(); 124 | 125 | spawn(async move { 126 | cluster_spawn.up().await; 127 | }); 128 | 129 | let consumer = self 130 | .amqp_channel 131 | .basic_consume( 132 | &incoming_queue, 133 | "read-task", 134 | BasicConsumeOptions::default(), 135 | FieldTable::default(), 136 | ) 137 | .await?; 138 | spawn(amqp_reader( 139 | self.cluster_id, 140 | consumer, 141 | cluster_channel, 142 | cluster_amqp, 143 | cluster_cache, 144 | )); 145 | 146 | while let Some((_, event)) = events.next().await { 147 | if self.cache_enabled { 148 | self.cache.update(&event); 149 | } 150 | if let Ok(dispatch_evt) = DispatchEvent::try_from(event) { 151 | // We can assume Some since this is a Dispatch event 152 | let kind = dispatch_evt.kind().name().unwrap(); 153 | let serialized = to_vec(&dispatch_evt)?; 154 | self.amqp_channel 155 | .basic_publish( 156 | &exchange_name, 157 | &kind, 158 | BasicPublishOptions::default(), 159 | serialized, 160 | BasicProperties::default(), 161 | ) 162 | .await?; 163 | } 164 | } 165 | 166 | Ok(()) 167 | } 168 | } 169 | --------------------------------------------------------------------------------