From c3ba5ad5ebe1d5bb28ed0a340af93e8547b1c5bc Mon Sep 17 00:00:00 2001 From: Yigit Sever Date: Wed, 7 Apr 2021 01:08:31 +0300 Subject: Initial commit --- .gitignore | 1 + Cargo.lock | 1277 +++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 19 + README.md | 15 + TODO.md | 10 + rustfmt.toml | 1 + src/custom_filters.rs | 21 + src/handlers.rs | 122 +++++ src/main.rs | 26 + src/routes.rs | 359 ++++++++++++++ src/schema.rs | 223 +++++++++ src/validators.rs | 44 ++ 12 files changed, 2118 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 TODO.md create mode 100644 rustfmt.toml create mode 100644 src/custom_filters.rs create mode 100644 src/handlers.rs create mode 100644 src/main.rs create mode 100644 src/routes.rs create mode 100644 src/schema.rs create mode 100644 src/validators.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..c531d87 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1277 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "buf_redux" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" +dependencies = [ + "memchr", + "safemem", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" + +[[package]] +name = "bytes" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "serde", + "time", + "winapi 0.3.9", +] + +[[package]] +name = "cpuid-bool" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "dtoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" + +[[package]] +name = "env_logger" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "futures" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" + +[[package]] +name = "futures-io" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" + +[[package]] +name = "futures-sink" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3" + +[[package]] +name = "futures-task" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80" + +[[package]] +name = "futures-util" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite 0.2.6", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gradecoin" +version = "0.1.0" +dependencies = [ + "chrono", + "log", + "pretty_env_logger", + "serde", + "serde_json", + "serde_test", + "tokio", + "warp", +] + +[[package]] +name = "h2" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" +dependencies = [ + "bytes 0.5.6", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", + "tracing-futures", +] + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + +[[package]] +name = "headers" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855" +dependencies = [ + "base64 0.13.0", + "bitflags", + "bytes 1.0.1", + "headers-core", + "http", + "mime", + "sha-1", + "time", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" +dependencies = [ + "bytes 1.0.1", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" +dependencies = [ + "bytes 0.5.6", + "http", +] + +[[package]] +name = "httparse" +version = "1.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691" + +[[package]] +name = "httpdate" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] +name = "hyper" +version = "0.13.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a6f157065790a3ed2f88679250419b5cdd96e714a0d65f7797fd337186e96bb" +dependencies = [ + "bytes 0.5.6", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project 1.0.6", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "idna" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "input_buffer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754" +dependencies = [ + "bytes 0.5.6", +] + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "multipart" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050aeedc89243f5347c3e237e3e13dc76fbe4ae3742a57b94dc14f69acf76d4" +dependencies = [ + "buf_redux", + "httparse", + "log", + "mime", + "mime_guess", + "quick-error", + "rand 0.7.3", + "safemem", + "tempfile", + "twoway", +] + +[[package]] +name = "net2" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918192b5c59119d51e0cd221f4d49dde9112824ba717369e903c97d076083d0f" +dependencies = [ + "pin-project-internal 0.4.28", +] + +[[package]] +name = "pin-project" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc174859768806e91ae575187ada95c91a29e96a98dc5d2cd9a1fed039501ba6" +dependencies = [ + "pin-project-internal 1.0.6", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be26700300be6d9d23264c73211d8190e755b6b5ca7a1b28230025511b52a5e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a490329918e856ed1b083f244e3bfe2d8c4f336407e4ea9e1a9f479ff09049e5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" + +[[package]] +name = "pin-project-lite" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "pretty_env_logger" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "717ee476b1690853d222af4634056d830b5197ffd747726a9a1eee6da9f49074" +dependencies = [ + "chrono", + "env_logger", + "log", +] + +[[package]] +name = "proc-macro2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha 0.3.0", + "rand_core 0.6.2", + "rand_hc 0.3.0", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +dependencies = [ + "getrandom 0.2.2", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core 0.6.2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "serde" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_test" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4bb5fef7eaf5a97917567183607ac4224c5b451c15023930f23b937cce879fe" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" +dependencies = [ + "dtoa", + "itoa", + "serde", + "url", +] + +[[package]] +name = "sha-1" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" +dependencies = [ + "block-buffer", + "cfg-if 1.0.0", + "cpuid-bool", + "digest", + "opaque-debug", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "syn" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "rand 0.8.3", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.9", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi 0.3.9", +] + +[[package]] +name = "tinyvec" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" +dependencies = [ + "bytes 0.5.6", + "fnv", + "futures-core", + "iovec", + "lazy_static", + "memchr", + "mio", + "pin-project-lite 0.1.12", + "slab", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9e878ad426ca286e4dcae09cbd4e1973a7f8987d97570e2469703dd7f5720c" +dependencies = [ + "futures-util", + "log", + "pin-project 0.4.28", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" +dependencies = [ + "bytes 0.5.6", + "futures-core", + "futures-sink", + "log", + "pin-project-lite 0.1.12", + "tokio", +] + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" +dependencies = [ + "cfg-if 1.0.0", + "log", + "pin-project-lite 0.2.6", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project 1.0.6", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "tungstenite" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0308d80d86700c5878b9ef6321f020f29b1bb9d5ff3cab25e75e23f3a492a23" +dependencies = [ + "base64 0.12.3", + "byteorder", + "bytes 0.5.6", + "http", + "httparse", + "input_buffer", + "log", + "rand 0.7.3", + "sha-1", + "url", + "utf-8", +] + +[[package]] +name = "twoway" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" +dependencies = [ + "memchr", +] + +[[package]] +name = "typenum" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" +dependencies = [ + "matches", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "url" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "urlencoding" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9232eb53352b4442e40d7900465dfc534e8cb2dc8f18656fcb2ac16112b5593" + +[[package]] +name = "utf-8" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "warp" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f41be6df54c97904af01aa23e613d4521eed7ab23537cede692d4058f6449407" +dependencies = [ + "bytes 0.5.6", + "futures", + "headers", + "http", + "hyper", + "log", + "mime", + "mime_guess", + "multipart", + "pin-project 0.4.28", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-tungstenite", + "tower-service", + "tracing", + "tracing-futures", + "urlencoding", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3f9c00d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "gradecoin" +version = "0.1.0" +authors = ["Yigit Sever "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +warp = "0.2.0" +tokio = { version = "0.2.9", features = ["macros"] } +serde = { version = "1.0.104", features = ["derive"] } +chrono = { version = "0.4.10", features = ["serde"] } +log = "0.4.8" +pretty_env_logger = "0.3.1" + +[dev-dependencies] +serde_json = "1.0.44" +serde_test = "1.0.104" diff --git a/README.md b/README.md new file mode 100644 index 0000000..fcfda11 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Gradecoin + +This will sit behind nginx reverse proxy so running at 127.0.0.1:8080 is no problem, or https. + +``` +$ cargo run + +$ curl --location --request POST 'localhost:8080/transaction' --header 'Content-Type: application/json' --data-raw '{ + "source": "Myself Truly", + "target": "Literally Anybody Else", + "amount": 12, + "timestamp": "2021-04-07T00:17:00" +}' +``` + diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..76292d2 --- /dev/null +++ b/TODO.md @@ -0,0 +1,10 @@ +# TODO +## Proof-of-work +- [ ] pick a block proposal scheme (= pick hash function) [list of hash functions](https://en.bitcoinwiki.org/wiki/List_of_hash_functions) +- [ ] check the nonce for incoming blocks + +## Authentication +- [ ] pick a user authentication scheme + - [ ] implement it + +- [ ] Switch to RwLock (parking_lot) diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..1a076d8 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +edition="2018" diff --git a/src/custom_filters.rs b/src/custom_filters.rs new file mode 100644 index 0000000..86a78d4 --- /dev/null +++ b/src/custom_filters.rs @@ -0,0 +1,21 @@ +// Common filters ment to be shared between many endpoints + +use std::convert::Infallible; +use warp::{Filter, Rejection}; + +use crate::schema::{Db, Transaction}; // `Block` coming later + +// Database context for routes +pub fn with_db(db: Db) -> impl Filter + Clone { + warp::any().map(move || db.clone()) +} + +// Optional query params to allow pagination +// pub fn list_options() -> impl Filter + Clone { +// warp::query::() +// } + +// Accept only JSON body and reject big payloads +pub fn json_body() -> impl Filter + Clone { + warp::body::content_length_limit(1024 * 32).and(warp::body::json()) +} diff --git a/src/handlers.rs b/src/handlers.rs new file mode 100644 index 0000000..51c7b63 --- /dev/null +++ b/src/handlers.rs @@ -0,0 +1,122 @@ +// API handlers, the ends of each filter chain + +use log::debug; +use std::convert::Infallible; +use warp::{http::StatusCode, reply}; + +use crate::schema::{Db, Transaction}; // `Block` coming later + +// PROPOSE Transaction +// POST /transaction +pub async fn propose_transaction( + new_transaction: Transaction, + db: Db, +) -> Result { + debug!("new transaction request {:?}", new_transaction); + + let mut transactions = db.lock().await; + + transactions.push(new_transaction); + + Ok(StatusCode::CREATED) +} + +// GET Transaction List +// GET /transaction +// Returns JSON array of transactions +// Cannot fail? +pub async fn list_transactions(db: Db) -> Result { + debug!("list all transactions"); + + let transactions = db.lock().await; + + let transactions: Vec = transactions.clone().into_iter().collect(); + + Ok(reply::with_status( + reply::json(&transactions), + StatusCode::OK, + )) +} + +// PROPOSE Block +// POST /block + +// `GET /games` +// Returns JSON array of todos +// Allows pagination, for example: `GET /games?offset=10&limit=5` +// pub async fn list_games(options: ListOptions, db: Db) -> Result { +// debug!("list all games"); + +// let games = db.lock().await; +// let games: Vec = games +// .clone() +// .into_iter() +// .skip(options.offset.unwrap_or(0)) +// .take(options.limit.unwrap_or(std::usize::MAX)) +// .collect(); + +// Ok(warp::reply::json(&games)) +// } + +// `POST /games` +// Create new game entry with JSON body +// pub async fn create_game(new_game: Game, db: Db) -> Result { +// debug!("create new game: {:?}", new_game); + +// let mut games = db.lock().await; + +// match games.iter().find(|game| game.id == new_game.id) { +// Some(game) => { +// debug!("game of given id already exists: {}", game.id); + +// Ok(StatusCode::BAD_REQUEST) +// } +// None => { +// games.push(new_game); +// Ok(StatusCode::CREATED) +// } +// } +// } + +// `PUT /games/:id` +// pub async fn update_game(id: u64, updated_game: Game, db: Db) -> Result { +// debug!("update existing game: id={}, game={:?}", id, updated_game); + +// let mut games = db.lock().await; + +// match games.iter_mut().find(|game| game.id == id) { +// Some(game) => { +// *game = updated_game; + +// Ok(StatusCode::OK) +// } +// None => { +// debug!("game of given id not found"); + +// Ok(StatusCode::NOT_FOUND) +// } +// } +// } + +// `DELETE /games/:id` +// pub async fn delete_game(id: u64, db: Db) -> Result { +// debug!("delete game: id={}", id); + +// let mut games = db.lock().await; + +// let len = games.len(); + +// // Removes all games with given id +// games.retain(|game| game.id != id); + +// // If games length was smaller that means specyfic game was found and removed +// let deleted = games.len() != len; + +// if deleted { +// Ok(StatusCode::NO_CONTENT) +// } else { +// debug!("game of given id not found"); + +// Ok(StatusCode::NOT_FOUND) +// } +// } diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..bcd4173 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,26 @@ +use std::env; +use warp::Filter; + +mod custom_filters; +mod handlers; +mod routes; +mod schema; +// mod validators; + +#[tokio::main] +async fn main() { + // Show debug logs by default by setting `RUST_LOG=restful_rust=debug` + if env::var_os("RUST_LOG").is_none() { + env::set_var("RUST_LOG", "restful_rust=debug"); + } + pretty_env_logger::init(); + + let db = schema::ledger(); // 1. we need this to return a _simple_ db + + let api = routes::consensus_routes(db); + + let routes = api.with(warp::log("restful_rust")); + + // Start the server + warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; +} diff --git a/src/routes.rs b/src/routes.rs new file mode 100644 index 0000000..fc4426a --- /dev/null +++ b/src/routes.rs @@ -0,0 +1,359 @@ +use warp::{Filter, Rejection, Reply}; + +use crate::custom_filters; +use crate::handlers; +use crate::schema::Db; + +// Root, all routes combined +pub fn consensus_routes(db: Db) -> impl Filter + Clone { + transaction_list(db.clone()).or(transaction_propose(db.clone())) +} + +// GET /transaction +pub fn transaction_list(db: Db) -> impl Filter + Clone { + warp::path!("transaction") + .and(warp::get()) + .and(custom_filters::with_db(db)) + .and_then(handlers::list_transactions) +} + +// POST /transaction +pub fn transaction_propose(db: Db) -> impl Filter + Clone { + warp::path!("transaction") + .and(warp::post()) + .and(custom_filters::json_body()) + .and(custom_filters::with_db(db)) + .and_then(handlers::propose_transaction) +} + +/////////////////////////// +// below are not mine. // +/////////////////////////// + +// Root, all routes combined +//pub fn games_routes(db: Db) -> impl Filter + Clone { +// games_list(db.clone()) +// .or(games_create(db.clone())) +// .or(games_update(db.clone())) +// .or(games_delete(db)) +//} + +//// `GET /games?offset=3&limit=5` +//pub fn games_list(db: Db) -> impl Filter + Clone { +// warp::path!("games") +// .and(warp::get()) +// .and(custom_filters::list_options()) +// .and(custom_filters::with_db(db)) +// .and_then(handlers::list_games) +//} + +//// `POST /games` +//pub fn games_create(db: Db) -> impl Filter + Clone { +// warp::path!("games") +// .and(warp::post()) +// .and(custom_filters::json_body()) +// .and(custom_filters::with_db(db)) +// .and_then(handlers::create_game) +//} + +//// `PUT /games/:id` +//pub fn games_update(db: Db) -> impl Filter + Clone { +// warp::path!("games" / u64) +// .and(warp::put()) +// .and(custom_filters::json_body()) +// .and(custom_filters::with_db(db)) +// .and_then(handlers::update_game) +//} + +//// `DELETE /games/:id` +//pub fn games_delete(db: Db) -> impl Filter + Clone { +// warp::path!("games" / u64) +// .and(warp::delete()) +// .and(custom_filters::with_db(db)) +// .and_then(handlers::delete_game) +//} + +//////////////////////////////// +//// tests below, it's fine // +//////////////////////////////// + +///////////////////////////////////// +// of course I'll write tests... // +///////////////////////////////////// + +// TODO: write tests <07-04-21, yigit> // + +//#[cfg(test)] +//mod tests { +// use super::*; + +// use chrono::prelude::*; +// use std::sync::Arc; +// use tokio::sync::Mutex; +// use warp::http::StatusCode; + +// use crate::schema::{Game, Genre}; + +// // Mocked dataset for each test + +// fn mocked_db() -> Db { +// Arc::new(Mutex::new(vec![ +// Game { +// id: 1, +// title: String::from("Crappy title"), +// rating: 35, +// genre: Genre::RolePlaying, +// description: Some(String::from("Test description...")), +// release_date: NaiveDate::from_ymd(2011, 9, 22).and_hms(0, 0, 0), +// }, +// Game { +// id: 2, +// title: String::from("Decent game"), +// rating: 84, +// genre: Genre::Strategy, +// description: None, +// release_date: NaiveDate::from_ymd(2014, 3, 11).and_hms(0, 0, 0), +// }, +// ])) +// } + +// fn mocked_game() -> Game { +// Game { +// id: 3, +// title: String::from("Another game"), +// rating: 65, +// description: None, +// genre: Genre::Strategy, +// release_date: NaiveDate::from_ymd(2016, 3, 11).and_hms(0, 0, 0), +// } +// } + +// #[tokio::test] +// async fn get_list_of_games_200() { +// let db = mocked_db(); +// let filter = games_routes(db); + +// let res = warp::test::request().method("GET").path("/games").reply(&filter).await; + +// assert_eq!(res.status(), StatusCode::OK); + +// let expected_json_body = r#"[{"id":1,"title":"Crappy title","rating":35,"genre":"ROLE_PLAYING","description":"Test description...","releaseDate":"2011-09-22T00:00:00"},{"id":2,"title":"Decent game","rating":84,"genre":"STRATEGY","description":null,"releaseDate":"2014-03-11T00:00:00"}]"#; +// assert_eq!(res.body(), expected_json_body); +// } + +// #[tokio::test] +// async fn get_list_of_games_with_options_200() { +// let db = mocked_db(); +// let filter = games_routes(db); + +// let res = warp::test::request() +// .method("GET") +// .path("/games?offset=1&limit=5") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::OK); + +// let expected_json_body = r#"[{"id":2,"title":"Decent game","rating":84,"genre":"STRATEGY","description":null,"releaseDate":"2014-03-11T00:00:00"}]"#; +// assert_eq!(res.body(), expected_json_body); +// } + +// #[tokio::test] +// async fn get_empty_list_with_offset_overshot_200() { +// let db = mocked_db(); +// let filter = games_routes(db); + +// let res = warp::test::request() +// .method("GET") +// .path("/games?offset=5&limit=5") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::OK); + +// let expected_json_body = r#"[]"#; +// assert_eq!(res.body(), expected_json_body); +// } + +// #[tokio::test] +// async fn get_incorrect_options_400() { +// let db = mocked_db(); +// let filter = games_routes(db); + +// let res = warp::test::request() +// .method("GET") +// .path("/games?offset=a&limit=b") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::BAD_REQUEST); +// } + +// #[tokio::test] +// async fn get_wrong_path_405() { +// let db = mocked_db(); +// let filter = games_routes(db); + +// let res = warp::test::request() +// .method("GET") +// .path("/games/42") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED); +// } + +// #[tokio::test] +// async fn post_json_201() { +// let db = mocked_db(); +// let filter = games_routes(db.clone()); + +// let res = warp::test::request() +// .method("POST") +// .json(&mocked_game()) +// .path("/games") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::CREATED); +// assert_eq!(db.lock().await.len(), 3); +// } + +// #[tokio::test] +// async fn post_too_long_content_413() { +// let db = mocked_db(); +// let filter = games_routes(db); + +// let res = warp::test::request() +// .method("POST") +// .header("content-length", 1024 * 36) +// .path("/games") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE); +// } + +// #[tokio::test] +// async fn post_wrong_payload_400() { +// let db = mocked_db(); +// let filter = games_routes(db); + +// let res = warp::test::request() +// .method("POST") +// .body(&r#"{"id":4}"#) +// .path("/games") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::BAD_REQUEST); +// } + +// #[tokio::test] +// async fn post_wrong_path_405() { +// let db = mocked_db(); +// let filter = games_routes(db); + +// let res = warp::test::request() +// .method("POST") +// .path("/games/42") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED); +// } + +// #[tokio::test] +// async fn put_json_200() { +// let db = mocked_db(); +// let filter = games_routes(db.clone()); + +// let res = warp::test::request() +// .method("PUT") +// .json(&mocked_game()) +// .path("/games/2") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::OK); + +// let db = db.lock().await; +// let ref title = db[1].title; +// assert_eq!(title, "Another game"); +// } + +// #[tokio::test] +// async fn put_wrong_id_404() { +// let db = mocked_db(); +// let filter = games_routes(db); + +// let res = warp::test::request() +// .method("PUT") +// .json(&mocked_game()) +// .path("/games/42") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::NOT_FOUND); +// } + +// #[tokio::test] +// async fn put_wrong_payload_400() { +// let db = mocked_db(); +// let filter = games_routes(db); + +// let res = warp::test::request() +// .method("PUT") +// .header("content-length", 1024 * 16) +// .body(&r#"{"id":2"#) +// .path("/games/2") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::BAD_REQUEST); +// } + +// #[tokio::test] +// async fn put_too_long_content_413() { +// let db = mocked_db(); +// let filter = games_routes(db); + +// let res = warp::test::request() +// .method("PUT") +// .header("content-length", 1024 * 36) +// .path("/games/2") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE); +// } + +// #[tokio::test] +// async fn delete_wrong_id_404() { +// let db = mocked_db(); +// let filter = games_routes(db); + +// let res = warp::test::request() +// .method("DELETE") +// .path("/games/42") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::NOT_FOUND); +// } + +// #[tokio::test] +// async fn delete_game_204() { +// let db = mocked_db(); +// let filter = games_routes(db.clone()); + +// let res = warp::test::request() +// .method("DELETE") +// .path("/games/1") +// .reply(&filter) +// .await; + +// assert_eq!(res.status(), StatusCode::NO_CONTENT); +// assert_eq!(db.lock().await.len(), 1); +// } +//} diff --git a/src/schema.rs b/src/schema.rs new file mode 100644 index 0000000..ea36a70 --- /dev/null +++ b/src/schema.rs @@ -0,0 +1,223 @@ +// Common types used across API + +use chrono::{NaiveDate, NaiveDateTime}; +use serde::{Deserialize, Serialize}; +use std::sync::Arc; +use tokio::sync::Mutex; + +// use crate::validators; + +pub fn ledger() -> Db { + // TODO: there was something simpler in one of the other tutorials? <07-04-21, yigit> // + + Arc::new(Mutex::new(vec![ + Transaction { + source: String::from("Myself"), + target: String::from("Nobody"), + amount: 4, + timestamp: NaiveDate::from_ymd(2021, 4, 7).and_hms(00, 17, 00), + }, + ])) +} + + +// For presentation purposes keep mocked data in in-memory structure +// In real life scenario connection with regular database would be established + +pub type Db = Arc>>; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct Transaction { + pub source: String, + pub target: String, + pub amount: i32, + pub timestamp: NaiveDateTime, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct Block { + pub transaction_list: Vec, // [Transaction; N] + pub nonce: i32, + pub timestamp: NaiveDateTime, + pub hash: String, // future proof'd baby +} + +// #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +// #[serde(rename_all = "camelCase")] +// pub struct Game { +// pub id: u64, +// pub title: String, +// #[serde(with = "validators::validate_game_rating")] +// pub rating: u8, +// pub genre: Genre, +// pub description: Option, +// pub release_date: NaiveDateTime, +// } + +// #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +// #[serde(rename_all = "SCREAMING_SNAKE_CASE")] +// pub enum Genre { +// RolePlaying, +// Strategy, +// Shooter, +// } + +// #[derive(Deserialize, Debug, PartialEq)] +// pub struct ListOptions { +// pub offset: Option, +// pub limit: Option, +// } + +// pub fn example_db() -> Db { +// Arc::new(Mutex::new( +// vec![ +// Game { +// id: 1, +// title: String::from("Dark Souls"), +// rating: 91, +// genre: Genre::RolePlaying, +// description: Some(String::from("Takes place in the fictional kingdom of Lordran, where players assume the role of a cursed undead character who begins a pilgrimage to discover the fate of their kind.")), +// release_date: NaiveDate::from_ymd(2011, 9, 22).and_hms(0, 0, 0), +// }, +// Game { +// id: 2, +// title: String::from("Dark Souls 2"), +// rating: 87, +// genre: Genre::RolePlaying, +// description: None, +// release_date: NaiveDate::from_ymd(2014, 3, 11).and_hms(0, 0, 0), +// }, +// Game { +// id: 3, +// title: String::from("Dark Souls 3"), +// rating: 89, +// genre: Genre::RolePlaying, +// description: Some(String::from("The latest chapter in the series with its trademark sword and sorcery combat and rewarding action RPG gameplay.")), +// release_date: NaiveDate::from_ymd(2016, 3, 24).and_hms(0, 0, 0), +// }, +// ] +// )) +// } + +// #[cfg(test)] +// mod tests { +// use super::*; + +// use serde_json::error::Error; +// use serde_test::{assert_tokens, Token}; + +// #[test] +// fn game_serialize_correctly() { +// let game = Game { +// id: 1, +// title: String::from("Test"), +// rating: 90, +// genre: Genre::Shooter, +// description: None, +// release_date: NaiveDate::from_ymd(2019, 11, 12).and_hms(0, 0, 0), +// }; + +// assert_tokens( +// &game, +// &[ +// Token::Struct { +// name: "Game", +// len: 6, +// }, +// Token::String("id"), +// Token::U64(1), +// Token::String("title"), +// Token::String("Test"), +// Token::String("rating"), +// Token::U8(90), +// Token::String("genre"), +// Token::UnitVariant { +// name: "Genre", +// variant: "SHOOTER", +// }, +// Token::String("description"), +// Token::None, +// Token::String("releaseDate"), +// Token::String("2019-11-12T00:00:00"), +// Token::StructEnd, +// ], +// ); +// } + +// #[test] +// fn game_deserialize_correctly() { +// let data = r#"{"id":3,"title":"Another game","rating":65,"genre":"STRATEGY","description":null,"releaseDate":"2016-03-11T00:00:00"}"#; +// let game: Game = serde_json::from_str(data).unwrap(); +// let expected_game = Game { +// id: 3, +// title: String::from("Another game"), +// rating: 65, +// genre: Genre::Strategy, +// description: None, +// release_date: NaiveDate::from_ymd(2016, 3, 11).and_hms(0, 0, 0), +// }; + +// assert_eq!(game, expected_game); +// } + +// #[test] +// fn game_error_when_wrong_rating_passed() { +// let data = r#"{"id":3,"title":"Another game","rating":120,"genre":"STRATEGY","description":null,"releaseDate":"2016-03-11T00:00:00"}"#; +// let err: Error = serde_json::from_str::(data).unwrap_err(); + +// assert_eq!(err.is_data(), true); +// } + +// #[test] +// fn genre_serialize_correctly() { +// let genre = Genre::Shooter; +// assert_tokens( +// &genre, +// &[Token::UnitVariant { +// name: "Genre", +// variant: "SHOOTER", +// }], +// ); + +// let genre = Genre::RolePlaying; +// assert_tokens( +// &genre, +// &[Token::UnitVariant { +// name: "Genre", +// variant: "ROLE_PLAYING", +// }], +// ); + +// let genre = Genre::Strategy; +// assert_tokens( +// &genre, +// &[Token::UnitVariant { +// name: "Genre", +// variant: "STRATEGY", +// }], +// ); +// } + +// #[test] +// fn genre_deserialize_correctly() { +// let data = r#""SHOOTER""#; +// let genre: Genre = serde_json::from_str(data).unwrap(); +// let expected_genre = Genre::Shooter; + +// assert_eq!(genre, expected_genre); + +// let data = r#""ROLE_PLAYING""#; +// let genre: Genre = serde_json::from_str(data).unwrap(); +// let expected_genre = Genre::RolePlaying; + +// assert_eq!(genre, expected_genre); +// } + +// #[test] +// fn genre_error_when_wrong_rating_passed() { +// let data = r#""SPORT""#; +// let err: Error = serde_json::from_str::(data).unwrap_err(); + +// assert_eq!(err.is_data(), true); +// } +// } diff --git a/src/validators.rs b/src/validators.rs new file mode 100644 index 0000000..dbebee8 --- /dev/null +++ b/src/validators.rs @@ -0,0 +1,44 @@ +// Custom validators incoming data + +use log::error; +use serde::de::{Deserializer, Error as DeserializerError, Unexpected}; +use serde::ser::{Error as SerializerError, Serializer}; +use serde::Deserialize; + +pub mod validate_game_rating { + use super::*; + + const ERROR_MESSAGE: &str = "rating must be a number between 0 and 100"; + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value = u8::deserialize(deserializer)?; + + if value > 100 { + error!("{}", ERROR_MESSAGE); + + return Err(DeserializerError::invalid_value( + Unexpected::Unsigned(u64::from(value)), + &ERROR_MESSAGE, + )); + } + + Ok(value) + } + + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn serialize(value: &u8, serializer: S) -> Result + where + S: Serializer, + { + if *value > 100 { + error!("{}", ERROR_MESSAGE); + + return Err(SerializerError::custom(ERROR_MESSAGE)); + } + + serializer.serialize_u8(*value) + } +} -- cgit v1.2.3-70-g09d2