initial commit
This commit is contained in:
commit
419513d2e7
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
389
Cargo.lock
generated
Normal file
389
Cargo.lock
generated
Normal file
@ -0,0 +1,389 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.5.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deranged"
|
||||||
|
version = "0.3.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||||
|
dependencies = [
|
||||||
|
"powerfmt",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.155"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"wasi",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-conv"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_threads"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "powerfmt"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pumpkin"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"crossbeam-channel",
|
||||||
|
"log",
|
||||||
|
"mio",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"simple_logger",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.204"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.204"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.120"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simple_logger"
|
||||||
|
version = "5.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8c5dfa5e08767553704aa0ffd9d9794d527103c736aba9854773851fd7497eb"
|
||||||
|
dependencies = [
|
||||||
|
"colored",
|
||||||
|
"log",
|
||||||
|
"time",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.72"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
||||||
|
dependencies = [
|
||||||
|
"deranged",
|
||||||
|
"itoa",
|
||||||
|
"libc",
|
||||||
|
"num-conv",
|
||||||
|
"num_threads",
|
||||||
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
|
"time-core",
|
||||||
|
"time-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-core"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-macros"
|
||||||
|
version = "0.2.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
|
||||||
|
dependencies = [
|
||||||
|
"num-conv",
|
||||||
|
"time-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||||
|
dependencies = [
|
||||||
|
"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.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.52.5",
|
||||||
|
"windows_aarch64_msvc 0.52.5",
|
||||||
|
"windows_i686_gnu 0.52.5",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc 0.52.5",
|
||||||
|
"windows_x86_64_gnu 0.52.5",
|
||||||
|
"windows_x86_64_gnullvm 0.52.5",
|
||||||
|
"windows_x86_64_msvc 0.52.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
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.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
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.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
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.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||||
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
|
members = [
|
||||||
|
"pumpkin/"]
|
||||||
|
|
||||||
|
[workspace.package]
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
|
||||||
18
pumpkin/Cargo.toml
Normal file
18
pumpkin/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "pumpkin"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
|
||||||
|
simple_logger = "5.0.0"
|
||||||
|
log = "0.4"
|
||||||
|
byteorder = "1"
|
||||||
|
mio = { version = "1.0.1", features = ["os-poll", "net"]}
|
||||||
|
crossbeam-channel = "0.5.13"
|
||||||
|
uuid = "1.10"
|
||||||
|
|
||||||
|
|
||||||
46
pumpkin/src/client/client_packet.rs
Normal file
46
pumpkin/src/client/client_packet.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use crate::protocol::{
|
||||||
|
client::status::{CPingResponse, CStatusResponse},
|
||||||
|
server::{
|
||||||
|
handshake::SHandShake,
|
||||||
|
status::{SPingRequest, SStatusRequest},
|
||||||
|
},
|
||||||
|
StatusResponse, Version,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::Client;
|
||||||
|
|
||||||
|
pub trait ClientPacketProcessor {
|
||||||
|
// Handshake
|
||||||
|
fn handle_handshake(&mut self, handshake: SHandShake);
|
||||||
|
// Status
|
||||||
|
fn handle_status_request(&mut self, status_request: SStatusRequest);
|
||||||
|
fn handle_ping_request(&mut self, ping_request: SPingRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientPacketProcessor for Client {
|
||||||
|
fn handle_handshake(&mut self, handshake: SHandShake) {
|
||||||
|
// TODO set protocol version and check protocol version
|
||||||
|
self.connection_state = handshake.next_state;
|
||||||
|
dbg!("handshake");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_status_request(&mut self, _status_request: SStatusRequest) {
|
||||||
|
dbg!("sending status");
|
||||||
|
let response = StatusResponse {
|
||||||
|
version: Version {
|
||||||
|
version: "1.21".into(),
|
||||||
|
protocol: 767,
|
||||||
|
},
|
||||||
|
description: "Pumpkin Server".into(),
|
||||||
|
};
|
||||||
|
self.send_packet(CStatusResponse::new(
|
||||||
|
serde_json::to_string(&response).unwrap(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_ping_request(&mut self, ping_request: SPingRequest) {
|
||||||
|
dbg!("ping");
|
||||||
|
self.send_packet(CPingResponse::new(ping_request.payload));
|
||||||
|
self.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
168
pumpkin/src/client/mod.rs
Normal file
168
pumpkin/src/client/mod.rs
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
use std::{
|
||||||
|
collections::VecDeque,
|
||||||
|
io::{self, Write},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::protocol::{
|
||||||
|
server::{
|
||||||
|
handshake::SHandShake,
|
||||||
|
status::{SPingRequest, SStatusRequest},
|
||||||
|
},
|
||||||
|
ClientPacket, RawPacket,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::protocol::{bytebuf::buffer::ByteBuffer, ConnectionState};
|
||||||
|
use mio::{event::Event, net::TcpStream, Registry};
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
mod client_packet;
|
||||||
|
pub mod player;
|
||||||
|
|
||||||
|
use client_packet::ClientPacketProcessor;
|
||||||
|
|
||||||
|
pub struct Client {
|
||||||
|
pub connection_state: ConnectionState,
|
||||||
|
pub closed: bool,
|
||||||
|
pub connection: TcpStream,
|
||||||
|
// Packets coming from the client -> server
|
||||||
|
client_packets_queue: VecDeque<RawPacket>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub fn new(connection: TcpStream) -> Self {
|
||||||
|
Self {
|
||||||
|
connection_state: ConnectionState::HandShake,
|
||||||
|
connection,
|
||||||
|
closed: false,
|
||||||
|
client_packets_queue: VecDeque::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_packet(&mut self, packet: RawPacket) {
|
||||||
|
self.client_packets_queue.push_back(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_packet<P: ClientPacket>(&mut self, packet: P) {
|
||||||
|
dbg!("WRITING");
|
||||||
|
let mut packet_buf = ByteBuffer::new();
|
||||||
|
packet.write(&mut packet_buf);
|
||||||
|
// Creating empty packet's buffer
|
||||||
|
let mut packet = ByteBuffer::new();
|
||||||
|
// Creating length's bytes buffer and fill it as VarInt
|
||||||
|
let mut len_bytes = ByteBuffer::new();
|
||||||
|
len_bytes.write_var_int(P::PACKET_ID);
|
||||||
|
// Writing full packet's length(content + length's bytes)
|
||||||
|
packet.write_var_int((packet_buf.len() + len_bytes.len()) as i32);
|
||||||
|
// Writing length bytes
|
||||||
|
packet.write_all(len_bytes.as_bytes()).unwrap();
|
||||||
|
// Drop(Free) length bytes buffer
|
||||||
|
drop(len_bytes);
|
||||||
|
// Writing some packet's content
|
||||||
|
packet.write_all(packet_buf.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
self.connection.write_all(packet.as_bytes()).unwrap();
|
||||||
|
self.connection.flush().unwrap(); // todo do not flush every time
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn procress_packets(&mut self) {
|
||||||
|
let mut i = 0;
|
||||||
|
while i < self.client_packets_queue.len() {
|
||||||
|
let mut packet = self.client_packets_queue.remove(i).unwrap();
|
||||||
|
self.handle_packet(&mut packet);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_packet(&mut self, packet: &mut RawPacket) {
|
||||||
|
dbg!("Handling packet");
|
||||||
|
let bytebuf = &mut packet.bytebuf;
|
||||||
|
match self.connection_state {
|
||||||
|
crate::protocol::ConnectionState::HandShake => match packet.id {
|
||||||
|
SHandShake::PACKET_ID => self.handle_handshake(SHandShake::read(bytebuf)),
|
||||||
|
_ => log::error!(
|
||||||
|
"Failed to handle packet id {} while in Handshake state",
|
||||||
|
packet.id
|
||||||
|
),
|
||||||
|
},
|
||||||
|
crate::protocol::ConnectionState::Status => match packet.id {
|
||||||
|
SStatusRequest::PACKET_ID => {
|
||||||
|
self.handle_status_request(SStatusRequest::read(bytebuf))
|
||||||
|
}
|
||||||
|
SPingRequest::PACKET_ID => self.handle_ping_request(SPingRequest::read(bytebuf)),
|
||||||
|
_ => log::error!(
|
||||||
|
"Failed to handle packet id {} while in Status state",
|
||||||
|
packet.id
|
||||||
|
),
|
||||||
|
},
|
||||||
|
_ => log::error!("Invalid Connection state {:?}", self.connection_state),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the connection is done.
|
||||||
|
pub fn handle_connection_event(
|
||||||
|
&mut self,
|
||||||
|
_registry: &Registry,
|
||||||
|
event: &Event,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
if event.is_readable() {
|
||||||
|
let mut received_data = vec![0; 4096];
|
||||||
|
let mut bytes_read = 0;
|
||||||
|
// We can (maybe) read from the connection.
|
||||||
|
loop {
|
||||||
|
match self.connection.read(&mut received_data[bytes_read..]) {
|
||||||
|
Ok(0) => {
|
||||||
|
// Reading 0 bytes means the other side has closed the
|
||||||
|
// connection or is done writing, then so are we.
|
||||||
|
self.closed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Ok(n) => {
|
||||||
|
bytes_read += n;
|
||||||
|
if bytes_read == received_data.len() {
|
||||||
|
received_data.resize(received_data.len() + 1024, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Would block "errors" are the OS's way of saying that the
|
||||||
|
// connection is not actually ready to perform this I/O operation.
|
||||||
|
Err(ref err) if would_block(err) => break,
|
||||||
|
Err(ref err) if interrupted(err) => continue,
|
||||||
|
// Other errors we'll consider fatal.
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes_read != 0 {
|
||||||
|
let received_data = &received_data[..bytes_read];
|
||||||
|
let mut bytebuf = ByteBuffer::from_bytes(received_data);
|
||||||
|
let packet = RawPacket {
|
||||||
|
len: bytebuf.read_var_int().unwrap(),
|
||||||
|
id: bytebuf.read_var_int().unwrap(),
|
||||||
|
bytebuf,
|
||||||
|
};
|
||||||
|
if packet.len + 1 != received_data.len() as i32 {
|
||||||
|
log::error!(
|
||||||
|
"Packet length does not match Data length: {} {}",
|
||||||
|
packet.len,
|
||||||
|
received_data.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
dbg!(&packet);
|
||||||
|
self.add_packet(packet);
|
||||||
|
self.procress_packets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
self.closed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn would_block(err: &io::Error) -> bool {
|
||||||
|
err.kind() == io::ErrorKind::WouldBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupted(err: &io::Error) -> bool {
|
||||||
|
err.kind() == io::ErrorKind::Interrupted
|
||||||
|
}
|
||||||
12
pumpkin/src/client/player.rs
Normal file
12
pumpkin/src/client/player.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use crate::protocol::RawPacket;
|
||||||
|
|
||||||
|
use super::Client;
|
||||||
|
|
||||||
|
pub struct Player {
|
||||||
|
// All networking stuff
|
||||||
|
pub client: Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Player {
|
||||||
|
pub fn handle_packet(&mut self, _packet: &mut RawPacket) {}
|
||||||
|
}
|
||||||
0
pumpkin/src/client/player_packet.rs
Normal file
0
pumpkin/src/client/player_packet.rs
Normal file
109
pumpkin/src/main.rs
Normal file
109
pumpkin/src/main.rs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
use mio::net::TcpListener;
|
||||||
|
use mio::{Events, Interest, Poll, Token};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io::{self};
|
||||||
|
|
||||||
|
// Setup some tokens to allow us to identify which event is for which socket.
|
||||||
|
const SERVER: Token = Token(0);
|
||||||
|
|
||||||
|
pub mod client;
|
||||||
|
pub mod protocol;
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "wasi"))]
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
use client::{interrupted, Client};
|
||||||
|
|
||||||
|
simple_logger::SimpleLogger::new().init().unwrap();
|
||||||
|
|
||||||
|
// Create a poll instance.
|
||||||
|
let mut poll = Poll::new()?;
|
||||||
|
// Create storage for events.
|
||||||
|
let mut events = Events::with_capacity(128);
|
||||||
|
|
||||||
|
// Setup the TCP server socket.
|
||||||
|
let addr = "127.0.0.1:25565".parse().unwrap();
|
||||||
|
let mut server = TcpListener::bind(addr)?;
|
||||||
|
|
||||||
|
// Register the server with poll we can receive events for it.
|
||||||
|
poll.registry()
|
||||||
|
.register(&mut server, SERVER, Interest::READABLE)?;
|
||||||
|
|
||||||
|
// Map of `Token` -> `TcpStream`.
|
||||||
|
let mut connections = HashMap::new();
|
||||||
|
// Unique token for each incoming connection.
|
||||||
|
let mut unique_token = Token(SERVER.0 + 1);
|
||||||
|
|
||||||
|
log::info!("You can connect to the server using `nc`:");
|
||||||
|
log::info!(" $ nc 127.0.0.1 9000");
|
||||||
|
log::info!("You'll see our welcome message and anything you type will be printed here.");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Err(err) = poll.poll(&mut events, None) {
|
||||||
|
if interrupted(&err) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
for event in events.iter() {
|
||||||
|
match event.token() {
|
||||||
|
SERVER => loop {
|
||||||
|
// Received an event for the TCP server socket, which
|
||||||
|
// indicates we can accept an connection.
|
||||||
|
let (mut connection, address) = match server.accept() {
|
||||||
|
Ok((connection, address)) => (connection, address),
|
||||||
|
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||||
|
// If we get a `WouldBlock` error we know our
|
||||||
|
// listener has no more incoming connections queued,
|
||||||
|
// so we can return to polling and wait for some
|
||||||
|
// more.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// If it was any other kind of error, something went
|
||||||
|
// wrong and we terminate with an error.
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
log::info!("Accepted connection from: {}", address);
|
||||||
|
|
||||||
|
let token = next(&mut unique_token);
|
||||||
|
poll.registry().register(
|
||||||
|
&mut connection,
|
||||||
|
token,
|
||||||
|
Interest::READABLE.add(Interest::WRITABLE),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
connections.insert(token, Client::new(connection));
|
||||||
|
},
|
||||||
|
token => {
|
||||||
|
// Maybe received an event for a TCP connection.
|
||||||
|
let done = if let Some(client) = connections.get_mut(&token) {
|
||||||
|
client.handle_connection_event(poll.registry(), event)?;
|
||||||
|
client.closed
|
||||||
|
} else {
|
||||||
|
// Sporadic events happen, we can safely ignore them.
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if done {
|
||||||
|
if let Some(mut client) = connections.remove(&token) {
|
||||||
|
poll.registry().deregister(&mut client.connection)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(current: &mut Token) -> Token {
|
||||||
|
let next = current.0;
|
||||||
|
current.0 += 1;
|
||||||
|
Token(next)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "wasi")]
|
||||||
|
fn main() {
|
||||||
|
panic!("can't bind to an address with wasi")
|
||||||
|
}
|
||||||
168
pumpkin/src/network/connection.rs
Normal file
168
pumpkin/src/network/connection.rs
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
use std::{
|
||||||
|
io::{self, Read},
|
||||||
|
string::FromUtf8Error,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crossbeam_channel::{Receiver, Sender};
|
||||||
|
use mio::{net::TcpStream, Token, Waker};
|
||||||
|
|
||||||
|
use crate::player::JoinInfo;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
protocol::{clientbound, read::MessageReader, serverbound},
|
||||||
|
ProtocolVersion,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Connection {
|
||||||
|
stream: TcpStream,
|
||||||
|
ver: Option<ProtocolVersion>,
|
||||||
|
|
||||||
|
tx: Sender<clientbound::Packet>,
|
||||||
|
rx: Receiver<clientbound::Packet>,
|
||||||
|
|
||||||
|
token: Token,
|
||||||
|
|
||||||
|
incoming: Vec<u8>,
|
||||||
|
outgoing: Vec<u8>,
|
||||||
|
garbage: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ConnSender {
|
||||||
|
tx: Sender<cb::Packet>,
|
||||||
|
wake: Sender<WakeEvent>,
|
||||||
|
waker: Arc<Waker>,
|
||||||
|
tok: Token,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NewConn {
|
||||||
|
pub sender: ConnSender,
|
||||||
|
pub info: JoinInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum ParseError {
|
||||||
|
InvalidType(i32),
|
||||||
|
CannotHandleOutput,
|
||||||
|
InvalidLength,
|
||||||
|
NotLoggedIn,
|
||||||
|
AlreadyLoggedIn,
|
||||||
|
InvalidPassword,
|
||||||
|
IO(io::Error),
|
||||||
|
InvalidMessage(FromUtf8Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Connection {
|
||||||
|
fn new(stream: TcpStream, token: Token) -> Self {
|
||||||
|
// For a 10 chunk render distance, we need to send 441 packets at once. So a
|
||||||
|
// limit of 512 means we don't block very much.
|
||||||
|
let (tx, rx) = crossbeam_channel::bounded(512);
|
||||||
|
Self {
|
||||||
|
stream,
|
||||||
|
rx,
|
||||||
|
tx,
|
||||||
|
token,
|
||||||
|
incoming: Vec::with_capacity(1024),
|
||||||
|
outgoing: Vec::with_capacity(1024),
|
||||||
|
garbage: vec![0; 256 * 1024],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn send(&self, p: clientbound::Packet) {
|
||||||
|
if let Ok(()) = self.tx.send(p) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self) -> io::Result<(bool, Option<NewConn>, Vec<serverbound::Packet>)> {
|
||||||
|
let mut out = vec![];
|
||||||
|
loop {
|
||||||
|
let n = match self.stream.read(&mut self.garbage) {
|
||||||
|
Ok(0) => return Ok((true, None, out)),
|
||||||
|
Ok(n) => n,
|
||||||
|
Err(e) if e.kind() == io::ErrorKind::WouldBlock => return Ok((false, None, out)),
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
|
self.incoming.extend_from_slice(&self.garbage[..n]);
|
||||||
|
let (new_conn, packets) = self.read_incoming()?;
|
||||||
|
if new_conn.is_some() {
|
||||||
|
return Ok((false, new_conn, packets));
|
||||||
|
}
|
||||||
|
out.extend(packets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_incoming(&mut self) -> io::Result<(Option<NewConn>, Vec<serverbound::Packet>)> {
|
||||||
|
let mut out = vec![];
|
||||||
|
while !self.incoming.is_empty() {
|
||||||
|
let mut m = MessageReader::new(&self.incoming);
|
||||||
|
match m.read_u32() {
|
||||||
|
Ok(len) => {
|
||||||
|
let len = len as usize;
|
||||||
|
if len + m.index() <= self.incoming.len() {
|
||||||
|
// Remove the length varint at the start
|
||||||
|
let idx = m.index();
|
||||||
|
self.incoming.drain(0..idx);
|
||||||
|
// We already handshaked
|
||||||
|
if self.ver.is_some() {
|
||||||
|
let mut m = MessageReader::new(&self.incoming[..len]);
|
||||||
|
let p = serverbound::Packet::read(&mut m).map_err(|err| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
format!("while reading packet got err: {err}"),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let n = m.index();
|
||||||
|
self.incoming.drain(0..n);
|
||||||
|
if n != len {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
format!("packet did not parse enough bytes (expected {len}, only parsed {n})"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
out.push(p);
|
||||||
|
} else {
|
||||||
|
// This is the first packet, so it must be a login packet.
|
||||||
|
let mut m = MessageReader::new(&self.incoming[..len]);
|
||||||
|
let info: JoinInfo = m.read().map_err(|e| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
format!("error reading handshake: {e}"),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let n = m.index();
|
||||||
|
self.incoming.drain(0..n);
|
||||||
|
if n != len {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
format!("handshake did not parse enough bytes (expected {len}, only parsed {n})"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
self.ver = Some(ProtocolVersion::from(info.ver as i32));
|
||||||
|
// We rely on the caller to set the player using this value.
|
||||||
|
return Ok((
|
||||||
|
Some(NewConn {
|
||||||
|
sender: self.sender(),
|
||||||
|
info,
|
||||||
|
}),
|
||||||
|
out,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If this is an EOF, then we have a partial varint, so we are done reading.
|
||||||
|
Err(e) => {
|
||||||
|
if matches!(e, ReadError::Invalid(InvalidReadError::EOF)) {
|
||||||
|
return Ok((None, out));
|
||||||
|
} else {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
format!("error reading packet id: {e}"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((None, out))
|
||||||
|
}
|
||||||
|
}
|
||||||
756
pumpkin/src/protocol/bytebuf/buffer.rs
Normal file
756
pumpkin/src/protocol/bytebuf/buffer.rs
Normal file
@ -0,0 +1,756 @@
|
|||||||
|
use crate::protocol::{VarInt, VarLong};
|
||||||
|
|
||||||
|
use super::{Endian, CONTINUE_BIT, SEGMENT_BITS};
|
||||||
|
use byteorder::{BigEndian, ByteOrder, LittleEndian};
|
||||||
|
use std::{
|
||||||
|
fmt::Debug,
|
||||||
|
io::{Error, ErrorKind, Read, Result, Write},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A byte buffer object specifically turned to easily read and write binary values
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ByteBuffer {
|
||||||
|
data: Vec<u8>,
|
||||||
|
wpos: usize,
|
||||||
|
rpos: usize,
|
||||||
|
wbit: usize,
|
||||||
|
rbit: usize,
|
||||||
|
endian: Endian,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&[u8]> for ByteBuffer {
|
||||||
|
fn from(val: &[u8]) -> Self {
|
||||||
|
ByteBuffer::from_bytes(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<u8>> for ByteBuffer {
|
||||||
|
fn from(val: Vec<u8>) -> Self {
|
||||||
|
ByteBuffer::from_vec(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ByteBuffer> for Vec<u8> {
|
||||||
|
fn from(val: ByteBuffer) -> Self {
|
||||||
|
val.into_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ByteBuffer {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Read for ByteBuffer {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
self.flush_bits();
|
||||||
|
let read_len = std::cmp::min(self.data.len() - self.rpos, buf.len());
|
||||||
|
let range = self.rpos..self.rpos + read_len;
|
||||||
|
for (i, val) in self.data[range].iter().enumerate() {
|
||||||
|
buf[i] = *val;
|
||||||
|
}
|
||||||
|
self.rpos += read_len;
|
||||||
|
Ok(read_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for ByteBuffer {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||||
|
self.write_bytes(buf);
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for ByteBuffer {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
let rpos = if self.rbit > 0 {
|
||||||
|
self.rpos + 1
|
||||||
|
} else {
|
||||||
|
self.rpos
|
||||||
|
};
|
||||||
|
|
||||||
|
let read_len = self.data.len() - rpos;
|
||||||
|
let mut remaining_data = vec![0; read_len];
|
||||||
|
let range = rpos..rpos + read_len;
|
||||||
|
for (i, val) in self.data[range].iter().enumerate() {
|
||||||
|
remaining_data[i] = *val;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"ByteBuffer {{ remaining_data: {:?}, total_data: {:?}, wpos: {:?}, rpos: {:?}, endian: {:?} }}",
|
||||||
|
remaining_data, self.data, self.wpos, self.rpos, self.endian
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! read_number {
|
||||||
|
($self:ident, $name:ident, $offset:expr) => {{
|
||||||
|
$self.flush_bits();
|
||||||
|
if $self.rpos + $offset > $self.data.len() {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
"could not read enough bits from buffer",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let range = $self.rpos..$self.rpos + $offset;
|
||||||
|
$self.rpos += $offset;
|
||||||
|
|
||||||
|
Ok(match $self.endian {
|
||||||
|
Endian::BigEndian => BigEndian::$name(&$self.data[range]),
|
||||||
|
Endian::LittleEndian => LittleEndian::$name(&$self.data[range]),
|
||||||
|
})
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ByteBuffer {
|
||||||
|
/// Construct a new, empty, ByteBuffer
|
||||||
|
pub fn new() -> ByteBuffer {
|
||||||
|
ByteBuffer {
|
||||||
|
data: vec![],
|
||||||
|
wpos: 0,
|
||||||
|
rpos: 0,
|
||||||
|
rbit: 0,
|
||||||
|
wbit: 0,
|
||||||
|
endian: Endian::BigEndian,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a new ByteBuffer filled with the data array.
|
||||||
|
pub fn from_bytes(bytes: &[u8]) -> ByteBuffer {
|
||||||
|
let mut buffer = ByteBuffer::new();
|
||||||
|
buffer.write_bytes(bytes);
|
||||||
|
buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a new ByteBuffer from an existing vector. This
|
||||||
|
/// function takes ownership of the vector
|
||||||
|
pub fn from_vec(vec: Vec<u8>) -> ByteBuffer {
|
||||||
|
let len = vec.len();
|
||||||
|
ByteBuffer {
|
||||||
|
data: vec,
|
||||||
|
wpos: len,
|
||||||
|
rpos: 0,
|
||||||
|
rbit: 0,
|
||||||
|
wbit: 0,
|
||||||
|
endian: Endian::BigEndian,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the buffer size
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.data.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.data.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear the buffer and reinitialize the reading and writing cursors
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.data.clear();
|
||||||
|
self.reset_cursors();
|
||||||
|
self.reset_bits_cursors();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reinitialize the reading and writing cursor
|
||||||
|
pub fn reset_cursors(&mut self) {
|
||||||
|
self.wpos = 0;
|
||||||
|
self.rpos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reinitialize the bit reading and bit writing cursor
|
||||||
|
pub fn reset_bits_cursors(&mut self) {
|
||||||
|
self.rbit = 0;
|
||||||
|
self.wbit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Change the buffer size to size.
|
||||||
|
///
|
||||||
|
/// _Note_: You cannot shrink a buffer with this method
|
||||||
|
pub fn resize(&mut self, size: usize) {
|
||||||
|
let diff = size - self.data.len();
|
||||||
|
if diff > 0 {
|
||||||
|
self.data.extend(std::iter::repeat(0).take(diff))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the byte order of the buffer
|
||||||
|
///
|
||||||
|
/// _Note_: By default the buffer uses big endian order
|
||||||
|
pub fn set_endian(&mut self, endian: Endian) {
|
||||||
|
self.endian = endian;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the current byte order of the buffer
|
||||||
|
pub fn endian(&self) -> Endian {
|
||||||
|
self.endian
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write operations
|
||||||
|
|
||||||
|
/// Append a byte array to the buffer. The buffer is automatically extended if needed
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::new();
|
||||||
|
/// buffer.write_bytes(&vec![0x1, 0xFF, 0x45]); // buffer contains [0x1, 0xFF, 0x45]
|
||||||
|
/// ```
|
||||||
|
pub fn write_bytes(&mut self, bytes: &[u8]) {
|
||||||
|
self.flush_bits();
|
||||||
|
|
||||||
|
let size = bytes.len() + self.wpos;
|
||||||
|
|
||||||
|
if size > self.data.len() {
|
||||||
|
self.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
for v in bytes {
|
||||||
|
self.data[self.wpos] = *v;
|
||||||
|
self.wpos += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a byte (8 bits value) to the buffer
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::new();
|
||||||
|
/// buffer.write_u8(1) // buffer contains [0x1]
|
||||||
|
/// ```
|
||||||
|
pub fn write_u8(&mut self, val: u8) {
|
||||||
|
self.write_bytes(&[val]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `write_u8()` but for signed values
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn write_i8(&mut self, val: i8) {
|
||||||
|
self.write_u8(val as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a word (16 bits value) to the buffer
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::new();
|
||||||
|
/// buffer.write_u16(1) // buffer contains [0x00, 0x1] if little endian
|
||||||
|
/// ```
|
||||||
|
pub fn write_u16(&mut self, val: u16) {
|
||||||
|
let mut buf = [0; 2];
|
||||||
|
|
||||||
|
match self.endian {
|
||||||
|
Endian::BigEndian => BigEndian::write_u16(&mut buf, val),
|
||||||
|
Endian::LittleEndian => LittleEndian::write_u16(&mut buf, val),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.write_bytes(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `write_u16()` but for signed values
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn write_i16(&mut self, val: i16) {
|
||||||
|
self.write_u16(val as u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a double word (32 bits value) to the buffer
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::new();
|
||||||
|
/// buffer.write_u32(1) // buffer contains [0x00, 0x00, 0x00, 0x1] if little endian
|
||||||
|
/// ```
|
||||||
|
pub fn write_u32(&mut self, val: u32) {
|
||||||
|
let mut buf = [0; 4];
|
||||||
|
|
||||||
|
match self.endian {
|
||||||
|
Endian::BigEndian => BigEndian::write_u32(&mut buf, val),
|
||||||
|
Endian::LittleEndian => LittleEndian::write_u32(&mut buf, val),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.write_bytes(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `write_u32()` but for signed values
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn write_i32(&mut self, val: i32) {
|
||||||
|
self.write_u32(val as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_var_int(&mut self, value: VarInt) {
|
||||||
|
let mut val = value as u32;
|
||||||
|
for _ in 0..5 {
|
||||||
|
let mut b: u8 = val as u8 & 0b01111111;
|
||||||
|
val >>= 7;
|
||||||
|
if val != 0 {
|
||||||
|
b |= 0b10000000;
|
||||||
|
}
|
||||||
|
self.write_u8(b);
|
||||||
|
if val == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a quaddruple word (64 bits value) to the buffer
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::new();
|
||||||
|
/// buffer.write_u64(1) // buffer contains [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1] if little endian
|
||||||
|
/// ```
|
||||||
|
pub fn write_u64(&mut self, val: u64) {
|
||||||
|
let mut buf = [0; 8];
|
||||||
|
match self.endian {
|
||||||
|
Endian::BigEndian => BigEndian::write_u64(&mut buf, val),
|
||||||
|
Endian::LittleEndian => LittleEndian::write_u64(&mut buf, val),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.write_bytes(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `write_u64()` but for signed values
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn write_i64(&mut self, val: i64) {
|
||||||
|
self.write_u64(val as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a 32 bits floating point number to the buffer.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::new();
|
||||||
|
/// buffer.write_f32(0.1)
|
||||||
|
/// ```
|
||||||
|
pub fn write_f32(&mut self, val: f32) {
|
||||||
|
let mut buf = [0; 4];
|
||||||
|
|
||||||
|
match self.endian {
|
||||||
|
Endian::BigEndian => BigEndian::write_f32(&mut buf, val),
|
||||||
|
Endian::LittleEndian => LittleEndian::write_f32(&mut buf, val),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.write_bytes(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a 64 bits floating point number to the buffer.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::new();
|
||||||
|
/// buffer.write_f64(0.1)
|
||||||
|
/// ```
|
||||||
|
pub fn write_f64(&mut self, val: f64) {
|
||||||
|
let mut buf = [0; 8];
|
||||||
|
|
||||||
|
match self.endian {
|
||||||
|
Endian::BigEndian => BigEndian::write_f64(&mut buf, val),
|
||||||
|
Endian::LittleEndian => LittleEndian::write_f64(&mut buf, val),
|
||||||
|
};
|
||||||
|
self.write_bytes(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a string to the buffer.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// *Format* The format is `(u32)size + size * (u8)characters`
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::new();
|
||||||
|
/// buffer.write_string("Hello")
|
||||||
|
/// ```
|
||||||
|
pub fn write_string(&mut self, val: &str) {
|
||||||
|
self.write_var_int(val.len() as VarInt);
|
||||||
|
self.write_bytes(val.as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read operations
|
||||||
|
|
||||||
|
/// Read a defined amount of raw bytes, or return an IO error if not enough bytes are
|
||||||
|
/// available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_bytes(&mut self, size: usize) -> Result<Vec<u8>> {
|
||||||
|
self.flush_bits();
|
||||||
|
if self.rpos + size > self.data.len() {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
"could not read enough bytes from buffer",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let range = self.rpos..self.rpos + size;
|
||||||
|
let mut res = Vec::<u8>::new();
|
||||||
|
res.write_all(&self.data[range])?;
|
||||||
|
self.rpos += size;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read one byte, or return an IO error if not enough bytes are available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::from_bytes(&vec![0x1]);
|
||||||
|
/// let value = buffer.read_u8().unwrap(); //Value contains 1
|
||||||
|
/// ```
|
||||||
|
pub fn read_u8(&mut self) -> Result<u8> {
|
||||||
|
self.flush_bits();
|
||||||
|
if self.rpos >= self.data.len() {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
"could not read enough bits from buffer",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let pos = self.rpos;
|
||||||
|
self.rpos += 1;
|
||||||
|
Ok(self.data[pos])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `read_u8()` but for signed values
|
||||||
|
pub fn read_i8(&mut self) -> Result<i8> {
|
||||||
|
Ok(self.read_u8()? as i8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a 2-bytes long value, or return an IO error if not enough bytes are available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::from_bytes(&vec![0x0, 0x1]);
|
||||||
|
/// let value = buffer.read_u16().unwrap(); //Value contains 1
|
||||||
|
/// ```
|
||||||
|
pub fn read_u16(&mut self) -> Result<u16> {
|
||||||
|
read_number!(self, read_u16, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `read_u16()` but for signed values
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_i16(&mut self) -> Result<i16> {
|
||||||
|
Ok(self.read_u16()? as i16)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a four-bytes long value, or return an IO error if not enough bytes are available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::from_bytes(&vec![0x0, 0x0, 0x0, 0x1]);
|
||||||
|
/// let value = buffer.read_u32().unwrap(); // Value contains 1
|
||||||
|
/// ```
|
||||||
|
pub fn read_u32(&mut self) -> Result<u32> {
|
||||||
|
read_number!(self, read_u32, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `read_u32()` but for signed values
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_i32(&mut self) -> Result<i32> {
|
||||||
|
Ok(self.read_u32()? as i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read an eight bytes long value, or return an IO error if not enough bytes are available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::from_bytes(&vec![0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1]);
|
||||||
|
/// let value = buffer.read_u64().unwrap(); //Value contains 1
|
||||||
|
/// ```
|
||||||
|
pub fn read_u64(&mut self) -> Result<u64> {
|
||||||
|
read_number!(self, read_u64, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_var_int(&mut self) -> Result<VarInt> {
|
||||||
|
let mut value: i32 = 0;
|
||||||
|
let mut position: i32 = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let read = self.read_u8()?;
|
||||||
|
|
||||||
|
value |= ((read & SEGMENT_BITS) as i32) << position;
|
||||||
|
|
||||||
|
if read & CONTINUE_BIT == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
position += 7;
|
||||||
|
|
||||||
|
if position >= 32 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "VarInt is too big"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_var_long(&mut self) -> Result<VarLong> {
|
||||||
|
let mut value: i64 = 0;
|
||||||
|
let mut position: i64 = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let read = self.read_u8()?;
|
||||||
|
|
||||||
|
value |= ((read & SEGMENT_BITS) as i64) << position;
|
||||||
|
|
||||||
|
if read & CONTINUE_BIT == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
position += 7;
|
||||||
|
|
||||||
|
if position >= 64 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "VarLong is too big"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `read_u64()` but for signed values
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_i64(&mut self) -> Result<i64> {
|
||||||
|
Ok(self.read_u64()? as i64)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a 32 bits floating point value, or return an IO error if not enough bytes are available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_f32(&mut self) -> Result<f32> {
|
||||||
|
read_number!(self, read_f32, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a 64 bits floating point value, or return an IO error if not enough bytes are available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_f64(&mut self) -> Result<f64> {
|
||||||
|
read_number!(self, read_f64, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a string.
|
||||||
|
///
|
||||||
|
/// _Note_: First it reads a 32 bits value representing the size, then 'size' raw bytes
|
||||||
|
/// that must be encoded as UTF8.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_string(&mut self) -> Result<String> {
|
||||||
|
let size = self.read_var_int()?;
|
||||||
|
match String::from_utf8(self.read_bytes(size as usize)?) {
|
||||||
|
Ok(string_result) => Ok(string_result),
|
||||||
|
Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other
|
||||||
|
|
||||||
|
/// Dump the byte buffer to a string.
|
||||||
|
pub fn to_hex_dump(&self) -> String {
|
||||||
|
let mut str = String::new();
|
||||||
|
for b in &self.data {
|
||||||
|
str = str + &format!("0x{:01$x} ", b, 2);
|
||||||
|
}
|
||||||
|
str.pop();
|
||||||
|
str
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the position of the reading cursor
|
||||||
|
pub fn get_rpos(&self) -> usize {
|
||||||
|
self.rpos
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the reading cursor position.
|
||||||
|
/// _Note_: Sets the reading cursor to `min(newPosition, self.len())` to prevent overflow
|
||||||
|
pub fn set_rpos(&mut self, rpos: usize) {
|
||||||
|
self.rpos = std::cmp::min(rpos, self.data.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the writing cursor position
|
||||||
|
pub fn get_wpos(&self) -> usize {
|
||||||
|
self.wpos
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the writing cursor position.
|
||||||
|
/// _Note_: Sets the writing cursor to `min(newPosition, self.len())` to prevent overflow
|
||||||
|
pub fn set_wpos(&mut self, wpos: usize) {
|
||||||
|
self.wpos = std::cmp::min(wpos, self.data.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the raw byte buffer bytes.
|
||||||
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the raw byte buffer as a Vec<u8>.
|
||||||
|
#[deprecated(
|
||||||
|
since = "2.1.0",
|
||||||
|
note = "use `as_bytes().to_vec()` or `into_vec()` instead"
|
||||||
|
)]
|
||||||
|
pub fn into_bytes(&self) -> Vec<u8> {
|
||||||
|
self.data.to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the raw byte buffer as a Vec<u8>.
|
||||||
|
pub fn into_vec(self) -> Vec<u8> {
|
||||||
|
self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
//Bit manipulation functions
|
||||||
|
|
||||||
|
/// Read 1 bit. Return true if the bit is set to 1, otherwhise, return false.
|
||||||
|
///
|
||||||
|
/// _Note_: Bits are read from left to right
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::from_bytes(&vec![128]); // 10000000b
|
||||||
|
/// let value1 = buffer.read_bit().unwrap(); //value1 contains true (eg: bit is 1)
|
||||||
|
/// let value2 = buffer.read_bit().unwrap(); //value2 contains false (eg: bit is 0)
|
||||||
|
/// ```
|
||||||
|
pub fn read_bit(&mut self) -> Result<bool> {
|
||||||
|
if self.rpos >= self.data.len() {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
"could not read enough bits from buffer",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let bit = self.data[self.rpos] & (1 << (7 - self.rbit)) != 0;
|
||||||
|
self.rbit += 1;
|
||||||
|
if self.rbit > 7 {
|
||||||
|
self.flush_rbits();
|
||||||
|
}
|
||||||
|
Ok(bit)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read n bits. an return the corresponding value an u64.
|
||||||
|
///
|
||||||
|
/// _Note_: We cannot read more than 64 bits
|
||||||
|
///
|
||||||
|
/// _Note_: Bits are read from left to right
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::from_bytes(&vec![128]); // 10000000b
|
||||||
|
/// let value = buffer.read_bits(3).unwrap(); // value contains 4 (eg: 100b)
|
||||||
|
/// ```
|
||||||
|
pub fn read_bits(&mut self, n: u8) -> Result<u64> {
|
||||||
|
if n > 64 {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::InvalidInput,
|
||||||
|
"cannot read more than 64 bits",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if n == 0 {
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
Ok((u64::from(self.read_bit()?) << (n - 1)) | self.read_bits(n - 1)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Discard all the pending bits available for reading or writing and place the corresponding cursor to the next byte.
|
||||||
|
///
|
||||||
|
/// _Note_: If no bits are currently read or written, this function does nothing.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// 10010010 | 00000001
|
||||||
|
/// ^
|
||||||
|
/// 10010010 | 00000001 // read_bit called
|
||||||
|
/// ^
|
||||||
|
/// 10010010 | 00000001 // flush_bit() called
|
||||||
|
/// ^
|
||||||
|
/// ```
|
||||||
|
pub fn flush_bits(&mut self) {
|
||||||
|
if self.rbit > 0 {
|
||||||
|
self.flush_rbits();
|
||||||
|
}
|
||||||
|
if self.wbit > 0 {
|
||||||
|
self.flush_wbits();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_rbits(&mut self) {
|
||||||
|
self.rpos += 1;
|
||||||
|
self.rbit = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_wbits(&mut self) {
|
||||||
|
self.wpos += 1;
|
||||||
|
self.wbit = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append 1 bit value to the buffer.
|
||||||
|
/// The bit is appended like this :
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// ...| XXXXXXXX | 10000000 |....
|
||||||
|
/// ```
|
||||||
|
pub fn write_bit(&mut self, bit: bool) {
|
||||||
|
let size = self.wpos + 1;
|
||||||
|
if size > self.data.len() {
|
||||||
|
self.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if bit {
|
||||||
|
self.data[self.wpos] |= 1 << (7 - self.wbit);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.wbit += 1;
|
||||||
|
|
||||||
|
if self.wbit > 7 {
|
||||||
|
self.wbit = 0;
|
||||||
|
self.wpos += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write the given value as a sequence of n bits
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let mut buffer = ByteBuffer::new();
|
||||||
|
/// buffer.write_bits(4, 3); // append 100b
|
||||||
|
/// ```
|
||||||
|
pub fn write_bits(&mut self, value: u64, n: u8) {
|
||||||
|
if n > 0 {
|
||||||
|
self.write_bit((value >> (n - 1)) & 1 != 0);
|
||||||
|
self.write_bits(value, n - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
pumpkin/src/protocol/bytebuf/mod.rs
Normal file
11
pumpkin/src/protocol/bytebuf/mod.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
pub mod buffer;
|
||||||
|
pub mod reader;
|
||||||
|
|
||||||
|
const SEGMENT_BITS: u8 = 0x7F;
|
||||||
|
const CONTINUE_BIT: u8 = 0x80;
|
||||||
|
/// An enum to represent the byte order of the ByteBuffer object
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Endian {
|
||||||
|
BigEndian,
|
||||||
|
LittleEndian,
|
||||||
|
}
|
||||||
368
pumpkin/src/protocol/bytebuf/reader.rs
Normal file
368
pumpkin/src/protocol/bytebuf/reader.rs
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
use super::Endian;
|
||||||
|
use byteorder::{BigEndian, ByteOrder, LittleEndian};
|
||||||
|
use std::{
|
||||||
|
fmt::Debug,
|
||||||
|
io::{Error, ErrorKind, Read, Result, Write},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A byte buffer object specifically turned to easily read and write binary values
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ByteReader<'a> {
|
||||||
|
data: &'a [u8],
|
||||||
|
rpos: usize,
|
||||||
|
rbit: usize,
|
||||||
|
endian: Endian,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a [u8]> for ByteReader<'a> {
|
||||||
|
fn from(val: &'a [u8]) -> Self {
|
||||||
|
ByteReader::from_bytes(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Read for ByteReader<'a> {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
self.flush_bits();
|
||||||
|
let read_len = std::cmp::min(self.data.len() - self.rpos, buf.len());
|
||||||
|
let range = self.rpos..self.rpos + read_len;
|
||||||
|
for (i, val) in self.data[range].iter().enumerate() {
|
||||||
|
buf[i] = *val;
|
||||||
|
}
|
||||||
|
self.rpos += read_len;
|
||||||
|
Ok(read_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Debug for ByteReader<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
let rpos = if self.rbit > 0 {
|
||||||
|
self.rpos + 1
|
||||||
|
} else {
|
||||||
|
self.rpos
|
||||||
|
};
|
||||||
|
|
||||||
|
let read_len = self.data.len() - rpos;
|
||||||
|
let mut remaining_data = vec![0; read_len];
|
||||||
|
let range = rpos..rpos + read_len;
|
||||||
|
for (i, val) in self.data[range].iter().enumerate() {
|
||||||
|
remaining_data[i] = *val;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"ByteReader {{ remaining_data: {:?}, total_data: {:?}, rpos: {:?}, endian: {:?} }}",
|
||||||
|
remaining_data, self.data, self.rpos, self.endian
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! read_number {
|
||||||
|
($self:ident, $name:ident, $offset:expr) => {{
|
||||||
|
$self.flush_bits();
|
||||||
|
if $self.rpos + $offset > $self.data.len() {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
"could not read enough bits from buffer",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let range = $self.rpos..$self.rpos + $offset;
|
||||||
|
$self.rpos += $offset;
|
||||||
|
|
||||||
|
Ok(match $self.endian {
|
||||||
|
Endian::BigEndian => BigEndian::$name(&$self.data[range]),
|
||||||
|
Endian::LittleEndian => LittleEndian::$name(&$self.data[range]),
|
||||||
|
})
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ByteReader<'a> {
|
||||||
|
/// Construct a new ByteReader filled with the data array.
|
||||||
|
pub fn from_bytes(bytes: &[u8]) -> ByteReader {
|
||||||
|
ByteReader {
|
||||||
|
data: bytes,
|
||||||
|
rpos: 0,
|
||||||
|
rbit: 0,
|
||||||
|
endian: Endian::BigEndian,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the buffer size
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.data.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.data.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reinitialize the reading cursor
|
||||||
|
pub fn reset_cursors(&mut self) {
|
||||||
|
self.rpos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reinitialize the bit reading cursor
|
||||||
|
pub fn reset_bits_cursors(&mut self) {
|
||||||
|
self.rbit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the byte order of the buffer
|
||||||
|
///
|
||||||
|
/// _Note_: By default the buffer uses big endian order
|
||||||
|
pub fn set_endian(&mut self, endian: Endian) {
|
||||||
|
self.endian = endian;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the current byte order of the buffer
|
||||||
|
pub fn endian(&self) -> Endian {
|
||||||
|
self.endian
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read operations
|
||||||
|
|
||||||
|
/// Read a defined amount of raw bytes, or return an IO error if not enough bytes are
|
||||||
|
/// available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_bytes(&mut self, size: usize) -> Result<Vec<u8>> {
|
||||||
|
self.flush_bits();
|
||||||
|
if self.rpos + size > self.data.len() {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
"could not read enough bytes from buffer",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let range = self.rpos..self.rpos + size;
|
||||||
|
let mut res = Vec::<u8>::new();
|
||||||
|
res.write_all(&self.data[range])?;
|
||||||
|
self.rpos += size;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read one byte, or return an IO error if not enough bytes are available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let data = vec![0x1];
|
||||||
|
/// let mut buffer = ByteReader::from_bytes(&data);
|
||||||
|
/// let value = buffer.read_u8().unwrap(); //Value contains 1
|
||||||
|
/// ```
|
||||||
|
pub fn read_u8(&mut self) -> Result<u8> {
|
||||||
|
self.flush_bits();
|
||||||
|
if self.rpos >= self.data.len() {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
"could not read enough bits from buffer",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let pos = self.rpos;
|
||||||
|
self.rpos += 1;
|
||||||
|
Ok(self.data[pos])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `read_u8()` but for signed values
|
||||||
|
pub fn read_i8(&mut self) -> Result<i8> {
|
||||||
|
Ok(self.read_u8()? as i8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a 2-bytes long value, or return an IO error if not enough bytes are available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let data = vec![0x0, 0x1];
|
||||||
|
/// let mut buffer = ByteReader::from_bytes(&data);
|
||||||
|
/// let value = buffer.read_u16().unwrap(); //Value contains 1
|
||||||
|
/// ```
|
||||||
|
pub fn read_u16(&mut self) -> Result<u16> {
|
||||||
|
read_number!(self, read_u16, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `read_u16()` but for signed values
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_i16(&mut self) -> Result<i16> {
|
||||||
|
Ok(self.read_u16()? as i16)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a four-bytes long value, or return an IO error if not enough bytes are available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let data = vec![0x0, 0x0, 0x0, 0x1];
|
||||||
|
/// let mut buffer = ByteReader::from_bytes(&data);
|
||||||
|
/// let value = buffer.read_u32().unwrap(); // Value contains 1
|
||||||
|
/// ```
|
||||||
|
pub fn read_u32(&mut self) -> Result<u32> {
|
||||||
|
read_number!(self, read_u32, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `read_u32()` but for signed values
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_i32(&mut self) -> Result<i32> {
|
||||||
|
Ok(self.read_u32()? as i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read an eight bytes long value, or return an IO error if not enough bytes are available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let data = vec![0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1];
|
||||||
|
/// let mut buffer = ByteReader::from_bytes(&data);
|
||||||
|
/// let value = buffer.read_u64().unwrap(); //Value contains 1
|
||||||
|
/// ```
|
||||||
|
pub fn read_u64(&mut self) -> Result<u64> {
|
||||||
|
read_number!(self, read_u64, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `read_u64()` but for signed values
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_i64(&mut self) -> Result<i64> {
|
||||||
|
Ok(self.read_u64()? as i64)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a 32 bits floating point value, or return an IO error if not enough bytes are available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_f32(&mut self) -> Result<f32> {
|
||||||
|
read_number!(self, read_f32, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a 64 bits floating point value, or return an IO error if not enough bytes are available.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_f64(&mut self) -> Result<f64> {
|
||||||
|
read_number!(self, read_f64, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a string.
|
||||||
|
///
|
||||||
|
/// _Note_: First it reads a 32 bits value representing the size, then 'size' raw bytes
|
||||||
|
/// that must be encoded as UTF8.
|
||||||
|
/// _Note_: This method resets the read and write cursor for bitwise reading.
|
||||||
|
pub fn read_string(&mut self) -> Result<String> {
|
||||||
|
let size = self.read_u32()?;
|
||||||
|
match String::from_utf8(self.read_bytes(size as usize)?) {
|
||||||
|
Ok(string_result) => Ok(string_result),
|
||||||
|
Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other
|
||||||
|
|
||||||
|
/// Dump the byte buffer to a string.
|
||||||
|
pub fn to_hex_dump(&self) -> String {
|
||||||
|
let mut str = String::new();
|
||||||
|
for b in self.data {
|
||||||
|
str = str + &format!("0x{:01$x} ", b, 2);
|
||||||
|
}
|
||||||
|
str.pop();
|
||||||
|
str
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the position of the reading cursor
|
||||||
|
pub fn get_rpos(&self) -> usize {
|
||||||
|
self.rpos
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the reading cursor position.
|
||||||
|
/// _Note_: Sets the reading cursor to `min(newPosition, self.len())` to prevent overflow
|
||||||
|
pub fn set_rpos(&mut self, rpos: usize) {
|
||||||
|
self.rpos = std::cmp::min(rpos, self.data.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the raw byte buffer bytes.
|
||||||
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
|
self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
//Bit manipulation functions
|
||||||
|
|
||||||
|
/// Read 1 bit. Return true if the bit is set to 1, otherwhise, return false.
|
||||||
|
///
|
||||||
|
/// _Note_: Bits are read from left to right
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let data = vec![128];
|
||||||
|
/// let mut buffer = ByteReader::from_bytes(&data); // 10000000b
|
||||||
|
/// let value1 = buffer.read_bit().unwrap(); //value1 contains true (eg: bit is 1)
|
||||||
|
/// let value2 = buffer.read_bit().unwrap(); //value2 contains false (eg: bit is 0)
|
||||||
|
/// ```
|
||||||
|
pub fn read_bit(&mut self) -> Result<bool> {
|
||||||
|
if self.rpos >= self.data.len() {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
"could not read enough bits from buffer",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let bit = self.data[self.rpos] & (1 << (7 - self.rbit)) != 0;
|
||||||
|
self.rbit += 1;
|
||||||
|
if self.rbit > 7 {
|
||||||
|
self.flush_rbits();
|
||||||
|
}
|
||||||
|
Ok(bit)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read n bits. an return the corresponding value an u64.
|
||||||
|
///
|
||||||
|
/// _Note_: We cannot read more than 64 bits
|
||||||
|
///
|
||||||
|
/// _Note_: Bits are read from left to right
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bytebuffer::*;
|
||||||
|
/// let data = vec![128];
|
||||||
|
/// let mut buffer = ByteReader::from_bytes(&data); // 10000000b
|
||||||
|
/// let value = buffer.read_bits(3).unwrap(); // value contains 4 (eg: 100b)
|
||||||
|
/// ```
|
||||||
|
pub fn read_bits(&mut self, n: u8) -> Result<u64> {
|
||||||
|
if n > 64 {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::InvalidInput,
|
||||||
|
"cannot read more than 64 bits",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if n == 0 {
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
Ok((u64::from(self.read_bit()?) << (n - 1)) | self.read_bits(n - 1)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Discard all the pending bits available for reading and place the corresponding cursor to the next byte.
|
||||||
|
///
|
||||||
|
/// _Note_: If no bits are currently read, this function does nothing.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// 10010010 | 00000001
|
||||||
|
/// ^
|
||||||
|
/// 10010010 | 00000001 // read_bit called
|
||||||
|
/// ^
|
||||||
|
/// 10010010 | 00000001 // flush_bit() called
|
||||||
|
/// ^
|
||||||
|
/// ```
|
||||||
|
pub fn flush_bits(&mut self) {
|
||||||
|
if self.rbit > 0 {
|
||||||
|
self.flush_rbits();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_rbits(&mut self) {
|
||||||
|
self.rpos += 1;
|
||||||
|
self.rbit = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
4
pumpkin/src/protocol/client/mod.rs
Normal file
4
pumpkin/src/protocol/client/mod.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// Clientbound Packets
|
||||||
|
// Server -> Client
|
||||||
|
//
|
||||||
|
pub mod status;
|
||||||
37
pumpkin/src/protocol/client/status/mod.rs
Normal file
37
pumpkin/src/protocol/client/status/mod.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use crate::protocol::{bytebuf::buffer::ByteBuffer, ClientPacket, VarInt};
|
||||||
|
|
||||||
|
pub struct CPingResponse {
|
||||||
|
payload: i64, // must responde with the same as in `SPingRequest`
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CPingResponse {
|
||||||
|
pub fn new(payload: i64) -> Self {
|
||||||
|
Self { payload }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientPacket for CPingResponse {
|
||||||
|
const PACKET_ID: VarInt = 1;
|
||||||
|
|
||||||
|
fn write(&self, bytebuf: &mut ByteBuffer) {
|
||||||
|
bytebuf.write_i64(self.payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CStatusResponse {
|
||||||
|
json_response: String, // 32767
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CStatusResponse {
|
||||||
|
pub fn new(json_response: String) -> Self {
|
||||||
|
Self { json_response }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientPacket for CStatusResponse {
|
||||||
|
const PACKET_ID: VarInt = 0;
|
||||||
|
|
||||||
|
fn write(&self, bytebuf: &mut ByteBuffer) {
|
||||||
|
bytebuf.write_string(self.json_response.as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
54
pumpkin/src/protocol/mod.rs
Normal file
54
pumpkin/src/protocol/mod.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use bytebuf::buffer::ByteBuffer;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
pub mod bytebuf;
|
||||||
|
|
||||||
|
pub mod client;
|
||||||
|
pub mod server;
|
||||||
|
|
||||||
|
type VarInt = i32;
|
||||||
|
type VarLong = i64;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ConnectionState {
|
||||||
|
HandShake,
|
||||||
|
Status,
|
||||||
|
Login,
|
||||||
|
Transfer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectionState {
|
||||||
|
pub fn from_varint(var_int: VarInt) -> Self {
|
||||||
|
match var_int {
|
||||||
|
1 => Self::Status,
|
||||||
|
2 => Self::Login,
|
||||||
|
3 => Self::Transfer,
|
||||||
|
_ => panic!("Unexpected Status {}", var_int),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RawPacket {
|
||||||
|
pub len: VarInt,
|
||||||
|
pub id: VarInt,
|
||||||
|
pub bytebuf: ByteBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ClientPacket {
|
||||||
|
const PACKET_ID: VarInt;
|
||||||
|
|
||||||
|
fn write(&self, bytebuf: &mut ByteBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct StatusResponse {
|
||||||
|
pub version: Version,
|
||||||
|
pub description: String,
|
||||||
|
// Players, favicon ...
|
||||||
|
}
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Version {
|
||||||
|
pub version: String,
|
||||||
|
pub protocol: u32,
|
||||||
|
}
|
||||||
21
pumpkin/src/protocol/server/handshake/mod.rs
Normal file
21
pumpkin/src/protocol/server/handshake/mod.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use crate::protocol::{bytebuf::buffer::ByteBuffer, ConnectionState, VarInt};
|
||||||
|
|
||||||
|
pub struct SHandShake {
|
||||||
|
pub protocol_version: VarInt,
|
||||||
|
pub server_address: String, // 255
|
||||||
|
pub server_port: u16,
|
||||||
|
pub next_state: ConnectionState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SHandShake {
|
||||||
|
pub const PACKET_ID: VarInt = 0;
|
||||||
|
|
||||||
|
pub fn read(bytebuf: &mut ByteBuffer) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol_version: bytebuf.read_var_int().unwrap(),
|
||||||
|
server_address: bytebuf.read_string().unwrap(),
|
||||||
|
server_port: bytebuf.read_u16().unwrap(),
|
||||||
|
next_state: ConnectionState::from_varint(bytebuf.read_var_int().unwrap()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
pumpkin/src/protocol/server/mod.rs
Normal file
4
pumpkin/src/protocol/server/mod.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// Serverbound Packets
|
||||||
|
// Client -> Server
|
||||||
|
pub mod handshake;
|
||||||
|
pub mod status;
|
||||||
27
pumpkin/src/protocol/server/status/mod.rs
Normal file
27
pumpkin/src/protocol/server/status/mod.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use crate::protocol::{bytebuf::buffer::ByteBuffer, VarInt};
|
||||||
|
|
||||||
|
pub struct SStatusRequest {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SStatusRequest {
|
||||||
|
pub const PACKET_ID: VarInt = 0;
|
||||||
|
|
||||||
|
pub fn read(_bytebuf: &mut ByteBuffer) -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SPingRequest {
|
||||||
|
pub payload: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SPingRequest {
|
||||||
|
pub const PACKET_ID: VarInt = 1;
|
||||||
|
|
||||||
|
pub fn read(bytebuf: &mut ByteBuffer) -> Self {
|
||||||
|
Self {
|
||||||
|
payload: bytebuf.read_i64().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user