mirror of
https://github.com/htrefil/rkvm.git
synced 2025-01-30 20:34:13 +01:00
Implement client and server
This commit is contained in:
parent
8c55c00a5f
commit
32dc80ddeb
28 changed files with 1070 additions and 126 deletions
473
Cargo.lock
generated
473
Cargo.lock
generated
|
@ -18,12 +18,6 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
|
@ -35,6 +29,22 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.55.1"
|
||||
|
@ -46,7 +56,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"clang-sys",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"env_logger 0.7.1",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
|
@ -65,12 +75,24 @@ version = "1.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.4.0"
|
||||
|
@ -115,6 +137,32 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger 0.8.1",
|
||||
"input",
|
||||
"log",
|
||||
"net",
|
||||
"serde",
|
||||
"structopt",
|
||||
"tokio",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
|
@ -123,7 +171,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
"humantime 1.3.0",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime 2.0.1",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
|
@ -135,6 +196,21 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
|
@ -152,10 +228,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.5"
|
||||
name = "getrandom"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399"
|
||||
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
|
@ -163,6 +244,15 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.15"
|
||||
|
@ -181,13 +271,21 @@ dependencies = [
|
|||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a"
|
||||
|
||||
[[package]]
|
||||
name = "input"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
"libc",
|
||||
"mio",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
@ -266,35 +364,12 @@ dependencies = [
|
|||
"kernel32-sys",
|
||||
"libc",
|
||||
"log",
|
||||
"miow 0.2.1",
|
||||
"miow",
|
||||
"net2",
|
||||
"slab",
|
||||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-named-pipes"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656"
|
||||
dependencies = [
|
||||
"log",
|
||||
"mio",
|
||||
"miow 0.3.5",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-uds"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
|
||||
dependencies = [
|
||||
"iovec",
|
||||
"libc",
|
||||
"mio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.1"
|
||||
|
@ -308,13 +383,31 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.3.5"
|
||||
name = "native-tls"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e"
|
||||
checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d"
|
||||
dependencies = [
|
||||
"socket2",
|
||||
"winapi 0.3.9",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"input",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -339,13 +432,36 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
name = "openssl"
|
||||
version = "0.10.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||
checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -361,17 +477,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.21"
|
||||
name = "pkg-config"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c"
|
||||
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proto"
|
||||
version = "0.1.0"
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
|
@ -388,6 +536,47 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.57"
|
||||
|
@ -412,15 +601,89 @@ version = "0.6.18"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "server"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger 0.8.1",
|
||||
"input",
|
||||
"log",
|
||||
"native-tls",
|
||||
"net",
|
||||
"serde",
|
||||
"structopt",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
|
@ -428,34 +691,12 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
|
@ -463,16 +704,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.41"
|
||||
name = "structopt"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b"
|
||||
checksum = "126d630294ec449fae0b16f964e35bf3c74f940da9dca17ee9b905f7b3112eb8"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"lazy_static",
|
||||
"structopt-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structopt-derive"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65e51c492f9e23a220534971ff5afc14037289de430e3c83f9daf6a1b6ae91e8"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ad5de3220ea04da322618ded2c42233d02baca219d6f160a3e9c87cda16c942"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"rand",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.0"
|
||||
|
@ -508,20 +787,13 @@ checksum = "5d34ca54d84bf2b5b4d7d31e901a8464f7b60ac145a284fba25ceb801f2ddccd"
|
|||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"iovec",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio",
|
||||
"mio-named-pipes",
|
||||
"mio-uds",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"tokio-macros",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -535,6 +807,31 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd608593a919a8e05a7d1fc6df885e40f6a88d3a70a3a7eff23ff27964eda069"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
|
@ -547,6 +844,12 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
|
@ -559,6 +862,12 @@ version = "0.9.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "3.1.1"
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[workspace]
|
||||
members = ["client", "server", "input", "proto"]
|
||||
members = ["client", "server", "input", "net"]
|
0
client/src/.gitignore → client/.gitignore
vendored
0
client/src/.gitignore → client/.gitignore
vendored
|
@ -7,3 +7,11 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "0.2.22", features = ["macros", "time", "fs", "tcp", "dns"] }
|
||||
input = { path = "../input" }
|
||||
net = { path = "../net" }
|
||||
serde = { version = "1.0.117", features = ["derive"] }
|
||||
toml = "0.5.7"
|
||||
structopt = "0.3.20"
|
||||
log = "0.4.11"
|
||||
env_logger = "0.8.1"
|
||||
|
|
56
client/src/config.rs
Normal file
56
client/src/config.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use serde::de::{self, Visitor};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use std::fmt::{self, Formatter};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Config {
|
||||
pub server: Server,
|
||||
}
|
||||
|
||||
pub struct Server {
|
||||
pub hostname: String,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Server {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_str(ServerVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct ServerVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ServerVisitor {
|
||||
type Value = Server;
|
||||
|
||||
fn expecting(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "a server description (hostname:port)")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, data: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
let err = || E::custom("Invalid server description");
|
||||
|
||||
let mut split = data.split(':');
|
||||
let hostname = split.next().ok_or_else(err)?;
|
||||
let port = split
|
||||
.next()
|
||||
.and_then(|data| data.parse().ok())
|
||||
.ok_or_else(err)?;
|
||||
|
||||
if split.next().is_some() {
|
||||
return Err(E::custom("Extraneous data"));
|
||||
}
|
||||
|
||||
Ok(Server {
|
||||
hostname: hostname.to_owned(),
|
||||
port,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,3 +1,77 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
mod config;
|
||||
|
||||
use config::Config;
|
||||
use input::EventWriter;
|
||||
use net::{self, Message, PROTOCOL_VERSION};
|
||||
use std::convert::Infallible;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use structopt::StructOpt;
|
||||
use tokio::fs;
|
||||
use tokio::net::TcpStream;
|
||||
|
||||
async fn run(server: &str, port: u16) -> Result<Infallible, Error> {
|
||||
let mut stream = TcpStream::connect((server, port)).await?;
|
||||
|
||||
log::info!("Connected to {}:{}", server, port);
|
||||
|
||||
net::write_version(&mut stream, PROTOCOL_VERSION).await?;
|
||||
|
||||
let version = net::read_version(&mut stream).await?;
|
||||
if version != PROTOCOL_VERSION {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
format!(
|
||||
"Incompatible protocol version (got {}, expecting {})",
|
||||
version, PROTOCOL_VERSION
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
let mut writer = EventWriter::new().await?;
|
||||
loop {
|
||||
let message: Message = net::read_message(&mut stream).await?;
|
||||
match message {
|
||||
Message::Event(event) => writer.write(event).await?,
|
||||
Message::KeepAlive => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[structopt(name = "rkvm-client", about = "The rkvm client application")]
|
||||
struct Args {
|
||||
#[structopt(
|
||||
help = "Path to configuration file",
|
||||
default_value = "/etc/rkvm/client.toml"
|
||||
)]
|
||||
config_path: PathBuf,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::builder().format_timestamp(None).init();
|
||||
|
||||
let args = Args::from_args();
|
||||
let config = match fs::read_to_string(&args.config_path).await {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
log::error!("Error loading config: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let config: Config = match toml::from_str(&config) {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
log::error!("Error parsing config: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = run(&config.server.hostname, config.server.port).await {
|
||||
log::error!("Error: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
|
1
example/client.toml
Normal file
1
example/client.toml
Normal file
|
@ -0,0 +1 @@
|
|||
server = "123.45.67.89:5258"
|
2
example/server.toml
Normal file
2
example/server.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
listen-address = "0.0.0.0:5258"
|
||||
switch-keys = [29, 56, 111]
|
|
@ -7,9 +7,11 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "0.2.22", features = ["full"] }
|
||||
tokio = { version = "0.2.22", features = ["fs", "io-util", "io-driver", "sync", "blocking"] }
|
||||
mio = { version = "0.6.22" }
|
||||
libc = "0.2.77"
|
||||
serde = { version = "1.0.117", features = ["derive"] }
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = "0.55.1"
|
||||
cc = "1.0.60"
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
use bindgen::{Builder, CargoCallbacks};
|
||||
use cc::Build;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=wrapper.h");
|
||||
println!("cargo:rerun-if-changed=setup/setup.h");
|
||||
println!("cargo:rerun-if-changed=setup/setup.c");
|
||||
|
||||
Build::new().file("setup/setup.c").compile("setup");
|
||||
|
||||
let bindings = Builder::default()
|
||||
.header("wrapper.h")
|
||||
.header("setup/setup.h")
|
||||
.parse_callbacks(Box::new(CargoCallbacks))
|
||||
.generate()
|
||||
.unwrap();
|
||||
|
||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
bindings
|
||||
.write_to_file(out_path.join("bindings.rs"))
|
||||
.unwrap();
|
||||
bindings.write_to_file(out_path.join("setup.rs")).unwrap();
|
||||
}
|
||||
|
|
39
input/setup/setup.c
Normal file
39
input/setup/setup.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "setup.h"
|
||||
|
||||
#define IOCTL(fd, ...) if (ioctl(fd, __VA_ARGS__) == -1) return 0;
|
||||
|
||||
int setup_write_fd(int fd) {
|
||||
IOCTL(fd, UI_SET_EVBIT, EV_KEY);
|
||||
IOCTL(fd, UI_SET_EVBIT, EV_SYN);
|
||||
IOCTL(fd, UI_SET_EVBIT, EV_REL);
|
||||
|
||||
for (int i = 0; i < KEY_MAX; i++)
|
||||
IOCTL(fd, UI_SET_KEYBIT, i);
|
||||
|
||||
IOCTL(fd, UI_SET_KEYBIT, BTN_LEFT);
|
||||
IOCTL(fd, UI_SET_KEYBIT, BTN_RIGHT);
|
||||
|
||||
IOCTL(fd, UI_SET_RELBIT, REL_X);
|
||||
IOCTL(fd, UI_SET_RELBIT, REL_Y);
|
||||
IOCTL(fd, UI_SET_RELBIT, REL_WHEEL);
|
||||
|
||||
struct uinput_setup setup;
|
||||
setup.id.bustype = BUS_USB;
|
||||
setup.id.vendor = 1;
|
||||
setup.id.product = 1;
|
||||
setup.ff_effects_max = 0;
|
||||
strcpy(setup.name, "kvm");
|
||||
|
||||
IOCTL(fd, UI_DEV_SETUP, &setup);
|
||||
IOCTL(fd, UI_DEV_CREATE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int setup_read_fd(int fd) {
|
||||
IOCTL(fd, EVIOCGRAB, 1);
|
||||
return 1;
|
||||
}
|
5
input/setup/setup.h
Normal file
5
input/setup/setup.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#include <linux/uinput.h>
|
||||
|
||||
int setup_write_fd(int fd);
|
||||
|
||||
int setup_read_fd(int fd);
|
|
@ -5,7 +5,6 @@ use mio::{Poll, PollOpt, Ready, Token};
|
|||
use std::convert::AsRef;
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::CString;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::ErrorKind;
|
||||
use std::io::{Error, Read, Write};
|
||||
use std::os::unix::ffi::OsStringExt;
|
||||
|
@ -32,7 +31,6 @@ impl AsyncFile {
|
|||
let flags = match mode {
|
||||
OpenMode::Read => libc::O_RDONLY,
|
||||
OpenMode::Write => libc::O_WRONLY,
|
||||
OpenMode::ReadWrite => libc::O_RDWR,
|
||||
};
|
||||
|
||||
let fd = unsafe { libc::open(path.as_ptr(), flags | libc::O_NONBLOCK) };
|
||||
|
@ -90,7 +88,6 @@ impl AsyncWrite for AsyncFile {
|
|||
pub enum OpenMode {
|
||||
Read,
|
||||
Write,
|
||||
ReadWrite,
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#![allow(warnings)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
|
@ -1,6 +1,83 @@
|
|||
#[derive(Clone, Copy, Debug)]
|
||||
use crate::setup::{self, input_event, timeval};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub enum Event {
|
||||
MouseScroll { delta: i8 },
|
||||
MouseMove { x_delta: i8, y_delta: i8 },
|
||||
Key { up: bool, code: u16 },
|
||||
MouseScroll { delta: i32 },
|
||||
MouseMove { axis: Axis, delta: i32 },
|
||||
Key { direction: Direction, code: u16 },
|
||||
Sync,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
pub(crate) fn to_raw(&self) -> input_event {
|
||||
let (type_, code, value) = match *self {
|
||||
Event::MouseScroll { delta } => (setup::EV_REL as _, setup::REL_WHEEL as _, delta),
|
||||
Event::MouseMove {
|
||||
axis: Axis::X,
|
||||
delta,
|
||||
} => (setup::EV_REL as _, setup::REL_X as _, delta),
|
||||
Event::MouseMove {
|
||||
axis: Axis::Y,
|
||||
delta,
|
||||
} => (setup::EV_REL as _, setup::REL_Y as _, delta),
|
||||
Event::Key {
|
||||
direction: Direction::Up,
|
||||
code,
|
||||
} => (setup::EV_KEY as _, code, 0),
|
||||
Event::Key {
|
||||
direction: Direction::Down,
|
||||
code,
|
||||
} => (setup::EV_KEY as _, code, 1),
|
||||
Event::Sync => (setup::EV_SYN as _, 0, 0),
|
||||
};
|
||||
|
||||
input_event {
|
||||
type_,
|
||||
code,
|
||||
value,
|
||||
time: timeval {
|
||||
tv_sec: 0,
|
||||
tv_usec: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_raw(raw: input_event) -> Option<Self> {
|
||||
let event = match (raw.type_ as _, raw.code as _, raw.value) {
|
||||
(setup::EV_REL, setup::REL_WHEEL, value) => Event::MouseScroll { delta: value },
|
||||
(setup::EV_REL, setup::REL_X, value) => Event::MouseMove {
|
||||
axis: Axis::X,
|
||||
delta: value,
|
||||
},
|
||||
(setup::EV_REL, setup::REL_Y, value) => Event::MouseMove {
|
||||
axis: Axis::Y,
|
||||
delta: value,
|
||||
},
|
||||
(setup::EV_KEY, code, 0) => Event::Key {
|
||||
direction: Direction::Up,
|
||||
code: code as _,
|
||||
},
|
||||
(setup::EV_KEY, code, 1) => Event::Key {
|
||||
direction: Direction::Down,
|
||||
code: code as _,
|
||||
},
|
||||
(setup::EV_SYN, _, _) => Event::Sync,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(event)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub enum Axis {
|
||||
X,
|
||||
Y,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||
pub enum Direction {
|
||||
Up, // The key is released.
|
||||
Down, // The key is pressed.
|
||||
}
|
||||
|
|
76
input/src/event_manager.rs
Normal file
76
input/src/event_manager.rs
Normal file
|
@ -0,0 +1,76 @@
|
|||
use crate::event::Event;
|
||||
use crate::event_reader::{EventReader, OpenError};
|
||||
use crate::event_writer::EventWriter;
|
||||
use crate::setup::input_event;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use tokio::fs;
|
||||
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
||||
|
||||
pub struct EventManager {
|
||||
writer: EventWriter,
|
||||
receiver: UnboundedReceiver<Result<input_event, Error>>,
|
||||
}
|
||||
|
||||
impl EventManager {
|
||||
pub async fn new() -> Result<Self, Error> {
|
||||
let (sender, receiver) = mpsc::unbounded_channel();
|
||||
let mut read_dir = fs::read_dir("/dev/input").await?;
|
||||
while let Some(entry) = read_dir.next_entry().await? {
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let reader = match EventReader::new(&path).await {
|
||||
Ok(reader) => reader,
|
||||
Err(OpenError::NotSupported) => continue,
|
||||
Err(OpenError::Io(err)) => return Err(err),
|
||||
};
|
||||
let sender = sender.clone();
|
||||
|
||||
tokio::spawn(handle_events(reader, sender));
|
||||
}
|
||||
|
||||
let writer = EventWriter::new().await?;
|
||||
Ok(EventManager { writer, receiver })
|
||||
}
|
||||
|
||||
pub async fn read(&mut self) -> Result<Event, Error> {
|
||||
loop {
|
||||
let event = self
|
||||
.receiver
|
||||
.recv()
|
||||
.await
|
||||
.ok_or_else(|| Error::new(ErrorKind::Other, "All devices closed"))??;
|
||||
if let Some(event) = Event::from_raw(event) {
|
||||
return Ok(event);
|
||||
}
|
||||
|
||||
// Not understood. Write it back.
|
||||
self.writer.write_raw(event).await?;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn write(&mut self, event: Event) -> Result<(), Error> {
|
||||
self.writer.write(event).await
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_events(
|
||||
mut reader: EventReader,
|
||||
sender: UnboundedSender<Result<input_event, Error>>,
|
||||
) {
|
||||
loop {
|
||||
let result = match reader.read().await {
|
||||
Ok(event) => sender.send(Ok(event)).is_ok(),
|
||||
Err(err) => {
|
||||
let _ = sender.send(Err(err));
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
if !result {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1,43 @@
|
|||
pub struct EventReader {}
|
||||
use crate::async_file::{AsyncFile, OpenMode};
|
||||
use crate::setup::{self, input_event};
|
||||
use std::io::Error;
|
||||
use std::mem;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::path::Path;
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
pub(crate) struct EventReader {
|
||||
file: AsyncFile,
|
||||
}
|
||||
|
||||
impl EventReader {
|
||||
pub async fn new(path: &Path) -> Result<Self, OpenError> {
|
||||
let file = AsyncFile::open(path, OpenMode::Read)
|
||||
.await
|
||||
.map_err(OpenError::Io)?;
|
||||
if unsafe { setup::setup_read_fd(file.as_raw_fd()) == 0 } {
|
||||
let err = Error::last_os_error();
|
||||
if err.raw_os_error() == Some(libc::ENOTTY) {
|
||||
return Err(OpenError::NotSupported);
|
||||
}
|
||||
|
||||
return Err(OpenError::Io(err));
|
||||
}
|
||||
|
||||
Ok(Self { file })
|
||||
}
|
||||
|
||||
pub async fn read(&mut self) -> Result<input_event, Error> {
|
||||
let mut buffer = [0u8; mem::size_of::<input_event>()];
|
||||
self.file
|
||||
.read_exact(&mut buffer)
|
||||
.await
|
||||
.map(|_| unsafe { mem::transmute(buffer) })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OpenError {
|
||||
NotSupported,
|
||||
Io(Error),
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use crate::async_file::{AsyncFile, OpenMode};
|
||||
use crate::bindings;
|
||||
use libc::c_int;
|
||||
use crate::event::Event;
|
||||
use crate::setup::{self, input_event};
|
||||
use std::io::Error;
|
||||
use std::mem;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
pub struct EventWriter {
|
||||
file: AsyncFile,
|
||||
|
@ -11,22 +13,19 @@ pub struct EventWriter {
|
|||
impl EventWriter {
|
||||
pub async fn new() -> Result<Self, Error> {
|
||||
let file = AsyncFile::open("/dev/uinput", OpenMode::Write).await?;
|
||||
let fd = file.as_raw_fd();
|
||||
|
||||
for evbit in &[bindings::EV_KEY, bindings::EV_REL] {
|
||||
// Doesn't work, UI_SET_KEYBIT not found.
|
||||
// Probably too complicated for bindgen to be able to do something with it.
|
||||
check_ioctl(unsafe { libc::ioctl(fd, bindings::UI_SET_KEYBIT, evbit) })?;
|
||||
if unsafe { setup::setup_write_fd(file.as_raw_fd()) == 0 } {
|
||||
return Err(Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(EventWriter { file })
|
||||
}
|
||||
}
|
||||
|
||||
fn check_ioctl(ret: c_int) -> Result<(), Error> {
|
||||
if ret == -1 {
|
||||
return Err(Error::last_os_error());
|
||||
Ok(Self { file })
|
||||
}
|
||||
|
||||
Ok(())
|
||||
pub async fn write(&mut self, event: Event) -> Result<(), Error> {
|
||||
self.write_raw(event.to_raw()).await
|
||||
}
|
||||
|
||||
pub(crate) async fn write_raw(&mut self, event: input_event) -> Result<(), Error> {
|
||||
let data: [u8; mem::size_of::<input_event>()] = unsafe { mem::transmute(event) };
|
||||
self.file.write_all(&data).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
#![deny(warnings)]
|
||||
|
||||
mod async_file;
|
||||
mod bindings;
|
||||
mod event;
|
||||
mod event_manager;
|
||||
mod event_reader;
|
||||
mod event_writer;
|
||||
mod setup;
|
||||
|
||||
pub use event::Event;
|
||||
pub use event_reader::EventReader;
|
||||
pub use event::{Axis, Direction, Event};
|
||||
pub use event_manager::EventManager;
|
||||
pub use event_writer::EventWriter;
|
||||
|
|
3
input/src/setup.rs
Normal file
3
input/src/setup.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
#![allow(warnings)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/setup.rs"));
|
|
@ -1 +0,0 @@
|
|||
#include <linux/uinput.h>
|
0
proto/.gitignore → net/.gitignore
vendored
0
proto/.gitignore → net/.gitignore
vendored
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "proto"
|
||||
name = "net"
|
||||
version = "0.1.0"
|
||||
authors = ["Jan Trefil <8711792+htrefil@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
|
@ -7,3 +7,7 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
input = { path = "../input" }
|
||||
serde = { version = "1.0.117", features = ["derive"] }
|
||||
bincode = "1.3.1"
|
||||
tokio = { version = "0.2.22", features = ["io-util"] }
|
65
net/src/lib.rs
Normal file
65
net/src/lib.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
use input::Event;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryInto;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||
|
||||
// Is it bold to assume there won't be more than 65536 protocol versions?
|
||||
pub const PROTOCOL_VERSION: u16 = 0;
|
||||
|
||||
pub async fn read_version<R>(mut reader: R) -> Result<u16, Error>
|
||||
where
|
||||
R: AsyncRead + Unpin,
|
||||
{
|
||||
let mut bytes = [0; 2];
|
||||
reader.read_exact(&mut bytes).await?;
|
||||
|
||||
Ok(u16::from_le_bytes(bytes))
|
||||
}
|
||||
|
||||
pub async fn write_version<W>(mut writer: W, version: u16) -> Result<(), Error>
|
||||
where
|
||||
W: AsyncWrite + Unpin,
|
||||
{
|
||||
writer.write_all(&version.to_le_bytes()).await
|
||||
}
|
||||
|
||||
pub async fn read_message<R>(mut reader: R) -> Result<Message, Error>
|
||||
where
|
||||
R: AsyncRead + Unpin,
|
||||
{
|
||||
let length = {
|
||||
let mut bytes = [0; 2];
|
||||
reader.read_exact(&mut bytes).await?;
|
||||
|
||||
u16::from_le_bytes(bytes)
|
||||
};
|
||||
|
||||
let mut data = vec![0; length as usize];
|
||||
reader.read_exact(&mut data).await?;
|
||||
|
||||
bincode::deserialize(&data).map_err(|err| Error::new(ErrorKind::InvalidData, err))
|
||||
}
|
||||
|
||||
pub async fn write_message<W>(mut writer: W, message: &Message) -> Result<(), Error>
|
||||
where
|
||||
W: AsyncWrite + Unpin,
|
||||
{
|
||||
let data =
|
||||
bincode::serialize(&message).map_err(|err| Error::new(ErrorKind::InvalidInput, err))?;
|
||||
let length: u16 = data
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(|_| Error::new(ErrorKind::InvalidInput, "Serialized data is too large"))?;
|
||||
writer.write_all(&length.to_le_bytes()).await?;
|
||||
writer.write_all(&data).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub enum Message {
|
||||
Event(Event),
|
||||
// Sent only to keep the connection alive.
|
||||
KeepAlive,
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -7,3 +7,13 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "0.2.22", features = ["macros", "time", "fs", "tcp"] }
|
||||
input = { path = "../input" }
|
||||
net = { path = "../net" }
|
||||
serde = { version = "1.0.117", features = ["derive"] }
|
||||
toml = "0.5.7"
|
||||
structopt = "0.3.20"
|
||||
log = "0.4.11"
|
||||
env_logger = "0.8.1"
|
||||
tokio-native-tls = "0.1.0"
|
||||
native-tls = "0.2.4"
|
10
server/src/config.rs
Normal file
10
server/src/config.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Config {
|
||||
pub listen_address: SocketAddr,
|
||||
pub switch_keys: HashSet<u16>,
|
||||
}
|
|
@ -1,3 +1,168 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
mod config;
|
||||
|
||||
use config::Config;
|
||||
use input::{Direction, Event, EventManager};
|
||||
use net::{self, Message, PROTOCOL_VERSION};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::convert::Infallible;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::net::SocketAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use std::time::Duration;
|
||||
use structopt::StructOpt;
|
||||
use tokio::fs;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
||||
use tokio::time;
|
||||
|
||||
async fn handle_connection<T>(
|
||||
mut stream: T,
|
||||
mut receiver: UnboundedReceiver<Event>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
{
|
||||
net::write_version(&mut stream, PROTOCOL_VERSION).await?;
|
||||
|
||||
let version = net::read_version(&mut stream).await?;
|
||||
if version != PROTOCOL_VERSION {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
format!(
|
||||
"Incompatible protocol version (got {}, expecting {})",
|
||||
version, PROTOCOL_VERSION
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
loop {
|
||||
let message = match time::timeout(Duration::from_secs(10), receiver.recv()).await {
|
||||
Ok(Some(message)) => Message::Event(message),
|
||||
Ok(None) => return Ok(()),
|
||||
Err(_) => Message::KeepAlive,
|
||||
};
|
||||
|
||||
net::write_message(&mut stream, &message).await?;
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(listen_address: SocketAddr, switch_keys: &HashSet<u16>) -> Result<Infallible, Error> {
|
||||
let mut listener = TcpListener::bind(listen_address).await?;
|
||||
|
||||
log::info!("Listening on {}", listen_address);
|
||||
|
||||
let (client_sender, mut client_receiver) = mpsc::unbounded_channel();
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
let (stream, address) = match listener.accept().await {
|
||||
Ok(sa) => sa,
|
||||
Err(err) => {
|
||||
let _ = client_sender.send(Err(err));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let (sender, receiver) = mpsc::unbounded_channel();
|
||||
if client_sender.send(Ok(sender)).is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
tokio::spawn(async move {
|
||||
log::info!("{}: connected", address);
|
||||
let message = handle_connection(stream, receiver)
|
||||
.await
|
||||
.err()
|
||||
.map(|err| format!(" ({})", err))
|
||||
.unwrap_or(String::new());
|
||||
log::info!("{}: disconnected{}", address, message);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let mut clients: Vec<UnboundedSender<Event>> = Vec::new();
|
||||
let mut current = 0;
|
||||
let mut manager = EventManager::new().await?;
|
||||
let mut key_states: HashMap<_, _> = switch_keys
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|key| (key, false))
|
||||
.collect();
|
||||
loop {
|
||||
tokio::select! {
|
||||
event = manager.read() => {
|
||||
let event = event?;
|
||||
if let Event::Key { direction, code } = event {
|
||||
if let Some(state) = key_states.get_mut(&code) {
|
||||
*state = if direction == Direction::Down {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if key_states.iter().filter(|(_, state)| **state).count() == key_states.len() {
|
||||
for (_, state) in &mut key_states {
|
||||
*state = false;
|
||||
}
|
||||
|
||||
current = (current + 1) % (clients.len() + 1);
|
||||
log::info!("Switching to client {}", current);
|
||||
}
|
||||
|
||||
if current != 0 {
|
||||
if clients[current - 1].send(event).is_ok() {
|
||||
continue;
|
||||
}
|
||||
|
||||
clients.remove(current);
|
||||
current = 0;
|
||||
}
|
||||
|
||||
manager.write(event).await?;
|
||||
}
|
||||
sender = client_receiver.recv() => {
|
||||
clients.push(sender.unwrap()?);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[structopt(name = "rkvm-server", about = "The rkvm server application")]
|
||||
struct Args {
|
||||
#[structopt(
|
||||
help = "Path to configuration file",
|
||||
default_value = "/etc/rkvm/server.toml"
|
||||
)]
|
||||
config_path: PathBuf,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
env_logger::builder().format_timestamp(None).init();
|
||||
|
||||
let args = Args::from_args();
|
||||
let config = match fs::read_to_string(&args.config_path).await {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
log::error!("Error loading config: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let config: Config = match toml::from_str(&config) {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
log::error!("Error parsing config: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = run(config.listen_address, &config.switch_keys).await {
|
||||
log::error!("Error: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue