Switch to MongoDB

This commit is contained in:
Daan Vanoverloop 2022-08-29 20:08:16 +02:00
parent 0751408450
commit fc87d5d019
Signed by: Danacus
GPG Key ID: F2272B50E129FC5C
9 changed files with 767 additions and 239 deletions

515
Cargo.lock generated
View File

@ -48,6 +48,15 @@ dependencies = [
"version_check",
]
[[package]]
name = "android_system_properties"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e"
dependencies = [
"libc",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
@ -151,6 +160,25 @@ dependencies = [
"generic-array",
]
[[package]]
name = "bson"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d76085681585d39016f4d3841eb019201fc54d2dd0d92ad1e4fab3bfb32754"
dependencies = [
"ahash",
"base64",
"hex",
"indexmap",
"lazy_static",
"rand",
"serde",
"serde_bytes",
"serde_json",
"time 0.3.14",
"uuid 1.1.2",
]
[[package]]
name = "bumpalo"
version = "3.11.0"
@ -181,6 +209,21 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
dependencies = [
"iana-time-zone",
"js-sys",
"num-integer",
"num-traits",
"time 0.1.44",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "cipher"
version = "0.3.0"
@ -204,10 +247,16 @@ dependencies = [
"rand",
"sha2",
"subtle",
"time",
"time 0.3.14",
"version_check",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "cpufeatures"
version = "0.2.4"
@ -318,6 +367,23 @@ dependencies = [
"parking_lot_core 0.9.3",
]
[[package]]
name = "data-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "devise"
version = "0.3.1"
@ -392,6 +458,18 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "enum-as-inner"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "event-listener"
version = "2.5.3"
@ -580,7 +658,7 @@ checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [
"cfg-if",
"libc",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
@ -684,6 +762,17 @@ dependencies = [
"digest",
]
[[package]]
name = "hostname"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
dependencies = [
"libc",
"match_cfg",
"winapi",
]
[[package]]
name = "http"
version = "0.2.8"
@ -742,6 +831,19 @@ dependencies = [
"want",
]
[[package]]
name = "iana-time-zone"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad2bfd338099682614d3ee3fe0cd72e0b6a41ca6a87f6a74a3bd593c91650501"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"js-sys",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "ident_case"
version = "1.0.1"
@ -785,6 +887,24 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "ipconfig"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98"
dependencies = [
"socket2",
"widestring",
"winapi",
"winreg",
]
[[package]]
name = "ipnet"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
[[package]]
name = "itertools"
version = "0.10.3"
@ -817,6 +937,7 @@ dependencies = [
"futures",
"lazy_static",
"okapi",
"paste",
"rocket",
"rocket_db_pools",
"rocket_okapi",
@ -824,7 +945,7 @@ dependencies = [
"serde_json",
"sqlx",
"thiserror",
"uuid",
"uuid 1.1.2",
]
[[package]]
@ -850,6 +971,12 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "lock_api"
version = "0.4.8"
@ -884,6 +1011,21 @@ dependencies = [
"tracing-subscriber",
]
[[package]]
name = "lru-cache"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "match_cfg"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]]
name = "matchers"
version = "0.1.0"
@ -899,6 +1041,15 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "md-5"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582"
dependencies = [
"digest",
]
[[package]]
name = "memchr"
version = "2.5.0"
@ -925,10 +1076,56 @@ checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
dependencies = [
"libc",
"log",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys",
]
[[package]]
name = "mongodb"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b95afe97b0c799fdf69cd960272a2cb9662d077bd6efd84eb722bb9805d47554"
dependencies = [
"async-trait",
"base64",
"bitflags",
"bson",
"chrono",
"derivative",
"futures-core",
"futures-executor",
"futures-util",
"hex",
"hmac",
"lazy_static",
"md-5",
"os_info",
"pbkdf2",
"percent-encoding",
"rand",
"rustc_version_runtime",
"rustls 0.20.6",
"rustls-pemfile",
"serde",
"serde_bytes",
"serde_with",
"sha-1",
"sha2",
"socket2",
"stringprep",
"strsim",
"take_mut",
"thiserror",
"tokio",
"tokio-rustls 0.23.4",
"tokio-util",
"trust-dns-proto",
"trust-dns-resolver",
"typed-builder",
"uuid 0.8.2",
"webpki-roots 0.22.4",
]
[[package]]
name = "multer"
version = "2.0.3"
@ -959,6 +1156,16 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
@ -1011,6 +1218,16 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "os_info"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5209b2162b2c140df493a93689e04f8deab3a67634f5bc7a553c0a98e5b8d399"
dependencies = [
"log",
"winapi",
]
[[package]]
name = "parking_lot"
version = "0.11.2"
@ -1065,6 +1282,15 @@ version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22"
[[package]]
name = "pbkdf2"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7"
dependencies = [
"digest",
]
[[package]]
name = "pear"
version = "0.2.3"
@ -1172,6 +1398,12 @@ dependencies = [
"yansi",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.21"
@ -1273,6 +1505,16 @@ dependencies = [
"winapi",
]
[[package]]
name = "resolv-conf"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00"
dependencies = [
"hostname",
"quick-error",
]
[[package]]
name = "ring"
version = "0.16.20"
@ -1318,7 +1560,7 @@ dependencies = [
"serde_json",
"state",
"tempfile",
"time",
"time 0.3.14",
"tokio",
"tokio-stream",
"tokio-util",
@ -1349,6 +1591,7 @@ version = "0.1.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bc154f4f4985a136e2d59c336474a56da02103993f5e637e3a5424971ee4eff"
dependencies = [
"mongodb",
"rocket",
"rocket_db_pools_codegen",
"sqlx",
@ -1387,7 +1630,7 @@ dependencies = [
"smallvec",
"stable-pattern",
"state",
"time",
"time 0.3.14",
"tokio",
"uncased",
]
@ -1422,6 +1665,25 @@ dependencies = [
"syn",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]]
name = "rustc_version_runtime"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d31b7153270ebf48bf91c65ae5b0c00e749c4cfad505f66530ac74950249582f"
dependencies = [
"rustc_version",
"semver",
]
[[package]]
name = "rustls"
version = "0.19.1"
@ -1431,8 +1693,29 @@ dependencies = [
"base64",
"log",
"ring",
"sct",
"webpki",
"sct 0.6.1",
"webpki 0.21.4",
]
[[package]]
name = "rustls"
version = "0.20.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033"
dependencies = [
"log",
"ring",
"sct 0.7.0",
"webpki 0.22.0",
]
[[package]]
name = "rustls-pemfile"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ee86d63972a7c661d1536fefe8c3c8407321c3df668891286de28abcd087360"
dependencies = [
"base64",
]
[[package]]
@ -1494,6 +1777,31 @@ dependencies = [
"untrusted",
]
[[package]]
name = "sct"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.144"
@ -1503,6 +1811,15 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde_bytes"
version = "0.11.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b"
dependencies = [
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.144"
@ -1531,11 +1848,45 @@ version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_with"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
dependencies = [
"serde",
"serde_with_macros",
]
[[package]]
name = "serde_with_macros"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "sha-1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha2"
version = "0.10.2"
@ -1658,7 +2009,7 @@ dependencies = [
"once_cell",
"paste",
"percent-encoding",
"rustls",
"rustls 0.19.1",
"serde",
"sha2",
"smallvec",
@ -1668,8 +2019,8 @@ dependencies = [
"thiserror",
"tokio-stream",
"url",
"webpki",
"webpki-roots",
"webpki 0.21.4",
"webpki-roots 0.21.1",
]
[[package]]
@ -1702,7 +2053,7 @@ checksum = "4db708cd3e459078f85f39f96a00960bd841f66ee2a669e90bf36907f5a79aae"
dependencies = [
"once_cell",
"tokio",
"tokio-rustls",
"tokio-rustls 0.22.0",
]
[[package]]
@ -1756,6 +2107,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "take_mut"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
[[package]]
name = "tempfile"
version = "3.3.0"
@ -1799,6 +2156,17 @@ dependencies = [
"once_cell",
]
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "time"
version = "0.3.14"
@ -1869,9 +2237,20 @@ version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6"
dependencies = [
"rustls",
"rustls 0.19.1",
"tokio",
"webpki",
"webpki 0.21.4",
]
[[package]]
name = "tokio-rustls"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
dependencies = [
"rustls 0.20.6",
"tokio",
"webpki 0.22.0",
]
[[package]]
@ -1976,12 +2355,68 @@ dependencies = [
"tracing-log",
]
[[package]]
name = "trust-dns-proto"
version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d"
dependencies = [
"async-trait",
"cfg-if",
"data-encoding",
"enum-as-inner",
"futures-channel",
"futures-io",
"futures-util",
"idna",
"ipnet",
"lazy_static",
"log",
"rand",
"smallvec",
"thiserror",
"tinyvec",
"tokio",
"url",
]
[[package]]
name = "trust-dns-resolver"
version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558"
dependencies = [
"cfg-if",
"futures-util",
"ipconfig",
"lazy_static",
"log",
"lru-cache",
"parking_lot 0.12.1",
"resolv-conf",
"smallvec",
"thiserror",
"tokio",
"trust-dns-proto",
]
[[package]]
name = "try-lock"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "typed-builder"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "typenum"
version = "1.15.0"
@ -2074,6 +2509,15 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom",
]
[[package]]
name = "uuid"
version = "1.1.2"
@ -2082,6 +2526,7 @@ checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
dependencies = [
"getrandom",
"rand",
"serde",
"uuid-macro-internal",
]
@ -2124,6 +2569,12 @@ dependencies = [
"try-lock",
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@ -2204,15 +2655,40 @@ dependencies = [
"untrusted",
]
[[package]]
name = "webpki"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "webpki-roots"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940"
dependencies = [
"webpki",
"webpki 0.21.4",
]
[[package]]
name = "webpki-roots"
version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf"
dependencies = [
"webpki 0.22.0",
]
[[package]]
name = "widestring"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983"
[[package]]
name = "winapi"
version = "0.3.9"
@ -2321,6 +2797,15 @@ version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]]
name = "winreg"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
dependencies = [
"winapi",
]
[[package]]
name = "yansi"
version = "0.5.1"

View File

@ -15,6 +15,7 @@ rocket_okapi = { version = "0.8.0-rc.2", features = ["swagger", "rocket_db_pools
futures = "0.3"
lazy_static = "1.4"
serde_json = "1"
paste = "1"
[dependencies.sqlx]
version = "*"
@ -23,7 +24,7 @@ features = ["macros", "offline", "migrate"]
[dependencies.rocket_db_pools]
version = "0.1.0-rc.2"
features = ["sqlx_sqlite"]
features = ["sqlx_sqlite", "mongodb"]
[dependencies.uuid]
version = "1.1.2"

View File

@ -1,2 +1,2 @@
[default.databases.party]
url = "party.sqlite"
url = "mongodb://root:example@localhost:27017"

View File

@ -1,181 +1,177 @@
use std::collections::HashMap;
use sqlx::FromRow;
use futures::TryStreamExt;
use rocket::serde::json::json;
use rocket_db_pools::mongodb::{bson::to_bson, options::InsertOneOptions};
use serde_json::Value;
use super::{prelude::*, util::PartyError};
api_routes!();
api_routes!(
create_event,
stop_event,
get_event,
update_event,
get_all_events,
event_outcome,
);
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
#[serde(crate = "rocket::serde")]
pub struct EventOutcome {
points: HashMap<i64, i64>,
points: HashMap<String, i64>,
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, FromRow)]
#[serde(crate = "rocket::serde")]
pub struct FreeForAllGame {}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, FromRow)]
#[serde(crate = "rocket::serde")]
pub struct TeamGame {}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, FromRow)]
#[serde(crate = "rocket::serde")]
pub struct Test {}
// # Event
//
// An event in which participants can win or lose points
/// # Event
///
/// An event in which participants can win or lose points
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(crate = "rocket::serde")]
pub enum Event {
FreeForAllGame(FreeForAllGame),
TeamGame(TeamGame),
Test(Test),
}
pub struct EventRecord {
id: i64,
name: String,
event_type: String,
event_id: i64,
}
macro_rules! dispatch {
($event:ident) => {
dispatch!($event,
free_for_all_game => FreeForAllGame,
team_game => TeamGame,
test => Test,
)
};
($event:ident, $($event_type:ident => $event_struct:ident),* $(,)?) => {
match $event.event_type.as_str() {
$(stringify!($event_type) => dispatch_run!($event_type, $event_struct),)*
_ => return Err(PartyError::Unknown("invalid event type".into())),
}
};
}
macro_rules! reverse_dispatch {
($event:ident) => {
reverse_dispatch!($event,
FreeForAllGame => free_for_all_game,
TeamGame => team_game,
Test => test,
)
};
($event:ident, $($event_struct:ident => $event_type:ident),* $(,)?) => {
match $event {
$(Event::$event_struct(e) => reverse_dispatch_run!($event_type, $event_struct, e),)*
}
};
}
impl EventRecord {
pub async fn get(db: &mut Connection<Db>, id: i64) -> Result<Self, PartyError> {
Ok(sqlx::query_as!(
EventRecord,
"SELECT id, name, event_type, event_id FROM events WHERE id = ?",
id
)
.fetch_one(&mut **db)
.await?)
}
pub async fn remove(&self, db: &mut Connection<Db>) -> Result<(), PartyError> {
macro_rules! dispatch_run {
($event_type:ident, $event_struct:ident) => {{
sqlx::query(&format!(
"DELETE FROM events_{} WHERE id = {}",
stringify!($event_type),
self.event_id
))
.fetch_one(&mut **db)
.await?;
}};
}
dispatch!(self);
sqlx::query!("DELETE FROM events WHERE id = ?", self.id)
.execute(&mut **db)
.await?;
Ok(())
}
pub struct Event {
/// Unique identifier of the event. This will be randomly generated and cannot be modified.
#[serde(default = "uuid")]
id: String,
/// Has this event concluded?
concluded: bool,
/// Event type
event_type: EventType,
}
impl Event {
pub async fn register(
&self,
db: &mut Connection<Db>,
name: String,
) -> Result<EventRecord, PartyError> {
let event_id = match self {
Self::FreeForAllGame(e) => {
unimplemented!()
/*
sqlx::query!("INSERT INTO events_free_for_all_game () VALUES ()")
.execute(&mut **db)
.await?
.last_insert_rowid()
*/
}
Self::TeamGame(e) => {
unimplemented!()
/*
sqlx::query!("INSERT INTO events_team_game () VALUES ()")
.execute(&mut **db)
.await?
.last_insert_rowid()
*/
}
Self::Test(e) => sqlx::query!("INSERT INTO events_test () VALUES ()")
.execute(&mut **db)
.await?
.last_insert_rowid(),
};
macro_rules! reverse_dispatch_run {
($event_type:ident, $event_struct:ident, $inner:ident) => {
sqlx::query!(
"INSERT INTO events (name, event_type, event_id) VALUES (?, ?, ?)",
stringify!($event_type),
name,
event_id
)
.execute(&mut **db)
.await?
};
pub fn outcome(&self) -> EventOutcome {
match self.event_type {
_ => EventOutcome::default(),
}
let id = reverse_dispatch!(self).last_insert_rowid();
Ok(EventRecord::get(db, id).await?)
}
pub async fn get(db: &mut Connection<Db>, record: EventRecord) -> Result<Self, PartyError> {
macro_rules! dispatch_run {
($event_type:ident, $event_struct:ident) => {
Event::$event_struct(
sqlx::query_as::<_, $event_struct>(&format!(
"SELECT id, name, event_type, event_id FROM events_{} WHERE id = {}",
stringify!($event_type),
record.event_id
))
.fetch_one(&mut **db)
.await?,
)
};
}
Ok(dispatch!(record))
}
pub fn conclude(&self) {}
}
fn uuid() -> String {
uuid::Uuid::new_v4().to_string()
}
/// # EventType
///
/// Enumeration of all different types of events
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(crate = "rocket::serde")]
pub enum EventType {
FreeForAllGame {},
TeamGame {},
Test {},
}
/// # Create event
///
/// If an `id` is supplied, it will be replaced by a randomly generated
/// one.
///
/// Returns the created event. #[openapi(tag = "Event")]
#[openapi(tag = "Event")]
#[post("/", data = "<event>")]
pub async fn create_event(
_api_key: ApiKey,
db: Connection<Db>,
mut event: Json<Event>,
) -> Result<Json<Event>, PartyError> {
event.id = uuid();
event.concluded = false;
db.events().insert_one(&*event, None).await?;
Ok(event)
}
/// # Update event
///
/// Update the supplied values in the event with the given id. The `id` of an event cannot be
/// changed and `concluded` will always be false.
#[openapi(tag = "Event")]
#[post("/<id>", data = "<event>")]
pub async fn update_event(
_api_key: ApiKey,
db: Connection<Db>,
id: String,
mut event: Json<Value>, // Use serde_json::Value to allow a partial struct
) -> Result<Status, PartyError> {
if let Some(i) = event.get_mut("id") {
*i = json! { &id };
}
if let Some(i) = event.get_mut("concluded") {
*i = json! { false };
}
db.users()
.update_one(doc! { "id": &id }, doc! { "$set": to_bson(&*event)? }, None)
.await?;
Ok(Status::Ok)
}
/// # Get event
///
/// Returns the event with the given id
#[openapi(tag = "Event")]
#[get("/<id>")]
pub async fn get_event(
_api_key: ApiKey,
db: Connection<Db>,
id: String,
) -> Result<Json<Event>, PartyError> {
Ok(Json(
db.events()
.find_one(doc! { "id": &id }, None)
.await?
.ok_or(PartyError::EventNotFound(id))?,
))
}
/// # Get events
///
/// Returns the event with the given id
#[openapi(tag = "Event")]
#[get("/")]
pub async fn get_all_events(
_api_key: ApiKey,
db: Connection<Db>,
) -> Result<Json<Vec<Event>>, PartyError> {
Ok(Json(
db.events().find(doc! {}, None).await?.try_collect().await?,
))
}
/// # Get outcome
///
/// Returns the outcome of a concluded event.
#[openapi(tag = "Event")]
#[get("/<id>/outcome")]
pub async fn event_outcome(
_api_key: ApiKey,
db: Connection<Db>,
id: String,
) -> Result<Json<EventOutcome>, PartyError> {
let event = db
.events()
.find_one(doc! { "id": &id }, None)
.await?
.ok_or(PartyError::EventNotFound(id.clone()))?;
Ok(Json(event.outcome()))
}
/// # Stop event
#[openapi(tag = "Event")]
#[post("/<id>/stop")]
pub fn stop_event(id: i64) -> Result<Json<EventOutcome>, PartyError> {
todo!()
pub async fn stop_event(
_api_key: ApiKey,
db: Connection<Db>,
id: String,
) -> Result<Json<EventOutcome>, PartyError> {
let event = db
.events()
.find_one(doc! { "id": &id }, None)
.await?
.ok_or(PartyError::EventNotFound(id.clone()))?;
event.conclude();
db.users()
.update_one(doc! { "id": &id }, doc! { "concluded": true }, None)
.await?;
Ok(Json(event.outcome()))
}

View File

@ -13,8 +13,12 @@ mod prelude {
response::status,
serde::{json::Json, Deserialize, Serialize},
};
pub use rocket_db_pools::{sqlx, Connection};
pub use rocket_db_pools::{
mongodb::bson::{doc, Document},
sqlx, Connection,
};
pub use rocket_okapi::{openapi, JsonSchema};
pub use util::MongoClientExt;
}
#[macro_export]
@ -40,7 +44,7 @@ macro_rules! mount_endpoints {
) -> Rocket<Build> {
mount_endpoints_and_merged_docs! {
building_rocket, "/api".to_owned(), openapi_settings,
$(stringify!("/", $endpoint) => $endpoint::get_routes_and_docs(&openapi_settings),)*
$(concat!("/", stringify!($endpoint)) => $endpoint::get_routes_and_docs(&openapi_settings),)*
};
building_rocket
}

View File

@ -1,5 +1,6 @@
use super::prelude::*;
use sqlx::FromRow;
use futures::{StreamExt, TryStreamExt};
use rocket_db_pools::mongodb::options::FindOptions;
use util::{Ordering, PartyError};
api_routes!(
@ -14,17 +15,15 @@ api_routes!(
/// # User
///
/// A user that represents a person participating in the LAN party
#[derive(Clone, Debug, FromForm, Serialize, Deserialize, JsonSchema, FromRow)]
#[derive(Clone, Debug, FromForm, Serialize, Deserialize, JsonSchema)]
#[serde(crate = "rocket::serde")]
pub struct User {
/// Name of the user
name: String,
/// Score of the user
#[serde(default)]
score: i64,
/// Unique identifier of the user
#[serde(default)]
id: i64,
id: String,
}
/// # Create new user with the give name
@ -34,19 +33,17 @@ pub struct User {
#[post("/", data = "<name>")]
pub async fn add_user(
_api_key: ApiKey,
mut db: Connection<Db>,
db: Connection<Db>,
name: Json<&str>,
) -> Result<status::Created<Json<User>>, PartyError> {
let result = sqlx::query!("INSERT INTO users (name) VALUES (?)", *name)
.execute(&mut *db)
.await?;
let user = User {
id: result.last_insert_rowid(),
id: uuid::Uuid::new_v4().to_string(),
score: 0,
name: name.to_string(),
};
db.users().insert_one(&user, None).await?;
Ok(status::Created::new("/").body(Json(user)))
}
@ -55,12 +52,10 @@ pub async fn add_user(
#[delete("/<id>")]
pub async fn delete_user(
_api_key: ApiKey,
mut db: Connection<Db>,
id: i64,
db: Connection<Db>,
id: String,
) -> Result<Status, PartyError> {
sqlx::query!("DELETE FROM users where (id = ?)", id)
.execute(&mut *db)
.await?;
db.users().delete_one(doc! { "id": id }, None).await?;
Ok(Status::Ok)
}
@ -72,12 +67,14 @@ pub async fn delete_user(
#[get("/<id>")]
pub async fn get_user(
_api_key: ApiKey,
mut db: Connection<Db>,
id: i64,
db: Connection<Db>,
id: String,
) -> Result<Json<User>, PartyError> {
let user = sqlx::query_as!(User, "SELECT id, name, score FROM users WHERE (id = ?)", id)
.fetch_one(&mut *db)
.await?;
let user = db
.users()
.find_one(doc! { "id": &id }, None)
.await?
.ok_or(PartyError::UserNotFound(id))?;
Ok(Json(user))
}
@ -113,17 +110,31 @@ impl ToString for UserSort {
#[get("/?<sort>&<order>")]
pub async fn get_all_users(
_api_key: ApiKey,
mut db: Connection<Db>,
db: Connection<Db>,
sort: Option<UserSort>,
order: Option<Ordering>,
) -> Result<Json<Vec<User>>, PartyError> {
let users = sqlx::query_as::<_, User>(&format!(
"SELECT id, name, score FROM users ORDER BY {} {}",
sort.unwrap_or(UserSort::Id).to_string(),
order.unwrap_or(Ordering::Asc).to_string()
))
.fetch_all(&mut *db)
.await?;
let options = if let Some(sort) = sort {
let order = order.unwrap_or(Ordering::Asc);
let mut doc = Document::new();
doc.insert(
sort.to_string(),
match order {
Ordering::Asc => 1,
Ordering::Desc => -1,
},
);
FindOptions::builder().sort(doc).build()
} else {
FindOptions::builder().build()
};
let users = db
.users()
.find(doc! {}, Some(options))
.await?
.try_collect()
.await?;
Ok(Json(users))
}
@ -133,13 +144,18 @@ pub async fn get_all_users(
#[post("/<id>/score", data = "<score>")]
pub async fn set_score(
_api_key: ApiKey,
mut db: Connection<Db>,
id: i64,
db: Connection<Db>,
id: String,
score: Json<i64>,
) -> Result<Status, PartyError> {
sqlx::query!("UPDATE users SET score = ? WHERE id = ?", *score, id)
.execute(&mut *db)
db.users()
.update_one(
doc! { "id": id },
doc! { "$set": { "score": *score } },
None,
)
.await?;
Ok(Status::Ok)
}
@ -150,11 +166,14 @@ pub async fn set_score(
#[get("/<id>/score")]
pub async fn get_score(
_api_key: ApiKey,
mut db: Connection<Db>,
id: i64,
db: Connection<Db>,
id: String,
) -> Result<Json<i64>, PartyError> {
let score = sqlx::query_scalar!("SELECT score FROM users WHERE id = ?", id)
.fetch_one(&mut *db)
.await?;
Ok(Json(score))
Ok(Json(
db.users()
.find_one(doc! { "id": &id }, None)
.await?
.ok_or(PartyError::UserNotFound(id))?
.score,
))
}

View File

@ -1,8 +1,11 @@
use rocket::{http::Status, response, response::Responder, Request};
use rocket_db_pools::mongodb;
use rocket_okapi::response::OpenApiResponderInner;
use schemars::JsonSchema;
use thiserror::Error;
use super::{event::Event, user::User};
/// # Ordering
///
/// Ordering of data in an array, ascending or descending
@ -28,7 +31,9 @@ impl ToString for Ordering {
#[derive(Error, Debug)]
pub enum PartyError {
#[error("user `{0}` does not exist")]
UserNotFound(i64),
UserNotFound(String),
#[error("event `{0}` does not exist")]
EventNotFound(String),
#[error("unknown error: {0}")]
Unknown(String),
#[error("invalid parameter: {0}")]
@ -43,6 +48,16 @@ pub enum PartyError {
#[from]
source: sqlx::Error,
},
#[error("mongodb error {source:?}")]
MongodbError {
#[from]
source: mongodb::error::Error,
},
#[error("failed to serialize bson: {source:?}")]
BsonSerializationError {
#[from]
source: mongodb::bson::ser::Error,
},
}
impl OpenApiResponderInner for PartyError {
@ -56,9 +71,29 @@ impl OpenApiResponderInner for PartyError {
impl<'r, 'o: 'r> Responder<'r, 'o> for PartyError {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
match self {
Self::UserNotFound(_) => Status::NotFound,
Self::UserNotFound(_) | Self::EventNotFound(_) => Status::NotFound,
_ => Status::InternalServerError,
}
.respond_to(req)
}
}
pub trait MongoClientExt {
fn party_db(&self) -> mongodb::Database;
fn users(&self) -> mongodb::Collection<User>;
fn events(&self) -> mongodb::Collection<Event>;
}
impl MongoClientExt for mongodb::Client {
fn party_db(&self) -> mongodb::Database {
self.database("lan_party")
}
fn users(&self) -> mongodb::Collection<User> {
self.party_db().collection("users")
}
fn events(&self) -> mongodb::Collection<Event> {
self.party_db().collection("events")
}
}

View File

@ -1,9 +1,8 @@
mod api;
use rocket::{fairing, fairing::AdHoc, Build, Rocket};
use rocket_db_pools::{sqlx, Database};
use rocket_db_pools::{mongodb, Database};
use rocket_okapi::{
mount_endpoints_and_merged_docs, openapi,
openapi,
rapidoc::*,
settings::{OpenApiSettings, UrlObject},
swagger_ui::{make_swagger_ui, SwaggerUIConfig},
@ -14,7 +13,7 @@ extern crate rocket;
#[derive(Database)]
#[database("party")]
pub struct Db(sqlx::SqlitePool);
pub struct Db(mongodb::Client);
#[openapi]
#[get("/")]
@ -22,27 +21,10 @@ fn index() -> String {
format!("Hello, world!")
}
async fn run_migrations(rocket: Rocket<Build>) -> fairing::Result {
match Db::fetch(&rocket) {
Some(db) => match sqlx::migrate!("db/migrations").run(&**db).await {
Ok(_) => {
println!("Migrations completed");
Ok(rocket)
}
Err(e) => {
error!("Failed to initialize SQLx database: {}", e);
Err(rocket)
}
},
None => Err(rocket),
}
}
#[launch]
fn rocket() -> _ {
let building_rocket = rocket::build()
.attach(Db::init())
.attach(AdHoc::try_on_ignite("SQLx Migrations", run_migrations))
.mount("/", routes![index])
.mount(
"/swagger",

6
start_mongodb.sh Executable file
View File

@ -0,0 +1,6 @@
podman run -d --rm --name lan_party_db \
-v lan-party-db:/data/db:z \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=root \
-e MONGO_INITDB_ROOT_PASSWORD=example \
docker.io/mongo:latest