summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/Cargo.lock414
-rw-r--r--server/Cargo.toml3
-rw-r--r--server/src/main.rs281
3 files changed, 421 insertions, 277 deletions
diff --git a/server/Cargo.lock b/server/Cargo.lock
index 610d853..ee52661 100644
--- a/server/Cargo.lock
+++ b/server/Cargo.lock
@@ -18,6 +18,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
+name = "async-trait"
+version = "0.1.81"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -39,12 +50,24 @@ dependencies = [
]
[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -54,6 +77,12 @@ dependencies = [
]
[[package]]
+name = "bumpalo"
+version = "3.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+
+[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -87,30 +116,6 @@ dependencies = [
]
[[package]]
-name = "crc32fast"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "crossbeam-epoch"
-version = "0.9.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
-dependencies = [
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
-
-[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -134,22 +139,29 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
+ "subtle",
]
[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
+[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
-name = "fs2"
-version = "0.4.3"
+name = "futures-channel"
+version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [
- "libc",
- "winapi",
+ "futures-core",
+ "futures-sink",
]
[[package]]
@@ -197,15 +209,6 @@ dependencies = [
]
[[package]]
-name = "fxhash"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
-dependencies = [
- "byteorder",
-]
-
-[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -239,6 +242,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
+[[package]]
name = "http"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -256,15 +268,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
[[package]]
-name = "instant"
-version = "0.1.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -276,10 +279,20 @@ version = "0.1.0"
dependencies = [
"futures-util",
"rand",
- "sled",
"tokio",
+ "tokio-postgres",
"tokio-tungstenite",
"tungstenite",
+ "zerocopy",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+dependencies = [
+ "wasm-bindgen",
]
[[package]]
@@ -305,6 +318,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
+name = "md-5"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
+dependencies = [
+ "cfg-if",
+ "digest",
+]
+
+[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -341,28 +364,56 @@ dependencies = [
]
[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
+[[package]]
name = "parking_lot"
-version = "0.11.2"
+version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
- "instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
-version = "0.8.6"
+version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
- "instant",
"libc",
- "redox_syscall",
+ "redox_syscall 0.5.3",
"smallvec",
- "winapi",
+ "windows-targets",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "phf"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
+dependencies = [
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
+dependencies = [
+ "siphasher",
]
[[package]]
@@ -378,6 +429,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
+name = "postgres-protocol"
+version = "0.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acda0ebdebc28befa84bee35e651e4c5f09073d668c7aed4cf7e23c3cda84b23"
+dependencies = [
+ "base64",
+ "byteorder",
+ "bytes",
+ "fallible-iterator",
+ "hmac",
+ "md-5",
+ "memchr",
+ "rand",
+ "sha2",
+ "stringprep",
+]
+
+[[package]]
+name = "postgres-types"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02048d9e032fb3cc3413bbf7b83a15d84a5d419778e2628751896d856498eee9"
+dependencies = [
+ "bytes",
+ "fallible-iterator",
+ "postgres-protocol",
+]
+
+[[package]]
name = "ppv-lite86"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -436,11 +516,20 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.2.16"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
dependencies = [
- "bitflags",
+ "bitflags 2.6.0",
]
[[package]]
@@ -467,6 +556,17 @@ dependencies = [
]
[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
name = "signal-hook-registry"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -476,6 +576,12 @@ dependencies = [
]
[[package]]
+name = "siphasher"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+
+[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -485,22 +591,6 @@ dependencies = [
]
[[package]]
-name = "sled"
-version = "0.34.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935"
-dependencies = [
- "crc32fast",
- "crossbeam-epoch",
- "crossbeam-utils",
- "fs2",
- "fxhash",
- "libc",
- "log",
- "parking_lot",
-]
-
-[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -517,6 +607,23 @@ dependencies = [
]
[[package]]
+name = "stringprep"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+ "unicode-properties",
+]
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
name = "syn"
version = "2.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -548,6 +655,21 @@ dependencies = [
]
[[package]]
+name = "tinyvec"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
name = "tokio"
version = "1.39.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -576,6 +698,32 @@ dependencies = [
]
[[package]]
+name = "tokio-postgres"
+version = "0.7.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03adcf0147e203b6032c0b2d30be1415ba03bc348901f3ff1cc0df6a733e60c3"
+dependencies = [
+ "async-trait",
+ "byteorder",
+ "bytes",
+ "fallible-iterator",
+ "futures-channel",
+ "futures-util",
+ "log",
+ "parking_lot",
+ "percent-encoding",
+ "phf",
+ "pin-project-lite",
+ "postgres-protocol",
+ "postgres-types",
+ "rand",
+ "socket2",
+ "tokio",
+ "tokio-util",
+ "whoami",
+]
+
+[[package]]
name = "tokio-tungstenite"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -588,6 +736,19 @@ dependencies = [
]
[[package]]
+name = "tokio-util"
+version = "0.7.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
name = "tungstenite"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -612,12 +773,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
+name = "unicode-bidi"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+
+[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
+name = "unicode-normalization"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "unicode-properties"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291"
+
+[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -636,26 +818,86 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
-name = "winapi"
-version = "0.3.9"
+name = "wasite"
+version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
+ "cfg-if",
+ "once_cell",
+ "wasm-bindgen-macro",
]
[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
+name = "wasm-bindgen-backend"
+version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
+name = "wasm-bindgen-macro-support"
+version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+
+[[package]]
+name = "web-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "whoami"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9"
+dependencies = [
+ "redox_syscall 0.4.1",
+ "wasite",
+ "web-sys",
+]
[[package]]
name = "windows-sys"
diff --git a/server/Cargo.toml b/server/Cargo.toml
index 130968f..642bbe1 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -6,7 +6,8 @@ edition = "2021"
[dependencies]
futures-util = "0.3"
rand = { version = "0.8.5", features = ["std", "std_rng"] }
-sled = "0.34.7"
tokio = { version = "1", features = ["rt", "macros", "rt-multi-thread", "net", "io-util", "sync", "time", "process"] }
+tokio-postgres = "0.7.11"
tokio-tungstenite = "0.23.1"
tungstenite = "0.23.0"
+zerocopy = "0.7.35"
diff --git a/server/src/main.rs b/server/src/main.rs
index f695910..eb9674b 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -1,3 +1,6 @@
+#![allow(dead_code)] // TODO : delete me
+#![allow(unused_variables)] // TODO : delete me
+
use futures_util::{SinkExt, StreamExt};
use rand::seq::SliceRandom;
use rand::Rng;
@@ -9,6 +12,7 @@ use std::time::{Duration, SystemTime};
use tokio::io::AsyncWriteExt;
use tokio::sync::{Mutex, RwLock};
use tungstenite::protocol::Message;
+use zerocopy::AsBytes;
const PUZZLE_ID_CHARSET: &[u8] = b"23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
const PUZZLE_ID_LEN: usize = 7;
@@ -21,19 +25,48 @@ fn generate_puzzle_id() -> [u8; PUZZLE_ID_LEN] {
#[derive(Debug)]
struct Server {
- puzzles: sled::Tree,
- pieces: sled::Tree,
- connectivity: sled::Tree,
// keep this in memory, since we want to reset it to 0 when the server restarts
player_counts: Mutex<HashMap<[u8; PUZZLE_ID_LEN], u16>>,
wikimedia_featured: Vec<String>,
wikimedia_potd: RwLock<String>,
+ database: tokio_postgres::Client,
+}
+
+
+impl Server {
+ async fn create_table_if_not_exists(&self) -> Result<()> {
+ todo!()
+ }
+ async fn try_register_id(&self, id: [u8; PUZZLE_ID_LEN]) -> Result<bool> {
+ todo!()
+ }
+ async fn set_puzzle_data(&self, id: [u8; PUZZLE_ID_LEN], width: u8, height: u8, url: &str, nib_types: Vec<u16>, piece_positions: Vec<f32>, connectivity_data: Vec<u16>) -> Result<()> {
+ todo!()
+ }
+ async fn move_piece(&self, piece: usize, x: f32, y: f32) -> Result<()> {
+ todo!()
+ }
+ async fn connect_pieces(&self, piece1: usize, piece2: usize) -> Result<()> {
+ todo!()
+ }
+ async fn get_connectivity(&self, id: [u8; PUZZLE_ID_LEN]) -> Result<Vec<u16>> {
+ todo!()
+ }
+ async fn get_positions(&self, id: [u8; PUZZLE_ID_LEN]) -> Result<Vec<f32>> {
+ todo!()
+ }
+ async fn get_details(&self, id: [u8; PUZZLE_ID_LEN]) -> Result<(u8, u8, String)> {
+ todo!()
+ }
+ async fn sweep(&self) -> Result<()> {
+ todo!()
+ }
}
#[derive(Debug)]
enum Error {
Tungstenite(tungstenite::Error),
- Sled(sled::Error),
+ Postgres(tokio_postgres::Error),
IO(std::io::Error),
UTF8(std::str::Utf8Error),
BadPuzzleID,
@@ -55,7 +88,7 @@ impl std::fmt::Display for Error {
Error::TooManyPieces => write!(f, "too many pieces"),
Error::NotJoined => write!(f, "haven't joined a puzzle"),
Error::TooManyPlayers => write!(f, "too many players"),
- Error::Sled(e) => write!(f, "{e}"),
+ Error::Postgres(e) => write!(f, "{e}"),
Error::IO(e) => write!(f, "{e}"),
Error::UTF8(e) => write!(f, "{e}"),
Error::Tungstenite(e) => write!(f, "{e}"),
@@ -63,9 +96,9 @@ impl std::fmt::Display for Error {
}
}
-impl From<sled::Error> for Error {
- fn from(value: sled::Error) -> Self {
- Self::Sled(value)
+impl From<tokio_postgres::Error> for Error {
+ fn from(value: tokio_postgres::Error) -> Self {
+ Self::Postgres(value)
}
}
@@ -87,21 +120,21 @@ impl From<std::str::Utf8Error> for Error {
type Result<T> = std::result::Result<T, Error>;
-fn get_puzzle_info(server: &Server, id: &[u8]) -> Result<Vec<u8>> {
- if id.len() != PUZZLE_ID_LEN {
- return Err(Error::BadPuzzleID);
- }
- let mut data = vec![1, 0, 0, 0, 0, 0, 0, 0]; // opcode + padding
- let puzzle = server.puzzles.get(id)?.ok_or(Error::BadPuzzleID)?;
- data.extend_from_slice(&puzzle);
+async fn get_puzzle_info(server: &Server, id: &[u8]) -> Result<Vec<u8>> {
+ let id: [u8; PUZZLE_ID_LEN] = id.try_into().map_err(|_| Error::BadPuzzleID)?;
+ let mut data = vec![1];
+ let (width, height, url) = server.get_details(id).await?;
+ data.push(width);
+ data.push(height);
+ data.extend(url.as_bytes());
while data.len() % 8 != 0 {
// padding
data.push(0);
}
- let pieces = server.pieces.get(id)?.ok_or(Error::BadPuzzleID)?;
- data.extend_from_slice(&pieces);
- let connectivity = server.connectivity.get(id)?.ok_or(Error::BadPuzzleID)?;
- data.extend_from_slice(&connectivity);
+ let pieces = server.get_positions(id).await?;
+ data.extend_from_slice(pieces.as_bytes());
+ let connectivity = server.get_connectivity(id).await?;
+ data.extend_from_slice(connectivity.as_bytes());
Ok(data)
}
@@ -136,82 +169,46 @@ async fn handle_websocket(
if (width as u16) * (height as u16) > 1000 {
return Err(Error::TooManyPieces);
}
- let mut puzzle_data = vec![width, height];
- let timestamp: u64 = SystemTime::now()
- .duration_since(SystemTime::UNIX_EPOCH)
- .expect("time went backwards :/")
- .as_secs();
- for byte in timestamp.to_le_bytes() {
- puzzle_data.push(byte);
- }
- // pick nib types
+ let nib_count = 2 * (width as usize) * (height as usize) - (width as usize) - (height as usize);
+ let mut nib_types: Vec<u16> = Vec::with_capacity(nib_count);
+ let mut piece_positions: Vec<f32> = Vec::with_capacity((width as usize) * (height as usize) * 2);
{
let mut rng = rand::thread_rng();
- for _ in 0..2u16 * (width as u16) * (height as u16)
- - (width as u16) - (height as u16)
- {
- puzzle_data.push(rng.gen());
- puzzle_data.push(rng.gen());
+ // pick nib types
+ for _ in 0..nib_count {
+ nib_types.push(rng.gen());
}
- }
- // URL
- puzzle_data.extend(url.as_bytes());
- puzzle_data.push(0);
- // puzzle ID
- let mut id;
- loop {
- id = generate_puzzle_id();
- let data = std::mem::take(&mut puzzle_data);
- if server
- .puzzles
- .compare_and_swap(id, None::<&'static [u8; 0]>, Some(&data[..]))?
- .is_ok()
- {
- break;
- }
- }
- drop(puzzle_data); // should be empty now
- *puzzle_id = Some(id);
- let pieces_data: Box<[u8]>;
- {
- let mut rng = rand::thread_rng();
- let mut positions = vec![];
- positions.reserve_exact((width as usize) * (height as usize));
- // positions
+ // pick piece positions
for y in 0..(height as u16) {
for x in 0..(width as u16) {
let dx: f32 = rng.gen_range(0.0..0.5);
let dy: f32 = rng.gen_range(0.0..0.5);
- positions.push([
- (x as f32 + dx) / ((width + 1) as f32),
- (y as f32 + dy) / ((height + 1) as f32),
- ]);
+ piece_positions.push((x as f32 + dx) / ((width + 1) as f32));
+ piece_positions.push((y as f32 + dy) / ((height + 1) as f32));
}
}
- positions.shuffle(&mut rng);
- // rust isn't smart enough to do the zero-copy with f32::to_le_bytes and Vec::into_flattened
- let ptr: *mut [[f32; 2]] = Box::into_raw(positions.into_boxed_slice());
- let ptr: *mut [u8] = std::ptr::slice_from_raw_parts_mut(
- ptr.cast(),
- (width as usize) * (height as usize) * 8,
- );
- // evil unsafe code >:3
- pieces_data = unsafe { Box::from_raw(ptr) };
+ piece_positions.shuffle(&mut rng);
}
- server.pieces.insert(id, pieces_data)?;
- let mut connectivity_data =
- Vec::with_capacity((width as usize) * (height as usize) * 2);
+ let mut connectivity_data: Vec<u16> =
+ Vec::with_capacity((width as usize) * (height as usize));
for i in 0..(width as u16) * (height as u16) {
- connectivity_data.extend(i.to_le_bytes());
+ connectivity_data.push(i);
}
- server.connectivity.insert(id, connectivity_data)?;
+ let mut id;
+ loop {
+ id = generate_puzzle_id();
+ if server.try_register_id(id).await? {
+ break;
+ }
+ }
+ server.set_puzzle_data(id, width, height, url, nib_types, piece_positions, connectivity_data).await?;
server.player_counts.lock().await.insert(id, 1);
ws.send(Message::Text(format!(
"id: {}",
std::str::from_utf8(&id).expect("puzzle ID has bad utf-8???")
)))
.await?;
- let info = get_puzzle_info(server, &id)?;
+ let info = get_puzzle_info(server, &id).await?;
ws.send(Message::Binary(info)).await?;
} else if let Some(id) = text.strip_prefix("join ") {
let id = id.as_bytes().try_into().map_err(|_| Error::BadSyntax)?;
@@ -223,17 +220,10 @@ async fn handle_websocket(
*entry += 1;
drop(player_counts); // release lock
*puzzle_id = Some(id);
- let info = get_puzzle_info(server, &id)?;
+ let info = get_puzzle_info(server, &id).await?;
ws.send(Message::Binary(info)).await?;
} else if text.starts_with("move ") {
let puzzle_id = puzzle_id.ok_or(Error::NotJoined)?;
- #[derive(Clone, Copy)]
- struct Motion {
- piece: usize,
- x: f32,
- y: f32,
- }
- let mut motions = vec![];
for line in text.split('\n') {
let mut parts = line.split(' ');
parts.next(); // skip "move"
@@ -252,29 +242,7 @@ async fn handle_websocket(
.ok_or(Error::BadSyntax)?
.parse()
.map_err(|_| Error::BadSyntax)?;
- motions.push(Motion { piece, x, y });
- }
- let mut error = None;
- server
- .pieces
- .fetch_and_update(puzzle_id, |curr_pieces: Option<&[u8]>| {
- let Some(curr_pieces) = curr_pieces else {
- error = Some(Error::BadPuzzleID);
- return None;
- };
- let mut new_pieces = curr_pieces.to_vec();
- for Motion { piece, x, y } in motions.iter().copied() {
- let Some(slice) = new_pieces.get_mut(8 * piece..8 * piece + 8) else {
- error = Some(Error::BadPieceID);
- break;
- };
- slice[0..4].copy_from_slice(&x.to_le_bytes());
- slice[4..8].copy_from_slice(&y.to_le_bytes());
- }
- Some(new_pieces)
- })?;
- if let Some(error) = error {
- return Err(error);
+ server.move_piece(piece, x, y).await?;
}
ws.send(Message::Text("ack".to_string())).await?;
} else if let Some(data) = text.strip_prefix("connect ") {
@@ -290,52 +258,12 @@ async fn handle_websocket(
.ok_or(Error::BadSyntax)?
.parse()
.map_err(|_| Error::BadSyntax)?;
- let mut error = None;
- server
- .connectivity
- .fetch_and_update(puzzle_id, |curr_connectivity| {
- let Some(curr_connectivity) = curr_connectivity else {
- error = Some(Error::BadPuzzleID);
- return None;
- };
- let mut new_connectivity = curr_connectivity.to_vec();
- if piece1 >= curr_connectivity.len() / 2
- || piece2 >= curr_connectivity.len() / 2
- {
- error = Some(Error::BadPieceID);
- return Some(new_connectivity);
- }
- let piece2_group = u16::from_le_bytes([
- curr_connectivity[piece2 * 2],
- curr_connectivity[piece2 * 2 + 1],
- ]);
- let a = curr_connectivity[piece1 * 2];
- let b = curr_connectivity[piece1 * 2 + 1];
- for piece in 0..curr_connectivity.len() / 2 {
- let piece_group = u16::from_le_bytes([
- curr_connectivity[piece * 2],
- curr_connectivity[piece * 2 + 1],
- ]);
- if piece_group == piece2_group {
- new_connectivity[piece * 2] = a;
- new_connectivity[piece * 2 + 1] = b;
- }
- }
- Some(new_connectivity)
- })?;
- if let Some(error) = error {
- return Err(error);
- }
+ server.connect_pieces(piece1, piece2).await?;
} else if text == "poll" {
let puzzle_id = puzzle_id.ok_or(Error::NotJoined)?;
- let pieces = server.pieces.get(puzzle_id)?.ok_or(Error::BadPuzzleID)?;
- let connectivity = server
- .connectivity
- .get(puzzle_id)?
- .ok_or(Error::BadPuzzleID)?;
let mut data = vec![2, 0, 0, 0, 0, 0, 0, 0]; // opcode / version number + padding
- data.extend_from_slice(&pieces);
- data.extend_from_slice(&connectivity);
+ data.extend_from_slice(server.get_positions(puzzle_id).await?.as_bytes());
+ data.extend_from_slice(server.get_connectivity(puzzle_id).await?.as_bytes());
ws.send(Message::Binary(data)).await?;
} else if text == "randomFeaturedWikimedia" {
let choice = rand::thread_rng().gen_range(0..server.wikimedia_featured.len());
@@ -427,22 +355,23 @@ async fn main() {
let server_arc: Arc<Server> = Arc::new({
let wikimedia_featured =
read_to_lines("featuredpictures.txt").expect("Couldn't read featuredpictures.txt");
- let db = sled::open("database.sled").expect("error opening database");
- let puzzles = db.open_tree("PUZZLES").expect("error opening puzzles tree");
- let pieces = db.open_tree("PIECES").expect("error opening pieces tree");
- let connectivity = db
- .open_tree("CONNECTIVITY")
- .expect("error opening connectivity tree");
let potd = get_potd().await;
+ let (client, connection) = tokio_postgres::connect("host=/var/run/postgresql dbname=jigsaw", tokio_postgres::NoTls).await.expect("Couldn't connect to database");
+
+ // docs say: "The connection object performs the actual communication with the database, so spawn it off to run on its own."
+ tokio::spawn(async move {
+ if let Err(e) = connection.await {
+ eprintln!("connection error: {}", e);
+ }
+ });
Server {
- puzzles,
- pieces,
player_counts: Mutex::new(HashMap::new()),
- connectivity,
+ database: client,
wikimedia_potd: RwLock::new(potd),
wikimedia_featured,
}
});
+ server_arc.create_table_if_not_exists().await.expect("error creating table");
let server_arc_clone = server_arc.clone();
tokio::task::spawn(async move {
let server: &Server = server_arc_clone.as_ref();
@@ -466,36 +395,8 @@ async fn main() {
loop {
// TODO : sweep
let now = SystemTime::now();
- let mut to_delete = vec![];
- for item in server.puzzles.iter() {
- let (key, value) = item.expect("sweep failed to read database");
- let timestamp: [u8; 8] = value[2..2 + 8].try_into().unwrap();
- let timestamp =
- SystemTime::UNIX_EPOCH + Duration::from_secs(u64::from_le_bytes(timestamp));
- if now.duration_since(timestamp).unwrap_or_default()
- >= Duration::from_secs(60 * 60 * 24 * 7)
- {
- // delete puzzles created at least 1 week ago
- to_delete.push(key);
- }
- }
- for key in to_delete {
- // technically there is a race condition here but stop being silly
- server
- .puzzles
- .remove(&key)
- .expect("sweep failed to delete puzzle");
- server
- .pieces
- .remove(&key)
- .expect("sweep failed to delete pieces");
- server
- .connectivity
- .remove(&key)
- .expect("sweep failed to delete connectivity");
- if let Some(key) = <[u8; PUZZLE_ID_LEN]>::try_from(&key[..]).ok() {
- server.player_counts.lock().await.remove(&key);
- }
+ if let Err(e) = server.sweep().await {
+ eprintln!("error sweeping DB: {e}");
}
tokio::time::sleep(std::time::Duration::from_secs(3600)).await;
}