Compare commits

...

6 Commits
v0.0.1 ... main

Author SHA1 Message Date
e359567e7d fix(deps): update rust crate uuid to v1.12.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-15 02:25:40 +00:00
dbe2d1fc7a
chore: fix demo
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-14 08:35:14 +01:00
aaba4ed411
feat: add demo gif
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-14 08:34:46 +01:00
153edb10d4
docs: add more thorough example
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-14 08:22:29 +01:00
37df2dcc6d
docs: correct docs 2025-01-14 08:19:39 +01:00
881094e484
feat: add basic remote copu
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-14 08:16:50 +01:00
13 changed files with 1427 additions and 9 deletions

777
Cargo.lock generated
View File

@ -72,12 +72,98 @@ version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]]
name = "async-stream"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
dependencies = [
"async-stream-impl",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-stream-impl"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "async-trait"
version = "0.1.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.4.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "axum"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
dependencies = [
"async-trait",
"axum-core",
"bytes",
"futures-util",
"http",
"http-body",
"http-body-util",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"rustversion",
"serde",
"sync_wrapper",
"tower 0.5.2",
"tower-layer",
"tower-service",
]
[[package]]
name = "axum-core"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
dependencies = [
"async-trait",
"bytes",
"futures-util",
"http",
"http-body",
"http-body-util",
"mime",
"pin-project-lite",
"rustversion",
"sync_wrapper",
"tower-layer",
"tower-service",
]
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.74" version = "0.3.74"
@ -93,18 +179,39 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.7.0" version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.9.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
[[package]]
name = "cc"
version = "1.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b"
dependencies = [
"shlex",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -157,12 +264,85 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "core-foundation"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]] [[package]]
name = "dotenv" name = "dotenv"
version = "0.15.0" version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "futures-channel"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-sink"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]]
name = "futures-task"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"pin-utils",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.15" version = "0.2.15"
@ -180,18 +360,183 @@ version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "h2"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e"
dependencies = [
"atomic-waker",
"bytes",
"fnv",
"futures-core",
"futures-sink",
"http",
"indexmap 2.7.0",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "http"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "http-body"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
"http",
]
[[package]]
name = "http-body-util"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
dependencies = [
"bytes",
"futures-util",
"http",
"http-body",
"pin-project-lite",
]
[[package]]
name = "httparse"
version = "1.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
[[package]]
name = "httpdate"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"h2",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"smallvec",
"tokio",
"want",
]
[[package]]
name = "hyper-timeout"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
dependencies = [
"hyper",
"hyper-util",
"pin-project-lite",
"tokio",
"tower-service",
]
[[package]]
name = "hyper-util"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http",
"http-body",
"hyper",
"pin-project-lite",
"socket2",
"tokio",
"tower-service",
"tracing",
]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]]
name = "indexmap"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
dependencies = [
"equivalent",
"hashbrown 0.15.2",
]
[[package]] [[package]]
name = "is_terminal_polyfill" name = "is_terminal_polyfill"
version = "1.70.1" version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.5.0" version = "1.5.0"
@ -220,12 +565,24 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "matchit"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.2" version = "0.8.2"
@ -271,6 +628,12 @@ version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]] [[package]]
name = "overload" name = "overload"
version = "0.1.1" version = "0.1.1"
@ -300,12 +663,53 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pin-project"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.16" version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "ppv-lite86"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.92" version = "1.0.92"
@ -315,6 +719,38 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "prost"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec"
dependencies = [
"bytes",
"prost-derive",
]
[[package]]
name = "prost-derive"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "prost-types"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2f1e56baa61e93533aebc21af4d2134b70f66275e0fcdf3cbe43d77ff7e8fc"
dependencies = [
"prost",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.38" version = "1.0.38"
@ -324,6 +760,36 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.5.8" version = "0.5.8"
@ -333,18 +799,124 @@ dependencies = [
"bitflags", "bitflags",
] ]
[[package]]
name = "ring"
version = "0.17.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
dependencies = [
"cc",
"cfg-if",
"getrandom",
"libc",
"spin",
"untrusted",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.24" version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustls"
version = "0.23.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8"
dependencies = [
"log",
"once_cell",
"ring",
"rustls-pki-types",
"rustls-webpki",
"subtle",
"zeroize",
]
[[package]]
name = "rustls-native-certs"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3"
dependencies = [
"openssl-probe",
"rustls-pki-types",
"schannel",
"security-framework",
]
[[package]]
name = "rustls-pemfile"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "rustls-pki-types"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37"
[[package]]
name = "rustls-webpki"
version = "0.102.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
dependencies = [
"ring",
"rustls-pki-types",
"untrusted",
]
[[package]]
name = "rustversion"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
[[package]]
name = "schannel"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
dependencies = [
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "security-framework"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.217" version = "1.0.217"
@ -374,6 +946,12 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.4.2" version = "1.4.2"
@ -383,6 +961,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.13.2" version = "1.13.2"
@ -399,12 +986,24 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.96" version = "2.0.96"
@ -416,6 +1015,12 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "sync_wrapper"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
[[package]] [[package]]
name = "thread_local" name = "thread_local"
version = "1.1.8" version = "1.1.8"
@ -455,6 +1060,119 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "tokio-rustls"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
dependencies = [
"rustls",
"tokio",
]
[[package]]
name = "tokio-stream"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tonic"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52"
dependencies = [
"async-stream",
"async-trait",
"axum",
"base64",
"bytes",
"h2",
"http",
"http-body",
"http-body-util",
"hyper",
"hyper-timeout",
"hyper-util",
"percent-encoding",
"pin-project",
"prost",
"rustls-native-certs",
"rustls-pemfile",
"socket2",
"tokio",
"tokio-rustls",
"tokio-stream",
"tower 0.4.13",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
dependencies = [
"futures-core",
"futures-util",
"indexmap 1.9.3",
"pin-project",
"pin-project-lite",
"rand",
"slab",
"tokio",
"tokio-util",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]]
name = "tower-service"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.41" version = "0.1.41"
@ -513,12 +1231,24 @@ dependencies = [
"tracing-log", "tracing-log",
] ]
[[package]]
name = "try-lock"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.14" version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "untrusted"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
version = "0.2.2" version = "0.2.2"
@ -527,9 +1257,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.11.1" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b913a3b5fe84142e269d63cc62b64319ccaf89b748fc31fe025177f767a756c4" checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4"
dependencies = [ dependencies = [
"getrandom", "getrandom",
] ]
@ -542,18 +1272,32 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]] [[package]]
name = "voidpin" name = "voidpin"
version = "0.1.0" version = "0.0.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait",
"bytes",
"clap", "clap",
"dotenv", "dotenv",
"prost",
"prost-types",
"serde", "serde",
"tokio", "tokio",
"tonic",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"uuid", "uuid",
] ]
[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
dependencies = [
"try-lock",
]
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
@ -663,3 +1407,30 @@ name = "windows_x86_64_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"

View File

@ -4,9 +4,25 @@ Voidpin allows sending copy/paste commands across the wire. It is specifically i
Voidpin sends clipboard content to a local service, that then puts content in a local clipboard. It can also go the other way, but the primary intent is remote -> local. Voidpin sends clipboard content to a local service, that then puts content in a local clipboard. It can also go the other way, but the primary intent is remote -> local.
## Demo
![demo](assets/demo.gif)
## Usage ## Usage
```bash ```bash
# Local
voidpin copy voidpin copy
VOIDPIN_REMOTE=10.0.9.1:19191 voidpin remote copy
# Remote
ip a # 10.0.9.1
voidpin listen & # make voidpin listener run in background
# login to remote
ssh remote@remote
export VOIDPIN_REMOTE=http://10.0.9.1:7900
echo "some content" | voidpin remote copy
# In a browser for example
# Ctrl+v or Command+v
``` ```

175
assets/demo.cast Normal file
View File

@ -0,0 +1,175 @@
{"version": 2, "width": 130, "height": 40, "timestamp": 1736839984, "env": {"SHELL": "/bin/zsh", "TERM": "xterm-256color"}}
[0.479638, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[0.586074, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\r\n\u001b[38;2;255;153;102mvoidpin\u001b[0m \u001b[90mHEAD\u001b[1;32m(153edb1)\u001b[0m \u001b[38;2;255;153;102m \u001b[0mis \u001b[1;38;5;208m📦 v0.0.1\u001b[0m \u001b[1;31mrs \u001b[0mwith \u001b[1;34m🐃 v1.49.0 \u001b[0m\r\n\u001b[38;2;255;153;102m\u001b[0m \u001b[K"]
[0.587071, "o", "\u001b[6 q"]
[0.587964, "o", "\u001b[6 q"]
[0.588147, "o", "\u001b[?2004h"]
[3.167878, "o", "v"]
[3.191237, "o", "\b\u001b[1m\u001b[31mv\u001b[0m\u001b[39m"]
[3.232572, "o", "\b\u001b[1m\u001b[31mv\u001b[0m\u001b[39m\u001b[90moidpin listen\u001b[39m\u001b[13D"]
[3.300942, "o", "\b\u001b[1m\u001b[31mv\u001b[1m\u001b[31mo\u001b[0m\u001b[39m"]
[3.430551, "o", "\b\b\u001b[1m\u001b[31mv\u001b[1m\u001b[31mo\u001b[1m\u001b[31mi\u001b[0m\u001b[39m"]
[3.544553, "o", "\b\u001b[1m\u001b[31mi\u001b[1m\u001b[31md\u001b[0m\u001b[39m"]
[3.689365, "o", "\b\u001b[1m\u001b[31md\u001b[1m\u001b[31mp\u001b[0m\u001b[39m"]
[3.797695, "o", "\b\u001b[1m\u001b[31mp\u001b[1m\u001b[31mi\u001b[0m\u001b[39m"]
[3.97905, "o", "\b\u001b[1m\u001b[31mi\u001b[1m\u001b[31mn\u001b[0m\u001b[39m"]
[3.980916, "o", "\b\b\b\b\b\b\b\u001b[0m\u001b[32mv\u001b[0m\u001b[32mo\u001b[0m\u001b[32mi\u001b[0m\u001b[32md\u001b[0m\u001b[32mp\u001b[0m\u001b[32mi\u001b[0m\u001b[32mn\u001b[39m"]
[4.066146, "o", "\b\u001b[32mn\u001b[32m \u001b[39m"]
[4.068196, "o", "\b\b\u001b[32mn\u001b[39m\u001b[39m "]
[4.336382, "o", "\u001b[39mr\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \b\b\b\b\b"]
[4.342211, "o", "\b\u001b[4mr\u001b[24m"]
[4.422896, "o", "\b\u001b[4mr\u001b[4me\u001b[24m"]
[4.452272, "o", "\b\u001b[4me\u001b[4mm\u001b[24m"]
[4.45517, "o", "\b\b\b\u001b[24mr\u001b[24me\u001b[24mm"]
[4.583628, "o", "o"]
[4.666593, "o", "t"]
[4.759127, "o", "e"]
[4.900598, "o", " "]
[5.746797, "o", "&"]
[6.624085, "o", "\b \b"]
[6.74323, "o", "\b"]
[6.896869, "o", "\b \b"]
[7.033699, "o", "\b \b"]
[7.174094, "o", "\b \b"]
[7.309328, "o", "\b \b"]
[7.313831, "o", "\b\b\u001b[4mr\u001b[4me\u001b[24m"]
[7.443394, "o", "\b\b\u001b[4mr\u001b[24m\u001b[24m \b"]
[7.573529, "o", "\b\u001b[24m \b"]
[7.600586, "o", "\u001b[90mlisten\u001b[39m\b\b\b\b\b\b"]
[7.789065, "o", "\u001b[39ml"]
[7.957613, "o", "\u001b[39mi"]
[8.041393, "o", "\u001b[39ms"]
[8.137227, "o", "\u001b[39mt"]
[8.196626, "o", "\u001b[39me"]
[8.263729, "o", "\u001b[39mn"]
[8.401872, "o", " "]
[8.5879, "o", "&"]
[8.95472, "o", "\u001b[?1l\u001b>"]
[8.954912, "o", "\u001b[?2004l"]
[8.960125, "o", "\u001b[0 q"]
[8.960423, "o", "\r\r\n"]
[8.986315, "o", "[1] 36816\r\n"]
[8.98642, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[8.995202, "o", "\u001b[2m2025-01-14T07:33:13.136349Z\u001b[0m \u001b[32m INFO\u001b[0m \u001b[2mvoidpin\u001b[0m\u001b[2m:\u001b[0m starting listener \u001b[3mgrpc\u001b[0m\u001b[2m=\u001b[0m\"0.0.0.0:7900\"\r\n"]
[9.060819, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\r\n\u001b[38;2;255;153;102mvoidpin\u001b[0m \u001b[90mHEAD\u001b[1;32m(153edb1)\u001b[0m \u001b[38;2;255;153;102m \u001b[0mis \u001b[1;38;5;208m📦 v0.0.1\u001b[0m \u001b[1;31mrs \u001b[0mwith \u001b[1;34m🐃 v1.49.0 \u001b[0m\r\n\u001b[1;34m✦\u001b[0m \u001b[38;2;255;153;102m\u001b[0m \u001b[K"]
[9.061906, "o", "\u001b[6 q"]
[9.062876, "o", "\u001b[6 q"]
[9.063056, "o", "\u001b[?2004h"]
[10.265829, "o", "s"]
[10.272815, "o", "\b\u001b[1m\u001b[31ms\u001b[0m\u001b[39m"]
[10.34456, "o", "\b\u001b[1m\u001b[31ms\u001b[0m\u001b[39m\u001b[90msh nef_remote\u001b[39m\u001b[13D"]
[10.409989, "o", "\b\u001b[1m\u001b[31ms\u001b[1m\u001b[31ms\u001b[0m\u001b[39m"]
[10.531573, "o", "\b\b\u001b[1m\u001b[31ms\u001b[1m\u001b[31ms\u001b[1m\u001b[31mh\u001b[0m\u001b[39m"]
[10.534938, "o", "\b\b\b\u001b[0m\u001b[32ms\u001b[0m\u001b[32ms\u001b[0m\u001b[32mh\u001b[39m"]
[10.650848, "o", "\b\u001b[32mh\u001b[32m \u001b[39m"]
[10.654699, "o", "\b\b\u001b[32mh\u001b[39m\u001b[39m "]
[12.060573, "o", "\u001b[39mn"]
[12.153753, "o", "\u001b[39me"]
[12.238632, "o", "\u001b[39mf"]
[12.536018, "o", "\u001b[39m_"]
[12.700909, "o", "\u001b[39mr"]
[12.776911, "o", "\u001b[39me"]
[12.839538, "o", "\u001b[39mm"]
[12.97043, "o", "\u001b[39mo"]
[13.030559, "o", "\u001b[39mt"]
[13.111063, "o", "\u001b[39me"]
[13.319003, "o", "\u001b[?1l\u001b>"]
[13.319486, "o", "\u001b[?2004l"]
[13.325988, "o", "\u001b[0 q"]
[13.326164, "o", "\r\r\n"]
[14.748903, "o", "Last login: Tue Jan 14 08:27:03 2025 from 10.0.9.20\r\r\n"]
[14.80584, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[14.840843, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\r\n\u001b[1;33mkjuulh\u001b[0m in \u001b[1;2;32m🌐 nefarious\u001b[0m in \u001b[38;2;255;153;102m~\u001b[0m on \u001b[1;33m☁ (eu-west-1) \u001b[0m\r\n\u001b[38;2;255;153;102m\u001b[0m \u001b[K\u001b[6 q\u001b[6 q\u001b[?2004h"]
[15.45051, "o", "e"]
[15.456172, "o", "\b\u001b[1m\u001b[31me\u001b[0m\u001b[39m"]
[15.461708, "o", "\b\u001b[1m\u001b[31me\u001b[0m\u001b[39m\u001b[90mcho \"mystuff\" | voidpin remote copy\u001b[39m\u001b[35D"]
[15.623151, "o", "\b\u001b[1m\u001b[31me\u001b[1m\u001b[31mx\u001b[0m\u001b[39m\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[34D"]
[15.644024, "o", "\u001b[90mport VOIDPIN_REMOTE=http://10.0.9.20:7900\u001b[39m\u001b[41D"]
[15.743819, "o", "\b\b\u001b[1m\u001b[31me\u001b[1m\u001b[31mx\u001b[1m\u001b[31mp\u001b[0m\u001b[39m"]
[15.908543, "o", "\b\u001b[1m\u001b[31mp\u001b[1m\u001b[31mo\u001b[0m\u001b[39m"]
[16.003031, "o", "\b\u001b[1m\u001b[31mo\u001b[1m\u001b[31mr\u001b[0m\u001b[39m"]
[16.265633, "o", "\b\u001b[1m\u001b[31mr\u001b[1m\u001b[31mt\u001b[0m\u001b[39m\b\b\b\b\b\b\u001b[0m\u001b[33me\u001b[0m\u001b[33mx\u001b[0m\u001b[33mp\u001b[0m\u001b[33mo\u001b[0m\u001b[33mr\u001b[0m\u001b[33mt\u001b[39m"]
[16.276286, "o", "\b\u001b[33mt\u001b[33m \u001b[39m\b\b\u001b[33mt\u001b[39m\u001b[39m "]
[17.117006, "o", "\u001b[39mV"]
[17.118576, "o", "\b\u001b[4mV\u001b[24m"]
[17.334112, "o", "\b\u001b[4mV\u001b[39m\u001b[4mO\u001b[24m\b\b\u001b[24mV\u001b[24mO"]
[17.363757, "o", "\u001b[39mI"]
[17.604581, "o", "\u001b[39mD"]
[17.931075, "o", "\u001b[39mP\u001b[39mI\u001b[39mN\u001b[39m_\u001b[39mR\u001b[39mE\u001b[39mM\u001b[39mO\u001b[39mT\u001b[39mE\u001b[39m=\u001b[39mh\u001b[39mt\u001b[39mt\u001b[39mp\u001b[39m:\u001b[39m/\u001b[39m/\u001b[39m1\u001b[39m0\u001b[39m.\u001b[39m0\u001b[39m.\u001b[39m9\u001b[39m.\u001b[39m2\u001b[39m0\u001b[39m:\u001b[39m7\u001b[39m9\u001b[39m0\u001b[39m0"]
[18.721578, "o", "\u001b[0 q\u001b[?2004l\r\r\n"]
[18.729848, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[18.745102, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\r\n\u001b[1;33mkjuulh\u001b[0m in \u001b[1;2;32m🌐 nefarious\u001b[0m in \u001b[38;2;255;153;102m~\u001b[0m on \u001b[1;33m☁ (eu-west-1) \u001b[0m\r\n\u001b[38;2;255;153;102m\u001b[0m \u001b[K\u001b[6 q\u001b[6 q\u001b[?2004h"]
[19.768372, "o", "v\b\u001b[4mv\u001b[24m"]
[19.787679, "o", "\b\u001b[4mv\u001b[24m\u001b[90mirtualenv venv\u001b[39m\u001b[14D"]
[19.948701, "o", "\b\u001b[4mv\u001b[39m\u001b[4mo\u001b[24m\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[13D"]
[19.950166, "o", "\b\b\u001b[24m\u001b[1m\u001b[31mv\u001b[24m\u001b[1m\u001b[31mo\u001b[0m\u001b[39m"]
[19.998976, "o", "\b\b\u001b[1m\u001b[31mv\u001b[1m\u001b[31mo\u001b[1m\u001b[31mi\u001b[0m\u001b[39m"]
[20.399333, "o", "\b\b\b\u001b[1m\u001b[31mv\u001b[1m\u001b[31mo\u001b[0m\u001b[39m\u001b[0m\u001b[39m \b"]
[20.536472, "o", "\b\b\u001b[1m\u001b[31mv\u001b[0m\u001b[39m\u001b[0m\u001b[39m \b\b\u001b[0m\u001b[39m\u001b[4mv\u001b[24m"]
[20.54648, "o", "\b\u001b[4mv\u001b[24m\u001b[90mirtualenv venv\u001b[39m\u001b[14D"]
[20.659047, "o", "\b\u001b[24m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[15D"]
[21.004154, "o", "e\b\u001b[1m\u001b[31me\u001b[0m\u001b[39m"]
[21.010045, "o", "\b\u001b[1m\u001b[31me\u001b[0m\u001b[39m\u001b[90mxport VOIDPIN_REMOTE=http://10.0.9.20:7900\u001b[39m\u001b[42D"]
[21.21325, "o", "\b\u001b[1m\u001b[31me\u001b[1m\u001b[31mc\u001b[0m\u001b[39m\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[41D"]
[21.222033, "o", "\u001b[90mho \"mystuff\" | voidpin remote copy\u001b[39m\u001b[34D"]
[21.294992, "o", "\b\b\u001b[1m\u001b[31me\u001b[1m\u001b[31mc\u001b[1m\u001b[31mh\u001b[0m\u001b[39m"]
[21.419667, "o", "\b\u001b[1m\u001b[31mh\u001b[1m\u001b[31mo\u001b[0m\u001b[39m"]
[21.42291, "o", "\b\b\b\b\u001b[0m\u001b[32me\u001b[0m\u001b[32mc\u001b[0m\u001b[32mh\u001b[0m\u001b[32mo\u001b[39m"]
[21.505433, "o", "\b\u001b[32mo\u001b[32m \u001b[39m\b\b\u001b[32mo\u001b[39m\u001b[39m "]
[21.988846, "o", "\u001b[39m\"\u001b[39mm\u001b[39my\u001b[39ms\u001b[39mt\u001b[39mu\u001b[39mf\u001b[39mf\u001b[39m\"\u001b[39m \u001b[39m|\u001b[39m \u001b[39mv\u001b[39mo\u001b[39mi\u001b[39md\u001b[39mp\u001b[39mi\u001b[39mn\u001b[39m \u001b[39mr\u001b[39me\u001b[39mm\u001b[39mo\u001b[39mt\u001b[39me\u001b[39m \u001b[39mc\u001b[39mo\u001b[39mp\u001b[39my"]
[21.993557, "o", "\u001b[31D\u001b[33m\"\u001b[33mm\u001b[33my\u001b[33ms\u001b[33mt\u001b[33mu\u001b[33mf\u001b[33mf\u001b[33m\"\u001b[39m\u001b[3C\u001b[32mv\u001b[32mo\u001b[32mi\u001b[32md\u001b[32mp\u001b[32mi\u001b[32mn\u001b[39m\u001b[12C"]
[23.489379, "o", "\u001b[0 q"]
[23.490939, "o", "\u001b[?2004l\r\r\n"]
[23.569732, "o", "\u001b[2m2025-01-14T07:33:20.444640Z\u001b[0m \u001b[32m INFO\u001b[0m \u001b[2mvoidpin::remote_copy\u001b[0m\u001b[2m:\u001b[0m sending copy request\r\n"]
[23.595738, "o", "\u001b[2m2025-01-14T07:33:27.736730Z\u001b[0m \u001b[32m INFO\u001b[0m \u001b[2mvoidpin::copy\u001b[0m\u001b[2m:\u001b[0m copy process ended with status: ExitStatus(unix_wait_status(0))\n"]
[23.677319, "o", "\u001b[2m2025-01-14T07:33:20.549068Z\u001b[0m \u001b[32m INFO\u001b[0m \u001b[2mvoidpin::remote_copy\u001b[0m\u001b[2m:\u001b[0m sent copy request\r\n"]
[23.677877, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[23.682634, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\r\n\u001b[1;33mkjuulh\u001b[0m in \u001b[1;2;32m🌐 nefarious\u001b[0m in \u001b[38;2;255;153;102m~\u001b[0m on \u001b[1;33m☁ (eu-west-1) \u001b[0m\r\n\u001b[38;2;255;153;102m\u001b[0m \u001b[K"]
[23.684943, "o", "\u001b[6 q\u001b[6 q"]
[23.685144, "o", "\u001b[?2004h"]
[26.039094, "o", "e\b\u001b[1m\u001b[31me\u001b[0m\u001b[39m"]
[26.058901, "o", "\b\u001b[1m\u001b[31me\u001b[0m\u001b[39m\u001b[90mcho \"mystuff\" | voidpin remote copy\u001b[39m\u001b[35D"]
[26.200566, "o", "\b\u001b[1m\u001b[31me\u001b[1m\u001b[31mx\u001b[0m\u001b[39m\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[34D"]
[26.224342, "o", "\b\b\u001b[1m\u001b[31me\u001b[1m\u001b[31mx\u001b[1m\u001b[31mi\u001b[0m\u001b[39m"]
[26.236469, "o", "\u001b[90mt\u001b[39m\b"]
[26.338963, "o", "\b\u001b[1m\u001b[31mi\u001b[1m\u001b[31mt\u001b[0m\u001b[39m"]
[26.347595, "o", "\b\b\b\b\u001b[0m\u001b[32me\u001b[0m\u001b[32mx\u001b[0m\u001b[32mi\u001b[0m\u001b[32mt\u001b[39m"]
[27.917748, "o", "\u001b[0 q\u001b[?2004l\r\r\n"]
[27.92436, "o", "Connection to 10.0.9.18 closed.\r\r\n"]
[27.927279, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[28.005869, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\r\n\u001b[38;2;255;153;102mvoidpin\u001b[0m \u001b[90mHEAD\u001b[1;32m(153edb1)\u001b[0m \u001b[38;2;255;153;102m \u001b[0mis \u001b[1;38;5;208m📦 v0.0.1\u001b[0m \u001b[1;31mrs \u001b[0mwith \u001b[1;34m🐃 v1.49.0 \u001b[0m\u001b[33m14s\u001b[0m \r\n\u001b[1;34m✦\u001b[0m \u001b[38;2;255;153;102m\u001b[0m \u001b[K"]
[28.006941, "o", "\u001b[6 q"]
[28.007819, "o", "\u001b[6 q"]
[28.007998, "o", "\u001b[?2004h"]
[29.624611, "o", "p"]
[29.632533, "o", "\b\u001b[1m\u001b[31mp\u001b[0m\u001b[39m"]
[29.674006, "o", "\b\u001b[1m\u001b[31mp\u001b[0m\u001b[39m\u001b[90msql -h localhost -p 5432 -U postgres -d service\u001b[39m\u001b[47D"]
[29.861312, "o", "\b\u001b[1m\u001b[31mp\u001b[1m\u001b[31mb\u001b[0m\u001b[39m\u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[39m \u001b[46D"]
[29.896875, "o", "\u001b[90mcopy\u001b[39m\b\b\b\b"]
[30.455748, "o", "\b\b\u001b[1m\u001b[31mp\u001b[1m\u001b[31mb\u001b[1m\u001b[31mp\u001b[0m\u001b[39m\u001b[39m \u001b[39m \u001b[39m \b\b\b"]
[30.492269, "o", "\u001b[90maste\u001b[39m\b\b\b\b"]
[30.511887, "o", "\b\u001b[1m\u001b[31mp\u001b[1m\u001b[31ma\u001b[0m\u001b[39m"]
[30.640428, "o", "\b\u001b[1m\u001b[31ma\u001b[1m\u001b[31ms\u001b[0m\u001b[39m"]
[30.900008, "o", "\b\u001b[1m\u001b[31ms\u001b[1m\u001b[31mt\u001b[0m\u001b[39m"]
[31.00196, "o", "\b\u001b[1m\u001b[31mt\u001b[1m\u001b[31me\u001b[0m\u001b[39m"]
[31.004152, "o", "\b\b\b\b\b\b\b\u001b[0m\u001b[32mp\u001b[0m\u001b[32mb\u001b[0m\u001b[32mp\u001b[0m\u001b[32ma\u001b[0m\u001b[32ms\u001b[0m\u001b[32mt\u001b[0m\u001b[32me\u001b[39m"]
[31.436893, "o", "\u001b[?1l\u001b>"]
[31.437147, "o", "\u001b[?2004l"]
[31.440483, "o", "\u001b[0 q"]
[31.440758, "o", "\r\r\n"]
[31.506519, "o", "mystuff\r\n"]
[31.507028, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[31.578124, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\r\n\u001b[38;2;255;153;102mvoidpin\u001b[0m \u001b[90mHEAD\u001b[1;32m(153edb1)\u001b[0m \u001b[38;2;255;153;102m \u001b[0mis \u001b[1;38;5;208m📦 v0.0.1\u001b[0m \u001b[1;31mrs \u001b[0mwith \u001b[1;34m🐃 v1.49.0 \u001b[0m\r\n\u001b[1;34m✦\u001b[0m \u001b[38;2;255;153;102m\u001b[0m \u001b[K"]
[31.579154, "o", "\u001b[6 q"]
[31.580021, "o", "\u001b[6 q"]
[31.580178, "o", "\u001b[?2004h"]
[33.751349, "o", "\u001b[?2004l\r\r\n"]
[33.75158, "o", "zsh: you have running jobs.\r\n"]
[33.751697, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"]
[33.839059, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\r\n\u001b[38;2;255;153;102mvoidpin\u001b[0m \u001b[90mHEAD\u001b[1;32m(153edb1)\u001b[0m \u001b[38;2;255;153;102m \u001b[0mis \u001b[1;38;5;208m📦 v0.0.1\u001b[0m \u001b[1;31mrs \u001b[0mwith \u001b[1;34m🐃 v1.49.0 \u001b[0m\r\n\u001b[1;34m✦\u001b[0m \u001b[38;2;255;153;102m\u001b[0m \u001b[K"]
[33.840399, "o", "\u001b[6 q"]
[33.841412, "o", "\u001b[6 q"]
[33.84158, "o", "\u001b[?2004h"]
[39.131276, "o", "\u001b[?2004l\r\r\n"]
[39.13278, "o", "zsh: warning: 1 jobs SIGHUPed\r\n"]
[39.13415, "o", "[1] + hangup voidpin listen\r\n"]

BIN
assets/demo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

10
buf.gen.yaml Normal file
View File

@ -0,0 +1,10 @@
version: v2
managed:
enabled: true
plugins:
- remote: buf.build/community/neoeinstein-prost
out: crates/voidpin/src/gen
- remote: buf.build/community/neoeinstein-tonic:v0.4.0
out: crates/voidpin/src/gen
inputs:
- directory: crates/voidpin/proto

4
buf.yaml Normal file
View File

@ -0,0 +1,4 @@
version: v2
modules:
- path: proto
name: buf.build/noschemaplz/voidpin

View File

@ -14,3 +14,8 @@ dotenv.workspace = true
serde = { version = "1.0.197", features = ["derive"] } serde = { version = "1.0.197", features = ["derive"] }
uuid = { version = "1.7.0", features = ["v4"] } uuid = { version = "1.7.0", features = ["v4"] }
tonic = { version = "0.12.3", features = ["tls", "tls-roots"] }
prost = "0.13.4"
prost-types = "0.13.4"
bytes = "1.9.0"
async-trait = "0.1.85"

View File

@ -0,0 +1,13 @@
syntax = "proto3";
package voidpin.v1;
service VoidPin {
rpc Copy(CopyRequest) returns (CopyResponse);
}
message CopyRequest {
bytes content = 1;
}
message CopyResponse {}

View File

@ -0,0 +1,14 @@
// @generated
// This file is @generated by prost-build.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CopyRequest {
#[prost(bytes="vec", tag="1")]
pub content: ::prost::alloc::vec::Vec<u8>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct CopyResponse {
}
include!("voidpin.v1.tonic.rs");
// @@protoc_insertion_point(module)

View File

@ -0,0 +1,287 @@
// @generated
/// Generated client implementations.
pub mod void_pin_client {
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
use tonic::codegen::*;
use tonic::codegen::http::Uri;
///
#[derive(Debug, Clone)]
pub struct VoidPinClient<T> {
inner: tonic::client::Grpc<T>,
}
impl VoidPinClient<tonic::transport::Channel> {
/// Attempt to create a new client by connecting to a given endpoint.
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
impl<T> VoidPinClient<T>
where
T: tonic::client::GrpcService<tonic::body::BoxBody>,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + Send,
{
pub fn new(inner: T) -> Self {
let inner = tonic::client::Grpc::new(inner);
Self { inner }
}
pub fn with_origin(inner: T, origin: Uri) -> Self {
let inner = tonic::client::Grpc::with_origin(inner, origin);
Self { inner }
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> VoidPinClient<InterceptedService<T, F>>
where
F: tonic::service::Interceptor,
T::ResponseBody: Default,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
>,
>,
<T as tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
>>::Error: Into<StdError> + Send + Sync,
{
VoidPinClient::new(InterceptedService::new(inner, interceptor))
}
/// Compress requests with the given encoding.
///
/// This requires the server to support it otherwise it might respond with an
/// error.
#[must_use]
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.send_compressed(encoding);
self
}
/// Enable decompressing responses.
#[must_use]
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.accept_compressed(encoding);
self
}
/// Limits the maximum size of a decoded message.
///
/// Default: `4MB`
#[must_use]
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_decoding_message_size(limit);
self
}
/// Limits the maximum size of an encoded message.
///
/// Default: `usize::MAX`
#[must_use]
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_encoding_message_size(limit);
self
}
///
pub async fn copy(
&mut self,
request: impl tonic::IntoRequest<super::CopyRequest>,
) -> std::result::Result<tonic::Response<super::CopyResponse>, tonic::Status> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static("/voidpin.v1.VoidPin/Copy");
let mut req = request.into_request();
req.extensions_mut().insert(GrpcMethod::new("voidpin.v1.VoidPin", "Copy"));
self.inner.unary(req, path, codec).await
}
}
}
/// Generated server implementations.
pub mod void_pin_server {
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
use tonic::codegen::*;
/// Generated trait containing gRPC methods that should be implemented for use with VoidPinServer.
#[async_trait]
pub trait VoidPin: Send + Sync + 'static {
///
async fn copy(
&self,
request: tonic::Request<super::CopyRequest>,
) -> std::result::Result<tonic::Response<super::CopyResponse>, tonic::Status>;
}
///
#[derive(Debug)]
pub struct VoidPinServer<T: VoidPin> {
inner: _Inner<T>,
accept_compression_encodings: EnabledCompressionEncodings,
send_compression_encodings: EnabledCompressionEncodings,
max_decoding_message_size: Option<usize>,
max_encoding_message_size: Option<usize>,
}
struct _Inner<T>(Arc<T>);
impl<T: VoidPin> VoidPinServer<T> {
pub fn new(inner: T) -> Self {
Self::from_arc(Arc::new(inner))
}
pub fn from_arc(inner: Arc<T>) -> Self {
let inner = _Inner(inner);
Self {
inner,
accept_compression_encodings: Default::default(),
send_compression_encodings: Default::default(),
max_decoding_message_size: None,
max_encoding_message_size: None,
}
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> InterceptedService<Self, F>
where
F: tonic::service::Interceptor,
{
InterceptedService::new(Self::new(inner), interceptor)
}
/// Enable decompressing requests with the given encoding.
#[must_use]
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.accept_compression_encodings.enable(encoding);
self
}
/// Compress responses with the given encoding, if the client supports it.
#[must_use]
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.send_compression_encodings.enable(encoding);
self
}
/// Limits the maximum size of a decoded message.
///
/// Default: `4MB`
#[must_use]
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
self.max_decoding_message_size = Some(limit);
self
}
/// Limits the maximum size of an encoded message.
///
/// Default: `usize::MAX`
#[must_use]
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
self.max_encoding_message_size = Some(limit);
self
}
}
impl<T, B> tonic::codegen::Service<http::Request<B>> for VoidPinServer<T>
where
T: VoidPin,
B: Body + Send + 'static,
B::Error: Into<StdError> + Send + 'static,
{
type Response = http::Response<tonic::body::BoxBody>;
type Error = std::convert::Infallible;
type Future = BoxFuture<Self::Response, Self::Error>;
fn poll_ready(
&mut self,
_cx: &mut Context<'_>,
) -> Poll<std::result::Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: http::Request<B>) -> Self::Future {
let inner = self.inner.clone();
match req.uri().path() {
"/voidpin.v1.VoidPin/Copy" => {
#[allow(non_camel_case_types)]
struct CopySvc<T: VoidPin>(pub Arc<T>);
impl<T: VoidPin> tonic::server::UnaryService<super::CopyRequest>
for CopySvc<T> {
type Response = super::CopyResponse;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<super::CopyRequest>,
) -> Self::Future {
let inner = Arc::clone(&self.0);
let fut = async move {
<T as VoidPin>::copy(&inner, request).await
};
Box::pin(fut)
}
}
let accept_compression_encodings = self.accept_compression_encodings;
let send_compression_encodings = self.send_compression_encodings;
let max_decoding_message_size = self.max_decoding_message_size;
let max_encoding_message_size = self.max_encoding_message_size;
let inner = self.inner.clone();
let fut = async move {
let inner = inner.0;
let method = CopySvc(inner);
let codec = tonic::codec::ProstCodec::default();
let mut grpc = tonic::server::Grpc::new(codec)
.apply_compression_config(
accept_compression_encodings,
send_compression_encodings,
)
.apply_max_message_size_config(
max_decoding_message_size,
max_encoding_message_size,
);
let res = grpc.unary(method, req).await;
Ok(res)
};
Box::pin(fut)
}
_ => {
Box::pin(async move {
Ok(
http::Response::builder()
.status(200)
.header("grpc-status", "12")
.header("content-type", "application/grpc")
.body(empty_body())
.unwrap(),
)
})
}
}
}
}
impl<T: VoidPin> Clone for VoidPinServer<T> {
fn clone(&self) -> Self {
let inner = self.inner.clone();
Self {
inner,
accept_compression_encodings: self.accept_compression_encodings,
send_compression_encodings: self.send_compression_encodings,
max_decoding_message_size: self.max_decoding_message_size,
max_encoding_message_size: self.max_encoding_message_size,
}
}
}
impl<T: VoidPin> Clone for _Inner<T> {
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for _Inner<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
impl<T: VoidPin> tonic::server::NamedService for VoidPinServer<T> {
const NAME: &'static str = "voidpin.v1.VoidPin";
}
}

View File

@ -0,0 +1,30 @@
use crate::{copy::LocalCopierState, state::State};
#[derive(Clone)]
pub struct GrpcServer {
state: State,
}
impl GrpcServer {
pub fn new(state: State) -> Self {
Self { state }
}
}
#[async_trait::async_trait]
impl crate::grpc::void_pin_server::VoidPin for GrpcServer {
async fn copy(
&self,
req: tonic::Request<crate::grpc::CopyRequest>,
) -> Result<tonic::Response<crate::grpc::CopyResponse>, tonic::Status> {
let req = req.into_inner();
self.state
.local_copier()
.copy(&req.content)
.await
.map_err(|e| tonic::Status::internal(e.to_string()))?;
Ok(tonic::Response::new(crate::grpc::CopyResponse {}))
}
}

View File

@ -1,11 +1,22 @@
use std::io::Read; use std::{io::Read, net::SocketAddr};
use anyhow::Context; use anyhow::Context;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use copy::LocalCopierState; use copy::LocalCopierState;
use grpc::void_pin_server::VoidPinServer;
use grpc_server::GrpcServer;
use remote_copy::RemoteCopierState;
use state::State; use state::State;
use tonic::transport;
mod grpc {
include!("gen/voidpin.v1.rs");
}
mod grpc_server;
mod copy; mod copy;
mod remote_copy;
mod state; mod state;
#[derive(Parser)] #[derive(Parser)]
@ -17,7 +28,10 @@ struct Command {
#[derive(Subcommand)] #[derive(Subcommand)]
enum Commands { enum Commands {
Listen {}, Listen {
#[arg(long, env = "VOIDPIN_GRPC_HOST", default_value = "0.0.0.0:7900")]
grpc: SocketAddr,
},
Copy {}, Copy {},
Remote { Remote {
#[command(subcommand)] #[command(subcommand)]
@ -27,7 +41,14 @@ enum Commands {
#[derive(Subcommand)] #[derive(Subcommand)]
enum RemoteCommands { enum RemoteCommands {
Copy {}, Copy {
#[arg(
long = "remote-host",
env = "VOIDPIN_REMOTE",
default_value = "http://0.0.0.0:7900"
)]
remote_host: String,
},
} }
#[tokio::main] #[tokio::main]
@ -41,7 +62,13 @@ async fn main() -> anyhow::Result<()> {
let state = State::new(); let state = State::new();
match cli.command.unwrap() { match cli.command.unwrap() {
Commands::Listen {} => {} Commands::Listen { grpc } => {
tracing::info!(grpc = grpc.to_string(), "starting listener");
transport::Server::builder()
.add_service(VoidPinServer::new(GrpcServer::new(state)))
.serve(grpc)
.await?;
}
Commands::Copy {} => { Commands::Copy {} => {
let mut input = String::new(); let mut input = String::new();
std::io::stdin() std::io::stdin()
@ -57,7 +84,23 @@ async fn main() -> anyhow::Result<()> {
state.local_copier().copy(input.as_bytes()).await?; state.local_copier().copy(input.as_bytes()).await?;
} }
Commands::Remote { command } => match command { Commands::Remote { command } => match command {
RemoteCommands::Copy {} => todo!(), RemoteCommands::Copy { remote_host } => {
let mut input = String::new();
std::io::stdin()
.read_to_string(&mut input)
.context("failed to read from stdin")?;
if input.is_empty() {
tracing::info!("no content to put in clipboard");
return Ok(());
}
tracing::debug!(content = &input, "found content");
state
.remote_copier(&remote_host)
.copy(input.as_bytes())
.await?;
}
}, },
_ => (), _ => (),
} }

View File

@ -0,0 +1,50 @@
use tonic::transport::{Channel, ClientTlsConfig};
use crate::{grpc::CopyRequest, state::State};
#[derive(Default)]
pub struct RemoteCopier {
host: String,
}
impl RemoteCopier {
pub fn new(remote_host: impl Into<String>) -> Self {
Self {
host: remote_host.into(),
}
}
pub async fn copy(&self, input: &[u8]) -> anyhow::Result<()> {
let tls = ClientTlsConfig::new();
let channel = Channel::from_shared(self.host.clone())?
.tls_config(if self.host.starts_with("https") {
tls.with_native_roots()
} else {
tls
})?
.connect()
.await?;
tracing::debug!("establishing connection to remote");
let mut client = crate::grpc::void_pin_client::VoidPinClient::new(channel);
tracing::info!("sending copy request");
client
.copy(CopyRequest {
content: input.into(),
})
.await?;
tracing::info!("sent copy request");
Ok(())
}
}
pub trait RemoteCopierState {
fn remote_copier(&self, host: impl Into<String>) -> RemoteCopier;
}
impl RemoteCopierState for State {
fn remote_copier(&self, host: impl Into<String>) -> RemoteCopier {
RemoteCopier::new(host)
}
}