hi
This commit is contained in:
commit
cbb92993b5
15 changed files with 1075 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
554
Cargo.lock
generated
Normal file
554
Cargo.lock
generated
Normal file
|
@ -0,0 +1,554 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[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 = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[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.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"time",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
|
||||
[[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 = "js-sys"
|
||||
version = "0.3.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
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",
|
||||
"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",
|
||||
"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"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[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-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[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 = "windows"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
|
||||
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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "bashhttp"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.29", features = ["full"] }
|
||||
chrono = "0.4.26"
|
13
LICENSE
Normal file
13
LICENSE
Normal file
|
@ -0,0 +1,13 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2023 Tyler Murphy <tylerm@tylerm.dev>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
25
README
Normal file
25
README
Normal file
|
@ -0,0 +1,25 @@
|
|||
# bashttp
|
||||
|
||||
A very goofy http server that runs scripts based of the given URI route
|
||||
|
||||
## Config
|
||||
|
||||
All routs and scripts must be layed out in a file called config, or you can specift the path by setting the `CONFIG_PATH` env variable.
|
||||
|
||||
An example config is shown below
|
||||
```
|
||||
/ ./hello_world
|
||||
/neo /usr/bin/neofetch
|
||||
/joe ./bide
|
||||
```
|
||||
As shown above, each route to script is a single line seperated by a single space.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [WTFPL](https://www.wtfpl.net/)
|
||||
|
||||
## Warrenty
|
||||
|
||||
This project is probably not secure and if it beaks, uh... have fun
|
||||
|
||||
...wtfpl
|
1
config.example
Normal file
1
config.example
Normal file
|
@ -0,0 +1 @@
|
|||
/ /usr/bin/neofetch
|
41
src/bash.rs
Normal file
41
src/bash.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use std::{env, collections::HashMap, fs::read_to_string, process::{exit, Command}};
|
||||
|
||||
pub fn load_config() -> HashMap<String, String> {
|
||||
|
||||
let config_path = env::var("CONFIG_PATH").unwrap_or_else(|_| String::from("config"));
|
||||
let config = match read_to_string(&config_path) {
|
||||
Ok(data) => data,
|
||||
Err(err) => {
|
||||
eprintln!("cannot load '{config_path}': {err}");
|
||||
exit(1);
|
||||
},
|
||||
};
|
||||
|
||||
let mut map = HashMap::new();
|
||||
let lines = config.split("\n").into_iter();
|
||||
|
||||
for line in lines {
|
||||
let mut parts = line.trim().split(" ");
|
||||
let Some(route) = parts.next() else { continue };
|
||||
let Some(script) = parts.next() else { continue };
|
||||
|
||||
println!("adding entry {route} => {script}");
|
||||
map.insert(route.to_owned(), script.to_owned());
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
pub fn handle_script(script: &str, body: Option<&String>) -> Result<String, String> {
|
||||
let mut command = Command::new(script);
|
||||
if let Some(body) = body {
|
||||
command.args([body]);
|
||||
}
|
||||
|
||||
let output = match command.output() {
|
||||
Ok(o) => o,
|
||||
Err(err) => return Err(format!("{err}")),
|
||||
};
|
||||
|
||||
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
|
||||
}
|
8
src/http/code.rs
Normal file
8
src/http/code.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub enum Code {
|
||||
Success = 200,
|
||||
MethodNotAllowed = 405,
|
||||
TooManyRequests = 429,
|
||||
InternalServerError = 500,
|
||||
}
|
96
src/http/header.rs
Normal file
96
src/http/header.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
use std::{collections::HashMap, str::Split};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HeaderMap {
|
||||
map: HashMap<String, usize>,
|
||||
headers: Vec<Header>
|
||||
}
|
||||
|
||||
impl HeaderMap {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get(&self, key: &str) -> Option<&Header> {
|
||||
let Some(index) = self.map.get(key) else {
|
||||
return None;
|
||||
};
|
||||
return Some(&self.headers[index.to_owned()]);
|
||||
}
|
||||
|
||||
pub fn put(&mut self, header: Header) {
|
||||
if let Some(index) = self.map.get(&header.key) {
|
||||
self.headers[index.to_owned()] = header;
|
||||
return
|
||||
}
|
||||
|
||||
let index = self.headers.len();
|
||||
self.map.insert(header.key.clone(), index);
|
||||
self.headers.push(header);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn del(&mut self, key: &str) -> Option<Header> {
|
||||
let Some(index) = self.map.get(key) else {
|
||||
return None
|
||||
};
|
||||
|
||||
let removed = self.headers.remove(index.to_owned());
|
||||
for i in (index.to_owned())..self.headers.len() {
|
||||
let key = &self.headers[i].key;
|
||||
|
||||
let Some(index) = self.map.get(key) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
self.map.insert(key.clone(), index - 1);
|
||||
}
|
||||
|
||||
Some(removed)
|
||||
}
|
||||
|
||||
pub fn deserialize(&self) -> String {
|
||||
let mut string = String::new();
|
||||
|
||||
for header in &self.headers {
|
||||
string += &format!("{}: {}\n", header.key, header.value);
|
||||
}
|
||||
|
||||
string
|
||||
}
|
||||
|
||||
pub fn serialize(lines: &mut Split<char>) -> Self {
|
||||
|
||||
let mut headers = Self::new();
|
||||
|
||||
loop {
|
||||
let Some(header) = lines.next() else { break };
|
||||
if header.trim().len() < 1 { break }
|
||||
|
||||
let mut parts = header.split(": ").into_iter();
|
||||
let Some(key) = parts.next() else { continue };
|
||||
let Some(value) = parts.next() else { continue };
|
||||
|
||||
headers.put(Header::new(key.trim(), value.trim()));
|
||||
}
|
||||
|
||||
headers
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
map: HashMap::new(),
|
||||
headers: Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Header {
|
||||
pub key: String,
|
||||
pub value: String
|
||||
}
|
||||
|
||||
impl Header {
|
||||
pub fn new(key: &str, value: &str) -> Self {
|
||||
return Self {key: key.to_owned(), value: value.to_owned()}
|
||||
}
|
||||
}
|
30
src/http/method.rs
Normal file
30
src/http/method.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum Method {
|
||||
Get,
|
||||
Head,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Connect,
|
||||
Options,
|
||||
Trace,
|
||||
Patch
|
||||
}
|
||||
|
||||
impl Method {
|
||||
pub fn serialize(string: &str) -> Option<Self> {
|
||||
match string {
|
||||
"GET" => Some(Self::Get),
|
||||
"HEAD" => Some(Self::Head),
|
||||
"POST" => Some(Self::Post),
|
||||
"PUT" => Some(Self::Put),
|
||||
"DELETE" => Some(Self::Delete),
|
||||
"CONNECT" => Some(Self::Connect),
|
||||
"OPTIONS" => Some(Self::Options),
|
||||
"TRACE" => Some(Self::Trace),
|
||||
"PATCH" => Some(Self::Patch),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
6
src/http/mod.rs
Normal file
6
src/http/mod.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
pub mod code;
|
||||
pub mod method;
|
||||
pub mod uri;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
pub mod header;
|
52
src/http/request.rs
Normal file
52
src/http/request.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use super::{method::Method, uri::URI, header::HeaderMap};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Request {
|
||||
pub method: Method,
|
||||
pub uri: URI,
|
||||
pub headers: HeaderMap,
|
||||
pub body: Option<String>
|
||||
}
|
||||
|
||||
impl Request {
|
||||
pub fn serialize(req: &str) -> Option<Self> {
|
||||
let mut lines = req.split('\n').to_owned();
|
||||
|
||||
let Some(head) = lines.next() else {
|
||||
eprintln!("missing head str");
|
||||
return None
|
||||
};
|
||||
|
||||
let mut parts = head.trim().split(" ");
|
||||
|
||||
let Some(method_str) = parts.next() else {
|
||||
eprintln!("missing method str");
|
||||
return None
|
||||
};
|
||||
|
||||
let Some(method) = Method::serialize(method_str.trim()) else {
|
||||
eprintln!("invalid http method");
|
||||
return None
|
||||
};
|
||||
|
||||
let Some(uri_str) = parts.next() else {
|
||||
eprintln!("missing uri str");
|
||||
return None
|
||||
};
|
||||
|
||||
let Some(uri) = URI::serialize(uri_str.trim()) else {
|
||||
eprintln!("invalid http uri");
|
||||
return None
|
||||
};
|
||||
|
||||
let headers = HeaderMap::serialize(&mut lines);
|
||||
let body: String = lines.collect();
|
||||
|
||||
Some(Self {
|
||||
method,
|
||||
uri,
|
||||
headers,
|
||||
body: if body.len() > 0 { Some(body) } else { None },
|
||||
})
|
||||
}
|
||||
}
|
42
src/http/response.rs
Normal file
42
src/http/response.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use super::{code::Code, header::{HeaderMap, Header}};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Response {
|
||||
pub status: Code,
|
||||
pub headers: HeaderMap,
|
||||
pub body: Option<String>
|
||||
}
|
||||
|
||||
impl Response {
|
||||
|
||||
pub fn new() -> Self {
|
||||
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.put(Header::new("Connection", "close"));
|
||||
|
||||
let date = chrono::offset::Utc::now();
|
||||
headers.put(Header::new("Date", &date.to_rfc2822()));
|
||||
|
||||
headers.put(Header::new("Server", "bashttp"));
|
||||
|
||||
return Self {
|
||||
status: Code::Success,
|
||||
headers,
|
||||
body: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize(&self) -> String {
|
||||
let mut string = String::new();
|
||||
|
||||
string += &format!("HTTP/1.1 {}\n", self.status.clone() as u16);
|
||||
string += &self.headers.deserialize();
|
||||
|
||||
if let Some(body) = &self.body {
|
||||
string += "\n";
|
||||
string += body;
|
||||
}
|
||||
|
||||
string
|
||||
}
|
||||
}
|
106
src/http/uri.rs
Normal file
106
src/http/uri.rs
Normal file
|
@ -0,0 +1,106 @@
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum Protocol {
|
||||
HTTP,
|
||||
HTTPS,
|
||||
}
|
||||
|
||||
impl Protocol {
|
||||
pub fn serialize(string: &str) -> Option<Self> {
|
||||
match string {
|
||||
"http" => return Some(Self::HTTP),
|
||||
"https" => return Some(Self::HTTPS),
|
||||
_ => return None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize(&self) -> &str {
|
||||
match self {
|
||||
Self::HTTP => "http",
|
||||
Self::HTTPS => "https",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct URI {
|
||||
pub protocol: Option<Protocol>,
|
||||
pub host: Option<String>,
|
||||
pub port: Option<u16>,
|
||||
pub route: String
|
||||
}
|
||||
|
||||
impl URI {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn deserialize(&self) -> String {
|
||||
let mut string = String::new();
|
||||
|
||||
if let Some(protocol) = &self.protocol {
|
||||
string += protocol.deserialize();
|
||||
string += "://";
|
||||
}
|
||||
if let Some(host) = &self.host {
|
||||
string += host;
|
||||
}
|
||||
if let Some(port) = self.port {
|
||||
string += &format!(":{port}");
|
||||
}
|
||||
string += &self.route;
|
||||
|
||||
string
|
||||
}
|
||||
|
||||
pub fn serialize(head: &str) -> Option<Self> {
|
||||
|
||||
let protocol_end = match head.find("://") {
|
||||
Some(i) => i,
|
||||
None => 0
|
||||
};
|
||||
|
||||
let protocol: Option<Protocol>;
|
||||
let host_start: usize;
|
||||
if protocol_end == 0 {
|
||||
protocol = None;
|
||||
host_start = 0;
|
||||
} else {
|
||||
let Some(p) = Protocol::serialize(&head[..protocol_end]) else {
|
||||
return None
|
||||
};
|
||||
protocol = Some(p);
|
||||
host_start = protocol_end + 3;
|
||||
}
|
||||
|
||||
let host_route = &head[host_start..];
|
||||
let host_end = host_route.find("/").unwrap_or(head.len());
|
||||
|
||||
let host: Option<String>;
|
||||
let port: Option<u16>;
|
||||
if host_start == host_end {
|
||||
host = None;
|
||||
port = None;
|
||||
} else {
|
||||
if let Some (host_split) = host_route.find(":") {
|
||||
let port_start = host_split + 1;
|
||||
let port_str = &head[port_start..host_end];
|
||||
let Ok(p) = port_str.parse::<u16>() else {
|
||||
return None
|
||||
};
|
||||
host = Some(head[host_start..host_split].to_owned());
|
||||
port = Some(p);
|
||||
} else {
|
||||
host = Some(head[host_start..host_end].to_owned());
|
||||
port = None;
|
||||
}
|
||||
}
|
||||
|
||||
let route = &head[host_end..];
|
||||
|
||||
Some(Self {
|
||||
protocol,
|
||||
host,
|
||||
port,
|
||||
route: route.to_owned()
|
||||
})
|
||||
}
|
||||
|
||||
}
|
92
src/main.rs
Normal file
92
src/main.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use http::code::Code;
|
||||
use http::header::Header;
|
||||
use http::request::Request;
|
||||
use http::response::Response;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
use crate::bash::handle_script;
|
||||
|
||||
mod http;
|
||||
mod bash;
|
||||
|
||||
async fn handle_response(mut socket: TcpStream, code: Code, body: String) {
|
||||
let mut res = Response::new();
|
||||
res.headers.put(Header::new("Content-Type", "text/plain"));
|
||||
res.status = code;
|
||||
res.body = Some(body);
|
||||
|
||||
let res_str = res.deserialize();
|
||||
|
||||
let _ = socket.write(res_str.as_bytes()).await;
|
||||
}
|
||||
|
||||
async fn handle_connection(mut socket: TcpStream, config: Arc<HashMap<String, String>>) {
|
||||
|
||||
let mut buf = [0; 1204];
|
||||
|
||||
let n: usize = match socket.read(&mut buf).await {
|
||||
Ok(n) if n == 0 => return,
|
||||
Ok(n) => n as usize,
|
||||
Err(e) => {
|
||||
eprintln!("failed to read from socket; err = {:?}", e);
|
||||
return
|
||||
}
|
||||
};
|
||||
|
||||
let str = String::from_utf8_lossy(&buf[0..n]);
|
||||
|
||||
let Some(req) = Request::serialize(&str) else {
|
||||
return
|
||||
};
|
||||
|
||||
|
||||
let Some(script) = config.get(&req.uri.route) else {
|
||||
handle_response(socket, Code::MethodNotAllowed, "Method Not Allowed".to_owned()).await;
|
||||
return
|
||||
};
|
||||
|
||||
match handle_script(script, req.body.as_ref()) {
|
||||
Ok(out) => {
|
||||
handle_response(socket, Code::Success, out).await;
|
||||
},
|
||||
Err(err) => {
|
||||
handle_response(socket, Code::MethodNotAllowed, err).await;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
||||
let config = Arc::new(bash::load_config());
|
||||
|
||||
let port = std::env::var("PORT")
|
||||
.unwrap_or_else(|_| String::from("8080"))
|
||||
.parse::<u16>()
|
||||
.unwrap_or_else(|_| 8080);
|
||||
|
||||
let addr = format!("127.0.0.1:{port}");
|
||||
|
||||
let Ok(listener) = TcpListener::bind(&addr).await else {
|
||||
println!("failed to bind {addr}");
|
||||
return
|
||||
};
|
||||
|
||||
println!("listening to tcp requests on {addr}");
|
||||
|
||||
loop {
|
||||
let Ok((socket, _)) = listener.accept().await else {
|
||||
println!("failed to accept new connection");
|
||||
continue
|
||||
};
|
||||
|
||||
let config = config.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
handle_connection(socket, config).await;
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue