From 0c26cff16ec99091ceff6e285a8bb8996ffb0f7e Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Wed, 13 Dec 2023 18:31:50 +0200 Subject: [PATCH 01/28] working on getting things to compile in wasm --- Cargo.lock | 886 +++++++++++++--------------- Cargo.toml | 18 +- crates/codec/Cargo.toml | 4 +- crates/db/Cargo.toml | 7 +- crates/primitives/Cargo.toml | 4 +- crates/serde/src/de.rs | 81 ++- rust-toolchain.toml | 1 + server/game/src/packets/msg_data.rs | 14 +- 8 files changed, 496 insertions(+), 519 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c36e667..c2786c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -32,9 +32,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -45,21 +45,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anyhow" version = "1.0.75" @@ -91,7 +76,7 @@ dependencies = [ "argh_shared", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] @@ -122,7 +107,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] @@ -133,7 +118,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] @@ -193,9 +178,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.19" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a1de45611fdb535bfde7b7de4fd54f4fd2b17b1737c0a59b69bf9b92074b8c" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", "axum-core", @@ -238,9 +223,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -253,15 +238,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "base64ct" @@ -275,7 +254,7 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d1c9c15093eb224f0baa400f38fcd713fc1391a6f1c389d886beef146d60a3" dependencies = [ - "base64 0.21.2", + "base64", "blowfish", "getrandom", "subtle", @@ -292,7 +271,7 @@ dependencies = [ "game", "local-ip-address", "parking_lot", - "pretty-hex", + "pretty-hex 0.3.0", "rand", "sqlx", "thiserror", @@ -314,9 +293,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" dependencies = [ "serde", ] @@ -340,37 +319,31 @@ dependencies = [ "cipher", ] -[[package]] -name = "bumpalo" -version = "3.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" - [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -380,9 +353,12 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -392,14 +368,11 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ - "android-tzdata", - "iana-time-zone", "num-traits", - "winapi", ] [[package]] @@ -452,21 +425,15 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -482,9 +449,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" @@ -497,9 +464,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "14c3242926edf34aec4ac3a77108ad4854bffaa2e4ddc1824124ce59231302d5" dependencies = [ "cfg-if", "crossbeam-utils", @@ -507,9 +474,9 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "b9bcf5bdbfdd6030fb4a1c497b5d5fc5921aa2f60d359a17e249c0e6df3de153" dependencies = [ "cfg-if", "crossbeam-utils", @@ -517,9 +484,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" dependencies = [ "cfg-if", ] @@ -536,9 +503,9 @@ dependencies = [ [[package]] name = "csv" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" dependencies = [ "csv-core", "itoa", @@ -548,31 +515,40 @@ dependencies = [ [[package]] name = "csv-core" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" dependencies = [ "memchr", ] [[package]] name = "der" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" dependencies = [ "const-oid", "pem-rfc7468", "zeroize", ] +[[package]] +name = "deranged" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +dependencies = [ + "powerfmt", +] + [[package]] name = "derive-packethandler" version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] @@ -580,7 +556,7 @@ name = "derive-packetid" version = "0.1.0" dependencies = [ "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] @@ -603,9 +579,9 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" dependencies = [ "serde", ] @@ -618,23 +594,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -645,7 +610,7 @@ checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" dependencies = [ "cfg-if", "home", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -656,18 +621,21 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "miniz_oxide", @@ -692,18 +660,18 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -715,9 +683,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -725,15 +693,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -753,27 +721,27 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-core", "futures-io", @@ -793,7 +761,7 @@ dependencies = [ "argh", "async-trait", "atomic", - "bitflags 2.4.0", + "bitflags 2.4.1", "bytes", "chrono", "console-subscriber", @@ -840,9 +808,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -851,15 +819,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -867,7 +835,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -889,9 +857,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ "ahash", "allocator-api2", @@ -899,20 +867,20 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.0", + "hashbrown 0.14.3", ] [[package]] name = "hdrhistogram" -version = "7.5.2" +version = "7.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f19b9f54f7c7f55e31401bb647626ce0cf0f67b0004982ce815b3ee72a02aa8" +checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" dependencies = [ - "base64 0.13.1", + "base64", "byteorder", "flate2", "nom", @@ -930,9 +898,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -942,9 +910,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] @@ -964,14 +932,14 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -980,9 +948,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -997,9 +965,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" @@ -1024,7 +992,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -1043,34 +1011,11 @@ dependencies = [ "tokio-io-timeout", ] -[[package]] -name = "iana-time-zone" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1088,12 +1033,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.3", ] [[package]] @@ -1106,48 +1051,28 @@ dependencies = [ ] [[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "itertools" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ - "hermit-abi", - "libc", - "windows-sys", + "either", ] [[package]] name = "itertools" -version = "0.10.5" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "js-sys" -version = "0.3.64" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" -dependencies = [ - "wasm-bindgen", -] +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "lazy_static" @@ -1160,15 +1085,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libsqlite3-sys" @@ -1183,9 +1108,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.8" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "local-ip-address" @@ -1196,14 +1121,14 @@ dependencies = [ "libc", "neli", "thiserror", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -1211,9 +1136,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "matchers" @@ -1226,24 +1151,25 @@ dependencies = [ [[package]] name = "matchit" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "md-5" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ + "cfg-if", "digest", ] [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "mime" @@ -1268,13 +1194,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1308,7 +1234,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "cfg-if", "libc", ] @@ -1373,9 +1299,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", "libm", @@ -1393,38 +1319,38 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] name = "object" -version = "0.31.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "overload" @@ -1444,15 +1370,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1472,35 +1398,35 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1535,6 +1461,12 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1547,6 +1479,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" +[[package]] +name = "pretty-hex" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6b968ed37d62e35b4febaba13bfa231b0b7929d68b8a94e65445a17e2d35f" + [[package]] name = "primitives" version = "0.1.0" @@ -1557,18 +1495,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fdd22f3b9c31b53c060df4a0613a1c7f062d4115a2b984dd15b1858f7e340d" +checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" dependencies = [ "bytes", "prost-derive", @@ -1576,22 +1514,22 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32" +checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" dependencies = [ "anyhow", - "itertools", + "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] name = "prost-types" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e081b29f63d83a4bc75cfc9f3fe424f9156cf92d8a4f0c9407cce9a1b67327cf" +checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" dependencies = [ "prost", ] @@ -1637,23 +1575,23 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.3", - "regex-syntax 0.7.4", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -1667,13 +1605,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.8.2", ] [[package]] @@ -1684,51 +1622,34 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "ring" -version = "0.16.20" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - -[[package]] -name = "ring" -version = "0.17.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babe80d5c16becf6594aa32ad2be8fe08498e7ae60b77de8df700e67f191d7e" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", "getrandom", "libc", "spin 0.9.8", - "untrusted 0.9.0", - "windows-sys", + "untrusted", + "windows-sys 0.48.0", ] [[package]] name = "rsa" -version = "0.9.2" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ - "byteorder", "const-oid", "digest", "num-bigint-dig", "num-integer", - "num-iter", "num-traits", "pkcs1", "pkcs8", @@ -1747,16 +1668,15 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.25" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4eb579851244c2c03e7c24f501c3432bed80b8f720af1d6e5b0e0f01555a035" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "errno", - "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1765,18 +1685,18 @@ version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ - "ring 0.17.3", + "ring", "rustls-webpki", "sct", ] [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.2", + "base64", ] [[package]] @@ -1785,8 +1705,8 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.3", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] @@ -1797,9 +1717,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "scopeguard" @@ -1809,12 +1729,12 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "ring", + "untrusted", ] [[package]] @@ -1834,14 +1754,14 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] name = "serde_json" -version = "1.0.103" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -1850,9 +1770,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -1861,9 +1781,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -1872,9 +1792,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -1890,9 +1810,9 @@ dependencies = [ [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", "rand_core", @@ -1900,29 +1820,39 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", ] +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "spin" version = "0.5.2" @@ -1940,9 +1870,9 @@ dependencies = [ [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", @@ -1950,11 +1880,11 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c12bc9199d1db8234678b7051747c07f517cdcf019262d1847b94ec8b1aee3e" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" dependencies = [ - "itertools", + "itertools 0.12.0", "nom", "unicode_categories", ] @@ -1994,7 +1924,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.0.0", + "indexmap 2.1.0", "log", "memchr", "once_cell", @@ -2063,8 +1993,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" dependencies = [ "atoi", - "base64 0.21.2", - "bitflags 2.4.0", + "base64", + "bitflags 2.4.1", "byteorder", "bytes", "crc", @@ -2106,8 +2036,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" dependencies = [ "atoi", - "base64 0.21.2", - "bitflags 2.4.0", + "base64", + "bitflags 2.4.1", "byteorder", "crc", "dotenvy", @@ -2165,10 +2095,11 @@ dependencies = [ [[package]] name = "stringprep" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3737bde7edce97102e0e2b15365bf7a20bfdb5f60f4f9e8d7004258a51a8da" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" dependencies = [ + "finl_unicode", "unicode-bidi", "unicode-normalization", ] @@ -2192,9 +2123,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" dependencies = [ "proc-macro2", "quote", @@ -2209,16 +2140,15 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "tempfile" -version = "3.6.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ - "autocfg", "cfg-if", "fastrand", "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2238,7 +2168,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] @@ -2253,11 +2183,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.23" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ + "deranged", "itoa", + "powerfmt", "serde", "time-core", "time-macros", @@ -2265,15 +2197,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] @@ -2295,11 +2227,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", @@ -2308,10 +2239,10 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.5", "tokio-macros", "tracing", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2326,13 +2257,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] @@ -2348,9 +2279,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -2369,7 +2300,7 @@ dependencies = [ "async-stream", "async-trait", "axum", - "base64 0.21.2", + "base64", "bytes", "h2", "http", @@ -2424,7 +2355,7 @@ name = "tq-codec" version = "0.1.0" dependencies = [ "bytes", - "pretty-hex", + "pretty-hex 0.4.0", "tokio", "tokio-stream", "tq-crypto", @@ -2504,7 +2435,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] @@ -2519,9 +2450,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -2537,27 +2468,27 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -2580,12 +2511,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" @@ -2594,9 +2519,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -2642,70 +2567,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasm-bindgen" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.32", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.32", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" - -[[package]] -name = "web-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "webpki-roots" version = "0.25.3" @@ -2741,79 +2602,136 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" +name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", ] [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "zerocopy" @@ -2832,11 +2750,11 @@ checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.41", ] [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index d07ff36..cd6c4b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,22 +31,22 @@ game = { path = "server/game" } futures = { version = "0.3", default-features = false } thiserror = "1.0" anyhow = "1.0" -serde = { version = "1.0", features = ["derive"] } -bytes = "1.5" +serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } +bytes = { version = "1.5", default-features = false } async-trait = "0.1" -tracing = "0.1" +tracing = { version = "0.1", default-features = false } dotenvy = "0.15" once_cell = "1.4" -bitflags = "2.4" +bitflags = { version = "2.4", default-features = false } argh = "0.1" -tokio-stream = "0.1.8" +tokio-stream = { version = "0.1.8", default-features = false } parking_lot = { version = "0.12.1", default-features = false, features = [] } rand = "0.8" arc-swap = { version = "1.6", features = ["weak"] } -atomic = "0.6" -bytemuck = { version = "1.13", features = ["derive"] } -chrono = { version = "0.4", default-features = false, features = ["clock"] } -num_enum = { version = "0.6", default-features = false } +atomic = { version = "0.6", default-features = false } +bytemuck = { version = "1.13", default-features = false, features = ["derive"] } +chrono = { version = "0.4", default-features = false, features = [] } +num_enum = { version = "0.7", default-features = false } bcrypt = "0.15" [workspace.dependencies.tokio] diff --git a/crates/codec/Cargo.toml b/crates/codec/Cargo.toml index ea5d9ec..a136fee 100644 --- a/crates/codec/Cargo.toml +++ b/crates/codec/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true [dependencies] bytes.workspace = true tq-crypto.workspace = true -tracing.workspace = true +tracing = { workspace = true, features = ["attributes"] } tokio-stream = { workspace = true, features = ["io-util"] } tokio = { workspace = true, default-features = false, features = ["io-util"] } -pretty-hex = "0.3" +pretty-hex = { version = "0.4", default-features = false } diff --git a/crates/db/Cargo.toml b/crates/db/Cargo.toml index 3f730dd..33e5f75 100644 --- a/crates/db/Cargo.toml +++ b/crates/db/Cargo.toml @@ -15,4 +15,9 @@ futures.workspace = true [dependencies.sqlx] workspace = true default-features = false -features = ["runtime-tokio-rustls", "sqlite", "macros"] +optional = true +features = ["sqlite"] + +[features] +default = ["sqlx"] +sqlx = ["dep:sqlx"] diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index d3611f1..4bd9b4d 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Shady Khalifa "] edition.workspace = true [dependencies] -num-traits = "0.2" -bytemuck.workspace = true +num-traits = { version = "0.2", default-features = false } +bytemuck = { workspace = true, default-features = false } diff --git a/crates/serde/src/de.rs b/crates/serde/src/de.rs index e6a2e1a..f939b7f 100644 --- a/crates/serde/src/de.rs +++ b/crates/serde/src/de.rs @@ -1,18 +1,63 @@ //! Deserializer for Binary Packets. use crate::TQSerdeError; -use bytes::Buf; use serde::de::{self, Deserialize, DeserializeSeed, SeqAccess, Visitor}; -use std::io::Cursor; + +struct SliceReader<'storage> { + slice: &'storage [u8], +} + +impl<'storage> SliceReader<'storage> { + /// Constructs a slice reader + fn new(bytes: &'storage [u8]) -> SliceReader<'storage> { + SliceReader { slice: bytes } + } + + fn get_ref(&self) -> &'storage [u8] { self.slice } + + fn get_byte_array( + &mut self, + ) -> Result<[u8; N], TQSerdeError> { + if N > self.slice.len() { + return Err(TQSerdeError::Eof); + } + let (read_slice, remaining) = self.slice.split_at(N); + self.slice = remaining; + let mut array = [0u8; N]; + array.copy_from_slice(read_slice); + Ok(array) + } + + fn get_byte(&mut self) -> Result { + if self.slice.is_empty() { + return Err(TQSerdeError::Eof); + } + let (read_slice, remaining) = self.slice.split_at(1); + self.slice = remaining; + Ok(read_slice[0]) + } + + fn get_byte_slice( + &mut self, + len: usize, + ) -> Result<&'storage [u8], TQSerdeError> { + if len > self.slice.len() { + return Err(TQSerdeError::Eof); + } + let (read_slice, remaining) = self.slice.split_at(len); + self.slice = remaining; + Ok(read_slice) + } +} struct Deserializer<'de> { - input: Cursor<&'de [u8]>, + input: SliceReader<'de>, } impl<'de> Deserializer<'de> { fn from_bytes(input: &'de [u8]) -> Self { Deserializer { - input: Cursor::new(input), + input: SliceReader::new(input), } } } @@ -22,12 +67,7 @@ where T: Deserialize<'a>, { let mut deserializer = Deserializer::from_bytes(s); - let t = T::deserialize(&mut deserializer)?; - if !deserializer.input.get_ref().is_empty() { - Ok(t) - } else { - Err(TQSerdeError::Eof) - } + T::deserialize(&mut deserializer).map_err(Into::into) } macro_rules! impl_nums { @@ -38,7 +78,9 @@ macro_rules! impl_nums { V: serde::de::Visitor<'de>, { use std::mem::size_of; - let value = self.input.get_uint_le(size_of::<$ty>()) as $ty; + const N: usize = size_of::<$ty>(); + let bytes = self.input.get_byte_array::()?; + let value = <$ty>::from_le_bytes(bytes); visitor.$visitor_method(value) } }; @@ -79,7 +121,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { V: Visitor<'de>, { // 0 = false, 1 = true - let value = self.input.get_u8(); + let value = self.input.get_byte()?; match value { 0 => visitor.visit_bool(false), 1 => visitor.visit_bool(true), @@ -91,7 +133,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { - let value = self.input.get_u8(); + let value = self.input.get_byte()?; visitor.visit_char(value as char) } @@ -106,9 +148,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { - let length = self.input.get_u8(); - let string_bytes = self.input.copy_to_bytes(length as usize); - let val = String::from_utf8_lossy(&string_bytes); + let length = self.input.get_byte()?; + let string_bytes = self.input.get_byte_slice(length as usize)?; + let val = String::from_utf8_lossy(string_bytes); let val = val.trim_end_matches('\0'); visitor.visit_string(val.to_string()) } @@ -122,7 +164,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { // and the rest of the bytes are the strings. // With that being said, we can just copy the bytes and pass it to the // visitor. - Visitor::visit_bytes(visitor, self.input.chunk()) + Visitor::visit_bytes(visitor, self.input.get_ref()) } fn deserialize_byte_buf( @@ -132,8 +174,8 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { - let length = self.input.get_u8(); - let bytes = self.input.copy_to_bytes(length as usize); + let length = self.input.get_byte()?; + let bytes = self.input.get_byte_slice(length as usize)?; visitor.visit_byte_buf(bytes.to_vec()) } @@ -293,6 +335,7 @@ impl<'de, 'a> SeqAccess<'de> for Access<'a, 'de> { fn test_struct_de() { use crate::String16; use serde::Deserialize; + #[derive(Deserialize, Debug, PartialEq)] struct MsgAccount { username: String16, diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 151a1a3..86e8f38 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,4 @@ [toolchain] channel = "nightly" components = ["rustfmt", "clippy", "rust-src"] +targets = ["wasm32-unknown-unknown"] diff --git a/server/game/src/packets/msg_data.rs b/server/game/src/packets/msg_data.rs index c14d732..d8b777f 100644 --- a/server/game/src/packets/msg_data.rs +++ b/server/game/src/packets/msg_data.rs @@ -1,6 +1,8 @@ +use std::time::{SystemTime, UNIX_EPOCH}; + use crate::state::State; use crate::{ActorState, Error}; -use chrono::{Datelike, Timelike}; +use chrono::{Datelike, NaiveDateTime, Timelike}; use num_enum::{FromPrimitive, IntoPrimitive}; use serde::{Deserialize, Serialize}; use tq_network::{Actor, PacketID, PacketProcess}; @@ -32,7 +34,15 @@ pub struct MsgData { impl MsgData { pub fn now() -> Self { - let now = chrono::Utc::now(); + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time before Unix epoch"); + let naive = NaiveDateTime::from_timestamp_opt( + now.as_secs() as i64, + now.subsec_nanos(), + ) + .unwrap(); + let now = chrono::TimeZone::from_utc_datetime(&chrono::Utc, &naive); Self { action: DataAction::SetServerTime.into(), year: now.year() - 1900, From 7c24382da0d0e0f1d5899f009f6dc7bce7ceec37 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Wed, 13 Dec 2023 18:54:26 +0200 Subject: [PATCH 02/28] network compiles to wasm --- crates/network/Cargo.toml | 13 +++++++++++-- crates/network/src/error.rs | 7 ++++--- crates/network/src/lib.rs | 2 ++ server/auth/src/packets/msg_transfer.rs | 12 ++++++------ 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/crates/network/Cargo.toml b/crates/network/Cargo.toml index b7964bc..948c4d5 100644 --- a/crates/network/Cargo.toml +++ b/crates/network/Cargo.toml @@ -14,13 +14,22 @@ tq-crypto.workspace = true async-trait.workspace = true tracing.workspace = true futures.workspace = true -tokio-stream = { workspace = true, features = ["io-util", "net"] } # macros derive-packetid.workspace = true derive-packethandler.workspace = true +[dependencies.tokio-stream] +workspace = true +default-features = false +optional = true +features = ["io-util", "net"] + [dependencies.tokio] workspace = true default-features = false -features = ["rt-multi-thread", "io-util", "net", "sync"] +features = ["io-util", "sync"] + +[features] +default = ["server"] +server = ["tokio/rt-multi-thread", "tokio/net", "dep:tokio-stream"] diff --git a/crates/network/src/error.rs b/crates/network/src/error.rs index 9050ecc..6f78055 100644 --- a/crates/network/src/error.rs +++ b/crates/network/src/error.rs @@ -1,5 +1,4 @@ use thiserror::Error; -use tokio::sync::mpsc::error::SendError; #[derive(Debug, Error)] pub enum Error { @@ -15,6 +14,8 @@ pub enum Error { Other(String), } -impl From> for Error { - fn from(_: SendError) -> Self { Self::SendError } +impl From> for Error { + fn from(_: tokio::sync::mpsc::error::SendError) -> Self { + Self::SendError + } } diff --git a/crates/network/src/lib.rs b/crates/network/src/lib.rs index c73dd32..4031a15 100644 --- a/crates/network/src/lib.rs +++ b/crates/network/src/lib.rs @@ -15,7 +15,9 @@ pub use error::Error; mod actor; pub use actor::{Actor, ActorHandle, ActorState, Message}; +#[cfg(feature = "server")] mod server; +#[cfg(feature = "server")] pub use server::Server; pub trait PacketID { diff --git a/server/auth/src/packets/msg_transfer.rs b/server/auth/src/packets/msg_transfer.rs index f45ed2e..75aecca 100644 --- a/server/auth/src/packets/msg_transfer.rs +++ b/server/auth/src/packets/msg_transfer.rs @@ -5,8 +5,8 @@ use tokio::net::TcpStream; use tokio_stream::StreamExt; use tq_db::realm::Realm; use tq_network::{ - Actor, CQCipher, IntoErrorPacket, PacketDecode, PacketEncode, PacketID, - TQCodec, + Actor, ActorState, CQCipher, IntoErrorPacket, PacketDecode, PacketEncode, + PacketID, TQCodec, }; use tracing::Instrument; @@ -24,9 +24,9 @@ pub struct MsgTransfer { impl MsgTransfer { #[tracing::instrument(skip(state, actor))] - pub async fn handle( + pub async fn handle( state: &crate::State, - actor: &Actor<()>, + actor: &Actor, realm: &str, ) -> Result { let maybe_realm = Realm::by_name(state.pool(), realm).await?; @@ -65,8 +65,8 @@ impl MsgTransfer { } #[tracing::instrument(skip(actor, stream), err, fields(realm = realm.name))] - async fn transfer( - actor: &Actor<()>, + async fn transfer( + actor: &Actor, realm: Realm, stream: TcpStream, ) -> Result { From 67e0af82e4d7b4151e1c1a02eec2a55ccaa94e47 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sat, 16 Dec 2023 17:07:25 +0200 Subject: [PATCH 03/28] Update dependencies and features to be no_std ready --- Cargo.lock | 4 +- crates/codec/Cargo.toml | 4 + crates/codec/src/lib.rs | 12 +- crates/crypto/Cargo.toml | 4 + crates/crypto/src/cq_cipher.rs | 6 +- crates/crypto/src/lib.rs | 5 + crates/crypto/src/rc5.rs | 18 +- crates/crypto/src/tq_cipher.rs | 7 +- crates/math/Cargo.toml | 6 + crates/math/src/lib.rs | 391 +++++++++++++++++++++++++++++-- crates/primitives/Cargo.toml | 4 + crates/primitives/src/lib.rs | 3 + crates/serde/Cargo.toml | 5 +- crates/serde/src/de.rs | 5 +- crates/serde/src/errors.rs | 34 ++- crates/serde/src/fixed_string.rs | 15 +- crates/serde/src/lib.rs | 6 + crates/serde/src/ser.rs | 3 + crates/serde/src/string_list.rs | 23 +- migrations/7_default_realms.sql | 2 +- 20 files changed, 492 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2786c2..c139578 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2385,6 +2385,9 @@ dependencies = [ [[package]] name = "tq-math" version = "0.1.0" +dependencies = [ + "libm", +] [[package]] name = "tq-network" @@ -2411,7 +2414,6 @@ version = "0.1.0" dependencies = [ "bytes", "serde", - "thiserror", "tq-crypto", ] diff --git a/crates/codec/Cargo.toml b/crates/codec/Cargo.toml index a136fee..c384582 100644 --- a/crates/codec/Cargo.toml +++ b/crates/codec/Cargo.toml @@ -11,3 +11,7 @@ tracing = { workspace = true, features = ["attributes"] } tokio-stream = { workspace = true, features = ["io-util"] } tokio = { workspace = true, default-features = false, features = ["io-util"] } pretty-hex = { version = "0.4", default-features = false } + +[features] +default = ["std"] +std = ["bytes/std", "tq-crypto/std", "tracing/std", "pretty-hex/alloc"] diff --git a/crates/codec/src/lib.rs b/crates/codec/src/lib.rs index ce352e8..1ee4f83 100644 --- a/crates/codec/src/lib.rs +++ b/crates/codec/src/lib.rs @@ -19,14 +19,18 @@ //! the next 2 bytes are the packet id. //! ``` +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; + use bytes::{Buf, BufMut, Bytes, BytesMut}; use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; use pretty_hex::{HexConfig, PrettyHex}; -use std::io; -use std::pin::Pin; -use std::task::{Context, Poll}; use tokio::io::{ - split, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadHalf, + self, split, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadHalf, WriteHalf, }; use tokio_stream::Stream; diff --git a/crates/crypto/Cargo.toml b/crates/crypto/Cargo.toml index 204948e..cfcf898 100644 --- a/crates/crypto/Cargo.toml +++ b/crates/crypto/Cargo.toml @@ -7,3 +7,7 @@ edition.workspace = true [dependencies] bytes.workspace = true parking_lot.workspace = true + +[features] +default = ["std"] +std = ["bytes/std"] diff --git a/crates/crypto/src/cq_cipher.rs b/crates/crypto/src/cq_cipher.rs index 6c4d4a4..0822a56 100644 --- a/crates/crypto/src/cq_cipher.rs +++ b/crates/crypto/src/cq_cipher.rs @@ -9,8 +9,12 @@ //! [1]: https://www.elitepvpers.com/forum/members/568265-cptsky.html //! [2]: https://www.elitepvpers.com/forum/co2-pserver-guides-releases/1652536-co2_core_dll-c-library.html //! [3]: https://www.conquerwiki.com/doku.php?id=conqueronlineclientasymmetriccipher +use core::sync::atomic::{AtomicU16, AtomicU8, Ordering}; use parking_lot::RwLock; -use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; + +#[cfg(not(feature = "std"))] +use alloc::sync::Arc; +#[cfg(feature = "std")] use std::sync::Arc; const KEY_SIZE: usize = 0x200; diff --git a/crates/crypto/src/lib.rs b/crates/crypto/src/lib.rs index 9f0b7a4..8622c39 100644 --- a/crates/crypto/src/lib.rs +++ b/crates/crypto/src/lib.rs @@ -3,6 +3,11 @@ //! used by `Server` for encrypting and //! decrypting data to and from the game client. +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; + mod rc5; pub use rc5::TQRC5; diff --git a/crates/crypto/src/rc5.rs b/crates/crypto/src/rc5.rs index 78b6404..7c48654 100644 --- a/crates/crypto/src/rc5.rs +++ b/crates/crypto/src/rc5.rs @@ -19,7 +19,7 @@ //! consists of a number of modular additions and eXclusive OR (XOR)s. The //! general structure of the algorithm is a Feistel-like network. -use bytes::{Buf, BufMut}; +use bytes::Buf; const SUB_KEY_SEED: [u32; 26] = [ 0xA991_5556, @@ -106,18 +106,12 @@ impl crate::Cipher for TQRC5 { ^ b; } let chunk_a = &mut data[(8 * word)..]; - let mut wtr_a = vec![]; - wtr_a.put_u32_le(a.wrapping_sub(sub[0])); - for (i, b) in wtr_a.iter().enumerate() { - chunk_a[i] = *b; - } - let chunk_b = &mut data[(8 * word + 4)..]; - let mut wtr_b = vec![]; - wtr_b.put_u32_le(b.wrapping_sub(sub[1])); + let a_bytes = a.wrapping_sub(sub[0]).to_le_bytes(); + chunk_a[..4].copy_from_slice(&a_bytes); - for (i, b) in wtr_b.iter().enumerate() { - chunk_b[i] = *b; - } + let chunk_b = &mut data[(8 * word + 4)..]; + let b_bytes = b.wrapping_sub(sub[1]).to_le_bytes(); + chunk_b[..4].copy_from_slice(&b_bytes); } } diff --git a/crates/crypto/src/tq_cipher.rs b/crates/crypto/src/tq_cipher.rs index 6243dea..884201f 100644 --- a/crates/crypto/src/tq_cipher.rs +++ b/crates/crypto/src/tq_cipher.rs @@ -10,8 +10,13 @@ //! [1]: https://www.elitepvpers.com/forum/members/568265-cptsky.html //! [2]: https://www.elitepvpers.com/forum/co2-pserver-guides-releases/2402439-cops-v6-source-tools-custom-emulator.html //! [3]: https://www.forum.darkfoxdeveloper.com/conquerwiki/doku.php?id=conqueronlineserverasymmetriccipher + +use core::sync::atomic::{AtomicU16, AtomicU8, Ordering}; use parking_lot::RwLock; -use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; + +#[cfg(not(feature = "std"))] +use alloc::sync::Arc; +#[cfg(feature = "std")] use std::sync::Arc; const KEY_SIZE: usize = 0x200; diff --git a/crates/math/Cargo.toml b/crates/math/Cargo.toml index ac0a94a..3eb5781 100644 --- a/crates/math/Cargo.toml +++ b/crates/math/Cargo.toml @@ -5,3 +5,9 @@ authors = ["Shady Khalifa "] edition.workspace = true [dependencies] +libm = { version = "0.2", default-features = false, optional = true } + +[features] +default = ["std"] +std = [] +libm = ["dep:libm"] diff --git a/crates/math/src/lib.rs b/crates/math/src/lib.rs index cd1a66d..6931658 100644 --- a/crates/math/src/lib.rs +++ b/crates/math/src/lib.rs @@ -1,11 +1,98 @@ -/// This crate contains generic and handler specific calculation functions used -/// during packet and server processing. It contains calculations for screen -/// updating, attacking, exploit checking, etc. +//! This crate contains generic and handler specific calculation functions used +//! during packet and server processing. It contains calculations for screen +//! updating, attacking, exploit checking, etc. + +#![cfg_attr(not(feature = "std"), no_std)] pub const SCREEN_DISTANCE: u16 = 18; -pub const RADIAN_TO_DEGREE: f64 = 57.29; +pub const RADIAN_TO_DEGREE: f32 = 57.29; pub const MAX_DIFFERENCE_IN_ELEVATION: u16 = 210; +fn atan2(y: f32, x: f32) -> f32 { + #[cfg(feature = "std")] + { + y.atan2(x) + } + #[cfg(all(not(feature = "std"), feature = "libm"))] + { + libm::atan2f(y, x) + } + #[cfg(not(any(feature = "std", feature = "libm")))] + { + compile_error!( + "Either the `std` or `libm` feature must be enabled to use `atan2`" + ) + } +} + +fn abs(x: f32) -> f32 { + #[cfg(feature = "std")] + { + x.abs() + } + #[cfg(all(not(feature = "std"), feature = "libm"))] + { + libm::fabsf(x) + } + #[cfg(not(any(feature = "std", feature = "libm")))] + { + compile_error!( + "Either the `std` or `libm` feature must be enabled to use `abs`" + ) + } +} + +fn pow(x: f32, y: i32) -> f32 { + #[cfg(feature = "std")] + { + x.powi(y) + } + #[cfg(all(not(feature = "std"), feature = "libm"))] + { + libm::powf(x, y as f32) + } + #[cfg(not(any(feature = "std", feature = "libm")))] + { + compile_error!( + "Either the `std` or `libm` feature must be enabled to use `powi`" + ) + } +} + +fn sqrt(x: f32) -> f32 { + #[cfg(feature = "std")] + { + x.sqrt() + } + #[cfg(all(not(feature = "std"), feature = "libm"))] + { + libm::sqrtf(x) + } + #[cfg(not(any(feature = "std", feature = "libm")))] + { + compile_error!( + "Either the `std` or `libm` feature must be enabled to use `sqrt`" + ) + } +} + +fn round(x: f32) -> f32 { + #[cfg(feature = "std")] + { + x.round() + } + #[cfg(all(not(feature = "std"), feature = "libm"))] + { + libm::roundf(x) + } + #[cfg(not(any(feature = "std", feature = "libm")))] + { + compile_error!( + "Either the `std` or `libm` feature must be enabled to use `round`" + ) + } +} + /// This function returns true if an object is within the bounds of another /// object's screen. pub fn in_screen(p1: (u16, u16), p2: (u16, u16)) -> bool { @@ -37,31 +124,31 @@ pub fn within_elevation(new: u16, initial: u16) -> bool { } /// This function returns the angle for a jump or attack. -pub fn get_angle(p1: (u16, u16), p2: (u16, u16)) -> f64 { +pub fn get_angle(p1: (u16, u16), p2: (u16, u16)) -> f32 { let (delta_x, delta_y) = delta(p1, p2); - let delta_x = delta_x as f64; - let delta_y = delta_y as f64; - let angle = (delta_y.atan2(delta_x) * RADIAN_TO_DEGREE) + 90.0; + let delta_x = delta_x as f32; + let delta_y = delta_y as f32; + let angle = (atan2(delta_y, delta_x) * RADIAN_TO_DEGREE) + 90.0; if angle.is_sign_negative() { - 270.0 + (90.0 - angle.abs()) + 270.0 + (90.0 - abs(angle)) } else { angle } } /// This function returns the distance between two objects. -pub fn get_distance(p1: (u16, u16), p2: (u16, u16)) -> f64 { - let x1 = p1.0 as f64; - let x2 = p2.0 as f64; - let y1 = p1.1 as f64; - let y2 = p2.1 as f64; - ((x2 - x1).powi(2) + (y2 - y1).powi(2)).sqrt() +pub fn get_distance(p1: (u16, u16), p2: (u16, u16)) -> f32 { + let x1 = p1.0 as f32; + let x2 = p2.0 as f32; + let y1 = p1.1 as f32; + let y2 = p2.1 as f32; + sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)) } /// This function returns the direction for a jump or attack. pub fn get_direction_sector(p1: (u16, u16), p2: (u16, u16)) -> u8 { let angle = get_angle(p1, p2); - let direction = (angle / 45.0).round() as u8; + let direction = round(angle / 45.0) as u8; if direction == 8 { 0 } else { @@ -74,9 +161,273 @@ pub fn in_circle( (center_x, center_y, r): (u16, u16, u16), (px, py): (u16, u16), ) -> bool { - let (center_x, center_y, r) = (center_x as f64, center_y as f64, r as f64); - let (px, py) = (px as f64, py as f64); - let dist_points = (px - center_x).powi(2) + (py - center_y).powi(2); - let r2 = r.powi(2); + if r == 0 { + return false; + } + let (center_x, center_y, r) = (center_x as f32, center_y as f32, r as f32); + let (px, py) = (px as f32, py as f32); + let dist_points = pow(px - center_x, 2) + pow(py - center_y, 2); + let r2 = pow(r, 2); dist_points < r2 } + +#[cfg(test)] +mod tests { + use super::*; + + /// Rounds a float to the nearest decimal place. + /// and then compares it to the expected value. + macro_rules! assert_approx_eq { + ($a:expr, $b:expr $(,)?) => { + assert_eq!($a.round(), $b); + }; + } + + #[test] + fn in_range_works() { + let p1 = (0, 0); + let p2 = (0, 0); + assert!(in_range(p1, p2, 0)); + + for i in 0..SCREEN_DISTANCE { + let p1 = (0, 0); + let p2 = (i, i); + assert!(in_range(p1, p2, SCREEN_DISTANCE)); + } + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE + 1, SCREEN_DISTANCE + 1); + assert!(!in_range(p1, p2, SCREEN_DISTANCE)); + } + + #[test] + fn in_screen_works() { + let p1 = (0, 0); + let p2 = (0, 0); + assert!(in_screen(p1, p2)); + + for i in 0..SCREEN_DISTANCE { + let p1 = (0, 0); + let p2 = (i, i); + assert!(in_screen(p1, p2)); + } + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE + 1, SCREEN_DISTANCE + 1); + assert!(!in_screen(p1, p2)); + } + + #[test] + fn delta_works() { + let p1 = (0, 0); + let p2 = (0, 0); + assert_eq!(delta(p1, p2), (0, 0)); + + let p1 = (0, 0); + let p2 = (1, 1); + assert_eq!(delta(p1, p2), (1, 1)); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + assert_eq!(delta(p1, p2), (SCREEN_DISTANCE, SCREEN_DISTANCE)); + } + + #[test] + fn within_elevation_works() { + let new = 0; + let initial = 0; + assert!(within_elevation(new, initial)); + + let new = 0; + let initial = MAX_DIFFERENCE_IN_ELEVATION; + assert!(within_elevation(new, initial)); + + let new = MAX_DIFFERENCE_IN_ELEVATION; + let initial = 0; + assert!(!within_elevation(new, initial)); + + let new = MAX_DIFFERENCE_IN_ELEVATION; + let initial = MAX_DIFFERENCE_IN_ELEVATION; + assert!(within_elevation(new, initial)); + } + + #[test] + fn get_angle_works() { + let p1 = (0, 0); + let p2 = (0, 0); + assert_approx_eq!(get_angle(p1, p2), 90.0); + + let p1 = (0, 0); + let p2 = (1, 1); + assert_approx_eq!(get_angle(p1, p2), 135.0); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + assert_approx_eq!(get_angle(p1, p2), 135.0); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE, 0); + assert_approx_eq!(get_angle(p1, p2), 90.0); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE, SCREEN_DISTANCE * 2); + assert_approx_eq!(get_angle(p1, p2), 153.0); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE * 2, SCREEN_DISTANCE); + assert_approx_eq!(get_angle(p1, p2), 117.0); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE * 2, SCREEN_DISTANCE * 2); + assert_approx_eq!(get_angle(p1, p2), 135.0); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE * 2, 0); + assert_approx_eq!(get_angle(p1, p2), 90.0); + + let p1 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + let p2 = (SCREEN_DISTANCE * 2, SCREEN_DISTANCE * 2); + assert_approx_eq!(get_angle(p1, p2), 135.0); + + let p1 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + let p2 = (SCREEN_DISTANCE * 2, SCREEN_DISTANCE); + assert_approx_eq!(get_angle(p1, p2), 90.0); + + let p1 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + let p2 = (0, 0); + assert_approx_eq!(get_angle(p1, p2), 135.0); + } + + #[test] + fn get_distance_works() { + let p1 = (0, 0); + let p2 = (0, 0); + assert_approx_eq!(get_distance(p1, p2), 0.0); + + let p1 = (0, 0); + let p2 = (1, 1); + assert_approx_eq!(get_distance(p1, p2), 1.0); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + assert_approx_eq!(get_distance(p1, p2), 25.0); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE, 0); + assert_approx_eq!(get_distance(p1, p2), 18.0); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE, SCREEN_DISTANCE * 2); + assert_approx_eq!(get_distance(p1, p2), 40.0); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE * 2, SCREEN_DISTANCE); + assert_approx_eq!(get_distance(p1, p2), 40.0); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE * 2, SCREEN_DISTANCE * 2); + assert_approx_eq!(get_distance(p1, p2), 51.0); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE * 2, 0); + assert_approx_eq!(get_distance(p1, p2), 36.0); + + let p1 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + let p2 = (SCREEN_DISTANCE * 2, SCREEN_DISTANCE * 2); + assert_approx_eq!(get_distance(p1, p2), 25.0); + + let p1 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + let p2 = (SCREEN_DISTANCE * 2, SCREEN_DISTANCE); + assert_approx_eq!(get_distance(p1, p2), 18.0); + + let p1 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + let p2 = (0, 0); + assert_approx_eq!(get_distance(p1, p2), 25.0); + } + + #[test] + fn get_direction_sector_works() { + let p1 = (0, 0); + let p2 = (0, 0); + assert_eq!(get_direction_sector(p1, p2), 2); + + let p1 = (0, 0); + let p2 = (1, 1); + assert_eq!(get_direction_sector(p1, p2), 3); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + assert_eq!(get_direction_sector(p1, p2), 3); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE, 0); + assert_eq!(get_direction_sector(p1, p2), 2); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE, SCREEN_DISTANCE * 2); + assert_eq!(get_direction_sector(p1, p2), 3); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE * 2, SCREEN_DISTANCE); + assert_eq!(get_direction_sector(p1, p2), 3); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE * 2, SCREEN_DISTANCE * 2); + assert_eq!(get_direction_sector(p1, p2), 3); + + let p1 = (0, 0); + let p2 = (SCREEN_DISTANCE * 2, 0); + assert_eq!(get_direction_sector(p1, p2), 2); + + let p1 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + let p2 = (SCREEN_DISTANCE * 2, SCREEN_DISTANCE * 2); + assert_eq!(get_direction_sector(p1, p2), 3); + + let p1 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + let p2 = (SCREEN_DISTANCE * 2, SCREEN_DISTANCE); + assert_eq!(get_direction_sector(p1, p2), 2); + + let p1 = (SCREEN_DISTANCE, SCREEN_DISTANCE); + let p2 = (0, 0); + assert_eq!(get_direction_sector(p1, p2), 3); + } + + #[test] + fn in_circle_works() { + let center = (0, 0, 0); + let point = (0, 0); + assert!(!in_circle(center, point)); + + let center = (0, 0, 0); + let point = (1, 1); + assert!(!in_circle(center, point)); + + let center = (0, 0, 0); + let point = (SCREEN_DISTANCE, SCREEN_DISTANCE); + assert!(!in_circle(center, point)); + + let center = (0, 0, 0); + let point = (SCREEN_DISTANCE + 1, SCREEN_DISTANCE + 1); + assert!(!in_circle(center, point)); + + let center = (0, 0, SCREEN_DISTANCE); + let point = (0, 0); + assert!(in_circle(center, point)); + + let center = (0, 0, SCREEN_DISTANCE); + let point = (1, 1); + assert!(in_circle(center, point)); + + let center = (0, 0, SCREEN_DISTANCE); + let point = (SCREEN_DISTANCE, SCREEN_DISTANCE); + assert!(!in_circle(center, point)); + + let center = (0, 0, SCREEN_DISTANCE); + let point = (SCREEN_DISTANCE + 1, SCREEN_DISTANCE + 1); + assert!(!in_circle(center, point)); + + let center = (0, 0, SCREEN_DISTANCE); + let point = (4, 6); + assert!(in_circle(center, point)); + } +} diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 4bd9b4d..b01ba3e 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -7,3 +7,7 @@ edition.workspace = true [dependencies] num-traits = { version = "0.2", default-features = false } bytemuck = { workspace = true, default-features = false } + +[features] +default = ["std"] +std = ["num-traits/std"] diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index bfe2ab3..e292ec4 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -1,3 +1,6 @@ +//! Primitives used by the game engine and game server. +#![cfg_attr(not(feature = "std"), no_std)] + use bytemuck::NoUninit; use core::fmt; use num_traits::PrimInt; diff --git a/crates/serde/Cargo.toml b/crates/serde/Cargo.toml index 276d232..036f3c6 100644 --- a/crates/serde/Cargo.toml +++ b/crates/serde/Cargo.toml @@ -5,10 +5,13 @@ authors = ["Shady Khalifa "] edition.workspace = true [dependencies] -thiserror.workspace = true bytes.workspace = true serde.workspace = true tq-crypto.workspace = true [dev-dependencies] serde = { workspace = true, features = ["derive"] } + +[features] +default = ["std"] +std = ["bytes/std", "serde/std", "tq-crypto/std"] diff --git a/crates/serde/src/de.rs b/crates/serde/src/de.rs index f939b7f..31d2cd9 100644 --- a/crates/serde/src/de.rs +++ b/crates/serde/src/de.rs @@ -3,6 +3,9 @@ use crate::TQSerdeError; use serde::de::{self, Deserialize, DeserializeSeed, SeqAccess, Visitor}; +#[cfg(not(feature = "std"))] +use alloc::string::{String, ToString}; + struct SliceReader<'storage> { slice: &'storage [u8], } @@ -77,7 +80,7 @@ macro_rules! impl_nums { where V: serde::de::Visitor<'de>, { - use std::mem::size_of; + use core::mem::size_of; const N: usize = size_of::<$ty>(); let bytes = self.input.get_byte_array::()?; let value = <$ty>::from_le_bytes(bytes); diff --git a/crates/serde/src/errors.rs b/crates/serde/src/errors.rs index 9685174..6c253bd 100644 --- a/crates/serde/src/errors.rs +++ b/crates/serde/src/errors.rs @@ -1,26 +1,40 @@ //! Handle Errors. +use core::fmt::Display; use serde::{de, ser}; -use std::fmt::Display; -use thiserror::Error; + +#[cfg(not(feature = "std"))] +use alloc::string::{String, ToString}; /// Represents Any Errors that could happens while Serializing/Deserializing /// Binary Packets. -#[derive(Clone, Debug, Error)] +#[derive(Clone, Debug)] pub enum TQSerdeError { - #[error("{}", _0)] Message(String), - #[error(transparent)] - Utf8Error(#[from] std::str::Utf8Error), - #[error("Invalid Boolean Value")] + Utf8Error(core::str::Utf8Error), InvalidBool, - #[error("EOF")] Eof, - #[error("Deserializing Any Not Supported")] DeserializeAnyNotSupported, - #[error("Unspported Type")] Unspported, } +impl Display for TQSerdeError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + TQSerdeError::Message(msg) => write!(f, "{}", msg), + TQSerdeError::Utf8Error(err) => write!(f, "{}", err), + TQSerdeError::InvalidBool => write!(f, "Invalid Boolean Value"), + TQSerdeError::Eof => write!(f, "EOF"), + TQSerdeError::DeserializeAnyNotSupported => { + write!(f, "Deserializing Any Not Supported") + }, + TQSerdeError::Unspported => write!(f, "Unspported Type"), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for TQSerdeError {} + impl ser::Error for TQSerdeError { fn custom(msg: T) -> Self { TQSerdeError::Message(msg.to_string()) diff --git a/crates/serde/src/fixed_string.rs b/crates/serde/src/fixed_string.rs index 5c84112..559b45d 100644 --- a/crates/serde/src/fixed_string.rs +++ b/crates/serde/src/fixed_string.rs @@ -1,10 +1,13 @@ //! A Fixed Length String, used in Binary Packets use core::fmt; +use core::marker::PhantomData; +use core::ops::Deref; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::marker::PhantomData; -use std::ops::Deref; use tq_crypto::{Cipher, TQRC5}; +#[cfg(not(feature = "std"))] +use alloc::string::String; + /// Fixed Length String. #[derive(Clone, Default, PartialEq, Eq)] pub struct FixedString { @@ -100,7 +103,7 @@ impl<'de> Deserialize<'de> for FixedString<10, ClearText> { ) -> Result { let slice: [u8; 10] = Deserialize::deserialize(deserializer)?; let result = - std::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; + core::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; let result = result.trim_end_matches('\0'); Ok(result.into()) } @@ -112,7 +115,7 @@ impl<'de> Deserialize<'de> for FixedString<16, ClearText> { ) -> Result { let slice: [u8; 16] = Deserialize::deserialize(deserializer)?; let result = - std::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; + core::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; let result = result.trim_end_matches('\0'); Ok(result.into()) } @@ -124,7 +127,7 @@ impl<'de> Deserialize<'de> for FixedString<16, Masked> { ) -> Result { let slice: [u8; 16] = Deserialize::deserialize(deserializer)?; let result = - std::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; + core::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; let result = result.trim_end_matches('\0'); Ok(result.into()) } @@ -138,7 +141,7 @@ impl<'de> Deserialize<'de> for FixedString<16, Encrypted> { let rc5 = TQRC5::new(); rc5.decrypt(&mut slice); let result = - std::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; + core::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; let result = result.trim_end_matches('\0'); Ok(result.into()) } diff --git a/crates/serde/src/lib.rs b/crates/serde/src/lib.rs index 6135aee..53b4a6d 100644 --- a/crates/serde/src/lib.rs +++ b/crates/serde/src/lib.rs @@ -1,6 +1,12 @@ //! This Crate is used to create a Binary Serialization and Deserialization on //! top of [serde](https://serde.rs). //! It will be use to Serialize and Deserialize Conquer Online Binary Packets. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; + mod errors; pub use errors::TQSerdeError; diff --git a/crates/serde/src/ser.rs b/crates/serde/src/ser.rs index 7ca509d..f939e1b 100644 --- a/crates/serde/src/ser.rs +++ b/crates/serde/src/ser.rs @@ -3,6 +3,9 @@ use crate::TQSerdeError; use bytes::{BufMut, BytesMut}; use serde::ser::{self, Serialize}; +#[cfg(not(feature = "std"))] +use alloc::string::ToString; + #[derive(Debug)] struct Serializer { output: BytesMut, diff --git a/crates/serde/src/string_list.rs b/crates/serde/src/string_list.rs index 908b292..485452d 100644 --- a/crates/serde/src/string_list.rs +++ b/crates/serde/src/string_list.rs @@ -29,6 +29,15 @@ use bytes::Buf; +#[cfg(feature = "std")] +use std::vec; + +#[cfg(not(feature = "std"))] +use alloc::{ + string::{String, ToString}, + vec::{self, Vec}, +}; + /// Defines a type that serializes to a list of strings. /// /// Read the [module level documentation](index.html) for more information. @@ -37,8 +46,8 @@ pub struct StringList { inner: Vec, } -impl std::fmt::Debug for StringList { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl core::fmt::Debug for StringList { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { if self.inner.is_empty() { return write!(f, "[]"); } @@ -115,7 +124,7 @@ impl> FromIterator for StringList { } impl IntoIterator for StringList { - type IntoIter = std::vec::IntoIter; + type IntoIter = vec::IntoIter; type Item = String; fn into_iter(self) -> Self::IntoIter { self.inner.into_iter() } @@ -158,8 +167,8 @@ impl<'de> serde::Deserialize<'de> for StringList { fn expecting( &self, - formatter: &mut std::fmt::Formatter, - ) -> std::fmt::Result { + formatter: &mut core::fmt::Formatter, + ) -> core::fmt::Result { formatter.write_str("a list of strings") } @@ -173,10 +182,10 @@ impl<'de> serde::Deserialize<'de> for StringList { for _ in 0..len { let string_len = reader.get_u8() as usize; let string_bytes = reader.copy_to_bytes(string_len); - let string = std::str::from_utf8(&string_bytes) + let string = core::str::from_utf8(&string_bytes) .map(|s| s.trim_end_matches('\0')) .map_err(serde::de::Error::custom)?; - strings.push(string.to_owned()); + strings.push(string.to_string()); } Ok(StringList { inner: strings }) } diff --git a/migrations/7_default_realms.sql b/migrations/7_default_realms.sql index 68d5666..a34bd24 100644 --- a/migrations/7_default_realms.sql +++ b/migrations/7_default_realms.sql @@ -2,7 +2,7 @@ INSERT INTO realms (name, game_ip_address, game_port) VALUES ( 'CoEmu', - '192.168.0.110', + '192.168.0.200', -- Change this to your server's IP address 5816 ) ON CONFLICT(name) DO NOTHING; From 665ed578d5e0351adfa2563c280aa381f0c1b9b4 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Mon, 18 Dec 2023 22:41:38 +0200 Subject: [PATCH 04/28] Split network into two different crates --- Cargo.lock | 21 +++++++++++- Cargo.toml | 3 +- crates/network/Cargo.toml | 11 +++++-- crates/network/src/actor.rs | 14 +++++--- crates/network/src/error.rs | 31 ++++++++++++------ crates/network/src/lib.rs | 29 +++++++++++------ crates/server/Cargo.toml | 26 +++++++++++++++ crates/server/src/error.rs | 32 +++++++++++++++++++ .../src/server.rs => server/src/lib.rs} | 15 +++++---- macros/derive-packethandler/src/lib.rs | 1 + server/auth/Cargo.toml | 7 ++-- server/auth/src/error.rs | 2 ++ server/auth/src/main.rs | 8 +++-- server/game/Cargo.toml | 7 ++-- server/game/src/error.rs | 7 ++++ server/game/src/main.rs | 8 +++-- 16 files changed, 174 insertions(+), 48 deletions(-) create mode 100644 crates/server/Cargo.toml create mode 100644 crates/server/src/error.rs rename crates/{network/src/server.rs => server/src/lib.rs} (96%) diff --git a/Cargo.lock b/Cargo.lock index c139578..acd969a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,6 +166,7 @@ dependencies = [ "tq-db", "tq-network", "tq-serde", + "tq-server", "tracing", "tracing-subscriber", ] @@ -743,6 +744,7 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-sink", @@ -781,6 +783,7 @@ dependencies = [ "tq-math", "tq-network", "tq-serde", + "tq-server", "tracing", "tracing-subscriber", ] @@ -2399,7 +2402,6 @@ dependencies = [ "derive-packetid", "futures", "serde", - "thiserror", "tokio", "tokio-stream", "tq-codec", @@ -2417,6 +2419,23 @@ dependencies = [ "tq-crypto", ] +[[package]] +name = "tq-server" +version = "0.1.0" +dependencies = [ + "async-trait", + "bytes", + "futures", + "serde", + "tokio", + "tokio-stream", + "tq-codec", + "tq-crypto", + "tq-network", + "tq-serde", + "tracing", +] + [[package]] name = "tracing" version = "0.1.40" diff --git a/Cargo.toml b/Cargo.toml index cd6c4b8..9f12517 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ tq-math = { path = "crates/math" } tq-crypto = { path = "crates/crypto" } tq-codec = { path = "crates/codec" } tq-db = { path = "crates/db" } +tq-server = { path = "crates/server" } derive-packetid = { path = "macros/derive-packetid" } derive-packethandler = { path = "macros/derive-packethandler" } @@ -33,7 +34,7 @@ thiserror = "1.0" anyhow = "1.0" serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } bytes = { version = "1.5", default-features = false } -async-trait = "0.1" +async-trait = { version = "0.1", default-features = false } tracing = { version = "0.1", default-features = false } dotenvy = "0.15" once_cell = "1.4" diff --git a/crates/network/Cargo.toml b/crates/network/Cargo.toml index 948c4d5..504974b 100644 --- a/crates/network/Cargo.toml +++ b/crates/network/Cargo.toml @@ -5,7 +5,6 @@ authors = ["Shady Khalifa "] edition.workspace = true [dependencies] -thiserror.workspace = true serde.workspace = true bytes.workspace = true tq-serde.workspace = true @@ -31,5 +30,11 @@ default-features = false features = ["io-util", "sync"] [features] -default = ["server"] -server = ["tokio/rt-multi-thread", "tokio/net", "dep:tokio-stream"] +default = [] +std = [ + "tq-serde/std", + "tq-codec/std", + "tq-crypto/std", + "tracing/std", + "futures/std" +] diff --git a/crates/network/src/actor.rs b/crates/network/src/actor.rs index 72606af..1e8164b 100644 --- a/crates/network/src/actor.rs +++ b/crates/network/src/actor.rs @@ -1,14 +1,18 @@ use crate::{Error, PacketEncode}; use async_trait::async_trait; use bytes::Bytes; +use core::hash::Hash; +use core::ops::Deref; +use core::sync::atomic::{AtomicUsize, Ordering}; use futures::TryFutureExt; -use std::hash::Hash; -use std::ops::Deref; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; use tokio::sync::mpsc::Sender; use tracing::instrument; +#[cfg(not(feature = "std"))] +use alloc::{sync::Arc, boxed::Box}; +#[cfg(feature = "std")] +use std::sync::Arc; + #[derive(Clone, Debug)] pub enum Message { GenerateKeys(u64), @@ -35,7 +39,7 @@ pub struct ActorHandle { } impl Hash for Actor { - fn hash(&self, state: &mut H) { + fn hash(&self, state: &mut H) { self.handle.id.load(Ordering::Relaxed).hash(state); } } diff --git a/crates/network/src/error.rs b/crates/network/src/error.rs index 6f78055..496498d 100644 --- a/crates/network/src/error.rs +++ b/crates/network/src/error.rs @@ -1,21 +1,32 @@ -use thiserror::Error; +#[cfg(not(feature = "std"))] +use alloc::string::String; -#[derive(Debug, Error)] +#[derive(Debug)] pub enum Error { - #[error(transparent)] - TQSerde(#[from] tq_serde::TQSerdeError), - #[error("Actor Send Error!")] + TQSerde(tq_serde::TQSerdeError), SendError, - #[error(transparent)] - AddrParseError(#[from] std::net::AddrParseError), - #[error(transparent)] - IO(#[from] std::io::Error), - #[error("{}", _0)] Other(String), } +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::TQSerde(e) => write!(f, "TQSerde Error: {}", e), + Self::SendError => write!(f, "Send Error"), + Self::Other(e) => write!(f, "{}", e), + } + } +} + +impl From for Error { + fn from(e: tq_serde::TQSerdeError) -> Self { Self::TQSerde(e) } +} + impl From> for Error { fn from(_: tokio::sync::mpsc::error::SendError) -> Self { Self::SendError } } + +#[cfg(feature = "std")] +impl std::error::Error for Error {} diff --git a/crates/network/src/lib.rs b/crates/network/src/lib.rs index 4031a15..14b9b51 100644 --- a/crates/network/src/lib.rs +++ b/crates/network/src/lib.rs @@ -1,7 +1,17 @@ +//! This crate contains the core networking components used by the server and +//! client crates. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; + +#[cfg(not(feature = "std"))] +use alloc::boxed::Box; + use bytes::Bytes; use serde::de::DeserializeOwned; use serde::Serialize; -use std::error::Error as StdError; pub use async_trait::async_trait; pub use derive_packethandler::PacketHandler; @@ -15,18 +25,17 @@ pub use error::Error; mod actor; pub use actor::{Actor, ActorHandle, ActorState, Message}; -#[cfg(feature = "server")] -mod server; -#[cfg(feature = "server")] -pub use server::Server; - +/// Assoucitates a packet structure with a packet ID. This is used for +/// serialization and deserialization of packets. The packet ID is used to +/// identify the packet type, and the packet structure is used to serialize and +/// deserialize the packet. pub trait PacketID { const PACKET_ID: u16; } #[async_trait] pub trait PacketProcess { - type Error: StdError; + type Error; type ActorState: ActorState; type State: Send + Sync; /// Process can be invoked by a packet after decode has been called to @@ -41,7 +50,7 @@ pub trait PacketProcess { } pub trait PacketEncode { - type Error: StdError + From; + type Error: From + core::fmt::Debug; /// The Packet that we will encode. type Packet: Serialize + PacketID; /// Encodes the packet structure defined by this message struct into a byte @@ -52,7 +61,7 @@ pub trait PacketEncode { } pub trait PacketDecode { - type Error: StdError; + type Error: From + core::fmt::Debug; /// The Packet that we will Decode into. type Packet: DeserializeOwned; /// Decodes a byte packet into the packet structure defined by this message @@ -64,7 +73,7 @@ pub trait PacketDecode { #[async_trait] pub trait PacketHandler { - type Error: StdError + PacketEncode + Send + Sync; + type Error: PacketEncode + Send + Sync; type ActorState: ActorState; type State: Send + Sync + 'static; async fn handle( diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml new file mode 100644 index 0000000..1db0a29 --- /dev/null +++ b/crates/server/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "tq-server" +version = "0.1.0" +authors = ["Shady Khalifa "] +edition.workspace = true + +[dependencies] +serde.workspace = true +bytes.workspace = true +tq-serde.workspace = true +tq-codec.workspace = true +tq-crypto.workspace = true +tq-network.workspace = true +async-trait.workspace = true +tracing.workspace = true +futures.workspace = true + +[dependencies.tokio-stream] +workspace = true +default-features = false +features = ["io-util", "net"] + +[dependencies.tokio] +workspace = true +default-features = false +features = ["io-util", "sync"] diff --git a/crates/server/src/error.rs b/crates/server/src/error.rs new file mode 100644 index 0000000..58ef0d5 --- /dev/null +++ b/crates/server/src/error.rs @@ -0,0 +1,32 @@ +#[derive(Debug)] +pub enum Error { + TQNetwork(tq_network::Error), + AddrParseError(std::net::AddrParseError), + IO(std::io::Error), + Internal(Box), +} + +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::TQNetwork(e) => write!(f, "TQNetwork Error: {}", e), + Self::AddrParseError(e) => write!(f, "AddrParse Error: {}", e), + Self::IO(e) => write!(f, "IO Error: {}", e), + Self::Internal(s) => write!(f, "Internal Error: {}", s), + } + } +} + +impl From for Error { + fn from(e: tq_network::Error) -> Self { Self::TQNetwork(e) } +} + +impl From for Error { + fn from(e: std::net::AddrParseError) -> Self { Self::AddrParseError(e) } +} + +impl From for Error { + fn from(e: std::io::Error) -> Self { Self::IO(e) } +} + +impl std::error::Error for Error {} diff --git a/crates/network/src/server.rs b/crates/server/src/lib.rs similarity index 96% rename from crates/network/src/server.rs rename to crates/server/src/lib.rs index 9939780..b432665 100644 --- a/crates/network/src/server.rs +++ b/crates/server/src/lib.rs @@ -1,6 +1,7 @@ -use crate::actor::Message; -use crate::{Actor, ActorState, Error, PacketHandler}; +//! This crate contains Creating Servers common code. + use async_trait::async_trait; +use tq_network::{ActorState, PacketHandler, Actor, Message}; use std::fmt::Debug; use std::net::SocketAddr; use std::ops::Deref; @@ -12,8 +13,11 @@ use tokio_stream::StreamExt; use tq_codec::{TQCodec, TQEncoder}; use tq_crypto::Cipher; +mod error; +pub use error::Error; + #[async_trait] -pub trait Server: Sized + Send + Sync { +pub trait TQServer: Sized + Send + Sync { type Cipher: Cipher; type ActorState: ActorState; type PacketHandler: PacketHandler; @@ -114,7 +118,7 @@ pub trait Server: Sized + Send + Sync { } #[tracing::instrument(skip_all, err)] -async fn handle_stream( +async fn handle_stream( stream: TcpStream, state: &::State, actor: &Actor, @@ -134,8 +138,7 @@ async fn handle_stream( { let result = actor .send(err) - .await - .map_err(|e| Error::Other(e.to_string())); + .await; if let Err(e) = result { tracing::error!( ?e, diff --git a/macros/derive-packethandler/src/lib.rs b/macros/derive-packethandler/src/lib.rs index 43d1582..a994d41 100644 --- a/macros/derive-packethandler/src/lib.rs +++ b/macros/derive-packethandler/src/lib.rs @@ -3,6 +3,7 @@ use quote::quote; use syn::parse::{Parse, ParseStream}; use syn::{parse_macro_input, Data, DataEnum, DeriveInput, Expr, Ident, Token}; +#[derive(Debug, Clone)] struct Args { actor_state: Expr, state: Expr, diff --git a/server/auth/Cargo.toml b/server/auth/Cargo.toml index 4d58a86..aaeffbf 100644 --- a/server/auth/Cargo.toml +++ b/server/auth/Cargo.toml @@ -16,15 +16,16 @@ path = "src/lib.rs" thiserror.workspace = true serde.workspace = true bytes.workspace = true -tq-network.workspace = true -tq-serde.workspace = true +tq-network = { workspace = true, features = ["std"] } +tq-serde = { workspace = true, features = ["std"] } tq-db.workspace = true +tq-server.workspace = true async-trait.workspace = true tracing.workspace = true dotenvy.workspace = true once_cell.workspace = true -num_enum = { workspace = true, default-features = false } tokio-stream.workspace = true +num_enum = { workspace = true, default-features = false } [dependencies.tracing-subscriber] version = "0.3" diff --git a/server/auth/src/error.rs b/server/auth/src/error.rs index 4087dcf..eed6a56 100644 --- a/server/auth/src/error.rs +++ b/server/auth/src/error.rs @@ -7,6 +7,8 @@ pub enum Error { #[error(transparent)] Network(#[from] tq_network::Error), #[error(transparent)] + Server(#[from] tq_server::Error), + #[error(transparent)] IO(#[from] std::io::Error), #[error(transparent)] DotEnv(#[from] dotenvy::Error), diff --git a/server/auth/src/main.rs b/server/auth/src/main.rs index da4e4ab..1c5b553 100644 --- a/server/auth/src/main.rs +++ b/server/auth/src/main.rs @@ -5,14 +5,15 @@ //! will be transferred to the message server of their choice. use std::env; -use tq_network::{PacketHandler, Server, TQCipher}; +use tq_network::{PacketHandler, TQCipher}; +use tq_server::TQServer; use auth::packets::{MsgAccount, MsgConnect}; use auth::{Error, State}; struct AuthServer; -impl Server for AuthServer { +impl TQServer for AuthServer { type ActorState = (); type Cipher = TQCipher; type PacketHandler = AuthServerHandler; @@ -42,7 +43,7 @@ async fn main() -> Result<(), Error> { \____/ \___/ \____/|_| |_| |_| \__,_| -Copyright 2020-2022 Shady Khalifa (@shekohex) +Copyright 2020-2023 Shady Khalifa (@shekohex) All Rights Reserved. "# ); @@ -85,6 +86,7 @@ fn setup_logger(verbosity: i32) -> Result<(), Error> { .add_directive(format!("tq_crypto={}", log_level).parse().unwrap()) .add_directive(format!("tq_codec={}", log_level).parse().unwrap()) .add_directive(format!("tq_network={}", log_level).parse().unwrap()) + .add_directive(format!("tq_server={}", log_level).parse().unwrap()) .add_directive(format!("auth={}", log_level).parse().unwrap()) .add_directive(format!("auth_server={}", log_level).parse().unwrap()); let logger = tracing_subscriber::fmt() diff --git a/server/game/Cargo.toml b/server/game/Cargo.toml index 6aac155..c99ae1f 100644 --- a/server/game/Cargo.toml +++ b/server/game/Cargo.toml @@ -15,12 +15,13 @@ path = "src/lib.rs" [dependencies] thiserror.workspace = true -serde = { workspace = true, features = ["derive"] } +serde.workspace = true bytes.workspace = true -tq-network.workspace = true -tq-serde.workspace = true +tq-network = { workspace = true, features = ["std"] } +tq-serde = { workspace = true, features = ["std"] } tq-math.workspace = true tq-db.workspace = true +tq-server.workspace = true primitives.workspace = true async-trait.workspace = true tracing.workspace = true diff --git a/server/game/src/error.rs b/server/game/src/error.rs index 060dec8..541ce37 100644 --- a/server/game/src/error.rs +++ b/server/game/src/error.rs @@ -10,6 +10,8 @@ pub enum Error { #[error(transparent)] Network(#[from] tq_network::Error), #[error(transparent)] + Server(#[from] tq_server::Error), + #[error(transparent)] IO(#[from] std::io::Error), #[error(transparent)] DotEnv(#[from] dotenvy::Error), @@ -190,3 +192,8 @@ impl PacketEncode for Error { impl From for tq_network::Error { fn from(v: Error) -> Self { Self::Other(v.to_string()) } } + + +impl From for tq_server::Error { + fn from(v: Error) -> Self { Self::Internal(Box::new(v)) } +} diff --git a/server/game/src/main.rs b/server/game/src/main.rs index 092cbc6..61de6fb 100644 --- a/server/game/src/main.rs +++ b/server/game/src/main.rs @@ -7,7 +7,8 @@ use async_trait::async_trait; use std::env; -use tq_network::{Actor, ActorState as _, PacketHandler, Server, TQCipher}; +use tq_network::{Actor, ActorState as _, PacketHandler, TQCipher}; +use tq_server::TQServer; use game::packets::*; use game::{ActorState, Error, State}; @@ -15,7 +16,7 @@ use game::{ActorState, Error, State}; struct GameServer; #[async_trait] -impl Server for GameServer { +impl TQServer for GameServer { type ActorState = ActorState; type Cipher = TQCipher; type PacketHandler = Handler; @@ -26,7 +27,7 @@ impl Server for GameServer { async fn on_disconnected( state: &::State, actor: Actor, - ) -> Result<(), tq_network::Error> { + ) -> Result<(), tq_server::Error> { if let Ok(entity) = actor.try_entity() { let me = entity.as_character().ok_or(Error::CharacterNotFound)?; let mymap_id = me.entity().map_id(); @@ -128,6 +129,7 @@ fn setup_logger(verbosity: i32) -> Result<(), Error> { .add_directive(format!("tq_crypto={}", log_level).parse().unwrap()) .add_directive(format!("tq_codec={}", log_level).parse().unwrap()) .add_directive(format!("tq_network={}", log_level).parse().unwrap()) + .add_directive(format!("tq_server={}", log_level).parse().unwrap()) .add_directive(format!("game={}", log_level).parse().unwrap()) .add_directive(format!("game_server={}", log_level).parse().unwrap()); From 3ad21454a125c2e2f0d8d380c5dd848041f8ad8a Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Mon, 18 Dec 2023 22:42:48 +0200 Subject: [PATCH 05/28] update deps --- Cargo.lock | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index acd969a..8248a8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,9 +426,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cpufeatures" @@ -931,11 +931,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -980,9 +980,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -995,7 +995,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2", "tokio", "tower-service", "tracing", @@ -1836,16 +1836,6 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.5" @@ -2156,18 +2146,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", @@ -2242,7 +2232,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2", "tokio-macros", "tracing", "windows-sys 0.48.0", @@ -2756,18 +2746,18 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "zerocopy" -version = "0.7.30" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7" +checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.30" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba" +checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" dependencies = [ "proc-macro2", "quote", From eea8311234a7a56cc856a60df1175c0f7ecbbb37 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Wed, 20 Dec 2023 00:01:45 +0200 Subject: [PATCH 06/28] Moving to crate per packet --- Cargo.lock | 50 ++++++++++++ Cargo.toml | 8 ++ crates/network/src/actor.rs | 2 +- crates/network/src/error.rs | 2 +- crates/server/src/lib.rs | 6 +- crates/system/Cargo.toml | 14 ++++ crates/system/src/lib.rs | 32 ++++++++ packets/account/Cargo.toml | 33 ++++++++ packets/account/src/functions.rs | 1 + packets/account/src/lib.rs | 102 +++++++++++++++++++++++++ packets/account/src/traits.rs | 4 + packets/account/src/types.rs | 1 + packets/connect-ex/Cargo.toml | 18 +++++ packets/connect-ex/src/lib.rs | 77 +++++++++++++++++++ packets/transfer/Cargo.toml | 32 ++++++++ packets/transfer/src/functions.rs | 68 +++++++++++++++++ packets/transfer/src/lib.rs | 97 +++++++++++++++++++++++ packets/transfer/src/traits.rs | 27 +++++++ packets/transfer/src/types.rs | 9 +++ server/auth/src/packets/msg_connect.rs | 1 + server/game/src/error.rs | 1 - 21 files changed, 578 insertions(+), 7 deletions(-) create mode 100644 crates/system/Cargo.toml create mode 100644 crates/system/src/lib.rs create mode 100644 packets/account/Cargo.toml create mode 100644 packets/account/src/functions.rs create mode 100644 packets/account/src/lib.rs create mode 100644 packets/account/src/traits.rs create mode 100644 packets/account/src/types.rs create mode 100644 packets/connect-ex/Cargo.toml create mode 100644 packets/connect-ex/src/lib.rs create mode 100644 packets/transfer/Cargo.toml create mode 100644 packets/transfer/src/functions.rs create mode 100644 packets/transfer/src/lib.rs create mode 100644 packets/transfer/src/traits.rs create mode 100644 packets/transfer/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 8248a8b..0f7d68e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1206,6 +1206,48 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "msg-account" +version = "0.1.0" +dependencies = [ + "async-trait", + "msg-connect-ex", + "msg-transfer", + "serde", + "tq-codec", + "tq-crypto", + "tq-network", + "tq-serde", + "tq-system", + "tracing", +] + +[[package]] +name = "msg-connect-ex" +version = "0.1.0" +dependencies = [ + "num_enum", + "serde", + "tq-network", + "tq-serde", +] + +[[package]] +name = "msg-transfer" +version = "0.1.0" +dependencies = [ + "async-trait", + "bytes", + "msg-connect-ex", + "serde", + "tq-codec", + "tq-crypto", + "tq-network", + "tq-serde", + "tq-system", + "tracing", +] + [[package]] name = "neli" version = "0.6.4" @@ -2426,6 +2468,14 @@ dependencies = [ "tracing", ] +[[package]] +name = "tq-system" +version = "0.1.0" +dependencies = [ + "async-trait", + "tq-network", +] + [[package]] name = "tracing" version = "0.1.40" diff --git a/Cargo.toml b/Cargo.toml index 9f12517..a19bbc6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,8 @@ package.edition = "2021" resolver = "2" members = [ "crates/*", + # Game Packets + "packets/*", # Servers "server/*", # Utils @@ -21,6 +23,7 @@ tq-crypto = { path = "crates/crypto" } tq-codec = { path = "crates/codec" } tq-db = { path = "crates/db" } tq-server = { path = "crates/server" } +tq-system = { path = "crates/system" } derive-packetid = { path = "macros/derive-packetid" } derive-packethandler = { path = "macros/derive-packethandler" } @@ -29,6 +32,11 @@ derive-packethandler = { path = "macros/derive-packethandler" } auth = { path = "server/auth" } game = { path = "server/game" } +# Packets +msg-account = { path = "packets/account" } +msg-connect-ex = { path = "packets/connect-ex" } +msg-transfer = { path = "packets/transfer" } + futures = { version = "0.3", default-features = false } thiserror = "1.0" anyhow = "1.0" diff --git a/crates/network/src/actor.rs b/crates/network/src/actor.rs index 1e8164b..7a8d276 100644 --- a/crates/network/src/actor.rs +++ b/crates/network/src/actor.rs @@ -9,7 +9,7 @@ use tokio::sync::mpsc::Sender; use tracing::instrument; #[cfg(not(feature = "std"))] -use alloc::{sync::Arc, boxed::Box}; +use alloc::{boxed::Box, sync::Arc}; #[cfg(feature = "std")] use std::sync::Arc; diff --git a/crates/network/src/error.rs b/crates/network/src/error.rs index 496498d..892b885 100644 --- a/crates/network/src/error.rs +++ b/crates/network/src/error.rs @@ -1,7 +1,7 @@ #[cfg(not(feature = "std"))] use alloc::string::String; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Error { TQSerde(tq_serde::TQSerdeError), SendError, diff --git a/crates/server/src/lib.rs b/crates/server/src/lib.rs index b432665..ad4896d 100644 --- a/crates/server/src/lib.rs +++ b/crates/server/src/lib.rs @@ -1,7 +1,6 @@ //! This crate contains Creating Servers common code. use async_trait::async_trait; -use tq_network::{ActorState, PacketHandler, Actor, Message}; use std::fmt::Debug; use std::net::SocketAddr; use std::ops::Deref; @@ -12,6 +11,7 @@ use tokio_stream::wrappers::{ReceiverStream, TcpListenerStream}; use tokio_stream::StreamExt; use tq_codec::{TQCodec, TQEncoder}; use tq_crypto::Cipher; +use tq_network::{Actor, ActorState, Message, PacketHandler}; mod error; pub use error::Error; @@ -136,9 +136,7 @@ async fn handle_stream( if let Err(err) = S::PacketHandler::handle((id, bytes), state, actor).await { - let result = actor - .send(err) - .await; + let result = actor.send(err).await; if let Err(e) = result { tracing::error!( ?e, diff --git a/crates/system/Cargo.toml b/crates/system/Cargo.toml new file mode 100644 index 0000000..cc984f9 --- /dev/null +++ b/crates/system/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "tq-system" +version = "0.1.0" +edition.workspace = true + +[dependencies] +async-trait.workspace = true +tq-network.workspace = true + +[features] +default = ["std"] +std = [ + "tq-network/std" +] diff --git a/crates/system/src/lib.rs b/crates/system/src/lib.rs new file mode 100644 index 0000000..0770309 --- /dev/null +++ b/crates/system/src/lib.rs @@ -0,0 +1,32 @@ +//! This crate is used to define common traits for defining packets and systems +//! in the game servers. + +#![cfg_attr(not(feature = "std"), no_std)] + +use tq_network::ActorHandle; + +/// A trait for querying a single value from a type. +/// +/// It is not required that the value is constant. +pub trait Get { + /// Return the current value. + fn get() -> T; +} + +impl Get for () { + fn get() -> T { T::default() } +} + +/// Implement Get by returning Default for any type that implements Default. +pub struct GetDefault; +impl Get for GetDefault { + fn get() -> T { T::default() } +} + +pub trait Config: Send + Sync + 'static {} + +#[async_trait::async_trait] +pub trait ProcessPacket { + type Error; + async fn process(&self, actor: ActorHandle) -> Result<(), Self::Error>; +} diff --git a/packets/account/Cargo.toml b/packets/account/Cargo.toml new file mode 100644 index 0000000..cab4a02 --- /dev/null +++ b/packets/account/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "msg-account" +version = "0.1.0" +edition.workspace = true + +[dependencies] +tq-serde.workspace = true +tq-codec.workspace = true +tq-crypto.workspace = true +tq-network.workspace = true +tq-system.workspace = true + +serde.workspace = true +async-trait.workspace = true +tracing.workspace = true + +msg-connect-ex.workspace = true +msg-transfer.workspace = true + +[features] +default = ["std"] +std = [ + "tq-serde/std", + "tq-codec/std", + "tq-crypto/std", + "tq-network/std", + "tq-system/std", + + "tracing/std", + + "msg-connect-ex/std", + "msg-transfer/std", +] diff --git a/packets/account/src/functions.rs b/packets/account/src/functions.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/packets/account/src/functions.rs @@ -0,0 +1 @@ + diff --git a/packets/account/src/lib.rs b/packets/account/src/lib.rs new file mode 100644 index 0000000..c3636c1 --- /dev/null +++ b/packets/account/src/lib.rs @@ -0,0 +1,102 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use msg_connect_ex::{MsgConnectEx, RejectionCode}; +use msg_transfer::MsgTransfer; +use serde::Deserialize; +use tq_network::{ActorHandle, PacketID}; +use tq_serde::{String16, TQPassword}; + +pub use traits::Authanticator; + +mod functions; +mod traits; +mod types; + +#[derive(Debug, Deserialize, PacketID)] +#[packet(id = 1051)] +pub struct MsgAccount { + pub username: String16, + pub password: TQPassword, + pub realm: String16, + #[serde(skip)] + pub rejection_code: u32, + #[serde(skip)] + pub account_id: i32, + #[serde(skip)] + _config: core::marker::PhantomData, +} + +pub trait Config: msg_transfer::Config { + /// The type of the authanticator used to authanticate accounts. + type Authanticator: Authanticator; +} + +#[async_trait::async_trait] +impl tq_system::ProcessPacket for MsgAccount { + type Error = Error; + + async fn process(&self, actor: ActorHandle) -> Result<(), Self::Error> { + let maybe_accont_id = + T::Authanticator::auth(&self.username, &self.password).await; + let account_id = match maybe_accont_id { + Ok(id) => id, + Err(e) => { + let res = match e { + Error::InvalidUsernameOrPassword => { + RejectionCode::InvalidPassword.packet() + }, + _ => { + tracing::error!("Error authenticating account: {e}"); + RejectionCode::TryAgainLater.packet() + }, + }; + actor.send(res).await?; + return Ok(()); + }, + }; + actor.set_id(account_id as usize); + let res = match MsgTransfer::::handle(&actor, &self.realm).await { + Ok(res) => res, + _ => { + tracing::warn!( + %account_id, + "Failed to transfer account" + ); + return Ok(()); + }, + }; + let res = MsgConnectEx::forword_connection(res); + actor.send(res).await?; + Ok(()) + } +} + +/// Possible errors that can occur while processing a packet. +pub enum Error { + /// User has entered an invalid username or password. + InvalidUsernameOrPassword, + /// Internal Network error. + Network(tq_network::Error), +} + +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::InvalidUsernameOrPassword => { + write!(f, "Invalid username or password") + }, + Self::Network(e) => write!(f, "Network error: {}", e), + } + } +} + +impl From for Error { + fn from(e: tq_network::Error) -> Self { Self::Network(e) } +} + +#[cfg(test)] +mod tests { + + #[test] + fn it_works() {} +} diff --git a/packets/account/src/traits.rs b/packets/account/src/traits.rs new file mode 100644 index 0000000..6333542 --- /dev/null +++ b/packets/account/src/traits.rs @@ -0,0 +1,4 @@ +#[async_trait::async_trait] +pub trait Authanticator { + async fn auth(username: &str, password: &str) -> Result; +} diff --git a/packets/account/src/types.rs b/packets/account/src/types.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/packets/account/src/types.rs @@ -0,0 +1 @@ + diff --git a/packets/connect-ex/Cargo.toml b/packets/connect-ex/Cargo.toml new file mode 100644 index 0000000..636c8b9 --- /dev/null +++ b/packets/connect-ex/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "msg-connect-ex" +version = "0.1.0" +edition.workspace = true + +[dependencies] +tq-serde.workspace = true +tq-network.workspace = true + +serde.workspace = true +num_enum.workspace = true + +[features] +default = ["std"] +std = [ + "tq-serde/std", + "tq-network/std", +] diff --git a/packets/connect-ex/src/lib.rs b/packets/connect-ex/src/lib.rs new file mode 100644 index 0000000..f761dd2 --- /dev/null +++ b/packets/connect-ex/src/lib.rs @@ -0,0 +1,77 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use num_enum::IntoPrimitive; +use serde::Serialize; +use tq_network::PacketID; +use tq_serde::String16; + +/// Rejection codes are sent to the client in offset 8 of this packet when the +/// client has failed authentication with the account server. These codes define +/// which error message will be displayed in the client. +#[derive(Debug, IntoPrimitive, Copy, Clone)] +#[repr(u32)] +pub enum RejectionCode { + Clear = 0, + InvalidPassword = 1, + Ready = 2, + ServerDown = 10, + TryAgainLater = 11, + AccountBanned = 12, + ServerBusy = 20, + AccountLocked = 22, + AccountNotActivated = 30, + AccountActivationFailed = 31, + ServerTimedOut = 42, + AccountMaxLoginAttempts = 51, + ServerLocked = 70, + ServerOldProtocol = 73, +} + +impl RejectionCode { + pub fn packet(self) -> MsgConnectRejection { MsgConnectEx::from_code(self) } +} + +#[derive(Debug, Serialize, PacketID)] +#[packet(id = 1055)] +pub struct MsgConnectEx { + token: u64, + game_server_ip: String16, + game_server_port: u32, +} + +#[derive(Debug, Serialize, PacketID)] +#[packet(id = 1055)] +pub struct MsgConnectRejection { + reserved: u32, + rejection_code: u32, + message: String16, +} + +#[derive(Debug, Clone)] +pub struct AccountCredentials { + pub token: u64, + pub server_ip: String, + pub server_port: u32, +} + +impl MsgConnectEx { + /// Instantiates a new instance of `MsgConnectRejection` for rejecting a + /// client connection using a rejection code. The rejection code spawns an + /// error dialog in the client with a respective error message. + #[allow(unused)] + pub fn from_code(code: RejectionCode) -> MsgConnectRejection { + MsgConnectRejection { + reserved: 0, + rejection_code: code.into(), + message: String::new().into(), + } + } + + pub fn forword_connection(acc_credentials: AccountCredentials) -> Self { + MsgConnectEx { + token: acc_credentials.token, + game_server_ip: acc_credentials.server_ip.into(), + game_server_port: acc_credentials.server_port, + } + } +} diff --git a/packets/transfer/Cargo.toml b/packets/transfer/Cargo.toml new file mode 100644 index 0000000..fa23b8c --- /dev/null +++ b/packets/transfer/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "msg-transfer" +version = "0.1.0" +edition.workspace = true + +[dependencies] +tq-serde.workspace = true +tq-codec.workspace = true +tq-crypto.workspace = true +tq-network.workspace = true +tq-system.workspace = true + +serde.workspace = true +async-trait.workspace = true +tracing.workspace = true +bytes.workspace = true + +msg-connect-ex.workspace = true + +[features] +default = ["std"] +std = [ + "tq-serde/std", + "tq-codec/std", + "tq-crypto/std", + "tq-network/std", + "tq-system/std", + + "tracing/std", + + "msg-connect-ex/std", +] diff --git a/packets/transfer/src/functions.rs b/packets/transfer/src/functions.rs new file mode 100644 index 0000000..d9b5669 --- /dev/null +++ b/packets/transfer/src/functions.rs @@ -0,0 +1,68 @@ +use msg_connect_ex::{AccountCredentials, RejectionCode}; +use tq_network::{ActorHandle, IntoErrorPacket}; + +use crate::types::Realm; + +use super::*; + +impl MsgTransfer { + #[tracing::instrument(skip(actor))] + pub async fn handle( + actor: &ActorHandle, + realm: &str, + ) -> Result { + let maybe_realm = T::RealmByName::by_name(realm).await?; + // Check if there is a realm with that name + let realm = match maybe_realm { + Some(realm) => realm, + None => { + return Err(RejectionCode::TryAgainLater + .packet() + .error_packet() + .into()); + }, + }; + // Try to connect to that realm first. + if let Err(e) = T::ServerBus::check(&realm).await { + tracing::error!( + ip = realm.game_ip_address, + port = realm.game_port, + realm_id = realm.id, + error = ?e, + "Failed to connect to realm" + ); + actor.send(RejectionCode::ServerDown.packet()).await?; + actor.shutdown().await?; + return Err(e); + } + Self::transfer(actor, realm).await + } + + #[tracing::instrument(skip(actor), err, fields(realm = realm.name))] + async fn transfer( + actor: &ActorHandle, + realm: Realm, + ) -> Result { + let res = T::ServerBus::transfer(actor, &realm).await; + match res { + Ok(token) => Ok(AccountCredentials { + token, + server_ip: realm.game_ip_address, + server_port: realm.game_port as u32, + }), + Err(e) => { + tracing::error!( + ip = realm.game_ip_address, + port = realm.game_port, + realm_id = realm.id, + error = ?e, + "Failed to transfer account" + ); + Err(RejectionCode::ServerTimedOut + .packet() + .error_packet() + .into()) + }, + } + } +} diff --git a/packets/transfer/src/lib.rs b/packets/transfer/src/lib.rs new file mode 100644 index 0000000..696348b --- /dev/null +++ b/packets/transfer/src/lib.rs @@ -0,0 +1,97 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use serde::{Deserialize, Serialize}; +use tq_network::{ActorHandle, ErrorPacket, PacketEncode, PacketID}; + +pub use traits::{RealmByName, ServerBus, TokenGenerator}; + +mod functions; +mod traits; +mod types; + +/// Defines account parameters to be transferred from the account server to the +/// game server. Account information is supplied from the account database, and +/// used on the game server to transfer authentication and authority level. +#[derive(Clone, Default, Debug, Deserialize, Serialize, PacketID)] +#[packet(id = 4001)] +pub struct MsgTransfer { + account_id: u32, + realm_id: u32, + token: u64, + #[serde(skip)] + _config: core::marker::PhantomData, +} + +pub trait Config: tq_system::Config { + /// The type of the authanticator used to authanticate accounts. + type TokenGenerator: TokenGenerator; + /// For querying realms by name. + type RealmByName: RealmByName; + /// Server bus for checking and transferring accounts + /// to other servers. + type ServerBus: ServerBus; +} + +#[async_trait::async_trait] +impl tq_system::ProcessPacket for MsgTransfer { + type Error = Error; + + async fn process(&self, actor: ActorHandle) -> Result<(), Self::Error> { + let token = T::TokenGenerator::generate_login_token( + self.account_id, + self.realm_id, + )?; + let msg = Self { + account_id: self.account_id, + realm_id: self.realm_id, + token, + _config: core::marker::PhantomData, + }; + actor.send(msg).await?; + actor.shutdown().await?; + Ok(()) + } +} + +/// Possible errors that can occur while processing a packet. +#[derive(Debug, Clone)] +pub enum Error { + /// Failed to generate a login token. + TokenGenerationFailed, + /// Internal Network error. + Network(tq_network::Error), + /// An error packet to be sent to the client. + Msg(u16, bytes::Bytes), +} + +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::TokenGenerationFailed => { + write!(f, "Failed to generate a login token") + }, + Self::Network(e) => write!(f, "Network error: {}", e), + Self::Msg(id, body) => { + write!(f, "Error packet: id = {}, body = {:?}", id, body) + }, + } + } +} + +impl From for Error { + fn from(e: tq_network::Error) -> Self { Self::Network(e) } +} + +impl From> for Error { + fn from(v: ErrorPacket) -> Self { + let (id, bytes) = v.0.encode().unwrap(); + Self::Msg(id, bytes) + } +} + +#[cfg(test)] +mod tests { + + #[test] + fn it_works() {} +} diff --git a/packets/transfer/src/traits.rs b/packets/transfer/src/traits.rs new file mode 100644 index 0000000..9539df4 --- /dev/null +++ b/packets/transfer/src/traits.rs @@ -0,0 +1,27 @@ +use tq_network::ActorHandle; + +use crate::types::Realm; + +/// Trait for generating login tokens. +pub trait TokenGenerator { + fn generate_login_token( + account_id: u32, + realm_id: u32, + ) -> Result; +} + +/// Trait for querying realms by name. +#[async_trait::async_trait] +pub trait RealmByName { + async fn by_name(name: &str) -> Result, crate::Error>; +} + +#[async_trait::async_trait] +pub trait ServerBus { + async fn check(realm: &Realm) -> Result<(), crate::Error>; + + async fn transfer( + actor: &ActorHandle, + realm: &Realm, + ) -> Result; +} diff --git a/packets/transfer/src/types.rs b/packets/transfer/src/types.rs new file mode 100644 index 0000000..968ff85 --- /dev/null +++ b/packets/transfer/src/types.rs @@ -0,0 +1,9 @@ +#[cfg(not(feature = "std"))] +use alloc::string::String; + +pub struct Realm { + pub id: u32, + pub name: String, + pub game_ip_address: String, + pub game_port: u16, +} diff --git a/server/auth/src/packets/msg_connect.rs b/server/auth/src/packets/msg_connect.rs index 15eb3a1..d10bcd8 100644 --- a/server/auth/src/packets/msg_connect.rs +++ b/server/auth/src/packets/msg_connect.rs @@ -3,6 +3,7 @@ use crate::Error; use serde::Deserialize; use tq_network::{Actor, PacketID, PacketProcess}; use tq_serde::String16; + /// Message containing a connection request to the game server. Contains the /// player's access token from the Account server, and the patch and language /// versions of the game client. diff --git a/server/game/src/error.rs b/server/game/src/error.rs index 541ce37..e2b5eee 100644 --- a/server/game/src/error.rs +++ b/server/game/src/error.rs @@ -193,7 +193,6 @@ impl From for tq_network::Error { fn from(v: Error) -> Self { Self::Other(v.to_string()) } } - impl From for tq_server::Error { fn from(v: Error) -> Self { Self::Internal(Box::new(v)) } } From fafd1fd91a95486c3663e429798e0e1f33e94d6c Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Wed, 20 Dec 2023 23:46:25 +0200 Subject: [PATCH 07/28] More code --- Cargo.lock | 35 ++++++-- Cargo.toml | 3 + crates/externalities/Cargo.toml | 21 +++++ crates/externalities/src/lib.rs | 47 ++++++++++ crates/io/Cargo.toml | 30 +++++++ crates/io/src/lib.rs | 51 +++++++++++ flake.nix | 1 + server/auth/Cargo.toml | 15 +++- server/auth/src/error.rs | 86 +++++++++++++++---- server/auth/src/lib.rs | 8 +- server/auth/src/packets/mod.rs | 11 --- server/auth/src/packets/msg_account.rs | 69 --------------- server/auth/src/packets/msg_connect.rs | 33 ------- server/auth/src/packets/msg_connect_ex.rs | 74 ---------------- server/auth/src/packets/msg_transfer.rs | 100 ---------------------- server/auth/src/state.rs | 3 + tools/benchbot/Cargo.toml | 4 +- 17 files changed, 270 insertions(+), 321 deletions(-) create mode 100644 crates/externalities/Cargo.toml create mode 100644 crates/externalities/src/lib.rs create mode 100644 crates/io/Cargo.toml create mode 100644 crates/io/src/lib.rs delete mode 100644 server/auth/src/packets/mod.rs delete mode 100644 server/auth/src/packets/msg_account.rs delete mode 100644 server/auth/src/packets/msg_connect.rs delete mode 100644 server/auth/src/packets/msg_connect_ex.rs delete mode 100644 server/auth/src/packets/msg_transfer.rs diff --git a/Cargo.lock b/Cargo.lock index 0f7d68e..8654001 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -272,7 +272,7 @@ dependencies = [ "game", "local-ip-address", "parking_lot", - "pretty-hex 0.3.0", + "pretty-hex", "rand", "sqlx", "thiserror", @@ -587,6 +587,12 @@ dependencies = [ "serde", ] +[[package]] +name = "environmental" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" + [[package]] name = "equivalent" version = "1.0.1" @@ -1518,12 +1524,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "pretty-hex" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" - [[package]] name = "pretty-hex" version = "0.4.0" @@ -2390,7 +2390,7 @@ name = "tq-codec" version = "0.1.0" dependencies = [ "bytes", - "pretty-hex 0.4.0", + "pretty-hex", "tokio", "tokio-stream", "tq-crypto", @@ -2417,6 +2417,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "tq-externalities" +version = "0.1.0" +dependencies = [ + "async-trait", + "environmental", + "futures", + "sqlx", +] + +[[package]] +name = "tq-io" +version = "0.1.0" +dependencies = [ + "sqlx", + "tokio", + "tq-externalities", +] + [[package]] name = "tq-math" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index a19bbc6..7322f58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ tq-codec = { path = "crates/codec" } tq-db = { path = "crates/db" } tq-server = { path = "crates/server" } tq-system = { path = "crates/system" } +tq-io = { path = "crates/io" } +tq-externalities = { path = "crates/externalities" } derive-packetid = { path = "macros/derive-packetid" } derive-packethandler = { path = "macros/derive-packethandler" } @@ -56,6 +58,7 @@ atomic = { version = "0.6", default-features = false } bytemuck = { version = "1.13", default-features = false, features = ["derive"] } chrono = { version = "0.4", default-features = false, features = [] } num_enum = { version = "0.7", default-features = false } +environmental = { version = "1.1.4", default-features = false } bcrypt = "0.15" [workspace.dependencies.tokio] diff --git a/crates/externalities/Cargo.toml b/crates/externalities/Cargo.toml new file mode 100644 index 0000000..c2f6fe3 --- /dev/null +++ b/crates/externalities/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "tq-externalities" +version = "0.1.0" +edition.workspace = true + +[dependencies] +async-trait.workspace = true +environmental.workspace = true +futures.workspace = true + +[dependencies.sqlx] +default-features = false +workspace = true +features = ["any"] + +[features] +default = [] +std = [ + "environmental/std", + "futures/std" +] diff --git a/crates/externalities/src/lib.rs b/crates/externalities/src/lib.rs new file mode 100644 index 0000000..73f6948 --- /dev/null +++ b/crates/externalities/src/lib.rs @@ -0,0 +1,47 @@ +//! Externalities abstraction +//! +//! The externalities mainly provide access to storage and to registered +//! extensions. Extensions are for example the RNGs or the Http externalities. +//! These externalities are used to access the server from the runtime via the +//! runtime traits. +//! +//! This crate exposes the main [`Externalities`] trait. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; + +environmental::environmental!(ext: trait Externalities); + +/// The Externalities. +/// +/// Provides access to the storage and to other registered extensions. +pub trait Externalities { + fn executer(&self) -> &sqlx::AnyPool; +} + +/// Set the given externalities while executing the given closure. To get access +/// to the externalities while executing the given closure +/// [`with_externalities`] grants access to them. The externalities are only set +/// for the same thread this function was called from. +pub fn set_and_run_with_externalities( + ext: &mut dyn Externalities, + f: F, +) -> R +where + F: FnOnce() -> R, +{ + ext::using(ext, f) +} + +/// Execute the given closure with the currently set externalities. +/// +/// Returns `None` if no externalities are set or `Some(_)` with the result of +/// the closure. +pub fn with_externalities(f: F) -> Option +where + F: FnOnce(&mut dyn Externalities) -> R, +{ + ext::with(f) +} diff --git a/crates/io/Cargo.toml b/crates/io/Cargo.toml new file mode 100644 index 0000000..a913284 --- /dev/null +++ b/crates/io/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "tq-io" +version = "0.1.0" +edition.workspace = true + +[dependencies] +tq-externalities.workspace = true + + +[dependencies.sqlx] +default-features = false +workspace = true +features = ["any"] + + +[dev-dependencies.sqlx] +default-features = false +workspace = true +features = ["runtime-tokio", "sqlite", "any"] + +[dev-dependencies.tokio] +workspace = true +default-features = false +features = ["rt-multi-thread", "macros", "test-util"] + +[features] +default = [] +std = [ + "tq-externalities/std", +] diff --git a/crates/io/src/lib.rs b/crates/io/src/lib.rs new file mode 100644 index 0000000..4501519 --- /dev/null +++ b/crates/io/src/lib.rs @@ -0,0 +1,51 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; + +use tq_externalities::Externalities; + +pub struct DefaultExtenernalities { + pool: sqlx::AnyPool, +} + +impl DefaultExtenernalities { + pub fn new(pool: sqlx::AnyPool) -> Self { Self { pool } } +} + +impl Externalities for DefaultExtenernalities { + fn executer(&self) -> &sqlx::AnyPool { &self.pool } +} + +#[cfg(test)] +mod tests { + use sqlx::Row; + + use super::*; + + #[tokio::test] + async fn it_works() { + let pool = sqlx::any::AnyPoolOptions::new() + .max_connections(42) + .min_connections(4) + .connect("sqlite::memory:") + .await + .unwrap(); + let mut ext = DefaultExtenernalities::new(pool); + + async fn add_one(x: i32) -> i32 { + tq_externalities::with_externalities(|ext| { + sqlx::query("select 1 + ?1") + .bind(x) + .try_map(|row: sqlx::any::AnyRow| row.try_get::(0)) + .fetch_one(ext.executer()) + }) + .unwrap() + .await + .unwrap() + } + + let p = + tq_externalities::set_and_run_with_externalities(&mut ext, || {}); + } +} diff --git a/flake.nix b/flake.nix index cb98bcc..7626d34 100644 --- a/flake.nix +++ b/flake.nix @@ -41,6 +41,7 @@ ]; packages = [ pkgs.cargo-nextest + pkgs.cargo-expand ]; # Environment variables RUST_SRC_PATH = "${toolchain}/lib/rustlib/src/rust/library"; diff --git a/server/auth/Cargo.toml b/server/auth/Cargo.toml index aaeffbf..10b1e8b 100644 --- a/server/auth/Cargo.toml +++ b/server/auth/Cargo.toml @@ -16,16 +16,16 @@ path = "src/lib.rs" thiserror.workspace = true serde.workspace = true bytes.workspace = true -tq-network = { workspace = true, features = ["std"] } -tq-serde = { workspace = true, features = ["std"] } tq-db.workspace = true tq-server.workspace = true +tq-network.workspace = true +tq-serde.workspace = true async-trait.workspace = true tracing.workspace = true dotenvy.workspace = true once_cell.workspace = true tokio-stream.workspace = true -num_enum = { workspace = true, default-features = false } +num_enum.workspace = true [dependencies.tracing-subscriber] version = "0.3" @@ -42,4 +42,11 @@ features = ["rt-multi-thread", "macros", "signal"] [dependencies.sqlx] workspace = true default-features = false -features = ["runtime-tokio-rustls", "sqlite", "macros"] +features = ["runtime-tokio", "sqlite", "macros"] + +[features] +default = [] +std = [ + "tq-network/std", + "tq-serde/std", +] diff --git a/server/auth/src/error.rs b/server/auth/src/error.rs index eed6a56..408268b 100644 --- a/server/auth/src/error.rs +++ b/server/auth/src/error.rs @@ -1,31 +1,79 @@ use bytes::Bytes; -use thiserror::Error; use tq_network::{ErrorPacket, PacketEncode}; -#[derive(Debug, Error)] +#[cfg(not(feature = "std"))] +use alloc::string::{String, ToString}; + +#[derive(Debug)] pub enum Error { - #[error(transparent)] - Network(#[from] tq_network::Error), - #[error(transparent)] - Server(#[from] tq_server::Error), - #[error(transparent)] - IO(#[from] std::io::Error), - #[error(transparent)] - DotEnv(#[from] dotenvy::Error), - #[error(transparent)] - Env(#[from] std::env::VarError), - #[error(transparent)] - Sqlx(#[from] sqlx::Error), - #[error(transparent)] - Db(#[from] tq_db::Error), - #[error("State Error: {}", _0)] + Network(tq_network::Error), + Server(tq_server::Error), + #[cfg(feature = "std")] + IO(std::io::Error), + DotEnv(dotenvy::Error), + #[cfg(feature = "std")] + Env(std::env::VarError), + Sqlx(sqlx::Error), + Db(tq_db::Error), State(&'static str), - #[error("{}", _0)] Other(String), - #[error("Msg {}", _0)] Msg(u16, Bytes), } +impl From for Error { + fn from(v: tq_db::Error) -> Self { Self::Db(v) } +} + +impl From for Error { + fn from(v: sqlx::Error) -> Self { Self::Sqlx(v) } +} + +#[cfg(feature = "std")] +impl From for Error { + fn from(v: std::env::VarError) -> Self { Self::Env(v) } +} + +impl From for Error { + fn from(v: dotenvy::Error) -> Self { Self::DotEnv(v) } +} + +#[cfg(feature = "std")] +impl From for Error { + fn from(v: std::io::Error) -> Self { Self::IO(v) } +} + +impl From for Error { + fn from(v: tq_server::Error) -> Self { Self::Server(v) } +} + +impl From for Error { + fn from(v: tq_network::Error) -> Self { Self::Network(v) } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} + +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Network(e) => write!(f, "Network error: {}", e), + Self::Server(e) => write!(f, "Server error: {}", e), + #[cfg(feature = "std")] + Self::IO(e) => write!(f, "IO error: {}", e), + Self::DotEnv(e) => write!(f, "DotEnv error: {}", e), + #[cfg(feature = "std")] + Self::Env(e) => write!(f, "Env error: {}", e), + Self::Sqlx(e) => write!(f, "Sqlx error: {}", e), + Self::Db(e) => write!(f, "Db error: {}", e), + Self::State(e) => write!(f, "State error: {}", e), + Self::Other(e) => write!(f, "{}", e), + Self::Msg(id, bytes) => { + write!(f, "Error packet: id = {}, body = {:?}", id, bytes) + }, + } + } +} + impl From> for Error { fn from(v: ErrorPacket) -> Self { let (id, bytes) = v.0.encode().unwrap(); diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index c7dc510..0fb451d 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -1,5 +1,11 @@ +//! Auth Server + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; + pub mod error; -pub mod packets; pub mod state; pub use error::Error; diff --git a/server/auth/src/packets/mod.rs b/server/auth/src/packets/mod.rs deleted file mode 100644 index ac04bd2..0000000 --- a/server/auth/src/packets/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod msg_account; -pub use msg_account::MsgAccount; - -mod msg_connect_ex; -pub use msg_connect_ex::{AccountCredentials, MsgConnectEx, RejectionCode}; - -mod msg_connect; -pub use msg_connect::MsgConnect; - -mod msg_transfer; -pub use msg_transfer::MsgTransfer; diff --git a/server/auth/src/packets/msg_account.rs b/server/auth/src/packets/msg_account.rs deleted file mode 100644 index 6f2c9f7..0000000 --- a/server/auth/src/packets/msg_account.rs +++ /dev/null @@ -1,69 +0,0 @@ -use super::{MsgConnectEx, MsgTransfer}; -use crate::packets::RejectionCode; -use crate::state::State; -use crate::Error; -use async_trait::async_trait; -use serde::Deserialize; -use tq_db::account::Account; -use tq_network::{Actor, PacketID, PacketProcess}; -use tq_serde::{String16, TQPassword}; - -#[derive(Debug, Deserialize, PacketID)] -#[packet(id = 1051)] -pub struct MsgAccount { - pub username: String16, - pub password: TQPassword, - pub realm: String16, - #[serde(skip)] - pub rejection_code: u32, - #[serde(skip)] - pub account_id: i32, -} - -#[async_trait] -impl PacketProcess for MsgAccount { - type ActorState = (); - type Error = Error; - type State = State; - - async fn process( - &self, - state: &Self::State, - actor: &Actor, - ) -> Result<(), Self::Error> { - let pool = state.pool(); - let maybe_accont = - Account::auth(pool, &self.username, &self.password).await; - let account = match maybe_accont { - Ok(account) => account, - Err(e) => { - let res = match e { - tq_db::Error::InvalidPassword - | tq_db::Error::AccountNotFound => { - RejectionCode::InvalidPassword.packet() - }, - _ => { - tracing::error!("Error authenticating account: {e}"); - RejectionCode::TryAgainLater.packet() - }, - }; - actor.send(res).await?; - return Ok(()); - }, - }; - actor.set_id(account.account_id as usize); - let res = match MsgTransfer::handle(state, actor, &self.realm).await { - Ok(res) => res, - _ => { - tracing::warn!( - account_id = account.account_id, - "Failed to transfer account" - ); - return Ok(()); - }, - }; - let res = MsgConnectEx::forword_connection(res); - actor.send(res).await?; - Ok(()) - } -} diff --git a/server/auth/src/packets/msg_connect.rs b/server/auth/src/packets/msg_connect.rs deleted file mode 100644 index d10bcd8..0000000 --- a/server/auth/src/packets/msg_connect.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::state::State; -use crate::Error; -use serde::Deserialize; -use tq_network::{Actor, PacketID, PacketProcess}; -use tq_serde::String16; - -/// Message containing a connection request to the game server. Contains the -/// player's access token from the Account server, and the patch and language -/// versions of the game client. -#[derive(Debug, Deserialize, PacketID)] -#[packet(id = 1052)] -#[allow(dead_code)] -pub struct MsgConnect { - id: u32, - file_contents: u32, - file_name: String16, -} - -#[async_trait::async_trait] -impl PacketProcess for MsgConnect { - type ActorState = (); - type Error = Error; - type State = State; - - async fn process( - &self, - _state: &Self::State, - actor: &Actor, - ) -> Result<(), Self::Error> { - actor.shutdown().await?; - Ok(()) - } -} diff --git a/server/auth/src/packets/msg_connect_ex.rs b/server/auth/src/packets/msg_connect_ex.rs deleted file mode 100644 index 9d340a4..0000000 --- a/server/auth/src/packets/msg_connect_ex.rs +++ /dev/null @@ -1,74 +0,0 @@ -use num_enum::IntoPrimitive; -use serde::Serialize; -use tq_network::PacketID; -use tq_serde::String16; -/// Rejection codes are sent to the client in offset 8 of this packet when the -/// client has failed authentication with the account server. These codes define -/// which error message will be displayed in the client. -#[derive(Debug, IntoPrimitive, Copy, Clone)] -#[repr(u32)] -pub enum RejectionCode { - Clear = 0, - InvalidPassword = 1, - Ready = 2, - ServerDown = 10, - TryAgainLater = 11, - AccountBanned = 12, - ServerBusy = 20, - AccountLocked = 22, - AccountNotActivated = 30, - AccountActivationFailed = 31, - ServerTimedOut = 42, - AccountMaxLoginAttempts = 51, - ServerLocked = 70, - ServerOldProtocol = 73, -} - -impl RejectionCode { - pub fn packet(self) -> MsgConnectRejection { MsgConnectEx::from_code(self) } -} - -#[derive(Debug, Serialize, PacketID)] -#[packet(id = 1055)] -pub struct MsgConnectEx { - token: u64, - game_server_ip: String16, - game_server_port: u32, -} - -#[derive(Debug, Serialize, PacketID)] -#[packet(id = 1055)] -pub struct MsgConnectRejection { - reserved: u32, - rejection_code: u32, - message: String16, -} - -#[derive(Debug, Clone)] -pub struct AccountCredentials { - pub token: u64, - pub server_ip: String, - pub server_port: u32, -} - -impl MsgConnectEx { - /// Instantiates a new instance of `MsgConnectRejection` for rejecting a - /// client connection using a rejection code. The rejection code spawns an - /// error dialog in the client with a respective error message. - #[allow(unused)] - pub fn from_code(code: RejectionCode) -> MsgConnectRejection { - MsgConnectRejection { - reserved: 0, - rejection_code: code.into(), - message: String::new().into(), - } - } - - pub fn forword_connection(acc_credentials: AccountCredentials) -> Self { - MsgConnectEx { - token: acc_credentials.token, - game_server_ip: acc_credentials.server_ip.into(), - game_server_port: acc_credentials.server_port, - } - } -} diff --git a/server/auth/src/packets/msg_transfer.rs b/server/auth/src/packets/msg_transfer.rs deleted file mode 100644 index 75aecca..0000000 --- a/server/auth/src/packets/msg_transfer.rs +++ /dev/null @@ -1,100 +0,0 @@ -use super::{AccountCredentials, RejectionCode}; -use crate::Error; -use serde::{Deserialize, Serialize}; -use tokio::net::TcpStream; -use tokio_stream::StreamExt; -use tq_db::realm::Realm; -use tq_network::{ - Actor, ActorState, CQCipher, IntoErrorPacket, PacketDecode, PacketEncode, - PacketID, TQCodec, -}; -use tracing::Instrument; - -/// Defines account parameters to be transferred from the account server to the -/// game server. Account information is supplied from the account database, and -/// used on the game server to transfer authentication and authority level. -#[derive(Default, Debug, Deserialize, Serialize, PacketID)] -#[packet(id = 4001)] -pub struct MsgTransfer { - pub account_id: u32, - pub realm_id: u32, - #[serde(skip_serializing)] - pub token: u64, -} - -impl MsgTransfer { - #[tracing::instrument(skip(state, actor))] - pub async fn handle( - state: &crate::State, - actor: &Actor, - realm: &str, - ) -> Result { - let maybe_realm = Realm::by_name(state.pool(), realm).await?; - // Check if there is a realm with that name - let realm = match maybe_realm { - Some(realm) => realm, - None => { - return Err(RejectionCode::TryAgainLater - .packet() - .error_packet() - .into()); - }, - }; - // Try to connect to that realm first. - let ip = realm.game_ip_address.as_str(); - let port = realm.game_port; - let stream = TcpStream::connect(format!("{ip}:{port}")) - .instrument(tracing::info_span!("realm_connect", %ip, %port, realm_id = realm.realm_id)) - .await; - let stream = match stream { - Ok(s) => s, - Err(e) => { - tracing::error!( - %ip, - %port, - realm_id = realm.realm_id, - error = ?e, - "Failed to connect to realm" - ); - actor.send(RejectionCode::ServerDown.packet()).await?; - actor.shutdown().await?; - return Err(e.into()); - }, - }; - Self::transfer(actor, realm, stream).await - } - - #[tracing::instrument(skip(actor, stream), err, fields(realm = realm.name))] - async fn transfer( - actor: &Actor, - realm: Realm, - stream: TcpStream, - ) -> Result { - let cipher = CQCipher::new(); - let (mut encoder, mut decoder) = TQCodec::new(stream, cipher).split(); - let transfer = MsgTransfer { - account_id: actor.id() as u32, - realm_id: realm.realm_id as u32, - ..Default::default() - }; - - let transfer = transfer.encode()?; - encoder.send(transfer).await?; - let res = decoder.next().await; - let res = match res { - Some(Ok((_, bytes))) => MsgTransfer::decode(&bytes)?, - Some(Err(e)) => return Err(e.into()), - None => { - return Err(RejectionCode::ServerTimedOut - .packet() - .error_packet() - .into()); - }, - }; - Ok(AccountCredentials { - token: res.token, - server_ip: realm.game_ip_address, - server_port: realm.game_port as u32, - }) - } -} diff --git a/server/auth/src/state.rs b/server/auth/src/state.rs index 9d3bcd7..7568be1 100644 --- a/server/auth/src/state.rs +++ b/server/auth/src/state.rs @@ -1,6 +1,9 @@ use crate::Error; use sqlx::sqlite::{SqlitePool, SqlitePoolOptions}; +#[cfg(not(feature = "std"))] +use alloc::format; + #[derive(Debug, Clone)] pub struct State { pool: SqlitePool, diff --git a/tools/benchbot/Cargo.toml b/tools/benchbot/Cargo.toml index b4449ba..1f99300 100644 --- a/tools/benchbot/Cargo.toml +++ b/tools/benchbot/Cargo.toml @@ -17,10 +17,10 @@ tq-codec.workspace = true tq-crypto.workspace = true tq-network.workspace = true tq-db.workspace = true -auth.workspace = true game.workspace = true +auth = { workspace = true, features = ["std"] } -pretty-hex = "0.3" +pretty-hex = "0.4" local-ip-address = "0.5" From 82cb2300237c4b590e86e5b693dbc8d3a12fc20e Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Tue, 26 Dec 2023 20:12:12 +0200 Subject: [PATCH 08/28] work still needed here --- Cargo.lock | 20 +++++++++---- Cargo.toml | 2 +- crates/system/Cargo.toml | 1 - crates/system/src/lib.rs | 45 +++++++++++++++++++++++++--- packets/account/Cargo.toml | 1 - packets/account/src/lib.rs | 15 +++++----- packets/account/src/traits.rs | 13 ++++++-- packets/connect/Cargo.toml | 15 ++++++++++ packets/connect/src/lib.rs | 49 +++++++++++++++++++++++++++++++ packets/transfer/Cargo.toml | 1 - packets/transfer/src/functions.rs | 20 ++++++------- packets/transfer/src/lib.rs | 15 ++++++---- packets/transfer/src/traits.rs | 39 ++++++++++++++++++++---- server/auth/Cargo.toml | 13 +++++++- server/auth/src/error.rs | 12 ++++++++ server/auth/src/lib.rs | 48 ++++++++++++++++++++++++++++++ server/auth/src/main.rs | 42 +++++++++++++++++++++----- server/game/Cargo.toml | 1 - 18 files changed, 297 insertions(+), 55 deletions(-) create mode 100644 packets/connect/Cargo.toml create mode 100644 packets/connect/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 8654001..5c9e7ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -156,8 +156,11 @@ dependencies = [ "async-trait", "bytes", "dotenvy", + "msg-account", + "msg-connect", + "msg-connect-ex", + "msg-transfer", "num_enum", - "once_cell", "serde", "sqlx", "thiserror", @@ -167,6 +170,7 @@ dependencies = [ "tq-network", "tq-serde", "tq-server", + "tq-system", "tracing", "tracing-subscriber", ] @@ -776,7 +780,6 @@ dependencies = [ "dotenvy", "futures", "num_enum", - "once_cell", "parking_lot", "primitives", "rand", @@ -1216,7 +1219,6 @@ dependencies = [ name = "msg-account" version = "0.1.0" dependencies = [ - "async-trait", "msg-connect-ex", "msg-transfer", "serde", @@ -1228,6 +1230,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "msg-connect" +version = "0.1.0" +dependencies = [ + "serde", + "tq-network", + "tq-serde", + "tq-system", +] + [[package]] name = "msg-connect-ex" version = "0.1.0" @@ -1242,7 +1254,6 @@ dependencies = [ name = "msg-transfer" version = "0.1.0" dependencies = [ - "async-trait", "bytes", "msg-connect-ex", "serde", @@ -2491,7 +2502,6 @@ dependencies = [ name = "tq-system" version = "0.1.0" dependencies = [ - "async-trait", "tq-network", ] diff --git a/Cargo.toml b/Cargo.toml index 7322f58..cba75fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ game = { path = "server/game" } # Packets msg-account = { path = "packets/account" } msg-connect-ex = { path = "packets/connect-ex" } +msg-connect = { path = "packets/connect" } msg-transfer = { path = "packets/transfer" } futures = { version = "0.3", default-features = false } @@ -47,7 +48,6 @@ bytes = { version = "1.5", default-features = false } async-trait = { version = "0.1", default-features = false } tracing = { version = "0.1", default-features = false } dotenvy = "0.15" -once_cell = "1.4" bitflags = { version = "2.4", default-features = false } argh = "0.1" tokio-stream = { version = "0.1.8", default-features = false } diff --git a/crates/system/Cargo.toml b/crates/system/Cargo.toml index cc984f9..82600d5 100644 --- a/crates/system/Cargo.toml +++ b/crates/system/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" edition.workspace = true [dependencies] -async-trait.workspace = true tq-network.workspace = true [features] diff --git a/crates/system/src/lib.rs b/crates/system/src/lib.rs index 0770309..0f1b90b 100644 --- a/crates/system/src/lib.rs +++ b/crates/system/src/lib.rs @@ -3,7 +3,24 @@ #![cfg_attr(not(feature = "std"), no_std)] -use tq_network::ActorHandle; +use core::{sync::atomic::AtomicUsize, sync::atomic::Ordering}; + +#[cfg(not(feature = "std"))] +use alloc::sync::Arc; +#[cfg(feature = "std")] +use std::sync::Arc; +use tq_network::PacketEncode; + +#[derive(Clone, Debug)] +pub struct ActorHandle { + id: Arc, +} + +impl ActorHandle { + pub fn id(&self) -> usize { self.id.load(Ordering::Relaxed) } + + pub fn set_id(&self, id: usize) { self.id.store(id, Ordering::Relaxed); } +} /// A trait for querying a single value from a type. /// @@ -23,10 +40,30 @@ impl Get for GetDefault { fn get() -> T { T::default() } } -pub trait Config: Send + Sync + 'static {} +pub trait Config: Send + Sync + 'static { + /// Enqueue the packet and send it to the client connected to this actor + fn send( + handle: &ActorHandle, + packet: P, + ) -> Result<(), P::Error>; + + /// Enqueue the packets and send it all at once to the client connected to + /// this actor + fn send_all(handle: &ActorHandle, packets: I) -> Result<(), P::Error> + where + P: PacketEncode, + I: IntoIterator; + + fn generate_keys( + handle: &ActorHandle, + seed: u64, + ) -> Result<(), tq_network::Error>; + + /// Shutdown the actor and disconnect the client. + fn shutdown(handle: &ActorHandle) -> Result<(), tq_network::Error>; +} -#[async_trait::async_trait] pub trait ProcessPacket { type Error; - async fn process(&self, actor: ActorHandle) -> Result<(), Self::Error>; + fn process(&self, actor: ActorHandle) -> Result<(), Self::Error>; } diff --git a/packets/account/Cargo.toml b/packets/account/Cargo.toml index cab4a02..c481fa2 100644 --- a/packets/account/Cargo.toml +++ b/packets/account/Cargo.toml @@ -11,7 +11,6 @@ tq-network.workspace = true tq-system.workspace = true serde.workspace = true -async-trait.workspace = true tracing.workspace = true msg-connect-ex.workspace = true diff --git a/packets/account/src/lib.rs b/packets/account/src/lib.rs index c3636c1..9080bc5 100644 --- a/packets/account/src/lib.rs +++ b/packets/account/src/lib.rs @@ -3,9 +3,10 @@ use msg_connect_ex::{MsgConnectEx, RejectionCode}; use msg_transfer::MsgTransfer; use serde::Deserialize; -use tq_network::{ActorHandle, PacketID}; +use tq_network::PacketID; use tq_serde::{String16, TQPassword}; +use tq_system::ActorHandle; pub use traits::Authanticator; mod functions; @@ -31,13 +32,12 @@ pub trait Config: msg_transfer::Config { type Authanticator: Authanticator; } -#[async_trait::async_trait] impl tq_system::ProcessPacket for MsgAccount { type Error = Error; - async fn process(&self, actor: ActorHandle) -> Result<(), Self::Error> { + fn process(&self, actor: ActorHandle) -> Result<(), Self::Error> { let maybe_accont_id = - T::Authanticator::auth(&self.username, &self.password).await; + T::Authanticator::auth(&self.username, &self.password); let account_id = match maybe_accont_id { Ok(id) => id, Err(e) => { @@ -50,12 +50,12 @@ impl tq_system::ProcessPacket for MsgAccount { RejectionCode::TryAgainLater.packet() }, }; - actor.send(res).await?; + T::send(&actor, res)?; return Ok(()); }, }; actor.set_id(account_id as usize); - let res = match MsgTransfer::::handle(&actor, &self.realm).await { + let res = match MsgTransfer::::handle(&actor, &self.realm) { Ok(res) => res, _ => { tracing::warn!( @@ -66,12 +66,13 @@ impl tq_system::ProcessPacket for MsgAccount { }, }; let res = MsgConnectEx::forword_connection(res); - actor.send(res).await?; + T::send(&actor, res)?; Ok(()) } } /// Possible errors that can occur while processing a packet. +#[derive(Debug)] pub enum Error { /// User has entered an invalid username or password. InvalidUsernameOrPassword, diff --git a/packets/account/src/traits.rs b/packets/account/src/traits.rs index 6333542..8fc16b1 100644 --- a/packets/account/src/traits.rs +++ b/packets/account/src/traits.rs @@ -1,4 +1,13 @@ -#[async_trait::async_trait] pub trait Authanticator { - async fn auth(username: &str, password: &str) -> Result; + fn auth(username: &str, password: &str) -> Result; +} + +// A dummy authanticator that always rejects the login attempt. +impl Authanticator for () { + fn auth( + _username: &str, + _password: &str, + ) -> Result { + Err(crate::Error::InvalidUsernameOrPassword) + } } diff --git a/packets/connect/Cargo.toml b/packets/connect/Cargo.toml new file mode 100644 index 0000000..db8bb07 --- /dev/null +++ b/packets/connect/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "msg-connect" +version = "0.1.0" +edition.workspace = true + +[dependencies] +tq-serde.workspace = true +tq-network.workspace = true +tq-system.workspace = true + +serde.workspace = true + +[features] +default = ["std"] +std = ["tq-serde/std", "tq-network/std", "tq-system/std"] diff --git a/packets/connect/src/lib.rs b/packets/connect/src/lib.rs new file mode 100644 index 0000000..f6251a4 --- /dev/null +++ b/packets/connect/src/lib.rs @@ -0,0 +1,49 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use serde::Deserialize; +use tq_network::PacketID; +use tq_serde::String16; +use tq_system::ActorHandle; +/// Message containing a connection request to the game server. Contains the +/// player's access token from the Account server, and the patch and language +/// versions of the game client. +#[derive(Debug, Deserialize, PacketID)] +#[packet(id = 1052)] +#[allow(dead_code)] +pub struct MsgConnect { + id: u32, + file_contents: u32, + file_name: String16, + #[serde(skip)] + _config: std::marker::PhantomData, +} + +pub trait Config: tq_system::Config {} + +impl tq_system::ProcessPacket for MsgConnect { + type Error = Error; + + fn process(&self, actor: ActorHandle) -> Result<(), Self::Error> { + T::shutdown(&actor)?; + Ok(()) + } +} + +/// Possible errors that can occur while processing a packet. +#[derive(Debug)] +pub enum Error { + /// Internal Network error. + Network(tq_network::Error), +} + +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Network(e) => write!(f, "Network error: {}", e), + } + } +} + +impl From for Error { + fn from(e: tq_network::Error) -> Self { Self::Network(e) } +} diff --git a/packets/transfer/Cargo.toml b/packets/transfer/Cargo.toml index fa23b8c..7f6f776 100644 --- a/packets/transfer/Cargo.toml +++ b/packets/transfer/Cargo.toml @@ -11,7 +11,6 @@ tq-network.workspace = true tq-system.workspace = true serde.workspace = true -async-trait.workspace = true tracing.workspace = true bytes.workspace = true diff --git a/packets/transfer/src/functions.rs b/packets/transfer/src/functions.rs index d9b5669..34789ee 100644 --- a/packets/transfer/src/functions.rs +++ b/packets/transfer/src/functions.rs @@ -1,17 +1,16 @@ use msg_connect_ex::{AccountCredentials, RejectionCode}; -use tq_network::{ActorHandle, IntoErrorPacket}; +use tq_network::IntoErrorPacket; use crate::types::Realm; use super::*; impl MsgTransfer { - #[tracing::instrument(skip(actor))] - pub async fn handle( + pub fn handle( actor: &ActorHandle, realm: &str, ) -> Result { - let maybe_realm = T::RealmByName::by_name(realm).await?; + let maybe_realm = T::RealmByName::by_name(realm)?; // Check if there is a realm with that name let realm = match maybe_realm { Some(realm) => realm, @@ -23,7 +22,7 @@ impl MsgTransfer { }, }; // Try to connect to that realm first. - if let Err(e) = T::ServerBus::check(&realm).await { + if let Err(e) = T::ServerBus::check(&realm) { tracing::error!( ip = realm.game_ip_address, port = realm.game_port, @@ -31,19 +30,18 @@ impl MsgTransfer { error = ?e, "Failed to connect to realm" ); - actor.send(RejectionCode::ServerDown.packet()).await?; - actor.shutdown().await?; + T::send(actor, RejectionCode::ServerDown.packet())?; + T::shutdown(actor)?; return Err(e); } - Self::transfer(actor, realm).await + Self::transfer(actor, realm) } - #[tracing::instrument(skip(actor), err, fields(realm = realm.name))] - async fn transfer( + fn transfer( actor: &ActorHandle, realm: Realm, ) -> Result { - let res = T::ServerBus::transfer(actor, &realm).await; + let res = T::ServerBus::transfer(actor, &realm); match res { Ok(token) => Ok(AccountCredentials { token, diff --git a/packets/transfer/src/lib.rs b/packets/transfer/src/lib.rs index 696348b..ac272e7 100644 --- a/packets/transfer/src/lib.rs +++ b/packets/transfer/src/lib.rs @@ -1,8 +1,9 @@ #![cfg_attr(not(feature = "std"), no_std)] use serde::{Deserialize, Serialize}; -use tq_network::{ActorHandle, ErrorPacket, PacketEncode, PacketID}; +use tq_network::{ErrorPacket, PacketEncode, PacketID}; +use tq_system::ActorHandle; pub use traits::{RealmByName, ServerBus, TokenGenerator}; mod functions; @@ -11,7 +12,7 @@ mod types; /// Defines account parameters to be transferred from the account server to the /// game server. Account information is supplied from the account database, and -/// used on the game server to transfer authentication and authority level. +/// used on the game server to transfer authentication and authority level. #[derive(Clone, Default, Debug, Deserialize, Serialize, PacketID)] #[packet(id = 4001)] pub struct MsgTransfer { @@ -32,11 +33,10 @@ pub trait Config: tq_system::Config { type ServerBus: ServerBus; } -#[async_trait::async_trait] impl tq_system::ProcessPacket for MsgTransfer { type Error = Error; - async fn process(&self, actor: ActorHandle) -> Result<(), Self::Error> { + fn process(&self, actor: ActorHandle) -> Result<(), Self::Error> { let token = T::TokenGenerator::generate_login_token( self.account_id, self.realm_id, @@ -47,8 +47,8 @@ impl tq_system::ProcessPacket for MsgTransfer { token, _config: core::marker::PhantomData, }; - actor.send(msg).await?; - actor.shutdown().await?; + T::send(&actor, msg)?; + T::shutdown(&actor)?; Ok(()) } } @@ -58,6 +58,8 @@ impl tq_system::ProcessPacket for MsgTransfer { pub enum Error { /// Failed to generate a login token. TokenGenerationFailed, + /// The realm is unavailable. + RealmUnavailable, /// Internal Network error. Network(tq_network::Error), /// An error packet to be sent to the client. @@ -70,6 +72,7 @@ impl core::fmt::Display for Error { Self::TokenGenerationFailed => { write!(f, "Failed to generate a login token") }, + Self::RealmUnavailable => write!(f, "Realm is unavailable"), Self::Network(e) => write!(f, "Network error: {}", e), Self::Msg(id, body) => { write!(f, "Error packet: id = {}, body = {:?}", id, body) diff --git a/packets/transfer/src/traits.rs b/packets/transfer/src/traits.rs index 9539df4..ae06a01 100644 --- a/packets/transfer/src/traits.rs +++ b/packets/transfer/src/traits.rs @@ -1,4 +1,4 @@ -use tq_network::ActorHandle; +use tq_system::ActorHandle; use crate::types::Realm; @@ -10,18 +10,45 @@ pub trait TokenGenerator { ) -> Result; } +// A dummy token generator that always returns 0. +impl TokenGenerator for () { + fn generate_login_token( + _account_id: u32, + _realm_id: u32, + ) -> Result { + Ok(0) + } +} + /// Trait for querying realms by name. -#[async_trait::async_trait] pub trait RealmByName { - async fn by_name(name: &str) -> Result, crate::Error>; + fn by_name(name: &str) -> Result, crate::Error>; +} + +// A dummy realm query that always returns None. +impl RealmByName for () { + fn by_name(_name: &str) -> Result, crate::Error> { Ok(None) } } -#[async_trait::async_trait] pub trait ServerBus { - async fn check(realm: &Realm) -> Result<(), crate::Error>; + fn check(realm: &Realm) -> Result<(), crate::Error>; - async fn transfer( + fn transfer( actor: &ActorHandle, realm: &Realm, ) -> Result; } + +// A dummy server bus that always returns an error. +impl ServerBus for () { + fn check(_realm: &Realm) -> Result<(), crate::Error> { + Err(crate::Error::RealmUnavailable) + } + + fn transfer( + _actor: &ActorHandle, + _realm: &Realm, + ) -> Result { + Err(crate::Error::RealmUnavailable) + } +} diff --git a/server/auth/Cargo.toml b/server/auth/Cargo.toml index 10b1e8b..d34ef78 100644 --- a/server/auth/Cargo.toml +++ b/server/auth/Cargo.toml @@ -20,13 +20,19 @@ tq-db.workspace = true tq-server.workspace = true tq-network.workspace = true tq-serde.workspace = true +tq-system.workspace = true async-trait.workspace = true tracing.workspace = true dotenvy.workspace = true -once_cell.workspace = true tokio-stream.workspace = true num_enum.workspace = true +# Packets +msg-account.workspace = true +msg-transfer.workspace = true +msg-connect-ex.workspace = true +msg-connect.workspace = true + [dependencies.tracing-subscriber] version = "0.3" default-features = false @@ -49,4 +55,9 @@ default = [] std = [ "tq-network/std", "tq-serde/std", + "tq-system/std", + "msg-account/std", + "msg-transfer/std", + "msg-connect-ex/std", + "msg-connect/std" ] diff --git a/server/auth/src/error.rs b/server/auth/src/error.rs index 408268b..4a04b18 100644 --- a/server/auth/src/error.rs +++ b/server/auth/src/error.rs @@ -18,6 +18,8 @@ pub enum Error { State(&'static str), Other(String), Msg(u16, Bytes), + MsgAccount(msg_account::Error), + Msgconnect(msg_connect::Error), } impl From for Error { @@ -50,6 +52,14 @@ impl From for Error { fn from(v: tq_network::Error) -> Self { Self::Network(v) } } +impl From for Error { + fn from(v: msg_account::Error) -> Self { Self::MsgAccount(v) } +} + +impl From for Error { + fn from(v: msg_connect::Error) -> Self { Self::Msgconnect(v) } +} + #[cfg(feature = "std")] impl std::error::Error for Error {} @@ -70,6 +80,8 @@ impl core::fmt::Display for Error { Self::Msg(id, bytes) => { write!(f, "Error packet: id = {}, body = {:?}", id, bytes) }, + Self::MsgAccount(e) => write!(f, "MsgAccount error: {}", e), + Self::Msgconnect(e) => write!(f, "MsgConnect error: {}", e), } } } diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index 0fb451d..5a715aa 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -10,3 +10,51 @@ pub mod state; pub use error::Error; pub use state::State; + +#[derive(Clone, Copy)] +pub struct Runtime; + +impl tq_system::Config for Runtime { + fn send( + handle: &tq_system::ActorHandle, + packet: P, + ) -> Result<(), P::Error> { + todo!() + } + + fn send_all( + handle: &tq_system::ActorHandle, + packets: I, + ) -> Result<(), P::Error> + where + P: tq_network::PacketEncode, + I: IntoIterator, + { + todo!() + } + + fn generate_keys( + handle: &tq_system::ActorHandle, + seed: u64, + ) -> Result<(), tq_network::Error> { + todo!() + } + + fn shutdown( + handle: &tq_system::ActorHandle, + ) -> Result<(), tq_network::Error> { + todo!() + } +} + +impl msg_account::Config for Runtime { + type Authanticator = (); +} + +impl msg_connect::Config for Runtime {} + +impl msg_transfer::Config for Runtime { + type RealmByName = (); + type ServerBus = (); + type TokenGenerator = (); +} diff --git a/server/auth/src/main.rs b/server/auth/src/main.rs index 1c5b553..4fbb468 100644 --- a/server/auth/src/main.rs +++ b/server/auth/src/main.rs @@ -4,12 +4,15 @@ //! correct with the database. If the combination is correct, the client //! will be transferred to the message server of their choice. +use bytes::Bytes; +use msg_account::MsgAccount; +use msg_connect::MsgConnect; use std::env; -use tq_network::{PacketHandler, TQCipher}; +use tq_network::{Actor, PacketDecode, PacketHandler, PacketID, TQCipher}; use tq_server::TQServer; -use auth::packets::{MsgAccount, MsgConnect}; -use auth::{Error, State}; +use auth::{Error, Runtime, State}; +use tq_system::ProcessPacket; struct AuthServer; @@ -19,11 +22,34 @@ impl TQServer for AuthServer { type PacketHandler = AuthServerHandler; } -#[derive(Debug, PacketHandler)] -#[handle(state = State, actor_state = ())] -pub enum AuthServerHandler { - MsgAccount, - MsgConnect, +enum AuthServerHandler {} + +#[async_trait::async_trait] +impl PacketHandler for AuthServerHandler { + type ActorState = (); + type Error = Error; + type State = State; + + async fn handle( + packet: (u16, Bytes), + state: &Self::State, + actor: &Actor, + ) -> Result<(), Self::Error> { + match packet.0 { + MsgAccount::::PACKET_ID => { + let packet = MsgAccount::::decode(&packet.1)?; + packet.process(actor.handle()).await?; + }, + MsgConnect::::PACKET_ID => { + let packet = MsgConnect::::decode(&packet.1)?; + packet.process(actor.handle()).await?; + }, + _ => { + tracing::warn!("Unknown packet: {:#?}", packet); + }, + } + Ok(()) + } } #[tokio::main] diff --git a/server/game/Cargo.toml b/server/game/Cargo.toml index c99ae1f..ba29440 100644 --- a/server/game/Cargo.toml +++ b/server/game/Cargo.toml @@ -26,7 +26,6 @@ primitives.workspace = true async-trait.workspace = true tracing.workspace = true dotenvy.workspace = true -once_cell.workspace = true tokio-stream.workspace = true rand.workspace = true chrono.workspace = true From 7e0fa1c0ae694326cf534fabb1096b8601e22f1a Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Fri, 29 Dec 2023 13:12:36 +0200 Subject: [PATCH 09/28] Use wasm32-wasi --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 86e8f38..a008d53 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] channel = "nightly" components = ["rustfmt", "clippy", "rust-src"] -targets = ["wasm32-unknown-unknown"] +targets = ["wasm32-wasi"] From 9388b2dde68096e6ef519d418155e86398c10836 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Fri, 29 Dec 2023 18:38:11 +0200 Subject: [PATCH 10/28] working on using wasmtime --- Cargo.lock | 1133 +++++++++++++++++++++++++++++-- Cargo.toml | 15 +- crates/db/Cargo.toml | 2 +- crates/externalities/Cargo.toml | 21 - crates/externalities/src/lib.rs | 47 -- crates/io/Cargo.toml | 30 - crates/io/src/lib.rs | 51 -- crates/system/Cargo.toml | 13 - crates/system/src/lib.rs | 69 -- flake.nix | 1 + packets/account/Cargo.toml | 2 - packets/connect/Cargo.toml | 20 +- packets/connect/src/lib.rs | 54 +- packets/connect/wit/deps | 1 + packets/connect/wit/world.wit | 12 + packets/transfer/Cargo.toml | 2 - server/auth/Cargo.toml | 43 +- server/auth/src/error.rs | 21 +- server/auth/src/lib.rs | 134 ++-- server/auth/src/main.rs | 62 +- server/auth/src/state.rs | 14 +- tools/benchbot/Cargo.toml | 2 +- wit/actor/types.wit | 15 + 23 files changed, 1342 insertions(+), 422 deletions(-) delete mode 100644 crates/externalities/Cargo.toml delete mode 100644 crates/externalities/src/lib.rs delete mode 100644 crates/io/Cargo.toml delete mode 100644 crates/io/src/lib.rs delete mode 100644 crates/system/Cargo.toml delete mode 100644 crates/system/src/lib.rs create mode 120000 packets/connect/wit/deps create mode 100644 packets/connect/wit/world.wit create mode 100644 wit/actor/types.wit diff --git a/Cargo.lock b/Cargo.lock index 5c9e7ab..f86887e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,12 +45,24 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +[[package]] +name = "ambient-authority" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" + [[package]] name = "anyhow" version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + [[package]] name = "arc-swap" version = "1.6.0" @@ -76,7 +88,7 @@ dependencies = [ "argh_shared", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -107,7 +119,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -118,7 +130,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -156,10 +168,7 @@ dependencies = [ "async-trait", "bytes", "dotenvy", - "msg-account", "msg-connect", - "msg-connect-ex", - "msg-transfer", "num_enum", "serde", "sqlx", @@ -170,9 +179,10 @@ dependencies = [ "tq-network", "tq-serde", "tq-server", - "tq-system", "tracing", "tracing-subscriber", + "wasmtime", + "wasmtime-wasi", ] [[package]] @@ -290,6 +300,15 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -324,6 +343,12 @@ dependencies = [ "cipher", ] +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + [[package]] name = "bytemuck" version = "1.14.0" @@ -341,7 +366,7 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -356,12 +381,109 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +[[package]] +name = "cap-fs-ext" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b779b2d0a001c125b4584ad586268fb4b92d957bff8d26d7fe0dd78283faa814" +dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes", + "windows-sys 0.48.0", +] + +[[package]] +name = "cap-net-ext" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ffc30dee200c20b4dcb80572226f42658e1d9c4b668656d7cc59c33d50e396e" +dependencies = [ + "cap-primitives", + "cap-std", + "rustix", + "smallvec", +] + +[[package]] +name = "cap-primitives" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf30c373a3bee22c292b1b6a7a26736a38376840f1af3d2d806455edf8c3899" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes", + "ipnet", + "maybe-owned", + "rustix", + "windows-sys 0.48.0", + "winx", +] + +[[package]] +name = "cap-rand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "577de6cff7c2a47d6b13efe5dd28bf116bd7f8f7db164ea95b7cc2640711f522" +dependencies = [ + "ambient-authority", + "rand", +] + +[[package]] +name = "cap-std" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84bade423fa6403efeebeafe568fdb230e8c590a275fba2ba978dd112efcf6e9" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes", + "rustix", +] + +[[package]] +name = "cap-time-ext" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f52b3c8f4abfe3252fd0a071f3004aaa3b18936ec97bdbd8763ce03aff6247" +dependencies = [ + "cap-primitives", + "once_cell", + "rustix", + "winx", +] + +[[package]] +name = "cargo-component-bindings" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545e48ba821e07f93c97aea897bee6d407de4d58947f914160131f3d78b2c704" +dependencies = [ + "cargo-component-macro", + "wit-bindgen", +] + +[[package]] +name = "cargo-component-macro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e198ee0b668e902b43b5e7d2e9620a3891d2632429b3ba66e1ceea455053cbf5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.43", +] + [[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] @@ -443,6 +565,115 @@ dependencies = [ "libc", ] +[[package]] +name = "cranelift-bforest" +version = "0.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c22542c0b95bd3302f7ed6839869c561f2324bac2fd5e7e99f5cfa65fdc8b92" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3db903ef2e9c8a4de2ea6db5db052c7857282952f9df604aa55d169e6000d8" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.14.3", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6590feb5a1d6438f974bf6a5ac4dddf69fca14e1f07f3265d880f69e61a94463" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7239038c56fafe77fddc8788fc8533dd6c474dc5bdc5637216404f41ba807330" + +[[package]] +name = "cranelift-control" +version = "0.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7dc9c595341404d381d27a3d950160856b35b402275f0c3990cd1ad683c8053" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44e3ee532fc4776c69bcedf7e62f9632cbb3f35776fa9a525cdade3195baa3f7" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-frontend" +version = "0.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a612c94d09e653662ec37681dc2d6fd2b9856e6df7147be0afc9aabb0abf19df" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85db9830abeb1170b7d29b536ffd55af1d4d26ac8a77570b5d1aca003bf225cc" + +[[package]] +name = "cranelift-native" +version = "0.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301ef0edafeaeda5771a5d2db64ac53e1818ae3111220a185677025fe91db4a1" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-wasm" +version = "0.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380f0abe8264e4570ac615fc31cef32a3b90a77f7eb97b08331f9dd357b1f500" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools 0.10.5", + "log", + "smallvec", + "wasmparser", + "wasmtime-types", +] + [[package]] name = "crc" version = "3.0.1" @@ -553,7 +784,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -561,7 +792,7 @@ name = "derive-packetid" version = "0.1.0" dependencies = [ "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -576,6 +807,47 @@ dependencies = [ "subtle", ] +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -592,10 +864,13 @@ dependencies = [ ] [[package]] -name = "environmental" -version = "1.1.4" +name = "encoding_rs" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] [[package]] name = "equivalent" @@ -630,12 +905,29 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + [[package]] name = "fastrand" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "fd-lock" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b0377f1edc77dbd1118507bc7a66e4ab64d2b90c66f90726dc801e73a8c68f9" +dependencies = [ + "cfg-if", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "finl_unicode" version = "1.2.0" @@ -678,6 +970,17 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs-set-times" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "033b337d725b97690d86893f9de22b67b80dcc4e9ad815f348254c38119db8fb" +dependencies = [ + "io-lifetimes", + "rustix", + "windows-sys 0.52.0", +] + [[package]] name = "futures" version = "0.3.29" @@ -834,6 +1137,11 @@ name = "gimli" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +dependencies = [ + "fallible-iterator", + "indexmap 2.1.0", + "stable_deref_trait", +] [[package]] name = "h2" @@ -867,6 +1175,15 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.14.3" @@ -1023,6 +1340,12 @@ dependencies = [ "tokio-io-timeout", ] +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + [[package]] name = "idna" version = "0.5.0" @@ -1051,6 +1374,7 @@ checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown 0.14.3", + "serde", ] [[package]] @@ -1062,6 +1386,37 @@ dependencies = [ "generic-array", ] +[[package]] +name = "io-extras" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c301e73fb90e8a29e600a9f402d095765f74310d582916a952f618836a1bd1ed" +dependencies = [ + "io-lifetimes", + "windows-sys 0.52.0", +] + +[[package]] +name = "io-lifetimes" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a611371471e98973dbcab4e0ec66c31a10bc356eeb4d54a0e05eac8158fe38c" + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.11.0" @@ -1086,6 +1441,15 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1095,6 +1459,12 @@ dependencies = [ "spin 0.5.2", ] +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + [[package]] name = "libc" version = "0.2.151" @@ -1107,6 +1477,17 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall", +] + [[package]] name = "libsqlite3-sys" version = "0.27.0" @@ -1152,6 +1533,15 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1167,6 +1557,12 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + [[package]] name = "md-5" version = "0.10.6" @@ -1184,16 +1580,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] -name = "mime" -version = "0.3.17" +name = "memfd" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +dependencies = [ + "rustix", +] [[package]] -name = "minimal-lexical" -version = "0.2.1" +name = "memoffset" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" @@ -1226,7 +1640,6 @@ dependencies = [ "tq-crypto", "tq-network", "tq-serde", - "tq-system", "tracing", ] @@ -1234,10 +1647,11 @@ dependencies = [ name = "msg-connect" version = "0.1.0" dependencies = [ + "bytes", + "cargo-component-bindings", "serde", "tq-network", "tq-serde", - "tq-system", ] [[package]] @@ -1261,7 +1675,6 @@ dependencies = [ "tq-crypto", "tq-network", "tq-serde", - "tq-system", "tracing", ] @@ -1396,7 +1809,7 @@ checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -1405,6 +1818,9 @@ version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ + "crc32fast", + "hashbrown 0.14.3", + "indexmap 2.1.0", "memchr", ] @@ -1481,7 +1897,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -1551,9 +1967,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" dependencies = [ "unicode-ident", ] @@ -1578,7 +1994,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -1590,6 +2006,15 @@ dependencies = [ "prost", ] +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + [[package]] name = "quote" version = "1.0.33" @@ -1638,6 +2063,30 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regalloc2" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" +dependencies = [ + "hashbrown 0.13.2", + "log", + "rustc-hash", + "slice-group-by", + "smallvec", +] + [[package]] name = "regex" version = "1.10.2" @@ -1722,6 +2171,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustix" version = "0.38.28" @@ -1730,8 +2185,10 @@ checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ "bitflags 2.4.1", "errno", + "itoa", "libc", "linux-raw-sys", + "once_cell", "windows-sys 0.52.0", ] @@ -1793,6 +2250,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + [[package]] name = "serde" version = "1.0.193" @@ -1810,7 +2273,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -1855,6 +2318,15 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shellexpand" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4" +dependencies = [ + "dirs", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -1883,6 +2355,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + [[package]] name = "smallvec" version = "1.11.2" @@ -1924,6 +2402,12 @@ dependencies = [ "der", ] +[[package]] +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" + [[package]] name = "sqlformat" version = "0.2.3" @@ -2139,6 +2623,12 @@ dependencies = [ "urlencoding", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "stringprep" version = "0.1.4" @@ -2169,9 +2659,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.41" +version = "2.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" dependencies = [ "proc-macro2", "quote", @@ -2184,6 +2674,28 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "system-interface" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ce32341b2c0b70c144bbf35627fdc1ef18c76ced5e5e7b3ee8b5ba6b2ab6a0" +dependencies = [ + "bitflags 2.4.1", + "cap-fs-ext", + "cap-std", + "fd-lock", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", + "winx", +] + +[[package]] +name = "target-lexicon" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" + [[package]] name = "tempfile" version = "3.8.1" @@ -2214,7 +2726,7 @@ checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -2309,7 +2821,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -2337,6 +2849,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "tonic" version = "0.10.2" @@ -2428,25 +2949,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tq-externalities" -version = "0.1.0" -dependencies = [ - "async-trait", - "environmental", - "futures", - "sqlx", -] - -[[package]] -name = "tq-io" -version = "0.1.0" -dependencies = [ - "sqlx", - "tokio", - "tq-externalities", -] - [[package]] name = "tq-math" version = "0.1.0" @@ -2498,13 +3000,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tq-system" -version = "0.1.0" -dependencies = [ - "tq-network", -] - [[package]] name = "tracing" version = "0.1.40" @@ -2525,7 +3020,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -2595,6 +3090,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "unicode_categories" version = "0.1.1" @@ -2657,6 +3158,383 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi-common" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d888b611fee7d273dd057dc009d2dd3132736f36710ffd65657ac83628d1e3b" +dependencies = [ + "anyhow", + "bitflags 2.4.1", + "cap-rand", + "cap-std", + "io-extras", + "log", + "rustix", + "thiserror", + "tracing", + "wasmtime", + "wiggle", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.38.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasmparser" +version = "0.118.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9" +dependencies = [ + "indexmap 2.1.0", + "semver", +] + +[[package]] +name = "wasmprinter" +version = "0.2.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d027eb8294904fc715ac0870cebe6b0271e96b90605ee21511e7565c4ce568c" +dependencies = [ + "anyhow", + "wasmparser", +] + +[[package]] +name = "wasmtime" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8e539fded2495422ea3c4dfa7beeddba45904eece182cf315294009e1a323bf" +dependencies = [ + "anyhow", + "async-trait", + "bincode", + "bumpalo", + "cfg-if", + "encoding_rs", + "indexmap 2.1.0", + "libc", + "log", + "object", + "once_cell", + "paste", + "serde", + "serde_derive", + "serde_json", + "target-lexicon", + "wasm-encoder", + "wasmparser", + "wasmtime-cache", + "wasmtime-component-macro", + "wasmtime-component-util", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-fiber", + "wasmtime-jit", + "wasmtime-runtime", + "wasmtime-winch", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "660ba9143e15a2acd921820df221b73aee256bd3ca2d208d73d8adc9587ccbb9" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-cache" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ce373743892002f9391c6741ef0cb0335b55ec899d874f311222b7e36f4594" +dependencies = [ + "anyhow", + "base64", + "bincode", + "directories-next", + "log", + "rustix", + "serde", + "serde_derive", + "sha2", + "toml", + "windows-sys 0.48.0", + "zstd", +] + +[[package]] +name = "wasmtime-component-macro" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ef32643324e564e1c359e9044daa06cbf90d7e2d6c99a738d17a12959f01a5" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn 2.0.43", + "wasmtime-component-util", + "wasmtime-wit-bindgen", + "wit-parser", +] + +[[package]] +name = "wasmtime-component-util" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c87d06c18d21a4818f354c00a85f4ebc62b2270961cd022968452b0e4dbed9d" + +[[package]] +name = "wasmtime-cranelift" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d648c8b4064a7911093b02237cd5569f71ca171d3a0a486bf80600b19e1cba2" +dependencies = [ + "anyhow", + "cfg-if", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli", + "log", + "object", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-cranelift-shared", + "wasmtime-environ", + "wasmtime-versioned-export-macros", +] + +[[package]] +name = "wasmtime-cranelift-shared" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290a89027688782da8ff60b12bb95695494b1874e0d0ba2ba387d23dace6d70c" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "cranelift-native", + "gimli", + "object", + "target-lexicon", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-environ" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61eb64fb3e0da883e2df4a13a81d6282e072336e6cb6295021d0f7ab2e352754" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli", + "indexmap 2.1.0", + "log", + "object", + "serde", + "serde_derive", + "target-lexicon", + "thiserror", + "wasm-encoder", + "wasmparser", + "wasmprinter", + "wasmtime-component-util", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-fiber" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecf1d3a838b0956b71ad3f8cb80069a228339775bf02dd35d86a5a68bbe443" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "rustix", + "wasmtime-asm-macros", + "wasmtime-versioned-export-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-jit" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f485336add49267d8859e8f8084d2d4b9a4b1564496b6f30ba5b168d50c10ceb" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "gimli", + "log", + "object", + "rustix", + "serde", + "serde_derive", + "target-lexicon", + "wasmtime-environ", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b6d197fcc34ad32ed440e1f9552fd57d1f377d9699d31dee1b5b457322c1f8a" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-runtime" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794b2bb19b99ef8322ff0dd9fe1ba7e19c41036dfb260b3f99ecce128c42ff92" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "encoding_rs", + "indexmap 2.1.0", + "libc", + "log", + "mach", + "memfd", + "memoffset", + "paste", + "psm", + "rustix", + "sptr", + "wasm-encoder", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-fiber", + "wasmtime-versioned-export-macros", + "wasmtime-wmemcheck", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-types" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d995db8bb56f2cd8d2dc0ed5ffab94ffb435283b0fe6747f80f7aab40b2d06a1" +dependencies = [ + "cranelift-entity", + "serde", + "serde_derive", + "thiserror", + "wasmparser", +] + +[[package]] +name = "wasmtime-versioned-export-macros" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55c5565959287c21dd0f4277ae3518dd2ae62679f655ee2dbc4396e19d210db" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.43", +] + +[[package]] +name = "wasmtime-wasi" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccd8370078149d49a3a47e93741553fd79b700421464b6a27ca32718192ab130" +dependencies = [ + "anyhow", + "async-trait", + "bitflags 2.4.1", + "bytes", + "cap-fs-ext", + "cap-net-ext", + "cap-rand", + "cap-std", + "cap-time-ext", + "fs-set-times", + "futures", + "io-extras", + "io-lifetimes", + "libc", + "log", + "once_cell", + "rustix", + "system-interface", + "thiserror", + "tokio", + "tracing", + "url", + "wasi-common", + "wasmtime", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-winch" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6f945ff9bad96e0a69973d74f193c19f627c8adbf250e7cb73ae7564b6cc8a" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "object", + "target-lexicon", + "wasmparser", + "wasmtime-cranelift-shared", + "wasmtime-environ", + "winch-codegen", +] + +[[package]] +name = "wasmtime-wit-bindgen" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f328b2d4a690270324756e886ed5be3a4da4c00be0eea48253f4595ad068062b" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.1.0", + "wit-parser", +] + +[[package]] +name = "wasmtime-wmemcheck" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67761d8f8c0b3c13a5d34356274b10a40baba67fe9cfabbfc379a8b414e45de2" + +[[package]] +name = "wast" +version = "35.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" +dependencies = [ + "leb128", +] + [[package]] name = "webpki-roots" version = "0.25.3" @@ -2669,6 +3547,48 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" +[[package]] +name = "wiggle" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0afb26cd3269289bb314a361ff0a6685e5ce793b62181a9fe3f81ace15051697" +dependencies = [ + "anyhow", + "async-trait", + "bitflags 2.4.1", + "thiserror", + "tracing", + "wasmtime", + "wiggle-macro", +] + +[[package]] +name = "wiggle-generate" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef2868fed7584d2b552fa317104858ded80021d23b073b2d682d3c932a027bd" +dependencies = [ + "anyhow", + "heck", + "proc-macro2", + "quote", + "shellexpand", + "syn 2.0.43", + "witx", +] + +[[package]] +name = "wiggle-macro" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31ae1ec11a17ea481539ee9a5719a278c9790d974060fbf71db4b2c05378780b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.43", + "wiggle-generate", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2691,6 +3611,22 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winch-codegen" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58e58c236a6abdd9ab454552b4f29e16cfa837a86897c1503313b2e62e7609ec" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "regalloc2", + "smallvec", + "target-lexicon", + "wasmparser", + "wasmtime-environ", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -2823,6 +3759,54 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "winx" +version = "0.36.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9643b83820c0cd246ecabe5fa454dd04ba4fa67996369466d0747472d337346" +dependencies = [ + "bitflags 2.4.1", + "windows-sys 0.52.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b76f1d099678b4f69402a421e888bbe71bf20320c2f3f3565d0e7484dbe5bc20" +dependencies = [ + "bitflags 2.4.1", +] + +[[package]] +name = "wit-parser" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15df6b7b28ce94b8be39d8df5cb21a08a4f3b9f33b631aedb4aa5776f785ead3" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.1.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", +] + +[[package]] +name = "witx" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" +dependencies = [ + "anyhow", + "log", + "thiserror", + "wast", +] + [[package]] name = "zerocopy" version = "0.7.31" @@ -2840,7 +3824,7 @@ checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.43", ] [[package]] @@ -2848,3 +3832,32 @@ name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index cba75fc..bdb8e9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,6 @@ tq-crypto = { path = "crates/crypto" } tq-codec = { path = "crates/codec" } tq-db = { path = "crates/db" } tq-server = { path = "crates/server" } -tq-system = { path = "crates/system" } -tq-io = { path = "crates/io" } -tq-externalities = { path = "crates/externalities" } derive-packetid = { path = "macros/derive-packetid" } derive-packethandler = { path = "macros/derive-packethandler" } @@ -58,9 +55,19 @@ atomic = { version = "0.6", default-features = false } bytemuck = { version = "1.13", default-features = false, features = ["derive"] } chrono = { version = "0.4", default-features = false, features = [] } num_enum = { version = "0.7", default-features = false } -environmental = { version = "1.1.4", default-features = false } bcrypt = "0.15" +# WASM deps +cargo-component-bindings = "0.6.0" + +[workspace.dependencies.wasmtime] +version = "16.0.0" +default-features = false + +[workspace.dependencies.wasmtime-wasi] +version = "16.0.0" +default-features = false + [workspace.dependencies.tokio] version = "1.21.2" default-features = false diff --git a/crates/db/Cargo.toml b/crates/db/Cargo.toml index 33e5f75..91c6e3b 100644 --- a/crates/db/Cargo.toml +++ b/crates/db/Cargo.toml @@ -16,7 +16,7 @@ futures.workspace = true workspace = true default-features = false optional = true -features = ["sqlite"] +features = ["sqlite", "macros"] [features] default = ["sqlx"] diff --git a/crates/externalities/Cargo.toml b/crates/externalities/Cargo.toml deleted file mode 100644 index c2f6fe3..0000000 --- a/crates/externalities/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "tq-externalities" -version = "0.1.0" -edition.workspace = true - -[dependencies] -async-trait.workspace = true -environmental.workspace = true -futures.workspace = true - -[dependencies.sqlx] -default-features = false -workspace = true -features = ["any"] - -[features] -default = [] -std = [ - "environmental/std", - "futures/std" -] diff --git a/crates/externalities/src/lib.rs b/crates/externalities/src/lib.rs deleted file mode 100644 index 73f6948..0000000 --- a/crates/externalities/src/lib.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Externalities abstraction -//! -//! The externalities mainly provide access to storage and to registered -//! extensions. Extensions are for example the RNGs or the Http externalities. -//! These externalities are used to access the server from the runtime via the -//! runtime traits. -//! -//! This crate exposes the main [`Externalities`] trait. - -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(not(feature = "std"))] -extern crate alloc; - -environmental::environmental!(ext: trait Externalities); - -/// The Externalities. -/// -/// Provides access to the storage and to other registered extensions. -pub trait Externalities { - fn executer(&self) -> &sqlx::AnyPool; -} - -/// Set the given externalities while executing the given closure. To get access -/// to the externalities while executing the given closure -/// [`with_externalities`] grants access to them. The externalities are only set -/// for the same thread this function was called from. -pub fn set_and_run_with_externalities( - ext: &mut dyn Externalities, - f: F, -) -> R -where - F: FnOnce() -> R, -{ - ext::using(ext, f) -} - -/// Execute the given closure with the currently set externalities. -/// -/// Returns `None` if no externalities are set or `Some(_)` with the result of -/// the closure. -pub fn with_externalities(f: F) -> Option -where - F: FnOnce(&mut dyn Externalities) -> R, -{ - ext::with(f) -} diff --git a/crates/io/Cargo.toml b/crates/io/Cargo.toml deleted file mode 100644 index a913284..0000000 --- a/crates/io/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "tq-io" -version = "0.1.0" -edition.workspace = true - -[dependencies] -tq-externalities.workspace = true - - -[dependencies.sqlx] -default-features = false -workspace = true -features = ["any"] - - -[dev-dependencies.sqlx] -default-features = false -workspace = true -features = ["runtime-tokio", "sqlite", "any"] - -[dev-dependencies.tokio] -workspace = true -default-features = false -features = ["rt-multi-thread", "macros", "test-util"] - -[features] -default = [] -std = [ - "tq-externalities/std", -] diff --git a/crates/io/src/lib.rs b/crates/io/src/lib.rs deleted file mode 100644 index 4501519..0000000 --- a/crates/io/src/lib.rs +++ /dev/null @@ -1,51 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(not(feature = "std"))] -extern crate alloc; - -use tq_externalities::Externalities; - -pub struct DefaultExtenernalities { - pool: sqlx::AnyPool, -} - -impl DefaultExtenernalities { - pub fn new(pool: sqlx::AnyPool) -> Self { Self { pool } } -} - -impl Externalities for DefaultExtenernalities { - fn executer(&self) -> &sqlx::AnyPool { &self.pool } -} - -#[cfg(test)] -mod tests { - use sqlx::Row; - - use super::*; - - #[tokio::test] - async fn it_works() { - let pool = sqlx::any::AnyPoolOptions::new() - .max_connections(42) - .min_connections(4) - .connect("sqlite::memory:") - .await - .unwrap(); - let mut ext = DefaultExtenernalities::new(pool); - - async fn add_one(x: i32) -> i32 { - tq_externalities::with_externalities(|ext| { - sqlx::query("select 1 + ?1") - .bind(x) - .try_map(|row: sqlx::any::AnyRow| row.try_get::(0)) - .fetch_one(ext.executer()) - }) - .unwrap() - .await - .unwrap() - } - - let p = - tq_externalities::set_and_run_with_externalities(&mut ext, || {}); - } -} diff --git a/crates/system/Cargo.toml b/crates/system/Cargo.toml deleted file mode 100644 index 82600d5..0000000 --- a/crates/system/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "tq-system" -version = "0.1.0" -edition.workspace = true - -[dependencies] -tq-network.workspace = true - -[features] -default = ["std"] -std = [ - "tq-network/std" -] diff --git a/crates/system/src/lib.rs b/crates/system/src/lib.rs deleted file mode 100644 index 0f1b90b..0000000 --- a/crates/system/src/lib.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! This crate is used to define common traits for defining packets and systems -//! in the game servers. - -#![cfg_attr(not(feature = "std"), no_std)] - -use core::{sync::atomic::AtomicUsize, sync::atomic::Ordering}; - -#[cfg(not(feature = "std"))] -use alloc::sync::Arc; -#[cfg(feature = "std")] -use std::sync::Arc; -use tq_network::PacketEncode; - -#[derive(Clone, Debug)] -pub struct ActorHandle { - id: Arc, -} - -impl ActorHandle { - pub fn id(&self) -> usize { self.id.load(Ordering::Relaxed) } - - pub fn set_id(&self, id: usize) { self.id.store(id, Ordering::Relaxed); } -} - -/// A trait for querying a single value from a type. -/// -/// It is not required that the value is constant. -pub trait Get { - /// Return the current value. - fn get() -> T; -} - -impl Get for () { - fn get() -> T { T::default() } -} - -/// Implement Get by returning Default for any type that implements Default. -pub struct GetDefault; -impl Get for GetDefault { - fn get() -> T { T::default() } -} - -pub trait Config: Send + Sync + 'static { - /// Enqueue the packet and send it to the client connected to this actor - fn send( - handle: &ActorHandle, - packet: P, - ) -> Result<(), P::Error>; - - /// Enqueue the packets and send it all at once to the client connected to - /// this actor - fn send_all(handle: &ActorHandle, packets: I) -> Result<(), P::Error> - where - P: PacketEncode, - I: IntoIterator; - - fn generate_keys( - handle: &ActorHandle, - seed: u64, - ) -> Result<(), tq_network::Error>; - - /// Shutdown the actor and disconnect the client. - fn shutdown(handle: &ActorHandle) -> Result<(), tq_network::Error>; -} - -pub trait ProcessPacket { - type Error; - fn process(&self, actor: ActorHandle) -> Result<(), Self::Error>; -} diff --git a/flake.nix b/flake.nix index 7626d34..d8e2472 100644 --- a/flake.nix +++ b/flake.nix @@ -29,6 +29,7 @@ nativeBuildInputs = [ pkgs.pkg-config pkgs.clang + pkgs.openssl # Mold Linker for faster builds (only on Linux) (lib.optionals pkgs.stdenv.isLinux pkgs.mold) (lib.optionals pkgs.stdenv.isDarwin pkgs.darwin.apple_sdk.frameworks.Security) diff --git a/packets/account/Cargo.toml b/packets/account/Cargo.toml index c481fa2..dc141c8 100644 --- a/packets/account/Cargo.toml +++ b/packets/account/Cargo.toml @@ -8,7 +8,6 @@ tq-serde.workspace = true tq-codec.workspace = true tq-crypto.workspace = true tq-network.workspace = true -tq-system.workspace = true serde.workspace = true tracing.workspace = true @@ -23,7 +22,6 @@ std = [ "tq-codec/std", "tq-crypto/std", "tq-network/std", - "tq-system/std", "tracing/std", diff --git a/packets/connect/Cargo.toml b/packets/connect/Cargo.toml index db8bb07..d992631 100644 --- a/packets/connect/Cargo.toml +++ b/packets/connect/Cargo.toml @@ -3,13 +3,29 @@ name = "msg-connect" version = "0.1.0" edition.workspace = true +[lib] +crate-type = ["cdylib", "rlib"] + [dependencies] tq-serde.workspace = true tq-network.workspace = true -tq-system.workspace = true serde.workspace = true +bytes.workspace = true + +# WASM +cargo-component-bindings.workspace = true + +[package.metadata.component] +package = "component:msg-connect" +bindings = { implementor = "MsgConnect", ownership = "borrowing-duplicate-if-necessary" } + +[package.metadata.component.target] +path = "wit" + +[package.metadata.component.target.dependencies] +"coemu:actor" = { path = "../../wit/actor/" } [features] default = ["std"] -std = ["tq-serde/std", "tq-network/std", "tq-system/std"] +std = ["tq-serde/std", "tq-network/std"] diff --git a/packets/connect/src/lib.rs b/packets/connect/src/lib.rs index f6251a4..01c27a2 100644 --- a/packets/connect/src/lib.rs +++ b/packets/connect/src/lib.rs @@ -1,49 +1,41 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(not(feature = "std"))] +extern crate alloc; + +#[cfg(not(feature = "std"))] +use alloc::string::ToString; + +cargo_component_bindings::generate!(); + +pub use bindings::Error; + +use bindings::ActorHandle; +use bytes::Bytes; use serde::Deserialize; -use tq_network::PacketID; +use tq_network::{PacketDecode, PacketID}; use tq_serde::String16; -use tq_system::ActorHandle; /// Message containing a connection request to the game server. Contains the /// player's access token from the Account server, and the patch and language /// versions of the game client. #[derive(Debug, Deserialize, PacketID)] #[packet(id = 1052)] #[allow(dead_code)] -pub struct MsgConnect { +pub struct MsgConnect { id: u32, file_contents: u32, file_name: String16, - #[serde(skip)] - _config: std::marker::PhantomData, } -pub trait Config: tq_system::Config {} - -impl tq_system::ProcessPacket for MsgConnect { - type Error = Error; - - fn process(&self, actor: ActorHandle) -> Result<(), Self::Error> { - T::shutdown(&actor)?; +impl bindings::Guest for MsgConnect { + fn process( + (id, buf): (u16, Vec), + actor: &ActorHandle, + ) -> Result<(), Error> { + assert_eq!(id, MsgConnect::PACKET_ID, "Invalid packet id"); + let _this = MsgConnect::decode(&Bytes::from(buf)) + .map_err(|e| Error::Decode(e.to_string()))?; + actor.shutdown(); Ok(()) } } - -/// Possible errors that can occur while processing a packet. -#[derive(Debug)] -pub enum Error { - /// Internal Network error. - Network(tq_network::Error), -} - -impl core::fmt::Display for Error { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::Network(e) => write!(f, "Network error: {}", e), - } - } -} - -impl From for Error { - fn from(e: tq_network::Error) -> Self { Self::Network(e) } -} diff --git a/packets/connect/wit/deps b/packets/connect/wit/deps new file mode 120000 index 0000000..b0ff866 --- /dev/null +++ b/packets/connect/wit/deps @@ -0,0 +1 @@ +../../../wit \ No newline at end of file diff --git a/packets/connect/wit/world.wit b/packets/connect/wit/world.wit new file mode 100644 index 0000000..fd5cf12 --- /dev/null +++ b/packets/connect/wit/world.wit @@ -0,0 +1,12 @@ +package coemu:msg-connect@0.1.0; + +world msg-connect { + use coemu:actor/types@0.1.0.{actor-handle, packet}; + variant error { + decode(string), + shutdown, + } + export process: func(packet: packet, actor: borrow) -> result<_, error>; +} + +// vim: set ft=typescript ts=2 sw=4 noet: diff --git a/packets/transfer/Cargo.toml b/packets/transfer/Cargo.toml index 7f6f776..6653183 100644 --- a/packets/transfer/Cargo.toml +++ b/packets/transfer/Cargo.toml @@ -8,7 +8,6 @@ tq-serde.workspace = true tq-codec.workspace = true tq-crypto.workspace = true tq-network.workspace = true -tq-system.workspace = true serde.workspace = true tracing.workspace = true @@ -23,7 +22,6 @@ std = [ "tq-codec/std", "tq-crypto/std", "tq-network/std", - "tq-system/std", "tracing/std", diff --git a/server/auth/Cargo.toml b/server/auth/Cargo.toml index d34ef78..2339d8c 100644 --- a/server/auth/Cargo.toml +++ b/server/auth/Cargo.toml @@ -7,6 +7,7 @@ edition.workspace = true [[bin]] name = "auth-server" path = "src/main.rs" +required-features = ["server"] [lib] name = "auth" @@ -17,10 +18,8 @@ thiserror.workspace = true serde.workspace = true bytes.workspace = true tq-db.workspace = true -tq-server.workspace = true tq-network.workspace = true tq-serde.workspace = true -tq-system.workspace = true async-trait.workspace = true tracing.workspace = true dotenvy.workspace = true @@ -28,19 +27,36 @@ tokio-stream.workspace = true num_enum.workspace = true # Packets -msg-account.workspace = true -msg-transfer.workspace = true -msg-connect-ex.workspace = true +# msg-account.workspace = true +# msg-transfer.workspace = true +# msg-connect-ex.workspace = true msg-connect.workspace = true + +[dependencies.tq-server] +workspace = true +optional = true + +[dependencies.wasmtime] +workspace = true +default-features = false +features = ["async", "cranelift", "coredump", "cache", "pooling-allocator", "component-model"] + +[dependencies.wasmtime-wasi] +workspace = true +default-features = false +features = ["preview2"] + [dependencies.tracing-subscriber] version = "0.3" +optional = true default-features = false features = ["env-filter", "ansi", "fmt", "smallvec"] # Runtime [dependencies.tokio] workspace = true +optional = true default-features = false features = ["rt-multi-thread", "macros", "signal"] @@ -48,16 +64,19 @@ features = ["rt-multi-thread", "macros", "signal"] [dependencies.sqlx] workspace = true default-features = false -features = ["runtime-tokio", "sqlite", "macros"] +features = ["sqlite"] [features] default = [] -std = [ +server = [ "tq-network/std", "tq-serde/std", - "tq-system/std", - "msg-account/std", - "msg-transfer/std", - "msg-connect-ex/std", - "msg-connect/std" + # "msg-account/std", + # "msg-transfer/std", + # "msg-connect-ex/std", + "msg-connect/std", + "dep:tokio", + "dep:tq-server", + "sqlx/runtime-tokio", + "dep:tracing-subscriber" ] diff --git a/server/auth/src/error.rs b/server/auth/src/error.rs index 4a04b18..03dcc4f 100644 --- a/server/auth/src/error.rs +++ b/server/auth/src/error.rs @@ -1,25 +1,21 @@ use bytes::Bytes; use tq_network::{ErrorPacket, PacketEncode}; -#[cfg(not(feature = "std"))] -use alloc::string::{String, ToString}; - #[derive(Debug)] pub enum Error { Network(tq_network::Error), + #[cfg(feature = "server")] Server(tq_server::Error), - #[cfg(feature = "std")] IO(std::io::Error), DotEnv(dotenvy::Error), - #[cfg(feature = "std")] Env(std::env::VarError), Sqlx(sqlx::Error), Db(tq_db::Error), State(&'static str), Other(String), Msg(u16, Bytes), - MsgAccount(msg_account::Error), Msgconnect(msg_connect::Error), + ActorNotFound, } impl From for Error { @@ -30,7 +26,6 @@ impl From for Error { fn from(v: sqlx::Error) -> Self { Self::Sqlx(v) } } -#[cfg(feature = "std")] impl From for Error { fn from(v: std::env::VarError) -> Self { Self::Env(v) } } @@ -39,11 +34,11 @@ impl From for Error { fn from(v: dotenvy::Error) -> Self { Self::DotEnv(v) } } -#[cfg(feature = "std")] impl From for Error { fn from(v: std::io::Error) -> Self { Self::IO(v) } } +#[cfg(feature = "server")] impl From for Error { fn from(v: tq_server::Error) -> Self { Self::Server(v) } } @@ -52,26 +47,20 @@ impl From for Error { fn from(v: tq_network::Error) -> Self { Self::Network(v) } } -impl From for Error { - fn from(v: msg_account::Error) -> Self { Self::MsgAccount(v) } -} - impl From for Error { fn from(v: msg_connect::Error) -> Self { Self::Msgconnect(v) } } -#[cfg(feature = "std")] impl std::error::Error for Error {} impl core::fmt::Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::Network(e) => write!(f, "Network error: {}", e), + #[cfg(feature = "server")] Self::Server(e) => write!(f, "Server error: {}", e), - #[cfg(feature = "std")] Self::IO(e) => write!(f, "IO error: {}", e), Self::DotEnv(e) => write!(f, "DotEnv error: {}", e), - #[cfg(feature = "std")] Self::Env(e) => write!(f, "Env error: {}", e), Self::Sqlx(e) => write!(f, "Sqlx error: {}", e), Self::Db(e) => write!(f, "Db error: {}", e), @@ -80,8 +69,8 @@ impl core::fmt::Display for Error { Self::Msg(id, bytes) => { write!(f, "Error packet: id = {}, body = {:?}", id, bytes) }, - Self::MsgAccount(e) => write!(f, "MsgAccount error: {}", e), Self::Msgconnect(e) => write!(f, "MsgConnect error: {}", e), + Self::ActorNotFound => write!(f, "Actor Not Found"), } } } diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index 5a715aa..e649e00 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -1,60 +1,116 @@ //! Auth Server -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(not(feature = "std"))] -extern crate alloc; +pub mod generated { + wasmtime::component::bindgen!({ + path: "../../packets/connect/wit", + async: true, + }); +} pub mod error; pub mod state; -pub use error::Error; pub use state::State; +use wasmtime::component::Resource; +use wasmtime_wasi::preview2::{Table, WasiCtx, WasiView}; + +pub struct Runtime { + pub state: &'static State, + pub wasi: WasiCtx, + pub table: Table, + pub packets: Packets, +} + +pub struct Packets { + pub msg_connect: generated::MsgConnect, +} + +impl WasiView for Runtime { + fn table(&self) -> &Table { &self.table } + + fn table_mut(&mut self) -> &mut Table { &mut self.table } -#[derive(Clone, Copy)] -pub struct Runtime; + fn ctx(&self) -> &WasiCtx { &self.wasi } -impl tq_system::Config for Runtime { - fn send( - handle: &tq_system::ActorHandle, - packet: P, - ) -> Result<(), P::Error> { - todo!() + fn ctx_mut(&mut self) -> &mut WasiCtx { &mut self.wasi } +} + +#[async_trait::async_trait] +impl generated::coemu::actor::types::HostActorHandle for Runtime { + async fn id( + &mut self, + r: Resource, + ) -> wasmtime::Result { + let actor = self + .state + .actor_handles + .get(&r.rep()) + .ok_or_else(|| error::Error::ActorNotFound)?; + Ok(actor.id() as u32) } - fn send_all( - handle: &tq_system::ActorHandle, - packets: I, - ) -> Result<(), P::Error> - where - P: tq_network::PacketEncode, - I: IntoIterator, - { - todo!() + async fn set_id( + &mut self, + r: Resource, + id: u32, + ) -> wasmtime::Result<()> { + let actor = self + .state + .actor_handles + .get(&r.rep()) + .ok_or_else(|| error::Error::ActorNotFound)?; + actor.set_id(id as usize); + Ok(()) } - fn generate_keys( - handle: &tq_system::ActorHandle, + async fn generate_keys( + &mut self, + r: Resource, seed: u64, - ) -> Result<(), tq_network::Error> { - todo!() + ) -> wasmtime::Result<()> { + let actor = self + .state + .actor_handles + .get(&r.rep()) + .ok_or_else(|| error::Error::ActorNotFound)?; + actor.generate_keys(seed).await?; + Ok(()) } - fn shutdown( - handle: &tq_system::ActorHandle, - ) -> Result<(), tq_network::Error> { - todo!() + async fn send( + &mut self, + r: Resource, + packet: (u16, Vec), + ) -> wasmtime::Result<()> { + Ok(()) } -} -impl msg_account::Config for Runtime { - type Authanticator = (); -} + async fn send_all( + &mut self, + r: Resource, + packet: Vec<(u16, Vec)>, + ) -> wasmtime::Result<()> { + Ok(()) + } -impl msg_connect::Config for Runtime {} + async fn shutdown( + &mut self, + r: Resource, + ) -> wasmtime::Result<()> { + let actor = self + .state + .actor_handles + .get(&r.rep()) + .ok_or_else(|| error::Error::ActorNotFound)?; + actor.shutdown().await?; + Ok(()) + } -impl msg_transfer::Config for Runtime { - type RealmByName = (); - type ServerBus = (); - type TokenGenerator = (); + fn drop( + &mut self, + r: Resource, + ) -> wasmtime::Result<()> { + // Drop Actor + Ok(()) + } } diff --git a/server/auth/src/main.rs b/server/auth/src/main.rs index 4fbb468..3ba5a31 100644 --- a/server/auth/src/main.rs +++ b/server/auth/src/main.rs @@ -5,30 +5,30 @@ //! will be transferred to the message server of their choice. use bytes::Bytes; -use msg_account::MsgAccount; use msg_connect::MsgConnect; use std::env; use tq_network::{Actor, PacketDecode, PacketHandler, PacketID, TQCipher}; use tq_server::TQServer; +use wasmtime::component::{Component, Linker}; +use wasmtime::{Config, Engine, Store}; +use wasmtime_wasi::preview2::{Table, WasiCtxBuilder}; -use auth::{Error, Runtime, State}; -use tq_system::ProcessPacket; +use auth::error::Error; +use auth::{Runtime, State}; struct AuthServer; impl TQServer for AuthServer { type ActorState = (); type Cipher = TQCipher; - type PacketHandler = AuthServerHandler; + type PacketHandler = Runtime; } -enum AuthServerHandler {} - #[async_trait::async_trait] -impl PacketHandler for AuthServerHandler { +impl PacketHandler for Runtime { type ActorState = (); type Error = Error; - type State = State; + type State = Self; async fn handle( packet: (u16, Bytes), @@ -36,13 +36,8 @@ impl PacketHandler for AuthServerHandler { actor: &Actor, ) -> Result<(), Self::Error> { match packet.0 { - MsgAccount::::PACKET_ID => { - let packet = MsgAccount::::decode(&packet.1)?; - packet.process(actor.handle()).await?; - }, - MsgConnect::::PACKET_ID => { - let packet = MsgConnect::::decode(&packet.1)?; - packet.process(actor.handle()).await?; + MsgConnect::PACKET_ID => { + state.packets.msg_connect.call_process(store, arg0, arg1) }, _ => { tracing::warn!("Unknown packet: {:#?}", packet); @@ -73,12 +68,47 @@ Copyright 2020-2023 Shady Khalifa (@shekohex) All Rights Reserved. "# ); - tracing::info!("Starting Auth Server"); + // Configure an `Engine` and compile the `Component` that is being run for + // the application. + let mut config = Config::new(); + config.wasm_component_model(true); + config.async_support(true); + + let engine = Engine::new(&config)?; + let mut linker = Linker::new(&engine); + wasmtime_wasi::preview2::command::add_to_linker(&mut linker)?; + let wasi = WasiCtxBuilder::new().inherit_stdio().build(); + let table = Table::new(); tracing::info!("Initializing State .."); + let static_state = { let state = State::init().await?; Box::leak(Box::new(state)) as *mut _ }; + + tracing::info!("Loading Packet and handlers.."); + let component = Component::from_file( + &engine, + "./target/wasm32-wasi/debug/msg_connect.wasm", + )?; + let (bindings, _) = auth::generated::MsgConnect::instantiate_async( + &mut store, &component, &linker, + ) + .await?; + let packets = auth::Packets { + msg_connect: bindings, + }; + let mut store = Store::new( + &engine, + Runtime { + state: static_state, + wasi, + table, + packets, + }, + ); + + tracing::info!("Starting Auth Server"); tracing::info!("Initializing server..."); let auth_port = env::var("AUTH_PORT")?; tracing::info!("Auth Server will be available on {auth_port}"); diff --git a/server/auth/src/state.rs b/server/auth/src/state.rs index 7568be1..50854c6 100644 --- a/server/auth/src/state.rs +++ b/server/auth/src/state.rs @@ -1,12 +1,13 @@ -use crate::Error; -use sqlx::sqlite::{SqlitePool, SqlitePoolOptions}; +use std::collections::HashMap; -#[cfg(not(feature = "std"))] -use alloc::format; +use crate::error::Error; +use sqlx::sqlite::{SqlitePool, SqlitePoolOptions}; +use tq_network::ActorHandle; #[derive(Debug, Clone)] pub struct State { pool: SqlitePool, + pub(crate) actor_handles: HashMap, } impl State { @@ -23,7 +24,10 @@ impl State { .min_connections(4) .connect(&db_url) .await?; - let state = Self { pool }; + let state = Self { + pool, + actor_handles: Default::default(), + }; Ok(state) } diff --git a/tools/benchbot/Cargo.toml b/tools/benchbot/Cargo.toml index 1f99300..a58941c 100644 --- a/tools/benchbot/Cargo.toml +++ b/tools/benchbot/Cargo.toml @@ -18,7 +18,7 @@ tq-crypto.workspace = true tq-network.workspace = true tq-db.workspace = true game.workspace = true -auth = { workspace = true, features = ["std"] } +auth.workspace = true pretty-hex = "0.4" local-ip-address = "0.5" diff --git a/wit/actor/types.wit b/wit/actor/types.wit new file mode 100644 index 0000000..0d1839d --- /dev/null +++ b/wit/actor/types.wit @@ -0,0 +1,15 @@ +package coemu:actor@0.1.0; + +interface types { + type packet = tuple>; + resource actor-handle { + id: func() -> u32; + set-id: func(id: u32); + send: func(packet: packet); + send-all: func(packet: list); + generate-keys: func(seed: u64); + shutdown: func(); + } +} + +// vim: set ft=typescript ts=2 sw=4 noet: From ca4201f47b8790d77c5f837a8135b5a8203e55b6 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sun, 7 Jan 2024 16:41:20 +0200 Subject: [PATCH 11/28] give up, will try lua --- .cargo/config.toml | 2 +- Cargo.lock | 99 -------------------------------------- Cargo.toml | 12 +++-- crates/server/Cargo.toml | 2 +- packets/connect/src/lib.rs | 4 +- server/auth/src/error.rs | 15 ++++-- server/auth/src/lib.rs | 45 +++++++++++++++-- server/auth/src/main.rs | 68 ++++++++------------------ 8 files changed, 85 insertions(+), 162 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 027ecee..3d911a8 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,5 @@ [alias] -auth = "run --bin auth-server" +auth = "run --bin auth-server --features=server" game = "run --bin game-server" hash-pwd = "run --bin hash-pwd" diff --git a/Cargo.lock b/Cargo.lock index f86887e..d491b90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -276,30 +276,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "benchbot" -version = "0.1.0" -dependencies = [ - "auth", - "dotenvy", - "futures", - "game", - "local-ip-address", - "parking_lot", - "pretty-hex", - "rand", - "sqlx", - "thiserror", - "tokio", - "tokio-stream", - "tq-codec", - "tq-crypto", - "tq-db", - "tq-network", - "tracing", - "tracing-subscriber", -] - [[package]] name = "bincode" version = "1.3.3" @@ -1505,18 +1481,6 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" -[[package]] -name = "local-ip-address" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66357e687a569abca487dc399a9c9ac19beb3f13991ed49f00c144e02cbd42ab" -dependencies = [ - "libc", - "neli", - "thiserror", - "windows-sys 0.48.0", -] - [[package]] name = "lock_api" version = "0.4.11" @@ -1629,20 +1593,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "msg-account" -version = "0.1.0" -dependencies = [ - "msg-connect-ex", - "msg-transfer", - "serde", - "tq-codec", - "tq-crypto", - "tq-network", - "tq-serde", - "tracing", -] - [[package]] name = "msg-connect" version = "0.1.0" @@ -1654,55 +1604,6 @@ dependencies = [ "tq-serde", ] -[[package]] -name = "msg-connect-ex" -version = "0.1.0" -dependencies = [ - "num_enum", - "serde", - "tq-network", - "tq-serde", -] - -[[package]] -name = "msg-transfer" -version = "0.1.0" -dependencies = [ - "bytes", - "msg-connect-ex", - "serde", - "tq-codec", - "tq-crypto", - "tq-network", - "tq-serde", - "tracing", -] - -[[package]] -name = "neli" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43" -dependencies = [ - "byteorder", - "libc", - "log", - "neli-proc-macros", -] - -[[package]] -name = "neli-proc-macros" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4" -dependencies = [ - "either", - "proc-macro2", - "quote", - "serde", - "syn 1.0.109", -] - [[package]] name = "nix" version = "0.27.1" diff --git a/Cargo.toml b/Cargo.toml index bdb8e9f..865fb5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,12 @@ members = [ # Cli Tools "tools/*", ] +exclude = [ + "packets/account", + "packets/connect-ex", + "packets/transfer", + "tools/benchbot" +] [workspace.dependencies] # Local Dependencies @@ -32,10 +38,10 @@ auth = { path = "server/auth" } game = { path = "server/game" } # Packets -msg-account = { path = "packets/account" } -msg-connect-ex = { path = "packets/connect-ex" } +# msg-account = { path = "packets/account" } +# msg-connect-ex = { path = "packets/connect-ex" } msg-connect = { path = "packets/connect" } -msg-transfer = { path = "packets/transfer" } +# msg-transfer = { path = "packets/transfer" } futures = { version = "0.3", default-features = false } thiserror = "1.0" diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index 1db0a29..b6665e7 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -23,4 +23,4 @@ features = ["io-util", "net"] [dependencies.tokio] workspace = true default-features = false -features = ["io-util", "sync"] +features = ["io-util", "sync", "tracing"] diff --git a/packets/connect/src/lib.rs b/packets/connect/src/lib.rs index 01c27a2..016dee0 100644 --- a/packets/connect/src/lib.rs +++ b/packets/connect/src/lib.rs @@ -8,9 +8,7 @@ use alloc::string::ToString; cargo_component_bindings::generate!(); -pub use bindings::Error; - -use bindings::ActorHandle; +use bindings::{ActorHandle, Error}; use bytes::Bytes; use serde::Deserialize; use tq_network::{PacketDecode, PacketID}; diff --git a/server/auth/src/error.rs b/server/auth/src/error.rs index 03dcc4f..ffb3be8 100644 --- a/server/auth/src/error.rs +++ b/server/auth/src/error.rs @@ -3,6 +3,7 @@ use tq_network::{ErrorPacket, PacketEncode}; #[derive(Debug)] pub enum Error { + Wasmtime(wasmtime::Error), Network(tq_network::Error), #[cfg(feature = "server")] Server(tq_server::Error), @@ -14,7 +15,7 @@ pub enum Error { State(&'static str), Other(String), Msg(u16, Bytes), - Msgconnect(msg_connect::Error), + MsgConnect(crate::generated::Error), ActorNotFound, } @@ -47,8 +48,12 @@ impl From for Error { fn from(v: tq_network::Error) -> Self { Self::Network(v) } } -impl From for Error { - fn from(v: msg_connect::Error) -> Self { Self::Msgconnect(v) } +impl From for Error { + fn from(v: crate::generated::Error) -> Self { Self::MsgConnect(v) } +} + +impl From for Error { + fn from(v: wasmtime::Error) -> Self { Self::Wasmtime(v) } } impl std::error::Error for Error {} @@ -56,6 +61,7 @@ impl std::error::Error for Error {} impl core::fmt::Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { + Self::Wasmtime(e) => write!(f, "Wasmtime error: {}", e), Self::Network(e) => write!(f, "Network error: {}", e), #[cfg(feature = "server")] Self::Server(e) => write!(f, "Server error: {}", e), @@ -69,12 +75,13 @@ impl core::fmt::Display for Error { Self::Msg(id, bytes) => { write!(f, "Error packet: id = {}, body = {:?}", id, bytes) }, - Self::Msgconnect(e) => write!(f, "MsgConnect error: {}", e), + Self::MsgConnect(e) => write!(f, "MsgConnect error: {}", e), Self::ActorNotFound => write!(f, "Actor Not Found"), } } } + impl From> for Error { fn from(v: ErrorPacket) -> Self { let (id, bytes) = v.0.encode().unwrap(); diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index e649e00..0b25558 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -10,19 +10,58 @@ pub mod generated { pub mod error; pub mod state; +use bytes::Bytes; pub use state::State; -use wasmtime::component::Resource; +use tq_network::{Actor, PacketHandler, PacketID}; +use wasmtime::component::{Component, Resource}; +use wasmtime::{Engine, Store}; use wasmtime_wasi::preview2::{Table, WasiCtx, WasiView}; pub struct Runtime { - pub state: &'static State, + pub state: State, + pub engine: Engine, pub wasi: WasiCtx, pub table: Table, pub packets: Packets, } pub struct Packets { - pub msg_connect: generated::MsgConnect, + pub msg_connect: Component, +} + +#[async_trait::async_trait] +impl PacketHandler for Runtime { + type ActorState = (); + type Error = crate::error::Error; + type State = Self; + + async fn handle( + packet: (u16, Bytes), + runtime: &Self::State, + actor: &Actor, + ) -> Result<(), Self::Error> { + let mut store = Store::new(&runtime.engine, ()); + let packet = (packet.0, packet.1.to_vec()); + let actor = Resource::new_borrow(actor.id() as _); + match packet.0 { + msg_connect::MsgConnect::PACKET_ID => { + let (bindings, _) = generated::MsgConnect::instantiate_async( + &mut store, &runtime.packets.msg_connect, &runtime.linker, + ) + .await?; + runtime + .packets + .msg_connect + .call_process(&mut store, &packet, actor) + .await? + .map_err(error::Error::MsgConnect) + }, + _ => { + tracing::warn!("Unknown packet: {:#?}", packet); + Ok(()) + }, + } + } } impl WasiView for Runtime { diff --git a/server/auth/src/main.rs b/server/auth/src/main.rs index 3ba5a31..0266e5a 100644 --- a/server/auth/src/main.rs +++ b/server/auth/src/main.rs @@ -8,6 +8,7 @@ use bytes::Bytes; use msg_connect::MsgConnect; use std::env; use tq_network::{Actor, PacketDecode, PacketHandler, PacketID, TQCipher}; +#[cfg(feature = "server")] use tq_server::TQServer; use wasmtime::component::{Component, Linker}; use wasmtime::{Config, Engine, Store}; @@ -24,29 +25,6 @@ impl TQServer for AuthServer { type PacketHandler = Runtime; } -#[async_trait::async_trait] -impl PacketHandler for Runtime { - type ActorState = (); - type Error = Error; - type State = Self; - - async fn handle( - packet: (u16, Bytes), - state: &Self::State, - actor: &Actor, - ) -> Result<(), Self::Error> { - match packet.0 { - MsgConnect::PACKET_ID => { - state.packets.msg_connect.call_process(store, arg0, arg1) - }, - _ => { - tracing::warn!("Unknown packet: {:#?}", packet); - }, - } - Ok(()) - } -} - #[tokio::main] async fn main() -> Result<(), Error> { dotenvy::dotenv()?; @@ -81,41 +59,35 @@ Copyright 2020-2023 Shady Khalifa (@shekohex) let table = Table::new(); tracing::info!("Initializing State .."); - let static_state = { - let state = State::init().await?; - Box::leak(Box::new(state)) as *mut _ - }; - tracing::info!("Loading Packet and handlers.."); - let component = Component::from_file( + + let msg_connect = Component::from_file( &engine, "./target/wasm32-wasi/debug/msg_connect.wasm", )?; - let (bindings, _) = auth::generated::MsgConnect::instantiate_async( - &mut store, &component, &linker, - ) - .await?; - let packets = auth::Packets { - msg_connect: bindings, - }; - let mut store = Store::new( - &engine, - Runtime { - state: static_state, - wasi, - table, - packets, - }, - ); - tracing::info!("Starting Auth Server"); tracing::info!("Initializing server..."); let auth_port = env::var("AUTH_PORT")?; tracing::info!("Auth Server will be available on {auth_port}"); + + let state = State::init().await?; + let packets = auth::Packets { msg_connect }; + + let static_runtime = { + let runtime = Runtime { + state, + engine, + linker, + wasi, + table, + packets, + }; + Box::leak(Box::new(runtime)) as *mut _ + }; // SAFETY: We are the only owner of this Box, and we are deref // it. This happens only once, so no one else can access. - let state = unsafe { &*static_state }; - AuthServer::run(format!("0.0.0.0:{}", auth_port), state).await?; + let runtime: &'static _ = unsafe { &*static_runtime }; + AuthServer::run(format!("0.0.0.0:{}", auth_port), runtime).await?; unsafe { // SAFETY: We are the only owner of this Box, and we are dropping // it. This happens at the end of the program, so no one From 52e20a2da405cde904aac3e2fdba825ec5ec39de Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Fri, 12 Jan 2024 21:28:28 +0200 Subject: [PATCH 12/28] using basic wasm works! --- .cargo/config.toml | 1 + Cargo.lock | 498 +++++------------------ Cargo.toml | 24 +- crates/bindings/Cargo.toml | 13 + crates/bindings/src/lib.rs | 30 ++ crates/network/Cargo.toml | 1 + crates/network/src/actor.rs | 2 +- crates/network/src/lib.rs | 1 + macros/derive-packetprocessor/Cargo.toml | 12 + macros/derive-packetprocessor/src/lib.rs | 130 ++++++ packets/connect/.cargo/config.toml | 2 + packets/connect/Cargo.toml | 17 +- packets/connect/src/lib.rs | 48 +-- packets/connect/wit/deps | 1 - packets/connect/wit/world.wit | 12 - rust-toolchain.toml | 2 +- server/auth/Cargo.toml | 13 +- server/auth/src/error.rs | 7 - server/auth/src/lib.rs | 216 +++++----- server/auth/src/main.rs | 42 +- server/auth/src/state.rs | 9 +- tools/externref/Cargo.toml | 8 + tools/externref/src/main.rs | 26 ++ wit/actor/types.wit | 15 - 24 files changed, 497 insertions(+), 633 deletions(-) create mode 100644 crates/bindings/Cargo.toml create mode 100644 crates/bindings/src/lib.rs create mode 100644 macros/derive-packetprocessor/Cargo.toml create mode 100644 macros/derive-packetprocessor/src/lib.rs create mode 100644 packets/connect/.cargo/config.toml delete mode 120000 packets/connect/wit/deps delete mode 100644 packets/connect/wit/world.wit create mode 100644 tools/externref/Cargo.toml create mode 100644 tools/externref/src/main.rs delete mode 100644 wit/actor/types.wit diff --git a/.cargo/config.toml b/.cargo/config.toml index 3d911a8..f52da08 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -2,6 +2,7 @@ auth = "run --bin auth-server --features=server" game = "run --bin game-server" hash-pwd = "run --bin hash-pwd" +externref = "run --bin externref-cli" [target.aarch64-apple-darwin] linker = "clang" diff --git a/Cargo.lock b/Cargo.lock index d491b90..acd46c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,12 +45,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" -[[package]] -name = "ambient-authority" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" - [[package]] name = "anyhow" version = "1.0.75" @@ -168,6 +162,7 @@ dependencies = [ "async-trait", "bytes", "dotenvy", + "futures", "msg-connect", "num_enum", "serde", @@ -182,7 +177,6 @@ dependencies = [ "tracing", "tracing-subscriber", "wasmtime", - "wasmtime-wasi", ] [[package]] @@ -357,102 +351,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" -[[package]] -name = "cap-fs-ext" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b779b2d0a001c125b4584ad586268fb4b92d957bff8d26d7fe0dd78283faa814" -dependencies = [ - "cap-primitives", - "cap-std", - "io-lifetimes", - "windows-sys 0.48.0", -] - -[[package]] -name = "cap-net-ext" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ffc30dee200c20b4dcb80572226f42658e1d9c4b668656d7cc59c33d50e396e" -dependencies = [ - "cap-primitives", - "cap-std", - "rustix", - "smallvec", -] - -[[package]] -name = "cap-primitives" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf30c373a3bee22c292b1b6a7a26736a38376840f1af3d2d806455edf8c3899" -dependencies = [ - "ambient-authority", - "fs-set-times", - "io-extras", - "io-lifetimes", - "ipnet", - "maybe-owned", - "rustix", - "windows-sys 0.48.0", - "winx", -] - -[[package]] -name = "cap-rand" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "577de6cff7c2a47d6b13efe5dd28bf116bd7f8f7db164ea95b7cc2640711f522" -dependencies = [ - "ambient-authority", - "rand", -] - -[[package]] -name = "cap-std" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84bade423fa6403efeebeafe568fdb230e8c590a275fba2ba978dd112efcf6e9" -dependencies = [ - "cap-primitives", - "io-extras", - "io-lifetimes", - "rustix", -] - -[[package]] -name = "cap-time-ext" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f52b3c8f4abfe3252fd0a071f3004aaa3b18936ec97bdbd8763ce03aff6247" -dependencies = [ - "cap-primitives", - "once_cell", - "rustix", - "winx", -] - -[[package]] -name = "cargo-component-bindings" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545e48ba821e07f93c97aea897bee6d407de4d58947f914160131f3d78b2c704" -dependencies = [ - "cargo-component-macro", - "wit-bindgen", -] - -[[package]] -name = "cargo-component-macro" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e198ee0b668e902b43b5e7d2e9620a3891d2632429b3ba66e1ceea455053cbf5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.43", -] - [[package]] name = "cc" version = "1.0.83" @@ -646,7 +544,7 @@ dependencies = [ "itertools 0.10.5", "log", "smallvec", - "wasmparser", + "wasmparser 0.118.1", "wasmtime-types", ] @@ -771,6 +669,14 @@ dependencies = [ "syn 2.0.43", ] +[[package]] +name = "derive-packetprocessor" +version = "0.1.0" +dependencies = [ + "quote", + "syn 2.0.43", +] + [[package]] name = "digest" version = "0.10.7" @@ -793,26 +699,6 @@ dependencies = [ "dirs-sys-next", ] -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -839,15 +725,6 @@ dependencies = [ "serde", ] -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - [[package]] name = "equivalent" version = "1.0.1" @@ -881,6 +758,35 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "externref" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b078507c9badc1c2304de402f373950b30ef80b793096cd2a8c0312c8c676cad" +dependencies = [ + "anyhow", + "externref-macro", + "walrus", +] + +[[package]] +name = "externref-cli" +version = "0.1.0" +dependencies = [ + "externref", +] + +[[package]] +name = "externref-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77107325d07454a4de518e92b1e061ded5af8aa32d52edb1fde60c813d1eff1b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.43", +] + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -893,17 +799,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" -[[package]] -name = "fd-lock" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b0377f1edc77dbd1118507bc7a66e4ab64d2b90c66f90726dc801e73a8c68f9" -dependencies = [ - "cfg-if", - "rustix", - "windows-sys 0.48.0", -] - [[package]] name = "finl_unicode" version = "1.2.0" @@ -946,17 +841,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs-set-times" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033b337d725b97690d86893f9de22b67b80dcc4e9ad815f348254c38119db8fb" -dependencies = [ - "io-lifetimes", - "rustix", - "windows-sys 0.52.0", -] - [[package]] name = "futures" version = "0.3.29" @@ -1192,6 +1076,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "heck" version = "0.4.1" @@ -1362,28 +1255,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "io-extras" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c301e73fb90e8a29e600a9f402d095765f74310d582916a952f618836a1bd1ed" -dependencies = [ - "io-lifetimes", - "windows-sys 0.52.0", -] - -[[package]] -name = "io-lifetimes" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a611371471e98973dbcab4e0ec66c31a10bc356eeb4d54a0e05eac8158fe38c" - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - [[package]] name = "itertools" version = "0.10.5" @@ -1521,12 +1392,6 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" -[[package]] -name = "maybe-owned" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" - [[package]] name = "md-5" version = "0.10.6" @@ -1598,8 +1463,8 @@ name = "msg-connect" version = "0.1.0" dependencies = [ "bytes", - "cargo-component-bindings", "serde", + "tq-bindings", "tq-network", "tq-serde", ] @@ -2086,10 +1951,8 @@ checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ "bitflags 2.4.1", "errno", - "itoa", "libc", "linux-raw-sys", - "once_cell", "windows-sys 0.52.0", ] @@ -2219,15 +2082,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shellexpand" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4" -dependencies = [ - "dirs", -] - [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -2399,7 +2253,7 @@ dependencies = [ "atomic-write-file", "dotenvy", "either", - "heck", + "heck 0.4.1", "hex", "once_cell", "proc-macro2", @@ -2575,22 +2429,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" -[[package]] -name = "system-interface" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ce32341b2c0b70c144bbf35627fdc1ef18c76ced5e5e7b3ee8b5ba6b2ab6a0" -dependencies = [ - "bitflags 2.4.1", - "cap-fs-ext", - "cap-std", - "fd-lock", - "io-lifetimes", - "rustix", - "windows-sys 0.48.0", - "winx", -] - [[package]] name = "target-lexicon" version = "0.12.12" @@ -2818,6 +2656,14 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +[[package]] +name = "tq-bindings" +version = "0.1.0" +dependencies = [ + "externref", + "tq-network", +] + [[package]] name = "tq-codec" version = "0.1.0" @@ -2865,6 +2711,7 @@ dependencies = [ "bytes", "derive-packethandler", "derive-packetid", + "derive-packetprocessor", "futures", "serde", "tokio", @@ -3044,6 +2891,32 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walrus" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb08e48cde54c05f363d984bb54ce374f49e242def9468d2e1b6c2372d291f8" +dependencies = [ + "anyhow", + "id-arena", + "leb128", + "log", + "walrus-macro", + "wasmparser 0.77.1", +] + +[[package]] +name = "walrus-macro" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e5bd22c71e77d60140b0bd5be56155a37e5bd14e24f5f87298040d0cc40d7" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "want" version = "0.3.1" @@ -3059,26 +2932,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasi-common" -version = "16.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d888b611fee7d273dd057dc009d2dd3132736f36710ffd65657ac83628d1e3b" -dependencies = [ - "anyhow", - "bitflags 2.4.1", - "cap-rand", - "cap-std", - "io-extras", - "log", - "rustix", - "thiserror", - "tracing", - "wasmtime", - "wiggle", - "windows-sys 0.48.0", -] - [[package]] name = "wasm-encoder" version = "0.38.1" @@ -3088,6 +2941,12 @@ dependencies = [ "leb128", ] +[[package]] +name = "wasmparser" +version = "0.77.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fe3d5405e9ea6c1317a656d6e0820912d8b7b3607823a7596117c8f666daf6f" + [[package]] name = "wasmparser" version = "0.118.1" @@ -3098,16 +2957,6 @@ dependencies = [ "semver", ] -[[package]] -name = "wasmprinter" -version = "0.2.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d027eb8294904fc715ac0870cebe6b0271e96b90605ee21511e7565c4ce568c" -dependencies = [ - "anyhow", - "wasmparser", -] - [[package]] name = "wasmtime" version = "16.0.0" @@ -3119,7 +2968,6 @@ dependencies = [ "bincode", "bumpalo", "cfg-if", - "encoding_rs", "indexmap 2.1.0", "libc", "log", @@ -3131,16 +2979,14 @@ dependencies = [ "serde_json", "target-lexicon", "wasm-encoder", - "wasmparser", + "wasmparser 0.118.1", "wasmtime-cache", "wasmtime-component-macro", - "wasmtime-component-util", "wasmtime-cranelift", "wasmtime-environ", "wasmtime-fiber", "wasmtime-jit", "wasmtime-runtime", - "wasmtime-winch", "windows-sys 0.48.0", ] @@ -3213,7 +3059,7 @@ dependencies = [ "object", "target-lexicon", "thiserror", - "wasmparser", + "wasmparser 0.118.1", "wasmtime-cranelift-shared", "wasmtime-environ", "wasmtime-versioned-export-macros", @@ -3251,10 +3097,7 @@ dependencies = [ "serde_derive", "target-lexicon", "thiserror", - "wasm-encoder", - "wasmparser", - "wasmprinter", - "wasmtime-component-util", + "wasmparser 0.118.1", "wasmtime-types", ] @@ -3315,7 +3158,6 @@ dependencies = [ "anyhow", "cc", "cfg-if", - "encoding_rs", "indexmap 2.1.0", "libc", "log", @@ -3345,7 +3187,7 @@ dependencies = [ "serde", "serde_derive", "thiserror", - "wasmparser", + "wasmparser 0.118.1", ] [[package]] @@ -3359,56 +3201,6 @@ dependencies = [ "syn 2.0.43", ] -[[package]] -name = "wasmtime-wasi" -version = "16.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd8370078149d49a3a47e93741553fd79b700421464b6a27ca32718192ab130" -dependencies = [ - "anyhow", - "async-trait", - "bitflags 2.4.1", - "bytes", - "cap-fs-ext", - "cap-net-ext", - "cap-rand", - "cap-std", - "cap-time-ext", - "fs-set-times", - "futures", - "io-extras", - "io-lifetimes", - "libc", - "log", - "once_cell", - "rustix", - "system-interface", - "thiserror", - "tokio", - "tracing", - "url", - "wasi-common", - "wasmtime", - "windows-sys 0.48.0", -] - -[[package]] -name = "wasmtime-winch" -version = "16.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6f945ff9bad96e0a69973d74f193c19f627c8adbf250e7cb73ae7564b6cc8a" -dependencies = [ - "anyhow", - "cranelift-codegen", - "gimli", - "object", - "target-lexicon", - "wasmparser", - "wasmtime-cranelift-shared", - "wasmtime-environ", - "winch-codegen", -] - [[package]] name = "wasmtime-wit-bindgen" version = "16.0.0" @@ -3416,7 +3208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f328b2d4a690270324756e886ed5be3a4da4c00be0eea48253f4595ad068062b" dependencies = [ "anyhow", - "heck", + "heck 0.4.1", "indexmap 2.1.0", "wit-parser", ] @@ -3427,15 +3219,6 @@ version = "16.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67761d8f8c0b3c13a5d34356274b10a40baba67fe9cfabbfc379a8b414e45de2" -[[package]] -name = "wast" -version = "35.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" -dependencies = [ - "leb128", -] - [[package]] name = "webpki-roots" version = "0.25.3" @@ -3448,48 +3231,6 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" -[[package]] -name = "wiggle" -version = "16.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0afb26cd3269289bb314a361ff0a6685e5ce793b62181a9fe3f81ace15051697" -dependencies = [ - "anyhow", - "async-trait", - "bitflags 2.4.1", - "thiserror", - "tracing", - "wasmtime", - "wiggle-macro", -] - -[[package]] -name = "wiggle-generate" -version = "16.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef2868fed7584d2b552fa317104858ded80021d23b073b2d682d3c932a027bd" -dependencies = [ - "anyhow", - "heck", - "proc-macro2", - "quote", - "shellexpand", - "syn 2.0.43", - "witx", -] - -[[package]] -name = "wiggle-macro" -version = "16.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31ae1ec11a17ea481539ee9a5719a278c9790d974060fbf71db4b2c05378780b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.43", - "wiggle-generate", -] - [[package]] name = "winapi" version = "0.3.9" @@ -3512,22 +3253,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "winch-codegen" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e58c236a6abdd9ab454552b4f29e16cfa837a86897c1503313b2e62e7609ec" -dependencies = [ - "anyhow", - "cranelift-codegen", - "gimli", - "regalloc2", - "smallvec", - "target-lexicon", - "wasmparser", - "wasmtime-environ", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -3660,25 +3385,6 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" -[[package]] -name = "winx" -version = "0.36.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9643b83820c0cd246ecabe5fa454dd04ba4fa67996369466d0747472d337346" -dependencies = [ - "bitflags 2.4.1", - "windows-sys 0.52.0", -] - -[[package]] -name = "wit-bindgen" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b76f1d099678b4f69402a421e888bbe71bf20320c2f3f3565d0e7484dbe5bc20" -dependencies = [ - "bitflags 2.4.1", -] - [[package]] name = "wit-parser" version = "0.13.0" @@ -3696,18 +3402,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "witx" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" -dependencies = [ - "anyhow", - "log", - "thiserror", - "wast", -] - [[package]] name = "zerocopy" version = "0.7.31" diff --git a/Cargo.toml b/Cargo.toml index 865fb5c..b8bc7cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,9 +29,11 @@ tq-crypto = { path = "crates/crypto" } tq-codec = { path = "crates/codec" } tq-db = { path = "crates/db" } tq-server = { path = "crates/server" } +tq-bindings = { path = "crates/bindings" } derive-packetid = { path = "macros/derive-packetid" } derive-packethandler = { path = "macros/derive-packethandler" } +derive-packetprocessor = { path = "macros/derive-packetprocessor" } # Servers & Libs auth = { path = "server/auth" } @@ -64,16 +66,12 @@ num_enum = { version = "0.7", default-features = false } bcrypt = "0.15" # WASM deps -cargo-component-bindings = "0.6.0" +externref = { version = "0.2.0", default-features = false } [workspace.dependencies.wasmtime] version = "16.0.0" default-features = false -[workspace.dependencies.wasmtime-wasi] -version = "16.0.0" -default-features = false - [workspace.dependencies.tokio] version = "1.21.2" default-features = false @@ -84,3 +82,19 @@ version = "0.7.3" [profile.dev] split-debuginfo = 'packed' +lto = true +codegen-units = 1 + +[profile.wasmdebug] +inherits = "dev" +panic = "abort" +codegen-units = 1 +opt-level = "z" # Optimize for size, rather than speed +lto = true + +[profile.wasm] +inherits = "release" +panic = "abort" +codegen-units = 1 +opt-level = "z" # Optimize for size, rather than speed +lto = true diff --git a/crates/bindings/Cargo.toml b/crates/bindings/Cargo.toml new file mode 100644 index 0000000..2735fac --- /dev/null +++ b/crates/bindings/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "tq-bindings" +version = "0.1.0" +edition.workspace = true + +[dependencies] +tq-network.workspace = true + +externref = { workspace = true, features = ["macro"] } + +[features] +default = [] +std = ["tq-network/std"] diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs new file mode 100644 index 0000000..05278a7 --- /dev/null +++ b/crates/bindings/src/lib.rs @@ -0,0 +1,30 @@ +//! Bindings to the host environment. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; + +pub use externref::{self as anyref, externref, Resource}; + +/// Generate host bindings. +#[macro_export] +macro_rules! generate { + () => { + #[$crate::externref(crate = "tq_bindings::anyref")] + #[link(wasm_import_module = "host")] + extern "C" { + fn shutdown(actor: &Resource); + } + + /// Host bindings. + mod host { + use $crate::Resource; + use tq_network::ActorHandle; + /// Shutdown an actor. + pub fn shutdown(actor: &Resource) { + unsafe { super::shutdown(actor) } + } + } + }; +} diff --git a/crates/network/Cargo.toml b/crates/network/Cargo.toml index 504974b..e7e0f5a 100644 --- a/crates/network/Cargo.toml +++ b/crates/network/Cargo.toml @@ -17,6 +17,7 @@ futures.workspace = true # macros derive-packetid.workspace = true derive-packethandler.workspace = true +derive-packetprocessor.workspace = true [dependencies.tokio-stream] workspace = true diff --git a/crates/network/src/actor.rs b/crates/network/src/actor.rs index 7a8d276..6b5c7f1 100644 --- a/crates/network/src/actor.rs +++ b/crates/network/src/actor.rs @@ -13,7 +13,7 @@ use alloc::{boxed::Box, sync::Arc}; #[cfg(feature = "std")] use std::sync::Arc; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum Message { GenerateKeys(u64), Packet(u16, Bytes), diff --git a/crates/network/src/lib.rs b/crates/network/src/lib.rs index 14b9b51..7b7c818 100644 --- a/crates/network/src/lib.rs +++ b/crates/network/src/lib.rs @@ -16,6 +16,7 @@ use serde::Serialize; pub use async_trait::async_trait; pub use derive_packethandler::PacketHandler; pub use derive_packetid::PacketID; +pub use derive_packetprocessor::packet_processor; pub use tq_codec::TQCodec; pub use tq_crypto::{CQCipher, Cipher, NopCipher, TQCipher}; diff --git a/macros/derive-packetprocessor/Cargo.toml b/macros/derive-packetprocessor/Cargo.toml new file mode 100644 index 0000000..785facc --- /dev/null +++ b/macros/derive-packetprocessor/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "derive-packetprocessor" +version = "0.1.0" +authors = ["Shady Khalifa "] +edition.workspace = true + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "2.0", features = ["full"] } +quote = "1.0" diff --git a/macros/derive-packetprocessor/src/lib.rs b/macros/derive-packetprocessor/src/lib.rs new file mode 100644 index 0000000..6dc889b --- /dev/null +++ b/macros/derive-packetprocessor/src/lib.rs @@ -0,0 +1,130 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::parse::{Parse, ParseStream}; +use syn::{parse_macro_input, FnArg, Ident, ItemFn, ReturnType}; + +struct Args { + msg: Ident, +} + +impl Parse for Args { + fn parse(input: ParseStream) -> syn::Result { + let msg: Ident = input.parse()?; + let args = Self { msg }; + Ok(args) + } +} + +macro_rules! syn_assert { + ($cond:expr, $msg:expr) => { + if !$cond { + return Err(syn::Error::new_spanned($cond, $msg)); + } + }; +} + +fn derive_packet_processor( + args: Args, + inner_fn: ItemFn, +) -> syn::Result { + let msg_ty = args.msg; + // make sure the function has the right signature + // fn process(msg: msg_ty, actor: &Resource) -> Result<(), + // crate::Error> + let fn_sig = &inner_fn.sig; + syn_assert!(fn_sig.constness.is_none(), "const fn not supported"); + syn_assert!(fn_sig.asyncness.is_none(), "async fn not supported"); + syn_assert!(fn_sig.abi.is_none(), "abi fn not supported"); + syn_assert!(fn_sig.unsafety.is_none(), "unsafe fn not supported"); + syn_assert!( + fn_sig.generics.params.is_empty(), + "generic fn not supported" + ); + syn_assert!( + fn_sig.generics.where_clause.is_none(), + "generic fn not supported" + ); + syn_assert!( + fn_sig.inputs.len() == 2, + "packet processor must have two arguments" + ); + syn_assert!( + fn_sig.output != ReturnType::Default, + "packet processor must have a return type" + ); + syn_assert!( + matches!(fn_sig.inputs[0], FnArg::Typed(_)), + "packet processor must have a typed msg argument" + ); + syn_assert!( + matches!(fn_sig.inputs[1], FnArg::Typed(_)), + "packet processor must have a typed actor argument" + ); + match fn_sig.inputs[0] { + FnArg::Receiver(_) => unreachable!(), + FnArg::Typed(ref p) => syn_assert!( + p.ty == syn::parse_quote!(#msg_ty), + "packet processor must have a typed msg argument" + ), + }; + match fn_sig.inputs[1] { + FnArg::Receiver(_) => unreachable!(), + FnArg::Typed(ref p) => { + syn_assert!( + p.ty == syn::parse_quote!(&Resource), + "packet processor must have a typed actor argument" + ); + }, + }; + + let inner_fn_call = inner_fn.sig.ident.clone(); + // Build the output, possibly using quasi-quotation + let expanded = quote! { + #[export_name = "alloc_packet"] + pub extern "C" fn alloc_packet(size: u32) -> *mut u8 { + let mut v = core::mem::ManuallyDrop::new(::alloc::vec::Vec::with_capacity(size as usize)); + unsafe { + v.set_len(size as usize); + } + v.shrink_to_fit(); + let ptr = v.as_mut_ptr(); + ptr + } + + #inner_fn + + #[::tq_bindings::externref(crate = "tq_bindings::anyref")] + #[export_name = "process_packet"] + pub unsafe extern "C" fn _process( + packet_ptr: *mut u8, + packet_len: u32, + actor: &::tq_bindings::Resource, + ) -> i32 { + let packet = ::alloc::vec::Vec::from_raw_parts(packet_ptr, packet_len as _, packet_len as _); + let bytes = ::bytes::BytesMut::from(packet.as_slice()).freeze(); + let packet = match <#msg_ty as ::tq_network::PacketDecode>::decode(&bytes) { + Ok(packet) => packet, + Err(e) => { + // TODO: use host to log the error + return 0xdec0de; + } + }; + match #inner_fn_call(packet, actor) { + Ok(()) => 0, + Err(e) => { + // TODO: use host to log the error + 0x00f + } + } + } + }; + Ok(expanded.into()) +} + +#[proc_macro_attribute] +pub fn packet_processor(args: TokenStream, input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as ItemFn); + let args = parse_macro_input!(args as Args); + derive_packet_processor(args, input) + .unwrap_or_else(|err| err.to_compile_error().into()) +} diff --git a/packets/connect/.cargo/config.toml b/packets/connect/.cargo/config.toml new file mode 100644 index 0000000..f4e8c00 --- /dev/null +++ b/packets/connect/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "wasm32-unknown-unknown" diff --git a/packets/connect/Cargo.toml b/packets/connect/Cargo.toml index d992631..7f4c3a8 100644 --- a/packets/connect/Cargo.toml +++ b/packets/connect/Cargo.toml @@ -9,23 +9,8 @@ crate-type = ["cdylib", "rlib"] [dependencies] tq-serde.workspace = true tq-network.workspace = true +tq-bindings.workspace = true serde.workspace = true bytes.workspace = true -# WASM -cargo-component-bindings.workspace = true - -[package.metadata.component] -package = "component:msg-connect" -bindings = { implementor = "MsgConnect", ownership = "borrowing-duplicate-if-necessary" } - -[package.metadata.component.target] -path = "wit" - -[package.metadata.component.target.dependencies] -"coemu:actor" = { path = "../../wit/actor/" } - -[features] -default = ["std"] -std = ["tq-serde/std", "tq-network/std"] diff --git a/packets/connect/src/lib.rs b/packets/connect/src/lib.rs index 016dee0..9ba634a 100644 --- a/packets/connect/src/lib.rs +++ b/packets/connect/src/lib.rs @@ -1,39 +1,35 @@ -#![cfg_attr(not(feature = "std"), no_std)] +#![no_std] -#[cfg(not(feature = "std"))] extern crate alloc; -#[cfg(not(feature = "std"))] -use alloc::string::ToString; +use tq_bindings::Resource; +use tq_network::ActorHandle; +use tq_serde::String16; + +tq_bindings::generate!(); -cargo_component_bindings::generate!(); -use bindings::{ActorHandle, Error}; -use bytes::Bytes; -use serde::Deserialize; -use tq_network::{PacketDecode, PacketID}; -use tq_serde::String16; /// Message containing a connection request to the game server. Contains the /// player's access token from the Account server, and the patch and language /// versions of the game client. -#[derive(Debug, Deserialize, PacketID)] +#[derive(Debug, serde::Serialize, serde::Deserialize, tq_network::PacketID)] #[packet(id = 1052)] -#[allow(dead_code)] pub struct MsgConnect { - id: u32, - file_contents: u32, - file_name: String16, + pub id: u32, + pub file_contents: u32, + pub file_name: String16, +} + +#[repr(C)] +pub enum Error { + Network(tq_network::Error), } -impl bindings::Guest for MsgConnect { - fn process( - (id, buf): (u16, Vec), - actor: &ActorHandle, - ) -> Result<(), Error> { - assert_eq!(id, MsgConnect::PACKET_ID, "Invalid packet id"); - let _this = MsgConnect::decode(&Bytes::from(buf)) - .map_err(|e| Error::Decode(e.to_string()))?; - actor.shutdown(); - Ok(()) - } +#[tq_network::packet_processor(MsgConnect)] +fn process( + _msg: MsgConnect, + actor: &Resource, +) -> Result<(), crate::Error> { + host::shutdown(actor); + Ok(()) } diff --git a/packets/connect/wit/deps b/packets/connect/wit/deps deleted file mode 120000 index b0ff866..0000000 --- a/packets/connect/wit/deps +++ /dev/null @@ -1 +0,0 @@ -../../../wit \ No newline at end of file diff --git a/packets/connect/wit/world.wit b/packets/connect/wit/world.wit deleted file mode 100644 index fd5cf12..0000000 --- a/packets/connect/wit/world.wit +++ /dev/null @@ -1,12 +0,0 @@ -package coemu:msg-connect@0.1.0; - -world msg-connect { - use coemu:actor/types@0.1.0.{actor-handle, packet}; - variant error { - decode(string), - shutdown, - } - export process: func(packet: packet, actor: borrow) -> result<_, error>; -} - -// vim: set ft=typescript ts=2 sw=4 noet: diff --git a/rust-toolchain.toml b/rust-toolchain.toml index a008d53..86e8f38 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] channel = "nightly" components = ["rustfmt", "clippy", "rust-src"] -targets = ["wasm32-wasi"] +targets = ["wasm32-unknown-unknown"] diff --git a/server/auth/Cargo.toml b/server/auth/Cargo.toml index 2339d8c..89a5e1d 100644 --- a/server/auth/Cargo.toml +++ b/server/auth/Cargo.toml @@ -25,6 +25,7 @@ tracing.workspace = true dotenvy.workspace = true tokio-stream.workspace = true num_enum.workspace = true +futures.workspace = true # Packets # msg-account.workspace = true @@ -40,12 +41,7 @@ optional = true [dependencies.wasmtime] workspace = true default-features = false -features = ["async", "cranelift", "coredump", "cache", "pooling-allocator", "component-model"] - -[dependencies.wasmtime-wasi] -workspace = true -default-features = false -features = ["preview2"] +features = ["async", "cranelift", "coredump", "cache", "pooling-allocator"] [dependencies.tracing-subscriber] version = "0.3" @@ -66,6 +62,10 @@ workspace = true default-features = false features = ["sqlite"] +[dev-dependencies] +tokio = { workspace = true, features = ["full"] } +sqlx = { workspace = true, features = ["sqlite", "runtime-tokio"] } + [features] default = [] server = [ @@ -74,7 +74,6 @@ server = [ # "msg-account/std", # "msg-transfer/std", # "msg-connect-ex/std", - "msg-connect/std", "dep:tokio", "dep:tq-server", "sqlx/runtime-tokio", diff --git a/server/auth/src/error.rs b/server/auth/src/error.rs index ffb3be8..a7f43cd 100644 --- a/server/auth/src/error.rs +++ b/server/auth/src/error.rs @@ -15,7 +15,6 @@ pub enum Error { State(&'static str), Other(String), Msg(u16, Bytes), - MsgConnect(crate::generated::Error), ActorNotFound, } @@ -48,10 +47,6 @@ impl From for Error { fn from(v: tq_network::Error) -> Self { Self::Network(v) } } -impl From for Error { - fn from(v: crate::generated::Error) -> Self { Self::MsgConnect(v) } -} - impl From for Error { fn from(v: wasmtime::Error) -> Self { Self::Wasmtime(v) } } @@ -75,13 +70,11 @@ impl core::fmt::Display for Error { Self::Msg(id, bytes) => { write!(f, "Error packet: id = {}, body = {:?}", id, bytes) }, - Self::MsgConnect(e) => write!(f, "MsgConnect error: {}", e), Self::ActorNotFound => write!(f, "Actor Not Found"), } } } - impl From> for Error { fn from(v: ErrorPacket) -> Self { let (id, bytes) = v.0.encode().unwrap(); diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index 0b25558..66c7df8 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -1,60 +1,70 @@ //! Auth Server -pub mod generated { - wasmtime::component::bindgen!({ - path: "../../packets/connect/wit", - async: true, - }); -} - pub mod error; pub mod state; use bytes::Bytes; pub use state::State; use tq_network::{Actor, PacketHandler, PacketID}; -use wasmtime::component::{Component, Resource}; -use wasmtime::{Engine, Store}; -use wasmtime_wasi::preview2::{Table, WasiCtx, WasiView}; +use wasmtime::{Engine, ExternRef, Linker, Module, Store}; pub struct Runtime { pub state: State, pub engine: Engine, - pub wasi: WasiCtx, - pub table: Table, + pub linker: Linker, pub packets: Packets, } pub struct Packets { - pub msg_connect: Component, + pub msg_connect: Module, } #[async_trait::async_trait] impl PacketHandler for Runtime { type ActorState = (); type Error = crate::error::Error; - type State = Self; + type State = Runtime; async fn handle( packet: (u16, Bytes), runtime: &Self::State, actor: &Actor, ) -> Result<(), Self::Error> { - let mut store = Store::new(&runtime.engine, ()); - let packet = (packet.0, packet.1.to_vec()); - let actor = Resource::new_borrow(actor.id() as _); + const ALLOC_PACKET: &str = "alloc_packet"; + const PROCESS_PACKET: &str = "process_packet"; + const MEMORY: &str = "memory"; + let mut store = Store::new(&runtime.engine, runtime.state.clone()); + let actor = ExternRef::new(actor.handle()); match packet.0 { msg_connect::MsgConnect::PACKET_ID => { - let (bindings, _) = generated::MsgConnect::instantiate_async( - &mut store, &runtime.packets.msg_connect, &runtime.linker, - ) - .await?; - runtime - .packets - .msg_connect - .call_process(&mut store, &packet, actor) - .await? - .map_err(error::Error::MsgConnect) + let packet_len = packet.1.len(); + let msg_connect = runtime + .linker + .instantiate_async(&mut store, &runtime.packets.msg_connect) + .await?; + let alloc_packet = msg_connect + .get_typed_func::(&mut store, ALLOC_PACKET)?; + let ptr = alloc_packet + .call_async(&mut store, packet_len as u32) + .await?; + let memory = msg_connect + .get_memory(&mut store, MEMORY) + .expect("Failed to get memory"); + memory + .write(&mut store, ptr as usize, &packet.1) + .expect("Failed to write packet to memory"); + let process = msg_connect + .get_typed_func::<(i32, i32, Option), i32>( + &mut store, + PROCESS_PACKET, + )?; + process + .call_async( + &mut store, + (ptr, packet_len as i32, Some(actor)), + ) + .await?; + Ok(()) }, _ => { tracing::warn!("Unknown packet: {:#?}", packet); @@ -64,92 +74,74 @@ impl PacketHandler for Runtime { } } -impl WasiView for Runtime { - fn table(&self) -> &Table { &self.table } - - fn table_mut(&mut self) -> &mut Table { &mut self.table } - - fn ctx(&self) -> &WasiCtx { &self.wasi } - - fn ctx_mut(&mut self) -> &mut WasiCtx { &mut self.wasi } -} - -#[async_trait::async_trait] -impl generated::coemu::actor::types::HostActorHandle for Runtime { - async fn id( - &mut self, - r: Resource, - ) -> wasmtime::Result { - let actor = self - .state - .actor_handles - .get(&r.rep()) - .ok_or_else(|| error::Error::ActorNotFound)?; - Ok(actor.id() as u32) - } - - async fn set_id( - &mut self, - r: Resource, - id: u32, - ) -> wasmtime::Result<()> { - let actor = self - .state - .actor_handles - .get(&r.rep()) - .ok_or_else(|| error::Error::ActorNotFound)?; - actor.set_id(id as usize); - Ok(()) - } - - async fn generate_keys( - &mut self, - r: Resource, - seed: u64, - ) -> wasmtime::Result<()> { - let actor = self - .state - .actor_handles - .get(&r.rep()) - .ok_or_else(|| error::Error::ActorNotFound)?; - actor.generate_keys(seed).await?; - Ok(()) - } - - async fn send( - &mut self, - r: Resource, - packet: (u16, Vec), - ) -> wasmtime::Result<()> { - Ok(()) - } - - async fn send_all( - &mut self, - r: Resource, - packet: Vec<(u16, Vec)>, - ) -> wasmtime::Result<()> { - Ok(()) - } - - async fn shutdown( - &mut self, - r: Resource, - ) -> wasmtime::Result<()> { - let actor = self - .state - .actor_handles - .get(&r.rep()) - .ok_or_else(|| error::Error::ActorNotFound)?; - actor.shutdown().await?; - Ok(()) +#[cfg(test)] +mod tests { + use msg_connect::MsgConnect; + use tq_network::{ActorHandle, Message, PacketEncode}; + use wasmtime::Config; + + use super::*; + + async fn create_runtime() -> Runtime { + let mut config = Config::new(); + config.async_support(true); + config.wasm_reference_types(true); + + let engine = Engine::new(&config).unwrap(); + let mut linker = Linker::new(&engine); + linker + .func_wrap1_async::, ()>( + "host", + "shutdown", + |caller, actor_ref| { + Box::new(async move { + let actor_ref = actor_ref.unwrap(); + let actor = actor_ref + .data() + .downcast_ref::() + .unwrap(); + let _ = actor.shutdown().await; + }) as _ + }, + ) + .unwrap(); + + let msg_connect = Module::from_file( + &engine, + "../../target/wasm32-unknown-unknown/release/msg_connect.s.wasm", + ) + .unwrap(); + std::env::set_var("DATABASE_URL", "sqlite::memory:"); + let state = State::init().await.unwrap(); + let packets = Packets { msg_connect }; + + Runtime { + state, + linker, + engine, + packets, + } } - fn drop( - &mut self, - r: Resource, - ) -> wasmtime::Result<()> { - // Drop Actor - Ok(()) + #[tokio::test] + async fn test_msg_connect() { + let (tx, mut rx) = tokio::sync::mpsc::channel(100); + let runtime = create_runtime().await; + let msg = MsgConnect { + id: 1, + file_contents: 0, + file_name: String::from("test").into(), + }; + let actor = Actor::<()>::new(tx); + Runtime::handle( + ::encode(&msg).unwrap(), + &runtime, + &actor, + ) + .await + .unwrap(); + + let msg = rx.recv().await.unwrap(); + assert_eq!(msg, Message::Shutdown); } } diff --git a/server/auth/src/main.rs b/server/auth/src/main.rs index 0266e5a..1fef205 100644 --- a/server/auth/src/main.rs +++ b/server/auth/src/main.rs @@ -7,12 +7,10 @@ use bytes::Bytes; use msg_connect::MsgConnect; use std::env; -use tq_network::{Actor, PacketDecode, PacketHandler, PacketID, TQCipher}; +use tq_network::{Actor, PacketDecode, PacketHandler, PacketID, TQCipher, ActorHandle}; #[cfg(feature = "server")] use tq_server::TQServer; -use wasmtime::component::{Component, Linker}; -use wasmtime::{Config, Engine, Store}; -use wasmtime_wasi::preview2::{Table, WasiCtxBuilder}; +use wasmtime::{Config, Engine, ExternRef, Linker, Module, Store}; use auth::error::Error; use auth::{Runtime, State}; @@ -49,37 +47,36 @@ Copyright 2020-2023 Shady Khalifa (@shekohex) // Configure an `Engine` and compile the `Component` that is being run for // the application. let mut config = Config::new(); - config.wasm_component_model(true); config.async_support(true); + config.wasm_reference_types(true); let engine = Engine::new(&config)?; let mut linker = Linker::new(&engine); - wasmtime_wasi::preview2::command::add_to_linker(&mut linker)?; - let wasi = WasiCtxBuilder::new().inherit_stdio().build(); - let table = Table::new(); - tracing::info!("Initializing State .."); + linker.func_wrap1_async::, ()>( + "host", + "shutdown", + |caller, actor_ref| Box::new(async move { + let actor_ref = actor_ref.unwrap(); + let actor = actor_ref.data().downcast_ref::().unwrap(); + let _ = actor.shutdown().await; + }) as _, + )?; tracing::info!("Loading Packet and handlers.."); - let msg_connect = Component::from_file( + let msg_connect = Module::from_file( &engine, - "./target/wasm32-wasi/debug/msg_connect.wasm", + "./target/wasm32-unknown-unknown/debug/msg_connect.wasm", )?; - tracing::info!("Starting Auth Server"); - tracing::info!("Initializing server..."); - let auth_port = env::var("AUTH_PORT")?; - tracing::info!("Auth Server will be available on {auth_port}"); - + tracing::info!("Initializing State .."); let state = State::init().await?; let packets = auth::Packets { msg_connect }; let static_runtime = { let runtime = Runtime { state, - engine, linker, - wasi, - table, + engine, packets, }; Box::leak(Box::new(runtime)) as *mut _ @@ -87,12 +84,17 @@ Copyright 2020-2023 Shady Khalifa (@shekohex) // SAFETY: We are the only owner of this Box, and we are deref // it. This happens only once, so no one else can access. let runtime: &'static _ = unsafe { &*static_runtime }; + + tracing::info!("Starting Auth Server"); + tracing::info!("Initializing server..."); + let auth_port = env::var("AUTH_PORT")?; + tracing::info!("Auth Server will be available on {auth_port}"); AuthServer::run(format!("0.0.0.0:{}", auth_port), runtime).await?; unsafe { // SAFETY: We are the only owner of this Box, and we are dropping // it. This happens at the end of the program, so no one // else can access. - let _ = Box::from_raw(static_state); + let _ = Box::from_raw(static_runtime); }; tracing::info!("Shutdown."); Ok(()) diff --git a/server/auth/src/state.rs b/server/auth/src/state.rs index 50854c6..2b4b622 100644 --- a/server/auth/src/state.rs +++ b/server/auth/src/state.rs @@ -1,13 +1,9 @@ -use std::collections::HashMap; - use crate::error::Error; use sqlx::sqlite::{SqlitePool, SqlitePoolOptions}; -use tq_network::ActorHandle; #[derive(Debug, Clone)] pub struct State { pool: SqlitePool, - pub(crate) actor_handles: HashMap, } impl State { @@ -24,10 +20,7 @@ impl State { .min_connections(4) .connect(&db_url) .await?; - let state = Self { - pool, - actor_handles: Default::default(), - }; + let state = Self { pool }; Ok(state) } diff --git a/tools/externref/Cargo.toml b/tools/externref/Cargo.toml new file mode 100644 index 0000000..f635620 --- /dev/null +++ b/tools/externref/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "externref-cli" +version = "0.1.0" +edition.workspace = true + + +[dependencies] +externref = { workspace = true, features = ["processor"] } diff --git a/tools/externref/src/main.rs b/tools/externref/src/main.rs new file mode 100644 index 0000000..9dc7fea --- /dev/null +++ b/tools/externref/src/main.rs @@ -0,0 +1,26 @@ +use externref::processor::Processor; + +fn main() { + let args = std::env::args().collect::>(); + let mut args = args.iter().skip(1); + let input = args.next().unwrap_or_else(print_usage); + let output = args.next().unwrap_or_else(print_usage); + let module = std::fs::read(input).unwrap_or_else(|err| { + eprintln!("Failed to read input file: {}", err); + std::process::exit(1); + }); + let processed: Vec = Processor::default() + .process_bytes(&module).unwrap(); + std::fs::write(output, processed).unwrap_or_else(|err| { + eprintln!("Failed to write output file: {}", err); + std::process::exit(1); + }); +} + +fn print_usage<'a>() -> &'a String { + eprintln!( + "Usage: {} ", + std::env::args().next().unwrap() + ); + std::process::exit(1); +} diff --git a/wit/actor/types.wit b/wit/actor/types.wit deleted file mode 100644 index 0d1839d..0000000 --- a/wit/actor/types.wit +++ /dev/null @@ -1,15 +0,0 @@ -package coemu:actor@0.1.0; - -interface types { - type packet = tuple>; - resource actor-handle { - id: func() -> u32; - set-id: func(id: u32); - send: func(packet: packet); - send-all: func(packet: list); - generate-keys: func(seed: u64); - shutdown: func(); - } -} - -// vim: set ft=typescript ts=2 sw=4 noet: From a370789928adf946e5b553f772e92751450ede33 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sat, 13 Jan 2024 00:09:02 +0200 Subject: [PATCH 13/28] Moving things now works! --- Cargo.lock | 13 ++++++ Cargo.toml | 2 - crates/bindings/src/lib.rs | 53 ++++++++++++++-------- crates/network/src/lib.rs | 7 +++ packets/connect/Cargo.toml | 2 +- packets/connect/src/lib.rs | 14 +++--- server/auth/Cargo.toml | 1 + server/auth/src/lib.rs | 90 ++++++++++++++++++++++++++++++++----- server/auth/src/main.rs | 17 ++++--- tools/externref/src/main.rs | 4 +- 10 files changed, 156 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index acd46c6..dad39a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1467,6 +1467,7 @@ dependencies = [ "tq-bindings", "tq-network", "tq-serde", + "tracing", ] [[package]] @@ -2781,6 +2782,17 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.18" @@ -2797,6 +2809,7 @@ dependencies = [ "thread_local", "tracing", "tracing-core", + "tracing-log", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b8bc7cb..89c3aaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,8 +82,6 @@ version = "0.7.3" [profile.dev] split-debuginfo = 'packed' -lto = true -codegen-units = 1 [profile.wasmdebug] inherits = "dev" diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs index 05278a7..9da8536 100644 --- a/crates/bindings/src/lib.rs +++ b/crates/bindings/src/lib.rs @@ -7,24 +7,41 @@ extern crate alloc; pub use externref::{self as anyref, externref, Resource}; -/// Generate host bindings. -#[macro_export] -macro_rules! generate { - () => { - #[$crate::externref(crate = "tq_bindings::anyref")] - #[link(wasm_import_module = "host")] - extern "C" { - fn shutdown(actor: &Resource); - } +#[externref(crate = "crate::anyref")] +#[link(wasm_import_module = "host")] +extern "C" { + fn shutdown(actor: &Resource); + fn send( + actor: &Resource, + packet_id: u16, + packet_data_ptr: *const u8, + packet_data_len: u32, + ); +} + +/// Host bindings. +pub mod host { + use crate::Resource; + use tq_network::ActorHandle; + /// Shutdown an actor. + pub fn shutdown(actor: &Resource) { + unsafe { super::shutdown(actor) } + } - /// Host bindings. - mod host { - use $crate::Resource; - use tq_network::ActorHandle; - /// Shutdown an actor. - pub fn shutdown(actor: &Resource) { - unsafe { super::shutdown(actor) } - } + /// Send a packet to an actor. + pub fn send( + actor: &Resource, + packet: T, + ) -> Result<(), T::Error> { + let (packet_id, packet_data) = packet.encode()?; + unsafe { + super::send( + actor, + packet_id, + packet_data.as_ptr(), + packet_data.len() as u32, + ) } - }; + Ok(()) + } } diff --git a/crates/network/src/lib.rs b/crates/network/src/lib.rs index 7b7c818..b53e3ec 100644 --- a/crates/network/src/lib.rs +++ b/crates/network/src/lib.rs @@ -98,6 +98,13 @@ where } } +impl PacketEncode for (u16, Bytes) { + type Error = Error; + type Packet = (); + + fn encode(&self) -> Result<(u16, Bytes), Self::Error> { Ok(self.clone()) } +} + impl PacketDecode for T where T: DeserializeOwned, diff --git a/packets/connect/Cargo.toml b/packets/connect/Cargo.toml index 7f4c3a8..b168303 100644 --- a/packets/connect/Cargo.toml +++ b/packets/connect/Cargo.toml @@ -13,4 +13,4 @@ tq-bindings.workspace = true serde.workspace = true bytes.workspace = true - +tracing.workspace = true diff --git a/packets/connect/src/lib.rs b/packets/connect/src/lib.rs index 9ba634a..199cf78 100644 --- a/packets/connect/src/lib.rs +++ b/packets/connect/src/lib.rs @@ -2,13 +2,10 @@ extern crate alloc; -use tq_bindings::Resource; +use tq_bindings::{host, Resource}; use tq_network::ActorHandle; use tq_serde::String16; -tq_bindings::generate!(); - - /// Message containing a connection request to the game server. Contains the /// player's access token from the Account server, and the patch and language /// versions of the game client. @@ -20,16 +17,21 @@ pub struct MsgConnect { pub file_name: String16, } -#[repr(C)] pub enum Error { Network(tq_network::Error), } +impl From for Error { + fn from(v: tq_network::Error) -> Self { Self::Network(v) } +} + #[tq_network::packet_processor(MsgConnect)] fn process( - _msg: MsgConnect, + msg: MsgConnect, actor: &Resource, ) -> Result<(), crate::Error> { + tracing::debug!(?msg, "Shutting down actor"); + host::send(actor, msg)?; host::shutdown(actor); Ok(()) } diff --git a/server/auth/Cargo.toml b/server/auth/Cargo.toml index 89a5e1d..eb13a51 100644 --- a/server/auth/Cargo.toml +++ b/server/auth/Cargo.toml @@ -65,6 +65,7 @@ features = ["sqlite"] [dev-dependencies] tokio = { workspace = true, features = ["full"] } sqlx = { workspace = true, features = ["sqlite", "runtime-tokio"] } +tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "ansi"] } [features] default = [] diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index 66c7df8..e2ccc11 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -6,7 +6,7 @@ pub mod state; use bytes::Bytes; pub use state::State; use tq_network::{Actor, PacketHandler, PacketID}; -use wasmtime::{Engine, ExternRef, Linker, Module, Store}; +use wasmtime::{Engine, ExternRef, Linker, Module}; pub struct Runtime { pub state: State, @@ -33,8 +33,9 @@ impl PacketHandler for Runtime { const ALLOC_PACKET: &str = "alloc_packet"; const PROCESS_PACKET: &str = "process_packet"; const MEMORY: &str = "memory"; - let mut store = Store::new(&runtime.engine, runtime.state.clone()); - let actor = ExternRef::new(actor.handle()); + let mut store = + wasmtime::Store::new(&runtime.engine, runtime.state.clone()); + let actor = wasmtime::ExternRef::new(actor.handle()); match packet.0 { msg_connect::MsgConnect::PACKET_ID => { let packet_len = packet.1.len(); @@ -76,6 +77,7 @@ impl PacketHandler for Runtime { #[cfg(test)] mod tests { + use bytes::BytesMut; use msg_connect::MsgConnect; use tq_network::{ActorHandle, Message, PacketEncode}; use wasmtime::Config; @@ -93,7 +95,7 @@ mod tests { .func_wrap1_async::, ()>( "host", "shutdown", - |caller, actor_ref| { + |_caller, actor_ref| { Box::new(async move { let actor_ref = actor_ref.unwrap(); let actor = actor_ref @@ -104,11 +106,46 @@ mod tests { }) as _ }, ) + .unwrap() + .func_wrap4_async::, i32, i32, i32, ()>( + "host", + "send", + |mut caller, + actor_ref, + packet_id, + packet_data_ptr, + packet_data_len| { + Box::new(async move { + let actor_ref = actor_ref.unwrap(); + let actor = actor_ref + .data() + .downcast_ref::() + .unwrap(); + let memory = caller + .get_export("memory") + .and_then(|e| e.into_memory()) + .expect("Failed to get memory"); + let mut packet_data = + BytesMut::with_capacity(packet_data_len as usize); + packet_data.resize(packet_data_len as usize, 0); + memory + .read( + caller, + packet_data_ptr as usize, + &mut packet_data, + ) + .expect("Failed to read packet from memory"); + let _ = actor + .send((packet_id as u16, packet_data.freeze())) + .await; + }) as _ + }, + ) .unwrap(); let msg_connect = Module::from_file( &engine, - "../../target/wasm32-unknown-unknown/release/msg_connect.s.wasm", + "../../target/wasm32-unknown-unknown/wasm/msg_connect.s.wasm", ) .unwrap(); std::env::set_var("DATABASE_URL", "sqlite::memory:"); @@ -123,8 +160,36 @@ mod tests { } } + fn setup_logger(verbosity: i32) { + use tracing::Level; + let log_level = match verbosity { + 0 => Level::ERROR, + 1 => Level::WARN, + 2 => Level::INFO, + 3 => Level::DEBUG, + _ => Level::TRACE, + }; + + let env_filter = tracing_subscriber::EnvFilter::from_default_env() + .add_directive(format!("tq_db={}", log_level).parse().unwrap()) + .add_directive(format!("tq_serde={}", log_level).parse().unwrap()) + .add_directive(format!("tq_crypto={}", log_level).parse().unwrap()) + .add_directive(format!("tq_codec={}", log_level).parse().unwrap()) + .add_directive(format!("tq_network={}", log_level).parse().unwrap()) + .add_directive(format!("tq_server={}", log_level).parse().unwrap()) + .add_directive(format!("auth={}", log_level).parse().unwrap()); + let logger = tracing_subscriber::fmt() + .pretty() + .with_test_writer() + .with_target(true) + .with_max_level(log_level) + .with_env_filter(env_filter); + logger.init(); + } + #[tokio::test] async fn test_msg_connect() { + setup_logger(3); let (tx, mut rx) = tokio::sync::mpsc::channel(100); let runtime = create_runtime().await; let msg = MsgConnect { @@ -133,13 +198,14 @@ mod tests { file_name: String::from("test").into(), }; let actor = Actor::<()>::new(tx); - Runtime::handle( - ::encode(&msg).unwrap(), - &runtime, - &actor, - ) - .await - .unwrap(); + + let encoded = ::encode(&msg).unwrap(); + Runtime::handle(encoded.clone(), &runtime, &actor) + .await + .unwrap(); + + let msg = rx.recv().await.unwrap(); + assert_eq!(msg, Message::Packet(encoded.0, encoded.1)); let msg = rx.recv().await.unwrap(); assert_eq!(msg, Message::Shutdown); diff --git a/server/auth/src/main.rs b/server/auth/src/main.rs index 1fef205..fa2fa09 100644 --- a/server/auth/src/main.rs +++ b/server/auth/src/main.rs @@ -7,7 +7,9 @@ use bytes::Bytes; use msg_connect::MsgConnect; use std::env; -use tq_network::{Actor, PacketDecode, PacketHandler, PacketID, TQCipher, ActorHandle}; +use tq_network::{ + Actor, ActorHandle, PacketDecode, PacketHandler, PacketID, TQCipher, +}; #[cfg(feature = "server")] use tq_server::TQServer; use wasmtime::{Config, Engine, ExternRef, Linker, Module, Store}; @@ -55,11 +57,14 @@ Copyright 2020-2023 Shady Khalifa (@shekohex) linker.func_wrap1_async::, ()>( "host", "shutdown", - |caller, actor_ref| Box::new(async move { - let actor_ref = actor_ref.unwrap(); - let actor = actor_ref.data().downcast_ref::().unwrap(); - let _ = actor.shutdown().await; - }) as _, + |caller, actor_ref| { + Box::new(async move { + let actor_ref = actor_ref.unwrap(); + let actor = + actor_ref.data().downcast_ref::().unwrap(); + let _ = actor.shutdown().await; + }) as _ + }, )?; tracing::info!("Loading Packet and handlers.."); diff --git a/tools/externref/src/main.rs b/tools/externref/src/main.rs index 9dc7fea..65cd1c0 100644 --- a/tools/externref/src/main.rs +++ b/tools/externref/src/main.rs @@ -9,8 +9,8 @@ fn main() { eprintln!("Failed to read input file: {}", err); std::process::exit(1); }); - let processed: Vec = Processor::default() - .process_bytes(&module).unwrap(); + let processed: Vec = + Processor::default().process_bytes(&module).unwrap(); std::fs::write(output, processed).unwrap_or_else(|err| { eprintln!("Failed to write output file: {}", err); std::process::exit(1); From 3120c60acbb1a74e801f417d8a46da93e97ce8b0 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sat, 13 Jan 2024 15:10:31 +0200 Subject: [PATCH 14/28] working on logs --- Cargo.lock | 12 ++ Cargo.toml | 3 + crates/bindings/Cargo.toml | 5 +- crates/bindings/src/lib.rs | 15 +++ crates/tracing-wasm/Cargo.toml | 12 ++ crates/tracing-wasm/src/lib.rs | 151 +++++++++++++++++++++++ macros/derive-packetprocessor/src/lib.rs | 11 +- packets/connect/Cargo.toml | 6 + packets/connect/src/lib.rs | 7 +- server/auth/Cargo.toml | 2 +- server/auth/src/lib.rs | 35 ++++++ 11 files changed, 254 insertions(+), 5 deletions(-) create mode 100644 crates/tracing-wasm/Cargo.toml create mode 100644 crates/tracing-wasm/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index dad39a8..fa127d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1468,6 +1468,7 @@ dependencies = [ "tq-network", "tq-serde", "tracing", + "tracing-wasm", ] [[package]] @@ -2663,6 +2664,9 @@ version = "0.1.0" dependencies = [ "externref", "tq-network", + "tracing", + "tracing-subscriber", + "tracing-wasm", ] [[package]] @@ -2812,6 +2816,14 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "tracing-wasm" +version = "0.1.0" +dependencies = [ + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "try-lock" version = "0.2.5" diff --git a/Cargo.toml b/Cargo.toml index 89c3aaf..338ad4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ tq-codec = { path = "crates/codec" } tq-db = { path = "crates/db" } tq-server = { path = "crates/server" } tq-bindings = { path = "crates/bindings" } +tracing-wasm = { path = "crates/tracing-wasm" } derive-packetid = { path = "macros/derive-packetid" } derive-packethandler = { path = "macros/derive-packethandler" } @@ -52,6 +53,8 @@ serde = { version = "1.0", default-features = false, features = ["alloc", "deriv bytes = { version = "1.5", default-features = false } async-trait = { version = "0.1", default-features = false } tracing = { version = "0.1", default-features = false } +tracing-core = { version = "0.1", default-features = false } +tracing-subscriber = { version = "0.3", default-features = false } dotenvy = "0.15" bitflags = { version = "2.4", default-features = false } argh = "0.1" diff --git a/crates/bindings/Cargo.toml b/crates/bindings/Cargo.toml index 2735fac..5f416e5 100644 --- a/crates/bindings/Cargo.toml +++ b/crates/bindings/Cargo.toml @@ -5,9 +5,12 @@ edition.workspace = true [dependencies] tq-network.workspace = true +tracing-wasm.workspace = true +tracing = { workspace = true, default-features = false, optional = true } +tracing-subscriber = { workspace = true, default-features = false, features = ["alloc"], optional = true } externref = { workspace = true, features = ["macro"] } [features] default = [] -std = ["tq-network/std"] +std = ["tq-network/std", "tracing-wasm/std", "dep:tracing", "dep:tracing-subscriber"] diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs index 9da8536..6770f7a 100644 --- a/crates/bindings/src/lib.rs +++ b/crates/bindings/src/lib.rs @@ -19,6 +19,19 @@ extern "C" { ); } +/// A [`MakeWriter`] emitting the written text to the [`host`]. +#[cfg(feature = "std")] +pub fn setup_logging(name: &'static str) { + let subscriber = tracing_subscriber::fmt() + .with_writer(tracing_wasm::MakeWasmWriter::new().with_target(name)) + .finish(); + tracing::subscriber::set_global_default(subscriber).unwrap(); +} + +/// A [`MakeWriter`] emitting the written text to the [`host`]. +#[cfg(not(feature = "std"))] +pub fn setup_logging(_name: &'static str) {} + /// Host bindings. pub mod host { use crate::Resource; @@ -44,4 +57,6 @@ pub mod host { } Ok(()) } + + pub use tracing_wasm::log; } diff --git a/crates/tracing-wasm/Cargo.toml b/crates/tracing-wasm/Cargo.toml new file mode 100644 index 0000000..bea13ca --- /dev/null +++ b/crates/tracing-wasm/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "tracing-wasm" +version = "0.1.0" +edition.workspace = true + +[dependencies] +tracing-core = { workspace = true, default-features = false } +tracing-subscriber = { workspace = true, default-features = false, features = ["alloc"] } + +[features] +default = [] +std = ["tracing-subscriber/std", "tracing-subscriber/fmt"] diff --git a/crates/tracing-wasm/src/lib.rs b/crates/tracing-wasm/src/lib.rs new file mode 100644 index 0000000..91cc633 --- /dev/null +++ b/crates/tracing-wasm/src/lib.rs @@ -0,0 +1,151 @@ +//! Wasm-specific extensions for `tracing`. +//! This crate provides a `tracing` layer for use in WASM environments. It +//! provides a `tracing` layer for use in WASM environments, and is used by +//! all packets that needs to emit tracing events. +//! +//! # Usage +//! ```rust, no_run +//! use tracing_wasm::MakeWasmWriter; +//! use tracing_subscriber::prelude::*; +//! +//! let fmt_layer = tracing_subscriber::fmt::layer() +//! .without_time() // std::time is not available in host +//! .with_writer(MakeWasmWriter::new()); // write events to the host +//! tracing_subscriber::registry() +//! .with(fmt_layer) +//! .init(); +//! ``` +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; + +#[cfg(not(feature = "std"))] +use alloc::{string::String, vec::Vec}; + +use tracing_core::Level; +#[cfg(feature = "std")] +use tracing_subscriber::fmt::MakeWriter; + +#[link(wasm_import_module = "host")] +extern "C" { + fn trace_event( + level: u8, + target: *const u8, + target_len: u32, + message: *const u8, + message_len: u32, + ); +} +/// A [`MakeWriter`] emitting the written text to the [`host`]. +pub struct MakeWasmWriter { + use_pretty_label: bool, + target: &'static str, +} + +impl Default for MakeWasmWriter { + fn default() -> Self { Self::new() } +} + +impl MakeWasmWriter { + /// Create a default console writer, i.e. no level annotation is shown when + /// logging a message. + pub fn new() -> Self { + Self { + use_pretty_label: false, + target: "wasm", + } + } + + /// Change writer with the given target. + pub fn with_target(mut self, target: &'static str) -> Self { + self.target = target; + self + } + + /// Enables an additional label for the log level to be shown. + /// + /// It is recommended that you also use [`Layer::with_level(false)`] if you + /// use this option, to avoid the event level being shown twice. + /// + /// [`Layer::with_level(false)`]: tracing_subscriber::fmt::Layer::with_level + pub fn with_pretty_level(mut self) -> Self { + self.use_pretty_label = true; + self + } +} + +type LogDispatcher = fn(Level, &str, &str); + +/// Dispatches a log message to the host. +pub fn log(level: Level, target: &str, message: &str) { + let level = match level { + Level::ERROR => 0, + Level::WARN => 1, + Level::INFO => 2, + Level::DEBUG => 3, + Level::TRACE => 4, + }; + let message = message.as_bytes(); + let target = target.as_bytes(); + unsafe { + trace_event( + level, + target.as_ptr(), + target.len() as u32, + message.as_ptr(), + message.len() as u32, + ) + } +} + +/// Concrete [`std::io::Write`] implementation returned by [`MakeWasmWriter`]. +pub struct WasmWriter { + buffer: Vec, + target: String, + level: Level, + log: LogDispatcher, +} + +impl Drop for WasmWriter { + fn drop(&mut self) { + let message = String::from_utf8_lossy(&self.buffer); + (self.log)(self.level, self.target.as_ref(), message.as_ref()) + } +} + +#[cfg(feature = "std")] +impl std::io::Write for WasmWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.buffer.write(buf) + } + + fn flush(&mut self) -> std::io::Result<()> { Ok(()) } +} +#[cfg(feature = "std")] +impl<'a> MakeWriter<'a> for MakeWasmWriter { + type Writer = WasmWriter; + + fn make_writer(&'a self) -> Self::Writer { + WasmWriter { + buffer: Vec::new(), + level: Level::TRACE, + target: self.target.to_string(), + log, + } + } + + fn make_writer_for( + &'a self, + meta: &tracing_core::Metadata<'_>, + ) -> Self::Writer { + let level = *meta.level(); + let target = meta.target().to_string(); + WasmWriter { + buffer: Vec::new(), + target, + level, + log, + } + } +} diff --git a/macros/derive-packetprocessor/src/lib.rs b/macros/derive-packetprocessor/src/lib.rs index 6dc889b..e668192 100644 --- a/macros/derive-packetprocessor/src/lib.rs +++ b/macros/derive-packetprocessor/src/lib.rs @@ -78,11 +78,16 @@ fn derive_packet_processor( }; let inner_fn_call = inner_fn.sig.ident.clone(); + let msg_ty_name = msg_ty.to_string().to_lowercase(); // Build the output, possibly using quasi-quotation let expanded = quote! { #[export_name = "alloc_packet"] pub extern "C" fn alloc_packet(size: u32) -> *mut u8 { - let mut v = core::mem::ManuallyDrop::new(::alloc::vec::Vec::with_capacity(size as usize)); + #[cfg(not(feature = "std"))] + let v = ::alloc::vec::Vec::with_capacity(size as usize); + #[cfg(feature = "std")] + let v = ::std::vec::Vec::with_capacity(size as usize); + let mut v = core::mem::ManuallyDrop::new(v); unsafe { v.set_len(size as usize); } @@ -100,7 +105,11 @@ fn derive_packet_processor( packet_len: u32, actor: &::tq_bindings::Resource, ) -> i32 { + ::tq_bindings::setup_logging(#msg_ty_name); + #[cfg(not(feature = "std"))] let packet = ::alloc::vec::Vec::from_raw_parts(packet_ptr, packet_len as _, packet_len as _); + #[cfg(feature = "std")] + let packet = ::std::vec::Vec::from_raw_parts(packet_ptr, packet_len as _, packet_len as _); let bytes = ::bytes::BytesMut::from(packet.as_slice()).freeze(); let packet = match <#msg_ty as ::tq_network::PacketDecode>::decode(&bytes) { Ok(packet) => packet, diff --git a/packets/connect/Cargo.toml b/packets/connect/Cargo.toml index b168303..598517c 100644 --- a/packets/connect/Cargo.toml +++ b/packets/connect/Cargo.toml @@ -14,3 +14,9 @@ tq-bindings.workspace = true serde.workspace = true bytes.workspace = true tracing.workspace = true +tracing-wasm.workspace = true + +[features] +default = [] +std = ["tq-serde/std", "tq-network/std", "tq-bindings/std", "tracing-wasm/std"] + diff --git a/packets/connect/src/lib.rs b/packets/connect/src/lib.rs index 199cf78..ac63dfe 100644 --- a/packets/connect/src/lib.rs +++ b/packets/connect/src/lib.rs @@ -1,5 +1,6 @@ -#![no_std] +#![cfg_attr(not(feature = "std"), no_std)] +#[cfg(not(feature = "std"))] extern crate alloc; use tq_bindings::{host, Resource}; @@ -30,7 +31,9 @@ fn process( msg: MsgConnect, actor: &Resource, ) -> Result<(), crate::Error> { - tracing::debug!(?msg, "Shutting down actor"); + host::log(tracing::Level::DEBUG, "msgconnect", "hello?"); + assert!(tracing::dispatcher::get_default(|_| Some(())).is_some()); + tracing::debug!(target: "msgconnect", ?msg, "Shutting down actor"); host::send(actor, msg)?; host::shutdown(actor); Ok(()) diff --git a/server/auth/Cargo.toml b/server/auth/Cargo.toml index eb13a51..e3bc2ce 100644 --- a/server/auth/Cargo.toml +++ b/server/auth/Cargo.toml @@ -44,7 +44,7 @@ default-features = false features = ["async", "cranelift", "coredump", "cache", "pooling-allocator"] [dependencies.tracing-subscriber] -version = "0.3" +workspace = true optional = true default-features = false features = ["env-filter", "ansi", "fmt", "smallvec"] diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index e2ccc11..6d0fc23 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -92,6 +92,41 @@ mod tests { let engine = Engine::new(&config).unwrap(); let mut linker = Linker::new(&engine); linker + .func_wrap5_async::( + "host", + "trace_event", + |mut caller, + level, + target, + target_len, + message, + message_len| { + Box::new(async move { + let memory = caller + .get_export("memory") + .and_then(|e| e.into_memory()) + .expect("Failed to get memory"); + let mut target_buf = vec![0; target_len as usize]; + let mut message_buf = vec![0; message_len as usize]; + memory + .read(&caller, target as usize, &mut target_buf) + .expect("Failed to read target from memory"); + memory + .read(&caller, message as usize, &mut message_buf) + .expect("Failed to read message from memory"); + let target = String::from_utf8(target_buf).unwrap(); + let message = String::from_utf8(message_buf).unwrap(); + match level { + 0 => tracing::error!(%target, %message), + 1 => tracing::warn!(%target, %message), + 2 => tracing::info!(%target, %message), + 3 => tracing::debug!(%target, %message), + _ => tracing::trace!(%target, %message), + }; + }) as _ + }, + ) + .unwrap() .func_wrap1_async::, ()>( "host", "shutdown", From 2bafaf9c93eb233508ad85f37f1eee3bc2057f0c Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sat, 13 Jan 2024 19:34:58 +0200 Subject: [PATCH 15/28] Logging and panic handler works! --- crates/bindings/Cargo.toml | 2 +- crates/bindings/src/lib.rs | 47 ++++++++++++++++++++++++ crates/tracing-wasm/src/lib.rs | 9 ++++- macros/derive-packetprocessor/src/lib.rs | 4 ++ packets/connect/src/lib.rs | 4 +- server/auth/src/lib.rs | 20 ++++++---- 6 files changed, 74 insertions(+), 12 deletions(-) diff --git a/crates/bindings/Cargo.toml b/crates/bindings/Cargo.toml index 5f416e5..15ce0b4 100644 --- a/crates/bindings/Cargo.toml +++ b/crates/bindings/Cargo.toml @@ -9,7 +9,7 @@ tracing-wasm.workspace = true tracing = { workspace = true, default-features = false, optional = true } tracing-subscriber = { workspace = true, default-features = false, features = ["alloc"], optional = true } -externref = { workspace = true, features = ["macro"] } +externref = { workspace = true, default-features = false, features = ["macro"] } [features] default = [] diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs index 6770f7a..5f2828c 100644 --- a/crates/bindings/src/lib.rs +++ b/crates/bindings/src/lib.rs @@ -7,6 +7,7 @@ extern crate alloc; pub use externref::{self as anyref, externref, Resource}; +#[cfg(target_arch = "wasm32")] #[externref(crate = "crate::anyref")] #[link(wasm_import_module = "host")] extern "C" { @@ -23,6 +24,10 @@ extern "C" { #[cfg(feature = "std")] pub fn setup_logging(name: &'static str) { let subscriber = tracing_subscriber::fmt() + .without_time() + .with_level(false) + .with_target(false) + .with_max_level(tracing_wasm::Level::TRACE) .with_writer(tracing_wasm::MakeWasmWriter::new().with_target(name)) .finish(); tracing::subscriber::set_global_default(subscriber).unwrap(); @@ -32,16 +37,50 @@ pub fn setup_logging(name: &'static str) { #[cfg(not(feature = "std"))] pub fn setup_logging(_name: &'static str) {} +/// Sets a panic hook that logs to the host. +#[cfg(feature = "std")] +pub fn set_panic_hook_once() { + static SET_HOOK: std::sync::Once = std::sync::Once::new(); + SET_HOOK.call_once(|| { + std::panic::set_hook(Box::new(|info| { + let payload = info + .payload() + .downcast_ref::<&str>() + .map(|s| *s) + .unwrap_or_else(|| { + info.payload().downcast_ref::().unwrap().as_str() + }); + let location = info + .location() + .map(|l| format!("{}:{}", l.file(), l.line())); + host::log( + tracing_wasm::Level::ERROR, + "panic", + &format!("{payload} {}", location.unwrap_or_default()), + ); + })); + }); +} + +#[cfg(not(feature = "std"))] +pub fn set_panic_hook_once() {} + /// Host bindings. pub mod host { use crate::Resource; use tq_network::ActorHandle; /// Shutdown an actor. + #[cfg(target_arch = "wasm32")] pub fn shutdown(actor: &Resource) { unsafe { super::shutdown(actor) } } + #[cfg(not(target_arch = "wasm32"))] + pub fn shutdown(_actor: &Resource) {} + /// Send a packet to an actor. + + #[cfg(target_arch = "wasm32")] pub fn send( actor: &Resource, packet: T, @@ -58,5 +97,13 @@ pub mod host { Ok(()) } + #[cfg(not(target_arch = "wasm32"))] + pub fn send( + _actor: &Resource, + _packet: T, + ) -> Result<(), T::Error> { + Ok(()) + } + pub use tracing_wasm::log; } diff --git a/crates/tracing-wasm/src/lib.rs b/crates/tracing-wasm/src/lib.rs index 91cc633..7d6c20c 100644 --- a/crates/tracing-wasm/src/lib.rs +++ b/crates/tracing-wasm/src/lib.rs @@ -23,11 +23,13 @@ extern crate alloc; #[cfg(not(feature = "std"))] use alloc::{string::String, vec::Vec}; -use tracing_core::Level; +pub use tracing_core::Level; + #[cfg(feature = "std")] use tracing_subscriber::fmt::MakeWriter; #[link(wasm_import_module = "host")] +#[cfg(target_arch = "wasm32")] extern "C" { fn trace_event( level: u8, @@ -37,6 +39,7 @@ extern "C" { message_len: u32, ); } + /// A [`MakeWriter`] emitting the written text to the [`host`]. pub struct MakeWasmWriter { use_pretty_label: bool, @@ -78,6 +81,7 @@ impl MakeWasmWriter { type LogDispatcher = fn(Level, &str, &str); /// Dispatches a log message to the host. +#[cfg(target_arch = "wasm32")] pub fn log(level: Level, target: &str, message: &str) { let level = match level { Level::ERROR => 0, @@ -99,6 +103,9 @@ pub fn log(level: Level, target: &str, message: &str) { } } +#[cfg(not(target_arch = "wasm32"))] +pub fn log(_level: Level, _target: &str, _message: &str) {} + /// Concrete [`std::io::Write`] implementation returned by [`MakeWasmWriter`]. pub struct WasmWriter { buffer: Vec, diff --git a/macros/derive-packetprocessor/src/lib.rs b/macros/derive-packetprocessor/src/lib.rs index e668192..1019602 100644 --- a/macros/derive-packetprocessor/src/lib.rs +++ b/macros/derive-packetprocessor/src/lib.rs @@ -82,6 +82,7 @@ fn derive_packet_processor( // Build the output, possibly using quasi-quotation let expanded = quote! { #[export_name = "alloc_packet"] + #[cfg(target_arch = "wasm32")] pub extern "C" fn alloc_packet(size: u32) -> *mut u8 { #[cfg(not(feature = "std"))] let v = ::alloc::vec::Vec::with_capacity(size as usize); @@ -96,15 +97,18 @@ fn derive_packet_processor( ptr } + #inner_fn #[::tq_bindings::externref(crate = "tq_bindings::anyref")] #[export_name = "process_packet"] + #[cfg(target_arch = "wasm32")] pub unsafe extern "C" fn _process( packet_ptr: *mut u8, packet_len: u32, actor: &::tq_bindings::Resource, ) -> i32 { + ::tq_bindings::set_panic_hook_once(); ::tq_bindings::setup_logging(#msg_ty_name); #[cfg(not(feature = "std"))] let packet = ::alloc::vec::Vec::from_raw_parts(packet_ptr, packet_len as _, packet_len as _); diff --git a/packets/connect/src/lib.rs b/packets/connect/src/lib.rs index ac63dfe..0908ab5 100644 --- a/packets/connect/src/lib.rs +++ b/packets/connect/src/lib.rs @@ -27,12 +27,10 @@ impl From for Error { } #[tq_network::packet_processor(MsgConnect)] -fn process( +pub fn process( msg: MsgConnect, actor: &Resource, ) -> Result<(), crate::Error> { - host::log(tracing::Level::DEBUG, "msgconnect", "hello?"); - assert!(tracing::dispatcher::get_default(|_| Some(())).is_some()); tracing::debug!(target: "msgconnect", ?msg, "Shutting down actor"); host::send(actor, msg)?; host::shutdown(actor); diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index 6d0fc23..13469ef 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -86,8 +86,13 @@ mod tests { async fn create_runtime() -> Runtime { let mut config = Config::new(); - config.async_support(true); - config.wasm_reference_types(true); + config + .async_support(true) + .wasm_reference_types(true) + .wasm_backtrace(true) + .wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable) + .native_unwind_info(true) + .coredump_on_trap(true); let engine = Engine::new(&config).unwrap(); let mut linker = Linker::new(&engine); @@ -117,11 +122,11 @@ mod tests { let target = String::from_utf8(target_buf).unwrap(); let message = String::from_utf8(message_buf).unwrap(); match level { - 0 => tracing::error!(%target, %message), - 1 => tracing::warn!(%target, %message), - 2 => tracing::info!(%target, %message), - 3 => tracing::debug!(%target, %message), - _ => tracing::trace!(%target, %message), + 0 => tracing::error!(target: "runtime", packet = target, %message), + 1 => tracing::warn!(target: "runtime", packet = target, %message), + 2 => tracing::info!(target: "runtime", packet = target, %message), + 3 => tracing::debug!(target: "runtime", packet = target, %message), + _ => tracing::trace!(target: "runtime", packet = target, %message), }; }) as _ }, @@ -212,6 +217,7 @@ mod tests { .add_directive(format!("tq_codec={}", log_level).parse().unwrap()) .add_directive(format!("tq_network={}", log_level).parse().unwrap()) .add_directive(format!("tq_server={}", log_level).parse().unwrap()) + .add_directive(format!("runtime={}", log_level).parse().unwrap()) .add_directive(format!("auth={}", log_level).parse().unwrap()); let logger = tracing_subscriber::fmt() .pretty() From 1fb4cbd2e405eb0c5165a4c2228f587b1698accc Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sun, 14 Jan 2024 18:48:21 +0200 Subject: [PATCH 16/28] Updates --- Cargo.lock | 2 +- crates/bindings/Cargo.toml | 4 +- crates/bindings/src/lib.rs | 10 +- crates/network/src/lib.rs | 11 +++ crates/serde/src/fixed_string.rs | 24 ++++- macros/derive-packetprocessor/src/lib.rs | 6 +- packets/connect/Cargo.toml | 6 +- packets/connect/build.rs | 3 + packets/connect/src/lib.rs | 11 +-- server/auth/src/lib.rs | 106 +++------------------ server/auth/src/linker.rs | 113 +++++++++++++++++++++++ server/auth/src/main.rs | 21 +---- 12 files changed, 184 insertions(+), 133 deletions(-) create mode 100644 packets/connect/build.rs create mode 100644 server/auth/src/linker.rs diff --git a/Cargo.lock b/Cargo.lock index fa127d9..2fc1450 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1464,11 +1464,11 @@ version = "0.1.0" dependencies = [ "bytes", "serde", + "thiserror", "tq-bindings", "tq-network", "tq-serde", "tracing", - "tracing-wasm", ] [[package]] diff --git a/crates/bindings/Cargo.toml b/crates/bindings/Cargo.toml index 15ce0b4..e0575f5 100644 --- a/crates/bindings/Cargo.toml +++ b/crates/bindings/Cargo.toml @@ -6,11 +6,11 @@ edition.workspace = true [dependencies] tq-network.workspace = true tracing-wasm.workspace = true + tracing = { workspace = true, default-features = false, optional = true } tracing-subscriber = { workspace = true, default-features = false, features = ["alloc"], optional = true } - externref = { workspace = true, default-features = false, features = ["macro"] } [features] -default = [] +default = ["std"] std = ["tq-network/std", "tracing-wasm/std", "dep:tracing", "dep:tracing-subscriber"] diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs index 5f2828c..ca4b50f 100644 --- a/crates/bindings/src/lib.rs +++ b/crates/bindings/src/lib.rs @@ -39,14 +39,14 @@ pub fn setup_logging(_name: &'static str) {} /// Sets a panic hook that logs to the host. #[cfg(feature = "std")] -pub fn set_panic_hook_once() { +pub fn set_panic_hook_once(name: &'static str) { static SET_HOOK: std::sync::Once = std::sync::Once::new(); SET_HOOK.call_once(|| { std::panic::set_hook(Box::new(|info| { let payload = info .payload() .downcast_ref::<&str>() - .map(|s| *s) + .copied() .unwrap_or_else(|| { info.payload().downcast_ref::().unwrap().as_str() }); @@ -55,15 +55,15 @@ pub fn set_panic_hook_once() { .map(|l| format!("{}:{}", l.file(), l.line())); host::log( tracing_wasm::Level::ERROR, - "panic", - &format!("{payload} {}", location.unwrap_or_default()), + name, + &format!("'{payload}' at {}", location.unwrap_or_default()), ); })); }); } #[cfg(not(feature = "std"))] -pub fn set_panic_hook_once() {} +pub fn set_panic_hook_once(_name: &'static str) {} /// Host bindings. pub mod host { diff --git a/crates/network/src/lib.rs b/crates/network/src/lib.rs index b53e3ec..4773cc3 100644 --- a/crates/network/src/lib.rs +++ b/crates/network/src/lib.rs @@ -105,6 +105,17 @@ impl PacketEncode for (u16, Bytes) { fn encode(&self) -> Result<(u16, Bytes), Self::Error> { Ok(self.clone()) } } + +impl<'a> PacketEncode for (u16, &'a [u8]) { + type Error = Error; + type Packet = (); + + fn encode(&self) -> Result<(u16, Bytes), Self::Error> { + let (id, bytes) = self; + Ok((*id, bytes.to_vec().into())) + } +} + impl PacketDecode for T where T: DeserializeOwned, diff --git a/crates/serde/src/fixed_string.rs b/crates/serde/src/fixed_string.rs index 559b45d..dfb035a 100644 --- a/crates/serde/src/fixed_string.rs +++ b/crates/serde/src/fixed_string.rs @@ -39,10 +39,32 @@ impl fmt::Display for FixedString { } } -impl fmt::Debug for FixedString { +impl fmt::Debug for FixedString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FixedString") .field("inner", &self.inner) + .field("max_len", &N) + .field("mode", &"clear_text") + .finish() + } +} + +impl fmt::Debug for FixedString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FixedString") + .field("inner", &self.inner) + .field("max_len", &N) + .field("mode", &"cipher") + .finish() + } +} + +impl fmt::Debug for FixedString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FixedString") + .field("inner", &self.inner) + .field("max_len", &N) + .field("mode", &"masked") .finish() } } diff --git a/macros/derive-packetprocessor/src/lib.rs b/macros/derive-packetprocessor/src/lib.rs index 1019602..cfe6f44 100644 --- a/macros/derive-packetprocessor/src/lib.rs +++ b/macros/derive-packetprocessor/src/lib.rs @@ -108,7 +108,7 @@ fn derive_packet_processor( packet_len: u32, actor: &::tq_bindings::Resource, ) -> i32 { - ::tq_bindings::set_panic_hook_once(); + ::tq_bindings::set_panic_hook_once(#msg_ty_name); ::tq_bindings::setup_logging(#msg_ty_name); #[cfg(not(feature = "std"))] let packet = ::alloc::vec::Vec::from_raw_parts(packet_ptr, packet_len as _, packet_len as _); @@ -118,14 +118,14 @@ fn derive_packet_processor( let packet = match <#msg_ty as ::tq_network::PacketDecode>::decode(&bytes) { Ok(packet) => packet, Err(e) => { - // TODO: use host to log the error + tracing::error!(error = ?e, "While decoding the packet"); return 0xdec0de; } }; match #inner_fn_call(packet, actor) { Ok(()) => 0, Err(e) => { - // TODO: use host to log the error + tracing::error!(error = ?e, "While handling the packet"); 0x00f } } diff --git a/packets/connect/Cargo.toml b/packets/connect/Cargo.toml index 598517c..c96dd2f 100644 --- a/packets/connect/Cargo.toml +++ b/packets/connect/Cargo.toml @@ -13,10 +13,10 @@ tq-bindings.workspace = true serde.workspace = true bytes.workspace = true +thiserror.workspace = true tracing.workspace = true -tracing-wasm.workspace = true [features] -default = [] -std = ["tq-serde/std", "tq-network/std", "tq-bindings/std", "tracing-wasm/std"] +default = ["std"] +std = ["tq-serde/std", "tq-network/std", "tq-bindings/std"] diff --git a/packets/connect/build.rs b/packets/connect/build.rs new file mode 100644 index 0000000..fdae23b --- /dev/null +++ b/packets/connect/build.rs @@ -0,0 +1,3 @@ +type Error = Box; + +fn main() -> Result<(), Error> { return Ok(()); } diff --git a/packets/connect/src/lib.rs b/packets/connect/src/lib.rs index 0908ab5..f366b21 100644 --- a/packets/connect/src/lib.rs +++ b/packets/connect/src/lib.rs @@ -18,12 +18,10 @@ pub struct MsgConnect { pub file_name: String16, } +#[derive(Debug, thiserror::Error)] pub enum Error { - Network(tq_network::Error), -} - -impl From for Error { - fn from(v: tq_network::Error) -> Self { Self::Network(v) } + #[error(transparent)] + Network(#[from] tq_network::Error), } #[tq_network::packet_processor(MsgConnect)] @@ -31,8 +29,7 @@ pub fn process( msg: MsgConnect, actor: &Resource, ) -> Result<(), crate::Error> { - tracing::debug!(target: "msgconnect", ?msg, "Shutting down actor"); - host::send(actor, msg)?; + tracing::debug!(?msg, "Shutting down actor"); host::shutdown(actor); Ok(()) } diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index 13469ef..29309a7 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -1,6 +1,7 @@ //! Auth Server pub mod error; +pub mod linker; pub mod state; use bytes::Bytes; @@ -75,11 +76,20 @@ impl PacketHandler for Runtime { } } +/// Add the runtime to the linker. +pub fn add_to_linker( + linker: &mut Linker, +) -> Result<(), error::Error> { + linker::actor::shutdown(linker)?; + linker::actor::send(linker)?; + linker::log::trace_event(linker)?; + Ok(()) +} + #[cfg(test)] mod tests { - use bytes::BytesMut; use msg_connect::MsgConnect; - use tq_network::{ActorHandle, Message, PacketEncode}; + use tq_network::{Message, PacketEncode}; use wasmtime::Config; use super::*; @@ -96,93 +106,7 @@ mod tests { let engine = Engine::new(&config).unwrap(); let mut linker = Linker::new(&engine); - linker - .func_wrap5_async::( - "host", - "trace_event", - |mut caller, - level, - target, - target_len, - message, - message_len| { - Box::new(async move { - let memory = caller - .get_export("memory") - .and_then(|e| e.into_memory()) - .expect("Failed to get memory"); - let mut target_buf = vec![0; target_len as usize]; - let mut message_buf = vec![0; message_len as usize]; - memory - .read(&caller, target as usize, &mut target_buf) - .expect("Failed to read target from memory"); - memory - .read(&caller, message as usize, &mut message_buf) - .expect("Failed to read message from memory"); - let target = String::from_utf8(target_buf).unwrap(); - let message = String::from_utf8(message_buf).unwrap(); - match level { - 0 => tracing::error!(target: "runtime", packet = target, %message), - 1 => tracing::warn!(target: "runtime", packet = target, %message), - 2 => tracing::info!(target: "runtime", packet = target, %message), - 3 => tracing::debug!(target: "runtime", packet = target, %message), - _ => tracing::trace!(target: "runtime", packet = target, %message), - }; - }) as _ - }, - ) - .unwrap() - .func_wrap1_async::, ()>( - "host", - "shutdown", - |_caller, actor_ref| { - Box::new(async move { - let actor_ref = actor_ref.unwrap(); - let actor = actor_ref - .data() - .downcast_ref::() - .unwrap(); - let _ = actor.shutdown().await; - }) as _ - }, - ) - .unwrap() - .func_wrap4_async::, i32, i32, i32, ()>( - "host", - "send", - |mut caller, - actor_ref, - packet_id, - packet_data_ptr, - packet_data_len| { - Box::new(async move { - let actor_ref = actor_ref.unwrap(); - let actor = actor_ref - .data() - .downcast_ref::() - .unwrap(); - let memory = caller - .get_export("memory") - .and_then(|e| e.into_memory()) - .expect("Failed to get memory"); - let mut packet_data = - BytesMut::with_capacity(packet_data_len as usize); - packet_data.resize(packet_data_len as usize, 0); - memory - .read( - caller, - packet_data_ptr as usize, - &mut packet_data, - ) - .expect("Failed to read packet from memory"); - let _ = actor - .send((packet_id as u16, packet_data.freeze())) - .await; - }) as _ - }, - ) - .unwrap(); - + add_to_linker(&mut linker).unwrap(); let msg_connect = Module::from_file( &engine, "../../target/wasm32-unknown-unknown/wasm/msg_connect.s.wasm", @@ -244,10 +168,6 @@ mod tests { Runtime::handle(encoded.clone(), &runtime, &actor) .await .unwrap(); - - let msg = rx.recv().await.unwrap(); - assert_eq!(msg, Message::Packet(encoded.0, encoded.1)); - let msg = rx.recv().await.unwrap(); assert_eq!(msg, Message::Shutdown); } diff --git a/server/auth/src/linker.rs b/server/auth/src/linker.rs new file mode 100644 index 0000000..322c213 --- /dev/null +++ b/server/auth/src/linker.rs @@ -0,0 +1,113 @@ +use wasmtime::Linker; + +const MODULE: &str = "host"; + +/// Read a slice of bytes from wasm memory. +macro_rules! memof { + ($caller:expr) => { + $caller + .get_export("memory") + .and_then(::wasmtime::Extern::into_memory) + .expect("failed to read wasm memory") + }; +} + +macro_rules! mread { + ($caller:expr, $mem:expr, $ptr:expr, $size:expr) => {{ + $mem.data(&$caller) + .get($ptr as usize..) + .and_then(|s| s.get(..$size as usize)) + .expect("failed to read wasm memory") + }}; +} + +pub mod actor { + use super::*; + use wasmtime::ExternRef; + + pub fn shutdown( + linker: &mut Linker, + ) -> Result<(), crate::error::Error> { + const NAME: &str = "shutdown"; + + linker.func_wrap1_async::, ()>( + MODULE, + NAME, + |_caller, actor_ref| { + Box::new(async move { + let actor_ref = actor_ref.expect("actor ref not null"); + let actor = actor_ref + .data() + .downcast_ref::() + .expect("actor ref is valid"); + let _ = actor.shutdown().await; + }) as _ + }, + )?; + Ok(()) + } + + pub fn send( + linker: &mut Linker, + ) -> Result<(), crate::error::Error> { + const NAME: &str = "send"; + linker.func_wrap4_async::, i32, i32, i32, ()>( + MODULE, + NAME, + |mut caller, + actor_ref, + packet_id, + packet_data_ptr, + packet_data_len| { + Box::new(async move { + let actor_ref = actor_ref.expect("actor ref not null"); + let actor = actor_ref + .data() + .downcast_ref::() + .expect("actor ref is valid"); + let mem = memof!(caller); + let packet_data = + mread!(caller, mem, packet_data_ptr, packet_data_len); + let _ = actor.send((packet_id as u16, packet_data)).await; + }) as _ + }, + )?; + Ok(()) + } +} +pub mod log { + use super::*; + + pub fn trace_event( + linker: &mut Linker, + ) -> Result<(), crate::error::Error> { + const NAME: &str = "trace_event"; + linker + .func_wrap5_async::( + MODULE, + NAME, + |mut caller, + level, + target, + target_len, + message, + message_len| { + Box::new(async move { + let mem = memof!(caller); + let target_slice = mread!(caller, mem, target, target_len); + let target = std::str::from_utf8(target_slice).expect("valid utf8"); + let message_slice = mread!(caller, mem, message, message_len); + let message = std::str::from_utf8(message_slice).expect("valid utf8"); + match level { + 0 => tracing::error!(target: "runtime", packet = target, %message), + 1 => tracing::warn!(target: "runtime", packet = target, %message), + 2 => tracing::info!(target: "runtime", packet = target, %message), + 3 => tracing::debug!(target: "runtime", packet = target, %message), + _ => tracing::trace!(target: "runtime", packet = target, %message), + }; + }) as _ + }, + )?; + Ok(()) + } +} diff --git a/server/auth/src/main.rs b/server/auth/src/main.rs index fa2fa09..fbeacde 100644 --- a/server/auth/src/main.rs +++ b/server/auth/src/main.rs @@ -46,32 +46,17 @@ Copyright 2020-2023 Shady Khalifa (@shekohex) All Rights Reserved. "# ); - // Configure an `Engine` and compile the `Component` that is being run for - // the application. let mut config = Config::new(); - config.async_support(true); - config.wasm_reference_types(true); + config.async_support(true).wasm_reference_types(true); let engine = Engine::new(&config)?; let mut linker = Linker::new(&engine); - linker.func_wrap1_async::, ()>( - "host", - "shutdown", - |caller, actor_ref| { - Box::new(async move { - let actor_ref = actor_ref.unwrap(); - let actor = - actor_ref.data().downcast_ref::().unwrap(); - let _ = actor.shutdown().await; - }) as _ - }, - )?; - + auth::add_to_linker(&mut linker)?; tracing::info!("Loading Packet and handlers.."); let msg_connect = Module::from_file( &engine, - "./target/wasm32-unknown-unknown/debug/msg_connect.wasm", + "./target/wasm32-unknown-unknown/wasm/msg_connect.s.wasm", )?; tracing::info!("Initializing State .."); let state = State::init().await?; From 539eff3bd99e26dc241a45ff3b72c0e6eadda3fd Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sun, 14 Jan 2024 20:08:29 +0200 Subject: [PATCH 17/28] add wasm builder --- Cargo.lock | 358 +++++++- Cargo.toml | 21 +- crates/network/src/lib.rs | 1 - crates/wasm-builder/Cargo.toml | 16 + crates/wasm-builder/src/builder.rs | 275 ++++++ crates/wasm-builder/src/lib.rs | 394 ++++++++ crates/wasm-builder/src/prerequisites.rs | 151 +++ crates/wasm-builder/src/version.rs | 221 +++++ crates/wasm-builder/src/wasm_project.rs | 1074 ++++++++++++++++++++++ packets/connect/.cargo/config.toml | 2 - packets/connect/Cargo.toml | 6 +- packets/connect/build.rs | 9 +- packets/connect/src/lib.rs | 4 +- server/auth/src/lib.rs | 8 +- 14 files changed, 2509 insertions(+), 31 deletions(-) create mode 100644 crates/wasm-builder/Cargo.toml create mode 100644 crates/wasm-builder/src/builder.rs create mode 100644 crates/wasm-builder/src/lib.rs create mode 100644 crates/wasm-builder/src/prerequisites.rs create mode 100644 crates/wasm-builder/src/version.rs create mode 100644 crates/wasm-builder/src/wasm_project.rs delete mode 100644 packets/connect/.cargo/config.toml diff --git a/Cargo.lock b/Cargo.lock index 2fc1450..fc7cd5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -313,6 +313,15 @@ dependencies = [ "cipher", ] +[[package]] +name = "build-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdce191bf3fa4995ce948c8c83b4640a1745457a149e73c6db75b4ffe36aad5f" +dependencies = [ + "semver 0.6.0", +] + [[package]] name = "bumpalo" version = "3.14.0" @@ -351,6 +360,38 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.20", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cc" version = "1.0.83" @@ -386,6 +427,29 @@ dependencies = [ "inout", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + [[package]] name = "console-api" version = "0.6.0" @@ -632,6 +696,50 @@ dependencies = [ "memchr", ] +[[package]] +name = "cxx" +version = "1.0.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ab30434ea0ff6aa640a08dda5284026a366d47565496fd40b6cbfbdd7e31a2" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b649d7dfae8268450d53d109388b337b9352c7cba1fc10db4a1bc23c3dc189fb" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.43", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42281b20eba5218c539295c667c18e2f50211bb11902419194c6ed1ae808e547" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45506e3c66512b0a65d291a6b452128b7b1dd9841e20d1e151addbd2c00ea50" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.43", +] + [[package]] name = "der" version = "0.7.8" @@ -725,6 +833,12 @@ dependencies = [ "serde", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "equivalent" version = "1.0.1" @@ -799,6 +913,18 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.52.0", +] + [[package]] name = "finl_unicode" version = "1.2.0" @@ -1346,6 +1472,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "link-cplusplus" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" +dependencies = [ + "cc", +] + [[package]] name = "linux-raw-sys" version = "0.4.12" @@ -1468,6 +1603,7 @@ dependencies = [ "tq-bindings", "tq-network", "tq-serde", + "tq-wasm-builder", "tracing", ] @@ -2000,12 +2136,27 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scratch" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" + [[package]] name = "sct" version = "0.7.1" @@ -2016,11 +2167,29 @@ dependencies = [ "untrusted", ] +[[package]] +name = "semver" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" @@ -2053,6 +2222,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "sha1" version = "0.10.6" @@ -2397,6 +2575,47 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros 0.25.3", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.43", +] + [[package]] name = "subtle" version = "2.5.0" @@ -2450,6 +2669,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.51" @@ -2599,6 +2827,40 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tonic" version = "0.10.2" @@ -2753,6 +3015,22 @@ dependencies = [ "tracing", ] +[[package]] +name = "tq-wasm-builder" +version = "0.1.0" +dependencies = [ + "build-helper", + "cargo_metadata", + "console", + "externref", + "filetime", + "strum 0.25.0", + "tempfile", + "toml 0.8.8", + "walkdir", + "wasm-opt", +] + [[package]] name = "tracing" version = "0.1.40" @@ -2863,6 +3141,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + [[package]] name = "unicode-xid" version = "0.2.4" @@ -2916,6 +3200,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "walrus" version = "0.19.0" @@ -2966,6 +3260,46 @@ dependencies = [ "leb128", ] +[[package]] +name = "wasm-opt" +version = "0.116.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc942673e7684671f0c5708fc18993569d184265fd5223bb51fc8e5b9b6cfd52" +dependencies = [ + "anyhow", + "libc", + "strum 0.24.1", + "strum_macros 0.24.3", + "tempfile", + "thiserror", + "wasm-opt-cxx-sys", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-cxx-sys" +version = "0.116.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c57b28207aa724318fcec6575fe74803c23f6f266fce10cbc9f3f116762f12e" +dependencies = [ + "anyhow", + "cxx", + "cxx-build", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-sys" +version = "0.116.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a1cce564dc768dacbdb718fc29df2dba80bd21cb47d8f77ae7e3d95ceb98cbe" +dependencies = [ + "anyhow", + "cc", + "cxx", + "cxx-build", +] + [[package]] name = "wasmparser" version = "0.77.1" @@ -2979,7 +3313,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9" dependencies = [ "indexmap 2.1.0", - "semver", + "semver 1.0.20", ] [[package]] @@ -3039,7 +3373,7 @@ dependencies = [ "serde", "serde_derive", "sha2", - "toml", + "toml 0.5.11", "windows-sys 0.48.0", "zstd", ] @@ -3272,6 +3606,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -3410,6 +3753,15 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "winnow" +version = "0.5.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +dependencies = [ + "memchr", +] + [[package]] name = "wit-parser" version = "0.13.0" @@ -3420,7 +3772,7 @@ dependencies = [ "id-arena", "indexmap 2.1.0", "log", - "semver", + "semver 1.0.20", "serde", "serde_derive", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 338ad4c..c5197be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,10 @@ +[workspace.package] +authors = ["Shady Khalifa "] +edition = "2021" +repository = "https://github.com/shekohex/coemu.git" +license = "GPL-3.0-only" + [workspace] -package.edition = "2021" resolver = "2" members = [ "crates/*", @@ -30,6 +35,7 @@ tq-codec = { path = "crates/codec" } tq-db = { path = "crates/db" } tq-server = { path = "crates/server" } tq-bindings = { path = "crates/bindings" } +tq-wasm-builder = { path = "crates/wasm-builder" } tracing-wasm = { path = "crates/tracing-wasm" } derive-packetid = { path = "macros/derive-packetid" } @@ -86,16 +92,3 @@ version = "0.7.3" [profile.dev] split-debuginfo = 'packed' -[profile.wasmdebug] -inherits = "dev" -panic = "abort" -codegen-units = 1 -opt-level = "z" # Optimize for size, rather than speed -lto = true - -[profile.wasm] -inherits = "release" -panic = "abort" -codegen-units = 1 -opt-level = "z" # Optimize for size, rather than speed -lto = true diff --git a/crates/network/src/lib.rs b/crates/network/src/lib.rs index 4773cc3..dcebeeb 100644 --- a/crates/network/src/lib.rs +++ b/crates/network/src/lib.rs @@ -105,7 +105,6 @@ impl PacketEncode for (u16, Bytes) { fn encode(&self) -> Result<(u16, Bytes), Self::Error> { Ok(self.clone()) } } - impl<'a> PacketEncode for (u16, &'a [u8]) { type Error = Error; type Packet = (); diff --git a/crates/wasm-builder/Cargo.toml b/crates/wasm-builder/Cargo.toml new file mode 100644 index 0000000..ab9eecc --- /dev/null +++ b/crates/wasm-builder/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "tq-wasm-builder" +version = "0.1.0" +edition.workspace = true + +[dependencies] +build-helper = "0.1" +cargo_metadata = "0.18" +console = "0.15" +strum = { version = "0.25", features = ["derive"] } +tempfile = "3.1" +toml = "0.8" +walkdir = "2.3" +filetime = "0.2" +wasm-opt = "0.116" +externref = { workspace = true, features = ["processor"] } diff --git a/crates/wasm-builder/src/builder.rs b/crates/wasm-builder/src/builder.rs new file mode 100644 index 0000000..8413a65 --- /dev/null +++ b/crates/wasm-builder/src/builder.rs @@ -0,0 +1,275 @@ +use std::path::{Path, PathBuf}; +use std::{env, process}; + +/// Returns the manifest dir from the `CARGO_MANIFEST_DIR` env. +fn get_manifest_dir() -> PathBuf { + env::var("CARGO_MANIFEST_DIR") + .expect("`CARGO_MANIFEST_DIR` is always set for `build.rs` files; qed") + .into() +} + +/// First step of the [`WasmBuilder`] to select the project to build. +pub struct WasmBuilderSelectProject { + /// This parameter just exists to make it impossible to construct + /// this type outside of this crate. + _ignore: (), +} + +impl WasmBuilderSelectProject { + /// Use the current project as project for building the WASM binary. + /// + /// # Panics + /// + /// Panics if the `CARGO_MANIFEST_DIR` variable is not set. This variable + /// is always set by `Cargo` in `build.rs` files. + pub fn with_current_project(self) -> WasmBuilder { + WasmBuilder { + rust_flags: Vec::new(), + file_name: None, + project_cargo_toml: get_manifest_dir().join("Cargo.toml"), + features_to_enable: Vec::new(), + } + } + + /// Use the given `path` as project for building the WASM binary. + /// + /// Returns an error if the given `path` does not points to a `Cargo.toml`. + pub fn with_project( + self, + path: impl Into, + ) -> Result { + let path = path.into(); + + if path.ends_with("Cargo.toml") && path.exists() { + Ok(WasmBuilder { + rust_flags: Vec::new(), + file_name: None, + project_cargo_toml: path, + features_to_enable: Vec::new(), + }) + } else { + Err("Project path must point to the `Cargo.toml` of the project") + } + } +} + +/// The builder for building a wasm binary. +/// +/// The builder itself is separated into multiple structs to make the setup type +/// safe. +/// +/// Building a wasm binary: +/// +/// 1. Call [`WasmBuilder::selector`] to create a new builder. +/// 2. Select the project to build using the methods of +/// [`WasmBuilderSelectProject`]. +/// 3. Set additional `RUST_FLAGS` or a different name for the file containing +/// the WASM code using methods of [`WasmBuilder`]. +/// 4. Build the WASM binary using [`Self::build`]. +pub struct WasmBuilder { + /// Flags that should be appended to `RUST_FLAGS` env variable. + rust_flags: Vec, + /// The name of the file that is being generated in `OUT_DIR`. + /// + /// Defaults to `wasm.rs`. + file_name: Option, + /// The path to the `Cargo.toml` of the project that should be built + /// for wasm. + project_cargo_toml: PathBuf, + /// Features that should be enabled when building the wasm binary. + features_to_enable: Vec, +} + +impl WasmBuilder { + /// Create a new instance of the builder. + pub fn selector() -> WasmBuilderSelectProject { + WasmBuilderSelectProject { _ignore: () } + } + + /// Enable exporting `__heap_base` as global variable in the WASM binary. + /// + /// This adds `-Clink-arg=--export=__heap_base` to `RUST_FLAGS`. + pub fn export_heap_base(mut self) -> Self { + self.rust_flags + .push("-Clink-arg=--export=__heap_base".into()); + self + } + + /// Set the name of the file that will be generated in `OUT_DIR`. + /// + /// This file needs to be included to get access to the build WASM binary. + /// + /// If this function is not called, `file_name` defaults to `wasm.rs` + pub fn set_file_name(mut self, file_name: impl Into) -> Self { + self.file_name = Some(file_name.into()); + self + } + + /// Instruct the linker to import the memory into the WASM binary. + /// + /// This adds `-C link-arg=--import-memory` to `RUST_FLAGS`. + pub fn import_memory(mut self) -> Self { + self.rust_flags.push("-C link-arg=--import-memory".into()); + self + } + + /// Append the given `flag` to `RUST_FLAGS`. + /// + /// `flag` is appended as is, so it needs to be a valid flag. + pub fn append_to_rust_flags(mut self, flag: impl Into) -> Self { + self.rust_flags.push(flag.into()); + self + } + + /// Enable the given feature when building the wasm binary. + /// + /// `feature` needs to be a valid feature that is defined in the project + /// `Cargo.toml`. + pub fn enable_feature(mut self, feature: impl Into) -> Self { + self.features_to_enable.push(feature.into()); + self + } + + /// Build the WASM binary. + pub fn build(self) { + let out_dir = PathBuf::from( + env::var("OUT_DIR").expect("`OUT_DIR` is set by cargo!"), + ); + let file_path = out_dir + .join(self.file_name.clone().unwrap_or_else(|| "wasm.rs".into())); + + if check_skip_build() { + // If we skip the build, we still want to make sure to be called + // when an env variable changes + generate_rerun_if_changed_instructions(); + + provide_dummy_wasm_binary_if_not_exist(&file_path); + + return; + } + + build_project( + file_path, + self.project_cargo_toml, + self.rust_flags + .into_iter() + .map(|f| format!("{} ", f)) + .collect(), + self.features_to_enable, + self.file_name, + ); + + // As last step we need to generate our `rerun-if-changed` stuff. If a + // build fails, we don't want to spam the output! + generate_rerun_if_changed_instructions(); + } +} + +/// Generate the name of the skip build environment variable for the current +/// crate. +fn generate_crate_skip_build_env_name() -> String { + format!( + "SKIP_{}_WASM_BUILD", + env::var("CARGO_PKG_NAME") + .expect("Package name is set") + .to_uppercase() + .replace('-', "_"), + ) +} + +/// Checks if the build of the WASM binary should be skipped. +fn check_skip_build() -> bool { + env::var(crate::SKIP_BUILD_ENV).is_ok() || + env::var(generate_crate_skip_build_env_name()).is_ok() || + // If we are running in docs.rs, let's skip building. + // https://docs.rs/about/builds#detecting-docsrs + env::var("DOCS_RS").is_ok() +} + +/// Provide a dummy WASM binary if there doesn't exist one. +fn provide_dummy_wasm_binary_if_not_exist(file_path: &Path) { + if !file_path.exists() { + crate::write_file_if_changed( + file_path, + "pub const WASM_BINARY: Option<&'static str> = None;\ + pub const WASM_BINARY_BLOATY: Option<&'static str> = None;", + ); + } +} + +/// Generate the `rerun-if-changed` instructions for cargo to make sure that the +/// WASM binary is rebuilt when needed. +fn generate_rerun_if_changed_instructions() { + // Make sure that the `build.rs` is called again if one of the following env + // variables changes. + println!("cargo:rerun-if-env-changed={}", crate::SKIP_BUILD_ENV); + println!("cargo:rerun-if-env-changed={}", crate::FORCE_WASM_BUILD_ENV); + println!( + "cargo:rerun-if-env-changed={}", + generate_crate_skip_build_env_name() + ); +} + +/// Build the currently built project as wasm binary. +/// +/// The current project is determined by using the `CARGO_MANIFEST_DIR` +/// environment variable. +/// +/// `file_name` - The name + path of the file being generated. The file contains +/// the constant `WASM_BINARY`, which contains the built wasm binary. +/// +/// `project_cargo_toml` - The path to the `Cargo.toml` of the project that +/// should be built. +/// +/// `default_rustflags` - Default `RUSTFLAGS` that will always be set for the +/// build. +/// +/// `features_to_enable` - Features that should be enabled for the project. +/// +/// `wasm_binary_name` - The optional wasm binary name that is extended with +/// `.compact.compressed.wasm`. If `None`, the project name will be used. +fn build_project( + file_name: PathBuf, + project_cargo_toml: PathBuf, + default_rustflags: String, + features_to_enable: Vec, + wasm_binary_name: Option, +) { + let cargo_cmd = match crate::prerequisites::check() { + Ok(cmd) => cmd, + Err(err_msg) => { + eprintln!("{}", err_msg); + process::exit(1); + }, + }; + + let (wasm_binary, bloaty) = crate::wasm_project::create_and_compile( + &project_cargo_toml, + &default_rustflags, + cargo_cmd, + features_to_enable, + wasm_binary_name, + ); + + let (wasm_binary, wasm_binary_bloaty) = + if let Some(wasm_binary) = wasm_binary { + ( + wasm_binary.wasm_binary_path_escaped(), + bloaty.bloaty_path_escaped(), + ) + } else { + (bloaty.bloaty_path_escaped(), bloaty.bloaty_path_escaped()) + }; + + crate::write_file_if_changed( + file_name, + format!( + r#" + pub const WASM_BINARY: Option<&'static str> = Some("{wasm_binary}"); + pub const WASM_BINARY_BLOATY: Option<&'static str> = Some("{wasm_binary_bloaty}"); + "#, + wasm_binary = wasm_binary, + wasm_binary_bloaty = wasm_binary_bloaty, + ), + ); +} diff --git a/crates/wasm-builder/src/lib.rs b/crates/wasm-builder/src/lib.rs new file mode 100644 index 0000000..48fb1a0 --- /dev/null +++ b/crates/wasm-builder/src/lib.rs @@ -0,0 +1,394 @@ +#![allow(clippy::needless_doctest_main)] +//! # Wasm builder is a utility for building a project as a Wasm binary +//! +//! The Wasm builder is a tool that integrates the process of building the WASM +//! binary of your project into the main `cargo` build process. +//! +//! ## Project setup +//! +//! A project that should be compiled as a Wasm binary needs to: +//! +//! 1. Add a `build.rs` file. +//! 2. Add `wasm-builder` as dependency into `build-dependencies`. +//! +//! The `build.rs` file needs to contain the following code: +//! +//! ```no_run +//! use tq_wasm_builder::WasmBuilder; +//! +//! fn main() { +//! WasmBuilder::selector() +//! // Tell the builder to build the project (crate) this `build.rs` is part of. +//! .with_current_project() +//! .enable_features("std") +//! // Build it. +//! .build() +//! } +//! ``` +//! +//! As the final step, you need to add the following to your project: +//! +//! ```ignore +//! include!(concat!(env!("OUT_DIR"), "/wasm.rs")); +//! ``` +//! +//! This will include the generated Wasm binary path as two static variables +//! `WASM_BINARY` and `WASM_BINARY_BLOATY`. The former is a compact Wasm binary +//! and the latter is the Wasm binary as being generated by the compiler. Both +//! variables have `Option<&'static str>` as type. +//! +//! ### Feature +//! +//! Wasm builder supports to enable cargo features while building the Wasm +//! binary. By default it will enable all features in the wasm build that are +//! enabled for the native build. Besides that, wasm builder supports the +//! special `runtime-wasm` feature. This `runtime-wasm` feature will be enabled +//! by the wasm builder when it compiles the Wasm binary. If this feature is not +//! present, it will not be enabled. +//! +//! ## Environment variables +//! +//! By using environment variables, you can configure which Wasm binaries are +//! built and how: +//! +//! - `SKIP_WASM_BUILD` - Skips building any Wasm binary. This is useful when +//! only native should be recompiled. If this is the first run and there +//! doesn't exist a Wasm binary, this will set both variables to `None`. +//! - `WASM_BUILD_TYPE` - Sets the build type for building Wasm binaries. +//! Supported values are `wasm` or `wasmdebug`. By default the build type is +//! equal to the build type used by the main build. +//! - `FORCE_WASM_BUILD` - Can be set to force a Wasm build. On subsequent calls +//! the value of the variable needs to change. As wasm-builder instructs +//! `cargo` to watch for file changes this environment variable should only be +//! required in certain circumstances. +//! - `WASM_BUILD_RUSTFLAGS` - Extend `RUSTFLAGS` given to `cargo build` while +//! building the wasm binary. +//! - `WASM_BUILD_NO_COLOR` - Disable color output of the wasm build. +//! - `WASM_TARGET_DIRECTORY` - Will copy any build Wasm binary to the given +//! directory. The path needs to be absolute. +//! - `WASM_BUILD_TOOLCHAIN` - The toolchain that should be used to build the +//! Wasm binaries. The format needs to be the same as used by cargo, e.g. +//! `nightly-2020-02-20`. +//! - `WASM_BUILD_WORKSPACE_HINT` - Hint the workspace that is being built. This +//! is normally not required as we walk up from the target directory until we +//! find a `Cargo.toml`. If the target directory is changed for the build, +//! this environment variable can be used to point to the actual workspace. +//! - `WASM_BUILD_STD` - Sets whether the Rust's standard library crates will +//! also be built. This is necessary to make sure the standard library crates +//! only use the exact WASM feature set that our executor supports. Enabled by +//! default. +//! - `CARGO_NET_OFFLINE` - If `true`, `--offline` will be passed to all +//! processes launched to prevent network access. Useful in offline +//! environments. +//! +//! Each project can be skipped individually by using the environment variable +//! `SKIP_PROJECT_NAME_WASM_BUILD`. Where `PROJECT_NAME` needs to be replaced by +//! the name of the cargo project, e.g. `kitchensink-runtime` will be +//! `NODE_RUNTIME`. +//! +//! ## Prerequisites: +//! +//! Wasm builder requires the following prerequisites for building the Wasm +//! binary: +//! +//! - rust nightly + `wasm32-unknown-unknown` toolchain +//! +//! or +//! +//! - rust stable and version at least 1.68.0 + `wasm32-unknown-unknown` +//! toolchain +//! +//! If a specific rust is installed with `rustup`, it is important that the wasm +//! target is installed as well. For example if installing the rust from +//! 20.02.2020 using `rustup install nightly-2020-02-20`, the wasm target needs +//! to be installed as well `rustup target add wasm32-unknown-unknown +//! --toolchain nightly-2020-02-20`. + +use std::io::BufRead; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::{env, fs}; +use version::Version; + +mod builder; +mod prerequisites; +mod version; +mod wasm_project; + +pub use builder::{WasmBuilder, WasmBuilderSelectProject}; + +/// Environment variable that tells us to skip building the wasm binary. +const SKIP_BUILD_ENV: &str = "SKIP_WASM_BUILD"; + +/// Environment variable that tells us whether we should avoid network requests +const OFFLINE: &str = "CARGO_NET_OFFLINE"; + +/// Environment variable to force a certain build type when building the wasm +/// binary. Expects "debug", "release" or "production" as value. +/// +/// When unset the WASM binary uses the same build type as the main cargo build +/// with the exception of a debug build: In this case the wasm build defaults to +/// `release` in order to avoid a slowdown when not explicitly requested. +const WASM_BUILD_TYPE_ENV: &str = "WASM_BUILD_TYPE"; + +/// Environment variable to extend the `RUSTFLAGS` variable given to the wasm +/// build. +const WASM_BUILD_RUSTFLAGS_ENV: &str = "WASM_BUILD_RUSTFLAGS"; + +/// Environment variable to set the target directory to copy the final wasm +/// binary. +/// +/// The directory needs to be an absolute path. +const WASM_TARGET_DIRECTORY: &str = "WASM_TARGET_DIRECTORY"; + +/// Environment variable to disable color output of the wasm build. +const WASM_BUILD_NO_COLOR: &str = "WASM_BUILD_NO_COLOR"; + +/// Environment variable to set the toolchain used to compile the wasm binary. +const WASM_BUILD_TOOLCHAIN: &str = "WASM_BUILD_TOOLCHAIN"; + +/// Environment variable that makes sure the WASM build is triggered. +const FORCE_WASM_BUILD_ENV: &str = "FORCE_WASM_BUILD"; + +/// Environment variable that hints the workspace we are building. +const WASM_BUILD_WORKSPACE_HINT: &str = "WASM_BUILD_WORKSPACE_HINT"; + +/// Environment variable to set whether we'll build `core`/`std`. +const WASM_BUILD_STD: &str = "WASM_BUILD_STD"; + +/// Write to the given `file` if the `content` is different. +fn write_file_if_changed(file: impl AsRef, content: impl AsRef) { + if fs::read_to_string(file.as_ref()).ok().as_deref() + != Some(content.as_ref()) + { + fs::write(file.as_ref(), content.as_ref()).unwrap_or_else(|_| { + panic!("Writing `{}` can not fail!", file.as_ref().display()) + }); + } +} + +/// Copy `src` to `dst` if the `dst` does not exist or is different. +fn copy_file_if_changed(src: PathBuf, dst: PathBuf) { + let src_file = fs::read_to_string(&src).ok(); + let dst_file = fs::read_to_string(&dst).ok(); + + if src_file != dst_file { + fs::copy(&src, &dst).unwrap_or_else(|_| { + panic!( + "Copying `{}` to `{}` can not fail; qed", + src.display(), + dst.display() + ) + }); + } +} + +/// Get a cargo command that should be used to invoke the compilation. +fn get_cargo_command() -> CargoCommand { + let env_cargo = CargoCommand::new( + &env::var("CARGO") + .expect("`CARGO` env variable is always set by cargo"), + ); + let default_cargo = CargoCommand::new("cargo"); + let wasm_toolchain = env::var(WASM_BUILD_TOOLCHAIN).ok(); + + // First check if the user requested a specific toolchain + if let Some(cmd) = wasm_toolchain + .map(|t| CargoCommand::new_with_args("rustup", &["run", &t, "cargo"])) + { + cmd + } else if env_cargo.supports_substrate_wasm_env() { + env_cargo + } else if default_cargo.supports_substrate_wasm_env() { + default_cargo + } else { + // If no command before provided us with a cargo that supports our + // Substrate wasm env, we try to search one with rustup. If that + // fails as well, we return the default cargo and let + // the prequisities check fail. + get_rustup_command().unwrap_or(default_cargo) + } +} + +/// Get the newest rustup command that supports our Substrate wasm env. +/// +/// Stable versions are always favored over nightly versions even if the nightly +/// versions are newer. +fn get_rustup_command() -> Option { + let host = format!( + "-{}", + env::var("HOST").expect("`HOST` is always set by cargo") + ); + + let output = Command::new("rustup") + .args(["toolchain", "list"]) + .output() + .ok()? + .stdout; + let lines = output.as_slice().lines(); + + let mut versions = Vec::new(); + for line in lines.map_while(Result::ok) { + let rustup_version = line.trim_end_matches(&host); + + let cmd = CargoCommand::new_with_args( + "rustup", + &["run", rustup_version, "cargo"], + ); + + if !cmd.supports_substrate_wasm_env() { + continue; + } + + let Some(cargo_version) = cmd.version() else { + continue; + }; + + versions.push((cargo_version, rustup_version.to_string())); + } + + // Sort by the parsed version to get the latest version (greatest version) + // at the end of the vec. + versions.sort_by_key(|v| v.0); + let version = &versions.last()?.1; + + Some(CargoCommand::new_with_args( + "rustup", + &["run", version, "cargo"], + )) +} + +/// Wraps a specific command which represents a cargo invocation. +#[derive(Debug)] +struct CargoCommand { + program: String, + args: Vec, + version: Option, +} + +impl CargoCommand { + fn new(program: &str) -> Self { + let version = Self::extract_version(program, &[]); + + CargoCommand { + program: program.into(), + args: Vec::new(), + version, + } + } + + fn new_with_args(program: &str, args: &[&str]) -> Self { + let version = Self::extract_version(program, args); + + CargoCommand { + program: program.into(), + args: args.iter().map(ToString::to_string).collect(), + version, + } + } + + fn command(&self) -> Command { + let mut cmd = Command::new(&self.program); + cmd.args(&self.args); + cmd + } + + fn extract_version(program: &str, args: &[&str]) -> Option { + let version = Command::new(program) + .args(args) + .arg("--version") + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok())?; + + Version::extract(&version) + } + + /// Returns the version of this cargo command or `None` if it failed to + /// extract the version. + fn version(&self) -> Option { self.version } + + /// Returns whether this version of the toolchain supports nightly features. + fn supports_nightly_features(&self) -> bool { + self.version.map_or(false, |version| version.is_nightly) + || env::var("RUSTC_BOOTSTRAP").is_ok() + } + + /// Check if the supplied cargo command supports our Substrate wasm + /// environment. + /// + /// This means that either the cargo version is at minimum 1.68.0 or this is + /// a nightly cargo. + /// + /// Assumes that cargo version matches the rustc version. + fn supports_substrate_wasm_env(&self) -> bool { + // `RUSTC_BOOTSTRAP` tells a stable compiler to behave like a nightly. + // So, when this env variable is set, we can assume that + // whatever rust compiler we have, it is a nightly compiler. For + // "more" information, see: https://github.com/rust-lang/rust/blob/fa0f7d0080d8e7e9eb20aa9cbf8013f96c81287f/src/libsyntax/feature_gate/check.rs#L891 + if env::var("RUSTC_BOOTSTRAP").is_ok() { + return true; + } + + let Some(version) = self.version() else { + return false; + }; + + // Check if major and minor are greater or equal than 1.68 or this is a + // nightly. + version.major > 1 + || (version.major == 1 && version.minor >= 68) + || version.is_nightly + } +} + +/// Wraps a [`CargoCommand`] and the version of `rustc` the cargo command uses. +struct CargoCommandVersioned { + command: CargoCommand, + version: String, +} + +impl CargoCommandVersioned { + fn new(command: CargoCommand, version: String) -> Self { + Self { command, version } + } + + /// Returns the `rustc` version. + fn rustc_version(&self) -> &str { &self.version } +} + +impl std::ops::Deref for CargoCommandVersioned { + type Target = CargoCommand; + + fn deref(&self) -> &CargoCommand { &self.command } +} + +/// Returns `true` when color output is enabled. +fn color_output_enabled() -> bool { + env::var(crate::WASM_BUILD_NO_COLOR).is_err() +} + +/// Fetches a boolean environment variable. Will exit the process if the value +/// is invalid. +fn get_bool_environment_variable(name: &str) -> Option { + let value = env::var_os(name)?; + + // We're comparing `OsString`s here so we can't use a `match`. + if value == "1" { + Some(true) + } else if value == "0" { + Some(false) + } else { + build_helper::warning!( + "the '{}' environment variable has an invalid value; it must be either '1' or '0'", + name + ); + std::process::exit(1); + } +} + +/// Returns whether we need to also compile the standard library when compiling +/// the runtime. +fn build_std_required() -> bool { + crate::get_bool_environment_variable(crate::WASM_BUILD_STD).unwrap_or(false) +} diff --git a/crates/wasm-builder/src/prerequisites.rs b/crates/wasm-builder/src/prerequisites.rs new file mode 100644 index 0000000..2b60607 --- /dev/null +++ b/crates/wasm-builder/src/prerequisites.rs @@ -0,0 +1,151 @@ +use crate::{write_file_if_changed, CargoCommand, CargoCommandVersioned}; + +use console::style; +use std::fs; +use std::path::Path; +use tempfile::tempdir; + +/// Print an error message. +fn print_error_message(message: &str) -> String { + if super::color_output_enabled() { + style(message).red().bold().to_string() + } else { + message.into() + } +} + +/// Checks that all prerequisites are installed. +/// +/// Returns the versioned cargo command on success. +pub(crate) fn check() -> Result { + let cargo_command = crate::get_cargo_command(); + + if !cargo_command.supports_substrate_wasm_env() { + return Err(print_error_message( + "Cannot compile the WASM runtime: no compatible Rust compiler found!\n\ + Install at least Rust 1.68.0 or a recent nightly version.", + )); + } + + check_wasm_toolchain_installed(cargo_command) +} + +/// Creates a minimal dummy crate at the given path and returns the manifest +/// path. +fn create_minimal_crate(project_dir: &Path) -> std::path::PathBuf { + fs::create_dir_all(project_dir.join("src")) + .expect("Creating src dir does not fail; qed"); + + let manifest_path = project_dir.join("Cargo.toml"); + write_file_if_changed( + &manifest_path, + r#" + [package] + name = "wasm-test" + version = "1.0.0" + edition = "2021" + + [workspace] + "#, + ); + + write_file_if_changed(project_dir.join("src/main.rs"), "fn main() {}"); + manifest_path +} + +fn check_wasm_toolchain_installed( + cargo_command: CargoCommand, +) -> Result { + let temp = tempdir().expect("Creating temp dir does not fail; qed"); + let manifest_path = create_minimal_crate(temp.path()).display().to_string(); + + let prepare_command = |subcommand| { + let mut cmd = cargo_command.command(); + // Chdir to temp to avoid including project's .cargo/config.toml + // by accident - it can happen in some CI environments. + cmd.current_dir(&temp); + cmd.args(&[ + subcommand, + "--target=wasm32-unknown-unknown", + "--manifest-path", + &manifest_path, + ]); + + if super::color_output_enabled() { + cmd.arg("--color=always"); + } + + // manually set the `CARGO_TARGET_DIR` to prevent a cargo deadlock + let target_dir = temp.path().join("target").display().to_string(); + cmd.env("CARGO_TARGET_DIR", &target_dir); + + // Make sure the host's flags aren't used here, e.g. if an alternative + // linker is specified in the RUSTFLAGS then the check we do + // here will break unless we clear these. + cmd.env_remove("CARGO_ENCODED_RUSTFLAGS"); + cmd.env_remove("RUSTFLAGS"); + cmd + }; + + let err_msg = print_error_message( + "Rust WASM toolchain is not properly installed; please install it!", + ); + let build_result = prepare_command("build") + .output() + .map_err(|_| err_msg.clone())?; + if !build_result.status.success() { + return match String::from_utf8(build_result.stderr) { + Ok(ref err) if err.contains("the `wasm32-unknown-unknown` target may not be installed") => + Err(print_error_message("Cannot compile the WASM runtime: the `wasm32-unknown-unknown` target is not installed!\n\ + You can install it with `rustup target add wasm32-unknown-unknown` if you're using `rustup`.")), + + // Apparently this can happen when we're running on a non Tier 1 platform. + Ok(ref err) if err.contains("linker `rust-lld` not found") => + Err(print_error_message("Cannot compile the WASM runtime: `rust-lld` not found!")), + + Ok(ref err) => Err(format!( + "{}\n\n{}\n{}\n{}{}\n", + err_msg, + style("Further error information:").yellow().bold(), + style("-".repeat(60)).yellow().bold(), + err, + style("-".repeat(60)).yellow().bold(), + )), + + Err(_) => Err(err_msg), + }; + } + + let mut run_cmd = prepare_command("rustc"); + run_cmd.args(&["-q", "--", "--version"]); + + let version = run_cmd + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok()) + .unwrap_or_else(|| "unknown rustc version".into()); + + if crate::build_std_required() { + let mut sysroot_cmd = prepare_command("rustc"); + sysroot_cmd.args(&["-q", "--", "--print", "sysroot"]); + if let Some(sysroot) = sysroot_cmd + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok()) + { + let src_path = Path::new(sysroot.trim()) + .join("lib") + .join("rustlib") + .join("src") + .join("rust"); + if !src_path.exists() { + return Err(print_error_message( + "Cannot compile the WASM runtime: no standard library sources found!\n\ + You can install them with `rustup component add rust-src` if you're using `rustup`.", + )); + } + } + } + + Ok(CargoCommandVersioned::new(cargo_command, version)) +} diff --git a/crates/wasm-builder/src/version.rs b/crates/wasm-builder/src/version.rs new file mode 100644 index 0000000..366b7c1 --- /dev/null +++ b/crates/wasm-builder/src/version.rs @@ -0,0 +1,221 @@ +use std::cmp::Ordering; + +/// The version of rustc/cargo. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Version { + pub major: u32, + pub minor: u32, + pub patch: u32, + pub is_nightly: bool, + pub year: Option, + pub month: Option, + pub day: Option, +} + +impl Version { + /// Returns if `self` is a stable version. + pub fn is_stable(&self) -> bool { !self.is_nightly } + + /// Return if `self` is a nightly version. + pub fn is_nightly(&self) -> bool { self.is_nightly } + + /// Extract from the given `version` string. + pub fn extract(version: &str) -> Option { + let mut is_nightly = false; + let version_parts = version + .trim() + .split(" ") + .nth(1)? + .split(".") + .filter_map(|v| { + if let Some(rest) = v.strip_suffix("-nightly") { + is_nightly = true; + rest.parse().ok() + } else { + v.parse().ok() + } + }) + .collect::>(); + + if version_parts.len() != 3 { + return None; + } + + let date_parts = version + .split(" ") + .nth(3) + .map(|date| { + date.split("-") + .filter_map(|v| { + v.trim().strip_suffix(")").unwrap_or(v).parse().ok() + }) + .collect::>() + }) + .unwrap_or_default(); + + Some(Version { + major: version_parts[0], + minor: version_parts[1], + patch: version_parts[2], + is_nightly, + year: date_parts.get(0).copied(), + month: date_parts.get(1).copied(), + day: date_parts.get(2).copied(), + }) + } +} + +/// Ordering is done in the following way: +/// +/// 1. `stable` > `nightly` +/// 2. Then compare major, minor and patch. +/// 3. Last compare the date. +impl Ord for Version { + fn cmp(&self, other: &Self) -> Ordering { + if self == other { + return Ordering::Equal; + } + + // Ensure that `stable > nightly` + if self.is_stable() && other.is_nightly() { + return Ordering::Greater; + } else if self.is_nightly() && other.is_stable() { + return Ordering::Less; + } + + let to_compare = [ + (Some(self.major), Some(other.major)), + (Some(self.minor), Some(other.minor)), + (Some(self.patch), Some(other.patch)), + (self.year, other.year), + (self.month, other.month), + (self.day, other.day), + ]; + + to_compare + .iter() + .find_map(|(l, r)| if l != r { l.partial_cmp(&r) } else { None }) + // We already checked this right at the beginning, so we should never return here + // `Equal`. + .unwrap_or(Ordering::Equal) + } +} + +impl PartialOrd for Version { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn version_compare_and_extract_works() { + let version_1_66_0 = + Version::extract("cargo 1.66.0 (d65d197ad 2022-11-15)").unwrap(); + let version_1_66_1 = + Version::extract("cargo 1.66.1 (d65d197ad 2022-11-15)").unwrap(); + let version_1_66_0_nightly = + Version::extract("cargo 1.66.0-nightly (d65d197ad 2022-10-15)") + .unwrap(); + let version_1_66_0_nightly_older_date = + Version::extract("cargo 1.66.0-nightly (d65d197ad 2022-10-14)") + .unwrap(); + let version_1_65_0 = + Version::extract("cargo 1.65.0 (d65d197ad 2022-10-15)").unwrap(); + let version_1_65_0_older_date = + Version::extract("cargo 1.65.0 (d65d197ad 2022-10-14)").unwrap(); + + assert!(version_1_66_1 > version_1_66_0); + assert!(version_1_66_1 > version_1_65_0); + assert!(version_1_66_1 > version_1_66_0_nightly); + assert!(version_1_66_1 > version_1_66_0_nightly_older_date); + assert!(version_1_66_1 > version_1_65_0_older_date); + + assert!(version_1_66_0 > version_1_65_0); + assert!(version_1_66_0 > version_1_66_0_nightly); + assert!(version_1_66_0 > version_1_66_0_nightly_older_date); + assert!(version_1_66_0 > version_1_65_0_older_date); + + assert!(version_1_65_0 > version_1_66_0_nightly); + assert!(version_1_65_0 > version_1_66_0_nightly_older_date); + assert!(version_1_65_0 > version_1_65_0_older_date); + + let mut versions = vec![ + version_1_66_0, + version_1_66_0_nightly, + version_1_66_0_nightly_older_date, + version_1_65_0_older_date, + version_1_65_0, + version_1_66_1, + ]; + versions.sort_by(|a, b| b.cmp(a)); + + let expected_versions_order = vec![ + version_1_66_1, + version_1_66_0, + version_1_65_0, + version_1_65_0_older_date, + version_1_66_0_nightly, + version_1_66_0_nightly_older_date, + ]; + assert_eq!(expected_versions_order, versions); + } + + #[test] + fn parse_with_newline() { + let version_1_66_0 = + Version::extract("cargo 1.66.0 (d65d197ad 2022-11-15)\n").unwrap(); + assert_eq!( + Version { + major: 1, + minor: 66, + patch: 0, + is_nightly: false, + year: Some(2022), + month: Some(11), + day: Some(15), + }, + version_1_66_0, + ); + } + + #[test] + fn version_without_hash_and_date() { + // Apparently there are installations that print without the hash and + // date. + let version_1_69_0 = Version::extract("cargo 1.69.0-nightly").unwrap(); + assert_eq!( + Version { + major: 1, + minor: 69, + patch: 0, + is_nightly: true, + year: None, + month: None, + day: None, + }, + version_1_69_0, + ); + } + + #[test] + fn parse_rustc_version() { + let version = + Version::extract("rustc 1.73.0 (cc66ad468 2023-10-03)").unwrap(); + assert_eq!( + version, + Version { + major: 1, + minor: 73, + patch: 0, + is_nightly: false, + year: Some(2023), + month: Some(10), + day: Some(3), + } + ); + } +} diff --git a/crates/wasm-builder/src/wasm_project.rs b/crates/wasm-builder/src/wasm_project.rs new file mode 100644 index 0000000..b752e37 --- /dev/null +++ b/crates/wasm-builder/src/wasm_project.rs @@ -0,0 +1,1074 @@ +use crate::{write_file_if_changed, CargoCommandVersioned, OFFLINE}; + +use build_helper::rerun_if_changed; +use cargo_metadata::{DependencyKind, Metadata, MetadataCommand}; +use console::style; +use std::borrow::ToOwned; +use std::collections::HashSet; +use std::hash::{Hash, Hasher}; +use std::ops::Deref; +use std::path::{Path, PathBuf}; +use std::{env, fs, process}; +use strum::{EnumIter, IntoEnumIterator}; +use toml::value::Table; +use walkdir::WalkDir; + +/// Colorize an info message. +/// +/// Returns the colorized message. +fn colorize_info_message(message: &str) -> String { + if super::color_output_enabled() { + style(message).yellow().bold().to_string() + } else { + message.into() + } +} + +/// Holds the path to the bloaty WASM binary. +pub struct WasmBinaryBloaty(PathBuf); + +impl WasmBinaryBloaty { + /// Returns the escaped path to the bloaty binary. + pub fn bloaty_path_escaped(&self) -> String { + self.0.display().to_string().escape_default().to_string() + } + + /// Returns the path to the binary. + pub fn bloaty_path(&self) -> &Path { &self.0 } +} + +/// Holds the path to the WASM binary. +pub struct WasmBinary(PathBuf); + +impl WasmBinary { + /// Returns the path to the wasm binary. + pub fn wasm_binary_path(&self) -> &Path { &self.0 } + + /// Returns the escaped path to the wasm binary. + pub fn wasm_binary_path_escaped(&self) -> String { + self.0.display().to_string().escape_default().to_string() + } +} + +fn crate_metadata(cargo_manifest: &Path) -> Metadata { + let mut cargo_lock = cargo_manifest.to_path_buf(); + cargo_lock.set_file_name("Cargo.lock"); + + let cargo_lock_existed = cargo_lock.exists(); + + // If we can find a `Cargo.lock`, we assume that this is the workspace root + // and there exists a `Cargo.toml` that we can use for getting the + // metadata. + let cargo_manifest = + if let Some(mut cargo_lock) = find_cargo_lock(cargo_manifest) { + cargo_lock.set_file_name("Cargo.toml"); + cargo_lock + } else { + cargo_manifest.to_path_buf() + }; + + let crate_metadata_command = create_metadata_command(cargo_manifest); + + let crate_metadata = crate_metadata_command + .exec() + .expect("`cargo metadata` can not fail on project `Cargo.toml`; qed"); + // If the `Cargo.lock` didn't exist, we need to remove it after + // calling `cargo metadata`. This is required to ensure that we don't change + // the build directory outside of the `target` folder. Commands like + // `cargo publish` require this. + if !cargo_lock_existed { + let _ = fs::remove_file(&cargo_lock); + } + + crate_metadata +} + +/// Creates the WASM project, compiles the WASM binary and compacts the WASM +/// binary. +/// +/// # Returns +/// +/// The path to the compact runtime binary and the bloaty runtime binary. +pub(crate) fn create_and_compile( + project_cargo_toml: &Path, + default_rustflags: &str, + cargo_cmd: CargoCommandVersioned, + features_to_enable: Vec, + bloaty_blob_out_name_override: Option, +) -> (Option, WasmBinaryBloaty) { + let runtime_workspace_root = get_wasm_workspace_root(); + let runtime_workspace = runtime_workspace_root.join("wbuild"); + + let crate_metadata = crate_metadata(project_cargo_toml); + + let project = create_project( + project_cargo_toml, + &runtime_workspace, + &crate_metadata, + crate_metadata.workspace_root.as_ref(), + features_to_enable, + ); + + let build_config = BuildConfiguration::detect(&project); + + // Build the bloaty runtime blob + build_bloaty_blob( + &build_config.blob_build_profile, + &project, + default_rustflags, + cargo_cmd, + ); + + // Get the name of the bloaty runtime blob. + let bloaty_blob_default_name = get_blob_name(project_cargo_toml); + let bloaty_blob_out_name = bloaty_blob_out_name_override + .unwrap_or_else(|| bloaty_blob_default_name.clone()); + + let bloaty_blob_binary = copy_bloaty_blob( + &project, + &build_config.blob_build_profile, + &bloaty_blob_default_name, + &bloaty_blob_out_name, + ); + + // Process the bloaty blob + let bloaty_blob_binary = process_bloaty_blob(bloaty_blob_binary); + + // Try to compact and _compress_ the bloaty blob, if the *outer* profile + // wants it. + // + // This is because, by default the inner profile will be set to `Release` + // even when the outer profile is `Debug`, because the blob built in + // `Debug` profile is too slow for normal development activities. + let (compact_blob_path, compact_compressed_blob_path) = + if build_config.outer_build_profile.wants_compact() { + let compact_blob_path = compact_wasm( + &project, + &build_config.blob_build_profile, + project_cargo_toml, + &bloaty_blob_out_name, + ); + // TODO: Compress the compacted blob. + (compact_blob_path, None) + } else { + (None, None) + }; + + if let Some(wasm_binary) = compact_blob_path.as_ref() { + copy_blob_to_target_directory(project_cargo_toml, wasm_binary) + } + + if let Some(wasm_binary_compressed) = compact_compressed_blob_path.as_ref() + { + copy_blob_to_target_directory( + project_cargo_toml, + wasm_binary_compressed, + ) + } + + let final_blob_binary = compact_compressed_blob_path.or(compact_blob_path); + + generate_rerun_if_changed_instructions( + project_cargo_toml, + &project, + &runtime_workspace, + final_blob_binary.as_ref(), + &bloaty_blob_binary, + ); + + if let Err(err) = + adjust_mtime(&bloaty_blob_binary, final_blob_binary.as_ref()) + { + build_helper::warning!( + "Error while adjusting the mtime of the blob binaries: {}", + err + ) + } + + (final_blob_binary, bloaty_blob_binary) +} + +/// Adjust the mtime of the bloaty and compressed/compact wasm files. +/// +/// We add the bloaty and the compressed/compact wasm file to the +/// `rerun-if-changed` files. Cargo/Rustc determines based on the timestamp of +/// the `invoked.timestamp` file that can be found in the `OUT_DIR/..`, if it +/// needs to rerun a `build.rs` script. The problem is that this +/// `invoked.timestamp` is created when the `build.rs` is executed and the wasm +/// binaries are created later. This leads to them having a later mtime than the +/// `invoked.timestamp` file and thus, cargo/rustc always re-executes the +/// `build.rs` script. To hack around this, we copy the mtime of the `invoked. +/// timestamp` to the wasm binaries. +fn adjust_mtime( + bloaty_wasm: &WasmBinaryBloaty, + compressed_or_compact_wasm: Option<&WasmBinary>, +) -> std::io::Result<()> { + let out_dir = build_helper::out_dir(); + let invoked_timestamp = out_dir.join("../invoked.timestamp"); + + // Get the mtime of the `invoked.timestamp` + let metadata = fs::metadata(invoked_timestamp)?; + let mtime = filetime::FileTime::from_last_modification_time(&metadata); + + filetime::set_file_mtime(bloaty_wasm.bloaty_path(), mtime)?; + if let Some(binary) = compressed_or_compact_wasm.as_ref() { + filetime::set_file_mtime(binary.wasm_binary_path(), mtime)?; + } + + Ok(()) +} + +/// Find the `Cargo.lock` relative to the `OUT_DIR` environment variable. +/// +/// If the `Cargo.lock` cannot be found, we emit a warning and return `None`. +fn find_cargo_lock(cargo_manifest: &Path) -> Option { + fn find_impl(mut path: PathBuf) -> Option { + loop { + if path.join("Cargo.lock").exists() { + return Some(path.join("Cargo.lock")); + } + + if !path.pop() { + return None; + } + } + } + + if let Ok(workspace) = env::var(crate::WASM_BUILD_WORKSPACE_HINT) { + let path = PathBuf::from(workspace); + + if path.join("Cargo.lock").exists() { + return Some(path.join("Cargo.lock")); + } else { + build_helper::warning!( + "`{}` env variable doesn't point to a directory that contains a `Cargo.lock`.", + crate::WASM_BUILD_WORKSPACE_HINT + ); + } + } + + if let Some(path) = find_impl(build_helper::out_dir()) { + return Some(path); + } + + build_helper::warning!( + "Could not find `Cargo.lock` for `{}`, while searching from `{}`. \ + To fix this, point the `{}` env variable to the directory of the workspace being compiled.", + cargo_manifest.display(), + build_helper::out_dir().display(), + crate::WASM_BUILD_WORKSPACE_HINT, + ); + + None +} + +/// Extract the crate name from the given `Cargo.toml`. +fn get_crate_name(cargo_manifest: &Path) -> String { + let cargo_toml: Table = toml::from_str( + &fs::read_to_string(cargo_manifest) + .expect("File exists as checked before; qed"), + ) + .expect("Cargo manifest is a valid toml file; qed"); + + let package = cargo_toml + .get("package") + .and_then(|t| t.as_table()) + .expect("`package` key exists in valid `Cargo.toml`; qed"); + + package + .get("name") + .and_then(|p| p.as_str()) + .map(ToOwned::to_owned) + .expect("Package name exists; qed") +} + +/// Returns the name for the blob binary. +fn get_blob_name(cargo_manifest: &Path) -> String { + get_crate_name(cargo_manifest).replace('-', "_") +} + +/// Returns the root path of the wasm workspace. +fn get_wasm_workspace_root() -> PathBuf { + let mut out_dir = build_helper::out_dir(); + + loop { + match out_dir.parent() { + Some(parent) if out_dir.ends_with("build") => { + return parent.to_path_buf() + }, + _ => { + if !out_dir.pop() { + break; + } + }, + } + } + + panic!( + "Could not find target dir in: {}", + build_helper::out_dir().display() + ) +} + +fn create_project_cargo_toml( + wasm_workspace: &Path, + workspace_root_path: &Path, + crate_name: &str, + crate_path: &Path, + wasm_binary: &str, + enabled_features: impl Iterator, +) { + let mut workspace_toml: Table = toml::from_str( + &fs::read_to_string(workspace_root_path.join("Cargo.toml")) + .expect("Workspace root `Cargo.toml` exists; qed"), + ) + .expect("Workspace root `Cargo.toml` is a valid toml file; qed"); + + let mut wasm_workspace_toml = Table::new(); + + // Add different profiles which are selected by setting `WASM_BUILD_TYPE`. + let mut release_profile = Table::new(); + release_profile.insert("panic".into(), "abort".into()); + release_profile.insert("lto".into(), "thin".into()); + + let mut production_profile = Table::new(); + production_profile.insert("inherits".into(), "release".into()); + production_profile.insert("lto".into(), "fat".into()); + production_profile.insert("codegen-units".into(), 1.into()); + + let mut dev_profile = Table::new(); + dev_profile.insert("panic".into(), "abort".into()); + + let mut profile = Table::new(); + profile.insert("release".into(), release_profile.into()); + profile.insert("production".into(), production_profile.into()); + profile.insert("dev".into(), dev_profile.into()); + + wasm_workspace_toml.insert("profile".into(), profile.into()); + + // Add patch section from the project root `Cargo.toml` + while let Some(mut patch) = workspace_toml + .remove("patch") + .and_then(|p| p.try_into::().ok()) + { + // Iterate over all patches and make the patch path absolute from the + // workspace root path. + patch + .iter_mut() + .filter_map(|p| { + p.1.as_table_mut() + .map(|t| t.iter_mut().filter_map(|t| t.1.as_table_mut())) + }) + .flatten() + .for_each(|p| { + p.iter_mut() + .filter(|(k, _)| k == &"path") + .for_each(|(_, v)| { + if let Some(path) = v.as_str().map(PathBuf::from) { + if path.is_relative() { + *v = workspace_root_path + .join(path) + .display() + .to_string() + .into(); + } + } + }) + }); + + wasm_workspace_toml.insert("patch".into(), patch.into()); + } + + let mut package = Table::new(); + package.insert("name".into(), format!("{}-wasm", crate_name).into()); + package.insert("version".into(), "1.0.0".into()); + package.insert("edition".into(), "2021".into()); + + wasm_workspace_toml.insert("package".into(), package.into()); + + let mut lib = Table::new(); + lib.insert("name".into(), wasm_binary.into()); + lib.insert("crate-type".into(), vec!["cdylib".to_string()].into()); + + wasm_workspace_toml.insert("lib".into(), lib.into()); + + let mut dependencies = Table::new(); + + let mut wasm_project = Table::new(); + wasm_project.insert("package".into(), crate_name.into()); + wasm_project.insert("path".into(), crate_path.display().to_string().into()); + wasm_project.insert("default-features".into(), false.into()); + wasm_project.insert( + "features".into(), + enabled_features.collect::>().into(), + ); + + dependencies.insert("wasm-project".into(), wasm_project.into()); + + wasm_workspace_toml.insert("dependencies".into(), dependencies.into()); + + wasm_workspace_toml.insert("workspace".into(), Table::new().into()); + + write_file_if_changed( + wasm_workspace.join("Cargo.toml"), + toml::to_string_pretty(&wasm_workspace_toml) + .expect("Wasm workspace toml is valid; qed"), + ); +} + +/// Find a package by the given `manifest_path` in the metadata. In case it +/// can't be found by its manifest_path, fallback to finding it by name; this is +/// necessary during publish because the package's manifest path will be +/// *generated* within a specific packaging directory, thus it won't be found by +/// its original path anymore. +/// +/// Panics if the package could not be found. +fn find_package_by_manifest_path<'a>( + pkg_name: &str, + manifest_path: &Path, + crate_metadata: &'a cargo_metadata::Metadata, +) -> &'a cargo_metadata::Package { + if let Some(pkg) = crate_metadata + .packages + .iter() + .find(|p| p.manifest_path == manifest_path) + { + return pkg; + } + + let pkgs_by_name = crate_metadata + .packages + .iter() + .filter(|p| p.name == pkg_name) + .collect::>(); + + if let Some(pkg) = pkgs_by_name.first() { + if pkgs_by_name.len() > 1 { + panic!( + "Found multiple packages matching the name {pkg_name} ({manifest_path:?}): {:?}", + pkgs_by_name + ); + } else { + pkg + } + } else { + panic!( + "Failed to find entry for package {pkg_name} ({manifest_path:?})." + ); + } +} + +/// Get a list of enabled features for the project. +fn project_enabled_features( + pkg_name: &str, + cargo_manifest: &Path, + crate_metadata: &cargo_metadata::Metadata, +) -> Vec { + let package = + find_package_by_manifest_path(pkg_name, cargo_manifest, crate_metadata); + + let std_enabled = package.features.get("std"); + + let mut enabled_features = package + .features + .iter() + .filter(|(f, v)| { + let mut feature_env = f.replace('-', "_"); + feature_env.make_ascii_uppercase(); + + // If this is a feature that corresponds only to an optional + // dependency and this feature is enabled by the `std` + // feature, we assume that this is only done through the + // `std` feature. This is a bad heuristic and should + // be removed after namespaced features are landed: + // https://doc.rust-lang.org/cargo/reference/unstable.html#namespaced-features + // Then we can just express this directly in the `Cargo.toml` and do + // not require this heuristic anymore. However, for the + // transition phase between now and namespaced + // features already being present in nightly, we need this code to + // make runtimes compile with all the possible rustc + // versions. + if v.len() == 1 + && v.get(0).map_or(false, |v| *v == format!("dep:{}", f)) + && std_enabled + .as_ref() + .map(|e| e.iter().any(|ef| ef == *f)) + .unwrap_or(false) + { + return false; + } + + // We don't want to enable the `std`/`default` feature for the wasm + // build and we need to check if the feature is enabled + // by checking the env variable. + *f != "std" + && *f != "default" + && env::var(format!("CARGO_FEATURE_{}", feature_env)) + .map(|v| v == "1") + .unwrap_or_default() + }) + .map(|d| d.0.clone()) + .collect::>(); + + enabled_features.sort(); + enabled_features +} + +/// Returns if the project has the `runtime-wasm` feature +fn has_runtime_wasm_feature_declared( + pkg_name: &str, + cargo_manifest: &Path, + crate_metadata: &cargo_metadata::Metadata, +) -> bool { + let package = + find_package_by_manifest_path(pkg_name, cargo_manifest, crate_metadata); + + package.features.keys().any(|k| k == "runtime-wasm") +} + +/// Create the project used to build the wasm binary. +/// +/// # Returns +/// +/// The path to the created wasm project. +fn create_project( + project_cargo_toml: &Path, + wasm_workspace: &Path, + crate_metadata: &Metadata, + workspace_root_path: &Path, + features_to_enable: Vec, +) -> PathBuf { + let crate_name = get_crate_name(project_cargo_toml); + let crate_path = project_cargo_toml + .parent() + .expect("Parent path exists; qed"); + let wasm_binary = get_blob_name(project_cargo_toml); + let wasm_project_folder = wasm_workspace.join(&crate_name); + + fs::create_dir_all(wasm_project_folder.join("src")) + .expect("Wasm project dir create can not fail; qed"); + + let mut enabled_features = project_enabled_features( + &crate_name, + project_cargo_toml, + crate_metadata, + ); + + if has_runtime_wasm_feature_declared( + &crate_name, + project_cargo_toml, + crate_metadata, + ) { + enabled_features.push("runtime-wasm".into()); + } + + let mut enabled_features = + enabled_features.into_iter().collect::>(); + enabled_features.extend(features_to_enable); + + create_project_cargo_toml( + &wasm_project_folder, + workspace_root_path, + &crate_name, + crate_path, + &wasm_binary, + enabled_features.into_iter(), + ); + + write_file_if_changed( + wasm_project_folder.join("src/lib.rs"), + "#![no_std] pub use wasm_project::*;", + ); + + if let Some(crate_lock_file) = find_cargo_lock(project_cargo_toml) { + // Use the `Cargo.lock` of the main project. + crate::copy_file_if_changed( + crate_lock_file, + wasm_project_folder.join("Cargo.lock"), + ); + } + + wasm_project_folder +} + +/// A rustc profile. +#[derive(Clone, Debug, EnumIter)] +enum Profile { + /// The `--profile dev` profile. + Debug, + /// The `--profile release` profile. + Release, + /// The `--profile production` profile. + Production, +} + +impl Profile { + /// The name of the profile as supplied to the cargo `--profile` cli option. + fn name(&self) -> &'static str { + match self { + Self::Debug => "dev", + Self::Release => "release", + Self::Production => "production", + } + } + + /// The sub directory within `target` where cargo places the build output. + /// + /// # Note + /// + /// Usually this is the same as [`Self::name`] with the exception of the + /// debug profile which is called `dev`. + fn directory(&self) -> &'static str { + match self { + Self::Debug => "debug", + _ => self.name(), + } + } + + /// Whether the resulting binary should be compacted and compressed. + fn wants_compact(&self) -> bool { !matches!(self, Self::Debug) } +} + +/// The build configuration for this build. +#[derive(Debug)] +struct BuildConfiguration { + /// The profile that is used to build the outer project. + pub outer_build_profile: Profile, + /// The profile to use to build the runtime blob. + pub blob_build_profile: Profile, +} + +impl BuildConfiguration { + /// Create a [`BuildConfiguration`] by detecting which profile is used for + /// the main build and checking any env var overrides. + /// + /// We cannot easily determine the profile that is used by the main cargo + /// invocation because the `PROFILE` environment variable won't contain + /// any custom profiles like "production". It would only contain the + /// builtin profile where the custom profile inherits from. This is why + /// we inspect the build path to learn which profile is used. + /// + /// When not overriden by a env variable we always default to building wasm + /// with the `Release` profile even when the main build uses the debug + /// build. This is because wasm built with the `Debug` profile is too + /// slow for normal development activities and almost never intended. + /// + /// When cargo is building in `--profile dev`, user likely intends to + /// compile fast, so we don't bother producing compact or compressed + /// blobs. + /// + /// # Note + /// + /// Can be overriden by setting [`crate::WASM_BUILD_TYPE_ENV`]. + fn detect(wasm_project: &Path) -> Self { + let (name, overriden) = if let Ok(name) = + env::var(crate::WASM_BUILD_TYPE_ENV) + { + (name, true) + } else { + // First go backwards to the beginning of the target directory. + // Then go forwards to find the "wbuild" directory. + // We need to go backwards first because when starting from the + // root there might be a chance that someone has + // a "wbuild" directory somewhere in the path. + let name = wasm_project + .components() + .rev() + .take_while(|c| c.as_os_str() != "target") + .collect::>() + .iter() + .rev() + .take_while(|c| c.as_os_str() != "wbuild") + .last() + .expect("We put the wasm project within a `target/.../wbuild` path; qed") + .as_os_str() + .to_str() + .expect("All our profile directory names are ascii; qed") + .to_string(); + (name, false) + }; + let outer_build_profile = + Profile::iter().find(|p| p.directory() == name); + let blob_build_profile = match (outer_build_profile.clone(), overriden) + { + // When not overriden by a env variable we default to using the + // `Release` profile for the wasm build even when the + // main build uses the debug build. This is because the + // `Debug` profile is too slow for normal development activities. + (Some(Profile::Debug), false) => Profile::Release, + // For any other profile or when overriden we take it at face value. + (Some(profile), _) => profile, + // For non overriden unknown profiles we fall back to `Release`. + // This allows us to continue building when a custom profile is used + // for the main builds cargo. When explicitly passing a + // profile via env variable we are not doing a fallback. + (None, false) => { + let profile = Profile::Release; + build_helper::warning!( + "Unknown cargo profile `{}`. Defaulted to `{:?}` for the runtime build.", + name, + profile, + ); + profile + }, + // Invalid profile specified. + (None, true) => { + // We use println! + exit instead of a panic in order to have a + // cleaner output. + println!( + "Unexpected profile name: `{}`. One of the following is expected: {:?}", + name, + Profile::iter().map(|p| p.directory()).collect::>(), + ); + process::exit(1); + }, + }; + BuildConfiguration { + outer_build_profile: outer_build_profile + .unwrap_or(Profile::Release), + blob_build_profile, + } + } +} + +/// Check environment whether we should build without network +fn offline_build() -> bool { env::var(OFFLINE).map_or(false, |v| v == "true") } + +/// Build the project and create the bloaty runtime blob. +fn build_bloaty_blob( + blob_build_profile: &Profile, + project: &Path, + default_rustflags: &str, + cargo_cmd: CargoCommandVersioned, +) { + let manifest_path = project.join("Cargo.toml"); + let mut build_cmd = cargo_cmd.command(); + + let rustflags = format!( + "-C target-cpu=mvp -C target-feature=-sign-ext -C link-arg=--export-table {} {}", + default_rustflags, + env::var(crate::WASM_BUILD_RUSTFLAGS_ENV).unwrap_or_default(), + ); + + build_cmd + .args(["rustc", "--target=wasm32-unknown-unknown"]) + .arg(format!("--manifest-path={}", manifest_path.display())) + .env("RUSTFLAGS", rustflags) + // Manually set the `CARGO_TARGET_DIR` to prevent a cargo deadlock (cargo locks a target dir + // exclusive). The runner project is created in `CARGO_TARGET_DIR` and executing it will + // create a sub target directory inside of `CARGO_TARGET_DIR`. + .env("CARGO_TARGET_DIR", &project.join("target").display().to_string()) + // As we are being called inside a build-script, this env variable is set. However, we set + // our own `RUSTFLAGS` and thus, we need to remove this. Otherwise cargo favors this + // env variable. + .env_remove("CARGO_ENCODED_RUSTFLAGS") + // We don't want to call ourselves recursively + .env(crate::SKIP_BUILD_ENV, ""); + + if super::color_output_enabled() { + build_cmd.arg("--color=always"); + } + + build_cmd.arg("--profile"); + build_cmd.arg(blob_build_profile.name()); + + if offline_build() { + build_cmd.arg("--offline"); + } + + // Our executor currently only supports the WASM MVP feature set, however + // nowadays when compiling WASM the Rust compiler has more features + // enabled by default. + // + // We do set the `-C target-cpu=mvp` flag to make sure that *our* code gets + // compiled in a way that is compatible with our executor, however this + // doesn't affect Rust's standard library crates (`std`, `core` and + // `alloc`) which are by default precompiled and still can make use of + // these extra features. + // + // So here we force the compiler to also compile the standard library crates + // for us to make sure that they also only use the MVP features. + if crate::build_std_required() { + // Unfortunately this is still a nightly-only flag, but FWIW it is + // pretty widely used so it's unlikely to break without a + // replacement. + build_cmd.arg("-Z").arg("build-std"); + if !cargo_cmd.supports_nightly_features() { + build_cmd.env("RUSTC_BOOTSTRAP", "1"); + } + } + + println!( + "{}", + colorize_info_message( + "Information that should be included in a bug report." + ) + ); + println!( + "{} {:?}", + colorize_info_message("Executing build command:"), + build_cmd + ); + println!( + "{} {}", + colorize_info_message("Using rustc version:"), + cargo_cmd.rustc_version() + ); + + // Use `process::exit(1)` to have a clean error output. + if build_cmd.status().map(|s| s.success()).is_err() { + process::exit(1); + } +} + +fn compact_wasm( + project: &Path, + inner_profile: &Profile, + cargo_manifest: &Path, + out_name: &str, +) -> Option { + let default_out_name = get_blob_name(cargo_manifest); + let in_path = project + .join("target/wasm32-unknown-unknown") + .join(inner_profile.directory()) + .join(format!("{}.wasm", default_out_name)); + + let wasm_compact_path = project.join(format!("{}.compact.wasm", out_name)); + let start = std::time::Instant::now(); + wasm_opt::OptimizationOptions::new_opt_level_0() + .mvp_features_only() + .debug_info(true) + .add_pass(wasm_opt::Pass::StripDwarf) + .run(in_path, &wasm_compact_path) + .expect("Failed to compact generated WASM binary."); + println!( + "{} {}", + colorize_info_message("Compacted wasm in"), + colorize_info_message(format!("{:?}", start.elapsed()).as_str()) + ); + Some(WasmBinary(wasm_compact_path)) +} + +fn copy_bloaty_blob( + project: &Path, + inner_profile: &Profile, + in_name: &str, + out_name: &str, +) -> WasmBinaryBloaty { + let in_path = project + .join("target/wasm32-unknown-unknown") + .join(inner_profile.directory()) + .join(format!("{}.wasm", in_name)); + + let bloaty_path = project.join(format!("{}.wasm", out_name)); + fs::copy(in_path, &bloaty_path) + .expect("Copying the bloaty file to the project dir."); + WasmBinaryBloaty(bloaty_path) +} + +fn process_bloaty_blob( + bloty_blob_binary: WasmBinaryBloaty, +) -> WasmBinaryBloaty { + let processor = externref::processor::Processor::default(); + let wasm_bytes = fs::read(bloty_blob_binary.bloaty_path()) + .expect("Reading the bloaty file."); + let processed_wasm_bytes = processor + .process_bytes(&wasm_bytes) + .expect("Processing the bloaty file."); + fs::write(bloty_blob_binary.bloaty_path(), processed_wasm_bytes) + .expect("Writing the bloaty file."); + bloty_blob_binary +} + +/// Custom wrapper for a [`cargo_metadata::Package`] to store it in +/// a `HashSet`. +#[derive(Debug)] +struct DeduplicatePackage<'a> { + package: &'a cargo_metadata::Package, + identifier: String, +} + +impl<'a> From<&'a cargo_metadata::Package> for DeduplicatePackage<'a> { + fn from(package: &'a cargo_metadata::Package) -> Self { + Self { + package, + identifier: format!( + "{}{}{:?}", + package.name, package.version, package.source + ), + } + } +} + +impl<'a> Hash for DeduplicatePackage<'a> { + fn hash(&self, state: &mut H) { self.identifier.hash(state); } +} + +impl<'a> PartialEq for DeduplicatePackage<'a> { + fn eq(&self, other: &Self) -> bool { self.identifier == other.identifier } +} + +impl<'a> Eq for DeduplicatePackage<'a> {} + +impl<'a> Deref for DeduplicatePackage<'a> { + type Target = cargo_metadata::Package; + + fn deref(&self) -> &Self::Target { self.package } +} + +fn create_metadata_command(path: impl Into) -> MetadataCommand { + let mut metadata_command = MetadataCommand::new(); + metadata_command.manifest_path(path); + + if offline_build() { + metadata_command.other_options(vec!["--offline".to_owned()]); + } + metadata_command +} + +/// Generate the `rerun-if-changed` instructions for cargo to make sure that the +/// WASM binary is rebuilt when needed. +fn generate_rerun_if_changed_instructions( + cargo_manifest: &Path, + project_folder: &Path, + wasm_workspace: &Path, + compressed_or_compact_wasm: Option<&WasmBinary>, + bloaty_wasm: &WasmBinaryBloaty, +) { + // Rerun `build.rs` if the `Cargo.lock` changes + if let Some(cargo_lock) = find_cargo_lock(cargo_manifest) { + rerun_if_changed(cargo_lock); + } + + let metadata = create_metadata_command(project_folder.join("Cargo.toml")) + .exec() + .expect("`cargo metadata` can not fail!"); + + let package = metadata + .packages + .iter() + .find(|p| p.manifest_path == cargo_manifest) + .expect("The crate package is contained in its own metadata; qed"); + + // Start with the dependencies of the crate we want to compile for wasm. + let mut dependencies = package.dependencies.iter().collect::>(); + + // Collect all packages by follow the dependencies of all packages we find. + let mut packages = HashSet::new(); + packages.insert(DeduplicatePackage::from(package)); + + while let Some(dependency) = dependencies.pop() { + // Ignore all dev dependencies + if dependency.kind == DependencyKind::Development { + continue; + } + + let path_or_git_dep = dependency + .source + .as_ref() + .map(|s| s.starts_with("git+")) + .unwrap_or(true); + + let package = metadata + .packages + .iter() + .filter(|p| !p.manifest_path.starts_with(wasm_workspace)) + .find(|p| { + // Check that the name matches and that the version matches or + // this is a git or path dep. A git or path + // dependency can only occur once, so we don't + // need to check the version. + (path_or_git_dep || dependency.req.matches(&p.version)) + && dependency.name == p.name + }); + + if let Some(package) = package { + if packages.insert(DeduplicatePackage::from(package)) { + dependencies.extend(package.dependencies.iter()); + } + } + } + + // Make sure that if any file/folder of a dependency change, we need to + // rerun the `build.rs` + packages.iter().for_each(package_rerun_if_changed); + + if let Some(w) = compressed_or_compact_wasm { + rerun_if_changed(w.wasm_binary_path()) + } + rerun_if_changed(bloaty_wasm.bloaty_path()); + + // Register our env variables + println!("cargo:rerun-if-env-changed={}", crate::SKIP_BUILD_ENV); + println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_TYPE_ENV); + println!( + "cargo:rerun-if-env-changed={}", + crate::WASM_BUILD_RUSTFLAGS_ENV + ); + println!( + "cargo:rerun-if-env-changed={}", + crate::WASM_TARGET_DIRECTORY + ); + println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_TOOLCHAIN); + println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_STD); +} + +/// Track files and paths related to the given package to rerun `build.rs` on +/// any relevant change. +fn package_rerun_if_changed(package: &DeduplicatePackage) { + let mut manifest_path = package.manifest_path.clone(); + if manifest_path.ends_with("Cargo.toml") { + manifest_path.pop(); + } + + WalkDir::new(&manifest_path) + .into_iter() + .filter_entry(|p| { + // Ignore this entry if it is a directory that contains a + // `Cargo.toml` that is not the `Cargo.toml` related to + // the current package. This is done to ignore sub-crates of a + // crate. If such a sub-crate is a dependency, it will be processed + // independently anyway. + p.path() == manifest_path + || !p.path().is_dir() + || !p.path().join("Cargo.toml").exists() + }) + .filter_map(|p| p.ok().map(|p| p.into_path())) + .filter(|p| { + p.extension() + .map(|e| e == "rs" || e == "toml") + .unwrap_or_default() + }) + .for_each(rerun_if_changed); +} + +/// Copy the blob binary to the target directory set in `WASM_TARGET_DIRECTORY` +/// environment variable. If the variable is not set, this is a no-op. +fn copy_blob_to_target_directory( + cargo_manifest: &Path, + blob_binary: &WasmBinary, +) { + let target_dir = match env::var(crate::WASM_TARGET_DIRECTORY) { + Ok(path) => PathBuf::from(path), + Err(_) => return, + }; + + if !target_dir.is_absolute() { + // We use println! + exit instead of a panic in order to have a cleaner + // output. + println!( + "Environment variable `{}` with `{}` is not an absolute path!", + crate::WASM_TARGET_DIRECTORY, + target_dir.display(), + ); + process::exit(1); + } + + fs::create_dir_all(&target_dir).expect("Creates `WASM_TARGET_DIRECTORY`."); + + fs::copy( + blob_binary.wasm_binary_path(), + target_dir.join(format!("{}.wasm", get_blob_name(cargo_manifest))), + ) + .expect("Copies blob binary to `WASM_TARGET_DIRECTORY`."); +} diff --git a/packets/connect/.cargo/config.toml b/packets/connect/.cargo/config.toml deleted file mode 100644 index f4e8c00..0000000 --- a/packets/connect/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -target = "wasm32-unknown-unknown" diff --git a/packets/connect/Cargo.toml b/packets/connect/Cargo.toml index c96dd2f..0cb4ded 100644 --- a/packets/connect/Cargo.toml +++ b/packets/connect/Cargo.toml @@ -3,9 +3,6 @@ name = "msg-connect" version = "0.1.0" edition.workspace = true -[lib] -crate-type = ["cdylib", "rlib"] - [dependencies] tq-serde.workspace = true tq-network.workspace = true @@ -16,6 +13,9 @@ bytes.workspace = true thiserror.workspace = true tracing.workspace = true +[build-dependencies] +tq-wasm-builder.workspace = true + [features] default = ["std"] std = ["tq-serde/std", "tq-network/std", "tq-bindings/std"] diff --git a/packets/connect/build.rs b/packets/connect/build.rs index fdae23b..ae2767a 100644 --- a/packets/connect/build.rs +++ b/packets/connect/build.rs @@ -1,3 +1,8 @@ -type Error = Box; +use tq_wasm_builder::WasmBuilder; -fn main() -> Result<(), Error> { return Ok(()); } +fn main() { + WasmBuilder::selector() + .with_current_project() + .enable_feature("std") + .build(); +} diff --git a/packets/connect/src/lib.rs b/packets/connect/src/lib.rs index f366b21..ad16f67 100644 --- a/packets/connect/src/lib.rs +++ b/packets/connect/src/lib.rs @@ -3,6 +3,8 @@ #[cfg(not(feature = "std"))] extern crate alloc; +include!(concat!(env!("OUT_DIR"), "/wasm.rs")); + use tq_bindings::{host, Resource}; use tq_network::ActorHandle; use tq_serde::String16; @@ -29,7 +31,7 @@ pub fn process( msg: MsgConnect, actor: &Resource, ) -> Result<(), crate::Error> { - tracing::debug!(?msg, "Shutting down actor"); + tracing::debug!(?msg, "Shutting down actor!"); host::shutdown(actor); Ok(()) } diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index 29309a7..2b26dee 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -107,11 +107,9 @@ mod tests { let engine = Engine::new(&config).unwrap(); let mut linker = Linker::new(&engine); add_to_linker(&mut linker).unwrap(); - let msg_connect = Module::from_file( - &engine, - "../../target/wasm32-unknown-unknown/wasm/msg_connect.s.wasm", - ) - .unwrap(); + let msg_connect = + Module::from_file(&engine, msg_connect::WASM_BINARY.unwrap()) + .unwrap(); std::env::set_var("DATABASE_URL", "sqlite::memory:"); let state = State::init().await.unwrap(); let packets = Packets { msg_connect }; From 518a2ec79a6c31ecefe1ae64691b6bc6f455496f Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Wed, 24 Jan 2024 20:01:07 +0200 Subject: [PATCH 18/28] working on transfer packet --- Cargo.lock | 26 +++++ Cargo.toml | 6 +- crates/bindings/src/lib.rs | 53 +++++----- crates/wasm-builder/src/prerequisites.rs | 6 +- crates/wasm-builder/src/version.rs | 14 +-- packets/transfer/Cargo.toml | 6 ++ packets/transfer/build.rs | 8 ++ packets/transfer/src/functions.rs | 66 ------------- packets/transfer/src/lib.rs | 121 +++++++++++++++-------- packets/transfer/src/traits.rs | 54 ---------- 10 files changed, 158 insertions(+), 202 deletions(-) create mode 100644 packets/transfer/build.rs diff --git a/Cargo.lock b/Cargo.lock index fc7cd5d..423b609 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1607,6 +1607,32 @@ dependencies = [ "tracing", ] +[[package]] +name = "msg-connect-ex" +version = "0.1.0" +dependencies = [ + "num_enum", + "serde", + "tq-network", + "tq-serde", +] + +[[package]] +name = "msg-transfer" +version = "0.1.0" +dependencies = [ + "bytes", + "msg-connect-ex", + "serde", + "tq-bindings", + "tq-codec", + "tq-crypto", + "tq-network", + "tq-serde", + "tq-wasm-builder", + "tracing", +] + [[package]] name = "nix" version = "0.27.1" diff --git a/Cargo.toml b/Cargo.toml index c5197be..32961f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,6 @@ members = [ ] exclude = [ "packets/account", - "packets/connect-ex", - "packets/transfer", "tools/benchbot" ] @@ -48,9 +46,9 @@ game = { path = "server/game" } # Packets # msg-account = { path = "packets/account" } -# msg-connect-ex = { path = "packets/connect-ex" } +msg-connect-ex = { path = "packets/connect-ex" } msg-connect = { path = "packets/connect" } -# msg-transfer = { path = "packets/transfer" } +msg-transfer = { path = "packets/transfer" } futures = { version = "0.3", default-features = false } thiserror = "1.0" diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs index ca4b50f..9dc8720 100644 --- a/crates/bindings/src/lib.rs +++ b/crates/bindings/src/lib.rs @@ -7,19 +7,6 @@ extern crate alloc; pub use externref::{self as anyref, externref, Resource}; -#[cfg(target_arch = "wasm32")] -#[externref(crate = "crate::anyref")] -#[link(wasm_import_module = "host")] -extern "C" { - fn shutdown(actor: &Resource); - fn send( - actor: &Resource, - packet_id: u16, - packet_data_ptr: *const u8, - packet_data_len: u32, - ); -} - /// A [`MakeWriter`] emitting the written text to the [`host`]. #[cfg(feature = "std")] pub fn setup_logging(name: &'static str) { @@ -65,22 +52,36 @@ pub fn set_panic_hook_once(name: &'static str) { #[cfg(not(feature = "std"))] pub fn set_panic_hook_once(_name: &'static str) {} +#[externref(crate = "crate::anyref")] +#[link(wasm_import_module = "host")] +extern "C" { + fn shutdown(actor: &Resource); + fn send( + actor: &Resource, + packet_id: u16, + packet_data_ptr: *const u8, + packet_data_len: u32, + ); + + fn generate_login_token( + actor: &Resource, + account_id: u32, + realm_id: u32, + ) -> u64; +} + /// Host bindings. pub mod host { use crate::Resource; use tq_network::ActorHandle; + + pub use tracing_wasm::log; /// Shutdown an actor. - #[cfg(target_arch = "wasm32")] pub fn shutdown(actor: &Resource) { unsafe { super::shutdown(actor) } } - #[cfg(not(target_arch = "wasm32"))] - pub fn shutdown(_actor: &Resource) {} - /// Send a packet to an actor. - - #[cfg(target_arch = "wasm32")] pub fn send( actor: &Resource, packet: T, @@ -97,13 +98,11 @@ pub mod host { Ok(()) } - #[cfg(not(target_arch = "wasm32"))] - pub fn send( - _actor: &Resource, - _packet: T, - ) -> Result<(), T::Error> { - Ok(()) + pub fn generate_login_token( + actor: &Resource, + account_id: u32, + realm_id: u32, + ) -> u64 { + unsafe { super::generate_login_token(actor, account_id, realm_id) } } - - pub use tracing_wasm::log; } diff --git a/crates/wasm-builder/src/prerequisites.rs b/crates/wasm-builder/src/prerequisites.rs index 2b60607..e090c8c 100644 --- a/crates/wasm-builder/src/prerequisites.rs +++ b/crates/wasm-builder/src/prerequisites.rs @@ -64,7 +64,7 @@ fn check_wasm_toolchain_installed( // Chdir to temp to avoid including project's .cargo/config.toml // by accident - it can happen in some CI environments. cmd.current_dir(&temp); - cmd.args(&[ + cmd.args([ subcommand, "--target=wasm32-unknown-unknown", "--manifest-path", @@ -117,7 +117,7 @@ fn check_wasm_toolchain_installed( } let mut run_cmd = prepare_command("rustc"); - run_cmd.args(&["-q", "--", "--version"]); + run_cmd.args(["-q", "--", "--version"]); let version = run_cmd .output() @@ -127,7 +127,7 @@ fn check_wasm_toolchain_installed( if crate::build_std_required() { let mut sysroot_cmd = prepare_command("rustc"); - sysroot_cmd.args(&["-q", "--", "--print", "sysroot"]); + sysroot_cmd.args(["-q", "--", "--print", "sysroot"]); if let Some(sysroot) = sysroot_cmd .output() .ok() diff --git a/crates/wasm-builder/src/version.rs b/crates/wasm-builder/src/version.rs index 366b7c1..26fda1e 100644 --- a/crates/wasm-builder/src/version.rs +++ b/crates/wasm-builder/src/version.rs @@ -24,9 +24,9 @@ impl Version { let mut is_nightly = false; let version_parts = version .trim() - .split(" ") + .split(' ') .nth(1)? - .split(".") + .split('.') .filter_map(|v| { if let Some(rest) = v.strip_suffix("-nightly") { is_nightly = true; @@ -42,12 +42,12 @@ impl Version { } let date_parts = version - .split(" ") + .split(' ') .nth(3) .map(|date| { - date.split("-") + date.split('-') .filter_map(|v| { - v.trim().strip_suffix(")").unwrap_or(v).parse().ok() + v.trim().strip_suffix(')').unwrap_or(v).parse().ok() }) .collect::>() }) @@ -58,7 +58,7 @@ impl Version { minor: version_parts[1], patch: version_parts[2], is_nightly, - year: date_parts.get(0).copied(), + year: date_parts.first().copied(), month: date_parts.get(1).copied(), day: date_parts.get(2).copied(), }) @@ -94,7 +94,7 @@ impl Ord for Version { to_compare .iter() - .find_map(|(l, r)| if l != r { l.partial_cmp(&r) } else { None }) + .find_map(|(l, r)| if l != r { l.partial_cmp(r) } else { None }) // We already checked this right at the beginning, so we should never return here // `Equal`. .unwrap_or(Ordering::Equal) diff --git a/packets/transfer/Cargo.toml b/packets/transfer/Cargo.toml index 6653183..1e93a6c 100644 --- a/packets/transfer/Cargo.toml +++ b/packets/transfer/Cargo.toml @@ -8,6 +8,7 @@ tq-serde.workspace = true tq-codec.workspace = true tq-crypto.workspace = true tq-network.workspace = true +tq-bindings.workspace = true serde.workspace = true tracing.workspace = true @@ -15,6 +16,10 @@ bytes.workspace = true msg-connect-ex.workspace = true + +[build-dependencies] +tq-wasm-builder.workspace = true + [features] default = ["std"] std = [ @@ -22,6 +27,7 @@ std = [ "tq-codec/std", "tq-crypto/std", "tq-network/std", + "tq-bindings/std", "tracing/std", diff --git a/packets/transfer/build.rs b/packets/transfer/build.rs new file mode 100644 index 0000000..ae2767a --- /dev/null +++ b/packets/transfer/build.rs @@ -0,0 +1,8 @@ +use tq_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::selector() + .with_current_project() + .enable_feature("std") + .build(); +} diff --git a/packets/transfer/src/functions.rs b/packets/transfer/src/functions.rs index 34789ee..e69de29 100644 --- a/packets/transfer/src/functions.rs +++ b/packets/transfer/src/functions.rs @@ -1,66 +0,0 @@ -use msg_connect_ex::{AccountCredentials, RejectionCode}; -use tq_network::IntoErrorPacket; - -use crate::types::Realm; - -use super::*; - -impl MsgTransfer { - pub fn handle( - actor: &ActorHandle, - realm: &str, - ) -> Result { - let maybe_realm = T::RealmByName::by_name(realm)?; - // Check if there is a realm with that name - let realm = match maybe_realm { - Some(realm) => realm, - None => { - return Err(RejectionCode::TryAgainLater - .packet() - .error_packet() - .into()); - }, - }; - // Try to connect to that realm first. - if let Err(e) = T::ServerBus::check(&realm) { - tracing::error!( - ip = realm.game_ip_address, - port = realm.game_port, - realm_id = realm.id, - error = ?e, - "Failed to connect to realm" - ); - T::send(actor, RejectionCode::ServerDown.packet())?; - T::shutdown(actor)?; - return Err(e); - } - Self::transfer(actor, realm) - } - - fn transfer( - actor: &ActorHandle, - realm: Realm, - ) -> Result { - let res = T::ServerBus::transfer(actor, &realm); - match res { - Ok(token) => Ok(AccountCredentials { - token, - server_ip: realm.game_ip_address, - server_port: realm.game_port as u32, - }), - Err(e) => { - tracing::error!( - ip = realm.game_ip_address, - port = realm.game_port, - realm_id = realm.id, - error = ?e, - "Failed to transfer account" - ); - Err(RejectionCode::ServerTimedOut - .packet() - .error_packet() - .into()) - }, - } - } -} diff --git a/packets/transfer/src/lib.rs b/packets/transfer/src/lib.rs index ac272e7..f991d4c 100644 --- a/packets/transfer/src/lib.rs +++ b/packets/transfer/src/lib.rs @@ -1,55 +1,85 @@ #![cfg_attr(not(feature = "std"), no_std)] -use serde::{Deserialize, Serialize}; -use tq_network::{ErrorPacket, PacketEncode, PacketID}; +#[cfg(not(feature = "std"))] +extern crate alloc; -use tq_system::ActorHandle; -pub use traits::{RealmByName, ServerBus, TokenGenerator}; +include!(concat!(env!("OUT_DIR"), "/wasm.rs")); -mod functions; -mod traits; -mod types; +use msg_connect_ex::{AccountCredentials, RejectionCode}; +use serde::{Deserialize, Serialize}; +use tq_bindings::{host, Resource}; +use tq_network::{ + ActorHandle, ErrorPacket, IntoErrorPacket, PacketEncode, PacketID, +}; /// Defines account parameters to be transferred from the account server to the /// game server. Account information is supplied from the account database, and /// used on the game server to transfer authentication and authority level. #[derive(Clone, Default, Debug, Deserialize, Serialize, PacketID)] #[packet(id = 4001)] -pub struct MsgTransfer { +pub struct MsgTransfer { account_id: u32, realm_id: u32, token: u64, - #[serde(skip)] - _config: core::marker::PhantomData, -} - -pub trait Config: tq_system::Config { - /// The type of the authanticator used to authanticate accounts. - type TokenGenerator: TokenGenerator; - /// For querying realms by name. - type RealmByName: RealmByName; - /// Server bus for checking and transferring accounts - /// to other servers. - type ServerBus: ServerBus; } -impl tq_system::ProcessPacket for MsgTransfer { - type Error = Error; - - fn process(&self, actor: ActorHandle) -> Result<(), Self::Error> { - let token = T::TokenGenerator::generate_login_token( - self.account_id, - self.realm_id, - )?; - let msg = Self { - account_id: self.account_id, - realm_id: self.realm_id, - token, - _config: core::marker::PhantomData, +impl MsgTransfer { + pub fn handle( + actor: &Resource, + realm: &str, + ) -> Result { + let maybe_realm = T::RealmByName::by_name(realm)?; + // Check if there is a realm with that name + let realm = match maybe_realm { + Some(realm) => realm, + None => { + return Err(RejectionCode::TryAgainLater + .packet() + .error_packet() + .into()); + }, }; - T::send(&actor, msg)?; - T::shutdown(&actor)?; - Ok(()) + // Try to connect to that realm first. + if let Err(e) = T::ServerBus::check(&realm) { + tracing::error!( + ip = realm.game_ip_address, + port = realm.game_port, + realm_id = realm.id, + error = ?e, + "Failed to connect to realm" + ); + host::send(actor, RejectionCode::ServerDown.packet())?; + host::shutdown(actor); + return Err(e); + } + Self::transfer(actor, realm) + } + + fn transfer( + actor: &Resource, + realm: Realm, + ) -> Result { + let res = T::ServerBus::transfer(actor, &realm); + match res { + Ok(token) => Ok(AccountCredentials { + token, + server_ip: realm.game_ip_address, + server_port: realm.game_port as u32, + }), + Err(e) => { + tracing::error!( + ip = realm.game_ip_address, + port = realm.game_port, + realm_id = realm.id, + error = ?e, + "Failed to transfer account" + ); + Err(RejectionCode::ServerTimedOut + .packet() + .error_packet() + .into()) + }, + } } } @@ -92,9 +122,18 @@ impl From> for Error { } } -#[cfg(test)] -mod tests { - - #[test] - fn it_works() {} +#[tq_network::packet_processor(MsgTransfer)] +fn process( + msg: MsgTransfer, + actor: &Resource, +) -> Result<(), crate::Error> { + let token = host::generate_login_token(actor, msg.account_id, msg.realm_id); + let msg = MsgTransfer { + account_id: msg.account_id, + realm_id: msg.realm_id, + token, + }; + host::send(&actor, msg)?; + host::shutdown(&actor); + Ok(()) } diff --git a/packets/transfer/src/traits.rs b/packets/transfer/src/traits.rs index ae06a01..e69de29 100644 --- a/packets/transfer/src/traits.rs +++ b/packets/transfer/src/traits.rs @@ -1,54 +0,0 @@ -use tq_system::ActorHandle; - -use crate::types::Realm; - -/// Trait for generating login tokens. -pub trait TokenGenerator { - fn generate_login_token( - account_id: u32, - realm_id: u32, - ) -> Result; -} - -// A dummy token generator that always returns 0. -impl TokenGenerator for () { - fn generate_login_token( - _account_id: u32, - _realm_id: u32, - ) -> Result { - Ok(0) - } -} - -/// Trait for querying realms by name. -pub trait RealmByName { - fn by_name(name: &str) -> Result, crate::Error>; -} - -// A dummy realm query that always returns None. -impl RealmByName for () { - fn by_name(_name: &str) -> Result, crate::Error> { Ok(None) } -} - -pub trait ServerBus { - fn check(realm: &Realm) -> Result<(), crate::Error>; - - fn transfer( - actor: &ActorHandle, - realm: &Realm, - ) -> Result; -} - -// A dummy server bus that always returns an error. -impl ServerBus for () { - fn check(_realm: &Realm) -> Result<(), crate::Error> { - Err(crate::Error::RealmUnavailable) - } - - fn transfer( - _actor: &ActorHandle, - _realm: &Realm, - ) -> Result { - Err(crate::Error::RealmUnavailable) - } -} From 55f390ce96c784a3efa6d39dc1ee5617ee909be2 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Wed, 24 Jan 2024 20:09:54 +0200 Subject: [PATCH 19/28] clippy fixes --- crates/network/src/actor.rs | 6 +++--- crates/wasm-builder/src/builder.rs | 3 +-- crates/wasm-builder/src/wasm_project.rs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/network/src/actor.rs b/crates/network/src/actor.rs index 6b5c7f1..e5a179c 100644 --- a/crates/network/src/actor.rs +++ b/crates/network/src/actor.rs @@ -69,10 +69,10 @@ impl From<(u16, Bytes)> for Message { pub trait ActorState: Send + Sync + Sized { fn init() -> Self; /// A good chance to dispose the state and clear anything. - #[instrument(skip_all, err, fields(id = %handle.id()))] + #[instrument(skip_all, err)] + #[allow(clippy::blocks_in_conditions)] async fn dispose(&self, handle: ActorHandle) -> Result<(), Error> { - let _ = handle; - tracing::debug!("Disposing Actor State"); + tracing::debug!(actor_id = %handle.id(), "Disposing Actor State"); Ok(()) } } diff --git a/crates/wasm-builder/src/builder.rs b/crates/wasm-builder/src/builder.rs index 8413a65..1ba6492 100644 --- a/crates/wasm-builder/src/builder.rs +++ b/crates/wasm-builder/src/builder.rs @@ -153,8 +153,7 @@ impl WasmBuilder { self.project_cargo_toml, self.rust_flags .into_iter() - .map(|f| format!("{} ", f)) - .collect(), + .fold(String::new(), |acc, f| format!("{acc} {f}")), self.features_to_enable, self.file_name, ); diff --git a/crates/wasm-builder/src/wasm_project.rs b/crates/wasm-builder/src/wasm_project.rs index b752e37..ee4b70b 100644 --- a/crates/wasm-builder/src/wasm_project.rs +++ b/crates/wasm-builder/src/wasm_project.rs @@ -489,7 +489,7 @@ fn project_enabled_features( // make runtimes compile with all the possible rustc // versions. if v.len() == 1 - && v.get(0).map_or(false, |v| *v == format!("dep:{}", f)) + && v.first().map_or(false, |v| *v == format!("dep:{}", f)) && std_enabled .as_ref() .map(|e| e.iter().any(|ef| ef == *f)) From 19fd9971da4107569a3ad1427611c0b357ce3fd6 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Wed, 24 Jan 2024 21:52:42 +0200 Subject: [PATCH 20/28] moving data between wasm and host --- Cargo.lock | 3 + Cargo.toml | 7 +- crates/bindings/Cargo.toml | 2 + crates/bindings/src/lib.rs | 132 +++++++++++++++++++++++------- crates/db/src/account.rs | 14 ++-- crates/db/src/character.rs | 22 +++-- crates/db/src/map.rs | 9 +- crates/db/src/npc.rs | 4 +- crates/db/src/portal.rs | 4 +- crates/db/src/realm.rs | 8 +- crates/network/src/actor.rs | 6 +- crates/tracing-wasm/src/lib.rs | 2 + packets/connect/src/lib.rs | 2 +- packets/transfer/Cargo.toml | 1 + packets/transfer/build.rs | 8 +- packets/transfer/src/functions.rs | 0 packets/transfer/src/lib.rs | 12 +-- packets/transfer/src/traits.rs | 0 server/game/src/world/portal.rs | 2 +- 19 files changed, 164 insertions(+), 74 deletions(-) delete mode 100644 packets/transfer/src/functions.rs delete mode 100644 packets/transfer/src/traits.rs diff --git a/Cargo.lock b/Cargo.lock index 423b609..83bcabf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1627,6 +1627,7 @@ dependencies = [ "tq-bindings", "tq-codec", "tq-crypto", + "tq-db", "tq-network", "tq-serde", "tq-wasm-builder", @@ -2951,6 +2952,8 @@ name = "tq-bindings" version = "0.1.0" dependencies = [ "externref", + "getrandom", + "tq-db", "tq-network", "tracing", "tracing-subscriber", diff --git a/Cargo.toml b/Cargo.toml index 32961f9..e0cfc73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,10 +17,7 @@ members = [ # Cli Tools "tools/*", ] -exclude = [ - "packets/account", - "tools/benchbot" -] +exclude = ["packets/account", "tools/benchbot"] [workspace.dependencies] # Local Dependencies @@ -65,6 +62,7 @@ argh = "0.1" tokio-stream = { version = "0.1.8", default-features = false } parking_lot = { version = "0.12.1", default-features = false, features = [] } rand = "0.8" +getrandom = { version = "0.2", default-features = false } arc-swap = { version = "1.6", features = ["weak"] } atomic = { version = "0.6", default-features = false } bytemuck = { version = "1.13", default-features = false, features = ["derive"] } @@ -89,4 +87,3 @@ version = "0.7.3" [profile.dev] split-debuginfo = 'packed' - diff --git a/crates/bindings/Cargo.toml b/crates/bindings/Cargo.toml index e0575f5..e8060f7 100644 --- a/crates/bindings/Cargo.toml +++ b/crates/bindings/Cargo.toml @@ -6,10 +6,12 @@ edition.workspace = true [dependencies] tq-network.workspace = true tracing-wasm.workspace = true +tq-db = { workspace = true, default-features = false } tracing = { workspace = true, default-features = false, optional = true } tracing-subscriber = { workspace = true, default-features = false, features = ["alloc"], optional = true } externref = { workspace = true, default-features = false, features = ["macro"] } +getrandom = { workspace = true, default-features = false, features = ["custom"] } [features] default = ["std"] diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs index 9dc8720..7c288c7 100644 --- a/crates/bindings/src/lib.rs +++ b/crates/bindings/src/lib.rs @@ -55,15 +55,23 @@ pub fn set_panic_hook_once(_name: &'static str) {} #[externref(crate = "crate::anyref")] #[link(wasm_import_module = "host")] extern "C" { - fn shutdown(actor: &Resource); - fn send( + fn getrandom(ptr: *mut u8, len: usize) -> i32; + fn tq_network_actor_shutdown(actor: &Resource); + fn tq_network_actor_send( actor: &Resource, packet_id: u16, packet_data_ptr: *const u8, packet_data_len: u32, ); - fn generate_login_token( + fn tq_db_realm_by_name( + realm_name_ptr: *const u8, + realm_name_len: u32, + out_realm_ptr: *mut u8, + out_realm_len: *mut u32, + ) -> i32; + + fn game_state_generate_login_token( actor: &Resource, account_id: u32, realm_id: u32, @@ -72,37 +80,103 @@ extern "C" { /// Host bindings. pub mod host { - use crate::Resource; - use tq_network::ActorHandle; - + /// [`tracing_wasm`] bindings. pub use tracing_wasm::log; - /// Shutdown an actor. - pub fn shutdown(actor: &Resource) { - unsafe { super::shutdown(actor) } + /// [`tq_network`] bindings. + pub mod network { + /// [`tq_network::actor`] bindings. + pub mod actor { + use crate::Resource; + use tq_network::ActorHandle; + /// [`tq_network::actor::ActorHandle::shutdown`] bindings. + pub fn shutdown(actor: &Resource) { + unsafe { crate::tq_network_actor_shutdown(actor) } + } + /// [`tq_network::actor::ActorHandle::send`] bindings. + pub fn send( + actor: &Resource, + packet: T, + ) -> Result<(), T::Error> { + let (packet_id, packet_data) = packet.encode()?; + unsafe { + crate::tq_network_actor_send( + actor, + packet_id, + packet_data.as_ptr(), + packet_data.len() as u32, + ) + } + Ok(()) + } + } } - /// Send a packet to an actor. - pub fn send( - actor: &Resource, - packet: T, - ) -> Result<(), T::Error> { - let (packet_id, packet_data) = packet.encode()?; - unsafe { - super::send( - actor, - packet_id, - packet_data.as_ptr(), - packet_data.len() as u32, - ) + /// [`tq_db`] bindings. + pub mod db { + /// [`tq_db::realm`] bindings. + pub mod realm { + use tq_db::realm::Realm; + /// [`tq_db::realm::Realm::by_name`] bindings. + pub fn by_name( + realm_name: &str, + ) -> Result, tq_db::Error> { + let realm = core::ptr::null_mut(); + let mut realm_len = 0; + let res = unsafe { + crate::tq_db_realm_by_name( + realm_name.as_ptr(), + realm_name.len() as u32, + realm, + &mut realm_len, + ) + }; + if res == 0 && realm_len > 0 && !realm.is_null() { + let realm = unsafe { + let bytes = std::vec::Vec::from_raw_parts( + realm, + realm_len as usize, + realm_len as usize, + ); + // Does not work! + core::mem::transmute(bytes) + }; + Ok(Some(realm)) + } else { + Ok(None) + } + } + } + } + /// [`game`] bindings. + pub mod game { + /// [`game::state`] bindings. + pub mod state { + use crate::Resource; + use tq_network::ActorHandle; + /// [`game::state::generate_login_token`] bindings. + pub fn generate_login_token( + actor: &Resource, + account_id: u32, + realm_id: u32, + ) -> u64 { + unsafe { + crate::game_state_generate_login_token( + actor, account_id, realm_id, + ) + } + } } - Ok(()) } - pub fn generate_login_token( - actor: &Resource, - account_id: u32, - realm_id: u32, - ) -> u64 { - unsafe { super::generate_login_token(actor, account_id, realm_id) } + /// Get random bytes. + pub fn getrandom(buf: &mut [u8]) -> Result<(), getrandom::Error> { + let res = unsafe { super::getrandom(buf.as_mut_ptr(), buf.len()) }; + if res == 0 { + Ok(()) + } else { + Err(getrandom::Error::FAILED_RDRAND) + } } } + +getrandom::register_custom_getrandom!(host::getrandom); diff --git a/crates/db/src/account.rs b/crates/db/src/account.rs index d2a7e6f..128fc35 100644 --- a/crates/db/src/account.rs +++ b/crates/db/src/account.rs @@ -1,11 +1,11 @@ use crate::Error; use futures::TryFutureExt; -use sqlx::SqlitePool; /// Account information for a registered player. The account server uses this /// information to authenticate the player on login. Passwords are hashed using /// bcrypt -#[derive(Default, Debug, sqlx::FromRow)] +#[derive(Default, Debug)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Account { pub account_id: i32, pub username: String, @@ -14,9 +14,10 @@ pub struct Account { pub email: Option, } +#[cfg(feature = "sqlx")] impl Account { pub async fn auth( - pool: &SqlitePool, + pool: &sqlx::SqlitePool, username: &str, password: &str, ) -> Result { @@ -43,7 +44,7 @@ impl Account { /// /// Useful for testing purposes. pub async fn all( - pool: &SqlitePool, + pool: &sqlx::SqlitePool, limit: Option, offset: Option, ) -> Result, Error> { @@ -58,7 +59,10 @@ impl Account { // === Methods === /// Creates a new account in the database. - pub async fn create(mut self, pool: &SqlitePool) -> Result { + pub async fn create( + mut self, + pool: &sqlx::SqlitePool, + ) -> Result { let password = bcrypt::hash(&self.password, bcrypt::DEFAULT_COST)?; let res = sqlx::query( "INSERT INTO accounts (username, password, name, email) VALUES (?, ?, ?, ?);", diff --git a/crates/db/src/character.rs b/crates/db/src/character.rs index 12deaa1..1696845 100644 --- a/crates/db/src/character.rs +++ b/crates/db/src/character.rs @@ -1,5 +1,3 @@ -use sqlx::SqlitePool; - use crate::Error; /// This struct encapsulates the game character for a player. The player @@ -7,7 +5,8 @@ use crate::Error; /// The character is the persona of the player who controls it. The persona can /// be altered using different avatars, hairstyles, and body types. The player /// also controls the character's professions and abilities. -#[derive(Debug, Clone, Default, sqlx::FromRow)] +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Character { pub character_id: i32, pub account_id: i32, @@ -37,16 +36,18 @@ pub struct Character { pub kill_points: i16, } -#[derive(Debug, sqlx::FromRow)] +#[derive(Debug)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Location { pub map_id: i32, pub x: i16, pub y: i16, } +#[cfg(feature = "sqlx")] impl Character { pub async fn from_account( - pool: &SqlitePool, + pool: &sqlx::SqlitePool, id: u32, ) -> Result, Error> { let maybe_character = sqlx::query_as::<_, Self>( @@ -59,7 +60,7 @@ impl Character { } pub async fn name_taken( - pool: &SqlitePool, + pool: &sqlx::SqlitePool, name: &str, ) -> Result { let result = sqlx::query_as::<_, (i32,)>( @@ -76,7 +77,10 @@ impl Character { } } - pub async fn by_id(pool: &SqlitePool, id: i32) -> Result { + pub async fn by_id( + pool: &sqlx::SqlitePool, + id: i32, + ) -> Result { let c = sqlx::query_as::<_, Self>( "SELECT * FROM characters WHERE character_id = ?;", ) @@ -86,7 +90,7 @@ impl Character { Ok(c) } - pub async fn save(self, pool: &SqlitePool) -> Result { + pub async fn save(self, pool: &sqlx::SqlitePool) -> Result { let (id,) = sqlx::query_as::<_, (i32,)>( " INSERT INTO characters @@ -128,7 +132,7 @@ impl Character { Ok(id) } - pub async fn update(self, pool: &SqlitePool) -> Result<(), Error> { + pub async fn update(self, pool: &sqlx::SqlitePool) -> Result<(), Error> { sqlx::query( " UPDATE characters diff --git a/crates/db/src/map.rs b/crates/db/src/map.rs index 6e8f953..6213cff 100644 --- a/crates/db/src/map.rs +++ b/crates/db/src/map.rs @@ -1,8 +1,8 @@ use crate::Error; -use sqlx::SqlitePool; use tokio_stream::StreamExt; -#[derive(Debug, Clone, Default, sqlx::FromRow)] +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Map { pub id: i32, pub map_id: i32, @@ -15,10 +15,11 @@ pub struct Map { pub color: i32, } +#[cfg(feature = "sqlx")] impl Map { /// Loads all maps from the database to add them to the state. #[tracing::instrument] - pub async fn load_all(pool: &SqlitePool) -> Result, Error> { + pub async fn load_all(pool: &sqlx::SqlitePool) -> Result, Error> { let mut maps = Vec::new(); let mut s = sqlx::query_as::<_, Self>("SELECT * FROM maps;").fetch(pool); @@ -37,7 +38,7 @@ impl Map { } pub async fn load( - pool: &SqlitePool, + pool: &sqlx::SqlitePool, id: i32, ) -> Result, Error> { let maybe_map = diff --git a/crates/db/src/npc.rs b/crates/db/src/npc.rs index 8647c2f..b6af3ba 100644 --- a/crates/db/src/npc.rs +++ b/crates/db/src/npc.rs @@ -2,7 +2,8 @@ use crate::Error; use sqlx::SqlitePool; use tokio_stream::StreamExt; -#[derive(Debug, Clone, Default, sqlx::FromRow)] +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Npc { pub id: i32, pub name: String, @@ -19,6 +20,7 @@ pub struct Npc { pub magic_defense: i32, } +#[cfg(feature = "sqlx")] impl Npc { #[tracing::instrument] pub async fn by_map( diff --git a/crates/db/src/portal.rs b/crates/db/src/portal.rs index 482a975..5b42257 100644 --- a/crates/db/src/portal.rs +++ b/crates/db/src/portal.rs @@ -2,7 +2,8 @@ use crate::Error; use sqlx::SqlitePool; use tokio_stream::StreamExt; -#[derive(Debug, Clone, Default, sqlx::FromRow)] +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Portal { pub id: i32, pub from_map_id: i32, @@ -13,6 +14,7 @@ pub struct Portal { pub to_y: i16, } +#[cfg(feature = "sqlx")] impl Portal { #[tracing::instrument] pub async fn by_map( diff --git a/crates/db/src/realm.rs b/crates/db/src/realm.rs index 6aeb052..da3d3c4 100644 --- a/crates/db/src/realm.rs +++ b/crates/db/src/realm.rs @@ -1,11 +1,10 @@ -use sqlx::SqlitePool; - use crate::Error; /// Realms are configured instances of the game server. This struct defines /// routing details for authenticated clients to be redirected to. Redirection /// involves access token leasing, provided by the game server via RPC. -#[derive(Clone, Debug, sqlx::FromRow)] +#[derive(Clone, Debug)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Realm { pub realm_id: i32, pub name: String, @@ -13,9 +12,10 @@ pub struct Realm { pub game_port: i16, } +#[cfg(feature = "sqlx")] impl Realm { pub async fn by_name( - pool: &SqlitePool, + pool: &sqlx::SqlitePool, name: &str, ) -> Result, Error> { let realm = diff --git a/crates/network/src/actor.rs b/crates/network/src/actor.rs index e5a179c..ad47a7c 100644 --- a/crates/network/src/actor.rs +++ b/crates/network/src/actor.rs @@ -46,10 +46,8 @@ impl Hash for Actor { impl PartialEq for Actor { fn eq(&self, other: &Self) -> bool { - self.handle - .id - .load(Ordering::Relaxed) - .eq(&other.handle.id.load(Ordering::Relaxed)) + self.handle.id.load(Ordering::Relaxed) + == other.handle.id.load(Ordering::Relaxed) } } diff --git a/crates/tracing-wasm/src/lib.rs b/crates/tracing-wasm/src/lib.rs index 7d6c20c..c64dd5f 100644 --- a/crates/tracing-wasm/src/lib.rs +++ b/crates/tracing-wasm/src/lib.rs @@ -103,6 +103,8 @@ pub fn log(level: Level, target: &str, message: &str) { } } +/// Does nothing. + #[cfg(not(target_arch = "wasm32"))] pub fn log(_level: Level, _target: &str, _message: &str) {} diff --git a/packets/connect/src/lib.rs b/packets/connect/src/lib.rs index ad16f67..a7fbcdb 100644 --- a/packets/connect/src/lib.rs +++ b/packets/connect/src/lib.rs @@ -32,6 +32,6 @@ pub fn process( actor: &Resource, ) -> Result<(), crate::Error> { tracing::debug!(?msg, "Shutting down actor!"); - host::shutdown(actor); + host::network::actor::shutdown(actor); Ok(()) } diff --git a/packets/transfer/Cargo.toml b/packets/transfer/Cargo.toml index 1e93a6c..41bf7ab 100644 --- a/packets/transfer/Cargo.toml +++ b/packets/transfer/Cargo.toml @@ -9,6 +9,7 @@ tq-codec.workspace = true tq-crypto.workspace = true tq-network.workspace = true tq-bindings.workspace = true +tq-db = { workspace = true, default-features = false } serde.workspace = true tracing.workspace = true diff --git a/packets/transfer/build.rs b/packets/transfer/build.rs index ae2767a..58aceb1 100644 --- a/packets/transfer/build.rs +++ b/packets/transfer/build.rs @@ -1,8 +1,8 @@ use tq_wasm_builder::WasmBuilder; fn main() { - WasmBuilder::selector() - .with_current_project() - .enable_feature("std") - .build(); + // WasmBuilder::selector() + // .with_current_project() + // .enable_feature("std") + // .build(); } diff --git a/packets/transfer/src/functions.rs b/packets/transfer/src/functions.rs deleted file mode 100644 index e69de29..0000000 diff --git a/packets/transfer/src/lib.rs b/packets/transfer/src/lib.rs index f991d4c..a3777c3 100644 --- a/packets/transfer/src/lib.rs +++ b/packets/transfer/src/lib.rs @@ -3,7 +3,7 @@ #[cfg(not(feature = "std"))] extern crate alloc; -include!(concat!(env!("OUT_DIR"), "/wasm.rs")); +// include!(concat!(env!("OUT_DIR"), "/wasm.rs")); use msg_connect_ex::{AccountCredentials, RejectionCode}; use serde::{Deserialize, Serialize}; @@ -28,7 +28,7 @@ impl MsgTransfer { actor: &Resource, realm: &str, ) -> Result { - let maybe_realm = T::RealmByName::by_name(realm)?; + let maybe_realm = host::realm_by_name(realm)?; // Check if there is a realm with that name let realm = match maybe_realm { Some(realm) => realm, @@ -40,7 +40,7 @@ impl MsgTransfer { }, }; // Try to connect to that realm first. - if let Err(e) = T::ServerBus::check(&realm) { + if let Err(e) = host::server_bus_check(&realm) { tracing::error!( ip = realm.game_ip_address, port = realm.game_port, @@ -57,9 +57,9 @@ impl MsgTransfer { fn transfer( actor: &Resource, - realm: Realm, + realm: tq_db::realm::Realm, ) -> Result { - let res = T::ServerBus::transfer(actor, &realm); + let res = host::server_bus_transfer(actor, &realm); match res { Ok(token) => Ok(AccountCredentials { token, @@ -70,7 +70,7 @@ impl MsgTransfer { tracing::error!( ip = realm.game_ip_address, port = realm.game_port, - realm_id = realm.id, + realm_id = realm.realm_id, error = ?e, "Failed to transfer account" ); diff --git a/packets/transfer/src/traits.rs b/packets/transfer/src/traits.rs deleted file mode 100644 index e69de29..0000000 diff --git a/server/game/src/world/portal.rs b/server/game/src/world/portal.rs index f34a4a5..6d6bf97 100644 --- a/server/game/src/world/portal.rs +++ b/server/game/src/world/portal.rs @@ -37,7 +37,7 @@ impl Portal { } impl PartialEq for Portal { - fn eq(&self, other: &Self) -> bool { self.id().eq(&other.id()) } + fn eq(&self, other: &Self) -> bool { self.id == other.id } } impl Eq for Portal {} From 92056f529ad14a770a3c977e6fbd1e860e13c80c Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sat, 27 Jan 2024 22:02:45 +0200 Subject: [PATCH 21/28] msg transfer --- Cargo.lock | 229 +++++++++++++++++++++++++--------- Cargo.toml | 5 +- crates/bindings/Cargo.toml | 2 + crates/bindings/src/lib.rs | 62 ++++++++- crates/db/Cargo.toml | 1 + crates/db/src/account.rs | 16 ++- crates/db/src/character.rs | 18 +-- crates/db/src/error.rs | 1 + crates/db/src/map.rs | 11 +- crates/db/src/npc.rs | 10 +- crates/db/src/portal.rs | 10 +- crates/db/src/realm.rs | 6 +- packets/transfer/Cargo.toml | 1 + packets/transfer/build.rs | 8 +- packets/transfer/src/lib.rs | 68 +++++----- packets/transfer/src/types.rs | 9 -- 16 files changed, 300 insertions(+), 157 deletions(-) delete mode 100644 packets/transfer/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 83bcabf..1d501d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.6" @@ -294,6 +305,18 @@ dependencies = [ "serde", ] +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -505,18 +528,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c22542c0b95bd3302f7ed6839869c561f2324bac2fd5e7e99f5cfa65fdc8b92" +checksum = "d819feeda4c420a18f1e28236ca0ce1177b22bf7c8a44ddee92dfe40de15bcf0" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3db903ef2e9c8a4de2ea6db5db052c7857282952f9df604aa55d169e6000d8" +checksum = "e9b8d03d5bdbca7e5f72b0e0a0f69933ed1f09e24be6c075aa6fe3f802b0cc0c" dependencies = [ "bumpalo", "cranelift-bforest", @@ -535,33 +558,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6590feb5a1d6438f974bf6a5ac4dddf69fca14e1f07f3265d880f69e61a94463" +checksum = "a3fd3664e38e51649b17dc30cfdd561273fe2f590dcd013fb75d9eabc6272dfb" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7239038c56fafe77fddc8788fc8533dd6c474dc5bdc5637216404f41ba807330" +checksum = "4b031ec5e605828975952622b5a77d49126f20ffe88d33719a0af66b23a0fc36" [[package]] name = "cranelift-control" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7dc9c595341404d381d27a3d950160856b35b402275f0c3990cd1ad683c8053" +checksum = "fada054d017cf2ed8f7ed2336e0517fc1b19e6825be1790de9eb00c94788362b" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44e3ee532fc4776c69bcedf7e62f9632cbb3f35776fa9a525cdade3195baa3f7" +checksum = "177b6f94ae8de6348eb45bf977c79ab9e3c40fc3ac8cb7ed8109560ea39bee7d" dependencies = [ "serde", "serde_derive", @@ -569,9 +592,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a612c94d09e653662ec37681dc2d6fd2b9856e6df7147be0afc9aabb0abf19df" +checksum = "ebebd23a69a23e3ddea78e98ff3a2de222e88c8e045d81ef4a72f042e0d79dbd" dependencies = [ "cranelift-codegen", "log", @@ -581,15 +604,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85db9830abeb1170b7d29b536ffd55af1d4d26ac8a77570b5d1aca003bf225cc" +checksum = "1571bfc14df8966d12c6121b5325026591a4b4009e22fea0fe3765ab7cd33b96" [[package]] name = "cranelift-native" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301ef0edafeaeda5771a5d2db64ac53e1818ae3111220a185677025fe91db4a1" +checksum = "35a69c37e0c10b46fe5527f2397ac821046efbf5f7ec112c8b84df25712f465b" dependencies = [ "cranelift-codegen", "libc", @@ -598,9 +621,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.103.0" +version = "0.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380f0abe8264e4570ac615fc31cef32a3b90a77f7eb97b08331f9dd357b1f500" +checksum = "9b3fef8bbceb8cb56d3f1778b0418d75c5cf12ec571a35fc01eb41abb0227a25" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -967,6 +990,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.29" @@ -1160,6 +1189,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.7", +] [[package]] name = "hashbrown" @@ -1167,7 +1199,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash", + "ahash 0.8.6", ] [[package]] @@ -1176,7 +1208,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash", + "ahash 0.8.6", "allocator-api2", ] @@ -1624,6 +1656,7 @@ dependencies = [ "bytes", "msg-connect-ex", "serde", + "thiserror", "tq-bindings", "tq-codec", "tq-crypto", @@ -1946,6 +1979,26 @@ dependencies = [ "cc", ] +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "quote" version = "1.0.33" @@ -1955,6 +2008,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -2076,6 +2135,31 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "rkyv" +version = "0.7.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527a97cdfef66f65998b5f3b637c26f5a5ec09cc52a3f9932313ac645f4190f5" +dependencies = [ + "bitvec", + "hashbrown 0.12.3", + "ptr_meta", + "rkyv_derive", + "seahash", + "tinyvec", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5c462a1328c8e67e4d6dbad1eb0355dd43e8ab432c6e227a43657f16ade5033" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "rsa" version = "0.9.6" @@ -2194,6 +2278,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "semver" version = "0.6.0" @@ -2400,7 +2490,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" dependencies = [ - "ahash", + "ahash 0.8.6", "atoi", "byteorder", "bytes", @@ -2677,6 +2767,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "target-lexicon" version = "0.12.12" @@ -2953,6 +3049,7 @@ version = "0.1.0" dependencies = [ "externref", "getrandom", + "rkyv", "tq-db", "tq-network", "tracing", @@ -2986,6 +3083,7 @@ version = "0.1.0" dependencies = [ "bcrypt", "futures", + "rkyv", "sqlx", "thiserror", "tokio-stream", @@ -3347,9 +3445,9 @@ dependencies = [ [[package]] name = "wasmtime" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e539fded2495422ea3c4dfa7beeddba45904eece182cf315294009e1a323bf" +checksum = "910fabce77e660f0e0e41cfd5f69fc8bf020a025f059718846e918db7177f469" dependencies = [ "anyhow", "async-trait", @@ -3375,23 +3473,23 @@ dependencies = [ "wasmtime-fiber", "wasmtime-jit", "wasmtime-runtime", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "wasmtime-asm-macros" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "660ba9143e15a2acd921820df221b73aee256bd3ca2d208d73d8adc9587ccbb9" +checksum = "37288142e9b4a61655a3bcbdc7316c2e4bb9e776b10ce3dd758f8186b4469572" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ce373743892002f9391c6741ef0cb0335b55ec899d874f311222b7e36f4594" +checksum = "45cbd74a636f09d2108f9405c79857f061e19323e4abeed22e837cfe7b08a22b" dependencies = [ "anyhow", "base64", @@ -3403,15 +3501,15 @@ dependencies = [ "serde_derive", "sha2", "toml 0.5.11", - "windows-sys 0.48.0", + "windows-sys 0.52.0", "zstd", ] [[package]] name = "wasmtime-component-macro" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ef32643324e564e1c359e9044daa06cbf90d7e2d6c99a738d17a12959f01a5" +checksum = "ad63de18eb42e586386b6091f787c82707cbd5ac5e9343216dba1976190cd03a" dependencies = [ "anyhow", "proc-macro2", @@ -3424,15 +3522,15 @@ dependencies = [ [[package]] name = "wasmtime-component-util" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c87d06c18d21a4818f354c00a85f4ebc62b2270961cd022968452b0e4dbed9d" +checksum = "7e0a160c0c44369aa4bee6d311a8e4366943bab1651040cc8b0fcec2c9eb8906" [[package]] name = "wasmtime-cranelift" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d648c8b4064a7911093b02237cd5569f71ca171d3a0a486bf80600b19e1cba2" +checksum = "3734cc01b7cd37bc62fdbcd9529ca9547440052d4b3886cfdec3b8081a5d3647" dependencies = [ "anyhow", "cfg-if", @@ -3455,9 +3553,9 @@ dependencies = [ [[package]] name = "wasmtime-cranelift-shared" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290a89027688782da8ff60b12bb95695494b1874e0d0ba2ba387d23dace6d70c" +checksum = "e0eb33cd30c47844aa228d4d0030587e65c1108343f311fe9f7248b5bd9cb65c" dependencies = [ "anyhow", "cranelift-codegen", @@ -3471,9 +3569,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61eb64fb3e0da883e2df4a13a81d6282e072336e6cb6295021d0f7ab2e352754" +checksum = "9a3a056b041fdea604f0972e2fae97958e7748d629a55180228348baefdfc217" dependencies = [ "anyhow", "cranelift-entity", @@ -3491,9 +3589,9 @@ dependencies = [ [[package]] name = "wasmtime-fiber" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecf1d3a838b0956b71ad3f8cb80069a228339775bf02dd35d86a5a68bbe443" +checksum = "43987d0977c07f15c3608c2f255870c127ffd19e35eeedb1ac1dccedf9932a42" dependencies = [ "anyhow", "cc", @@ -3501,14 +3599,14 @@ dependencies = [ "rustix", "wasmtime-asm-macros", "wasmtime-versioned-export-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "wasmtime-jit" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f485336add49267d8859e8f8084d2d4b9a4b1564496b6f30ba5b168d50c10ceb" +checksum = "9b3e48395ac672b386ed588d97a9612aa13a345008f26466f0dfb2a91628aa9f" dependencies = [ "anyhow", "bincode", @@ -3523,25 +3621,25 @@ dependencies = [ "wasmtime-environ", "wasmtime-jit-icache-coherence", "wasmtime-runtime", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "wasmtime-jit-icache-coherence" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b6d197fcc34ad32ed440e1f9552fd57d1f377d9699d31dee1b5b457322c1f8a" +checksum = "bdc26415bb89e9ccd3bdc498fef63aabf665c4c0dd710c107691deb9694955da" dependencies = [ "cfg-if", "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "wasmtime-runtime" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794b2bb19b99ef8322ff0dd9fe1ba7e19c41036dfb260b3f99ecce128c42ff92" +checksum = "0abddaf17912aabaf39be0802d5eba9a002e956e902d1ebd438a2fe1c88769a2" dependencies = [ "anyhow", "cc", @@ -3562,14 +3660,14 @@ dependencies = [ "wasmtime-fiber", "wasmtime-versioned-export-macros", "wasmtime-wmemcheck", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "wasmtime-types" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d995db8bb56f2cd8d2dc0ed5ffab94ffb435283b0fe6747f80f7aab40b2d06a1" +checksum = "b35a95cdc1433729085beab42c0a5c742b431f25b17c40d7718e46df63d5ffc7" dependencies = [ "cranelift-entity", "serde", @@ -3580,9 +3678,9 @@ dependencies = [ [[package]] name = "wasmtime-versioned-export-macros" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c5565959287c21dd0f4277ae3518dd2ae62679f655ee2dbc4396e19d210db" +checksum = "fad322733fe67e45743784d8b1df452bcb54f581572a4f1a646a4332deecbcc2" dependencies = [ "proc-macro2", "quote", @@ -3591,9 +3689,9 @@ dependencies = [ [[package]] name = "wasmtime-wit-bindgen" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f328b2d4a690270324756e886ed5be3a4da4c00be0eea48253f4595ad068062b" +checksum = "41e5675998fdc74495afdd90ad2bd221206a258075b23048af0535a969b07893" dependencies = [ "anyhow", "heck 0.4.1", @@ -3603,9 +3701,9 @@ dependencies = [ [[package]] name = "wasmtime-wmemcheck" -version = "16.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67761d8f8c0b3c13a5d34356274b10a40baba67fe9cfabbfc379a8b414e45de2" +checksum = "b20a19e10d8cb50b45412fb21192982b7ce85c0122dc33bb71f1813e25dc6e52" [[package]] name = "webpki-roots" @@ -3808,6 +3906,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "zerocopy" version = "0.7.31" diff --git a/Cargo.toml b/Cargo.toml index e0cfc73..fa72461 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ tq-serde = { path = "crates/serde" } tq-math = { path = "crates/math" } tq-crypto = { path = "crates/crypto" } tq-codec = { path = "crates/codec" } -tq-db = { path = "crates/db" } +tq-db = { path = "crates/db", default-features = false } tq-server = { path = "crates/server" } tq-bindings = { path = "crates/bindings" } tq-wasm-builder = { path = "crates/wasm-builder" } @@ -68,13 +68,14 @@ atomic = { version = "0.6", default-features = false } bytemuck = { version = "1.13", default-features = false, features = ["derive"] } chrono = { version = "0.4", default-features = false, features = [] } num_enum = { version = "0.7", default-features = false } +rkyv = { version = "0.7", default-features = false } bcrypt = "0.15" # WASM deps externref = { version = "0.2.0", default-features = false } [workspace.dependencies.wasmtime] -version = "16.0.0" +version = "17.0.0" default-features = false [workspace.dependencies.tokio] diff --git a/crates/bindings/Cargo.toml b/crates/bindings/Cargo.toml index e8060f7..7c80578 100644 --- a/crates/bindings/Cargo.toml +++ b/crates/bindings/Cargo.toml @@ -7,12 +7,14 @@ edition.workspace = true tq-network.workspace = true tracing-wasm.workspace = true tq-db = { workspace = true, default-features = false } +rkyv = { workspace = true, default-features = false, features = ["alloc", "size_32"] } tracing = { workspace = true, default-features = false, optional = true } tracing-subscriber = { workspace = true, default-features = false, features = ["alloc"], optional = true } externref = { workspace = true, default-features = false, features = ["macro"] } getrandom = { workspace = true, default-features = false, features = ["custom"] } + [features] default = ["std"] std = ["tq-network/std", "tracing-wasm/std", "dep:tracing", "dep:tracing-subscriber"] diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs index 7c288c7..c45fcc5 100644 --- a/crates/bindings/src/lib.rs +++ b/crates/bindings/src/lib.rs @@ -76,6 +76,13 @@ extern "C" { account_id: u32, realm_id: u32, ) -> u64; + + fn auth_server_bus_check(realm_ptr: *const u8, realm_len: u32) -> i32; + fn auth_server_bus_transfer( + actor: &Resource, + realm_ptr: *const u8, + realm_len: u32, + ) -> u64; } /// Host bindings. @@ -115,6 +122,7 @@ pub mod host { pub mod db { /// [`tq_db::realm`] bindings. pub mod realm { + use rkyv::Deserialize; use tq_db::realm::Realm; /// [`tq_db::realm::Realm::by_name`] bindings. pub fn by_name( @@ -132,13 +140,12 @@ pub mod host { }; if res == 0 && realm_len > 0 && !realm.is_null() { let realm = unsafe { - let bytes = std::vec::Vec::from_raw_parts( + let bytes = core::slice::from_raw_parts( realm, realm_len as usize, - realm_len as usize, ); - // Does not work! - core::mem::transmute(bytes) + let archived = rkyv::archived_root::(bytes); + archived.deserialize(&mut rkyv::Infallible).unwrap() }; Ok(Some(realm)) } else { @@ -168,6 +175,53 @@ pub mod host { } } + /// [`auth`] bindings. + pub mod auth { + /// [`auth::server_bus`] bindings. + pub mod server_bus { + use externref::Resource; + use tq_db::realm::Realm; + + /// [`auth::server_bus::check`] bindings. + pub fn check(realm: &Realm) -> Result<(), tq_network::Error> { + let archived = rkyv::to_bytes::<_, 64>(realm).unwrap(); + let res = unsafe { + crate::auth_server_bus_check( + archived.as_ptr(), + archived.len() as u32, + ) + }; + if res == 0 { + Ok(()) + } else { + Err(tq_network::Error::Other(String::from("Server Down"))) + } + } + + /// [`auth::server_bus::transfer`] bindings. + pub fn transfer( + actor: &Resource, + realm: &Realm, + ) -> Result { + let archived = rkyv::to_bytes::<_, 64>(realm).unwrap(); + let token = unsafe { + crate::auth_server_bus_transfer( + actor, + archived.as_ptr(), + archived.len() as u32, + ) + }; + if token == 0 { + Err(tq_network::Error::Other(String::from( + "Server Timed Out", + ))) + } else { + Ok(token) + } + } + } + } + /// Get random bytes. pub fn getrandom(buf: &mut [u8]) -> Result<(), getrandom::Error> { let res = unsafe { super::getrandom(buf.as_mut_ptr(), buf.len()) }; diff --git a/crates/db/Cargo.toml b/crates/db/Cargo.toml index 91c6e3b..a355b74 100644 --- a/crates/db/Cargo.toml +++ b/crates/db/Cargo.toml @@ -10,6 +10,7 @@ thiserror.workspace = true tokio-stream.workspace = true tracing.workspace = true futures.workspace = true +rkyv = { workspace = true, default-features = false, features = ["alloc", "size_32"] } # Database [dependencies.sqlx] diff --git a/crates/db/src/account.rs b/crates/db/src/account.rs index 128fc35..0102634 100644 --- a/crates/db/src/account.rs +++ b/crates/db/src/account.rs @@ -1,6 +1,3 @@ -use crate::Error; -use futures::TryFutureExt; - /// Account information for a registered player. The account server uses this /// information to authenticate the player on login. Passwords are hashed using /// bcrypt @@ -20,7 +17,7 @@ impl Account { pool: &sqlx::SqlitePool, username: &str, password: &str, - ) -> Result { + ) -> Result { let maybe_account = sqlx::query_as::<_, Self>( "SELECT * FROM accounts WHERE username = ?;", ) @@ -33,10 +30,10 @@ impl Account { if matched { Ok(account) } else { - Err(Error::InvalidPassword) + Err(crate::Error::InvalidPassword) } }, - None => Err(Error::AccountNotFound), + None => Err(crate::Error::AccountNotFound), } } @@ -47,7 +44,8 @@ impl Account { pool: &sqlx::SqlitePool, limit: Option, offset: Option, - ) -> Result, Error> { + ) -> Result, crate::Error> { + use futures::TryFutureExt; sqlx::query_as::<_, Self>("SELECT * FROM accounts LIMIT ? OFFSET ?;") .bind(limit.unwrap_or(100)) .bind(offset.unwrap_or(0)) @@ -62,7 +60,7 @@ impl Account { pub async fn create( mut self, pool: &sqlx::SqlitePool, - ) -> Result { + ) -> Result { let password = bcrypt::hash(&self.password, bcrypt::DEFAULT_COST)?; let res = sqlx::query( "INSERT INTO accounts (username, password, name, email) VALUES (?, ?, ?, ?);", @@ -74,7 +72,7 @@ impl Account { .execute(pool) .await?; if res.rows_affected() == 0 { - Err(Error::CreateAccountFailed) + Err(crate::Error::CreateAccountFailed) } else { self.account_id = res.last_insert_rowid() as i32; Ok(self) diff --git a/crates/db/src/character.rs b/crates/db/src/character.rs index 1696845..2612d30 100644 --- a/crates/db/src/character.rs +++ b/crates/db/src/character.rs @@ -1,5 +1,3 @@ -use crate::Error; - /// This struct encapsulates the game character for a player. The player /// controls the character as the protagonist of the Conquer Online storyline. /// The character is the persona of the player who controls it. The persona can @@ -49,7 +47,7 @@ impl Character { pub async fn from_account( pool: &sqlx::SqlitePool, id: u32, - ) -> Result, Error> { + ) -> Result, crate::Error> { let maybe_character = sqlx::query_as::<_, Self>( "SELECT * FROM characters WHERE account_id = ?;", ) @@ -62,7 +60,7 @@ impl Character { pub async fn name_taken( pool: &sqlx::SqlitePool, name: &str, - ) -> Result { + ) -> Result { let result = sqlx::query_as::<_, (i32,)>( "SELECT EXISTS (SELECT 1 FROM characters WHERE name = ? LIMIT 1);", ) @@ -80,7 +78,7 @@ impl Character { pub async fn by_id( pool: &sqlx::SqlitePool, id: i32, - ) -> Result { + ) -> Result { let c = sqlx::query_as::<_, Self>( "SELECT * FROM characters WHERE character_id = ?;", ) @@ -90,7 +88,10 @@ impl Character { Ok(c) } - pub async fn save(self, pool: &sqlx::SqlitePool) -> Result { + pub async fn save( + self, + pool: &sqlx::SqlitePool, + ) -> Result { let (id,) = sqlx::query_as::<_, (i32,)>( " INSERT INTO characters @@ -132,7 +133,10 @@ impl Character { Ok(id) } - pub async fn update(self, pool: &sqlx::SqlitePool) -> Result<(), Error> { + pub async fn update( + self, + pool: &sqlx::SqlitePool, + ) -> Result<(), crate::Error> { sqlx::query( " UPDATE characters diff --git a/crates/db/src/error.rs b/crates/db/src/error.rs index d2521cf..36fa346 100644 --- a/crates/db/src/error.rs +++ b/crates/db/src/error.rs @@ -1,5 +1,6 @@ #[derive(Debug, thiserror::Error)] pub enum Error { + #[cfg(feature = "sqlx")] #[error(transparent)] Db(#[from] sqlx::Error), #[error(transparent)] diff --git a/crates/db/src/map.rs b/crates/db/src/map.rs index 6213cff..0981f90 100644 --- a/crates/db/src/map.rs +++ b/crates/db/src/map.rs @@ -1,6 +1,3 @@ -use crate::Error; -use tokio_stream::StreamExt; - #[derive(Debug, Clone, Default)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Map { @@ -19,7 +16,11 @@ pub struct Map { impl Map { /// Loads all maps from the database to add them to the state. #[tracing::instrument] - pub async fn load_all(pool: &sqlx::SqlitePool) -> Result, Error> { + pub async fn load_all( + pool: &sqlx::SqlitePool, + ) -> Result, crate::Error> { + use tokio_stream::StreamExt; + let mut maps = Vec::new(); let mut s = sqlx::query_as::<_, Self>("SELECT * FROM maps;").fetch(pool); @@ -40,7 +41,7 @@ impl Map { pub async fn load( pool: &sqlx::SqlitePool, id: i32, - ) -> Result, Error> { + ) -> Result, crate::Error> { let maybe_map = sqlx::query_as::<_, Self>("SELECT * FROM maps WHERE id = ?;") .bind(id) diff --git a/crates/db/src/npc.rs b/crates/db/src/npc.rs index b6af3ba..384c8b4 100644 --- a/crates/db/src/npc.rs +++ b/crates/db/src/npc.rs @@ -1,7 +1,3 @@ -use crate::Error; -use sqlx::SqlitePool; -use tokio_stream::StreamExt; - #[derive(Debug, Clone, Default)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Npc { @@ -24,9 +20,11 @@ pub struct Npc { impl Npc { #[tracing::instrument] pub async fn by_map( - pool: &SqlitePool, + pool: &sqlx::SqlitePool, id: i32, - ) -> Result, Error> { + ) -> Result, crate::Error> { + use tokio_stream::StreamExt; + let mut npcs = Vec::new(); let mut s = sqlx::query_as::<_, Self>("SELECT * FROM npcs WHERE map_id = ?;") diff --git a/crates/db/src/portal.rs b/crates/db/src/portal.rs index 5b42257..ed11304 100644 --- a/crates/db/src/portal.rs +++ b/crates/db/src/portal.rs @@ -1,7 +1,3 @@ -use crate::Error; -use sqlx::SqlitePool; -use tokio_stream::StreamExt; - #[derive(Debug, Clone, Default)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Portal { @@ -18,9 +14,11 @@ pub struct Portal { impl Portal { #[tracing::instrument] pub async fn by_map( - pool: &SqlitePool, + pool: &sqlx::SqlitePool, from: i32, - ) -> Result, Error> { + ) -> Result, crate::Error> { + use tokio_stream::StreamExt; + let mut portals = Vec::new(); let mut s = sqlx::query_as::<_, Self>( "SELECT * FROM portals WHERE from_map_id = ?;", diff --git a/crates/db/src/realm.rs b/crates/db/src/realm.rs index da3d3c4..593242b 100644 --- a/crates/db/src/realm.rs +++ b/crates/db/src/realm.rs @@ -1,9 +1,7 @@ -use crate::Error; - /// Realms are configured instances of the game server. This struct defines /// routing details for authenticated clients to be redirected to. Redirection /// involves access token leasing, provided by the game server via RPC. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Realm { pub realm_id: i32, @@ -17,7 +15,7 @@ impl Realm { pub async fn by_name( pool: &sqlx::SqlitePool, name: &str, - ) -> Result, Error> { + ) -> Result, crate::Error> { let realm = sqlx::query_as::<_, Self>("SELECT * FROM realms WHERE name = ?;") .bind(name) diff --git a/packets/transfer/Cargo.toml b/packets/transfer/Cargo.toml index 41bf7ab..bdf3ea7 100644 --- a/packets/transfer/Cargo.toml +++ b/packets/transfer/Cargo.toml @@ -14,6 +14,7 @@ tq-db = { workspace = true, default-features = false } serde.workspace = true tracing.workspace = true bytes.workspace = true +thiserror.workspace = true msg-connect-ex.workspace = true diff --git a/packets/transfer/build.rs b/packets/transfer/build.rs index 58aceb1..ae2767a 100644 --- a/packets/transfer/build.rs +++ b/packets/transfer/build.rs @@ -1,8 +1,8 @@ use tq_wasm_builder::WasmBuilder; fn main() { - // WasmBuilder::selector() - // .with_current_project() - // .enable_feature("std") - // .build(); + WasmBuilder::selector() + .with_current_project() + .enable_feature("std") + .build(); } diff --git a/packets/transfer/src/lib.rs b/packets/transfer/src/lib.rs index a3777c3..a9774eb 100644 --- a/packets/transfer/src/lib.rs +++ b/packets/transfer/src/lib.rs @@ -3,7 +3,7 @@ #[cfg(not(feature = "std"))] extern crate alloc; -// include!(concat!(env!("OUT_DIR"), "/wasm.rs")); +include!(concat!(env!("OUT_DIR"), "/wasm.rs")); use msg_connect_ex::{AccountCredentials, RejectionCode}; use serde::{Deserialize, Serialize}; @@ -28,38 +28,35 @@ impl MsgTransfer { actor: &Resource, realm: &str, ) -> Result { - let maybe_realm = host::realm_by_name(realm)?; + let maybe_realm = host::db::realm::by_name(realm)?; // Check if there is a realm with that name let realm = match maybe_realm { Some(realm) => realm, None => { - return Err(RejectionCode::TryAgainLater + return Err(RejectionCode::ServerLocked .packet() .error_packet() .into()); }, }; // Try to connect to that realm first. - if let Err(e) = host::server_bus_check(&realm) { + if let Err(e) = host::auth::server_bus::check(&realm) { tracing::error!( ip = realm.game_ip_address, port = realm.game_port, - realm_id = realm.id, + realm_id = realm.realm_id, error = ?e, "Failed to connect to realm" ); - host::send(actor, RejectionCode::ServerDown.packet())?; - host::shutdown(actor); - return Err(e); + host::network::actor::send( + actor, + RejectionCode::ServerDown.packet(), + )?; + host::network::actor::shutdown(actor); + return Err(e.into()); } - Self::transfer(actor, realm) - } - fn transfer( - actor: &Resource, - realm: tq_db::realm::Realm, - ) -> Result { - let res = host::server_bus_transfer(actor, &realm); + let res = host::auth::server_bus::transfer(actor, &realm); match res { Ok(token) => Ok(AccountCredentials { token, @@ -84,37 +81,24 @@ impl MsgTransfer { } /// Possible errors that can occur while processing a packet. -#[derive(Debug, Clone)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// Failed to generate a login token. + #[error("Failed to generate login token")] TokenGenerationFailed, /// The realm is unavailable. + #[error("Realm unavailable")] RealmUnavailable, /// Internal Network error. - Network(tq_network::Error), + #[error(transparent)] + Network(#[from] tq_network::Error), + #[error(transparent)] + Db(#[from] tq_db::Error), + #[error("Error packet: {0:?}")] /// An error packet to be sent to the client. Msg(u16, bytes::Bytes), } -impl core::fmt::Display for Error { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::TokenGenerationFailed => { - write!(f, "Failed to generate a login token") - }, - Self::RealmUnavailable => write!(f, "Realm is unavailable"), - Self::Network(e) => write!(f, "Network error: {}", e), - Self::Msg(id, body) => { - write!(f, "Error packet: id = {}, body = {:?}", id, body) - }, - } - } -} - -impl From for Error { - fn from(e: tq_network::Error) -> Self { Self::Network(e) } -} - impl From> for Error { fn from(v: ErrorPacket) -> Self { let (id, bytes) = v.0.encode().unwrap(); @@ -123,17 +107,21 @@ impl From> for Error { } #[tq_network::packet_processor(MsgTransfer)] -fn process( +pub fn process( msg: MsgTransfer, actor: &Resource, ) -> Result<(), crate::Error> { - let token = host::generate_login_token(actor, msg.account_id, msg.realm_id); + let token = host::game::state::generate_login_token( + actor, + msg.account_id, + msg.realm_id, + ); let msg = MsgTransfer { account_id: msg.account_id, realm_id: msg.realm_id, token, }; - host::send(&actor, msg)?; - host::shutdown(&actor); + host::network::actor::send(actor, msg)?; + host::network::actor::shutdown(actor); Ok(()) } diff --git a/packets/transfer/src/types.rs b/packets/transfer/src/types.rs deleted file mode 100644 index 968ff85..0000000 --- a/packets/transfer/src/types.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[cfg(not(feature = "std"))] -use alloc::string::String; - -pub struct Realm { - pub id: u32, - pub name: String, - pub game_ip_address: String, - pub game_port: u16, -} From 4aadc2bbd86651a8cd1e9818767c86ab2997eb7e Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sat, 27 Jan 2024 23:05:35 +0200 Subject: [PATCH 22/28] msg account --- .vscode/settings.json | 8 ++ Cargo.lock | 21 ++++ Cargo.toml | 4 +- crates/bindings/.cargo/config.toml | 2 + crates/bindings/src/lib.rs | 109 ++++++++++++++++- macros/derive-packetprocessor/src/lib.rs | 4 +- packets/account/Cargo.toml | 10 ++ packets/account/build.rs | 8 ++ packets/account/src/functions.rs | 1 - packets/account/src/lib.rs | 126 ++++++++------------ packets/account/src/traits.rs | 13 -- packets/account/src/types.rs | 1 - server/auth/Cargo.toml | 12 +- server/auth/src/lib.rs | 9 +- server/auth/src/linker.rs | 144 +++++++++++++++++------ 15 files changed, 327 insertions(+), 145 deletions(-) create mode 100644 crates/bindings/.cargo/config.toml create mode 100644 packets/account/build.rs delete mode 100644 packets/account/src/functions.rs delete mode 100644 packets/account/src/traits.rs delete mode 100644 packets/account/src/types.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index d42c92b..14d432e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,14 @@ "rust-analyzer.lens.references.adt.enable": true, "rust-analyzer.lens.references.method.enable": true, "rust-analyzer.lens.implementations.enable": true, + "rust-analyzer.check.allTargets": true, + "rust-analyzer.checkOnSave": true, + "rust-analyzer.check.targets": [ + "x86_64-unknown-linux-gnu", + "x86_64-pc-windows-msvc", + "aarch64-apple-darwin", + "wasm32-unknown-unknown" + ], "sqltools.useNodeRuntime": true, "sqltools.connections": [ { diff --git a/Cargo.lock b/Cargo.lock index 1d501d2..9307eb8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,8 +174,10 @@ dependencies = [ "bytes", "dotenvy", "futures", + "msg-account", "msg-connect", "num_enum", + "rand", "serde", "sqlx", "thiserror", @@ -1625,6 +1627,25 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "msg-account" +version = "0.1.0" +dependencies = [ + "bytes", + "msg-connect-ex", + "msg-transfer", + "serde", + "thiserror", + "tq-bindings", + "tq-codec", + "tq-crypto", + "tq-db", + "tq-network", + "tq-serde", + "tq-wasm-builder", + "tracing", +] + [[package]] name = "msg-connect" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index fa72461..616a3df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ members = [ # Cli Tools "tools/*", ] -exclude = ["packets/account", "tools/benchbot"] +exclude = ["tools/benchbot"] [workspace.dependencies] # Local Dependencies @@ -42,7 +42,7 @@ auth = { path = "server/auth" } game = { path = "server/game" } # Packets -# msg-account = { path = "packets/account" } +msg-account = { path = "packets/account" } msg-connect-ex = { path = "packets/connect-ex" } msg-connect = { path = "packets/connect" } msg-transfer = { path = "packets/transfer" } diff --git a/crates/bindings/.cargo/config.toml b/crates/bindings/.cargo/config.toml new file mode 100644 index 0000000..f4e8c00 --- /dev/null +++ b/crates/bindings/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "wasm32-unknown-unknown" diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs index c45fcc5..bffe52a 100644 --- a/crates/bindings/src/lib.rs +++ b/crates/bindings/src/lib.rs @@ -54,6 +54,7 @@ pub fn set_panic_hook_once(_name: &'static str) {} #[externref(crate = "crate::anyref")] #[link(wasm_import_module = "host")] +#[cfg(target_arch = "wasm32")] extern "C" { fn getrandom(ptr: *mut u8, len: usize) -> i32; fn tq_network_actor_shutdown(actor: &Resource); @@ -64,6 +65,11 @@ extern "C" { packet_data_len: u32, ); + fn tq_network_actor_set_id( + actor: &Resource, + id: u32, + ); + fn tq_db_realm_by_name( realm_name_ptr: *const u8, realm_name_len: u32, @@ -71,6 +77,13 @@ extern "C" { out_realm_len: *mut u32, ) -> i32; + fn tq_db_account_auth( + username_ptr: *const u8, + username_len: u32, + password_ptr: *const u8, + password_len: u32, + ) -> i32; + fn game_state_generate_login_token( actor: &Resource, account_id: u32, @@ -95,11 +108,18 @@ pub mod host { pub mod actor { use crate::Resource; use tq_network::ActorHandle; + /// [`tq_network::actor::ActorHandle::shutdown`] bindings. + #[cfg(target_arch = "wasm32")] pub fn shutdown(actor: &Resource) { unsafe { crate::tq_network_actor_shutdown(actor) } } + + #[cfg(not(target_arch = "wasm32"))] + pub fn shutdown(_actor: &Resource) {} + /// [`tq_network::actor::ActorHandle::send`] bindings. + #[cfg(target_arch = "wasm32")] pub fn send( actor: &Resource, packet: T, @@ -115,19 +135,72 @@ pub mod host { } Ok(()) } + #[cfg(not(target_arch = "wasm32"))] + pub fn send( + _actor: &Resource, + _packet: T, + ) -> Result<(), T::Error> { + Ok(()) + } + /// [`tq_network::actor::ActorHandle::set_id`] bindings. + #[cfg(target_arch = "wasm32")] + pub fn set_id(actor: &Resource, id: u32) { + unsafe { crate::tq_network_actor_set_id(actor, id) } + } + + #[cfg(not(target_arch = "wasm32"))] + pub fn set_id(_actor: &Resource, _id: u32) {} } } /// [`tq_db`] bindings. pub mod db { + /// [`tq_db::account`] bindings. + pub mod account { + /// [`tq_db::account::Account::auth`] bindings. + #[cfg(target_arch = "wasm32")] + pub fn auth( + username: &str, + password: &str, + ) -> Result { + let res = unsafe { + crate::tq_db_account_auth( + username.as_ptr(), + username.len() as u32, + password.as_ptr(), + password.len() as u32, + ) + }; + if res > 0 { + Ok(res as u32) + } else { + match res { + -1 => Err(tq_db::Error::AccountNotFound), + -2 => Err(tq_db::Error::InvalidPassword), + _ => unreachable!("Unknown error code"), + } + } + } + + #[cfg(not(target_arch = "wasm32"))] + pub fn auth( + _username: &str, + _password: &str, + ) -> Result { + unimplemented!("Not implemented on non-wasm32") + } + } + /// [`tq_db::realm`] bindings. pub mod realm { - use rkyv::Deserialize; use tq_db::realm::Realm; /// [`tq_db::realm::Realm::by_name`] bindings. + #[cfg(target_arch = "wasm32")] pub fn by_name( realm_name: &str, ) -> Result, tq_db::Error> { + use rkyv::Deserialize; + let realm = core::ptr::null_mut(); let mut realm_len = 0; let res = unsafe { @@ -152,6 +225,13 @@ pub mod host { Ok(None) } } + + #[cfg(not(target_arch = "wasm32"))] + pub fn by_name( + _realm_name: &str, + ) -> Result, tq_db::Error> { + unimplemented!("Not implemented on non-wasm32") + } } } /// [`game`] bindings. @@ -161,6 +241,7 @@ pub mod host { use crate::Resource; use tq_network::ActorHandle; /// [`game::state::generate_login_token`] bindings. + #[cfg(target_arch = "wasm32")] pub fn generate_login_token( actor: &Resource, account_id: u32, @@ -172,6 +253,15 @@ pub mod host { ) } } + + #[cfg(not(target_arch = "wasm32"))] + pub fn generate_login_token( + _actor: &Resource, + _account_id: u32, + _realm_id: u32, + ) -> u64 { + unimplemented!("Not implemented on non-wasm32") + } } } @@ -183,6 +273,7 @@ pub mod host { use tq_db::realm::Realm; /// [`auth::server_bus::check`] bindings. + #[cfg(target_arch = "wasm32")] pub fn check(realm: &Realm) -> Result<(), tq_network::Error> { let archived = rkyv::to_bytes::<_, 64>(realm).unwrap(); let res = unsafe { @@ -198,7 +289,13 @@ pub mod host { } } + #[cfg(not(target_arch = "wasm32"))] + pub fn check(_realm: &Realm) -> Result<(), tq_network::Error> { + unimplemented!("Not implemented on non-wasm32") + } + /// [`auth::server_bus::transfer`] bindings. + #[cfg(target_arch = "wasm32")] pub fn transfer( actor: &Resource, realm: &Realm, @@ -219,10 +316,19 @@ pub mod host { Ok(token) } } + + #[cfg(not(target_arch = "wasm32"))] + pub fn transfer( + _actor: &Resource, + _realm: &Realm, + ) -> Result { + unimplemented!("Not implemented on non-wasm32") + } } } /// Get random bytes. + #[cfg(target_arch = "wasm32")] pub fn getrandom(buf: &mut [u8]) -> Result<(), getrandom::Error> { let res = unsafe { super::getrandom(buf.as_mut_ptr(), buf.len()) }; if res == 0 { @@ -233,4 +339,5 @@ pub mod host { } } +#[cfg(target_arch = "wasm32")] getrandom::register_custom_getrandom!(host::getrandom); diff --git a/macros/derive-packetprocessor/src/lib.rs b/macros/derive-packetprocessor/src/lib.rs index cfe6f44..c224c0e 100644 --- a/macros/derive-packetprocessor/src/lib.rs +++ b/macros/derive-packetprocessor/src/lib.rs @@ -81,9 +81,9 @@ fn derive_packet_processor( let msg_ty_name = msg_ty.to_string().to_lowercase(); // Build the output, possibly using quasi-quotation let expanded = quote! { - #[export_name = "alloc_packet"] + #[export_name = "__alloc"] #[cfg(target_arch = "wasm32")] - pub extern "C" fn alloc_packet(size: u32) -> *mut u8 { + pub extern "C" fn __alloc(size: u32) -> *mut u8 { #[cfg(not(feature = "std"))] let v = ::alloc::vec::Vec::with_capacity(size as usize); #[cfg(feature = "std")] diff --git a/packets/account/Cargo.toml b/packets/account/Cargo.toml index dc141c8..a5edd7e 100644 --- a/packets/account/Cargo.toml +++ b/packets/account/Cargo.toml @@ -8,13 +8,22 @@ tq-serde.workspace = true tq-codec.workspace = true tq-crypto.workspace = true tq-network.workspace = true +tq-bindings.workspace = true +tq-db = { workspace = true, default-features = false } + serde.workspace = true +bytes.workspace = true tracing.workspace = true +thiserror.workspace = true + msg-connect-ex.workspace = true msg-transfer.workspace = true +[build-dependencies] +tq-wasm-builder.workspace = true + [features] default = ["std"] std = [ @@ -22,6 +31,7 @@ std = [ "tq-codec/std", "tq-crypto/std", "tq-network/std", + "tq-bindings/std", "tracing/std", diff --git a/packets/account/build.rs b/packets/account/build.rs new file mode 100644 index 0000000..ae2767a --- /dev/null +++ b/packets/account/build.rs @@ -0,0 +1,8 @@ +use tq_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::selector() + .with_current_project() + .enable_feature("std") + .build(); +} diff --git a/packets/account/src/functions.rs b/packets/account/src/functions.rs deleted file mode 100644 index 8b13789..0000000 --- a/packets/account/src/functions.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packets/account/src/lib.rs b/packets/account/src/lib.rs index 9080bc5..6ea3613 100644 --- a/packets/account/src/lib.rs +++ b/packets/account/src/lib.rs @@ -1,21 +1,22 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(not(feature = "std"))] +extern crate alloc; + +include!(concat!(env!("OUT_DIR"), "/wasm.rs")); + use msg_connect_ex::{MsgConnectEx, RejectionCode}; use msg_transfer::MsgTransfer; use serde::Deserialize; +use tq_bindings::{host, Resource}; use tq_network::PacketID; use tq_serde::{String16, TQPassword}; -use tq_system::ActorHandle; -pub use traits::Authanticator; - -mod functions; -mod traits; -mod types; +use tq_network::ActorHandle; #[derive(Debug, Deserialize, PacketID)] #[packet(id = 1051)] -pub struct MsgAccount { +pub struct MsgAccount { pub username: String16, pub password: TQPassword, pub realm: String16, @@ -23,81 +24,56 @@ pub struct MsgAccount { pub rejection_code: u32, #[serde(skip)] pub account_id: i32, - #[serde(skip)] - _config: core::marker::PhantomData, -} - -pub trait Config: msg_transfer::Config { - /// The type of the authanticator used to authanticate accounts. - type Authanticator: Authanticator; -} - -impl tq_system::ProcessPacket for MsgAccount { - type Error = Error; - - fn process(&self, actor: ActorHandle) -> Result<(), Self::Error> { - let maybe_accont_id = - T::Authanticator::auth(&self.username, &self.password); - let account_id = match maybe_accont_id { - Ok(id) => id, - Err(e) => { - let res = match e { - Error::InvalidUsernameOrPassword => { - RejectionCode::InvalidPassword.packet() - }, - _ => { - tracing::error!("Error authenticating account: {e}"); - RejectionCode::TryAgainLater.packet() - }, - }; - T::send(&actor, res)?; - return Ok(()); - }, - }; - actor.set_id(account_id as usize); - let res = match MsgTransfer::::handle(&actor, &self.realm) { - Ok(res) => res, - _ => { - tracing::warn!( - %account_id, - "Failed to transfer account" - ); - return Ok(()); - }, - }; - let res = MsgConnectEx::forword_connection(res); - T::send(&actor, res)?; - Ok(()) - } } /// Possible errors that can occur while processing a packet. -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// User has entered an invalid username or password. + #[error("Invalid username or password")] InvalidUsernameOrPassword, /// Internal Network error. - Network(tq_network::Error), -} - -impl core::fmt::Display for Error { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::InvalidUsernameOrPassword => { - write!(f, "Invalid username or password") - }, - Self::Network(e) => write!(f, "Network error: {}", e), - } - } + #[error(transparent)] + Network(#[from] tq_network::Error), + #[error(transparent)] + Db(#[from] tq_db::Error), } -impl From for Error { - fn from(e: tq_network::Error) -> Self { Self::Network(e) } -} - -#[cfg(test)] -mod tests { - - #[test] - fn it_works() {} +#[tq_network::packet_processor(MsgAccount)] +pub fn process( + msg: MsgAccount, + actor: &Resource, +) -> Result<(), crate::Error> { + let maybe_accont_id = host::db::account::auth(&msg.username, &msg.password); + let account_id = match maybe_accont_id { + Ok(id) => id, + Err(e) => { + let res = match e { + tq_db::Error::AccountNotFound + | tq_db::Error::InvalidPassword => { + RejectionCode::InvalidPassword.packet() + }, + _ => { + tracing::error!("Error authenticating account: {e}"); + RejectionCode::TryAgainLater.packet() + }, + }; + host::network::actor::send(actor, res)?; + return Ok(()); + }, + }; + host::network::actor::set_id(actor, account_id); + let res = match MsgTransfer::handle(actor, &msg.realm) { + Ok(res) => res, + _ => { + tracing::warn!( + %account_id, + "Failed to transfer account" + ); + return Ok(()); + }, + }; + let res = MsgConnectEx::forword_connection(res); + host::network::actor::send(actor, res)?; + Ok(()) } diff --git a/packets/account/src/traits.rs b/packets/account/src/traits.rs deleted file mode 100644 index 8fc16b1..0000000 --- a/packets/account/src/traits.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub trait Authanticator { - fn auth(username: &str, password: &str) -> Result; -} - -// A dummy authanticator that always rejects the login attempt. -impl Authanticator for () { - fn auth( - _username: &str, - _password: &str, - ) -> Result { - Err(crate::Error::InvalidUsernameOrPassword) - } -} diff --git a/packets/account/src/types.rs b/packets/account/src/types.rs deleted file mode 100644 index 8b13789..0000000 --- a/packets/account/src/types.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/server/auth/Cargo.toml b/server/auth/Cargo.toml index e3bc2ce..b057040 100644 --- a/server/auth/Cargo.toml +++ b/server/auth/Cargo.toml @@ -26,11 +26,10 @@ dotenvy.workspace = true tokio-stream.workspace = true num_enum.workspace = true futures.workspace = true +rand.workspace = true # Packets -# msg-account.workspace = true -# msg-transfer.workspace = true -# msg-connect-ex.workspace = true +msg-account.workspace = true msg-connect.workspace = true @@ -72,11 +71,10 @@ default = [] server = [ "tq-network/std", "tq-serde/std", - # "msg-account/std", - # "msg-transfer/std", - # "msg-connect-ex/std", + "msg-account/std", + "msg-connect/std", "dep:tokio", "dep:tq-server", "sqlx/runtime-tokio", - "dep:tracing-subscriber" + "dep:tracing-subscriber", ] diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index 2b26dee..7d10abd 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -31,7 +31,7 @@ impl PacketHandler for Runtime { runtime: &Self::State, actor: &Actor, ) -> Result<(), Self::Error> { - const ALLOC_PACKET: &str = "alloc_packet"; + const ALLOC: &str = "__alloc"; const PROCESS_PACKET: &str = "process_packet"; const MEMORY: &str = "memory"; let mut store = @@ -45,7 +45,7 @@ impl PacketHandler for Runtime { .instantiate_async(&mut store, &runtime.packets.msg_connect) .await?; let alloc_packet = msg_connect - .get_typed_func::(&mut store, ALLOC_PACKET)?; + .get_typed_func::(&mut store, ALLOC)?; let ptr = alloc_packet .call_async(&mut store, packet_len as u32) .await?; @@ -80,9 +80,10 @@ impl PacketHandler for Runtime { pub fn add_to_linker( linker: &mut Linker, ) -> Result<(), error::Error> { - linker::actor::shutdown(linker)?; - linker::actor::send(linker)?; + linker::network::actor::shutdown(linker)?; + linker::network::actor::send(linker)?; linker::log::trace_event(linker)?; + linker::rand::getrandom(linker)?; Ok(()) } diff --git a/server/auth/src/linker.rs b/server/auth/src/linker.rs index 322c213..35b3c76 100644 --- a/server/auth/src/linker.rs +++ b/server/auth/src/linker.rs @@ -21,63 +21,129 @@ macro_rules! mread { }}; } -pub mod actor { - use super::*; - use wasmtime::ExternRef; +macro_rules! mread_mut { + ($caller:expr, $mem:expr, $ptr:expr, $size:expr) => {{ + $mem.data_mut(&mut $caller) + .get_mut($ptr as usize..) + .and_then(|s| s.get_mut(..$size as usize)) + .expect("failed to read wasm memory") + }}; +} - pub fn shutdown( - linker: &mut Linker, - ) -> Result<(), crate::error::Error> { - const NAME: &str = "shutdown"; +pub mod network { + pub mod actor { + use wasmtime::{ExternRef, Linker}; - linker.func_wrap1_async::, ()>( - MODULE, - NAME, - |_caller, actor_ref| { - Box::new(async move { - let actor_ref = actor_ref.expect("actor ref not null"); - let actor = actor_ref - .data() - .downcast_ref::() - .expect("actor ref is valid"); - let _ = actor.shutdown().await; - }) as _ - }, - )?; - Ok(()) + use crate::linker::MODULE; + + pub fn set_id( + linker: &mut Linker, + ) -> Result<(), crate::error::Error> { + const NAME: &str = "tq_network_actor_set_id"; + + linker.func_wrap2_async::, i32, ()>( + MODULE, + NAME, + |_caller, actor_ref, id| { + Box::new(async move { + let actor_ref = actor_ref.expect("actor ref not null"); + let actor = actor_ref + .data() + .downcast_ref::() + .expect("actor ref is valid"); + actor.set_id(id as usize); + }) as _ + }, + )?; + Ok(()) + } + + pub fn shutdown( + linker: &mut Linker, + ) -> Result<(), crate::error::Error> { + const NAME: &str = "tq_network_actor_shutdown"; + + linker.func_wrap1_async::, ()>( + MODULE, + NAME, + |_caller, actor_ref| { + Box::new(async move { + let actor_ref = actor_ref.expect("actor ref not null"); + let actor = actor_ref + .data() + .downcast_ref::() + .expect("actor ref is valid"); + let _ = actor.shutdown().await; + }) as _ + }, + )?; + Ok(()) + } + + pub fn send( + linker: &mut Linker, + ) -> Result<(), crate::error::Error> { + const NAME: &str = "tq_network_actor_send"; + linker.func_wrap4_async::, i32, i32, i32, ()>( + MODULE, + NAME, + |mut caller, + actor_ref, + packet_id, + packet_data_ptr, + packet_data_len| { + Box::new(async move { + let actor_ref = actor_ref.expect("actor ref not null"); + let actor = actor_ref + .data() + .downcast_ref::() + .expect("actor ref is valid"); + let mem = memof!(caller); + let packet_data = mread!( + caller, + mem, + packet_data_ptr, + packet_data_len + ); + let _ = + actor.send((packet_id as u16, packet_data)).await; + }) as _ + }, + )?; + Ok(()) + } } +} + +pub mod rand { + use wasmtime::Linker; + + use crate::linker::MODULE; + use rand::Rng; - pub fn send( + pub fn getrandom( linker: &mut Linker, ) -> Result<(), crate::error::Error> { - const NAME: &str = "send"; - linker.func_wrap4_async::, i32, i32, i32, ()>( + const NAME: &str = "getrandom"; + linker.func_wrap2_async::( MODULE, NAME, - |mut caller, - actor_ref, - packet_id, - packet_data_ptr, - packet_data_len| { + |mut caller, ptr, len| { Box::new(async move { - let actor_ref = actor_ref.expect("actor ref not null"); - let actor = actor_ref - .data() - .downcast_ref::() - .expect("actor ref is valid"); let mem = memof!(caller); - let packet_data = - mread!(caller, mem, packet_data_ptr, packet_data_len); - let _ = actor.send((packet_id as u16, packet_data)).await; + let slice = mread_mut!(caller, mem, ptr, len); + let mut rng = rand::thread_rng(); + rng.fill(slice); + 0 }) as _ }, )?; Ok(()) } } + pub mod log { use super::*; - pub fn trace_event( linker: &mut Linker, ) -> Result<(), crate::error::Error> { From d78421e7e1d50091e1e0b060848f6bf1ba072a62 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sat, 27 Jan 2024 23:16:32 +0200 Subject: [PATCH 23/28] account auth --- server/auth/src/linker.rs | 49 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/server/auth/src/linker.rs b/server/auth/src/linker.rs index 35b3c76..54597e6 100644 --- a/server/auth/src/linker.rs +++ b/server/auth/src/linker.rs @@ -177,3 +177,52 @@ pub mod log { Ok(()) } } + +pub mod db { + pub mod account { + pub fn auth( + linker: &mut Linker, + ) -> Result<(), crate::error::Error> { + const NAME: &str = "tq_db_account_auth"; + linker.func_wrap4_async::( + MODULE, + NAME, + |mut caller, + username_ptr, + username_len, + password_ptr, + password_len| { + Box::new(async move { + let mem = memof!(caller); + let username_slice = + mread!(caller, mem, username_ptr, password_len); + let username = std::str::from_utf8(username_slice) + .expect("valid utf8"); + let password_slice = + mread!(caller, mem, password_ptr, password_len); + let password = std::str::from_utf8(password_slice) + .expect("valid utf8"); + let pool = caller.data().pool(); + let account = tq_db::account::Account::auth( + pool, username, password, + ) + .await; + match account { + Ok(account) => account.id as i32, + Err(tq_db::Error::AccountNotFound) => -1, + Err(tq_db::Error::InvalidPassword) => -2, + Err(e) => { + tracing::error!( + "Failed to auth account: {}", + e + ); + -1 + }, + } + }) as _ + }, + )?; + Ok(()) + } + } +} From 2670acc382a79622c2d37f60c1584ec4bc8673f8 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sun, 28 Jan 2024 21:20:17 +0200 Subject: [PATCH 24/28] add more functions to the linker --- .vscode/settings.json | 6 - server/auth/src/linker.rs | 355 +++++++++++++++++++++++++------------- 2 files changed, 233 insertions(+), 128 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 14d432e..438142f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,12 +5,6 @@ "rust-analyzer.lens.implementations.enable": true, "rust-analyzer.check.allTargets": true, "rust-analyzer.checkOnSave": true, - "rust-analyzer.check.targets": [ - "x86_64-unknown-linux-gnu", - "x86_64-pc-windows-msvc", - "aarch64-apple-darwin", - "wasm32-unknown-unknown" - ], "sqltools.useNodeRuntime": true, "sqltools.connections": [ { diff --git a/server/auth/src/linker.rs b/server/auth/src/linker.rs index 54597e6..ef845b6 100644 --- a/server/auth/src/linker.rs +++ b/server/auth/src/linker.rs @@ -1,12 +1,13 @@ use wasmtime::Linker; const MODULE: &str = "host"; +const ALLOC: &str = "__alloc"; +const MEMORY: &str = "memory"; -/// Read a slice of bytes from wasm memory. macro_rules! memof { ($caller:expr) => { $caller - .get_export("memory") + .get_export($crate::linker::MEMORY) .and_then(::wasmtime::Extern::into_memory) .expect("failed to read wasm memory") }; @@ -30,68 +31,61 @@ macro_rules! mread_mut { }}; } +macro_rules! alloc { + ($caller:expr) => {{ + $caller + .get_export($crate::linker::ALLOC) + .and_then(::wasmtime::Extern::into_func) + .expect("failed to read wasm alloc function") + .typed::(&mut $caller) + .expect("failed to read wasm typed alloc function") + }}; +} + pub mod network { pub mod actor { use wasmtime::{ExternRef, Linker}; use crate::linker::MODULE; - pub fn set_id( - linker: &mut Linker, - ) -> Result<(), crate::error::Error> { + pub fn set_id(linker: &mut Linker) -> Result<(), crate::error::Error> { const NAME: &str = "tq_network_actor_set_id"; - linker.func_wrap2_async::, i32, ()>( - MODULE, - NAME, - |_caller, actor_ref, id| { - Box::new(async move { - let actor_ref = actor_ref.expect("actor ref not null"); - let actor = actor_ref - .data() - .downcast_ref::() - .expect("actor ref is valid"); - actor.set_id(id as usize); - }) as _ - }, - )?; + linker.func_wrap2_async::, i32, ()>(MODULE, NAME, |_caller, actor_ref, id| { + Box::new(async move { + let actor_ref = actor_ref.expect("actor ref not null"); + let actor = actor_ref + .data() + .downcast_ref::() + .expect("actor ref is valid"); + actor.set_id(id as usize); + }) as _ + })?; Ok(()) } - pub fn shutdown( - linker: &mut Linker, - ) -> Result<(), crate::error::Error> { + pub fn shutdown(linker: &mut Linker) -> Result<(), crate::error::Error> { const NAME: &str = "tq_network_actor_shutdown"; - linker.func_wrap1_async::, ()>( - MODULE, - NAME, - |_caller, actor_ref| { - Box::new(async move { - let actor_ref = actor_ref.expect("actor ref not null"); - let actor = actor_ref - .data() - .downcast_ref::() - .expect("actor ref is valid"); - let _ = actor.shutdown().await; - }) as _ - }, - )?; + linker.func_wrap1_async::, ()>(MODULE, NAME, |_caller, actor_ref| { + Box::new(async move { + let actor_ref = actor_ref.expect("actor ref not null"); + let actor = actor_ref + .data() + .downcast_ref::() + .expect("actor ref is valid"); + let _ = actor.shutdown().await; + }) as _ + })?; Ok(()) } - pub fn send( - linker: &mut Linker, - ) -> Result<(), crate::error::Error> { + pub fn send(linker: &mut Linker) -> Result<(), crate::error::Error> { const NAME: &str = "tq_network_actor_send"; linker.func_wrap4_async::, i32, i32, i32, ()>( MODULE, NAME, - |mut caller, - actor_ref, - packet_id, - packet_data_ptr, - packet_data_len| { + |mut caller, actor_ref, packet_id, packet_data_ptr, packet_data_len| { Box::new(async move { let actor_ref = actor_ref.expect("actor ref not null"); let actor = actor_ref @@ -99,14 +93,8 @@ pub mod network { .downcast_ref::() .expect("actor ref is valid"); let mem = memof!(caller); - let packet_data = mread!( - caller, - mem, - packet_data_ptr, - packet_data_len - ); - let _ = - actor.send((packet_id as u16, packet_data)).await; + let packet_data = mread!(caller, mem, packet_data_ptr, packet_data_len); + let _ = actor.send((packet_id as u16, packet_data)).await; }) as _ }, )?; @@ -121,101 +109,75 @@ pub mod rand { use crate::linker::MODULE; use rand::Rng; - pub fn getrandom( - linker: &mut Linker, - ) -> Result<(), crate::error::Error> { + pub fn getrandom(linker: &mut Linker) -> Result<(), crate::error::Error> { const NAME: &str = "getrandom"; - linker.func_wrap2_async::( - MODULE, - NAME, - |mut caller, ptr, len| { - Box::new(async move { - let mem = memof!(caller); - let slice = mread_mut!(caller, mem, ptr, len); - let mut rng = rand::thread_rng(); - rng.fill(slice); - 0 - }) as _ - }, - )?; + linker.func_wrap2_async::(MODULE, NAME, |mut caller, ptr, len| { + Box::new(async move { + let mem = memof!(caller); + let slice = mread_mut!(caller, mem, ptr, len); + let mut rng = rand::thread_rng(); + rng.fill(slice); + 0 + }) as _ + })?; Ok(()) } } pub mod log { use super::*; - pub fn trace_event( - linker: &mut Linker, - ) -> Result<(), crate::error::Error> { + pub fn trace_event(linker: &mut Linker) -> Result<(), crate::error::Error> { const NAME: &str = "trace_event"; - linker - .func_wrap5_async::( - MODULE, - NAME, - |mut caller, - level, - target, - target_len, - message, - message_len| { - Box::new(async move { - let mem = memof!(caller); - let target_slice = mread!(caller, mem, target, target_len); - let target = std::str::from_utf8(target_slice).expect("valid utf8"); - let message_slice = mread!(caller, mem, message, message_len); - let message = std::str::from_utf8(message_slice).expect("valid utf8"); - match level { - 0 => tracing::error!(target: "runtime", packet = target, %message), - 1 => tracing::warn!(target: "runtime", packet = target, %message), - 2 => tracing::info!(target: "runtime", packet = target, %message), - 3 => tracing::debug!(target: "runtime", packet = target, %message), - _ => tracing::trace!(target: "runtime", packet = target, %message), - }; - }) as _ - }, - )?; + linker.func_wrap5_async::( + MODULE, + NAME, + |mut caller, level, target, target_len, message, message_len| { + Box::new(async move { + let mem = memof!(caller); + let target_slice = mread!(caller, mem, target, target_len); + let target = std::str::from_utf8(target_slice).expect("valid utf8"); + let message_slice = mread!(caller, mem, message, message_len); + let message = std::str::from_utf8(message_slice).expect("valid utf8"); + match level { + 0 => tracing::error!(target: "runtime", packet = target, %message), + 1 => tracing::warn!(target: "runtime", packet = target, %message), + 2 => tracing::info!(target: "runtime", packet = target, %message), + 3 => tracing::debug!(target: "runtime", packet = target, %message), + _ => tracing::trace!(target: "runtime", packet = target, %message), + }; + }) as _ + }, + )?; Ok(()) } } pub mod db { pub mod account { - pub fn auth( - linker: &mut Linker, - ) -> Result<(), crate::error::Error> { + use wasmtime::Linker; + + use crate::linker::MODULE; + + pub fn auth(linker: &mut Linker) -> Result<(), crate::error::Error> { const NAME: &str = "tq_db_account_auth"; linker.func_wrap4_async::( MODULE, NAME, - |mut caller, - username_ptr, - username_len, - password_ptr, - password_len| { + |mut caller, username_ptr, username_len, password_ptr, password_len| { Box::new(async move { let mem = memof!(caller); - let username_slice = - mread!(caller, mem, username_ptr, password_len); - let username = std::str::from_utf8(username_slice) - .expect("valid utf8"); - let password_slice = - mread!(caller, mem, password_ptr, password_len); - let password = std::str::from_utf8(password_slice) - .expect("valid utf8"); + let username_slice = mread!(caller, mem, username_ptr, username_len); + let username = std::str::from_utf8(username_slice).expect("valid utf8"); + let password_slice = mread!(caller, mem, password_ptr, password_len); + let password = std::str::from_utf8(password_slice).expect("valid utf8"); let pool = caller.data().pool(); - let account = tq_db::account::Account::auth( - pool, username, password, - ) - .await; + let account = tq_db::account::Account::auth(pool, username, password).await; match account { - Ok(account) => account.id as i32, + Ok(account) => account.account_id, Err(tq_db::Error::AccountNotFound) => -1, Err(tq_db::Error::InvalidPassword) => -2, Err(e) => { - tracing::error!( - "Failed to auth account: {}", - e - ); + tracing::error!("Failed to auth account: {}", e); -1 }, } @@ -225,4 +187,153 @@ pub mod db { Ok(()) } } + + pub mod realm { + use wasmtime::Linker; + + use crate::linker::MODULE; + + pub fn by_name(linker: &mut Linker) -> Result<(), crate::error::Error> { + const NAME: &str = "tq_db_realm_by_name"; + linker.func_wrap2_async::(MODULE, NAME, |mut caller, name_ptr, name_len| { + Box::new(async move { + let mem = memof!(caller); + let name_slice = mread!(caller, mem, name_ptr, name_len); + let name = std::str::from_utf8(name_slice).expect("valid utf8"); + let pool = caller.data().pool(); + let realm = tq_db::realm::Realm::by_name(pool, name).await; + let archived = match realm { + Ok(Some(realm)) => rkyv::to_bytes::<_, 64>(&realm).expect("failed to archive realm"), + Ok(None) => return (0, 0), + Err(e) => { + tracing::error!("Failed to get realm by name: {e}",); + return (-1, -1); + }, + }; + let alloc = alloc!(caller); + let ptr = alloc + .call_async(&mut caller, archived.len() as u32) + .await + .expect("failed to allocate memory"); + mem.write(&mut caller, ptr as usize, &archived) + .expect("failed to write realm to memory"); + (ptr, archived.len() as i32) + }) as _ + })?; + Ok(()) + } + } +} + +pub mod server_bus { + use msg_transfer::MsgTransfer; + use tokio::net::TcpStream; + use tokio_stream::StreamExt; + use tq_network::{CQCipher, PacketDecode, PacketEncode, PacketID, TQCodec}; + use tracing::Instrument; + use wasmtime::{ExternRef, Linker}; + + use crate::linker::MODULE; + + pub fn check(linker: &mut Linker) -> Result<(), crate::error::Error> { + const NAME: &str = "auth_server_bus_check"; + linker.func_wrap2_async::(MODULE, NAME, |mut caller, realm_ptr, realm_len| { + Box::new(async move { + let mem = memof!(caller); + let realm_slice = mread!(caller, mem, realm_ptr, realm_len); + let realm = unsafe { + rkyv::from_bytes_unchecked::(realm_slice).expect("failed to deserialize realm") + }; + let ip = realm.game_ip_address.as_str(); + let port = realm.game_port; + let stream = TcpStream::connect(format!("{ip}:{port}")) + .instrument(tracing::info_span!("realm_connect", %ip, %port, realm_id = realm.realm_id)) + .await; + match stream { + Ok(_) => 0, + Err(e) => { + tracing::error!( + %ip, + %port, + realm_id = realm.realm_id, + error = ?e, + "Failed to connect to realm" + ); + -1 + }, + } + }) as _ + })?; + Ok(()) + } + + pub fn transfer(linker: &mut Linker) -> Result<(), crate::error::Error> { + const NAME: &str = "auth_server_bus_transfer"; + linker.func_wrap3_async::, i32, i32, i64>( + MODULE, + NAME, + |mut caller, actor_ref, realm_ptr, realm_len| { + Box::new(async move { + let actor_ref = actor_ref.expect("actor ref not null"); + let actor = actor_ref + .data() + .downcast_ref::() + .expect("actor ref is valid"); + let mem = memof!(caller); + let realm_slice = mread!(caller, mem, realm_ptr, realm_len); + let realm = unsafe { + rkyv::from_bytes_unchecked::(realm_slice) + .expect("failed to deserialize realm") + }; + let ip = realm.game_ip_address.as_str(); + let port = realm.game_port; + let stream = TcpStream::connect(format!("{ip}:{port}")) + .instrument(tracing::info_span!("realm_connect", %ip, %port, realm_id = realm.realm_id)) + .await; + let tcp_stream = match stream { + Ok(s) => s, + Err(e) => { + tracing::error!( + %ip, + %port, + realm_id = realm.realm_id, + error = ?e, + "Failed to connect to realm" + ); + return -1; + }, + }; + let cipher = CQCipher::new(); + let (mut encoder, mut decoder) = TQCodec::new(tcp_stream, cipher).split(); + let transfer = MsgTransfer { + account_id: actor.id() as _, + realm_id: realm.realm_id as _, + ..Default::default() + }; + + let transfer = transfer.encode().expect("failed to encode transfer"); + encoder.send(transfer).await.expect("failed to send transfer"); + let res = decoder.next().await; + let res = match res { + Some(Ok((MsgTransfer::PACKET_ID, bytes))) => { + MsgTransfer::decode(&bytes).expect("failed to decode transfer") + }, + Some(Ok((id, _))) => { + tracing::error!(packet_id = ?id, "Unexpected packet id"); + return -1; + }, + Some(Err(e)) => { + tracing::error!(error = ?e, "Failed to decode transfer"); + return -1; + }, + None => { + return -1; + }, + }; + res.token as i64 + }) as _ + }, + )?; + Ok(()) + } } From 961087897777503d2aad83b97bd3f3dd1fb9e3c6 Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sun, 28 Jan 2024 21:22:16 +0200 Subject: [PATCH 25/28] cargo fmt --- Cargo.lock | 2 + crates/bindings/src/lib.rs | 117 ++------- crates/codec/src/lib.rs | 28 +- crates/crypto/src/cq_cipher.rs | 15 +- crates/crypto/src/rc5.rs | 19 +- crates/crypto/src/tq_cipher.rs | 19 +- crates/db/src/account.rs | 37 +-- crates/db/src/character.rs | 55 ++-- crates/db/src/map.rs | 21 +- crates/db/src/npc.rs | 12 +- crates/db/src/portal.rs | 13 +- crates/db/src/realm.rs | 14 +- crates/math/src/lib.rs | 25 +- crates/network/src/actor.rs | 41 +-- crates/network/src/error.rs | 4 +- crates/network/src/lib.rs | 18 +- crates/primitives/src/lib.rs | 56 ++-- crates/serde/src/de.rs | 72 ++--- crates/serde/src/fixed_string.rs | 47 +--- crates/serde/src/ser.rs | 87 +++--- crates/serde/src/string_list.rs | 89 ++++--- crates/server/src/error.rs | 12 +- crates/server/src/lib.rs | 24 +- crates/tracing-wasm/src/lib.rs | 21 +- crates/wasm-builder/src/builder.rs | 34 +-- crates/wasm-builder/src/lib.rs | 75 ++---- crates/wasm-builder/src/prerequisites.rs | 71 +++-- crates/wasm-builder/src/version.rs | 37 ++- crates/wasm-builder/src/wasm_project.rs | 292 +++++++-------------- macros/derive-packethandler/src/lib.rs | 54 ++-- macros/derive-packetid/src/lib.rs | 9 +- macros/derive-packetprocessor/src/lib.rs | 23 +- packets/account/src/lib.rs | 8 +- packets/connect-ex/src/lib.rs | 4 +- packets/connect/src/lib.rs | 5 +- packets/transfer/src/lib.rs | 41 +-- rustfmt.toml | 4 +- server/auth/Cargo.toml | 11 +- server/auth/src/error.rs | 32 ++- server/auth/src/lib.rs | 36 +-- server/auth/src/main.rs | 9 +- server/auth/src/state.rs | 10 +- server/game/src/constants.rs | 11 +- server/game/src/entities/basic.rs | 73 ++++-- server/game/src/entities/character.rs | 106 +++++--- server/game/src/entities/floor_item.rs | 16 +- server/game/src/entities/mod.rs | 24 +- server/game/src/entities/npc.rs | 53 ++-- server/game/src/error.rs | 76 ++---- server/game/src/main.rs | 4 +- server/game/src/packets/msg_action.rs | 165 +++--------- server/game/src/packets/msg_connect.rs | 18 +- server/game/src/packets/msg_data.rs | 12 +- server/game/src/packets/msg_item.rs | 6 +- server/game/src/packets/msg_map_info.rs | 12 +- server/game/src/packets/msg_npc.rs | 13 +- server/game/src/packets/msg_register.rs | 38 +-- server/game/src/packets/msg_talk.rs | 40 +-- server/game/src/packets/msg_task_dialog.rs | 18 +- server/game/src/packets/msg_transfer.rs | 9 +- server/game/src/packets/msg_walk.rs | 20 +- server/game/src/packets/msg_weather.rs | 36 ++- server/game/src/state/mod.rs | 61 ++--- server/game/src/systems/commands.rs | 24 +- server/game/src/systems/floor.rs | 42 ++- server/game/src/systems/screen.rs | 117 ++------- server/game/src/test_utils.rs | 32 +-- server/game/src/utils.rs | 24 +- server/game/src/world/map.rs | 109 ++++---- server/game/src/world/portal.rs | 44 +++- tools/externref/src/main.rs | 8 +- tools/gamemap-decoder/src/main.rs | 19 +- tools/hash-pwd/src/main.rs | 7 +- 73 files changed, 1092 insertions(+), 1748 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9307eb8..695061d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -176,8 +176,10 @@ dependencies = [ "futures", "msg-account", "msg-connect", + "msg-transfer", "num_enum", "rand", + "rkyv", "serde", "sqlx", "thiserror", diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs index bffe52a..e4b323a 100644 --- a/crates/bindings/src/lib.rs +++ b/crates/bindings/src/lib.rs @@ -34,12 +34,8 @@ pub fn set_panic_hook_once(name: &'static str) { .payload() .downcast_ref::<&str>() .copied() - .unwrap_or_else(|| { - info.payload().downcast_ref::().unwrap().as_str() - }); - let location = info - .location() - .map(|l| format!("{}:{}", l.file(), l.line())); + .unwrap_or_else(|| info.payload().downcast_ref::().unwrap().as_str()); + let location = info.location().map(|l| format!("{}:{}", l.file(), l.line())); host::log( tracing_wasm::Level::ERROR, name, @@ -65,17 +61,9 @@ extern "C" { packet_data_len: u32, ); - fn tq_network_actor_set_id( - actor: &Resource, - id: u32, - ); + fn tq_network_actor_set_id(actor: &Resource, id: u32); - fn tq_db_realm_by_name( - realm_name_ptr: *const u8, - realm_name_len: u32, - out_realm_ptr: *mut u8, - out_realm_len: *mut u32, - ) -> i32; + fn tq_db_realm_by_name(realm_name_ptr: *const u8, realm_name_len: u32) -> (i32, i32); fn tq_db_account_auth( username_ptr: *const u8, @@ -91,11 +79,8 @@ extern "C" { ) -> u64; fn auth_server_bus_check(realm_ptr: *const u8, realm_len: u32) -> i32; - fn auth_server_bus_transfer( - actor: &Resource, - realm_ptr: *const u8, - realm_len: u32, - ) -> u64; + fn auth_server_bus_transfer(actor: &Resource, realm_ptr: *const u8, realm_len: u32) + -> u64; } /// Host bindings. @@ -120,18 +105,10 @@ pub mod host { /// [`tq_network::actor::ActorHandle::send`] bindings. #[cfg(target_arch = "wasm32")] - pub fn send( - actor: &Resource, - packet: T, - ) -> Result<(), T::Error> { + pub fn send(actor: &Resource, packet: T) -> Result<(), T::Error> { let (packet_id, packet_data) = packet.encode()?; unsafe { - crate::tq_network_actor_send( - actor, - packet_id, - packet_data.as_ptr(), - packet_data.len() as u32, - ) + crate::tq_network_actor_send(actor, packet_id, packet_data.as_ptr(), packet_data.len() as u32) } Ok(()) } @@ -159,10 +136,7 @@ pub mod host { pub mod account { /// [`tq_db::account::Account::auth`] bindings. #[cfg(target_arch = "wasm32")] - pub fn auth( - username: &str, - password: &str, - ) -> Result { + pub fn auth(username: &str, password: &str) -> Result { let res = unsafe { crate::tq_db_account_auth( username.as_ptr(), @@ -183,10 +157,7 @@ pub mod host { } #[cfg(not(target_arch = "wasm32"))] - pub fn auth( - _username: &str, - _password: &str, - ) -> Result { + pub fn auth(_username: &str, _password: &str) -> Result { unimplemented!("Not implemented on non-wasm32") } } @@ -196,28 +167,15 @@ pub mod host { use tq_db::realm::Realm; /// [`tq_db::realm::Realm::by_name`] bindings. #[cfg(target_arch = "wasm32")] - pub fn by_name( - realm_name: &str, - ) -> Result, tq_db::Error> { + pub fn by_name(realm_name: &str) -> Result, tq_db::Error> { use rkyv::Deserialize; - - let realm = core::ptr::null_mut(); - let mut realm_len = 0; - let res = unsafe { - crate::tq_db_realm_by_name( - realm_name.as_ptr(), - realm_name.len() as u32, - realm, - &mut realm_len, - ) - }; - if res == 0 && realm_len > 0 && !realm.is_null() { + let (realm_ptr, realm_len) = + unsafe { crate::tq_db_realm_by_name(realm_name.as_ptr(), realm_name.len() as u32) }; + if realm_ptr != 0 && realm_len > 0 { let realm = unsafe { - let bytes = core::slice::from_raw_parts( - realm, - realm_len as usize, - ); - let archived = rkyv::archived_root::(bytes); + let bytes = + std::vec::Vec::from_raw_parts(realm_ptr as *mut u8, realm_len as usize, realm_len as usize); + let archived = rkyv::archived_root::(&bytes); archived.deserialize(&mut rkyv::Infallible).unwrap() }; Ok(Some(realm)) @@ -227,9 +185,7 @@ pub mod host { } #[cfg(not(target_arch = "wasm32"))] - pub fn by_name( - _realm_name: &str, - ) -> Result, tq_db::Error> { + pub fn by_name(_realm_name: &str) -> Result, tq_db::Error> { unimplemented!("Not implemented on non-wasm32") } } @@ -242,24 +198,12 @@ pub mod host { use tq_network::ActorHandle; /// [`game::state::generate_login_token`] bindings. #[cfg(target_arch = "wasm32")] - pub fn generate_login_token( - actor: &Resource, - account_id: u32, - realm_id: u32, - ) -> u64 { - unsafe { - crate::game_state_generate_login_token( - actor, account_id, realm_id, - ) - } + pub fn generate_login_token(actor: &Resource, account_id: u32, realm_id: u32) -> u64 { + unsafe { crate::game_state_generate_login_token(actor, account_id, realm_id) } } #[cfg(not(target_arch = "wasm32"))] - pub fn generate_login_token( - _actor: &Resource, - _account_id: u32, - _realm_id: u32, - ) -> u64 { + pub fn generate_login_token(_actor: &Resource, _account_id: u32, _realm_id: u32) -> u64 { unimplemented!("Not implemented on non-wasm32") } } @@ -276,12 +220,7 @@ pub mod host { #[cfg(target_arch = "wasm32")] pub fn check(realm: &Realm) -> Result<(), tq_network::Error> { let archived = rkyv::to_bytes::<_, 64>(realm).unwrap(); - let res = unsafe { - crate::auth_server_bus_check( - archived.as_ptr(), - archived.len() as u32, - ) - }; + let res = unsafe { crate::auth_server_bus_check(archived.as_ptr(), archived.len() as u32) }; if res == 0 { Ok(()) } else { @@ -301,17 +240,9 @@ pub mod host { realm: &Realm, ) -> Result { let archived = rkyv::to_bytes::<_, 64>(realm).unwrap(); - let token = unsafe { - crate::auth_server_bus_transfer( - actor, - archived.as_ptr(), - archived.len() as u32, - ) - }; + let token = unsafe { crate::auth_server_bus_transfer(actor, archived.as_ptr(), archived.len() as u32) }; if token == 0 { - Err(tq_network::Error::Other(String::from( - "Server Timed Out", - ))) + Err(tq_network::Error::Other(String::from("Server Timed Out"))) } else { Ok(token) } diff --git a/crates/codec/src/lib.rs b/crates/codec/src/lib.rs index 1ee4f83..b9a5272 100644 --- a/crates/codec/src/lib.rs +++ b/crates/codec/src/lib.rs @@ -29,10 +29,7 @@ use core::future::Future; use core::pin::Pin; use core::task::{Context, Poll}; use pretty_hex::{HexConfig, PrettyHex}; -use tokio::io::{ - self, split, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadHalf, - WriteHalf, -}; +use tokio::io::{self, split, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadHalf, WriteHalf}; use tokio_stream::Stream; use tq_crypto::Cipher; @@ -67,10 +64,7 @@ impl TQDecoder { /// Read data from the socket. /// /// This only returns `Ready` when the socket has closed. - fn fill_read_buf( - &mut self, - cx: &mut Context<'_>, - ) -> Poll> { + fn fill_read_buf(&mut self, cx: &mut Context<'_>) -> Poll> { loop { // Ensure the read buffer has capacity. // @@ -115,10 +109,7 @@ impl TQDecoder { tracing::trace!(%n, %packet_id, "decoded head"); if n > MAX_PACKET_SIZE { tracing::warn!(%n, %packet_id, "Frame too big!"); - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "Frame Too Big", - )); + return Err(io::Error::new(io::ErrorKind::InvalidData, "Frame Too Big")); } (n as usize, packet_id) }; @@ -209,9 +200,7 @@ impl TQEncoder { fn buffer(&mut self, buf: &[u8]) { // Ensure the buffer has capacity. Ideally this would not be unbounded, // but to keep the example simple, we will not limit this. - if self.buf.capacity() <= buf.len() - && self.buf.capacity() < MAX_CAPACITY - { + if self.buf.capacity() <= buf.len() && self.buf.capacity() < MAX_CAPACITY { self.buf.reserve(buf.len()); } @@ -246,7 +235,9 @@ pub struct TQCodec { } impl TQCodec { - pub fn new(stream: S, cipher: C) -> Self { Self { stream, cipher } } + pub fn new(stream: S, cipher: C) -> Self { + Self { stream, cipher } + } pub fn split(self) -> (TQEncoder, TQDecoder) { let (rdr, wrt) = split(self.stream); @@ -273,10 +264,7 @@ where type Item = io::Result<(u16, Bytes)>; #[tracing::instrument(skip(self, cx))] - fn poll_next( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { // First, read any new data that might have been received off the socket let sock_closed = self.fill_read_buf(cx)?.is_ready(); tracing::trace!("Socket Close? {}", sock_closed); diff --git a/crates/crypto/src/cq_cipher.rs b/crates/crypto/src/cq_cipher.rs index 0822a56..1b66b79 100644 --- a/crates/crypto/src/cq_cipher.rs +++ b/crates/crypto/src/cq_cipher.rs @@ -108,17 +108,14 @@ impl super::Cipher for CQCipher { key2[i] = key1[i] ^ tmp1[i % 4]; key2[i + C] = key1[i + C] ^ tmp2[i % 4]; } - self.active_key - .store(ActiveKey::Key2 as u8, Ordering::SeqCst); + self.active_key.store(ActiveKey::Key2 as u8, Ordering::SeqCst); self.decrypt_counter.store(0, Ordering::SeqCst); } /// Decrypts data with the COCAC algorithm. fn decrypt(&self, data: &mut [u8]) { let key1 = self.key1.read(); - let mut x = self - .decrypt_counter - .fetch_add(data.len() as u16, Ordering::SeqCst); + let mut x = self.decrypt_counter.fetch_add(data.len() as u16, Ordering::SeqCst); (0..data.len()).for_each(|i| { data[i] ^= key1[((x >> 8) + 0x100) as usize]; data[i] ^= key1[(x & 0xff) as usize]; @@ -132,9 +129,7 @@ impl super::Cipher for CQCipher { fn encrypt(&self, data: &mut [u8]) { let active_key_value = self.active_key.load(Ordering::SeqCst); let active_key = ActiveKey::from(active_key_value); - let mut x = self - .encrypt_counter - .fetch_add(data.len() as u16, Ordering::SeqCst); + let mut x = self.encrypt_counter.fetch_add(data.len() as u16, Ordering::SeqCst); let key1 = self.key1.read(); let key2 = self.key2.read(); (0..data.len()).for_each(|i| { @@ -156,7 +151,9 @@ impl super::Cipher for CQCipher { } impl Default for CQCipher { - fn default() -> Self { Self::new() } + fn default() -> Self { + Self::new() + } } #[cfg(test)] diff --git a/crates/crypto/src/rc5.rs b/crates/crypto/src/rc5.rs index 7c48654..47c5a2b 100644 --- a/crates/crypto/src/rc5.rs +++ b/crates/crypto/src/rc5.rs @@ -77,7 +77,9 @@ impl TQRC5 { } impl Default for TQRC5 { - fn default() -> Self { Self::new() } + fn default() -> Self { + Self::new() + } } impl crate::Cipher for TQRC5 { @@ -99,11 +101,8 @@ impl crate::Cipher for TQRC5 { let sub = self.sub; for round in (1..=rounds).rev() { - b = (b.wrapping_sub(sub[(2 * round + 1) as usize])) - .rotate_right(a) - ^ a; - a = (a.wrapping_sub(sub[(2 * round) as usize])).rotate_right(b) - ^ b; + b = (b.wrapping_sub(sub[(2 * round + 1) as usize])).rotate_right(a) ^ a; + a = (a.wrapping_sub(sub[(2 * round) as usize])).rotate_right(b) ^ b; } let chunk_a = &mut data[(8 * word)..]; let a_bytes = a.wrapping_sub(sub[0]).to_le_bytes(); @@ -128,16 +127,12 @@ mod tests { fn test_rc5() { let rc5 = TQRC5::new(); let mut buf = [ - 0x1C, 0xFD, 0x41, 0xC9, 0xA1, 0x69, 0xAA, 0xB6, 0x0D, 0xA6, 0x08, - 0x4D, 0xF3, 0x67, 0xEB, 0x73, + 0x1C, 0xFD, 0x41, 0xC9, 0xA1, 0x69, 0xAA, 0xB6, 0x0D, 0xA6, 0x08, 0x4D, 0xF3, 0x67, 0xEB, 0x73, ]; rc5.decrypt(&mut buf); assert_eq!( buf, - [ - 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ] + [0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] ); } } diff --git a/crates/crypto/src/tq_cipher.rs b/crates/crypto/src/tq_cipher.rs index 884201f..36e44b5 100644 --- a/crates/crypto/src/tq_cipher.rs +++ b/crates/crypto/src/tq_cipher.rs @@ -135,8 +135,7 @@ impl super::Cipher for TQCipher { key2[i] = key1[i] ^ tmp1[i % 4]; key2[i + C] = key1[i + C] ^ tmp2[i % 4]; } - self.active_key - .store(ActiveKey::Key2 as u8, Ordering::SeqCst); + self.active_key.store(ActiveKey::Key2 as u8, Ordering::SeqCst); self.encrypt_counter.store(0, Ordering::SeqCst); } @@ -160,7 +159,9 @@ impl super::Cipher for TQCipher { } impl Default for TQCipher { - fn default() -> Self { Self::new() } + fn default() -> Self { + Self::new() + } } #[cfg(test)] @@ -174,19 +175,15 @@ mod tests { let tq_cipher = TQCipher::new(); tq_cipher.generate_keys(0x1234); let mut buffer = [ - 0x22, 0x00, 0x1F, 0x04, 0x61, 0xFF, 0xC3, 0xA6, 0x3A, 0x6D, 0xD3, - 0x90, 0x31, 0x39, 0x32, 0x2E, 0x31, 0x36, 0x38, 0x2E, 0x31, 0x2E, - 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x16, 0x00, 0x00, 0x00, - 0x00, + 0x22, 0x00, 0x1F, 0x04, 0x61, 0xFF, 0xC3, 0xA6, 0x3A, 0x6D, 0xD3, 0x90, 0x31, 0x39, 0x32, 0x2E, 0x31, 0x36, + 0x38, 0x2E, 0x31, 0x2E, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x16, 0x00, 0x00, 0x00, 0x00, ]; tq_cipher.encrypt(&mut buffer); assert_eq!( buffer, [ - 0x67, 0x48, 0xAA, 0x12, 0x1F, 0xAB, 0x3, 0x44, 0x5E, 0x26, 0xE, - 0x53, 0x52, 0x2F, 0x74, 0x14, 0xE6, 0xFB, 0x88, 0xC0, 0x2A, - 0x86, 0x4C, 0x3E, 0x6D, 0x0, 0xE3, 0x2A, 0xFA, 0x2D, 0x87, - 0xC6, 0x65, 0x28 + 0x67, 0x48, 0xAA, 0x12, 0x1F, 0xAB, 0x3, 0x44, 0x5E, 0x26, 0xE, 0x53, 0x52, 0x2F, 0x74, 0x14, 0xE6, + 0xFB, 0x88, 0xC0, 0x2A, 0x86, 0x4C, 0x3E, 0x6D, 0x0, 0xE3, 0x2A, 0xFA, 0x2D, 0x87, 0xC6, 0x65, 0x28 ] ); } diff --git a/crates/db/src/account.rs b/crates/db/src/account.rs index 0102634..7fd34a4 100644 --- a/crates/db/src/account.rs +++ b/crates/db/src/account.rs @@ -13,17 +13,11 @@ pub struct Account { #[cfg(feature = "sqlx")] impl Account { - pub async fn auth( - pool: &sqlx::SqlitePool, - username: &str, - password: &str, - ) -> Result { - let maybe_account = sqlx::query_as::<_, Self>( - "SELECT * FROM accounts WHERE username = ?;", - ) - .bind(username) - .fetch_optional(pool) - .await?; + pub async fn auth(pool: &sqlx::SqlitePool, username: &str, password: &str) -> Result { + let maybe_account = sqlx::query_as::<_, Self>("SELECT * FROM accounts WHERE username = ?;") + .bind(username) + .fetch_optional(pool) + .await?; match maybe_account { Some(account) => { let matched = bcrypt::verify(password, &account.password)?; @@ -57,20 +51,15 @@ impl Account { // === Methods === /// Creates a new account in the database. - pub async fn create( - mut self, - pool: &sqlx::SqlitePool, - ) -> Result { + pub async fn create(mut self, pool: &sqlx::SqlitePool) -> Result { let password = bcrypt::hash(&self.password, bcrypt::DEFAULT_COST)?; - let res = sqlx::query( - "INSERT INTO accounts (username, password, name, email) VALUES (?, ?, ?, ?);", - ) - .bind(&self.username) - .bind(&password) - .bind(&self.name) - .bind(&self.email) - .execute(pool) - .await?; + let res = sqlx::query("INSERT INTO accounts (username, password, name, email) VALUES (?, ?, ?, ?);") + .bind(&self.username) + .bind(&password) + .bind(&self.name) + .bind(&self.email) + .execute(pool) + .await?; if res.rows_affected() == 0 { Err(crate::Error::CreateAccountFailed) } else { diff --git a/crates/db/src/character.rs b/crates/db/src/character.rs index 2612d30..46bf5f1 100644 --- a/crates/db/src/character.rs +++ b/crates/db/src/character.rs @@ -44,29 +44,19 @@ pub struct Location { #[cfg(feature = "sqlx")] impl Character { - pub async fn from_account( - pool: &sqlx::SqlitePool, - id: u32, - ) -> Result, crate::Error> { - let maybe_character = sqlx::query_as::<_, Self>( - "SELECT * FROM characters WHERE account_id = ?;", - ) - .bind(id) - .fetch_optional(pool) - .await?; + pub async fn from_account(pool: &sqlx::SqlitePool, id: u32) -> Result, crate::Error> { + let maybe_character = sqlx::query_as::<_, Self>("SELECT * FROM characters WHERE account_id = ?;") + .bind(id) + .fetch_optional(pool) + .await?; Ok(maybe_character) } - pub async fn name_taken( - pool: &sqlx::SqlitePool, - name: &str, - ) -> Result { - let result = sqlx::query_as::<_, (i32,)>( - "SELECT EXISTS (SELECT 1 FROM characters WHERE name = ? LIMIT 1);", - ) - .bind(name) - .fetch_optional(pool) - .await?; + pub async fn name_taken(pool: &sqlx::SqlitePool, name: &str) -> Result { + let result = sqlx::query_as::<_, (i32,)>("SELECT EXISTS (SELECT 1 FROM characters WHERE name = ? LIMIT 1);") + .bind(name) + .fetch_optional(pool) + .await?; match result { Some((1,)) => Ok(true), Some((0,)) => Ok(false), @@ -75,23 +65,15 @@ impl Character { } } - pub async fn by_id( - pool: &sqlx::SqlitePool, - id: i32, - ) -> Result { - let c = sqlx::query_as::<_, Self>( - "SELECT * FROM characters WHERE character_id = ?;", - ) - .bind(id) - .fetch_one(pool) - .await?; + pub async fn by_id(pool: &sqlx::SqlitePool, id: i32) -> Result { + let c = sqlx::query_as::<_, Self>("SELECT * FROM characters WHERE character_id = ?;") + .bind(id) + .fetch_one(pool) + .await?; Ok(c) } - pub async fn save( - self, - pool: &sqlx::SqlitePool, - ) -> Result { + pub async fn save(self, pool: &sqlx::SqlitePool) -> Result { let (id,) = sqlx::query_as::<_, (i32,)>( " INSERT INTO characters @@ -133,10 +115,7 @@ impl Character { Ok(id) } - pub async fn update( - self, - pool: &sqlx::SqlitePool, - ) -> Result<(), crate::Error> { + pub async fn update(self, pool: &sqlx::SqlitePool) -> Result<(), crate::Error> { sqlx::query( " UPDATE characters diff --git a/crates/db/src/map.rs b/crates/db/src/map.rs index 0981f90..60ebc94 100644 --- a/crates/db/src/map.rs +++ b/crates/db/src/map.rs @@ -16,14 +16,11 @@ pub struct Map { impl Map { /// Loads all maps from the database to add them to the state. #[tracing::instrument] - pub async fn load_all( - pool: &sqlx::SqlitePool, - ) -> Result, crate::Error> { + pub async fn load_all(pool: &sqlx::SqlitePool) -> Result, crate::Error> { use tokio_stream::StreamExt; let mut maps = Vec::new(); - let mut s = - sqlx::query_as::<_, Self>("SELECT * FROM maps;").fetch(pool); + let mut s = sqlx::query_as::<_, Self>("SELECT * FROM maps;").fetch(pool); while let Some(maybe_map) = s.next().await { match maybe_map { Ok(map) => maps.push(map), @@ -38,15 +35,11 @@ impl Map { Ok(maps) } - pub async fn load( - pool: &sqlx::SqlitePool, - id: i32, - ) -> Result, crate::Error> { - let maybe_map = - sqlx::query_as::<_, Self>("SELECT * FROM maps WHERE id = ?;") - .bind(id) - .fetch_optional(pool) - .await?; + pub async fn load(pool: &sqlx::SqlitePool, id: i32) -> Result, crate::Error> { + let maybe_map = sqlx::query_as::<_, Self>("SELECT * FROM maps WHERE id = ?;") + .bind(id) + .fetch_optional(pool) + .await?; Ok(maybe_map) } } diff --git a/crates/db/src/npc.rs b/crates/db/src/npc.rs index 384c8b4..7e4b101 100644 --- a/crates/db/src/npc.rs +++ b/crates/db/src/npc.rs @@ -19,17 +19,13 @@ pub struct Npc { #[cfg(feature = "sqlx")] impl Npc { #[tracing::instrument] - pub async fn by_map( - pool: &sqlx::SqlitePool, - id: i32, - ) -> Result, crate::Error> { + pub async fn by_map(pool: &sqlx::SqlitePool, id: i32) -> Result, crate::Error> { use tokio_stream::StreamExt; let mut npcs = Vec::new(); - let mut s = - sqlx::query_as::<_, Self>("SELECT * FROM npcs WHERE map_id = ?;") - .bind(id) - .fetch(pool); + let mut s = sqlx::query_as::<_, Self>("SELECT * FROM npcs WHERE map_id = ?;") + .bind(id) + .fetch(pool); while let Some(maybe_npc) = s.next().await { match maybe_npc { Ok(npc) => npcs.push(npc), diff --git a/crates/db/src/portal.rs b/crates/db/src/portal.rs index ed11304..f77a4a0 100644 --- a/crates/db/src/portal.rs +++ b/crates/db/src/portal.rs @@ -13,18 +13,13 @@ pub struct Portal { #[cfg(feature = "sqlx")] impl Portal { #[tracing::instrument] - pub async fn by_map( - pool: &sqlx::SqlitePool, - from: i32, - ) -> Result, crate::Error> { + pub async fn by_map(pool: &sqlx::SqlitePool, from: i32) -> Result, crate::Error> { use tokio_stream::StreamExt; let mut portals = Vec::new(); - let mut s = sqlx::query_as::<_, Self>( - "SELECT * FROM portals WHERE from_map_id = ?;", - ) - .bind(from) - .fetch(pool); + let mut s = sqlx::query_as::<_, Self>("SELECT * FROM portals WHERE from_map_id = ?;") + .bind(from) + .fetch(pool); while let Some(maybe_portal) = s.next().await { match maybe_portal { Ok(portal) => portals.push(portal), diff --git a/crates/db/src/realm.rs b/crates/db/src/realm.rs index 593242b..97bc847 100644 --- a/crates/db/src/realm.rs +++ b/crates/db/src/realm.rs @@ -12,15 +12,11 @@ pub struct Realm { #[cfg(feature = "sqlx")] impl Realm { - pub async fn by_name( - pool: &sqlx::SqlitePool, - name: &str, - ) -> Result, crate::Error> { - let realm = - sqlx::query_as::<_, Self>("SELECT * FROM realms WHERE name = ?;") - .bind(name) - .fetch_optional(pool) - .await?; + pub async fn by_name(pool: &sqlx::SqlitePool, name: &str) -> Result, crate::Error> { + let realm = sqlx::query_as::<_, Self>("SELECT * FROM realms WHERE name = ?;") + .bind(name) + .fetch_optional(pool) + .await?; Ok(realm) } } diff --git a/crates/math/src/lib.rs b/crates/math/src/lib.rs index 6931658..97f4180 100644 --- a/crates/math/src/lib.rs +++ b/crates/math/src/lib.rs @@ -19,9 +19,7 @@ fn atan2(y: f32, x: f32) -> f32 { } #[cfg(not(any(feature = "std", feature = "libm")))] { - compile_error!( - "Either the `std` or `libm` feature must be enabled to use `atan2`" - ) + compile_error!("Either the `std` or `libm` feature must be enabled to use `atan2`") } } @@ -36,9 +34,7 @@ fn abs(x: f32) -> f32 { } #[cfg(not(any(feature = "std", feature = "libm")))] { - compile_error!( - "Either the `std` or `libm` feature must be enabled to use `abs`" - ) + compile_error!("Either the `std` or `libm` feature must be enabled to use `abs`") } } @@ -53,9 +49,7 @@ fn pow(x: f32, y: i32) -> f32 { } #[cfg(not(any(feature = "std", feature = "libm")))] { - compile_error!( - "Either the `std` or `libm` feature must be enabled to use `powi`" - ) + compile_error!("Either the `std` or `libm` feature must be enabled to use `powi`") } } @@ -70,9 +64,7 @@ fn sqrt(x: f32) -> f32 { } #[cfg(not(any(feature = "std", feature = "libm")))] { - compile_error!( - "Either the `std` or `libm` feature must be enabled to use `sqrt`" - ) + compile_error!("Either the `std` or `libm` feature must be enabled to use `sqrt`") } } @@ -87,9 +79,7 @@ fn round(x: f32) -> f32 { } #[cfg(not(any(feature = "std", feature = "libm")))] { - compile_error!( - "Either the `std` or `libm` feature must be enabled to use `round`" - ) + compile_error!("Either the `std` or `libm` feature must be enabled to use `round`") } } @@ -157,10 +147,7 @@ pub fn get_direction_sector(p1: (u16, u16), p2: (u16, u16)) -> u8 { } /// Check if a Point (px, py) lies inside a circle (x, y, r) -pub fn in_circle( - (center_x, center_y, r): (u16, u16, u16), - (px, py): (u16, u16), -) -> bool { +pub fn in_circle((center_x, center_y, r): (u16, u16, u16), (px, py): (u16, u16)) -> bool { if r == 0 { return false; } diff --git a/crates/network/src/actor.rs b/crates/network/src/actor.rs index ad47a7c..3ccb89c 100644 --- a/crates/network/src/actor.rs +++ b/crates/network/src/actor.rs @@ -46,8 +46,7 @@ impl Hash for Actor { impl PartialEq for Actor { fn eq(&self, other: &Self) -> bool { - self.handle.id.load(Ordering::Relaxed) - == other.handle.id.load(Ordering::Relaxed) + self.handle.id.load(Ordering::Relaxed) == other.handle.id.load(Ordering::Relaxed) } } @@ -56,11 +55,15 @@ impl Eq for Actor {} impl Deref for Actor { type Target = S; - fn deref(&self) -> &Self::Target { &self.state } + fn deref(&self) -> &Self::Target { + &self.state + } } impl From<(u16, Bytes)> for Message { - fn from((id, bytes): (u16, Bytes)) -> Self { Self::Packet(id, bytes) } + fn from((id, bytes): (u16, Bytes)) -> Self { + Self::Packet(id, bytes) + } } #[async_trait] @@ -91,18 +94,21 @@ impl Actor { } /// Returns a cheap clone of the actor handle - pub fn handle(&self) -> ActorHandle { self.handle.clone() } + pub fn handle(&self) -> ActorHandle { + self.handle.clone() + } - pub fn id(&self) -> usize { self.handle.id() } + pub fn id(&self) -> usize { + self.handle.id() + } - pub fn set_id(&self, id: usize) { self.handle.set_id(id) } + pub fn set_id(&self, id: usize) { + self.handle.set_id(id) + } /// Enqueue the packet and send it to the client connected to this actor #[instrument(skip(self, packet))] - pub async fn send( - &self, - packet: P, - ) -> Result<(), P::Error> { + pub async fn send(&self, packet: P) -> Result<(), P::Error> { self.handle.send(packet).await } @@ -129,16 +135,17 @@ impl Actor { } impl ActorHandle { - pub fn id(&self) -> usize { self.id.load(Ordering::Relaxed) } + pub fn id(&self) -> usize { + self.id.load(Ordering::Relaxed) + } - pub fn set_id(&self, id: usize) { self.id.store(id, Ordering::Relaxed); } + pub fn set_id(&self, id: usize) { + self.id.store(id, Ordering::Relaxed); + } /// Enqueue the packet and send it to the client connected to this actor #[instrument(skip(self, packet))] - pub async fn send( - &self, - packet: P, - ) -> Result<(), P::Error> { + pub async fn send(&self, packet: P) -> Result<(), P::Error> { let msg = packet.encode()?; self.tx.send(msg.into()).map_err(Into::into).await?; Ok(()) diff --git a/crates/network/src/error.rs b/crates/network/src/error.rs index 892b885..3d98264 100644 --- a/crates/network/src/error.rs +++ b/crates/network/src/error.rs @@ -19,7 +19,9 @@ impl core::fmt::Display for Error { } impl From for Error { - fn from(e: tq_serde::TQSerdeError) -> Self { Self::TQSerde(e) } + fn from(e: tq_serde::TQSerdeError) -> Self { + Self::TQSerde(e) + } } impl From> for Error { diff --git a/crates/network/src/lib.rs b/crates/network/src/lib.rs index dcebeeb..a84912b 100644 --- a/crates/network/src/lib.rs +++ b/crates/network/src/lib.rs @@ -43,11 +43,7 @@ pub trait PacketProcess { /// structure packet fields and properties. For the server /// implementations, this is called in the packet handler after the /// message has been dequeued from the server's PacketProcessor - async fn process( - &self, - state: &Self::State, - actor: &Actor, - ) -> Result<(), Self::Error>; + async fn process(&self, state: &Self::State, actor: &Actor) -> Result<(), Self::Error>; } pub trait PacketEncode { @@ -102,7 +98,9 @@ impl PacketEncode for (u16, Bytes) { type Error = Error; type Packet = (); - fn encode(&self) -> Result<(u16, Bytes), Self::Error> { Ok(self.clone()) } + fn encode(&self) -> Result<(u16, Bytes), Self::Error> { + Ok(self.clone()) + } } impl<'a> PacketEncode for (u16, &'a [u8]) { @@ -141,12 +139,16 @@ impl IntoErrorPacket for T where T: PacketEncode, { - fn error_packet(self) -> ErrorPacket { ErrorPacket(self) } + fn error_packet(self) -> ErrorPacket { + ErrorPacket(self) + } } impl From for ErrorPacket where T: PacketEncode, { - fn from(v: T) -> Self { Self(v) } + fn from(v: T) -> Self { + Self(v) + } } diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index e292ec4..293eb4c 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -12,9 +12,13 @@ pub struct Size { } impl Size { - pub const fn new(width: I, height: I) -> Self { Self { width, height } } + pub const fn new(width: I, height: I) -> Self { + Self { width, height } + } - pub fn area(&self) -> I { self.width * self.height } + pub fn area(&self) -> I { + self.width * self.height + } } impl fmt::Display for Size { @@ -30,7 +34,9 @@ pub struct Point { } impl Point { - pub fn new(x: I, y: I) -> Self { Self { x, y } } + pub fn new(x: I, y: I) -> Self { + Self { x, y } + } } impl fmt::Display for Point { @@ -81,7 +87,9 @@ impl From<(u16, u16, u8)> for Location { } impl From<(u16, u16)> for Location { - fn from((x, y): (u16, u16)) -> Self { Self::new(x, y, 0) } + fn from((x, y): (u16, u16)) -> Self { + Self::new(x, y, 0) + } } impl From for (u16, u16, u8) { @@ -91,16 +99,16 @@ impl From for (u16, u16, u8) { } impl From for (u16, u16) { - fn from(location: Location) -> Self { (location.x, location.y) } + fn from(location: Location) -> Self { + (location.x, location.y) + } } /// A Gauge is a value that can be incremented and decremented, but never /// exceeds a maximum value. /// /// Gauges are used to represent health, mana, and stamina. -#[derive( - Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Default, NoUninit, -)] +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Default, NoUninit)] #[repr(C, align(4))] pub struct Gauge { /// Current value @@ -110,19 +118,33 @@ pub struct Gauge { } impl Gauge { - pub fn new(current: u16, max: u16) -> Self { Self { current, max } } + pub fn new(current: u16, max: u16) -> Self { + Self { current, max } + } - pub fn full(max: u16) -> Self { Self { current: max, max } } + pub fn full(max: u16) -> Self { + Self { current: max, max } + } - pub fn current(&self) -> u16 { self.current } + pub fn current(&self) -> u16 { + self.current + } - pub fn max(&self) -> u16 { self.max } + pub fn max(&self) -> u16 { + self.max + } - pub fn make_full(&mut self) { self.current = self.max } + pub fn make_full(&mut self) { + self.current = self.max + } - pub fn is_full(&self) -> bool { self.current == self.max } + pub fn is_full(&self) -> bool { + self.current == self.max + } - pub fn is_empty(&self) -> bool { self.current == 0 } + pub fn is_empty(&self) -> bool { + self.current == 0 + } pub fn increment(&mut self, amount: u16) { self.current = (self.current + amount).min(self.max); @@ -132,5 +154,7 @@ impl Gauge { self.current = self.current.saturating_sub(amount); } - pub fn set(&mut self, value: u16) { self.current = value.min(self.max); } + pub fn set(&mut self, value: u16) { + self.current = value.min(self.max); + } } diff --git a/crates/serde/src/de.rs b/crates/serde/src/de.rs index 31d2cd9..a183de1 100644 --- a/crates/serde/src/de.rs +++ b/crates/serde/src/de.rs @@ -16,11 +16,11 @@ impl<'storage> SliceReader<'storage> { SliceReader { slice: bytes } } - fn get_ref(&self) -> &'storage [u8] { self.slice } + fn get_ref(&self) -> &'storage [u8] { + self.slice + } - fn get_byte_array( - &mut self, - ) -> Result<[u8; N], TQSerdeError> { + fn get_byte_array(&mut self) -> Result<[u8; N], TQSerdeError> { if N > self.slice.len() { return Err(TQSerdeError::Eof); } @@ -40,10 +40,7 @@ impl<'storage> SliceReader<'storage> { Ok(read_slice[0]) } - fn get_byte_slice( - &mut self, - len: usize, - ) -> Result<&'storage [u8], TQSerdeError> { + fn get_byte_slice(&mut self, len: usize) -> Result<&'storage [u8], TQSerdeError> { if len > self.slice.len() { return Err(TQSerdeError::Eof); } @@ -170,10 +167,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { Visitor::visit_bytes(visitor, self.input.get_ref()) } - fn deserialize_byte_buf( - self, - visitor: V, - ) -> Result + fn deserialize_byte_buf(self, visitor: V) -> Result where V: Visitor<'de>, { @@ -182,10 +176,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { visitor.visit_byte_buf(bytes.to_vec()) } - fn deserialize_option( - self, - _visitor: V, - ) -> Result + fn deserialize_option(self, _visitor: V) -> Result where V: Visitor<'de>, { @@ -201,22 +192,14 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { } // Unit struct means a named value containing no data. - fn deserialize_unit_struct( - self, - _name: &'static str, - visitor: V, - ) -> Result + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_unit(visitor) } - fn deserialize_newtype_struct( - self, - _name: &'static str, - visitor: V, - ) -> Result + fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: Visitor<'de>, { @@ -232,23 +215,14 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { self.deserialize_tuple(len, visitor) } - fn deserialize_tuple( - self, - len: usize, - visitor: V, - ) -> Result + fn deserialize_tuple(self, len: usize, visitor: V) -> Result where V: Visitor<'de>, { visitor.visit_seq(Access { de: self, len }) } - fn deserialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - visitor: V, - ) -> Result + fn deserialize_tuple_struct(self, _name: &'static str, _len: usize, visitor: V) -> Result where V: Visitor<'de>, { @@ -286,20 +260,14 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { Err(TQSerdeError::Unspported) } - fn deserialize_identifier( - self, - visitor: V, - ) -> Result + fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_str(visitor) } - fn deserialize_ignored_any( - self, - visitor: V, - ) -> Result + fn deserialize_ignored_any(self, visitor: V) -> Result where V: Visitor<'de>, { @@ -317,10 +285,7 @@ struct Access<'a, 'de: 'a> { impl<'de, 'a> SeqAccess<'de> for Access<'a, 'de> { type Error = TQSerdeError; - fn next_element_seed( - &mut self, - seed: T, - ) -> Result, TQSerdeError> + fn next_element_seed(&mut self, seed: T) -> Result, TQSerdeError> where T: DeserializeSeed<'de>, { @@ -349,11 +314,10 @@ fn test_struct_de() { } let test: MsgAccount = from_bytes(&[ - 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x31, 0x32, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5a, 0x65, 0x75, 0x73, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x76, 0x61, 0x72, - 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2, 0x0, 0x0, 0x0, + 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x32, 0x33, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5a, 0x65, 0x75, 0x73, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x76, 0x61, 0x72, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2, 0x0, + 0x0, 0x0, ]) .unwrap(); assert_eq!( diff --git a/crates/serde/src/fixed_string.rs b/crates/serde/src/fixed_string.rs index dfb035a..8397eab 100644 --- a/crates/serde/src/fixed_string.rs +++ b/crates/serde/src/fixed_string.rs @@ -30,7 +30,9 @@ where impl Deref for FixedString { type Target = str; - fn deref(&self) -> &Self::Target { &self.inner } + fn deref(&self) -> &Self::Target { + &self.inner + } } impl fmt::Display for FixedString { @@ -92,78 +94,57 @@ pub struct Encrypted; pub struct Masked; impl Serialize for FixedString { - fn serialize( - &self, - serializer: S, - ) -> Result { + fn serialize(&self, serializer: S) -> Result { encode_fixed_string::(&self.inner).serialize(serializer) } } impl Serialize for FixedString { - fn serialize( - &self, - serializer: S, - ) -> Result { + fn serialize(&self, serializer: S) -> Result { encode_fixed_string::(&self.inner).serialize(serializer) } } impl Serialize for FixedString<16, Encrypted> { - fn serialize( - &self, - serializer: S, - ) -> Result { + fn serialize(&self, serializer: S) -> Result { // FIXME: encrypt password encode_fixed_string::<16>(&self.inner).serialize(serializer) } } impl<'de> Deserialize<'de> for FixedString<10, ClearText> { - fn deserialize>( - deserializer: D, - ) -> Result { + fn deserialize>(deserializer: D) -> Result { let slice: [u8; 10] = Deserialize::deserialize(deserializer)?; - let result = - core::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; + let result = core::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; let result = result.trim_end_matches('\0'); Ok(result.into()) } } impl<'de> Deserialize<'de> for FixedString<16, ClearText> { - fn deserialize>( - deserializer: D, - ) -> Result { + fn deserialize>(deserializer: D) -> Result { let slice: [u8; 16] = Deserialize::deserialize(deserializer)?; - let result = - core::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; + let result = core::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; let result = result.trim_end_matches('\0'); Ok(result.into()) } } impl<'de> Deserialize<'de> for FixedString<16, Masked> { - fn deserialize>( - deserializer: D, - ) -> Result { + fn deserialize>(deserializer: D) -> Result { let slice: [u8; 16] = Deserialize::deserialize(deserializer)?; - let result = - core::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; + let result = core::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; let result = result.trim_end_matches('\0'); Ok(result.into()) } } impl<'de> Deserialize<'de> for FixedString<16, Encrypted> { - fn deserialize>( - deserializer: D, - ) -> Result { + fn deserialize>(deserializer: D) -> Result { let mut slice: [u8; 16] = Deserialize::deserialize(deserializer)?; let rc5 = TQRC5::new(); rc5.decrypt(&mut slice); - let result = - core::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; + let result = core::str::from_utf8(&slice).map_err(serde::de::Error::custom)?; let result = result.trim_end_matches('\0'); Ok(result.into()) } diff --git a/crates/serde/src/ser.rs b/crates/serde/src/ser.rs index f939e1b..763f780 100644 --- a/crates/serde/src/ser.rs +++ b/crates/serde/src/ser.rs @@ -94,21 +94,19 @@ impl<'a> ser::Serializer for &'a mut Serializer { Ok(()) } - fn serialize_none(self) -> Result { Ok(()) } + fn serialize_none(self) -> Result { + Ok(()) + } - fn serialize_some( - self, - value: &T, - ) -> Result { + fn serialize_some(self, value: &T) -> Result { value.serialize(self) } - fn serialize_unit(self) -> Result { Ok(()) } + fn serialize_unit(self) -> Result { + Ok(()) + } - fn serialize_unit_struct( - self, - _: &'static str, - ) -> Result { + fn serialize_unit_struct(self, _: &'static str) -> Result { self.serialize_unit() } @@ -142,17 +140,11 @@ impl<'a> ser::Serializer for &'a mut Serializer { Ok(()) } - fn serialize_seq( - self, - _len: Option, - ) -> Result { + fn serialize_seq(self, _len: Option) -> Result { Ok(self) } - fn serialize_tuple( - self, - _: usize, - ) -> Result { + fn serialize_tuple(self, _: usize) -> Result { Ok(self) } @@ -174,18 +166,11 @@ impl<'a> ser::Serializer for &'a mut Serializer { Err(TQSerdeError::Unspported) } - fn serialize_map( - self, - _: Option, - ) -> Result { + fn serialize_map(self, _: Option) -> Result { Err(TQSerdeError::Unspported) } - fn serialize_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { Ok(self) } @@ -204,58 +189,52 @@ impl<'a> ser::SerializeSeq for &'a mut Serializer { type Error = TQSerdeError; type Ok = (); - fn serialize_element( - &mut self, - v: &T, - ) -> Result<(), Self::Error> { + fn serialize_element(&mut self, v: &T) -> Result<(), Self::Error> { v.serialize(&mut **self) } - fn end(self) -> Result { Ok(()) } + fn end(self) -> Result { + Ok(()) + } } impl<'a> ser::SerializeTuple for &'a mut Serializer { type Error = TQSerdeError; type Ok = (); - fn serialize_element( - &mut self, - v: &T, - ) -> Result<(), Self::Error> { + fn serialize_element(&mut self, v: &T) -> Result<(), Self::Error> { v.serialize(&mut **self) } - fn end(self) -> Result { Ok(()) } + fn end(self) -> Result { + Ok(()) + } } impl<'a> ser::SerializeStruct for &'a mut Serializer { type Error = TQSerdeError; type Ok = (); - fn serialize_field( - &mut self, - _: &'static str, - v: &T, - ) -> Result<(), Self::Error> { + fn serialize_field(&mut self, _: &'static str, v: &T) -> Result<(), Self::Error> { v.serialize(&mut **self) } - fn end(self) -> Result { Ok(()) } + fn end(self) -> Result { + Ok(()) + } } impl<'a> ser::SerializeStructVariant for &'a mut Serializer { type Error = TQSerdeError; type Ok = (); - fn serialize_field( - &mut self, - _: &'static str, - v: &T, - ) -> Result<(), Self::Error> { + fn serialize_field(&mut self, _: &'static str, v: &T) -> Result<(), Self::Error> { v.serialize(&mut **self) } - fn end(self) -> Result { Ok(()) } + fn end(self) -> Result { + Ok(()) + } } /// Serialize `T` into `BytesMut`. @@ -290,12 +269,10 @@ fn test_struct_ser() { }; assert_eq!( vec![ - 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x31, 0x32, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5a, 0x65, 0x75, 0x73, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x76, - 0x61, 0x72, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2, 0x0, - 0x0, 0x0 + 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x32, 0x33, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5a, 0x65, 0x75, 0x73, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x76, 0x61, 0x72, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x2, 0x0, 0x0, 0x0 ], to_bytes(&test).unwrap().as_ref() ); diff --git a/crates/serde/src/string_list.rs b/crates/serde/src/string_list.rs index 485452d..d62035d 100644 --- a/crates/serde/src/string_list.rs +++ b/crates/serde/src/string_list.rs @@ -67,58 +67,78 @@ impl core::fmt::Debug for StringList { impl StringList { /// Creates a new empty StringList. - pub fn new() -> Self { StringList { inner: Vec::new() } } + pub fn new() -> Self { + StringList { inner: Vec::new() } + } /// Pushes a new string onto the StringList. - pub fn push(&mut self, s: String) { self.inner.push(s); } + pub fn push(&mut self, s: String) { + self.inner.push(s); + } /// Returns the number of strings in the StringList. - pub fn len(&self) -> usize { self.inner.len() } + pub fn len(&self) -> usize { + self.inner.len() + } /// Returns true if the StringList is empty. - pub fn is_empty(&self) -> bool { self.inner.is_empty() } + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } /// Returns a reference to the Vec that the StringList wraps. - pub fn as_vec(&self) -> &Vec { &self.inner } + pub fn as_vec(&self) -> &Vec { + &self.inner + } - pub fn iter(&self) -> impl Iterator { self.inner.iter() } + pub fn iter(&self) -> impl Iterator { + self.inner.iter() + } } impl From> for StringList where T: Into, { - fn from(strings: Vec) -> Self { StringList::from_iter(strings) } + fn from(strings: Vec) -> Self { + StringList::from_iter(strings) + } } impl From for Vec { - fn from(string_list: StringList) -> Self { string_list.inner } + fn from(string_list: StringList) -> Self { + string_list.inner + } } impl AsRef> for StringList { - fn as_ref(&self) -> &Vec { &self.inner } + fn as_ref(&self) -> &Vec { + &self.inner + } } impl AsRef<[String]> for StringList { - fn as_ref(&self) -> &[String] { &self.inner } + fn as_ref(&self) -> &[String] { + &self.inner + } } impl AsMut> for StringList { - fn as_mut(&mut self) -> &mut Vec { &mut self.inner } + fn as_mut(&mut self) -> &mut Vec { + &mut self.inner + } } impl AsMut<[String]> for StringList { - fn as_mut(&mut self) -> &mut [String] { &mut self.inner } + fn as_mut(&mut self) -> &mut [String] { + &mut self.inner + } } impl> FromIterator for StringList { fn from_iter>(iter: I) -> Self { StringList { - inner: iter - .into_iter() - .take((u8::MAX - 1) as _) - .map(|s| s.into()) - .collect(), + inner: iter.into_iter().take((u8::MAX - 1) as _).map(|s| s.into()).collect(), } } } @@ -127,17 +147,15 @@ impl IntoIterator for StringList { type IntoIter = vec::IntoIter; type Item = String; - fn into_iter(self) -> Self::IntoIter { self.inner.into_iter() } + fn into_iter(self) -> Self::IntoIter { + self.inner.into_iter() + } } impl serde::Serialize for StringList { - fn serialize( - &self, - serializer: S, - ) -> Result { + fn serialize(&self, serializer: S) -> Result { let len = self.inner.len() as u8; - let total_string_len = - self.inner.iter().map(|s| s.len() + 1).sum::(); + let total_string_len = self.inner.iter().map(|s| s.len() + 1).sum::(); let mut bytes = Vec::with_capacity(total_string_len); bytes.push(len); for s in &self.inner { @@ -157,25 +175,17 @@ impl serde::Serialize for StringList { } impl<'de> serde::Deserialize<'de> for StringList { - fn deserialize>( - deserializer: D, - ) -> Result { + fn deserialize>(deserializer: D) -> Result { struct StringListVisitor; impl<'de> serde::de::Visitor<'de> for StringListVisitor { type Value = StringList; - fn expecting( - &self, - formatter: &mut core::fmt::Formatter, - ) -> core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { formatter.write_str("a list of strings") } - fn visit_bytes( - self, - v: &[u8], - ) -> Result { + fn visit_bytes(self, v: &[u8]) -> Result { let mut strings = Vec::new(); let mut reader = bytes::Bytes::copy_from_slice(v); let len = reader.get_u8() as usize; @@ -237,8 +247,7 @@ mod tests { #[test] fn test_from_iterator() { - let list: StringList = - ["hello", "world"].iter().map(|s| s.to_string()).collect(); + let list: StringList = ["hello", "world"].iter().map(|s| s.to_string()).collect(); assert_eq!(list.len(), 2); assert_eq!(list.as_vec()[0], "hello"); assert_eq!(list.as_vec()[1], "world"); @@ -246,8 +255,7 @@ mod tests { #[test] fn test_serialize_deserialize() { - let list = - StringList::from(vec!["hello".to_string(), "world".to_string()]); + let list = StringList::from(vec!["hello".to_string(), "world".to_string()]); let serialized = crate::to_bytes(&list).unwrap(); let deserialized: StringList = crate::from_bytes(&serialized).unwrap(); assert_eq!(list, deserialized); @@ -271,8 +279,7 @@ mod tests { msgs: StringList::from(vec!["hello", "world"]), }; let serialized = crate::to_bytes(&msg).unwrap(); - let deserialized: MsgTaskDialog = - crate::from_bytes(&serialized).unwrap(); + let deserialized: MsgTaskDialog = crate::from_bytes(&serialized).unwrap(); assert_eq!(msg, deserialized); } } diff --git a/crates/server/src/error.rs b/crates/server/src/error.rs index 58ef0d5..09b1d5c 100644 --- a/crates/server/src/error.rs +++ b/crates/server/src/error.rs @@ -18,15 +18,21 @@ impl core::fmt::Display for Error { } impl From for Error { - fn from(e: tq_network::Error) -> Self { Self::TQNetwork(e) } + fn from(e: tq_network::Error) -> Self { + Self::TQNetwork(e) + } } impl From for Error { - fn from(e: std::net::AddrParseError) -> Self { Self::AddrParseError(e) } + fn from(e: std::net::AddrParseError) -> Self { + Self::AddrParseError(e) + } } impl From for Error { - fn from(e: std::io::Error) -> Self { Self::IO(e) } + fn from(e: std::io::Error) -> Self { + Self::IO(e) + } } impl std::error::Error for Error {} diff --git a/crates/server/src/lib.rs b/crates/server/src/lib.rs index ad4896d..1e95762 100644 --- a/crates/server/src/lib.rs +++ b/crates/server/src/lib.rs @@ -49,10 +49,7 @@ pub trait TQServer: Sized + Send + Sync { /// Runs the server and listen on the configured Address for new /// Connections. #[tracing::instrument(skip(state))] - async fn run( - addr: A, - state: &'static ::State, - ) -> Result<(), Error> + async fn run(addr: A, state: &'static ::State) -> Result<(), Error> where A: Debug + ToSocketAddrs + Send + Sync, { @@ -64,10 +61,7 @@ pub trait TQServer: Sized + Send + Sync { while let Some(stream) = incoming.next().await { let stream = match stream { Ok(s) => { - tracing::debug!( - "Got Connection from {}", - s.peer_addr()? - ); + tracing::debug!("Got Connection from {}", s.peer_addr()?); s.set_nodelay(true)?; s.set_linger(None)?; s.set_ttl(5)?; @@ -83,14 +77,13 @@ pub trait TQServer: Sized + Send + Sync { }; Builder::new().name("TCP Stream").spawn(async { tracing::trace!("Calling on_connected lifetime hook"); - Self::on_connected(state, stream.peer_addr()?) - .await?; + Self::on_connected(state, stream.peer_addr()?).await?; let (tx, rx) = mpsc::channel(1024); let actor = Actor::::new(tx); match handle_stream::(stream, state, &actor, rx).await { Err(e) => { tracing::error!("{e}"); - } + }, Ok(_) => { tracing::debug!("Client Disconnected."); }, @@ -133,15 +126,10 @@ async fn handle_stream( while let Some(packet) = decoder.next().await { let (id, bytes) = packet?; - if let Err(err) = - S::PacketHandler::handle((id, bytes), state, actor).await - { + if let Err(err) = S::PacketHandler::handle((id, bytes), state, actor).await { let result = actor.send(err).await; if let Err(e) = result { - tracing::error!( - ?e, - "Got Error while sending error packet, stopping task." - ); + tracing::error!(?e, "Got Error while sending error packet, stopping task."); break; } } diff --git a/crates/tracing-wasm/src/lib.rs b/crates/tracing-wasm/src/lib.rs index c64dd5f..cc15978 100644 --- a/crates/tracing-wasm/src/lib.rs +++ b/crates/tracing-wasm/src/lib.rs @@ -31,13 +31,7 @@ use tracing_subscriber::fmt::MakeWriter; #[link(wasm_import_module = "host")] #[cfg(target_arch = "wasm32")] extern "C" { - fn trace_event( - level: u8, - target: *const u8, - target_len: u32, - message: *const u8, - message_len: u32, - ); + fn trace_event(level: u8, target: *const u8, target_len: u32, message: *const u8, message_len: u32); } /// A [`MakeWriter`] emitting the written text to the [`host`]. @@ -47,7 +41,9 @@ pub struct MakeWasmWriter { } impl Default for MakeWasmWriter { - fn default() -> Self { Self::new() } + fn default() -> Self { + Self::new() + } } impl MakeWasmWriter { @@ -129,7 +125,9 @@ impl std::io::Write for WasmWriter { self.buffer.write(buf) } - fn flush(&mut self) -> std::io::Result<()> { Ok(()) } + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } } #[cfg(feature = "std")] impl<'a> MakeWriter<'a> for MakeWasmWriter { @@ -144,10 +142,7 @@ impl<'a> MakeWriter<'a> for MakeWasmWriter { } } - fn make_writer_for( - &'a self, - meta: &tracing_core::Metadata<'_>, - ) -> Self::Writer { + fn make_writer_for(&'a self, meta: &tracing_core::Metadata<'_>) -> Self::Writer { let level = *meta.level(); let target = meta.target().to_string(); WasmWriter { diff --git a/crates/wasm-builder/src/builder.rs b/crates/wasm-builder/src/builder.rs index 1ba6492..61859b0 100644 --- a/crates/wasm-builder/src/builder.rs +++ b/crates/wasm-builder/src/builder.rs @@ -34,10 +34,7 @@ impl WasmBuilderSelectProject { /// Use the given `path` as project for building the WASM binary. /// /// Returns an error if the given `path` does not points to a `Cargo.toml`. - pub fn with_project( - self, - path: impl Into, - ) -> Result { + pub fn with_project(self, path: impl Into) -> Result { let path = path.into(); if path.ends_with("Cargo.toml") && path.exists() { @@ -90,8 +87,7 @@ impl WasmBuilder { /// /// This adds `-Clink-arg=--export=__heap_base` to `RUST_FLAGS`. pub fn export_heap_base(mut self) -> Self { - self.rust_flags - .push("-Clink-arg=--export=__heap_base".into()); + self.rust_flags.push("-Clink-arg=--export=__heap_base".into()); self } @@ -132,11 +128,8 @@ impl WasmBuilder { /// Build the WASM binary. pub fn build(self) { - let out_dir = PathBuf::from( - env::var("OUT_DIR").expect("`OUT_DIR` is set by cargo!"), - ); - let file_path = out_dir - .join(self.file_name.clone().unwrap_or_else(|| "wasm.rs".into())); + let out_dir = PathBuf::from(env::var("OUT_DIR").expect("`OUT_DIR` is set by cargo!")); + let file_path = out_dir.join(self.file_name.clone().unwrap_or_else(|| "wasm.rs".into())); if check_skip_build() { // If we skip the build, we still want to make sure to be called @@ -203,10 +196,7 @@ fn generate_rerun_if_changed_instructions() { // variables changes. println!("cargo:rerun-if-env-changed={}", crate::SKIP_BUILD_ENV); println!("cargo:rerun-if-env-changed={}", crate::FORCE_WASM_BUILD_ENV); - println!( - "cargo:rerun-if-env-changed={}", - generate_crate_skip_build_env_name() - ); + println!("cargo:rerun-if-env-changed={}", generate_crate_skip_build_env_name()); } /// Build the currently built project as wasm binary. @@ -250,15 +240,11 @@ fn build_project( wasm_binary_name, ); - let (wasm_binary, wasm_binary_bloaty) = - if let Some(wasm_binary) = wasm_binary { - ( - wasm_binary.wasm_binary_path_escaped(), - bloaty.bloaty_path_escaped(), - ) - } else { - (bloaty.bloaty_path_escaped(), bloaty.bloaty_path_escaped()) - }; + let (wasm_binary, wasm_binary_bloaty) = if let Some(wasm_binary) = wasm_binary { + (wasm_binary.wasm_binary_path_escaped(), bloaty.bloaty_path_escaped()) + } else { + (bloaty.bloaty_path_escaped(), bloaty.bloaty_path_escaped()) + }; crate::write_file_if_changed( file_name, diff --git a/crates/wasm-builder/src/lib.rs b/crates/wasm-builder/src/lib.rs index 48fb1a0..3b4102d 100644 --- a/crates/wasm-builder/src/lib.rs +++ b/crates/wasm-builder/src/lib.rs @@ -158,12 +158,9 @@ const WASM_BUILD_STD: &str = "WASM_BUILD_STD"; /// Write to the given `file` if the `content` is different. fn write_file_if_changed(file: impl AsRef, content: impl AsRef) { - if fs::read_to_string(file.as_ref()).ok().as_deref() - != Some(content.as_ref()) - { - fs::write(file.as_ref(), content.as_ref()).unwrap_or_else(|_| { - panic!("Writing `{}` can not fail!", file.as_ref().display()) - }); + if fs::read_to_string(file.as_ref()).ok().as_deref() != Some(content.as_ref()) { + fs::write(file.as_ref(), content.as_ref()) + .unwrap_or_else(|_| panic!("Writing `{}` can not fail!", file.as_ref().display())); } } @@ -173,29 +170,19 @@ fn copy_file_if_changed(src: PathBuf, dst: PathBuf) { let dst_file = fs::read_to_string(&dst).ok(); if src_file != dst_file { - fs::copy(&src, &dst).unwrap_or_else(|_| { - panic!( - "Copying `{}` to `{}` can not fail; qed", - src.display(), - dst.display() - ) - }); + fs::copy(&src, &dst) + .unwrap_or_else(|_| panic!("Copying `{}` to `{}` can not fail; qed", src.display(), dst.display())); } } /// Get a cargo command that should be used to invoke the compilation. fn get_cargo_command() -> CargoCommand { - let env_cargo = CargoCommand::new( - &env::var("CARGO") - .expect("`CARGO` env variable is always set by cargo"), - ); + let env_cargo = CargoCommand::new(&env::var("CARGO").expect("`CARGO` env variable is always set by cargo")); let default_cargo = CargoCommand::new("cargo"); let wasm_toolchain = env::var(WASM_BUILD_TOOLCHAIN).ok(); // First check if the user requested a specific toolchain - if let Some(cmd) = wasm_toolchain - .map(|t| CargoCommand::new_with_args("rustup", &["run", &t, "cargo"])) - { + if let Some(cmd) = wasm_toolchain.map(|t| CargoCommand::new_with_args("rustup", &["run", &t, "cargo"])) { cmd } else if env_cargo.supports_substrate_wasm_env() { env_cargo @@ -215,26 +202,16 @@ fn get_cargo_command() -> CargoCommand { /// Stable versions are always favored over nightly versions even if the nightly /// versions are newer. fn get_rustup_command() -> Option { - let host = format!( - "-{}", - env::var("HOST").expect("`HOST` is always set by cargo") - ); - - let output = Command::new("rustup") - .args(["toolchain", "list"]) - .output() - .ok()? - .stdout; + let host = format!("-{}", env::var("HOST").expect("`HOST` is always set by cargo")); + + let output = Command::new("rustup").args(["toolchain", "list"]).output().ok()?.stdout; let lines = output.as_slice().lines(); let mut versions = Vec::new(); for line in lines.map_while(Result::ok) { let rustup_version = line.trim_end_matches(&host); - let cmd = CargoCommand::new_with_args( - "rustup", - &["run", rustup_version, "cargo"], - ); + let cmd = CargoCommand::new_with_args("rustup", &["run", rustup_version, "cargo"]); if !cmd.supports_substrate_wasm_env() { continue; @@ -252,10 +229,7 @@ fn get_rustup_command() -> Option { versions.sort_by_key(|v| v.0); let version = &versions.last()?.1; - Some(CargoCommand::new_with_args( - "rustup", - &["run", version, "cargo"], - )) + Some(CargoCommand::new_with_args("rustup", &["run", version, "cargo"])) } /// Wraps a specific command which represents a cargo invocation. @@ -306,12 +280,13 @@ impl CargoCommand { /// Returns the version of this cargo command or `None` if it failed to /// extract the version. - fn version(&self) -> Option { self.version } + fn version(&self) -> Option { + self.version + } /// Returns whether this version of the toolchain supports nightly features. fn supports_nightly_features(&self) -> bool { - self.version.map_or(false, |version| version.is_nightly) - || env::var("RUSTC_BOOTSTRAP").is_ok() + self.version.map_or(false, |version| version.is_nightly) || env::var("RUSTC_BOOTSTRAP").is_ok() } /// Check if the supplied cargo command supports our Substrate wasm @@ -336,9 +311,7 @@ impl CargoCommand { // Check if major and minor are greater or equal than 1.68 or this is a // nightly. - version.major > 1 - || (version.major == 1 && version.minor >= 68) - || version.is_nightly + version.major > 1 || (version.major == 1 && version.minor >= 68) || version.is_nightly } } @@ -354,13 +327,17 @@ impl CargoCommandVersioned { } /// Returns the `rustc` version. - fn rustc_version(&self) -> &str { &self.version } + fn rustc_version(&self) -> &str { + &self.version + } } impl std::ops::Deref for CargoCommandVersioned { type Target = CargoCommand; - fn deref(&self) -> &CargoCommand { &self.command } + fn deref(&self) -> &CargoCommand { + &self.command + } } /// Returns `true` when color output is enabled. @@ -380,9 +357,9 @@ fn get_bool_environment_variable(name: &str) -> Option { Some(false) } else { build_helper::warning!( - "the '{}' environment variable has an invalid value; it must be either '1' or '0'", - name - ); + "the '{}' environment variable has an invalid value; it must be either '1' or '0'", + name + ); std::process::exit(1); } } diff --git a/crates/wasm-builder/src/prerequisites.rs b/crates/wasm-builder/src/prerequisites.rs index e090c8c..502cc4c 100644 --- a/crates/wasm-builder/src/prerequisites.rs +++ b/crates/wasm-builder/src/prerequisites.rs @@ -22,9 +22,9 @@ pub(crate) fn check() -> Result { if !cargo_command.supports_substrate_wasm_env() { return Err(print_error_message( - "Cannot compile the WASM runtime: no compatible Rust compiler found!\n\ + "Cannot compile the WASM runtime: no compatible Rust compiler found!\n\ Install at least Rust 1.68.0 or a recent nightly version.", - )); + )); } check_wasm_toolchain_installed(cargo_command) @@ -33,8 +33,7 @@ pub(crate) fn check() -> Result { /// Creates a minimal dummy crate at the given path and returns the manifest /// path. fn create_minimal_crate(project_dir: &Path) -> std::path::PathBuf { - fs::create_dir_all(project_dir.join("src")) - .expect("Creating src dir does not fail; qed"); + fs::create_dir_all(project_dir.join("src")).expect("Creating src dir does not fail; qed"); let manifest_path = project_dir.join("Cargo.toml"); write_file_if_changed( @@ -53,9 +52,7 @@ fn create_minimal_crate(project_dir: &Path) -> std::path::PathBuf { manifest_path } -fn check_wasm_toolchain_installed( - cargo_command: CargoCommand, -) -> Result { +fn check_wasm_toolchain_installed(cargo_command: CargoCommand) -> Result { let temp = tempdir().expect("Creating temp dir does not fail; qed"); let manifest_path = create_minimal_crate(temp.path()).display().to_string(); @@ -87,33 +84,33 @@ fn check_wasm_toolchain_installed( cmd }; - let err_msg = print_error_message( - "Rust WASM toolchain is not properly installed; please install it!", - ); - let build_result = prepare_command("build") - .output() - .map_err(|_| err_msg.clone())?; + let err_msg = print_error_message("Rust WASM toolchain is not properly installed; please install it!"); + let build_result = prepare_command("build").output().map_err(|_| err_msg.clone())?; if !build_result.status.success() { return match String::from_utf8(build_result.stderr) { - Ok(ref err) if err.contains("the `wasm32-unknown-unknown` target may not be installed") => - Err(print_error_message("Cannot compile the WASM runtime: the `wasm32-unknown-unknown` target is not installed!\n\ - You can install it with `rustup target add wasm32-unknown-unknown` if you're using `rustup`.")), - - // Apparently this can happen when we're running on a non Tier 1 platform. - Ok(ref err) if err.contains("linker `rust-lld` not found") => - Err(print_error_message("Cannot compile the WASM runtime: `rust-lld` not found!")), - - Ok(ref err) => Err(format!( - "{}\n\n{}\n{}\n{}{}\n", - err_msg, - style("Further error information:").yellow().bold(), - style("-".repeat(60)).yellow().bold(), - err, - style("-".repeat(60)).yellow().bold(), - )), - - Err(_) => Err(err_msg), - }; + Ok(ref err) if err.contains("the `wasm32-unknown-unknown` target may not be installed") => { + Err(print_error_message( + "Cannot compile the WASM runtime: the `wasm32-unknown-unknown` target is not installed!\n\ + You can install it with `rustup target add wasm32-unknown-unknown` if you're using `rustup`.", + )) + }, + + // Apparently this can happen when we're running on a non Tier 1 platform. + Ok(ref err) if err.contains("linker `rust-lld` not found") => Err(print_error_message( + "Cannot compile the WASM runtime: `rust-lld` not found!", + )), + + Ok(ref err) => Err(format!( + "{}\n\n{}\n{}\n{}{}\n", + err_msg, + style("Further error information:").yellow().bold(), + style("-".repeat(60)).yellow().bold(), + err, + style("-".repeat(60)).yellow().bold(), + )), + + Err(_) => Err(err_msg), + }; } let mut run_cmd = prepare_command("rustc"); @@ -128,11 +125,7 @@ fn check_wasm_toolchain_installed( if crate::build_std_required() { let mut sysroot_cmd = prepare_command("rustc"); sysroot_cmd.args(["-q", "--", "--print", "sysroot"]); - if let Some(sysroot) = sysroot_cmd - .output() - .ok() - .and_then(|o| String::from_utf8(o.stdout).ok()) - { + if let Some(sysroot) = sysroot_cmd.output().ok().and_then(|o| String::from_utf8(o.stdout).ok()) { let src_path = Path::new(sysroot.trim()) .join("lib") .join("rustlib") @@ -140,9 +133,9 @@ fn check_wasm_toolchain_installed( .join("rust"); if !src_path.exists() { return Err(print_error_message( - "Cannot compile the WASM runtime: no standard library sources found!\n\ + "Cannot compile the WASM runtime: no standard library sources found!\n\ You can install them with `rustup component add rust-src` if you're using `rustup`.", - )); + )); } } } diff --git a/crates/wasm-builder/src/version.rs b/crates/wasm-builder/src/version.rs index 26fda1e..c8990f7 100644 --- a/crates/wasm-builder/src/version.rs +++ b/crates/wasm-builder/src/version.rs @@ -14,10 +14,14 @@ pub struct Version { impl Version { /// Returns if `self` is a stable version. - pub fn is_stable(&self) -> bool { !self.is_nightly } + pub fn is_stable(&self) -> bool { + !self.is_nightly + } /// Return if `self` is a nightly version. - pub fn is_nightly(&self) -> bool { self.is_nightly } + pub fn is_nightly(&self) -> bool { + self.is_nightly + } /// Extract from the given `version` string. pub fn extract(version: &str) -> Option { @@ -46,9 +50,7 @@ impl Version { .nth(3) .map(|date| { date.split('-') - .filter_map(|v| { - v.trim().strip_suffix(')').unwrap_or(v).parse().ok() - }) + .filter_map(|v| v.trim().strip_suffix(')').unwrap_or(v).parse().ok()) .collect::>() }) .unwrap_or_default(); @@ -113,20 +115,13 @@ mod tests { #[test] fn version_compare_and_extract_works() { - let version_1_66_0 = - Version::extract("cargo 1.66.0 (d65d197ad 2022-11-15)").unwrap(); - let version_1_66_1 = - Version::extract("cargo 1.66.1 (d65d197ad 2022-11-15)").unwrap(); - let version_1_66_0_nightly = - Version::extract("cargo 1.66.0-nightly (d65d197ad 2022-10-15)") - .unwrap(); + let version_1_66_0 = Version::extract("cargo 1.66.0 (d65d197ad 2022-11-15)").unwrap(); + let version_1_66_1 = Version::extract("cargo 1.66.1 (d65d197ad 2022-11-15)").unwrap(); + let version_1_66_0_nightly = Version::extract("cargo 1.66.0-nightly (d65d197ad 2022-10-15)").unwrap(); let version_1_66_0_nightly_older_date = - Version::extract("cargo 1.66.0-nightly (d65d197ad 2022-10-14)") - .unwrap(); - let version_1_65_0 = - Version::extract("cargo 1.65.0 (d65d197ad 2022-10-15)").unwrap(); - let version_1_65_0_older_date = - Version::extract("cargo 1.65.0 (d65d197ad 2022-10-14)").unwrap(); + Version::extract("cargo 1.66.0-nightly (d65d197ad 2022-10-14)").unwrap(); + let version_1_65_0 = Version::extract("cargo 1.65.0 (d65d197ad 2022-10-15)").unwrap(); + let version_1_65_0_older_date = Version::extract("cargo 1.65.0 (d65d197ad 2022-10-14)").unwrap(); assert!(version_1_66_1 > version_1_66_0); assert!(version_1_66_1 > version_1_65_0); @@ -166,8 +161,7 @@ mod tests { #[test] fn parse_with_newline() { - let version_1_66_0 = - Version::extract("cargo 1.66.0 (d65d197ad 2022-11-15)\n").unwrap(); + let version_1_66_0 = Version::extract("cargo 1.66.0 (d65d197ad 2022-11-15)\n").unwrap(); assert_eq!( Version { major: 1, @@ -203,8 +197,7 @@ mod tests { #[test] fn parse_rustc_version() { - let version = - Version::extract("rustc 1.73.0 (cc66ad468 2023-10-03)").unwrap(); + let version = Version::extract("rustc 1.73.0 (cc66ad468 2023-10-03)").unwrap(); assert_eq!( version, Version { diff --git a/crates/wasm-builder/src/wasm_project.rs b/crates/wasm-builder/src/wasm_project.rs index ee4b70b..7fa4228 100644 --- a/crates/wasm-builder/src/wasm_project.rs +++ b/crates/wasm-builder/src/wasm_project.rs @@ -34,7 +34,9 @@ impl WasmBinaryBloaty { } /// Returns the path to the binary. - pub fn bloaty_path(&self) -> &Path { &self.0 } + pub fn bloaty_path(&self) -> &Path { + &self.0 + } } /// Holds the path to the WASM binary. @@ -42,7 +44,9 @@ pub struct WasmBinary(PathBuf); impl WasmBinary { /// Returns the path to the wasm binary. - pub fn wasm_binary_path(&self) -> &Path { &self.0 } + pub fn wasm_binary_path(&self) -> &Path { + &self.0 + } /// Returns the escaped path to the wasm binary. pub fn wasm_binary_path_escaped(&self) -> String { @@ -59,13 +63,12 @@ fn crate_metadata(cargo_manifest: &Path) -> Metadata { // If we can find a `Cargo.lock`, we assume that this is the workspace root // and there exists a `Cargo.toml` that we can use for getting the // metadata. - let cargo_manifest = - if let Some(mut cargo_lock) = find_cargo_lock(cargo_manifest) { - cargo_lock.set_file_name("Cargo.toml"); - cargo_lock - } else { - cargo_manifest.to_path_buf() - }; + let cargo_manifest = if let Some(mut cargo_lock) = find_cargo_lock(cargo_manifest) { + cargo_lock.set_file_name("Cargo.toml"); + cargo_lock + } else { + cargo_manifest.to_path_buf() + }; let crate_metadata_command = create_metadata_command(cargo_manifest); @@ -112,17 +115,11 @@ pub(crate) fn create_and_compile( let build_config = BuildConfiguration::detect(&project); // Build the bloaty runtime blob - build_bloaty_blob( - &build_config.blob_build_profile, - &project, - default_rustflags, - cargo_cmd, - ); + build_bloaty_blob(&build_config.blob_build_profile, &project, default_rustflags, cargo_cmd); // Get the name of the bloaty runtime blob. let bloaty_blob_default_name = get_blob_name(project_cargo_toml); - let bloaty_blob_out_name = bloaty_blob_out_name_override - .unwrap_or_else(|| bloaty_blob_default_name.clone()); + let bloaty_blob_out_name = bloaty_blob_out_name_override.unwrap_or_else(|| bloaty_blob_default_name.clone()); let bloaty_blob_binary = copy_bloaty_blob( &project, @@ -140,30 +137,25 @@ pub(crate) fn create_and_compile( // This is because, by default the inner profile will be set to `Release` // even when the outer profile is `Debug`, because the blob built in // `Debug` profile is too slow for normal development activities. - let (compact_blob_path, compact_compressed_blob_path) = - if build_config.outer_build_profile.wants_compact() { - let compact_blob_path = compact_wasm( - &project, - &build_config.blob_build_profile, - project_cargo_toml, - &bloaty_blob_out_name, - ); - // TODO: Compress the compacted blob. - (compact_blob_path, None) - } else { - (None, None) - }; + let (compact_blob_path, compact_compressed_blob_path) = if build_config.outer_build_profile.wants_compact() { + let compact_blob_path = compact_wasm( + &project, + &build_config.blob_build_profile, + project_cargo_toml, + &bloaty_blob_out_name, + ); + // TODO: Compress the compacted blob. + (compact_blob_path, None) + } else { + (None, None) + }; if let Some(wasm_binary) = compact_blob_path.as_ref() { copy_blob_to_target_directory(project_cargo_toml, wasm_binary) } - if let Some(wasm_binary_compressed) = compact_compressed_blob_path.as_ref() - { - copy_blob_to_target_directory( - project_cargo_toml, - wasm_binary_compressed, - ) + if let Some(wasm_binary_compressed) = compact_compressed_blob_path.as_ref() { + copy_blob_to_target_directory(project_cargo_toml, wasm_binary_compressed) } let final_blob_binary = compact_compressed_blob_path.or(compact_blob_path); @@ -176,13 +168,8 @@ pub(crate) fn create_and_compile( &bloaty_blob_binary, ); - if let Err(err) = - adjust_mtime(&bloaty_blob_binary, final_blob_binary.as_ref()) - { - build_helper::warning!( - "Error while adjusting the mtime of the blob binaries: {}", - err - ) + if let Err(err) = adjust_mtime(&bloaty_blob_binary, final_blob_binary.as_ref()) { + build_helper::warning!("Error while adjusting the mtime of the blob binaries: {}", err) } (final_blob_binary, bloaty_blob_binary) @@ -264,11 +251,9 @@ fn find_cargo_lock(cargo_manifest: &Path) -> Option { /// Extract the crate name from the given `Cargo.toml`. fn get_crate_name(cargo_manifest: &Path) -> String { - let cargo_toml: Table = toml::from_str( - &fs::read_to_string(cargo_manifest) - .expect("File exists as checked before; qed"), - ) - .expect("Cargo manifest is a valid toml file; qed"); + let cargo_toml: Table = + toml::from_str(&fs::read_to_string(cargo_manifest).expect("File exists as checked before; qed")) + .expect("Cargo manifest is a valid toml file; qed"); let package = cargo_toml .get("package") @@ -293,9 +278,7 @@ fn get_wasm_workspace_root() -> PathBuf { loop { match out_dir.parent() { - Some(parent) if out_dir.ends_with("build") => { - return parent.to_path_buf() - }, + Some(parent) if out_dir.ends_with("build") => return parent.to_path_buf(), _ => { if !out_dir.pop() { break; @@ -304,10 +287,7 @@ fn get_wasm_workspace_root() -> PathBuf { } } - panic!( - "Could not find target dir in: {}", - build_helper::out_dir().display() - ) + panic!("Could not find target dir in: {}", build_helper::out_dir().display()) } fn create_project_cargo_toml( @@ -319,8 +299,7 @@ fn create_project_cargo_toml( enabled_features: impl Iterator, ) { let mut workspace_toml: Table = toml::from_str( - &fs::read_to_string(workspace_root_path.join("Cargo.toml")) - .expect("Workspace root `Cargo.toml` exists; qed"), + &fs::read_to_string(workspace_root_path.join("Cargo.toml")).expect("Workspace root `Cargo.toml` exists; qed"), ) .expect("Workspace root `Cargo.toml` is a valid toml file; qed"); @@ -347,10 +326,7 @@ fn create_project_cargo_toml( wasm_workspace_toml.insert("profile".into(), profile.into()); // Add patch section from the project root `Cargo.toml` - while let Some(mut patch) = workspace_toml - .remove("patch") - .and_then(|p| p.try_into::
().ok()) - { + while let Some(mut patch) = workspace_toml.remove("patch").and_then(|p| p.try_into::
().ok()) { // Iterate over all patches and make the patch path absolute from the // workspace root path. patch @@ -361,19 +337,13 @@ fn create_project_cargo_toml( }) .flatten() .for_each(|p| { - p.iter_mut() - .filter(|(k, _)| k == &"path") - .for_each(|(_, v)| { - if let Some(path) = v.as_str().map(PathBuf::from) { - if path.is_relative() { - *v = workspace_root_path - .join(path) - .display() - .to_string() - .into(); - } + p.iter_mut().filter(|(k, _)| k == &"path").for_each(|(_, v)| { + if let Some(path) = v.as_str().map(PathBuf::from) { + if path.is_relative() { + *v = workspace_root_path.join(path).display().to_string().into(); } - }) + } + }) }); wasm_workspace_toml.insert("patch".into(), patch.into()); @@ -398,10 +368,7 @@ fn create_project_cargo_toml( wasm_project.insert("package".into(), crate_name.into()); wasm_project.insert("path".into(), crate_path.display().to_string().into()); wasm_project.insert("default-features".into(), false.into()); - wasm_project.insert( - "features".into(), - enabled_features.collect::>().into(), - ); + wasm_project.insert("features".into(), enabled_features.collect::>().into()); dependencies.insert("wasm-project".into(), wasm_project.into()); @@ -411,8 +378,7 @@ fn create_project_cargo_toml( write_file_if_changed( wasm_workspace.join("Cargo.toml"), - toml::to_string_pretty(&wasm_workspace_toml) - .expect("Wasm workspace toml is valid; qed"), + toml::to_string_pretty(&wasm_workspace_toml).expect("Wasm workspace toml is valid; qed"), ); } @@ -452,9 +418,7 @@ fn find_package_by_manifest_path<'a>( pkg } } else { - panic!( - "Failed to find entry for package {pkg_name} ({manifest_path:?})." - ); + panic!("Failed to find entry for package {pkg_name} ({manifest_path:?})."); } } @@ -464,8 +428,7 @@ fn project_enabled_features( cargo_manifest: &Path, crate_metadata: &cargo_metadata::Metadata, ) -> Vec { - let package = - find_package_by_manifest_path(pkg_name, cargo_manifest, crate_metadata); + let package = find_package_by_manifest_path(pkg_name, cargo_manifest, crate_metadata); let std_enabled = package.features.get("std"); @@ -520,8 +483,7 @@ fn has_runtime_wasm_feature_declared( cargo_manifest: &Path, crate_metadata: &cargo_metadata::Metadata, ) -> bool { - let package = - find_package_by_manifest_path(pkg_name, cargo_manifest, crate_metadata); + let package = find_package_by_manifest_path(pkg_name, cargo_manifest, crate_metadata); package.features.keys().any(|k| k == "runtime-wasm") } @@ -539,31 +501,19 @@ fn create_project( features_to_enable: Vec, ) -> PathBuf { let crate_name = get_crate_name(project_cargo_toml); - let crate_path = project_cargo_toml - .parent() - .expect("Parent path exists; qed"); + let crate_path = project_cargo_toml.parent().expect("Parent path exists; qed"); let wasm_binary = get_blob_name(project_cargo_toml); let wasm_project_folder = wasm_workspace.join(&crate_name); - fs::create_dir_all(wasm_project_folder.join("src")) - .expect("Wasm project dir create can not fail; qed"); + fs::create_dir_all(wasm_project_folder.join("src")).expect("Wasm project dir create can not fail; qed"); - let mut enabled_features = project_enabled_features( - &crate_name, - project_cargo_toml, - crate_metadata, - ); + let mut enabled_features = project_enabled_features(&crate_name, project_cargo_toml, crate_metadata); - if has_runtime_wasm_feature_declared( - &crate_name, - project_cargo_toml, - crate_metadata, - ) { + if has_runtime_wasm_feature_declared(&crate_name, project_cargo_toml, crate_metadata) { enabled_features.push("runtime-wasm".into()); } - let mut enabled_features = - enabled_features.into_iter().collect::>(); + let mut enabled_features = enabled_features.into_iter().collect::>(); enabled_features.extend(features_to_enable); create_project_cargo_toml( @@ -582,10 +532,7 @@ fn create_project( if let Some(crate_lock_file) = find_cargo_lock(project_cargo_toml) { // Use the `Cargo.lock` of the main project. - crate::copy_file_if_changed( - crate_lock_file, - wasm_project_folder.join("Cargo.lock"), - ); + crate::copy_file_if_changed(crate_lock_file, wasm_project_folder.join("Cargo.lock")); } wasm_project_folder @@ -626,7 +573,9 @@ impl Profile { } /// Whether the resulting binary should be compacted and compressed. - fn wants_compact(&self) -> bool { !matches!(self, Self::Debug) } + fn wants_compact(&self) -> bool { + !matches!(self, Self::Debug) + } } /// The build configuration for this build. @@ -661,9 +610,7 @@ impl BuildConfiguration { /// /// Can be overriden by setting [`crate::WASM_BUILD_TYPE_ENV`]. fn detect(wasm_project: &Path) -> Self { - let (name, overriden) = if let Ok(name) = - env::var(crate::WASM_BUILD_TYPE_ENV) - { + let (name, overriden) = if let Ok(name) = env::var(crate::WASM_BUILD_TYPE_ENV) { (name, true) } else { // First go backwards to the beginning of the target directory. @@ -672,25 +619,23 @@ impl BuildConfiguration { // root there might be a chance that someone has // a "wbuild" directory somewhere in the path. let name = wasm_project - .components() - .rev() - .take_while(|c| c.as_os_str() != "target") - .collect::>() - .iter() - .rev() - .take_while(|c| c.as_os_str() != "wbuild") - .last() - .expect("We put the wasm project within a `target/.../wbuild` path; qed") - .as_os_str() - .to_str() - .expect("All our profile directory names are ascii; qed") - .to_string(); + .components() + .rev() + .take_while(|c| c.as_os_str() != "target") + .collect::>() + .iter() + .rev() + .take_while(|c| c.as_os_str() != "wbuild") + .last() + .expect("We put the wasm project within a `target/.../wbuild` path; qed") + .as_os_str() + .to_str() + .expect("All our profile directory names are ascii; qed") + .to_string(); (name, false) }; - let outer_build_profile = - Profile::iter().find(|p| p.directory() == name); - let blob_build_profile = match (outer_build_profile.clone(), overriden) - { + let outer_build_profile = Profile::iter().find(|p| p.directory() == name); + let blob_build_profile = match (outer_build_profile.clone(), overriden) { // When not overriden by a env variable we default to using the // `Release` profile for the wasm build even when the // main build uses the debug build. This is because the @@ -724,15 +669,16 @@ impl BuildConfiguration { }, }; BuildConfiguration { - outer_build_profile: outer_build_profile - .unwrap_or(Profile::Release), + outer_build_profile: outer_build_profile.unwrap_or(Profile::Release), blob_build_profile, } } } /// Check environment whether we should build without network -fn offline_build() -> bool { env::var(OFFLINE).map_or(false, |v| v == "true") } +fn offline_build() -> bool { + env::var(OFFLINE).map_or(false, |v| v == "true") +} /// Build the project and create the bloaty runtime blob. fn build_bloaty_blob( @@ -748,7 +694,7 @@ fn build_bloaty_blob( "-C target-cpu=mvp -C target-feature=-sign-ext -C link-arg=--export-table {} {}", default_rustflags, env::var(crate::WASM_BUILD_RUSTFLAGS_ENV).unwrap_or_default(), - ); + ); build_cmd .args(["rustc", "--target=wasm32-unknown-unknown"]) @@ -800,15 +746,9 @@ fn build_bloaty_blob( println!( "{}", - colorize_info_message( - "Information that should be included in a bug report." - ) - ); - println!( - "{} {:?}", - colorize_info_message("Executing build command:"), - build_cmd + colorize_info_message("Information that should be included in a bug report.") ); + println!("{} {:?}", colorize_info_message("Executing build command:"), build_cmd); println!( "{} {}", colorize_info_message("Using rustc version:"), @@ -821,12 +761,7 @@ fn build_bloaty_blob( } } -fn compact_wasm( - project: &Path, - inner_profile: &Profile, - cargo_manifest: &Path, - out_name: &str, -) -> Option { +fn compact_wasm(project: &Path, inner_profile: &Profile, cargo_manifest: &Path, out_name: &str) -> Option { let default_out_name = get_blob_name(cargo_manifest); let in_path = project .join("target/wasm32-unknown-unknown") @@ -849,34 +784,24 @@ fn compact_wasm( Some(WasmBinary(wasm_compact_path)) } -fn copy_bloaty_blob( - project: &Path, - inner_profile: &Profile, - in_name: &str, - out_name: &str, -) -> WasmBinaryBloaty { +fn copy_bloaty_blob(project: &Path, inner_profile: &Profile, in_name: &str, out_name: &str) -> WasmBinaryBloaty { let in_path = project .join("target/wasm32-unknown-unknown") .join(inner_profile.directory()) .join(format!("{}.wasm", in_name)); let bloaty_path = project.join(format!("{}.wasm", out_name)); - fs::copy(in_path, &bloaty_path) - .expect("Copying the bloaty file to the project dir."); + fs::copy(in_path, &bloaty_path).expect("Copying the bloaty file to the project dir."); WasmBinaryBloaty(bloaty_path) } -fn process_bloaty_blob( - bloty_blob_binary: WasmBinaryBloaty, -) -> WasmBinaryBloaty { +fn process_bloaty_blob(bloty_blob_binary: WasmBinaryBloaty) -> WasmBinaryBloaty { let processor = externref::processor::Processor::default(); - let wasm_bytes = fs::read(bloty_blob_binary.bloaty_path()) - .expect("Reading the bloaty file."); + let wasm_bytes = fs::read(bloty_blob_binary.bloaty_path()).expect("Reading the bloaty file."); let processed_wasm_bytes = processor .process_bytes(&wasm_bytes) .expect("Processing the bloaty file."); - fs::write(bloty_blob_binary.bloaty_path(), processed_wasm_bytes) - .expect("Writing the bloaty file."); + fs::write(bloty_blob_binary.bloaty_path(), processed_wasm_bytes).expect("Writing the bloaty file."); bloty_blob_binary } @@ -892,20 +817,21 @@ impl<'a> From<&'a cargo_metadata::Package> for DeduplicatePackage<'a> { fn from(package: &'a cargo_metadata::Package) -> Self { Self { package, - identifier: format!( - "{}{}{:?}", - package.name, package.version, package.source - ), + identifier: format!("{}{}{:?}", package.name, package.version, package.source), } } } impl<'a> Hash for DeduplicatePackage<'a> { - fn hash(&self, state: &mut H) { self.identifier.hash(state); } + fn hash(&self, state: &mut H) { + self.identifier.hash(state); + } } impl<'a> PartialEq for DeduplicatePackage<'a> { - fn eq(&self, other: &Self) -> bool { self.identifier == other.identifier } + fn eq(&self, other: &Self) -> bool { + self.identifier == other.identifier + } } impl<'a> Eq for DeduplicatePackage<'a> {} @@ -913,7 +839,9 @@ impl<'a> Eq for DeduplicatePackage<'a> {} impl<'a> Deref for DeduplicatePackage<'a> { type Target = cargo_metadata::Package; - fn deref(&self) -> &Self::Target { self.package } + fn deref(&self) -> &Self::Target { + self.package + } } fn create_metadata_command(path: impl Into) -> MetadataCommand { @@ -978,8 +906,7 @@ fn generate_rerun_if_changed_instructions( // this is a git or path dep. A git or path // dependency can only occur once, so we don't // need to check the version. - (path_or_git_dep || dependency.req.matches(&p.version)) - && dependency.name == p.name + (path_or_git_dep || dependency.req.matches(&p.version)) && dependency.name == p.name }); if let Some(package) = package { @@ -1001,14 +928,8 @@ fn generate_rerun_if_changed_instructions( // Register our env variables println!("cargo:rerun-if-env-changed={}", crate::SKIP_BUILD_ENV); println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_TYPE_ENV); - println!( - "cargo:rerun-if-env-changed={}", - crate::WASM_BUILD_RUSTFLAGS_ENV - ); - println!( - "cargo:rerun-if-env-changed={}", - crate::WASM_TARGET_DIRECTORY - ); + println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_RUSTFLAGS_ENV); + println!("cargo:rerun-if-env-changed={}", crate::WASM_TARGET_DIRECTORY); println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_TOOLCHAIN); println!("cargo:rerun-if-env-changed={}", crate::WASM_BUILD_STD); } @@ -1029,25 +950,16 @@ fn package_rerun_if_changed(package: &DeduplicatePackage) { // the current package. This is done to ignore sub-crates of a // crate. If such a sub-crate is a dependency, it will be processed // independently anyway. - p.path() == manifest_path - || !p.path().is_dir() - || !p.path().join("Cargo.toml").exists() + p.path() == manifest_path || !p.path().is_dir() || !p.path().join("Cargo.toml").exists() }) .filter_map(|p| p.ok().map(|p| p.into_path())) - .filter(|p| { - p.extension() - .map(|e| e == "rs" || e == "toml") - .unwrap_or_default() - }) + .filter(|p| p.extension().map(|e| e == "rs" || e == "toml").unwrap_or_default()) .for_each(rerun_if_changed); } /// Copy the blob binary to the target directory set in `WASM_TARGET_DIRECTORY` /// environment variable. If the variable is not set, this is a no-op. -fn copy_blob_to_target_directory( - cargo_manifest: &Path, - blob_binary: &WasmBinary, -) { +fn copy_blob_to_target_directory(cargo_manifest: &Path, blob_binary: &WasmBinary) { let target_dir = match env::var(crate::WASM_TARGET_DIRECTORY) { Ok(path) => PathBuf::from(path), Err(_) => return, diff --git a/macros/derive-packethandler/src/lib.rs b/macros/derive-packethandler/src/lib.rs index a994d41..8059f74 100644 --- a/macros/derive-packethandler/src/lib.rs +++ b/macros/derive-packethandler/src/lib.rs @@ -11,50 +11,28 @@ struct Args { impl Parse for Args { fn parse(input: ParseStream) -> syn::Result { - let ident1: Ident = input.parse().map_err(|e| { - syn::Error::new( - e.span(), - "expected `state` or `actor_state` but got nothing", - ) - })?; - let _: Token!(=) = input + let ident1: Ident = input .parse() - .map_err(|e| syn::Error::new(e.span(), "expected `=`"))?; + .map_err(|e| syn::Error::new(e.span(), "expected `state` or `actor_state` but got nothing"))?; + let _: Token!(=) = input.parse().map_err(|e| syn::Error::new(e.span(), "expected `=`"))?; let ident1_value: Expr = input .parse() .map_err(|e| syn::Error::new(e.span(), "expected `Expr`"))?; - let _: Token!(,) = input - .parse() - .map_err(|e| syn::Error::new(e.span(), "expected `,`"))?; - let ident2: Ident = input.parse().map_err(|e| { - syn::Error::new( - e.span(), - "expected `state` or `actor_state` but got nothing", - ) - })?; - let _: Token!(=) = input + let _: Token!(,) = input.parse().map_err(|e| syn::Error::new(e.span(), "expected `,`"))?; + let ident2: Ident = input .parse() - .map_err(|e| syn::Error::new(e.span(), "expected `=`"))?; + .map_err(|e| syn::Error::new(e.span(), "expected `state` or `actor_state` but got nothing"))?; + let _: Token!(=) = input.parse().map_err(|e| syn::Error::new(e.span(), "expected `=`"))?; let ident2_value: Expr = input .parse() .map_err(|e| syn::Error::new(e.span(), "expected `Expr`"))?; let (state, actor_state) = match (ident1, ident2) { - (ident1, ident2) - if ident1 == "state" && ident2 == "actor_state" => - { - (ident1_value, ident2_value) - }, - (ident1, ident2) - if ident1 == "actor_state" && ident2 == "state" => - { - (ident2_value, ident1_value) - }, + (ident1, ident2) if ident1 == "state" && ident2 == "actor_state" => (ident1_value, ident2_value), + (ident1, ident2) if ident1 == "actor_state" && ident2 == "state" => (ident2_value, ident1_value), (v1, v2) => { return Err(syn::Error::new( input.span(), - format!( - "expected `state` or `actor_state` but got {v1} and {v2}", - ), + format!("expected `state` or `actor_state` but got {v1} and {v2}",), )) }, }; @@ -78,9 +56,12 @@ fn derive_packet_handler(input: DeriveInput) -> syn::Result { .attrs .iter() .find(|a| a.path().is_ident("handle")) - .ok_or_else( || - syn::Error::new(name.span(),"Missing State and ActorState! please add #[handle(state = .., actor_state = ...)] on the enum"), - )?; + .ok_or_else(|| { + syn::Error::new( + name.span(), + "Missing State and ActorState! please add #[handle(state = .., actor_state = ...)] on the enum", + ) + })?; let args: Args = attr.parse_args()?; let state = args.state; let actor_state = args.actor_state; @@ -144,6 +125,5 @@ fn body(e: DataEnum) -> syn::Result { pub fn derive(input: TokenStream) -> TokenStream { // Parse the input tokens into a syntax tree let input = parse_macro_input!(input as DeriveInput); - derive_packet_handler(input) - .unwrap_or_else(|err| err.to_compile_error().into()) + derive_packet_handler(input).unwrap_or_else(|err| err.to_compile_error().into()) } diff --git a/macros/derive-packetid/src/lib.rs b/macros/derive-packetid/src/lib.rs index ca2ec0d..426d8a2 100644 --- a/macros/derive-packetid/src/lib.rs +++ b/macros/derive-packetid/src/lib.rs @@ -37,9 +37,12 @@ fn derive_packet_id(input: DeriveInput) -> syn::Result { .attrs .iter() .find(|a| a.path().is_ident("packet")) - .ok_or_else( || - syn::Error::new(name.span(),"Missing Packet id! please add #[packet(id = ..)] on the struct"), - )?; + .ok_or_else(|| { + syn::Error::new( + name.span(), + "Missing Packet id! please add #[packet(id = ..)] on the struct", + ) + })?; let args: Args = attr.parse_args()?; let id = args.id; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); diff --git a/macros/derive-packetprocessor/src/lib.rs b/macros/derive-packetprocessor/src/lib.rs index c224c0e..b44535a 100644 --- a/macros/derive-packetprocessor/src/lib.rs +++ b/macros/derive-packetprocessor/src/lib.rs @@ -23,10 +23,7 @@ macro_rules! syn_assert { }; } -fn derive_packet_processor( - args: Args, - inner_fn: ItemFn, -) -> syn::Result { +fn derive_packet_processor(args: Args, inner_fn: ItemFn) -> syn::Result { let msg_ty = args.msg; // make sure the function has the right signature // fn process(msg: msg_ty, actor: &Resource) -> Result<(), @@ -36,18 +33,9 @@ fn derive_packet_processor( syn_assert!(fn_sig.asyncness.is_none(), "async fn not supported"); syn_assert!(fn_sig.abi.is_none(), "abi fn not supported"); syn_assert!(fn_sig.unsafety.is_none(), "unsafe fn not supported"); - syn_assert!( - fn_sig.generics.params.is_empty(), - "generic fn not supported" - ); - syn_assert!( - fn_sig.generics.where_clause.is_none(), - "generic fn not supported" - ); - syn_assert!( - fn_sig.inputs.len() == 2, - "packet processor must have two arguments" - ); + syn_assert!(fn_sig.generics.params.is_empty(), "generic fn not supported"); + syn_assert!(fn_sig.generics.where_clause.is_none(), "generic fn not supported"); + syn_assert!(fn_sig.inputs.len() == 2, "packet processor must have two arguments"); syn_assert!( fn_sig.output != ReturnType::Default, "packet processor must have a return type" @@ -138,6 +126,5 @@ fn derive_packet_processor( pub fn packet_processor(args: TokenStream, input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as ItemFn); let args = parse_macro_input!(args as Args); - derive_packet_processor(args, input) - .unwrap_or_else(|err| err.to_compile_error().into()) + derive_packet_processor(args, input).unwrap_or_else(|err| err.to_compile_error().into()) } diff --git a/packets/account/src/lib.rs b/packets/account/src/lib.rs index 6ea3613..c66b1bc 100644 --- a/packets/account/src/lib.rs +++ b/packets/account/src/lib.rs @@ -40,17 +40,13 @@ pub enum Error { } #[tq_network::packet_processor(MsgAccount)] -pub fn process( - msg: MsgAccount, - actor: &Resource, -) -> Result<(), crate::Error> { +pub fn process(msg: MsgAccount, actor: &Resource) -> Result<(), crate::Error> { let maybe_accont_id = host::db::account::auth(&msg.username, &msg.password); let account_id = match maybe_accont_id { Ok(id) => id, Err(e) => { let res = match e { - tq_db::Error::AccountNotFound - | tq_db::Error::InvalidPassword => { + tq_db::Error::AccountNotFound | tq_db::Error::InvalidPassword => { RejectionCode::InvalidPassword.packet() }, _ => { diff --git a/packets/connect-ex/src/lib.rs b/packets/connect-ex/src/lib.rs index f761dd2..165c080 100644 --- a/packets/connect-ex/src/lib.rs +++ b/packets/connect-ex/src/lib.rs @@ -28,7 +28,9 @@ pub enum RejectionCode { } impl RejectionCode { - pub fn packet(self) -> MsgConnectRejection { MsgConnectEx::from_code(self) } + pub fn packet(self) -> MsgConnectRejection { + MsgConnectEx::from_code(self) + } } #[derive(Debug, Serialize, PacketID)] diff --git a/packets/connect/src/lib.rs b/packets/connect/src/lib.rs index a7fbcdb..2377717 100644 --- a/packets/connect/src/lib.rs +++ b/packets/connect/src/lib.rs @@ -27,10 +27,7 @@ pub enum Error { } #[tq_network::packet_processor(MsgConnect)] -pub fn process( - msg: MsgConnect, - actor: &Resource, -) -> Result<(), crate::Error> { +pub fn process(msg: MsgConnect, actor: &Resource) -> Result<(), crate::Error> { tracing::debug!(?msg, "Shutting down actor!"); host::network::actor::shutdown(actor); Ok(()) diff --git a/packets/transfer/src/lib.rs b/packets/transfer/src/lib.rs index a9774eb..8579823 100644 --- a/packets/transfer/src/lib.rs +++ b/packets/transfer/src/lib.rs @@ -8,9 +8,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm.rs")); use msg_connect_ex::{AccountCredentials, RejectionCode}; use serde::{Deserialize, Serialize}; use tq_bindings::{host, Resource}; -use tq_network::{ - ActorHandle, ErrorPacket, IntoErrorPacket, PacketEncode, PacketID, -}; +use tq_network::{ActorHandle, ErrorPacket, IntoErrorPacket, PacketEncode, PacketID}; /// Defines account parameters to be transferred from the account server to the /// game server. Account information is supplied from the account database, and @@ -18,25 +16,19 @@ use tq_network::{ #[derive(Clone, Default, Debug, Deserialize, Serialize, PacketID)] #[packet(id = 4001)] pub struct MsgTransfer { - account_id: u32, - realm_id: u32, - token: u64, + pub account_id: u32, + pub realm_id: u32, + pub token: u64, } impl MsgTransfer { - pub fn handle( - actor: &Resource, - realm: &str, - ) -> Result { + pub fn handle(actor: &Resource, realm: &str) -> Result { let maybe_realm = host::db::realm::by_name(realm)?; // Check if there is a realm with that name let realm = match maybe_realm { Some(realm) => realm, None => { - return Err(RejectionCode::ServerLocked - .packet() - .error_packet() - .into()); + return Err(RejectionCode::ServerLocked.packet().error_packet().into()); }, }; // Try to connect to that realm first. @@ -48,10 +40,7 @@ impl MsgTransfer { error = ?e, "Failed to connect to realm" ); - host::network::actor::send( - actor, - RejectionCode::ServerDown.packet(), - )?; + host::network::actor::send(actor, RejectionCode::ServerDown.packet())?; host::network::actor::shutdown(actor); return Err(e.into()); } @@ -71,10 +60,7 @@ impl MsgTransfer { error = ?e, "Failed to transfer account" ); - Err(RejectionCode::ServerTimedOut - .packet() - .error_packet() - .into()) + Err(RejectionCode::ServerTimedOut.packet().error_packet().into()) }, } } @@ -107,15 +93,8 @@ impl From> for Error { } #[tq_network::packet_processor(MsgTransfer)] -pub fn process( - msg: MsgTransfer, - actor: &Resource, -) -> Result<(), crate::Error> { - let token = host::game::state::generate_login_token( - actor, - msg.account_id, - msg.realm_id, - ); +pub fn process(msg: MsgTransfer, actor: &Resource) -> Result<(), crate::Error> { + let token = host::game::state::generate_login_token(actor, msg.account_id, msg.realm_id); let msg = MsgTransfer { account_id: msg.account_id, realm_id: msg.realm_id, diff --git a/rustfmt.toml b/rustfmt.toml index 684f912..37ea1d4 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,6 +1,6 @@ -max_width = 80 +max_width = 120 tab_spaces = 4 -fn_single_line = true +fn_single_line = false match_block_trailing_comma = true normalize_comments = true wrap_comments = true diff --git a/server/auth/Cargo.toml b/server/auth/Cargo.toml index b057040..fda3433 100644 --- a/server/auth/Cargo.toml +++ b/server/auth/Cargo.toml @@ -27,10 +27,13 @@ tokio-stream.workspace = true num_enum.workspace = true futures.workspace = true rand.workspace = true +rkyv = { workspace = true, default-features = false, features = ["alloc", "size_32"] } + # Packets msg-account.workspace = true msg-connect.workspace = true +msg-transfer.workspace = true [dependencies.tq-server] @@ -51,9 +54,8 @@ features = ["env-filter", "ansi", "fmt", "smallvec"] # Runtime [dependencies.tokio] workspace = true -optional = true default-features = false -features = ["rt-multi-thread", "macros", "signal"] +features = [] # Database [dependencies.sqlx] @@ -73,7 +75,10 @@ server = [ "tq-serde/std", "msg-account/std", "msg-connect/std", - "dep:tokio", + "msg-transfer/std", + "tokio/rt-multi-thread", + "tokio/macros", + "tokio/signal", "dep:tq-server", "sqlx/runtime-tokio", "dep:tracing-subscriber", diff --git a/server/auth/src/error.rs b/server/auth/src/error.rs index a7f43cd..89870f5 100644 --- a/server/auth/src/error.rs +++ b/server/auth/src/error.rs @@ -19,36 +19,52 @@ pub enum Error { } impl From for Error { - fn from(v: tq_db::Error) -> Self { Self::Db(v) } + fn from(v: tq_db::Error) -> Self { + Self::Db(v) + } } impl From for Error { - fn from(v: sqlx::Error) -> Self { Self::Sqlx(v) } + fn from(v: sqlx::Error) -> Self { + Self::Sqlx(v) + } } impl From for Error { - fn from(v: std::env::VarError) -> Self { Self::Env(v) } + fn from(v: std::env::VarError) -> Self { + Self::Env(v) + } } impl From for Error { - fn from(v: dotenvy::Error) -> Self { Self::DotEnv(v) } + fn from(v: dotenvy::Error) -> Self { + Self::DotEnv(v) + } } impl From for Error { - fn from(v: std::io::Error) -> Self { Self::IO(v) } + fn from(v: std::io::Error) -> Self { + Self::IO(v) + } } #[cfg(feature = "server")] impl From for Error { - fn from(v: tq_server::Error) -> Self { Self::Server(v) } + fn from(v: tq_server::Error) -> Self { + Self::Server(v) + } } impl From for Error { - fn from(v: tq_network::Error) -> Self { Self::Network(v) } + fn from(v: tq_network::Error) -> Self { + Self::Network(v) + } } impl From for Error { - fn from(v: wasmtime::Error) -> Self { Self::Wasmtime(v) } + fn from(v: wasmtime::Error) -> Self { + Self::Wasmtime(v) + } } impl std::error::Error for Error {} diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index 7d10abd..65516a4 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -34,8 +34,7 @@ impl PacketHandler for Runtime { const ALLOC: &str = "__alloc"; const PROCESS_PACKET: &str = "process_packet"; const MEMORY: &str = "memory"; - let mut store = - wasmtime::Store::new(&runtime.engine, runtime.state.clone()); + let mut store = wasmtime::Store::new(&runtime.engine, runtime.state.clone()); let actor = wasmtime::ExternRef::new(actor.handle()); match packet.0 { msg_connect::MsgConnect::PACKET_ID => { @@ -44,27 +43,18 @@ impl PacketHandler for Runtime { .linker .instantiate_async(&mut store, &runtime.packets.msg_connect) .await?; - let alloc_packet = msg_connect - .get_typed_func::(&mut store, ALLOC)?; - let ptr = alloc_packet - .call_async(&mut store, packet_len as u32) - .await?; + let alloc_packet = msg_connect.get_typed_func::(&mut store, ALLOC)?; + let ptr = alloc_packet.call_async(&mut store, packet_len as u32).await?; let memory = msg_connect .get_memory(&mut store, MEMORY) .expect("Failed to get memory"); memory .write(&mut store, ptr as usize, &packet.1) .expect("Failed to write packet to memory"); - let process = msg_connect - .get_typed_func::<(i32, i32, Option), i32>( - &mut store, - PROCESS_PACKET, - )?; + let process = + msg_connect.get_typed_func::<(i32, i32, Option), i32>(&mut store, PROCESS_PACKET)?; process - .call_async( - &mut store, - (ptr, packet_len as i32, Some(actor)), - ) + .call_async(&mut store, (ptr, packet_len as i32, Some(actor))) .await?; Ok(()) }, @@ -77,13 +67,13 @@ impl PacketHandler for Runtime { } /// Add the runtime to the linker. -pub fn add_to_linker( - linker: &mut Linker, -) -> Result<(), error::Error> { +pub fn add_to_linker(linker: &mut Linker) -> Result<(), error::Error> { linker::network::actor::shutdown(linker)?; linker::network::actor::send(linker)?; linker::log::trace_event(linker)?; linker::rand::getrandom(linker)?; + linker::db::account::auth(linker)?; + linker::db::realm::by_name(linker)?; Ok(()) } @@ -108,9 +98,7 @@ mod tests { let engine = Engine::new(&config).unwrap(); let mut linker = Linker::new(&engine); add_to_linker(&mut linker).unwrap(); - let msg_connect = - Module::from_file(&engine, msg_connect::WASM_BINARY.unwrap()) - .unwrap(); + let msg_connect = Module::from_file(&engine, msg_connect::WASM_BINARY.unwrap()).unwrap(); std::env::set_var("DATABASE_URL", "sqlite::memory:"); let state = State::init().await.unwrap(); let packets = Packets { msg_connect }; @@ -164,9 +152,7 @@ mod tests { let actor = Actor::<()>::new(tx); let encoded = ::encode(&msg).unwrap(); - Runtime::handle(encoded.clone(), &runtime, &actor) - .await - .unwrap(); + Runtime::handle(encoded.clone(), &runtime, &actor).await.unwrap(); let msg = rx.recv().await.unwrap(); assert_eq!(msg, Message::Shutdown); } diff --git a/server/auth/src/main.rs b/server/auth/src/main.rs index fbeacde..34188d0 100644 --- a/server/auth/src/main.rs +++ b/server/auth/src/main.rs @@ -7,9 +7,7 @@ use bytes::Bytes; use msg_connect::MsgConnect; use std::env; -use tq_network::{ - Actor, ActorHandle, PacketDecode, PacketHandler, PacketID, TQCipher, -}; +use tq_network::{Actor, ActorHandle, PacketDecode, PacketHandler, PacketID, TQCipher}; #[cfg(feature = "server")] use tq_server::TQServer; use wasmtime::{Config, Engine, ExternRef, Linker, Module, Store}; @@ -54,10 +52,7 @@ Copyright 2020-2023 Shady Khalifa (@shekohex) auth::add_to_linker(&mut linker)?; tracing::info!("Loading Packet and handlers.."); - let msg_connect = Module::from_file( - &engine, - "./target/wasm32-unknown-unknown/wasm/msg_connect.s.wasm", - )?; + let msg_connect = Module::from_file(&engine, "./target/wasm32-unknown-unknown/wasm/msg_connect.s.wasm")?; tracing::info!("Initializing State .."); let state = State::init().await?; let packets = auth::Packets { msg_connect }; diff --git a/server/auth/src/state.rs b/server/auth/src/state.rs index 2b4b622..cb55979 100644 --- a/server/auth/src/state.rs +++ b/server/auth/src/state.rs @@ -11,10 +11,8 @@ impl State { /// Should only get called once. pub async fn init() -> Result { let data_dir = dotenvy::var("DATA_LOCATION")?; - let default_db_location = - format!("sqlite://{data_dir}/coemu.db?mode=rwc"); - let db_url = - dotenvy::var("DATABASE_URL").unwrap_or(default_db_location); + let default_db_location = format!("sqlite://{data_dir}/coemu.db?mode=rwc"); + let db_url = dotenvy::var("DATABASE_URL").unwrap_or(default_db_location); let pool = SqlitePoolOptions::new() .max_connections(42) .min_connections(4) @@ -25,5 +23,7 @@ impl State { } /// Get access to the database pool - pub fn pool(&self) -> &SqlitePool { &self.pool } + pub fn pool(&self) -> &SqlitePool { + &self.pool + } } diff --git a/server/game/src/constants.rs b/server/game/src/constants.rs index 12383ac..6bcf2c4 100644 --- a/server/game/src/constants.rs +++ b/server/game/src/constants.rs @@ -7,8 +7,7 @@ pub const NEW_ROLE: &str = "NEW_ROLE"; pub const MAX_TXT_LEN: usize = 250; -pub const HAIR_STYLES: [i16; 12] = - [10, 11, 13, 14, 15, 24, 30, 35, 37, 38, 39, 40]; +pub const HAIR_STYLES: [i16; 12] = [10, 11, 13, 14, 15, 24, 30, 35, 37, 38, 39, 40]; pub const WALK_XCOORDS: [i8; 8] = [0, -1, -1, -1, 0, 1, 1, 1]; pub const WALK_YCOORDS: [i8; 8] = [1, 1, 0, -1, -1, -1, 0, 1]; @@ -26,7 +25,9 @@ pub const CALL_PET_ID_MAX: u32 = 799999; pub const CHARACTER_ID_MIN: u32 = 1000000; pub const CHARACTER_ID_MAX: u32 = 10000000; -pub const fn is_npc(id: u32) -> bool { id >= NPC_ID_MIN && id <= NPC_ID_MAX } +pub const fn is_npc(id: u32) -> bool { + id >= NPC_ID_MIN && id <= NPC_ID_MAX +} pub const fn is_terrain_npc(id: u32) -> bool { id >= DYN_NPC_ID_MIN && id <= DYN_NPC_ID_MAX @@ -36,7 +37,9 @@ pub const fn is_monster(id: u32) -> bool { id >= MONSTER_ID_MIN && id <= MONSTER_ID_MAX } -pub const fn is_pet(id: u32) -> bool { id >= PET_ID_MIN && id <= PET_ID_MAX } +pub const fn is_pet(id: u32) -> bool { + id >= PET_ID_MIN && id <= PET_ID_MAX +} pub const fn is_call_pet(id: u32) -> bool { id >= CALL_PET_ID_MIN && id <= CALL_PET_ID_MAX diff --git a/server/game/src/entities/basic.rs b/server/game/src/entities/basic.rs index 9fcda74..a6445a5 100644 --- a/server/game/src/entities/basic.rs +++ b/server/game/src/entities/basic.rs @@ -75,25 +75,40 @@ pub struct Entity { } impl Entity { - pub fn id(&self) -> u32 { self.id } + pub fn id(&self) -> u32 { + self.id + } - pub fn is_character(&self) -> bool { constants::is_character(self.id) } + pub fn is_character(&self) -> bool { + constants::is_character(self.id) + } - pub fn is_npc(&self) -> bool { constants::is_npc(self.id) } + pub fn is_npc(&self) -> bool { + constants::is_npc(self.id) + } - pub fn is_monster(&self) -> bool { constants::is_monster(self.id) } + pub fn is_monster(&self) -> bool { + constants::is_monster(self.id) + } - pub fn is_pet(&self) -> bool { constants::is_pet(self.id) } + pub fn is_pet(&self) -> bool { + constants::is_pet(self.id) + } - pub fn is_call_pet(&self) -> bool { constants::is_call_pet(self.id) } + pub fn is_call_pet(&self) -> bool { + constants::is_call_pet(self.id) + } - pub fn is_terrain_npc(&self) -> bool { constants::is_terrain_npc(self.id) } + pub fn is_terrain_npc(&self) -> bool { + constants::is_terrain_npc(self.id) + } - pub fn name(&self) -> &str { &self.name } + pub fn name(&self) -> &str { + &self.name + } pub fn flags(&self) -> Flags { - Flags::from_bits(self.flags.load(Ordering::Relaxed)) - .unwrap_or(Flags::NONE) + Flags::from_bits(self.flags.load(Ordering::Relaxed)).unwrap_or(Flags::NONE) } pub fn set_flags(&self, flags: Flags) -> &Self { @@ -101,14 +116,18 @@ impl Entity { self } - pub fn mesh(&self) -> u32 { self.mesh.load(Ordering::Relaxed) } + pub fn mesh(&self) -> u32 { + self.mesh.load(Ordering::Relaxed) + } pub fn set_mesh(&self, value: u32) -> &Self { self.mesh.store(value, Ordering::Relaxed); self } - pub fn map_id(&self) -> u32 { self.map_id.load(Ordering::Relaxed) } + pub fn map_id(&self) -> u32 { + self.map_id.load(Ordering::Relaxed) + } pub fn set_map_id(&self, value: u32) -> &Self { let prev_map_id = self.map_id(); @@ -117,7 +136,9 @@ impl Entity { self } - pub fn location(&self) -> Location { self.location.load(Ordering::Relaxed) } + pub fn location(&self) -> Location { + self.location.load(Ordering::Relaxed) + } pub fn set_location(&self, value: Location) -> &Self { let prev_location = self.location(); @@ -126,14 +147,18 @@ impl Entity { self } - pub fn level(&self) -> u16 { self.level.load(Ordering::Relaxed) } + pub fn level(&self) -> u16 { + self.level.load(Ordering::Relaxed) + } pub fn set_level(&self, value: u16) -> &Self { self.level.store(value, Ordering::Relaxed); self } - pub fn action(&self) -> u16 { self.action.load(Ordering::Relaxed) } + pub fn action(&self) -> u16 { + self.action.load(Ordering::Relaxed) + } pub fn set_action(&self, action: u16) -> &Self { self.action.store(action, Ordering::Relaxed); @@ -148,11 +173,17 @@ impl Entity { self.prev_location.load(Ordering::Relaxed) } - pub fn hp(&self) -> Gauge { self.hp.load(Ordering::Relaxed) } + pub fn hp(&self) -> Gauge { + self.hp.load(Ordering::Relaxed) + } - pub fn is_alive(&self) -> bool { !self.flags().contains(Flags::DEAD) } + pub fn is_alive(&self) -> bool { + !self.flags().contains(Flags::DEAD) + } - pub fn is_dead(&self) -> bool { self.flags().contains(Flags::DEAD) } + pub fn is_dead(&self) -> bool { + self.flags().contains(Flags::DEAD) + } } impl From<&tq_db::character::Character> for Entity { @@ -194,11 +225,7 @@ impl From<&tq_db::npc::Npc> for Entity { mesh: AtomicU32::new(v.look as _), name: v.name.clone(), map_id: AtomicU32::new(v.map_id as _), - location: Atomic::new(Location::new( - v.x as _, - v.y as _, - (v.look % 10) as _, - )), + location: Atomic::new(Location::new(v.x as _, v.y as _, (v.look % 10) as _)), flags: AtomicU64::new(Flags::NONE.bits()), level: AtomicU16::new(v.level as _), action: AtomicU16::new(100), diff --git a/server/game/src/entities/character.rs b/server/game/src/entities/character.rs index 464cc9d..d809123 100644 --- a/server/game/src/entities/character.rs +++ b/server/game/src/entities/character.rs @@ -1,7 +1,5 @@ use crate::entities::{Entity, GameEntity}; -use crate::packets::{ - ActionType, MsgAction, MsgMapInfo, MsgPlayer, MsgWeather, -}; +use crate::packets::{ActionType, MsgAction, MsgMapInfo, MsgPlayer, MsgWeather}; use crate::systems::Screen; use crate::utils::LoHi; use crate::Error; @@ -45,51 +43,91 @@ impl Character { } #[inline] - pub fn owner(&self) -> ActorHandle { self.owner.clone() } + pub fn owner(&self) -> ActorHandle { + self.owner.clone() + } #[inline] - pub fn entity(&self) -> &Entity { &self.entity } + pub fn entity(&self) -> &Entity { + &self.entity + } #[inline] - pub fn id(&self) -> u32 { self.entity.id() } + pub fn id(&self) -> u32 { + self.entity.id() + } - pub fn elevation(&self) -> u16 { self.elevation.load(Ordering::Relaxed) } + pub fn elevation(&self) -> u16 { + self.elevation.load(Ordering::Relaxed) + } pub fn set_elevation(&self, value: u16) { self.elevation.store(value, Ordering::Relaxed); } - pub fn hair_style(&self) -> u16 { self.inner.hair_style as u16 } + pub fn hair_style(&self) -> u16 { + self.inner.hair_style as u16 + } - pub fn avatar(&self) -> u16 { self.inner.avatar as u16 } + pub fn avatar(&self) -> u16 { + self.inner.avatar as u16 + } - pub fn silver(&self) -> u64 { self.inner.silver as u64 } + pub fn silver(&self) -> u64 { + self.inner.silver as u64 + } - pub fn cps(&self) -> u64 { self.inner.cps as u64 } + pub fn cps(&self) -> u64 { + self.inner.cps as u64 + } - pub fn experience(&self) -> u64 { self.inner.experience as u64 } + pub fn experience(&self) -> u64 { + self.inner.experience as u64 + } - pub fn strength(&self) -> u16 { self.inner.strength as u16 } + pub fn strength(&self) -> u16 { + self.inner.strength as u16 + } - pub fn agility(&self) -> u16 { self.inner.agility as u16 } + pub fn agility(&self) -> u16 { + self.inner.agility as u16 + } - pub fn vitality(&self) -> u16 { self.inner.vitality as u16 } + pub fn vitality(&self) -> u16 { + self.inner.vitality as u16 + } - pub fn spirit(&self) -> u16 { self.inner.spirit as u16 } + pub fn spirit(&self) -> u16 { + self.inner.spirit as u16 + } - pub fn attribute_points(&self) -> u16 { self.inner.attribute_points as u16 } + pub fn attribute_points(&self) -> u16 { + self.inner.attribute_points as u16 + } - pub fn health_points(&self) -> u16 { self.inner.health_points as u16 } + pub fn health_points(&self) -> u16 { + self.inner.health_points as u16 + } - pub fn mana_points(&self) -> u16 { self.inner.mana_points as u16 } + pub fn mana_points(&self) -> u16 { + self.inner.mana_points as u16 + } - pub fn kill_points(&self) -> u16 { self.inner.kill_points as u16 } + pub fn kill_points(&self) -> u16 { + self.inner.kill_points as u16 + } - pub fn current_class(&self) -> u8 { self.inner.current_class as u8 } + pub fn current_class(&self) -> u8 { + self.inner.current_class as u8 + } - pub fn previous_class(&self) -> u8 { self.inner.previous_class as u8 } + pub fn previous_class(&self) -> u8 { + self.inner.previous_class as u8 + } - pub fn rebirths(&self) -> u8 { self.inner.rebirths as u8 } + pub fn rebirths(&self) -> u8 { + self.inner.rebirths as u8 + } pub async fn kick_back(&self) -> Result<(), Error> { let location = self.entity.location(); @@ -106,12 +144,7 @@ impl Character { } #[tracing::instrument(skip(self, state), fields(me = self.entity.id()))] - pub async fn teleport( - &self, - state: &crate::State, - map_id: u32, - (x, y): (u16, u16), - ) -> Result<(), Error> { + pub async fn teleport(&self, state: &crate::State, map_id: u32, (x, y): (u16, u16)) -> Result<(), Error> { let mut location = self.entity.location(); let xy = u32::constract(y, x); let msg = MsgAction::new( @@ -126,10 +159,7 @@ impl Character { let tile = new_map.tile(x, y).ok_or(Error::TileNotFound(x, y))?; // remove from old map if let Ok(old_map) = state.try_map(self.entity.map_id()) { - old_map.remove_entity_by_id_and_location( - self.id(), - self.entity().location(), - )?; + old_map.remove_entity_by_id_and_location(self.id(), self.entity().location())?; self.try_screen()?.remove_from_observers().await?; } location.x = x; @@ -143,10 +173,7 @@ impl Character { } #[tracing::instrument(skip_all, fields(me = self.entity.id()))] - pub async fn exchange_spawn_packets>( - &self, - observer: &E, - ) -> Result<(), Error> { + pub async fn exchange_spawn_packets>(&self, observer: &E) -> Result<(), Error> { match observer.as_ref() { GameEntity::Character(c) => { self.send_spawn(&c.owner()).await?; @@ -195,10 +222,7 @@ impl Character { } #[tracing::instrument(skip(self, to), fields(me = self.entity.id()))] - pub(super) async fn send_spawn( - &self, - to: &ActorHandle, - ) -> Result<(), Error> { + pub(super) async fn send_spawn(&self, to: &ActorHandle) -> Result<(), Error> { let msg = MsgPlayer::from(self); to.send(msg).await?; tracing::trace!("Sent Spawn"); diff --git a/server/game/src/entities/floor_item.rs b/server/game/src/entities/floor_item.rs index 180c0f4..2c44de6 100644 --- a/server/game/src/entities/floor_item.rs +++ b/server/game/src/entities/floor_item.rs @@ -9,11 +9,19 @@ pub trait FloorItem: Default { pub struct Item; impl FloorItem for Item { - fn money(&self) -> u32 { 0 } + fn money(&self) -> u32 { + 0 + } - fn map_id(&self) -> u32 { 0 } + fn map_id(&self) -> u32 { + 0 + } - fn x(&self) -> u16 { 0 } + fn x(&self) -> u16 { + 0 + } - fn y(&self) -> u16 { 0 } + fn y(&self) -> u16 { + 0 + } } diff --git a/server/game/src/entities/mod.rs b/server/game/src/entities/mod.rs index 9c8b510..87d7446 100644 --- a/server/game/src/entities/mod.rs +++ b/server/game/src/entities/mod.rs @@ -20,11 +20,15 @@ pub enum GameEntity { } impl From for GameEntity { - fn from(v: Character) -> Self { Self::Character(v) } + fn from(v: Character) -> Self { + Self::Character(v) + } } impl From for GameEntity { - fn from(v: Npc) -> Self { Self::Npc(v) } + fn from(v: Npc) -> Self { + Self::Npc(v) + } } impl GameEntity { @@ -56,12 +60,8 @@ impl GameEntity { /// This method sends the spawn packet to another entity pub async fn send_spawn(&self, to: &Self) -> Result<(), Error> { match (self, to) { - (Self::Character(from), Self::Character(to)) => { - from.send_spawn(&to.owner()).await - }, - (Self::Npc(from), Self::Character(to)) => { - from.send_spawn(&to.owner()).await - }, + (Self::Character(from), Self::Character(to)) => from.send_spawn(&to.owner()).await, + (Self::Npc(from), Self::Character(to)) => from.send_spawn(&to.owner()).await, _ => todo!("send_spawn for non-character entities"), } } @@ -70,7 +70,9 @@ impl GameEntity { /// /// [`Character`]: GameEntity::Character #[must_use] - pub fn is_character(&self) -> bool { matches!(self, Self::Character(..)) } + pub fn is_character(&self) -> bool { + matches!(self, Self::Character(..)) + } pub fn as_character(&self) -> Option<&Character> { if let Self::Character(v) = self { @@ -84,7 +86,9 @@ impl GameEntity { /// /// [`Npc`]: GameEntity::Npc #[must_use] - pub fn is_npc(&self) -> bool { matches!(self, Self::Npc(..)) } + pub fn is_npc(&self) -> bool { + matches!(self, Self::Npc(..)) + } pub fn as_npc(&self) -> Option<&Npc> { if let Self::Npc(v) = self { diff --git a/server/game/src/entities/npc.rs b/server/game/src/entities/npc.rs index de0bf73..fefec4c 100644 --- a/server/game/src/entities/npc.rs +++ b/server/game/src/entities/npc.rs @@ -4,9 +4,7 @@ use crate::Error; use num_enum::{FromPrimitive, IntoPrimitive}; use tq_network::ActorHandle; -#[derive( - Debug, Clone, Copy, PartialEq, Eq, Default, FromPrimitive, IntoPrimitive, -)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, FromPrimitive, IntoPrimitive)] #[repr(u8)] pub enum NpcKind { #[default] @@ -37,9 +35,7 @@ pub enum NpcKind { NeighbourGate = 27, } -#[derive( - Debug, Clone, Copy, PartialEq, Eq, Default, FromPrimitive, IntoPrimitive, -)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, FromPrimitive, IntoPrimitive)] #[repr(u8)] pub enum NpcSort { #[default] @@ -54,9 +50,7 @@ pub enum NpcSort { Table = 1 << 7, } -#[derive( - Debug, Clone, Copy, PartialEq, Eq, Default, FromPrimitive, IntoPrimitive, -)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, FromPrimitive, IntoPrimitive)] #[repr(u8)] pub enum NpcBase { #[default] @@ -102,28 +96,41 @@ impl Npc { } #[inline] - pub fn id(&self) -> u32 { self.inner.id as _ } + pub fn id(&self) -> u32 { + self.inner.id as _ + } - pub fn kind(&self) -> NpcKind { self.kind } + pub fn kind(&self) -> NpcKind { + self.kind + } - pub fn sort(&self) -> NpcSort { self.sort } + pub fn sort(&self) -> NpcSort { + self.sort + } - pub fn base(&self) -> NpcBase { self.base } + pub fn base(&self) -> NpcBase { + self.base + } #[inline] - pub fn entity(&self) -> &Entity { &self.entity } + pub fn entity(&self) -> &Entity { + &self.entity + } - pub fn is_shopkeeper(&self) -> bool { self.kind == NpcKind::ShopKeeper } + pub fn is_shopkeeper(&self) -> bool { + self.kind == NpcKind::ShopKeeper + } - pub fn is_storage(&self) -> bool { self.kind == NpcKind::Storage } + pub fn is_storage(&self) -> bool { + self.kind == NpcKind::Storage + } - pub fn is_booth(&self) -> bool { self.kind == NpcKind::Booth } + pub fn is_booth(&self) -> bool { + self.kind == NpcKind::Booth + } #[tracing::instrument(skip(self, to), fields(npc = self.entity.id()))] - pub(super) async fn send_spawn( - &self, - to: &ActorHandle, - ) -> Result<(), Error> { + pub(super) async fn send_spawn(&self, to: &ActorHandle) -> Result<(), Error> { let msg = if self.is_booth() { MsgNpcInfo::from_npc_with_name(self) } else { @@ -136,5 +143,7 @@ impl Npc { } impl From for Npc { - fn from(value: tq_db::npc::Npc) -> Self { Self::new(value) } + fn from(value: tq_db::npc::Npc) -> Self { + Self::new(value) + } } diff --git a/server/game/src/error.rs b/server/game/src/error.rs index e2b5eee..62f2657 100644 --- a/server/game/src/error.rs +++ b/server/game/src/error.rs @@ -64,11 +64,15 @@ pub enum Error { } impl From> for Error { - fn from(_: mpsc::error::SendError) -> Self { Self::SendError } + fn from(_: mpsc::error::SendError) -> Self { + Self::SendError + } } impl From for Error { - fn from(_: oneshot::error::RecvError) -> Self { Self::RecvError } + fn from(_: oneshot::error::RecvError) -> Self { + Self::RecvError + } } impl From> for Error { @@ -86,65 +90,37 @@ impl PacketEncode for Error { match self { Self::Msg(id, bytes) => Ok((*id, bytes.clone())), Self::MapNotFound => { - let msg = MsgTalk::from_system( - 0, - crate::packets::TalkChannel::TopLeft, - "Map not found!", - ); + let msg = MsgTalk::from_system(0, crate::packets::TalkChannel::TopLeft, "Map not found!"); let (id, bytes) = msg.encode()?; Ok((id, bytes)) }, Self::MapRegionNotFound => { - let msg = MsgTalk::from_system( - 0, - crate::packets::TalkChannel::TopLeft, - "Map Region not found!", - ); + let msg = MsgTalk::from_system(0, crate::packets::TalkChannel::TopLeft, "Map Region not found!"); let (id, bytes) = msg.encode()?; Ok((id, bytes)) }, Self::LoginTokenNotFound => { - let msg = MsgTalk::from_system( - 0, - crate::packets::TalkChannel::Login, - "Login Token not found!", - ); + let msg = MsgTalk::from_system(0, crate::packets::TalkChannel::Login, "Login Token not found!"); let (id, bytes) = msg.encode()?; Ok((id, bytes)) }, Self::CreationTokenNotFound => { - let msg = MsgTalk::from_system( - 0, - crate::packets::TalkChannel::Register, - "Creation Token not found!", - ); + let msg = MsgTalk::from_system(0, crate::packets::TalkChannel::Register, "Creation Token not found!"); let (id, bytes) = msg.encode()?; Ok((id, bytes)) }, Self::RealmNotFound => { - let msg = MsgTalk::from_system( - 0, - crate::packets::TalkChannel::Login, - "Realm not found!", - ); + let msg = MsgTalk::from_system(0, crate::packets::TalkChannel::Login, "Realm not found!"); let (id, bytes) = msg.encode()?; Ok((id, bytes)) }, Self::CharacterNotFound => { - let msg = MsgTalk::from_system( - 0, - crate::packets::TalkChannel::TopLeft, - "Character not found!", - ); + let msg = MsgTalk::from_system(0, crate::packets::TalkChannel::TopLeft, "Character not found!"); let (id, bytes) = msg.encode()?; Ok((id, bytes)) }, Self::ScreenNotFound => { - let msg = MsgTalk::from_system( - 0, - crate::packets::TalkChannel::TopLeft, - "Screen not found!", - ); + let msg = MsgTalk::from_system(0, crate::packets::TalkChannel::TopLeft, "Screen not found!"); let (id, bytes) = msg.encode()?; Ok((id, bytes)) }, @@ -158,29 +134,17 @@ impl PacketEncode for Error { Ok((id, bytes)) }, Self::InvalidSceneFileName => { - let msg = MsgTalk::from_system( - 0, - crate::packets::TalkChannel::TopLeft, - "Invalid Scene File Name!", - ); + let msg = MsgTalk::from_system(0, crate::packets::TalkChannel::TopLeft, "Invalid Scene File Name!"); let (id, bytes) = msg.encode()?; Ok((id, bytes)) }, Self::InvalidBodyType => { - let msg = MsgTalk::from_system( - 0, - crate::packets::TalkChannel::Register, - "Invalid Body Type!", - ); + let msg = MsgTalk::from_system(0, crate::packets::TalkChannel::Register, "Invalid Body Type!"); let (id, bytes) = msg.encode()?; Ok((id, bytes)) }, Self::InvalidClass => { - let msg = MsgTalk::from_system( - 0, - crate::packets::TalkChannel::Register, - "Invalid Class!", - ); + let msg = MsgTalk::from_system(0, crate::packets::TalkChannel::Register, "Invalid Class!"); let (id, bytes) = msg.encode()?; Ok((id, bytes)) }, @@ -190,9 +154,13 @@ impl PacketEncode for Error { } impl From for tq_network::Error { - fn from(v: Error) -> Self { Self::Other(v.to_string()) } + fn from(v: Error) -> Self { + Self::Other(v.to_string()) + } } impl From for tq_server::Error { - fn from(v: Error) -> Self { Self::Internal(Box::new(v)) } + fn from(v: Error) -> Self { + Self::Internal(Box::new(v)) + } } diff --git a/server/game/src/main.rs b/server/game/src/main.rs index 61de6fb..6552a0a 100644 --- a/server/game/src/main.rs +++ b/server/game/src/main.rs @@ -139,9 +139,7 @@ fn setup_logger(verbosity: i32) -> Result<(), Error> { .add_directive("runtime=trace".parse().unwrap()); #[cfg(feature = "console")] - let console_layer = console_subscriber::ConsoleLayer::builder() - .with_default_env() - .spawn(); + let console_layer = console_subscriber::ConsoleLayer::builder().with_default_env().spawn(); let registry = tracing_subscriber::registry().with(env_filter).with(logger); diff --git a/server/game/src/packets/msg_action.rs b/server/game/src/packets/msg_action.rs index cd34175..885e766 100644 --- a/server/game/src/packets/msg_action.rs +++ b/server/game/src/packets/msg_action.rs @@ -95,13 +95,7 @@ pub struct MsgAction { } impl MsgAction { - pub fn new( - character_id: u32, - data1: u32, - data2: u32, - details: u16, - action_type: ActionType, - ) -> Self { + pub fn new(character_id: u32, data1: u32, data2: u32, details: u16, action_type: ActionType) -> Self { Self { client_timestamp: utils::current_ts(), character_id, @@ -112,11 +106,7 @@ impl MsgAction { } } - pub fn from_character( - character: &Character, - data1: u32, - action_type: ActionType, - ) -> Self { + pub fn from_character(character: &Character, data1: u32, action_type: ActionType) -> Self { let character_id = character.id(); let (x, y, d) = character.entity().location().into(); let data2 = u32::constract(y, x); @@ -125,15 +115,10 @@ impl MsgAction { } #[tracing::instrument(skip_all)] - async fn handle_send_location( - &self, - state: &State, - actor: &Actor, - ) -> Result<(), Error> { + async fn handle_send_location(&self, state: &State, actor: &Actor) -> Result<(), Error> { let mut res = self.clone(); let entity = actor.try_entity()?; - let character = - entity.as_character().ok_or(Error::CharacterNotFound)?; + let character = entity.as_character().ok_or(Error::CharacterNotFound)?; let map_id = character.entity().map_id(); let location = character.entity().location(); match state.try_map(map_id) { @@ -173,15 +158,10 @@ impl MsgAction { } #[tracing::instrument(skip_all)] - async fn handle_map_argb( - &self, - state: &State, - actor: &Actor, - ) -> Result<(), Error> { + async fn handle_map_argb(&self, state: &State, actor: &Actor) -> Result<(), Error> { let mut res = self.clone(); let entity = actor.try_entity()?; - let character = - entity.as_character().ok_or(Error::CharacterNotFound)?; + let character = entity.as_character().ok_or(Error::CharacterNotFound)?; let map_id = character.entity().map_id(); let location = character.entity().location(); let map = state.try_map(map_id)?; @@ -192,22 +172,14 @@ impl MsgAction { } #[tracing::instrument(skip_all)] - async fn handle_login_completed( - &self, - _state: &State, - actor: &Actor, - ) -> Result<(), Error> { + async fn handle_login_completed(&self, _state: &State, actor: &Actor) -> Result<(), Error> { let res = self.clone(); actor.send(res).await?; Ok(()) } #[tracing::instrument(skip_all)] - async fn handle_leave_booth( - &self, - state: &State, - actor: &Actor, - ) -> Result<(), Error> { + async fn handle_leave_booth(&self, state: &State, actor: &Actor) -> Result<(), Error> { // Remove Player from Booth. let myscreen = actor.screen(); myscreen.clear()?; @@ -216,11 +188,7 @@ impl MsgAction { } #[tracing::instrument(skip_all)] - async fn handle_jump( - &self, - state: &State, - actor: &Actor, - ) -> Result<(), Error> { + async fn handle_jump(&self, state: &State, actor: &Actor) -> Result<(), Error> { let new_x = self.data1.lo(); let new_y = self.data1.hi(); let current_x = self.data2.lo(); @@ -243,19 +211,14 @@ impl MsgAction { } let mymap = state.try_map(mymap_id)?; - let within_elevation = mymap.sample_elevation( - (loc.x, loc.y), - (new_x, new_y), - me.elevation(), - ); + let within_elevation = mymap.sample_elevation((loc.x, loc.y), (new_x, new_y), me.elevation()); if !within_elevation { tracing::debug!(%loc.x, %loc.y, %new_x, %new_y, "Elevation diff > 210"); me.kick_back().await?; return Ok(()); } - let direction = - tq_math::get_direction_sector((loc.x, loc.y), (new_x, new_y)); + let direction = tq_math::get_direction_sector((loc.x, loc.y), (new_x, new_y)); match mymap.tile(new_x, new_y) { Some(tile) if tile.access > TileType::Npc => { // I guess everything seems to be valid .. send the jump. @@ -270,11 +233,7 @@ impl MsgAction { }, Some(_) | None => { // Invalid Location move them back - let msg = MsgTalk::from_system( - me.id(), - TalkChannel::TopLeft, - String::from("Invalid Location"), - ); + let msg = MsgTalk::from_system(me.id(), TalkChannel::TopLeft, String::from("Invalid Location")); actor.send(msg).await?; me.kick_back().await?; tracing::debug!(id = %me.id(), %loc.x, %loc.y, %new_x, %new_y, "Invalid Location"); @@ -285,10 +244,7 @@ impl MsgAction { } #[tracing::instrument(skip_all)] - async fn handle_change_facing( - &self, - actor: &Actor, - ) -> Result<(), Error> { + async fn handle_change_facing(&self, actor: &Actor) -> Result<(), Error> { let current_x = self.data2.lo(); let current_y = self.data2.hi(); let entity = actor.try_entity()?; @@ -311,42 +267,24 @@ impl MsgAction { } #[tracing::instrument(skip_all)] - async fn handle_query_entity( - &self, - state: &State, - actor: &Actor, - ) -> Result<(), Error> { + async fn handle_query_entity(&self, state: &State, actor: &Actor) -> Result<(), Error> { let entity = actor.try_entity()?; let me = entity.as_character().ok_or(Error::CharacterNotFound)?; let mymap_id = me.entity().map_id(); let mymap = state.try_map(mymap_id)?; - let other = mymap.with_regions(|r| { - r.iter().find_map(|r| r.try_entities(self.data1)) - }); - if let Some(other) = other - .and_then(|o| o.upgrade()) - .as_ref() - .and_then(|o| o.as_character()) - { + let other = mymap.with_regions(|r| r.iter().find_map(|r| r.try_entities(self.data1))); + if let Some(other) = other.and_then(|o| o.upgrade()).as_ref().and_then(|o| o.as_character()) { let msg = super::MsgPlayer::from(other); actor.send(msg).await?; } else { - let msg = super::MsgTalk::from_system( - me.id(), - TalkChannel::System, - "Player not found", - ); + let msg = super::MsgTalk::from_system(me.id(), TalkChannel::System, "Player not found"); actor.send(msg).await?; } Ok(()) } #[tracing::instrument(skip_all)] - async fn handle_change_map( - &self, - state: &State, - actor: &Actor, - ) -> Result<(), Error> { + async fn handle_change_map(&self, state: &State, actor: &Actor) -> Result<(), Error> { let portal_x = self.data1.lo(); let portal_y = self.data1.hi(); let entity = actor.try_entity()?; @@ -360,20 +298,17 @@ impl MsgAction { return Ok(()); } let mymap = state.try_map(mymap_id)?; - let maybe_portal = mymap.portals().iter().find(|p| { - tq_math::in_circle((loc.x, loc.y, 5), (p.from_x(), p.from_y())) - }); + let maybe_portal = mymap + .portals() + .iter() + .find(|p| tq_math::in_circle((loc.x, loc.y, 5), (p.from_x(), p.from_y()))); match maybe_portal { Some(portal) => { let portal_map = state.try_map(portal.to_map_id())?; mymap.remove_entity(&entity)?; portal_map.insert_entity(entity.clone()).await?; - me.teleport( - state, - portal.to_map_id(), - (portal.to_x(), portal.to_y()), - ) - .await?; + me.teleport(state, portal.to_map_id(), (portal.to_x(), portal.to_y())) + .await?; }, None => { tracing::debug!(%portal_x, %portal_y, %loc.x, %loc.y, "Portal not found"); @@ -384,26 +319,20 @@ impl MsgAction { } #[tracing::instrument(skip_all)] - async fn handle_set_kill_mode( - &self, - _state: &State, - actor: &Actor, - ) -> Result<(), Error> { + async fn handle_set_kill_mode(&self, _state: &State, actor: &Actor) -> Result<(), Error> { let kill_mode = KillMode::from(self.data1 as u16); // TODO: Update player kill mode. // TODO: handle i18n let notice = match kill_mode { KillMode::Free => "In free mode, you can attack everybody.", KillMode::Safe => "In safe mode, you can only attack monsters.", - KillMode::Team => "In team mode, you can attack everybody, except your friends, your teammates, and your guildmates.", + KillMode::Team => { + "In team mode, you can attack everybody, except your friends, your teammates, and your guildmates." + }, KillMode::Arrestment => "In arrestment mode, you can only attack monsters and black name players.", }; actor.send(self.clone()).await?; - let msg = super::MsgTalk::from_system( - actor.entity().id(), - TalkChannel::System, - notice, - ); + let msg = super::MsgTalk::from_system(actor.entity().id(), TalkChannel::System, notice); actor.send(msg).await?; Ok(()) } @@ -415,23 +344,13 @@ impl PacketProcess for MsgAction { type Error = Error; type State = State; - async fn process( - &self, - state: &Self::State, - actor: &Actor, - ) -> Result<(), Self::Error> { + async fn process(&self, state: &Self::State, actor: &Actor) -> Result<(), Self::Error> { let ty = self.action_type.into(); match ty { - ActionType::SendLocation => { - self.handle_send_location(state, actor).await - }, + ActionType::SendLocation => self.handle_send_location(state, actor).await, ActionType::MapARGB => self.handle_map_argb(state, actor).await, - ActionType::SetKillMode => { - self.handle_set_kill_mode(state, actor).await - }, - ActionType::LeaveBooth => { - self.handle_leave_booth(state, actor).await - }, + ActionType::SetKillMode => self.handle_set_kill_mode(state, actor).await, + ActionType::LeaveBooth => self.handle_leave_booth(state, actor).await, ActionType::SendItems => { // TODO: send MsgItemInfo actor.send(self.clone()).await?; @@ -460,31 +379,21 @@ impl PacketProcess for MsgAction { actor.send(self.clone()).await?; Ok(()) }, - ActionType::LoginCompeleted => { - self.handle_login_completed(state, actor).await - }, + ActionType::LoginCompeleted => self.handle_login_completed(state, actor).await, ActionType::Jump => self.handle_jump(state, actor).await, ActionType::ChangeFacing => self.handle_change_facing(actor).await, - ActionType::QueryEntity => { - self.handle_query_entity(state, actor).await - }, + ActionType::QueryEntity => self.handle_query_entity(state, actor).await, ActionType::ChangeMap => self.handle_change_map(state, actor).await, _ => { let p = MsgTalk::from_system( self.character_id, TalkChannel::Talk, - format!( - "Missing Action Type {ty:?} = {}", - self.action_type - ), + format!("Missing Action Type {ty:?} = {}", self.action_type), ); actor.send(p).await?; let res = self.clone(); actor.send(res).await?; - tracing::warn!( - "Missing Action Type {ty:?} = {}", - self.action_type - ); + tracing::warn!("Missing Action Type {ty:?} = {}", self.action_type); Ok(()) }, } diff --git a/server/game/src/packets/msg_connect.rs b/server/game/src/packets/msg_connect.rs index b00121b..7112761 100644 --- a/server/game/src/packets/msg_connect.rs +++ b/server/game/src/packets/msg_connect.rs @@ -26,21 +26,13 @@ impl PacketProcess for MsgConnect { type Error = Error; type State = State; - async fn process( - &self, - state: &Self::State, - actor: &Actor, - ) -> Result<(), Self::Error> { + async fn process(&self, state: &Self::State, actor: &Actor) -> Result<(), Self::Error> { let info = state .remove_login_token(self.token) .map_err(|_| MsgTalk::login_invalid().error_packet())?; actor.generate_keys(self.token).await?; actor.set_id(info.account_id as usize); - let maybe_character = tq_db::character::Character::from_account( - state.pool(), - info.account_id, - ) - .await?; + let maybe_character = tq_db::character::Character::from_account(state.pool(), info.account_id).await?; match maybe_character { Some(character) => { let me = Character::new(actor.handle(), character); @@ -58,11 +50,7 @@ impl PacketProcess for MsgConnect { actor.send(MsgData::now()).await?; }, None => { - state.store_creation_token( - self.token as u32, - info.account_id, - info.realm_id, - )?; + state.store_creation_token(self.token as u32, info.account_id, info.realm_id)?; actor.send(MsgTalk::login_new_role()).await?; }, }; diff --git a/server/game/src/packets/msg_data.rs b/server/game/src/packets/msg_data.rs index d8b777f..c8b5a9e 100644 --- a/server/game/src/packets/msg_data.rs +++ b/server/game/src/packets/msg_data.rs @@ -37,11 +37,7 @@ impl MsgData { let now = SystemTime::now() .duration_since(UNIX_EPOCH) .expect("system time before Unix epoch"); - let naive = NaiveDateTime::from_timestamp_opt( - now.as_secs() as i64, - now.subsec_nanos(), - ) - .unwrap(); + let naive = NaiveDateTime::from_timestamp_opt(now.as_secs() as i64, now.subsec_nanos()).unwrap(); let now = chrono::TimeZone::from_utc_datetime(&chrono::Utc, &naive); Self { action: DataAction::SetServerTime.into(), @@ -61,11 +57,7 @@ impl PacketProcess for MsgData { type Error = Error; type State = State; - async fn process( - &self, - _state: &Self::State, - _actor: &Actor, - ) -> Result<(), Self::Error> { + async fn process(&self, _state: &Self::State, _actor: &Actor) -> Result<(), Self::Error> { Ok(()) } } diff --git a/server/game/src/packets/msg_item.rs b/server/game/src/packets/msg_item.rs index bfc53a8..6e9d1ca 100644 --- a/server/game/src/packets/msg_item.rs +++ b/server/game/src/packets/msg_item.rs @@ -66,11 +66,7 @@ impl PacketProcess for MsgItem { type Error = crate::Error; type State = State; - async fn process( - &self, - _state: &Self::State, - actor: &Actor, - ) -> Result<(), Self::Error> { + async fn process(&self, _state: &Self::State, actor: &Actor) -> Result<(), Self::Error> { let action = self.action_type.into(); match action { ItemActionType::Ping => { diff --git a/server/game/src/packets/msg_map_info.rs b/server/game/src/packets/msg_map_info.rs index 98cabc8..44b81a2 100644 --- a/server/game/src/packets/msg_map_info.rs +++ b/server/game/src/packets/msg_map_info.rs @@ -64,11 +64,17 @@ impl MsgMapInfo { } } - pub fn is_static(&self) -> bool { self.uid == self.map_id } + pub fn is_static(&self) -> bool { + self.uid == self.map_id + } - pub fn is_copy(&self) -> bool { self.uid != self.map_id } + pub fn is_copy(&self) -> bool { + self.uid != self.map_id + } } impl From<&Map> for MsgMapInfo { - fn from(map: &Map) -> Self { Self::from_map(map) } + fn from(map: &Map) -> Self { + Self::from_map(map) + } } diff --git a/server/game/src/packets/msg_npc.rs b/server/game/src/packets/msg_npc.rs index 39b2600..ce74c93 100644 --- a/server/game/src/packets/msg_npc.rs +++ b/server/game/src/packets/msg_npc.rs @@ -35,11 +35,7 @@ impl PacketProcess for MsgNpc { type Error = crate::Error; type State = crate::State; - async fn process( - &self, - state: &Self::State, - actor: &Actor, - ) -> Result<(), Self::Error> { + async fn process(&self, state: &Self::State, actor: &Actor) -> Result<(), Self::Error> { tracing::debug!( npc_id = self.npc_id, data = self.data, @@ -48,8 +44,7 @@ impl PacketProcess for MsgNpc { "MsgNpc received" ); let me = actor.entity(); - let mycharacter = - me.as_character().ok_or(crate::Error::CharacterNotFound)?; + let mycharacter = me.as_character().ok_or(crate::Error::CharacterNotFound)?; let mymap = state.try_map(me.basic().map_id())?; let npc = match mymap.npc(self.npc_id) { Some(npc) => npc, @@ -87,9 +82,7 @@ impl PacketProcess for MsgNpc { let npc_name = npc.entity().name(); // For now, lets try sending a dummy dialog let dialog = MsgTaskDialog::builder() - .text(format!( - "Hello, My name is {npc_name} and my id is {npc_id}", - )) + .text(format!("Hello, My name is {npc_name} and my id is {npc_id}",)) .with_edit(1, "What is your name?") .with_option(255, "Nice to meet you") .and() diff --git a/server/game/src/packets/msg_register.rs b/server/game/src/packets/msg_register.rs index 67e6ad2..428c304 100644 --- a/server/game/src/packets/msg_register.rs +++ b/server/game/src/packets/msg_register.rs @@ -21,15 +21,10 @@ pub struct MsgRegister { } impl MsgRegister { - pub fn build_character( - &self, - account_id: u32, - realm_id: u32, - ) -> Result { + pub fn build_character(&self, account_id: u32, realm_id: u32) -> Result { Self::build_character_with( self.character_name.to_string(), - BodyType::try_from(self.mesh) - .map_err(|_| Error::InvalidBodyType)?, + BodyType::try_from(self.mesh).map_err(|_| Error::InvalidBodyType)?, BaseClass::try_from(self.class).map_err(|_| Error::InvalidClass)?, account_id, realm_id, @@ -54,8 +49,7 @@ impl MsgRegister { _ => rng.gen_range(201..249), }; - let hair_style = rng.gen_range(3..9) * 100 - + crate::constants::HAIR_STYLES[rng.gen_range(0..12)]; + let hair_style = rng.gen_range(3..9) * 100 + crate::constants::HAIR_STYLES[rng.gen_range(0..12)]; let strength = match class { BaseClass::Taoist => 2, _ => 4, @@ -67,8 +61,7 @@ impl MsgRegister { _ => 0, }; - let health_points = - (strength * 3) + (agility * 3) + (spirit * 3) + (vitality * 24); + let health_points = (strength * 3) + (agility * 3) + (spirit * 3) + (vitality * 24); let mana_points = spirit * 5; let c = tq_db::character::Character { @@ -121,37 +114,24 @@ impl PacketProcess for MsgRegister { type Error = Error; type State = State; - async fn process( - &self, - state: &Self::State, - actor: &Actor, - ) -> Result<(), Self::Error> { + async fn process(&self, state: &Self::State, actor: &Actor) -> Result<(), Self::Error> { let info = state .remove_creation_token(self.token) .map_err(|_| MsgTalk::register_invalid().error_packet())?; - if tq_db::character::Character::name_taken( - state.pool(), - &self.character_name, - ) - .await? - { + if tq_db::character::Character::name_taken(state.pool(), &self.character_name).await? { return Err(MsgTalk::register_name_taken().error_packet().into()); } // Validate Data. - BodyType::try_from(self.mesh) - .map_err(|_| MsgTalk::register_invalid().error_packet())?; - BaseClass::try_from(self.class) - .map_err(|_| MsgTalk::register_invalid().error_packet())?; + BodyType::try_from(self.mesh).map_err(|_| MsgTalk::register_invalid().error_packet())?; + BaseClass::try_from(self.class).map_err(|_| MsgTalk::register_invalid().error_packet())?; let character_id = self .build_character(info.account_id, info.realm_id)? .save(state.pool()) .await?; - let character = - tq_db::character::Character::by_id(state.pool(), character_id) - .await?; + let character = tq_db::character::Character::by_id(state.pool(), character_id).await?; let map_id = character.map_id; let me = Character::new(actor.handle(), character); let screen = Screen::new(actor.handle()); diff --git a/server/game/src/packets/msg_talk.rs b/server/game/src/packets/msg_talk.rs index b1bf28b..7837822 100644 --- a/server/game/src/packets/msg_talk.rs +++ b/server/game/src/packets/msg_talk.rs @@ -82,11 +82,7 @@ pub struct MsgTalk { } impl MsgTalk { - pub fn from_system( - character_id: u32, - channel: TalkChannel, - message: impl Into, - ) -> Self { + pub fn from_system(character_id: u32, channel: TalkChannel, message: impl Into) -> Self { MsgTalk { color: 0x00FF_FFFF, channel: channel.into(), @@ -107,19 +103,11 @@ impl MsgTalk { } pub fn register_invalid() -> Self { - Self::from_system( - 0, - TalkChannel::Register, - String::from("Register Invalid"), - ) + Self::from_system(0, TalkChannel::Register, String::from("Register Invalid")) } pub fn register_ok() -> Self { - Self::from_system( - 0, - TalkChannel::Register, - crate::constants::ANSWER_OK.to_owned(), - ) + Self::from_system(0, TalkChannel::Register, crate::constants::ANSWER_OK.to_owned()) } pub fn register_name_taken() -> Self { @@ -131,19 +119,11 @@ impl MsgTalk { } pub fn login_ok() -> Self { - Self::from_system( - 0, - TalkChannel::Login, - crate::constants::ANSWER_OK.to_owned(), - ) + Self::from_system(0, TalkChannel::Login, crate::constants::ANSWER_OK.to_owned()) } pub fn login_new_role() -> Self { - Self::from_system( - 0, - TalkChannel::Login, - crate::constants::NEW_ROLE.to_owned(), - ) + Self::from_system(0, TalkChannel::Login, crate::constants::NEW_ROLE.to_owned()) } } @@ -153,11 +133,7 @@ impl PacketProcess for MsgTalk { type Error = crate::Error; type State = State; - async fn process( - &self, - state: &Self::State, - actor: &Actor, - ) -> Result<(), Self::Error> { + async fn process(&self, state: &Self::State, actor: &Actor) -> Result<(), Self::Error> { if self.message.starts_with('$') { // Command Message. let (_, command) = self.message.split_at(1); @@ -169,9 +145,7 @@ impl PacketProcess for MsgTalk { let map_id = actor.entity().basic().map_id(); let loc = actor.entity().basic().location(); let mymap = state.try_map(map_id)?; - let myregion = mymap - .region(loc.x, loc.y) - .ok_or(crate::Error::MapRegionNotFound)?; + let myregion = mymap.region(loc.x, loc.y).ok_or(crate::Error::MapRegionNotFound)?; myregion.broadcast(self.clone()).await?; Ok(()) } diff --git a/server/game/src/packets/msg_task_dialog.rs b/server/game/src/packets/msg_task_dialog.rs index 3b19805..1e0f2e9 100644 --- a/server/game/src/packets/msg_task_dialog.rs +++ b/server/game/src/packets/msg_task_dialog.rs @@ -81,10 +81,7 @@ impl MultiTaskDialogBuilder { /// # Arguments /// /// * `text` - A string slice representing the text to be added to the task. - pub fn text>( - mut self, - text: T, - ) -> MultiTaskDialogBuilder { + pub fn text>(mut self, text: T) -> MultiTaskDialogBuilder { let text = text.as_ref(); let msgs = text .as_bytes() @@ -106,12 +103,7 @@ impl MultiTaskDialogBuilder { } impl MultiTaskDialogBuilder { - fn mk_option>( - mut self, - option_id: u8, - text: T, - action: DialogActionKind, - ) -> Self { + fn mk_option>(mut self, option_id: u8, text: T, action: DialogActionKind) -> Self { let s = text.as_ref(); // Truncate the text to the maximum allowed length. let option_text = if s.len() <= constants::MAX_TXT_LEN { @@ -189,11 +181,7 @@ impl PacketProcess for MsgTaskDialog { type Error = crate::Error; type State = crate::State; - async fn process( - &self, - _state: &Self::State, - _actor: &Actor, - ) -> Result<(), Self::Error> { + async fn process(&self, _state: &Self::State, _actor: &Actor) -> Result<(), Self::Error> { tracing::debug!(msg = ?self, "MsgTaskDialog received"); Ok(()) } diff --git a/server/game/src/packets/msg_transfer.rs b/server/game/src/packets/msg_transfer.rs index 4078c26..e44ffe8 100644 --- a/server/game/src/packets/msg_transfer.rs +++ b/server/game/src/packets/msg_transfer.rs @@ -21,13 +21,8 @@ impl PacketProcess for MsgTransfer { type Error = Error; type State = State; - async fn process( - &self, - state: &Self::State, - actor: &Actor, - ) -> Result<(), Self::Error> { - let generated = - state.generate_login_token(self.account_id, self.realm_id)?; + async fn process(&self, state: &Self::State, actor: &Actor) -> Result<(), Self::Error> { + let generated = state.generate_login_token(self.account_id, self.realm_id)?; let mut msg = self.clone(); msg.token = generated.token; actor.send(msg).await?; diff --git a/server/game/src/packets/msg_walk.rs b/server/game/src/packets/msg_walk.rs index 6940e90..a89a4a4 100644 --- a/server/game/src/packets/msg_walk.rs +++ b/server/game/src/packets/msg_walk.rs @@ -43,19 +43,12 @@ impl PacketProcess for MsgWalk { /// the movement is valid, then distributes it to observing players. if /// the movement is invalid, the packet will not be sent back and the actor /// will be teleported back to the character's original position. - async fn process( - &self, - state: &Self::State, - actor: &Actor, - ) -> Result<(), Self::Error> { + async fn process(&self, state: &Self::State, actor: &Actor) -> Result<(), Self::Error> { let direction = (self.direction % 8) as usize; let entity = actor.entity(); let me = entity.as_character().ok_or(Error::CharacterNotFound)?; let current_location = me.entity().location(); - let offset = ( - (WALK_XCOORDS[direction] as u16), - (WALK_YCOORDS[direction] as u16), - ); + let offset = ((WALK_XCOORDS[direction] as u16), (WALK_YCOORDS[direction] as u16)); let x = current_location.x.wrapping_add(offset.0); let y = current_location.y.wrapping_add(offset.1); let map = state.try_map(me.entity().map_id())?; @@ -63,8 +56,7 @@ impl PacketProcess for MsgWalk { Some(tile) if tile.access > TileType::Npc => { // The packet is valid. Assign character data: // Send the movement back to the message server and client: - me.entity() - .set_location(Location::new(x, y, direction as _)); + me.entity().set_location(Location::new(x, y, direction as _)); me.set_elevation(tile.elevation); actor.send(self.clone()).await?; map.update_region_for(actor.entity()); @@ -72,11 +64,7 @@ impl PacketProcess for MsgWalk { myscreen.send_movement(state, self.clone()).await?; }, Some(_) | None => { - let msg = MsgTalk::from_system( - me.id(), - TalkChannel::TopLeft, - "Invalid Location", - ); + let msg = MsgTalk::from_system(me.id(), TalkChannel::TopLeft, "Invalid Location"); actor.send(msg).await?; me.kick_back().await?; return Ok(()); diff --git a/server/game/src/packets/msg_weather.rs b/server/game/src/packets/msg_weather.rs index 2e93eee..8415ba3 100644 --- a/server/game/src/packets/msg_weather.rs +++ b/server/game/src/packets/msg_weather.rs @@ -26,13 +26,17 @@ impl WeatherKind { /// /// [`None`]: WeatherKind::None #[must_use] - pub fn is_none(&self) -> bool { matches!(self, Self::None) } + pub fn is_none(&self) -> bool { + matches!(self, Self::None) + } /// Returns `true` if the weather kind is [`Unknwon`]. /// /// [`Unknwon`]: WeatherKind::Unknwon #[must_use] - pub fn is_unknwon(&self) -> bool { matches!(self, Self::Unknwon) } + pub fn is_unknwon(&self) -> bool { + matches!(self, Self::Unknwon) + } } /// This packet is sent from the game server to the client for invoking weather @@ -62,15 +66,25 @@ impl MsgWeather { } } - pub fn none() -> Self { Self::new(WeatherKind::None) } + pub fn none() -> Self { + Self::new(WeatherKind::None) + } - pub fn rain() -> Self { Self::new(WeatherKind::Rain) } + pub fn rain() -> Self { + Self::new(WeatherKind::Rain) + } - pub fn snow() -> Self { Self::new(WeatherKind::Snow) } + pub fn snow() -> Self { + Self::new(WeatherKind::Snow) + } - pub fn rain_wind() -> Self { Self::new(WeatherKind::RainWind) } + pub fn rain_wind() -> Self { + Self::new(WeatherKind::RainWind) + } - pub fn autumn_leaves() -> Self { Self::new(WeatherKind::AutumnLeaves) } + pub fn autumn_leaves() -> Self { + Self::new(WeatherKind::AutumnLeaves) + } pub fn cherry_blossom_petals() -> Self { Self::new(WeatherKind::CherryBlossomPetals) @@ -80,7 +94,11 @@ impl MsgWeather { Self::new(WeatherKind::CherryBlossomPetalsWind) } - pub fn blowing_cotten() -> Self { Self::new(WeatherKind::BlowingCotten) } + pub fn blowing_cotten() -> Self { + Self::new(WeatherKind::BlowingCotten) + } - pub fn atoms() -> Self { Self::new(WeatherKind::Atoms) } + pub fn atoms() -> Self { + Self::new(WeatherKind::Atoms) + } } diff --git a/server/game/src/state/mod.rs b/server/game/src/state/mod.rs index 7bf512c..e64618c 100644 --- a/server/game/src/state/mod.rs +++ b/server/game/src/state/mod.rs @@ -31,10 +31,8 @@ impl State { /// Should only get called once. pub async fn init() -> Result { let data_dir = dotenvy::var("DATA_LOCATION")?; - let default_db_location = - format!("sqlite://{data_dir}/coemu.db?mode=rwc"); - let db_url = - dotenvy::var("DATABASE_URL").unwrap_or(default_db_location); + let default_db_location = format!("sqlite://{data_dir}/coemu.db?mode=rwc"); + let db_url = dotenvy::var("DATABASE_URL").unwrap_or(default_db_location); let pool = SqlitePoolOptions::new() .max_connections(42) .min_connections(4) @@ -68,9 +66,13 @@ impl State { } /// Get access to the database pool - pub fn pool(&self) -> &SqlitePool { &self.pool } + pub fn pool(&self) -> &SqlitePool { + &self.pool + } - pub fn maps(&self) -> &Maps { &self.maps } + pub fn maps(&self) -> &Maps { + &self.maps + } pub fn try_map(&self, map_id: u32) -> Result<&Map, Error> { self.maps.get(&map_id).ok_or(Error::MapNotFound) @@ -104,27 +106,16 @@ impl State { /// /// The token will be stored internally, and can be later removed by calling /// [`TokenStore::remove_login_token`]. - pub fn generate_login_token( - &self, - account_id: u32, - realm_id: u32, - ) -> Result { + pub fn generate_login_token(&self, account_id: u32, realm_id: u32) -> Result { let token = rand::random(); - self.login_tokens.lock().insert( - token, - LoginToken { - account_id, - realm_id, - }, - ); + self.login_tokens + .lock() + .insert(token, LoginToken { account_id, realm_id }); Ok(GeneratedLoginToken { token }) } /// Remove a Login Token. - pub fn remove_login_token( - &self, - token: u64, - ) -> Result { + pub fn remove_login_token(&self, token: u64) -> Result { self.login_tokens .lock() .remove(&token) @@ -134,27 +125,15 @@ impl State { /// Store a new CreationToken. /// The token will be stored internally, and can be later removed by calling /// [`TokenStore::remove_creation_token`]. - pub fn store_creation_token( - &self, - token: u32, - account_id: u32, - realm_id: u32, - ) -> Result<(), crate::Error> { - self.creation_tokens.lock().insert( - token, - CreationToken { - account_id, - realm_id, - }, - ); + pub fn store_creation_token(&self, token: u32, account_id: u32, realm_id: u32) -> Result<(), crate::Error> { + self.creation_tokens + .lock() + .insert(token, CreationToken { account_id, realm_id }); Ok(()) } /// Remove a CreationToken. - pub fn remove_creation_token( - &self, - token: u32, - ) -> Result { + pub fn remove_creation_token(&self, token: u32) -> Result { self.creation_tokens .lock() .remove(&token) @@ -174,9 +153,7 @@ impl State { let entities = self.drain_entities(); for e in entities { match e.as_ref() { - GameEntity::Character(character) => { - character.save(&self).await? - }, + GameEntity::Character(character) => character.save(&self).await?, GameEntity::Npc(_) => { // Do nothing for now }, diff --git a/server/game/src/systems/commands.rs b/server/game/src/systems/commands.rs index 2166b5d..8a17a5d 100644 --- a/server/game/src/systems/commands.rs +++ b/server/game/src/systems/commands.rs @@ -4,28 +4,16 @@ use crate::{ActorState, Error}; use argh::FromArgs; use tq_network::Actor; -pub async fn parse_and_execute( - state: &crate::State, - actor: &Actor, - args: &[&str], -) -> Result<(), Error> { +pub async fn parse_and_execute(state: &crate::State, actor: &Actor, args: &[&str]) -> Result<(), Error> { let entity = actor.entity(); let me = entity.as_character().ok_or(Error::CharacterNotFound)?; let c = match Command::from_args(&["commands"], args) { Ok(cmd) => cmd, Err(e) => { - let lines = e - .output - .lines() - .map(|e| e.to_owned()) - .skip_while(|e| e.is_empty()); + let lines = e.output.lines().map(|e| e.to_owned()).skip_while(|e| e.is_empty()); for line in lines { actor - .send(MsgTalk::from_system( - me.id(), - TalkChannel::System, - line, - )) + .send(MsgTalk::from_system(me.id(), TalkChannel::System, line)) .await?; } return Ok(()); @@ -54,11 +42,7 @@ pub async fn parse_and_execute( .send(MsgTalk::from_system( me.id(), TalkChannel::System, - format!( - "Current Map: {:?} = {}", - Maps::from(map_id), - map_id - ), + format!("Current Map: {:?} = {}", Maps::from(map_id), map_id), )) .await?; } diff --git a/server/game/src/systems/floor.rs b/server/game/src/systems/floor.rs index da51a41..05dd804 100644 --- a/server/game/src/systems/floor.rs +++ b/server/game/src/systems/floor.rs @@ -42,7 +42,9 @@ impl Floor { self.loaded.load(std::sync::atomic::Ordering::Relaxed) } - pub fn boundaries(&self) -> Size { *self.boundaries.read() } + pub fn boundaries(&self) -> Size { + *self.boundaries.read() + } pub fn with_coordinates(&self, f: F) -> T where @@ -90,8 +92,7 @@ impl Floor { } *self.boundaries.write() = boundaries; *self.coordinates.write() = coordinates; - self.loaded - .store(true, std::sync::atomic::Ordering::Relaxed); + self.loaded.store(true, std::sync::atomic::Ordering::Relaxed); trace!("Loaded Map {}", self.path.display()); } else { trace!("we didn't found the map at {}", map_path.display()); @@ -109,17 +110,13 @@ impl Floor { #[tracing::instrument(skip(self), fields(path = %self.path.display()))] pub fn unload(&self) { *self.coordinates.write() = Default::default(); - self.loaded - .store(false, std::sync::atomic::Ordering::Relaxed); + self.loaded.store(false, std::sync::atomic::Ordering::Relaxed); } /// This method converts a data map from TQ Digital's Conquer Online client /// to a compressed map file that only holds access values. #[tracing::instrument(skip(self), err, fields(path = %self.path.display()))] - async fn convert_and_load>( - &self, - path: P, - ) -> Result<(), Error> { + async fn convert_and_load>(&self, path: P) -> Result<(), Error> { let p = path.into(); trace!("converting {}", p.display()); let f = File::open(&p).await?; @@ -192,21 +189,16 @@ impl Floor { let (buf, _) = buf.split_at(terminator_byte_idx); let scene_file_name = std::str::from_utf8(buf)?; // replace backslashes with forward slashes - let scene_file_name = - scene_file_name.replace("map\\", "").replace('\\', "/"); + let scene_file_name = scene_file_name.replace("map\\", "").replace('\\', "/"); let data_path = PathBuf::from(env::var("DATA_LOCATION")?); - let scene_path = data_path - .join("GameMaps") - .join(scene_file_name) - .canonicalize()?; + let scene_path = data_path.join("GameMaps").join(scene_file_name).canonicalize()?; trace!("Loading scene file {}", scene_path.display()); let px = buffer.get_i32_le(); let py = buffer.get_i32_le(); let location = Point::new(px, py); // Get scene Data from the scene file let scene = File::open(scene_path).await?; - let mut scene_reader = - io::BufReader::with_capacity(1024, scene); + let mut scene_reader = io::BufReader::with_capacity(1024, scene); let mut buffer = Vec::new(); scene_reader.read_to_end(&mut buffer).await?; let mut scene_buffer = Bytes::from(buffer); @@ -256,8 +248,7 @@ impl Floor { trace!("loaded #{} scenery data", count); *self.boundaries.write() = boundaries; *self.coordinates.write() = coordinates; - self.loaded - .store(true, std::sync::atomic::Ordering::Relaxed); + self.loaded.store(true, std::sync::atomic::Ordering::Relaxed); self.save().await?; Ok(()) } @@ -269,10 +260,8 @@ impl Floor { #[tracing::instrument(skip(self), fields(path = %self.path.display()))] async fn save(&self) -> Result<(), Error> { let boundaries = self.boundaries(); - let can_save = !self.path.exists() - && !self.loaded() - && boundaries.area() != 0 - && !self.with_coordinates(|c| c.is_empty()); + let can_save = + !self.path.exists() && !self.loaded() && boundaries.area() != 0 && !self.with_coordinates(|c| c.is_empty()); trace!("Can we save {}? {}", self.path.display(), can_save); if can_save { let mut buffer = BytesMut::new(); @@ -292,8 +281,7 @@ impl Floor { let data_path = PathBuf::from(env::var("DATA_LOCATION")?); let map_path = data_path.join("Maps").join(&self.path); let f = File::create(map_path).await?; - let mut writer = - io::BufWriter::with_capacity(boundaries.area() as usize, f); + let mut writer = io::BufWriter::with_capacity(boundaries.area() as usize, f); writer.write_all(&buffer).await?; writer.flush().await?; debug!("Saved Map {}", self.path.display()); @@ -327,7 +315,9 @@ pub enum TileType { } impl Default for TileType { - fn default() -> Self { Self::Unknown } + fn default() -> Self { + Self::Unknown + } } /// This enumeration type defines the types of scenery files used by the client. diff --git a/server/game/src/systems/screen.rs b/server/game/src/systems/screen.rs index 9ecae21..690094d 100644 --- a/server/game/src/systems/screen.rs +++ b/server/game/src/systems/screen.rs @@ -76,34 +76,24 @@ impl Screen { /// screen object is being added, and the object is of type character, then /// the owner will be added to the observer's screen as well. #[tracing::instrument(skip(self, observer), fields(me = self.owner.id()))] - pub fn insert_entity( - &self, - observer: Weak, - ) -> Result { + pub fn insert_entity(&self, observer: Weak) -> Result { let o = observer.upgrade().ok_or(Error::CharacterNotFound)?; let alredy_exists = self.with_entities(|c| c.contains_key(&o.id())); if alredy_exists { return Ok(false); } let oid = o.id(); - let added = self - .with_entities_mut(|c| c.insert(oid, Arc::downgrade(&o)).is_none()); + let added = self.with_entities_mut(|c| c.insert(oid, Arc::downgrade(&o)).is_none()); if !added { return Ok(false); } match o.as_ref() { GameEntity::Character(c) => { - let me = self - .character - .load() - .upgrade() - .ok_or(Error::CharacterNotFound)?; + let me = self.character.load().upgrade().ok_or(Error::CharacterNotFound)?; debug!(character = c.id(), "Added Character to Screen"); let oscreen = c.try_screen()?; let myid = self.character_id()?; - let added = oscreen.with_entities_mut(|c| { - c.insert(myid, Arc::downgrade(&me)).is_none() - }); + let added = oscreen.with_entities_mut(|c| c.insert(myid, Arc::downgrade(&me)).is_none()); Ok(added) }, GameEntity::Npc(o) => { @@ -118,9 +108,7 @@ impl Screen { /// characters who are actively removing themselves out of the screen. #[tracing::instrument(skip(self), fields(me = self.owner.id()))] pub fn remove_entity(&self, observer: u32) -> Result { - let Some(o) = self.with_entities_mut(|c| { - c.remove(&observer).and_then(|c| c.upgrade()) - }) else { + let Some(o) = self.with_entities_mut(|c| c.remove(&observer).and_then(|c| c.upgrade())) else { return Ok(false); }; match o.as_ref() { @@ -128,8 +116,7 @@ impl Screen { debug!(character = c.id(), "Removed Character from Screen"); let oscreen = c.try_screen()?; let myid = self.character_id()?; - let removed = - oscreen.with_entities_mut(|c| c.remove(&myid).is_some()); + let removed = oscreen.with_entities_mut(|c| c.remove(&myid).is_some()); Ok(removed) }, GameEntity::Npc(o) => { @@ -150,13 +137,7 @@ impl Screen { return Ok(false); } self.owner - .send(MsgAction::new( - observer, - observer, - 0, - 0, - ActionType::LeaveMap, - )) + .send(MsgAction::new(observer, observer, 0, 0, ActionType::LeaveMap)) .await?; tracing::trace!(%observer, "Deleted from Screen"); Ok(true) @@ -174,10 +155,7 @@ impl Screen { for o in iter { match o.as_ref() { GameEntity::Character(c) => { - tracing::trace!( - character = c.id(), - "Found Character Observer" - ); + tracing::trace!(character = c.id(), "Found Character Observer"); let Ok(screen) = c.try_screen() else { continue; }; @@ -202,10 +180,7 @@ impl Screen { let res = task?; match res { Ok(observer) => { - tracing::trace!( - observer = observer, - "Removed from Observer's Screen" - ); + tracing::trace!(observer = observer, "Removed from Observer's Screen"); }, Err(e) => { tracing::error!(error = ?e, "Failed to delete from screen"); @@ -225,15 +200,8 @@ impl Screen { /// spawns it to the owner's screen (if the object is within the owner's /// screen distance). #[tracing::instrument(skip(self, state), fields(me = self.owner.id()))] - pub async fn load_surroundings( - &self, - state: &crate::State, - ) -> Result<(), Error> { - let entity = self - .character - .load() - .upgrade() - .ok_or(Error::CharacterNotFound)?; + pub async fn load_surroundings(&self, state: &crate::State) -> Result<(), Error> { + let entity = self.character.load().upgrade().ok_or(Error::CharacterNotFound)?; let me = entity.as_character().ok_or(Error::CharacterNotFound)?; let mymap = state.try_map(me.entity().map_id())?; let loc = me.entity().location(); @@ -255,15 +223,11 @@ impl Screen { GameEntity::Character(_) if can_see(&o, &myself) => { let o = o.clone(); let fut = async move { - let added = - self.insert_entity(Arc::downgrade(&o))?; + let added = self.insert_entity(Arc::downgrade(&o))?; if !added { return Ok(()); } - tracing::trace!( - character = o.id(), - "Loaded Into Screen" - ); + tracing::trace!(character = o.id(), "Loaded Into Screen"); me.exchange_spawn_packets(&o).await?; Result::<_, Error>::Ok(()) } @@ -275,15 +239,11 @@ impl Screen { let me = entity.clone(); // Spawn the npc to the owner's screen. let fut = async move { - let added = - self.insert_entity(Arc::downgrade(&o))?; + let added = self.insert_entity(Arc::downgrade(&o))?; if !added { return Ok(()); } - tracing::trace!( - npc = o.id(), - "Loaded Into Screen" - ); + tracing::trace!(npc = o.id(), "Loaded Into Screen"); o.send_spawn(&me).await?; Result::<_, Error>::Ok(()) } @@ -323,9 +283,7 @@ impl Screen { { let futures = FuturesUnordered::new(); self.with_entities(|c| { - let iter = c - .values() - .filter_map(|v| v.upgrade().and_then(|o| o.owner())); + let iter = c.values().filter_map(|v| v.upgrade().and_then(|o| o.owner())); for o in iter { let packet = packet.clone(); let fut = async move { @@ -363,19 +321,11 @@ impl Screen { /// within the new screen distance, the method will attempt to remove it /// from the owner's screen. #[tracing::instrument(skip(self, state, packet), fields(me = self.owner.id(), packet_id = P::PACKET_ID))] - pub async fn send_movement

( - &self, - state: &crate::State, - packet: P, - ) -> Result<(), Error> + pub async fn send_movement

(&self, state: &crate::State, packet: P) -> Result<(), Error> where P: PacketEncode + PacketID + Clone + Send + Sync + 'static, { - let entity = self - .character - .load() - .upgrade() - .ok_or(Error::CharacterNotFound)?; + let entity = self.character.load().upgrade().ok_or(Error::CharacterNotFound)?; let me = entity.as_character().ok_or(Error::CharacterNotFound)?; let mymap = state.try_map(me.entity().map_id())?; let loc = me.entity().location(); @@ -399,14 +349,10 @@ impl Screen { let o = o.clone(); let oowner = c.owner(); let fut = async move { - let added = - self.insert_entity(Arc::downgrade(&o))?; + let added = self.insert_entity(Arc::downgrade(&o))?; // new, let's exchange spawn packets if added { - tracing::trace!( - observer = o.id(), - "Loaded Into Screen", - ); + tracing::trace!(observer = o.id(), "Loaded Into Screen",); me.exchange_spawn_packets(&o).await?; } else { // observer is already there, send the @@ -430,21 +376,12 @@ impl Screen { // Else, remove the observer and send the last // packet. if oscreen.remove_entity(me.id())? { - tracing::trace!( - observer = observer_id, - "UnLoaded Screen" - ); + tracing::trace!(observer = observer_id, "UnLoaded Screen"); // send the last packet. - oowner - .send(packet) - .await - .unwrap_or_default(); + oowner.send(packet).await.unwrap_or_default(); } if self.remove_entity(observer_id)? { - tracing::trace!( - observer = observer_id, - "Removed from Screen" - ); + tracing::trace!(observer = observer_id, "Removed from Screen"); } Result::<_, Error>::Ok(()) } @@ -453,14 +390,10 @@ impl Screen { }, GameEntity::Npc(_) if can_see_npc(&o, &myself) => { let fut = async move { - let added = - self.insert_entity(Arc::downgrade(&o))?; + let added = self.insert_entity(Arc::downgrade(&o))?; // new, Send NPC spawn packet to the owner if added { - tracing::trace!( - npc = o.id(), - "Loaded Into Screen" - ); + tracing::trace!(npc = o.id(), "Loaded Into Screen"); o.send_spawn(&myself).await?; } else { // observer is already there diff --git a/server/game/src/test_utils.rs b/server/game/src/test_utils.rs index 0920cbe..d62b85d 100644 --- a/server/game/src/test_utils.rs +++ b/server/game/src/test_utils.rs @@ -8,15 +8,9 @@ use crate::packets::MsgRegister; use crate::systems::Screen; use crate::ActorState; -pub async fn with_test_env<'a, F>( - log_level: tracing::Level, - f: F, -) -> Result<(), crate::Error> +pub async fn with_test_env<'a, F>(log_level: tracing::Level, f: F) -> Result<(), crate::Error> where - F: FnOnce( - crate::State, - [Actor; 2], - ) -> BoxFuture<'a, Result<(), crate::Error>>, + F: FnOnce(crate::State, [Actor; 2]) -> BoxFuture<'a, Result<(), crate::Error>>, { let root_dir = std::process::Command::new("git") .args(["rev-parse", "--show-toplevel"]) @@ -40,10 +34,7 @@ where .pretty() .with_target(true) .with_test_writer(); - tracing_subscriber::registry() - .with(env_filter) - .with(logger) - .init(); + tracing_subscriber::registry().with(env_filter).with(logger).init(); let pool = SqlitePoolOptions::new() .max_connections(42) @@ -56,17 +47,11 @@ where .await .expect("Failed to migrate database"); let state = crate::State::with_pool(pool).await?; - let actors = [ - make_test_actor(&state, 1).await?, - make_test_actor(&state, 2).await?, - ]; + let actors = [make_test_actor(&state, 1).await?, make_test_actor(&state, 2).await?]; f(state, actors).await } -pub async fn make_test_actor( - state: &crate::State, - id: usize, -) -> Result, crate::Error> { +pub async fn make_test_actor(state: &crate::State, id: usize) -> Result, crate::Error> { let (tx, _rx) = tokio::sync::mpsc::channel(50); let actor = Actor::::new(tx); actor.set_id(id); @@ -78,10 +63,9 @@ pub async fn make_test_actor( 1, )?; inner_character.save(state.pool()).await?; - let inner_character = - tq_db::character::Character::from_account(state.pool(), id as _) - .await? - .expect("Failed to load character"); + let inner_character = tq_db::character::Character::from_account(state.pool(), id as _) + .await? + .expect("Failed to load character"); let character = Character::new(actor.handle(), inner_character); let screen = Screen::new(actor.handle()); actor.update(character, screen); diff --git a/server/game/src/utils.rs b/server/game/src/utils.rs index edfedc6..faebf1e 100644 --- a/server/game/src/utils.rs +++ b/server/game/src/utils.rs @@ -17,9 +17,13 @@ pub trait LoHi { impl LoHi for u16 { type Output = u8; - fn lo(&self) -> Self::Output { *self as u8 } + fn lo(&self) -> Self::Output { + *self as u8 + } - fn hi(&self) -> Self::Output { (*self >> 8) as u8 } + fn hi(&self) -> Self::Output { + (*self >> 8) as u8 + } fn constract(hi: Self::Output, lo: Self::Output) -> Self { lo as u16 | (hi as u16) << 8 @@ -29,9 +33,13 @@ impl LoHi for u16 { impl LoHi for u32 { type Output = u16; - fn lo(&self) -> Self::Output { *self as u16 } + fn lo(&self) -> Self::Output { + *self as u16 + } - fn hi(&self) -> Self::Output { (*self >> 16) as u16 } + fn hi(&self) -> Self::Output { + (*self >> 16) as u16 + } fn constract(hi: Self::Output, lo: Self::Output) -> Self { lo as u32 | (hi as u32) << 16 @@ -41,9 +49,13 @@ impl LoHi for u32 { impl LoHi for u64 { type Output = u32; - fn lo(&self) -> Self::Output { *self as u32 } + fn lo(&self) -> Self::Output { + *self as u32 + } - fn hi(&self) -> Self::Output { (*self >> 32) as u32 } + fn hi(&self) -> Self::Output { + (*self >> 32) as u32 + } fn constract(hi: Self::Output, lo: Self::Output) -> Self { lo as u64 | (hi as u64) << 32 diff --git a/server/game/src/world/map.rs b/server/game/src/world/map.rs index 7698d62..2ba6cd1 100644 --- a/server/game/src/world/map.rs +++ b/server/game/src/world/map.rs @@ -42,11 +42,7 @@ pub struct Map { } impl Map { - pub fn new( - inner: tq_db::map::Map, - portals: Vec, - npcs: Vec, - ) -> Self { + pub fn new(inner: tq_db::map::Map, portals: Vec, npcs: Vec) -> Self { let portals = portals.into_iter().map(Portal::new).collect(); let npcs = npcs .into_iter() @@ -55,10 +51,7 @@ impl Map { .collect(); Self { floor: Floor::new(inner.path.clone()), - revive_point: Point::new( - inner.revive_point_x as u32, - inner.revive_point_y as u32, - ), + revive_point: Point::new(inner.revive_point_x as u32, inner.revive_point_y as u32), regions: RwLock::new(Vec::new()), npcs, portals, @@ -66,9 +59,13 @@ impl Map { } } - pub fn id(&self) -> u32 { self.inner.id as u32 } + pub fn id(&self) -> u32 { + self.inner.id as u32 + } - pub fn map_id(&self) -> u32 { self.inner.map_id as u32 } + pub fn map_id(&self) -> u32 { + self.inner.map_id as u32 + } pub fn weather(&self) -> WeatherKind { WeatherKind::from(self.inner.weather as u32) @@ -78,17 +75,29 @@ impl Map { MapFlags::from_bits(self.inner.flags as u32).unwrap_or_default() } - pub fn color(&self) -> u32 { self.inner.color as u32 } + pub fn color(&self) -> u32 { + self.inner.color as u32 + } - pub fn revive_point(&self) -> Point { self.revive_point } + pub fn revive_point(&self) -> Point { + self.revive_point + } - pub fn is_static(&self) -> bool { self.inner.id == self.inner.map_id } + pub fn is_static(&self) -> bool { + self.inner.id == self.inner.map_id + } - pub fn is_copy(&self) -> bool { self.inner.id == self.inner.map_id } + pub fn is_copy(&self) -> bool { + self.inner.id == self.inner.map_id + } - pub fn portals(&self) -> &Portals { &self.portals } + pub fn portals(&self) -> &Portals { + &self.portals + } - pub fn tile(&self, x: u16, y: u16) -> Option { self.floor.tile(x, y) } + pub fn tile(&self, x: u16, y: u16) -> Option { + self.floor.tile(x, y) + } pub fn npc(&self, id: u32) -> Option<&Npc> { self.npcs.get(&id).and_then(|v| v.as_npc()) @@ -108,8 +117,7 @@ impl Map { let region_size = MapRegion::SIZE; let region_x = x as u32 / region_size.width; let region_y = y as u32 / region_size.height; - let width = - (map_size.width as f32 / region_size.width as f32).ceil() as u32; + let width = (map_size.width as f32 / region_size.width as f32).ceil() as u32; let region_index = region_x * width + region_y; tracing::trace!(%x, %y, %region_x, %region_y, %region_index, "Querying Region"); regions.get(region_index as usize).cloned() @@ -121,10 +129,8 @@ impl Map { let regions = self.regions.read(); let map_size = self.floor.boundaries(); let region_size = MapRegion::SIZE; - let height = - (map_size.height as f32 / region_size.height as f32).ceil() as u32; - let width = - (map_size.width as f32 / region_size.width as f32).ceil() as u32; + let height = (map_size.height as f32 / region_size.height as f32).ceil() as u32; + let width = (map_size.width as f32 / region_size.width as f32).ceil() as u32; let region_x = x as u32 / region_size.width; let region_y = y as u32 / region_size.height; let region_index = |x, y| (x * width + y) as usize; @@ -136,11 +142,7 @@ impl Map { for i in 0..constants::WALK_XCOORDS.len() { let view_x = region_x as i32 + constants::WALK_XCOORDS[i] as i32; let view_y = region_y as i32 + constants::WALK_YCOORDS[i] as i32; - if view_x.is_negative() - || view_y.is_negative() - || view_x >= width as _ - || view_y >= height as _ - { + if view_x.is_negative() || view_y.is_negative() || view_x >= width as _ || view_y >= height as _ { continue; } let j = region_index(view_x as u32, view_y as u32); @@ -166,10 +168,8 @@ impl Map { let map_size = self.floor.boundaries(); let region_size = MapRegion::SIZE; // ceil division to get the number of regions - let height = - (map_size.height as f32 / region_size.height as f32).ceil() as u32; - let width = - (map_size.width as f32 / region_size.width as f32).ceil() as u32; + let height = (map_size.height as f32 / region_size.height as f32).ceil() as u32; + let width = (map_size.width as f32 / region_size.width as f32).ceil() as u32; let number_of_regions = height * width; tracing::trace!( %map_size, @@ -179,8 +179,7 @@ impl Map { number_of_regions, "Building regions", ); - let mut regions = - vec![MapRegion::default(); number_of_regions as usize]; + let mut regions = vec![MapRegion::default(); number_of_regions as usize]; for y in 0..height { for x in 0..width { let start_point = Point::new(x, y); @@ -231,11 +230,7 @@ impl Map { self.remove_entity_by_id_and_location(e.id(), e.basic().location()) } - pub fn remove_entity_by_id_and_location( - &self, - id: u32, - Location { x, y, .. }: Location, - ) -> Result<(), Error> { + pub fn remove_entity_by_id_and_location(&self, id: u32, Location { x, y, .. }: Location) -> Result<(), Error> { let region = self.region(x, y); if let Some(region) = region { region.remove_entity(id); @@ -253,12 +248,7 @@ impl Map { /// and check that the player is not wall jumping. It checks all tiles /// in between the player and the jumping destination. #[tracing::instrument(skip(self), fields(map_id = self.id()))] - pub fn sample_elevation( - &self, - start: (u16, u16), - end: (u16, u16), - elevation: u16, - ) -> bool { + pub fn sample_elevation(&self, start: (u16, u16), end: (u16, u16), elevation: u16) -> bool { let distance = tq_math::get_distance(start, end) as u16; // If the distance is 0, we are not moving. if distance == 0 { @@ -271,8 +261,7 @@ impl Map { let tile = self.floor.tile(x, y); match tile { Some(tile) => { - let within_elevation = - tq_math::within_elevation(tile.elevation, elevation); + let within_elevation = tq_math::within_elevation(tile.elevation, elevation); if !within_elevation { return false; } @@ -350,10 +339,7 @@ impl Map { Ok(()) } - pub async fn change_weather( - &self, - weather: WeatherKind, - ) -> Result<(), Error> { + pub async fn change_weather(&self, weather: WeatherKind) -> Result<(), Error> { let msg = MsgWeather::new(weather); self.broadcast(msg).map_err(Into::into).await } @@ -385,7 +371,9 @@ pub struct MapRegion { impl Eq for MapRegion {} impl PartialEq for MapRegion { - fn eq(&self, other: &Self) -> bool { self.start_point == other.start_point } + fn eq(&self, other: &Self) -> bool { + self.start_point == other.start_point + } } impl fmt::Display for MapRegion { @@ -398,8 +386,7 @@ impl fmt::Display for MapRegion { impl MapRegion { /// WIDTH and HEIGHT are the number of tiles in a region. - pub const SIZE: Size = - Size::new(SCREEN_DISTANCE as _, SCREEN_DISTANCE as _); + pub const SIZE: Size = Size::new(SCREEN_DISTANCE as _, SCREEN_DISTANCE as _); pub fn new(start_point: Point, map_size: Size) -> Self { Self { @@ -410,13 +397,14 @@ impl MapRegion { } pub fn id(&self) -> usize { - let width = (self.map_size.width as f32 / Self::SIZE.width as f32) - .ceil() as u32; + let width = (self.map_size.width as f32 / Self::SIZE.width as f32).ceil() as u32; let Point { x, y } = self.start_point; (x * width + y) as usize } - pub fn is_empty(&self) -> bool { self.with_entities(|c| c.is_empty()) } + pub fn is_empty(&self) -> bool { + self.with_entities(|c| c.is_empty()) + } pub fn try_entities(&self, id: u32) -> Option> { self.with_entities(|c| c.get(&id).cloned()) @@ -438,9 +426,7 @@ impl MapRegion { #[tracing::instrument(skip_all, fields(map_id = self.id(), entity_id = entity.as_ref().id()))] pub fn insert_entity(&self, entity: Arc) { - self.with_entities_mut(|c| { - c.insert(entity.id(), Arc::downgrade(&entity)) - }); + self.with_entities_mut(|c| c.insert(entity.id(), Arc::downgrade(&entity))); } #[tracing::instrument(skip_all, fields(map_id = self.id(), entity_id = id))] @@ -457,8 +443,7 @@ impl MapRegion { self.with_entities(|entities| { for character in entities.values() { let p = packet.clone(); - let Some(owner) = character.upgrade().and_then(|c| c.owner()) - else { + let Some(owner) = character.upgrade().and_then(|c| c.owner()) else { continue; }; let f = async move { owner.send(p).await }; diff --git a/server/game/src/world/portal.rs b/server/game/src/world/portal.rs index 6d6bf97..5d8667d 100644 --- a/server/game/src/world/portal.rs +++ b/server/game/src/world/portal.rs @@ -10,34 +10,56 @@ pub struct Portal { impl Deref for Portal { type Target = tq_db::portal::Portal; - fn deref(&self) -> &Self::Target { &self.inner } + fn deref(&self) -> &Self::Target { + &self.inner + } } impl Portal { - pub fn new(inner: tq_db::portal::Portal) -> Self { Self { inner } } + pub fn new(inner: tq_db::portal::Portal) -> Self { + Self { inner } + } - pub fn uid(&self) -> u32 { self.inner.id as u32 } + pub fn uid(&self) -> u32 { + self.inner.id as u32 + } - pub fn id(&self) -> u32 { u32::constract(self.from_y(), self.from_x()) } + pub fn id(&self) -> u32 { + u32::constract(self.from_y(), self.from_x()) + } #[allow(clippy::wrong_self_convention)] - pub fn from_map_id(&self) -> u32 { self.inner.from_map_id as u32 } + pub fn from_map_id(&self) -> u32 { + self.inner.from_map_id as u32 + } - pub fn to_map_id(&self) -> u32 { self.inner.to_map_id as u32 } + pub fn to_map_id(&self) -> u32 { + self.inner.to_map_id as u32 + } #[allow(clippy::wrong_self_convention)] - pub fn from_x(&self) -> u16 { self.inner.from_x as u16 } + pub fn from_x(&self) -> u16 { + self.inner.from_x as u16 + } #[allow(clippy::wrong_self_convention)] - pub fn from_y(&self) -> u16 { self.inner.from_y as u16 } + pub fn from_y(&self) -> u16 { + self.inner.from_y as u16 + } - pub fn to_x(&self) -> u16 { self.inner.to_x as u16 } + pub fn to_x(&self) -> u16 { + self.inner.to_x as u16 + } - pub fn to_y(&self) -> u16 { self.inner.to_y as u16 } + pub fn to_y(&self) -> u16 { + self.inner.to_y as u16 + } } impl PartialEq for Portal { - fn eq(&self, other: &Self) -> bool { self.id == other.id } + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } } impl Eq for Portal {} diff --git a/tools/externref/src/main.rs b/tools/externref/src/main.rs index 65cd1c0..3ef8c88 100644 --- a/tools/externref/src/main.rs +++ b/tools/externref/src/main.rs @@ -9,8 +9,7 @@ fn main() { eprintln!("Failed to read input file: {}", err); std::process::exit(1); }); - let processed: Vec = - Processor::default().process_bytes(&module).unwrap(); + let processed: Vec = Processor::default().process_bytes(&module).unwrap(); std::fs::write(output, processed).unwrap_or_else(|err| { eprintln!("Failed to write output file: {}", err); std::process::exit(1); @@ -18,9 +17,6 @@ fn main() { } fn print_usage<'a>() -> &'a String { - eprintln!( - "Usage: {} ", - std::env::args().next().unwrap() - ); + eprintln!("Usage: {} ", std::env::args().next().unwrap()); std::process::exit(1); } diff --git a/tools/gamemap-decoder/src/main.rs b/tools/gamemap-decoder/src/main.rs index 31378a2..b6fd705 100644 --- a/tools/gamemap-decoder/src/main.rs +++ b/tools/gamemap-decoder/src/main.rs @@ -53,23 +53,16 @@ struct Portal { fn main() -> anyhow::Result<()> { dotenvy::dotenv()?; let data_path = env::var("DATA_LOCATION")?; - let dat_path = PathBuf::from(&data_path) - .join("GameMaps") - .join("GameMap.dat"); + let dat_path = PathBuf::from(&data_path).join("GameMaps").join("GameMap.dat"); let maps_csv = PathBuf::from(&data_path).join("Maps").join("Maps.csv"); - let portals_csv = - PathBuf::from(&data_path).join("Maps").join("Portals.csv"); - let csv_reader = csv::ReaderBuilder::new() - .has_headers(true) - .from_path(maps_csv)?; + let portals_csv = PathBuf::from(&data_path).join("Maps").join("Portals.csv"); + let csv_reader = csv::ReaderBuilder::new().has_headers(true).from_path(maps_csv)?; let mut maps = csv_reader .into_deserialize::() .filter_map(Result::ok) .map(|m| (m.uid, m)) .collect::>(); - let csv_reader = csv::ReaderBuilder::new() - .has_headers(true) - .from_path(portals_csv)?; + let csv_reader = csv::ReaderBuilder::new().has_headers(true).from_path(portals_csv)?; let portals = csv_reader .into_deserialize::() .filter_map(Result::ok) @@ -136,9 +129,7 @@ fn main() -> anyhow::Result<()> { } in portals { match (maps.get(&from_map_id), maps.get(&to_map_id)) { - (Some(from), Some(to)) - if !from.path.is_empty() && !to.path.is_empty() => - { + (Some(from), Some(to)) if !from.path.is_empty() && !to.path.is_empty() => { println!( r#"INSERT INTO portals VALUES ({id}, {from_map_id}, {from_x}, {from_y}, {to_map_id}, {to_x}, {to_y});"#, ); diff --git a/tools/hash-pwd/src/main.rs b/tools/hash-pwd/src/main.rs index b54b5fe..861f5ca 100644 --- a/tools/hash-pwd/src/main.rs +++ b/tools/hash-pwd/src/main.rs @@ -1,11 +1,8 @@ const SHOW_USAGE: &str = "usage hash-pwd "; fn main() -> Result<(), String> { - let pwd = std::env::args() - .nth(1) - .ok_or_else(|| SHOW_USAGE.to_owned())?; - let hashed = - bcrypt::hash(pwd, bcrypt::DEFAULT_COST).map_err(|e| e.to_string())?; + let pwd = std::env::args().nth(1).ok_or_else(|| SHOW_USAGE.to_owned())?; + let hashed = bcrypt::hash(pwd, bcrypt::DEFAULT_COST).map_err(|e| e.to_string())?; println!("{}", hashed); Ok(()) } From 1ec776627c413acae7e12ab71e5cf773f8b5342c Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Sun, 28 Jan 2024 23:39:06 +0200 Subject: [PATCH 26/28] wasm works so far --- crates/bindings/src/lib.rs | 73 +++++---- crates/crypto/src/rc5.rs | 40 ++++- crates/wasm-builder/src/builder.rs | 8 + crates/wasm-builder/src/wasm_project.rs | 3 +- packets/account/src/lib.rs | 4 +- server/auth/Cargo.toml | 2 +- server/auth/src/error.rs | 2 + server/auth/src/lib.rs | 101 ++++++++++-- server/auth/src/linker.rs | 204 ++++++++++++------------ 9 files changed, 286 insertions(+), 151 deletions(-) diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs index e4b323a..54f0e2f 100644 --- a/crates/bindings/src/lib.rs +++ b/crates/bindings/src/lib.rs @@ -20,6 +20,14 @@ pub fn setup_logging(name: &'static str) { tracing::subscriber::set_global_default(subscriber).unwrap(); } +pub fn encode_ptr_len(a: *mut u8, b: usize) -> u64 { + (a as u64) << 32 | b as u64 +} + +pub fn decode_ptr_len(c: u64) -> (*mut u8, usize) { + ((c >> 32) as u32 as *mut u8, c as u32 as usize) +} + /// A [`MakeWriter`] emitting the written text to the [`host`]. #[cfg(not(feature = "std"))] pub fn setup_logging(_name: &'static str) {} @@ -52,25 +60,15 @@ pub fn set_panic_hook_once(_name: &'static str) {} #[link(wasm_import_module = "host")] #[cfg(target_arch = "wasm32")] extern "C" { - fn getrandom(ptr: *mut u8, len: usize) -> i32; + fn getrandom(buffer: u64) -> i32; fn tq_network_actor_shutdown(actor: &Resource); - fn tq_network_actor_send( - actor: &Resource, - packet_id: u16, - packet_data_ptr: *const u8, - packet_data_len: u32, - ); + fn tq_network_actor_send(actor: &Resource, packet_id: u16, packet: u64); fn tq_network_actor_set_id(actor: &Resource, id: u32); - fn tq_db_realm_by_name(realm_name_ptr: *const u8, realm_name_len: u32) -> (i32, i32); + fn tq_db_realm_by_name(realm_name: u64) -> u64; - fn tq_db_account_auth( - username_ptr: *const u8, - username_len: u32, - password_ptr: *const u8, - password_len: u32, - ) -> i32; + fn tq_db_account_auth(username: u64, password: u64) -> i32; fn game_state_generate_login_token( actor: &Resource, @@ -78,9 +76,8 @@ extern "C" { realm_id: u32, ) -> u64; - fn auth_server_bus_check(realm_ptr: *const u8, realm_len: u32) -> i32; - fn auth_server_bus_transfer(actor: &Resource, realm_ptr: *const u8, realm_len: u32) - -> u64; + fn auth_server_bus_check(realm: u64) -> i32; + fn auth_server_bus_transfer(actor: &Resource, realm: u64) -> u64; } /// Host bindings. @@ -107,9 +104,8 @@ pub mod host { #[cfg(target_arch = "wasm32")] pub fn send(actor: &Resource, packet: T) -> Result<(), T::Error> { let (packet_id, packet_data) = packet.encode()?; - unsafe { - crate::tq_network_actor_send(actor, packet_id, packet_data.as_ptr(), packet_data.len() as u32) - } + let packet = crate::encode_ptr_len(packet_data.as_ptr() as *mut u8, packet_data.len()); + unsafe { crate::tq_network_actor_send(actor, packet_id, packet) } Ok(()) } #[cfg(not(target_arch = "wasm32"))] @@ -134,16 +130,14 @@ pub mod host { pub mod db { /// [`tq_db::account`] bindings. pub mod account { + /// [`tq_db::account::Account::auth`] bindings. #[cfg(target_arch = "wasm32")] pub fn auth(username: &str, password: &str) -> Result { let res = unsafe { - crate::tq_db_account_auth( - username.as_ptr(), - username.len() as u32, - password.as_ptr(), - password.len() as u32, - ) + let username = crate::encode_ptr_len(username.as_ptr() as *mut u8, username.len()); + let password = crate::encode_ptr_len(password.as_ptr() as *mut u8, password.len()); + crate::tq_db_account_auth(username, password) }; if res > 0 { Ok(res as u32) @@ -169,12 +163,14 @@ pub mod host { #[cfg(target_arch = "wasm32")] pub fn by_name(realm_name: &str) -> Result, tq_db::Error> { use rkyv::Deserialize; - let (realm_ptr, realm_len) = - unsafe { crate::tq_db_realm_by_name(realm_name.as_ptr(), realm_name.len() as u32) }; - if realm_ptr != 0 && realm_len > 0 { + let realm_encoded = unsafe { + let realm_name = crate::encode_ptr_len(realm_name.as_ptr() as *mut u8, realm_name.len()); + crate::tq_db_realm_by_name(realm_name) + }; + let (realm_ptr, realm_len) = crate::decode_ptr_len(realm_encoded); + if !realm_ptr.is_null() && realm_len > 0 { let realm = unsafe { - let bytes = - std::vec::Vec::from_raw_parts(realm_ptr as *mut u8, realm_len as usize, realm_len as usize); + let bytes = std::vec::Vec::from_raw_parts(realm_ptr, realm_len, realm_len); let archived = rkyv::archived_root::(&bytes); archived.deserialize(&mut rkyv::Infallible).unwrap() }; @@ -220,7 +216,10 @@ pub mod host { #[cfg(target_arch = "wasm32")] pub fn check(realm: &Realm) -> Result<(), tq_network::Error> { let archived = rkyv::to_bytes::<_, 64>(realm).unwrap(); - let res = unsafe { crate::auth_server_bus_check(archived.as_ptr(), archived.len() as u32) }; + let res = unsafe { + let archived = crate::encode_ptr_len(archived.as_ptr() as *mut u8, archived.len()); + crate::auth_server_bus_check(archived) + }; if res == 0 { Ok(()) } else { @@ -240,7 +239,10 @@ pub mod host { realm: &Realm, ) -> Result { let archived = rkyv::to_bytes::<_, 64>(realm).unwrap(); - let token = unsafe { crate::auth_server_bus_transfer(actor, archived.as_ptr(), archived.len() as u32) }; + let token = unsafe { + let archived = crate::encode_ptr_len(archived.as_ptr() as *mut u8, archived.len()); + crate::auth_server_bus_transfer(actor, archived) + }; if token == 0 { Err(tq_network::Error::Other(String::from("Server Timed Out"))) } else { @@ -261,7 +263,10 @@ pub mod host { /// Get random bytes. #[cfg(target_arch = "wasm32")] pub fn getrandom(buf: &mut [u8]) -> Result<(), getrandom::Error> { - let res = unsafe { super::getrandom(buf.as_mut_ptr(), buf.len()) }; + let res = unsafe { + let buffer = crate::encode_ptr_len(buf.as_mut_ptr(), buf.len()); + super::getrandom(buffer) + }; if res == 0 { Ok(()) } else { diff --git a/crates/crypto/src/rc5.rs b/crates/crypto/src/rc5.rs index 47c5a2b..4390232 100644 --- a/crates/crypto/src/rc5.rs +++ b/crates/crypto/src/rc5.rs @@ -114,8 +114,32 @@ impl crate::Cipher for TQRC5 { } } - fn encrypt(&self, _data: &mut [u8]) { - unimplemented!("RC5 encryption is not implemented") + fn encrypt(&self, data: &mut [u8]) { + let mut src_len = data.len() / 8; + if data.len() % 8 > 0 { + src_len += 1; + } + + for word in 0..src_len { + let mut chunk_a = &data[8 * word..]; + let mut chunk_b = &data[(8 * word + 4)..]; + let mut a = chunk_a.get_u32_le(); + let mut b = chunk_b.get_u32_le(); + let rounds = self.rounds; + let sub = self.sub; + + for round in 1..=rounds { + a = a.rotate_left(b) ^ b.wrapping_add(sub[(2 * round) as usize]); + b = b.rotate_left(a) ^ a.wrapping_add(sub[(2 * round + 1) as usize]); + } + let chunk_a = &mut data[(8 * word)..]; + let a_bytes = a.wrapping_add(sub[0]).to_le_bytes(); + chunk_a[..4].copy_from_slice(&a_bytes); + + let chunk_b = &mut data[(8 * word + 4)..]; + let b_bytes = b.wrapping_add(sub[1]).to_le_bytes(); + chunk_b[..4].copy_from_slice(&b_bytes); + } } } @@ -124,7 +148,7 @@ mod tests { use super::TQRC5; use crate::Cipher; #[test] - fn test_rc5() { + fn rc5() { let rc5 = TQRC5::new(); let mut buf = [ 0x1C, 0xFD, 0x41, 0xC9, 0xA1, 0x69, 0xAA, 0xB6, 0x0D, 0xA6, 0x08, 0x4D, 0xF3, 0x67, 0xEB, 0x73, @@ -135,4 +159,14 @@ mod tests { [0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] ); } + + #[test] + fn encrypt_decrypt() { + let rc5 = TQRC5::new(); + let mut buf = [0x31; 16]; + let origional = buf; + rc5.encrypt(&mut buf); + rc5.decrypt(&mut buf); + assert_eq!(buf, origional); + } } diff --git a/crates/wasm-builder/src/builder.rs b/crates/wasm-builder/src/builder.rs index 61859b0..ebdea46 100644 --- a/crates/wasm-builder/src/builder.rs +++ b/crates/wasm-builder/src/builder.rs @@ -91,6 +91,14 @@ impl WasmBuilder { self } + /// Enable Support for Multi-Value Return in the WASM binary. + /// + /// This adds `-Ctarget-feature=+multivalue` to `RUST_FLAGS`. + pub fn support_multi_value(mut self) -> Self { + self.rust_flags.push("-Ctarget-feature=+multivalue".into()); + self + } + /// Set the name of the file that will be generated in `OUT_DIR`. /// /// This file needs to be included to get access to the build WASM binary. diff --git a/crates/wasm-builder/src/wasm_project.rs b/crates/wasm-builder/src/wasm_project.rs index 7fa4228..89008bf 100644 --- a/crates/wasm-builder/src/wasm_project.rs +++ b/crates/wasm-builder/src/wasm_project.rs @@ -699,7 +699,7 @@ fn build_bloaty_blob( build_cmd .args(["rustc", "--target=wasm32-unknown-unknown"]) .arg(format!("--manifest-path={}", manifest_path.display())) - .env("RUSTFLAGS", rustflags) + .env("RUSTFLAGS", &rustflags) // Manually set the `CARGO_TARGET_DIR` to prevent a cargo deadlock (cargo locks a target dir // exclusive). The runner project is created in `CARGO_TARGET_DIR` and executing it will // create a sub target directory inside of `CARGO_TARGET_DIR`. @@ -748,6 +748,7 @@ fn build_bloaty_blob( "{}", colorize_info_message("Information that should be included in a bug report.") ); + println!("RUSTC_FLAGS: {}", colorize_info_message(&rustflags)); println!("{} {:?}", colorize_info_message("Executing build command:"), build_cmd); println!( "{} {}", diff --git a/packets/account/src/lib.rs b/packets/account/src/lib.rs index c66b1bc..851d7b6 100644 --- a/packets/account/src/lib.rs +++ b/packets/account/src/lib.rs @@ -7,14 +7,14 @@ include!(concat!(env!("OUT_DIR"), "/wasm.rs")); use msg_connect_ex::{MsgConnectEx, RejectionCode}; use msg_transfer::MsgTransfer; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use tq_bindings::{host, Resource}; use tq_network::PacketID; use tq_serde::{String16, TQPassword}; use tq_network::ActorHandle; -#[derive(Debug, Deserialize, PacketID)] +#[derive(Default, Debug, Serialize, Deserialize, PacketID)] #[packet(id = 1051)] pub struct MsgAccount { pub username: String16, diff --git a/server/auth/Cargo.toml b/server/auth/Cargo.toml index fda3433..06416da 100644 --- a/server/auth/Cargo.toml +++ b/server/auth/Cargo.toml @@ -17,7 +17,7 @@ path = "src/lib.rs" thiserror.workspace = true serde.workspace = true bytes.workspace = true -tq-db.workspace = true +tq-db = { workspace = true, features = ["sqlx"] } tq-network.workspace = true tq-serde.workspace = true async-trait.workspace = true diff --git a/server/auth/src/error.rs b/server/auth/src/error.rs index 89870f5..5cb1e92 100644 --- a/server/auth/src/error.rs +++ b/server/auth/src/error.rs @@ -16,6 +16,7 @@ pub enum Error { Other(String), Msg(u16, Bytes), ActorNotFound, + InvalidPacket, } impl From for Error { @@ -87,6 +88,7 @@ impl core::fmt::Display for Error { write!(f, "Error packet: id = {}, body = {:?}", id, bytes) }, Self::ActorNotFound => write!(f, "Actor Not Found"), + Self::InvalidPacket => write!(f, "Invalid Packet"), } } } diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index 65516a4..0233522 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -18,6 +18,7 @@ pub struct Runtime { pub struct Packets { pub msg_connect: Module, + pub msg_account: Module, } #[async_trait::async_trait] @@ -31,32 +32,79 @@ impl PacketHandler for Runtime { runtime: &Self::State, actor: &Actor, ) -> Result<(), Self::Error> { - const ALLOC: &str = "__alloc"; const PROCESS_PACKET: &str = "process_packet"; - const MEMORY: &str = "memory"; + let packet_len = packet.1.len(); + let mut store = wasmtime::Store::new(&runtime.engine, runtime.state.clone()); let actor = wasmtime::ExternRef::new(actor.handle()); match packet.0 { msg_connect::MsgConnect::PACKET_ID => { - let packet_len = packet.1.len(); let msg_connect = runtime .linker .instantiate_async(&mut store, &runtime.packets.msg_connect) .await?; - let alloc_packet = msg_connect.get_typed_func::(&mut store, ALLOC)?; + let alloc_packet = msg_connect.get_typed_func::(&mut store, linker::ALLOC)?; let ptr = alloc_packet.call_async(&mut store, packet_len as u32).await?; let memory = msg_connect - .get_memory(&mut store, MEMORY) + .get_memory(&mut store, linker::MEMORY) .expect("Failed to get memory"); memory .write(&mut store, ptr as usize, &packet.1) .expect("Failed to write packet to memory"); let process = msg_connect.get_typed_func::<(i32, i32, Option), i32>(&mut store, PROCESS_PACKET)?; - process + let ret = process .call_async(&mut store, (ptr, packet_len as i32, Some(actor))) .await?; - Ok(()) + match ret { + 0 => Ok(()), + 0xdec0de => { + tracing::error!("Failed to decode packet: {:#?}", packet); + Err(crate::error::Error::InvalidPacket) + }, + 0x00f => { + tracing::error!("Failed to handle packet: {:#?}", packet); + Err(crate::error::Error::InvalidPacket) + }, + code => { + tracing::error!("Unknown error: {:#?}", packet); + Err(crate::error::Error::Other(format!("Unknown error: {}", code))) + }, + } + }, + msg_account::MsgAccount::PACKET_ID => { + let msg_connect = runtime + .linker + .instantiate_async(&mut store, &runtime.packets.msg_account) + .await?; + let alloc_packet = msg_connect.get_typed_func::(&mut store, linker::ALLOC)?; + let ptr = alloc_packet.call_async(&mut store, packet_len as u32).await?; + let memory = msg_connect + .get_memory(&mut store, linker::MEMORY) + .expect("Failed to get memory"); + memory + .write(&mut store, ptr as usize, &packet.1) + .expect("Failed to write packet to memory"); + let process = + msg_connect.get_typed_func::<(i32, i32, Option), i32>(&mut store, PROCESS_PACKET)?; + let ret = process + .call_async(&mut store, (ptr, packet_len as i32, Some(actor))) + .await?; + match ret { + 0 => Ok(()), + 0xdec0de => { + tracing::error!("Failed to decode packet: {:#?}", packet); + Err(crate::error::Error::InvalidPacket) + }, + 0x00f => { + tracing::error!("Failed to handle packet: {:#?}", packet); + Err(crate::error::Error::InvalidPacket) + }, + code => { + tracing::error!("Unknown error: {:#?}", packet); + Err(crate::error::Error::Other(format!("Unknown error: {}", code))) + }, + } }, _ => { tracing::warn!("Unknown packet: {:#?}", packet); @@ -68,17 +116,24 @@ impl PacketHandler for Runtime { /// Add the runtime to the linker. pub fn add_to_linker(linker: &mut Linker) -> Result<(), error::Error> { - linker::network::actor::shutdown(linker)?; - linker::network::actor::send(linker)?; linker::log::trace_event(linker)?; linker::rand::getrandom(linker)?; + + linker::network::actor::shutdown(linker)?; + linker::network::actor::send(linker)?; + linker::network::actor::set_id(linker)?; + linker::db::account::auth(linker)?; linker::db::realm::by_name(linker)?; + + linker::server_bus::check(linker)?; + linker::server_bus::transfer(linker)?; Ok(()) } #[cfg(test)] mod tests { + use msg_account::MsgAccount; use msg_connect::MsgConnect; use tq_network::{Message, PacketEncode}; use wasmtime::Config; @@ -99,9 +154,14 @@ mod tests { let mut linker = Linker::new(&engine); add_to_linker(&mut linker).unwrap(); let msg_connect = Module::from_file(&engine, msg_connect::WASM_BINARY.unwrap()).unwrap(); + let msg_account = Module::from_file(&engine, msg_account::WASM_BINARY.unwrap()).unwrap(); + std::env::set_var("DATABASE_URL", "sqlite::memory:"); let state = State::init().await.unwrap(); - let packets = Packets { msg_connect }; + let packets = Packets { + msg_connect, + msg_account, + }; Runtime { state, @@ -140,7 +200,7 @@ mod tests { } #[tokio::test] - async fn test_msg_connect() { + async fn msg_connect() { setup_logger(3); let (tx, mut rx) = tokio::sync::mpsc::channel(100); let runtime = create_runtime().await; @@ -156,4 +216,23 @@ mod tests { let msg = rx.recv().await.unwrap(); assert_eq!(msg, Message::Shutdown); } + + #[tokio::test] + async fn msg_account() { + setup_logger(3); + let (tx, mut rx) = tokio::sync::mpsc::channel(100); + let runtime = create_runtime().await; + let msg = MsgAccount { + username: String::from("test").into(), + password: String::from("test").into(), + realm: String::from("coemu").into(), + ..Default::default() + }; + let actor = Actor::<()>::new(tx); + + let encoded = ::encode(&msg).unwrap(); + Runtime::handle(encoded.clone(), &runtime, &actor).await.unwrap(); + let msg = rx.recv().await.unwrap(); + assert_eq!(msg, Message::Shutdown); + } } diff --git a/server/auth/src/linker.rs b/server/auth/src/linker.rs index ef845b6..8b06c75 100644 --- a/server/auth/src/linker.rs +++ b/server/auth/src/linker.rs @@ -1,8 +1,16 @@ use wasmtime::Linker; -const MODULE: &str = "host"; -const ALLOC: &str = "__alloc"; -const MEMORY: &str = "memory"; +pub const MODULE: &str = "host"; +pub const ALLOC: &str = "__alloc"; +pub const MEMORY: &str = "memory"; + +pub fn encode_ptr_len(a: *mut u8, b: usize) -> u64 { + (a as u64) << 32 | b as u64 +} + +pub fn decode_ptr_len(c: u64) -> (*mut u8, usize) { + ((c >> 32) as u32 as *mut u8, c as u32 as usize) +} macro_rules! memof { ($caller:expr) => { @@ -82,10 +90,10 @@ pub mod network { pub fn send(linker: &mut Linker) -> Result<(), crate::error::Error> { const NAME: &str = "tq_network_actor_send"; - linker.func_wrap4_async::, i32, i32, i32, ()>( + linker.func_wrap3_async::, u32, u64, ()>( MODULE, NAME, - |mut caller, actor_ref, packet_id, packet_data_ptr, packet_data_len| { + |mut caller, actor_ref, packet_id, packet_data| { Box::new(async move { let actor_ref = actor_ref.expect("actor ref not null"); let actor = actor_ref @@ -93,6 +101,7 @@ pub mod network { .downcast_ref::() .expect("actor ref is valid"); let mem = memof!(caller); + let (packet_data_ptr, packet_data_len) = crate::linker::decode_ptr_len(packet_data); let packet_data = mread!(caller, mem, packet_data_ptr, packet_data_len); let _ = actor.send((packet_id as u16, packet_data)).await; }) as _ @@ -111,9 +120,10 @@ pub mod rand { pub fn getrandom(linker: &mut Linker) -> Result<(), crate::error::Error> { const NAME: &str = "getrandom"; - linker.func_wrap2_async::(MODULE, NAME, |mut caller, ptr, len| { + linker.func_wrap1_async::(MODULE, NAME, |mut caller, buffer| { Box::new(async move { let mem = memof!(caller); + let (ptr, len) = crate::linker::decode_ptr_len(buffer); let slice = mread_mut!(caller, mem, ptr, len); let mut rng = rand::thread_rng(); rng.fill(slice); @@ -160,30 +170,28 @@ pub mod db { pub fn auth(linker: &mut Linker) -> Result<(), crate::error::Error> { const NAME: &str = "tq_db_account_auth"; - linker.func_wrap4_async::( - MODULE, - NAME, - |mut caller, username_ptr, username_len, password_ptr, password_len| { - Box::new(async move { - let mem = memof!(caller); - let username_slice = mread!(caller, mem, username_ptr, username_len); - let username = std::str::from_utf8(username_slice).expect("valid utf8"); - let password_slice = mread!(caller, mem, password_ptr, password_len); - let password = std::str::from_utf8(password_slice).expect("valid utf8"); - let pool = caller.data().pool(); - let account = tq_db::account::Account::auth(pool, username, password).await; - match account { - Ok(account) => account.account_id, - Err(tq_db::Error::AccountNotFound) => -1, - Err(tq_db::Error::InvalidPassword) => -2, - Err(e) => { - tracing::error!("Failed to auth account: {}", e); - -1 - }, - } - }) as _ - }, - )?; + linker.func_wrap2_async::(MODULE, NAME, |mut caller, username, password| { + Box::new(async move { + let mem = memof!(caller); + let (username_ptr, username_len) = crate::linker::decode_ptr_len(username); + let username_slice = mread!(caller, mem, username_ptr, username_len); + let username = std::str::from_utf8(username_slice).expect("valid utf8"); + let (password_ptr, password_len) = crate::linker::decode_ptr_len(password); + let password_slice = mread!(caller, mem, password_ptr, password_len); + let password = std::str::from_utf8(password_slice).expect("valid utf8"); + let pool = caller.data().pool(); + let account = tq_db::account::Account::auth(pool, username, password).await; + match account { + Ok(account) => account.account_id, + Err(tq_db::Error::AccountNotFound) => -1, + Err(tq_db::Error::InvalidPassword) => -2, + Err(e) => { + tracing::error!("Failed to auth account: {}", e); + -1 + }, + } + }) as _ + })?; Ok(()) } } @@ -195,19 +203,20 @@ pub mod db { pub fn by_name(linker: &mut Linker) -> Result<(), crate::error::Error> { const NAME: &str = "tq_db_realm_by_name"; - linker.func_wrap2_async::(MODULE, NAME, |mut caller, name_ptr, name_len| { + linker.func_wrap1_async::(MODULE, NAME, |mut caller, name| { Box::new(async move { let mem = memof!(caller); + let (name_ptr, name_len) = crate::linker::decode_ptr_len(name); let name_slice = mread!(caller, mem, name_ptr, name_len); let name = std::str::from_utf8(name_slice).expect("valid utf8"); let pool = caller.data().pool(); let realm = tq_db::realm::Realm::by_name(pool, name).await; let archived = match realm { Ok(Some(realm)) => rkyv::to_bytes::<_, 64>(&realm).expect("failed to archive realm"), - Ok(None) => return (0, 0), + Ok(None) => return 0, Err(e) => { tracing::error!("Failed to get realm by name: {e}",); - return (-1, -1); + return 0; }, }; let alloc = alloc!(caller); @@ -217,7 +226,7 @@ pub mod db { .expect("failed to allocate memory"); mem.write(&mut caller, ptr as usize, &archived) .expect("failed to write realm to memory"); - (ptr, archived.len() as i32) + crate::linker::encode_ptr_len(ptr as *mut u8, archived.len()) }) as _ })?; Ok(()) @@ -237,9 +246,10 @@ pub mod server_bus { pub fn check(linker: &mut Linker) -> Result<(), crate::error::Error> { const NAME: &str = "auth_server_bus_check"; - linker.func_wrap2_async::(MODULE, NAME, |mut caller, realm_ptr, realm_len| { + linker.func_wrap1_async::(MODULE, NAME, |mut caller, realm| { Box::new(async move { let mem = memof!(caller); + let (realm_ptr, realm_len) = crate::linker::decode_ptr_len(realm); let realm_slice = mread!(caller, mem, realm_ptr, realm_len); let realm = unsafe { rkyv::from_bytes_unchecked::(realm_slice).expect("failed to deserialize realm") @@ -269,71 +279,67 @@ pub mod server_bus { pub fn transfer(linker: &mut Linker) -> Result<(), crate::error::Error> { const NAME: &str = "auth_server_bus_transfer"; - linker.func_wrap3_async::, i32, i32, i64>( - MODULE, - NAME, - |mut caller, actor_ref, realm_ptr, realm_len| { - Box::new(async move { - let actor_ref = actor_ref.expect("actor ref not null"); - let actor = actor_ref - .data() - .downcast_ref::() - .expect("actor ref is valid"); - let mem = memof!(caller); - let realm_slice = mread!(caller, mem, realm_ptr, realm_len); - let realm = unsafe { - rkyv::from_bytes_unchecked::(realm_slice) - .expect("failed to deserialize realm") - }; - let ip = realm.game_ip_address.as_str(); - let port = realm.game_port; - let stream = TcpStream::connect(format!("{ip}:{port}")) - .instrument(tracing::info_span!("realm_connect", %ip, %port, realm_id = realm.realm_id)) - .await; - let tcp_stream = match stream { - Ok(s) => s, - Err(e) => { - tracing::error!( - %ip, - %port, - realm_id = realm.realm_id, - error = ?e, - "Failed to connect to realm" - ); - return -1; - }, - }; - let cipher = CQCipher::new(); - let (mut encoder, mut decoder) = TQCodec::new(tcp_stream, cipher).split(); - let transfer = MsgTransfer { - account_id: actor.id() as _, - realm_id: realm.realm_id as _, - ..Default::default() - }; + linker.func_wrap2_async::, u64, i64>(MODULE, NAME, |mut caller, actor_ref, realm| { + Box::new(async move { + let actor_ref = actor_ref.expect("actor ref not null"); + let actor = actor_ref + .data() + .downcast_ref::() + .expect("actor ref is valid"); + let mem = memof!(caller); + let (realm_ptr, realm_len) = crate::linker::decode_ptr_len(realm); + let realm_slice = mread!(caller, mem, realm_ptr, realm_len); + let realm = unsafe { + rkyv::from_bytes_unchecked::(realm_slice).expect("failed to deserialize realm") + }; + let ip = realm.game_ip_address.as_str(); + let port = realm.game_port; + let stream = TcpStream::connect(format!("{ip}:{port}")) + .instrument(tracing::info_span!("realm_connect", %ip, %port, realm_id = realm.realm_id)) + .await; + let tcp_stream = match stream { + Ok(s) => s, + Err(e) => { + tracing::error!( + %ip, + %port, + realm_id = realm.realm_id, + error = ?e, + "Failed to connect to realm" + ); + return -1; + }, + }; + let cipher = CQCipher::new(); + let (mut encoder, mut decoder) = TQCodec::new(tcp_stream, cipher).split(); + let transfer = MsgTransfer { + account_id: actor.id() as _, + realm_id: realm.realm_id as _, + ..Default::default() + }; - let transfer = transfer.encode().expect("failed to encode transfer"); - encoder.send(transfer).await.expect("failed to send transfer"); - let res = decoder.next().await; - let res = match res { - Some(Ok((MsgTransfer::PACKET_ID, bytes))) => { - MsgTransfer::decode(&bytes).expect("failed to decode transfer") - }, - Some(Ok((id, _))) => { - tracing::error!(packet_id = ?id, "Unexpected packet id"); - return -1; - }, - Some(Err(e)) => { - tracing::error!(error = ?e, "Failed to decode transfer"); - return -1; - }, - None => { - return -1; - }, - }; - res.token as i64 - }) as _ - }, - )?; + let transfer = transfer.encode().expect("failed to encode transfer"); + encoder.send(transfer).await.expect("failed to send transfer"); + let res = decoder.next().await; + let res = match res { + Some(Ok((MsgTransfer::PACKET_ID, bytes))) => { + MsgTransfer::decode(&bytes).expect("failed to decode transfer") + }, + Some(Ok((id, _))) => { + tracing::error!(packet_id = ?id, "Unexpected packet id"); + return -1; + }, + Some(Err(e)) => { + tracing::error!(error = ?e, "Failed to decode transfer"); + return -1; + }, + None => { + return -1; + }, + }; + res.token as i64 + }) as _ + })?; Ok(()) } } From 4de5ad22daf726eaaf4018b311e7b3a7d6cd295f Mon Sep 17 00:00:00 2001 From: Shady Khalifa Date: Mon, 5 Feb 2024 22:24:48 +0200 Subject: [PATCH 27/28] fix rc5 and add tests --- Cargo.lock | 1 + crates/crypto/src/rc5.rs | 193 ++++++++++++++++++++----------- crates/network/src/actor.rs | 1 - crates/serde/src/fixed_string.rs | 8 +- server/auth/Cargo.toml | 4 +- server/auth/src/lib.rs | 22 +++- server/auth/src/linker.rs | 8 +- 7 files changed, 152 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 695061d..a1aeebf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -176,6 +176,7 @@ dependencies = [ "futures", "msg-account", "msg-connect", + "msg-connect-ex", "msg-transfer", "num_enum", "rand", diff --git a/crates/crypto/src/rc5.rs b/crates/crypto/src/rc5.rs index 4390232..2fad153 100644 --- a/crates/crypto/src/rc5.rs +++ b/crates/crypto/src/rc5.rs @@ -19,35 +19,17 @@ //! consists of a number of modular additions and eXclusive OR (XOR)s. The //! general structure of the algorithm is a Feistel-like network. -use bytes::Buf; - -const SUB_KEY_SEED: [u32; 26] = [ - 0xA991_5556, - 0x48E4_4110, - 0x9F32_308F, - 0x27F4_1D3E, - 0xCF4F_3523, - 0xEAC3_C6B4, - 0xE9EA_5E03, - 0xE597_4BBA, - 0x334D_7692, - 0x2C6B_CF2E, - 0x0DC5_3B74, - 0x995C_92A6, - 0x7E4F_6D77, - 0x1EB2_B79F, - 0x1D34_8D89, - 0xED64_1354, - 0x15E0_4A9D, - 0x488D_A159, - 0x6478_17D3, - 0x8CA0_BC20, - 0x9264_F7FE, - 0x91E7_8C6C, - 0x5C9A_07FB, - 0xABD4_DCCE, - 0x6416_F98D, - 0x6642_AB5B, +const PW32: u32 = 0xB7E15163; +const QW32: u32 = 0x61C88647; + +const RC5_12: usize = 12; +const RC5_16: usize = 16; + +const RC5_SUB: usize = RC5_12 * 2 + 2; +const RC5_KEY: usize = RC5_16 / 4; + +const SEED: [u8; RC5_16] = [ + 0x3C, 0xDC, 0xFE, 0xE8, 0xC4, 0x54, 0xD6, 0x7E, 0x16, 0xA6, 0xF8, 0x1A, 0xE8, 0xD0, 0x38, 0xBE, ]; /// Rivest Cipher 5 is implemented for interoperability with the Conquer Online @@ -57,7 +39,7 @@ const SUB_KEY_SEED: [u32; 26] = [ /// exchange protocol). #[derive(Copy, Clone)] pub struct TQRC5 { - rounds: u8, + rounds: usize, sub: [u32; 26], } @@ -67,12 +49,46 @@ impl TQRC5 { /// In later versions of the client, a random buffer is used to seed the /// cipher. This random buffer is sent to the client to establish a /// shared initial key. - pub const fn new() -> Self { - let rounds = 12; - Self { - rounds, - sub: SUB_KEY_SEED, + pub fn new() -> Self { + let mut key = unsafe { core::mem::transmute::<[u8; RC5_16], [u32; RC5_KEY]>(SEED) }; + let mut sub = [0u32; RC5_SUB]; + sub[0] = PW32; + + for i in 1..RC5_SUB { + sub[i] = sub[i - 1].wrapping_sub(QW32); } + + let mut i = 0; + let mut j = 0; + let mut x = 0; + let mut y = 0; + let count = core::cmp::max(RC5_SUB, RC5_KEY) * 3; + + for _ in 0..count { + let value = sub[i].wrapping_add(x).wrapping_add(y); + sub[i] = Self::rotl(value, 3); + x = sub[i]; + i = (i + 1).wrapping_rem(RC5_SUB); + let value = key[j].wrapping_add(x).wrapping_add(y); + let count = x.wrapping_add(y); + key[j] = Self::rotl(value, count); + y = key[j]; + j = (j + 1).wrapping_rem(RC5_KEY); + } + + Self { rounds: RC5_12, sub } + } + + const fn rotl(value: u32, count: u32) -> u32 { + let left_shift = count % 32; + let right_shift = 32 - left_shift; + value.wrapping_shl(left_shift) | value.wrapping_shr(right_shift) + } + + const fn rotr(value: u32, count: u32) -> u32 { + let right_shift = count % 32; + let left_shift = 32 - right_shift; + value.wrapping_shr(right_shift) | value.wrapping_shl(left_shift) } } @@ -91,26 +107,28 @@ impl crate::Cipher for TQRC5 { if data.len() % 8 > 0 { src_len += 1; } - // Decrypt the buffer - for word in 0..src_len { - let mut chunk_a = &data[8 * word..]; - let mut chunk_b = &data[(8 * word + 4)..]; - let mut a = chunk_a.get_u32_le(); - let mut b = chunk_b.get_u32_le(); - let rounds = self.rounds; - let sub = self.sub; - - for round in (1..=rounds).rev() { - b = (b.wrapping_sub(sub[(2 * round + 1) as usize])).rotate_right(a) ^ a; - a = (a.wrapping_sub(sub[(2 * round) as usize])).rotate_right(b) ^ b; + + for k in 0..src_len { + let (lv_bytes, lf, lt) = { + let (from, to) = (8 * k, (8 * k) + 4); + (&data[from..to].try_into().unwrap(), from, to) + }; + let (rv_bytes, rf, rt) = { + let (from, to) = (lt, lt + 4); + (&data[from..to].try_into().unwrap(), from, to) + }; + let mut lv = u32::from_le_bytes(*lv_bytes); + let mut rv = u32::from_le_bytes(*rv_bytes); + + for i in (1..=self.rounds).rev() { + rv = Self::rotr(rv.wrapping_sub(self.sub[2 * i + 1]), lv) ^ lv; + lv = Self::rotr(lv.wrapping_sub(self.sub[2 * i]), rv) ^ rv; } - let chunk_a = &mut data[(8 * word)..]; - let a_bytes = a.wrapping_sub(sub[0]).to_le_bytes(); - chunk_a[..4].copy_from_slice(&a_bytes); - let chunk_b = &mut data[(8 * word + 4)..]; - let b_bytes = b.wrapping_sub(sub[1]).to_le_bytes(); - chunk_b[..4].copy_from_slice(&b_bytes); + lv = lv.wrapping_sub(self.sub[0]); + rv = rv.wrapping_sub(self.sub[1]); + data[lf..lt].copy_from_slice(&lv.to_le_bytes()); + data[rf..rt].copy_from_slice(&rv.to_le_bytes()); } } @@ -120,25 +138,25 @@ impl crate::Cipher for TQRC5 { src_len += 1; } - for word in 0..src_len { - let mut chunk_a = &data[8 * word..]; - let mut chunk_b = &data[(8 * word + 4)..]; - let mut a = chunk_a.get_u32_le(); - let mut b = chunk_b.get_u32_le(); - let rounds = self.rounds; - let sub = self.sub; - - for round in 1..=rounds { - a = a.rotate_left(b) ^ b.wrapping_add(sub[(2 * round) as usize]); - b = b.rotate_left(a) ^ a.wrapping_add(sub[(2 * round + 1) as usize]); + for k in 0..src_len { + let (lv_bytes, lf, lt) = { + let (from, to) = (8 * k, (8 * k) + 4); + (&data[from..to].try_into().unwrap(), from, to) + }; + let (rv_bytes, rf, rt) = { + let (from, to) = (lt, lt + 4); + (&data[from..to].try_into().unwrap(), from, to) + }; + let mut lv = u32::from_le_bytes(*lv_bytes).wrapping_add(self.sub[0]); + let mut rv = u32::from_le_bytes(*rv_bytes).wrapping_add(self.sub[1]); + + for i in 1..=self.rounds { + lv = Self::rotl(lv ^ rv, rv).wrapping_add(self.sub[2 * i]); + rv = Self::rotl(rv ^ lv, lv).wrapping_add(self.sub[2 * i + 1]); } - let chunk_a = &mut data[(8 * word)..]; - let a_bytes = a.wrapping_add(sub[0]).to_le_bytes(); - chunk_a[..4].copy_from_slice(&a_bytes); - let chunk_b = &mut data[(8 * word + 4)..]; - let b_bytes = b.wrapping_add(sub[1]).to_le_bytes(); - chunk_b[..4].copy_from_slice(&b_bytes); + data[lf..lt].copy_from_slice(&lv.to_le_bytes()); + data[rf..rt].copy_from_slice(&rv.to_le_bytes()); } } } @@ -147,6 +165,41 @@ impl crate::Cipher for TQRC5 { mod tests { use super::TQRC5; use crate::Cipher; + #[test] + fn seed() { + const EXPECTED_SUB_KEY_SEED: [u32; 26] = [ + 0xA991_5556, + 0x48E4_4110, + 0x9F32_308F, + 0x27F4_1D3E, + 0xCF4F_3523, + 0xEAC3_C6B4, + 0xE9EA_5E03, + 0xE597_4BBA, + 0x334D_7692, + 0x2C6B_CF2E, + 0x0DC5_3B74, + 0x995C_92A6, + 0x7E4F_6D77, + 0x1EB2_B79F, + 0x1D34_8D89, + 0xED64_1354, + 0x15E0_4A9D, + 0x488D_A159, + 0x6478_17D3, + 0x8CA0_BC20, + 0x9264_F7FE, + 0x91E7_8C6C, + 0x5C9A_07FB, + 0xABD4_DCCE, + 0x6416_F98D, + 0x6642_AB5B, + ]; + + let rc5 = TQRC5::new(); + assert_eq!(rc5.sub, EXPECTED_SUB_KEY_SEED); + } + #[test] fn rc5() { let rc5 = TQRC5::new(); diff --git a/crates/network/src/actor.rs b/crates/network/src/actor.rs index 3ccb89c..3c0d569 100644 --- a/crates/network/src/actor.rs +++ b/crates/network/src/actor.rs @@ -71,7 +71,6 @@ pub trait ActorState: Send + Sync + Sized { fn init() -> Self; /// A good chance to dispose the state and clear anything. #[instrument(skip_all, err)] - #[allow(clippy::blocks_in_conditions)] async fn dispose(&self, handle: ActorHandle) -> Result<(), Error> { tracing::debug!(actor_id = %handle.id(), "Disposing Actor State"); Ok(()) diff --git a/crates/serde/src/fixed_string.rs b/crates/serde/src/fixed_string.rs index 8397eab..d97b348 100644 --- a/crates/serde/src/fixed_string.rs +++ b/crates/serde/src/fixed_string.rs @@ -56,7 +56,7 @@ impl fmt::Debug for FixedString { f.debug_struct("FixedString") .field("inner", &self.inner) .field("max_len", &N) - .field("mode", &"cipher") + .field("mode", &"encrypted") .finish() } } @@ -107,8 +107,10 @@ impl Serialize for FixedString { impl Serialize for FixedString<16, Encrypted> { fn serialize(&self, serializer: S) -> Result { - // FIXME: encrypt password - encode_fixed_string::<16>(&self.inner).serialize(serializer) + let mut final_string = encode_fixed_string::<16>(&self.inner); + let rc5 = TQRC5::new(); + rc5.encrypt(&mut final_string); + final_string.serialize(serializer) } } diff --git a/server/auth/Cargo.toml b/server/auth/Cargo.toml index 06416da..f19e5a5 100644 --- a/server/auth/Cargo.toml +++ b/server/auth/Cargo.toml @@ -65,9 +65,11 @@ features = ["sqlite"] [dev-dependencies] tokio = { workspace = true, features = ["full"] } -sqlx = { workspace = true, features = ["sqlite", "runtime-tokio"] } +sqlx = { workspace = true, features = ["sqlite", "runtime-tokio", "migrate"] } tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "ansi"] } +msg-connect-ex.workspace = true + [features] default = [] server = [ diff --git a/server/auth/src/lib.rs b/server/auth/src/lib.rs index 0233522..fadbbb6 100644 --- a/server/auth/src/lib.rs +++ b/server/auth/src/lib.rs @@ -158,6 +158,12 @@ mod tests { std::env::set_var("DATABASE_URL", "sqlite::memory:"); let state = State::init().await.unwrap(); + + // Run database migrations + sqlx::migrate!("../../migrations") + .run(state.pool()) + .await + .expect("Failed to migrate database"); let packets = Packets { msg_connect, msg_account, @@ -171,7 +177,7 @@ mod tests { } } - fn setup_logger(verbosity: i32) { + fn setup_logger(verbosity: i32) -> tracing::subscriber::DefaultGuard { use tracing::Level; let log_level = match verbosity { 0 => Level::ERROR, @@ -196,12 +202,12 @@ mod tests { .with_target(true) .with_max_level(log_level) .with_env_filter(env_filter); - logger.init(); + tracing::subscriber::set_default(logger.finish()) } #[tokio::test] async fn msg_connect() { - setup_logger(3); + let _guard = setup_logger(3); let (tx, mut rx) = tokio::sync::mpsc::channel(100); let runtime = create_runtime().await; let msg = MsgConnect { @@ -219,7 +225,7 @@ mod tests { #[tokio::test] async fn msg_account() { - setup_logger(3); + let _guard = setup_logger(3); let (tx, mut rx) = tokio::sync::mpsc::channel(100); let runtime = create_runtime().await; let msg = MsgAccount { @@ -230,9 +236,13 @@ mod tests { }; let actor = Actor::<()>::new(tx); - let encoded = ::encode(&msg).unwrap(); + let encoded = msg.encode().unwrap(); Runtime::handle(encoded.clone(), &runtime, &actor).await.unwrap(); + let code = msg_connect_ex::RejectionCode::InvalidPassword; + let expected_msg = msg_connect_ex::MsgConnectEx::from_code(code); + + let encoded = expected_msg.encode().unwrap(); let msg = rx.recv().await.unwrap(); - assert_eq!(msg, Message::Shutdown); + assert_eq!(msg, Message::from(encoded)); } } diff --git a/server/auth/src/linker.rs b/server/auth/src/linker.rs index 8b06c75..651b41a 100644 --- a/server/auth/src/linker.rs +++ b/server/auth/src/linker.rs @@ -4,12 +4,12 @@ pub const MODULE: &str = "host"; pub const ALLOC: &str = "__alloc"; pub const MEMORY: &str = "memory"; -pub fn encode_ptr_len(a: *mut u8, b: usize) -> u64 { +pub fn encode_ptr_len(a: i32, b: usize) -> u64 { (a as u64) << 32 | b as u64 } -pub fn decode_ptr_len(c: u64) -> (*mut u8, usize) { - ((c >> 32) as u32 as *mut u8, c as u32 as usize) +pub fn decode_ptr_len(c: u64) -> (i32, usize) { + ((c >> 32) as u32 as i32, c as u32 as usize) } macro_rules! memof { @@ -226,7 +226,7 @@ pub mod db { .expect("failed to allocate memory"); mem.write(&mut caller, ptr as usize, &archived) .expect("failed to write realm to memory"); - crate::linker::encode_ptr_len(ptr as *mut u8, archived.len()) + crate::linker::encode_ptr_len(ptr, archived.len()) }) as _ })?; Ok(()) From efb8676e6e270b6f984c5177af85e96f7d5e1d33 Mon Sep 17 00:00:00 2001 From: shekohex Date: Fri, 6 Dec 2024 14:57:48 +0200 Subject: [PATCH 28/28] Update crates/crypto/src/rc5.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- crates/crypto/src/rc5.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/crypto/src/rc5.rs b/crates/crypto/src/rc5.rs index 2fad153..648681f 100644 --- a/crates/crypto/src/rc5.rs +++ b/crates/crypto/src/rc5.rs @@ -217,7 +217,7 @@ mod tests { fn encrypt_decrypt() { let rc5 = TQRC5::new(); let mut buf = [0x31; 16]; - let origional = buf; + let original = buf; rc5.encrypt(&mut buf); rc5.decrypt(&mut buf); assert_eq!(buf, origional);