19 Commits

Author SHA1 Message Date
20254d1e2e fix(deps): update rust crate tonic to 0.14.0
Some checks failed
renovate/artifacts Artifact file update failure
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2025-11-29 05:03:22 +00:00
b130ee0d4b chore(deps): update tokio-tracing monorepo
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-11-29 02:09:11 +00:00
9b69517093 chore(deps): update rust crate clap to v4.5.53
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-11-20 02:04:55 +00:00
e806b99035 chore(deps): update rust crate clap to v4.5.52
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-11-18 02:03:49 +00:00
64220bea63 fix(deps): update rust crate bytes to v1.11.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-11-15 02:03:49 +00:00
e75c4c4825 fix(deps): update rust crate serde to v1.0.228
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-11-14 02:00:48 +00:00
ad605fc173 fix(deps): update all dependencies
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-11-13 04:52:19 +00:00
7c15f73d1f chore(deps): update rust crate tracing-subscriber to v0.3.20
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-11-13 02:49:12 +00:00
d1fbc70b40 chore(release): v0.0.4 (#22)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
chore(release): 0.0.4

Co-authored-by: cuddle-please <bot@cuddle.sh>
Reviewed-on: #22
2025-08-03 14:37:13 +02:00
f060e9d2ca feat: pipe output
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-03 14:32:52 +02:00
05b34fd7ee feat: replace bytes with string to avoid endianness
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-03 13:38:42 +02:00
97f5c3a500 feat: sanitise output
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-03 13:33:31 +02:00
404e393b97 chore: add print to output from paste
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-03 13:29:36 +02:00
838cd9d6b1 feat: replace output spawn with native tokio method
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-03 13:03:57 +02:00
50a929d883 chore(release): v0.0.3 (#21)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
chore(release): 0.0.3

Co-authored-by: cuddle-please <bot@cuddle.sh>
Reviewed-on: #21
2025-08-03 12:45:21 +02:00
f982f094be feat: don't use front
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-03 12:45:01 +02:00
4408c1839e test commit
Some checks failed
continuous-integration/drone/push Build is failing
2025-08-03 12:39:14 +02:00
bef15cb280 feat: add paste command both local and remote
Some checks failed
continuous-integration/drone/push Build is failing
2025-08-03 12:30:07 +02:00
3e27fb2847 feat: add publish 2025-08-03 12:11:17 +02:00
12 changed files with 349 additions and 160 deletions

View File

@@ -6,6 +6,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.0.4] - 2025-08-03
### Added
- pipe output
- replace bytes with string to avoid endianness
- sanitise output
- replace output spawn with native tokio method
### Other
- add print to output from paste
## [0.0.3] - 2025-08-03
### Added
- don't use front
- add paste command both local and remote
- add publish
### Other
- test commit
## [0.0.2] - 2025-08-02 ## [0.0.2] - 2025-08-02
### Added ### Added

223
Cargo.lock generated
View File

@@ -3,20 +3,14 @@
version = 4 version = 4
[[package]] [[package]]
name = "addr2line" name = "aho-corasick"
version = "0.24.2" version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [ dependencies = [
"gimli", "memchr",
] ]
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.19" version = "0.6.19"
@@ -69,9 +63,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.98" version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]] [[package]]
name = "async-stream" name = "async-stream"
@@ -97,9 +91,9 @@ dependencies = [
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.88" version = "0.1.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -165,21 +159,6 @@ dependencies = [
"tower-service", "tower-service",
] ]
[[package]]
name = "backtrace"
version = "0.3.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets",
]
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.22.1" version = "0.22.1"
@@ -200,9 +179,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.10.1" version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
[[package]] [[package]]
name = "cc" name = "cc"
@@ -221,9 +200,9 @@ checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.42" version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882" checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@@ -231,9 +210,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.42" version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966" checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@@ -243,9 +222,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.5.41" version = "4.5.49"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
@@ -367,12 +346,6 @@ dependencies = [
"wasi 0.14.2+wasi-0.2.4", "wasi 0.14.2+wasi-0.2.4",
] ]
[[package]]
name = "gimli"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.4.11" version = "0.4.11"
@@ -505,7 +478,7 @@ dependencies = [
"hyper", "hyper",
"libc", "libc",
"pin-project-lite", "pin-project-lite",
"socket2 0.6.0", "socket2 0.5.10",
"tokio", "tokio",
"tower-service", "tower-service",
"tracing", "tracing",
@@ -531,17 +504,6 @@ dependencies = [
"hashbrown 0.15.4", "hashbrown 0.15.4",
] ]
[[package]]
name = "io-uring"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4"
dependencies = [
"bitflags",
"cfg-if",
"libc",
]
[[package]] [[package]]
name = "is_terminal_polyfill" name = "is_terminal_polyfill"
version = "1.70.1" version = "1.70.1"
@@ -601,6 +563,15 @@ version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "matchers"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
"regex-automata",
]
[[package]] [[package]]
name = "matchit" name = "matchit"
version = "0.7.3" version = "0.7.3"
@@ -619,15 +590,6 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
]
[[package]] [[package]]
name = "mio" name = "mio"
version = "1.0.4" version = "1.0.4"
@@ -641,21 +603,11 @@ dependencies = [
[[package]] [[package]]
name = "nu-ansi-term" name = "nu-ansi-term"
version = "0.46.0" version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [ dependencies = [
"overload", "windows-sys 0.59.0",
"winapi",
]
[[package]]
name = "object"
version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
dependencies = [
"memchr",
] ]
[[package]] [[package]]
@@ -676,12 +628,6 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.4" version = "0.12.4"
@@ -847,6 +793,23 @@ dependencies = [
"bitflags", "bitflags",
] ]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]] [[package]]
name = "ring" name = "ring"
version = "0.17.14" version = "0.17.14"
@@ -861,12 +824,6 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "rustc-demangle"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.31" version = "0.23.31"
@@ -969,18 +926,28 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.219" version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.219" version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1083,29 +1050,26 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.47.1" version = "1.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
dependencies = [ dependencies = [
"backtrace",
"bytes", "bytes",
"io-uring",
"libc", "libc",
"mio", "mio",
"parking_lot", "parking_lot",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry", "signal-hook-registry",
"slab",
"socket2 0.6.0", "socket2 0.6.0",
"tokio-macros", "tokio-macros",
"windows-sys 0.59.0", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "2.5.0" version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1227,9 +1191,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.41" version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647"
dependencies = [ dependencies = [
"log", "log",
"pin-project-lite", "pin-project-lite",
@@ -1239,9 +1203,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-attributes" name = "tracing-attributes"
version = "0.1.30" version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1250,9 +1214,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.34" version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"valuable", "valuable",
@@ -1271,14 +1235,18 @@ dependencies = [
[[package]] [[package]]
name = "tracing-subscriber" name = "tracing-subscriber"
version = "0.3.19" version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
dependencies = [ dependencies = [
"matchers",
"nu-ansi-term", "nu-ansi-term",
"once_cell",
"regex-automata",
"sharded-slab", "sharded-slab",
"smallvec", "smallvec",
"thread_local", "thread_local",
"tracing",
"tracing-core", "tracing-core",
"tracing-log", "tracing-log",
] ]
@@ -1309,9 +1277,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.17.0" version = "1.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
dependencies = [ dependencies = [
"getrandom 0.3.3", "getrandom 0.3.3",
"js-sys", "js-sys",
@@ -1326,7 +1294,7 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]] [[package]]
name = "voidpin" name = "voidpin"
version = "0.0.1" version = "0.0.4"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@@ -1426,26 +1394,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "winapi" name = "windows-link"
version = "0.3.9" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
@@ -1465,6 +1417,15 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.6" version = "0.52.6"

View File

@@ -3,7 +3,7 @@ members = ["crates/*"]
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
version = "0.0.2" version = "0.0.4"
[workspace.dependencies] [workspace.dependencies]
voidpin = { path = "crates/voidpin" } voidpin = { path = "crates/voidpin" }

View File

@@ -1,6 +1,11 @@
[package] [package]
name = "voidpin" name = "voidpin"
edition = "2024" edition = "2024"
readme = "../../README.md"
license = "MIT"
authors = ["kjuulh <contact@kasperhermansen.com>"]
repository = "https://git.kjuulh.io/kjuulh/voidpin.git"
description = "Voidpin allows sending copy/paste commands across the wire. It is specifically intended for use in ssh tunnels for long running sessions, where you want to share a clipboard. The primary use case is when a remote machine is used for development, but clipboard continues to be an ergonomic hurdle."
version.workspace = true version.workspace = true
@@ -8,13 +13,13 @@ version.workspace = true
anyhow.workspace = true anyhow.workspace = true
tokio.workspace = true tokio.workspace = true
tracing.workspace = true tracing.workspace = true
tracing-subscriber.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"] }
clap.workspace = true clap.workspace = true
dotenv.workspace = true 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"] } tonic = { version = "0.14.0", features = ["tls", "tls-roots"] }
prost = "0.13.4" prost = "0.13.4"
prost-types = "0.13.4" prost-types = "0.13.4"
bytes = "1.9.0" bytes = "1.9.0"

View File

@@ -2,12 +2,20 @@ syntax = "proto3";
package voidpin.v1; package voidpin.v1;
service VoidPin {
rpc Copy(CopyRequest) returns (CopyResponse);
}
message CopyRequest { message CopyRequest {
bytes content = 1; string content = 1;
} }
message CopyResponse {} message CopyResponse {}
message PasteRequest {
}
message PasteResponse {
string content = 1;
}
service VoidPin {
rpc Copy(CopyRequest) returns (CopyResponse);
rpc Paste(PasteRequest) returns (PasteResponse);
}

View File

@@ -1,7 +1,7 @@
use std::process::Stdio; use std::process::Stdio;
use anyhow::Context; use anyhow::Context;
use tokio::io::AsyncWriteExt; use tokio::io::{AsyncReadExt, AsyncWriteExt};
use crate::state::State; use crate::state::State;
@@ -30,10 +30,6 @@ impl LocalCopier {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
let mut copy_process = { let mut copy_process = {
todo!("windows not supported yet"); todo!("windows not supported yet");
tokio::process::Command::new("wl-copy")
.stdin(Stdio::piped())
.spawn()?
}; };
if let Some(mut stdin_handle) = copy_process.stdin.take() { if let Some(mut stdin_handle) = copy_process.stdin.take() {
@@ -52,6 +48,41 @@ impl LocalCopier {
Ok(()) Ok(())
} }
pub async fn paste(&self) -> anyhow::Result<Vec<u8>> {
// FIXME: hardcode for macos
#[cfg(target_os = "macos")]
let paste_process = {
tokio::process::Command::new("pbpaste")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?
};
#[cfg(target_os = "linux")]
let mut paste_process = {
tokio::process::Command::new("wl-paste")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?
};
#[cfg(target_os = "windows")]
let mut paste_process = {
todo!("windows not supported yet");
};
let output = paste_process.wait_with_output().await?;
if !output.status.success() {
anyhow::bail!(
"output failed with: {}, {}, exit_code: {}",
std::str::from_utf8(&output.stdout).unwrap_or_default(),
std::str::from_utf8(&output.stderr).unwrap_or_default(),
output.status.code().unwrap_or_default(),
)
}
Ok(output.stdout)
}
} }
pub trait LocalCopierState { pub trait LocalCopierState {

View File

@@ -3,12 +3,22 @@
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct CopyRequest { pub struct CopyRequest {
#[prost(bytes="vec", tag="1")] #[prost(string, tag="1")]
pub content: ::prost::alloc::vec::Vec<u8>, pub content: ::prost::alloc::string::String,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, Copy, PartialEq, ::prost::Message)] #[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct CopyResponse { pub struct CopyResponse {
} }
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct PasteRequest {
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PasteResponse {
#[prost(string, tag="1")]
pub content: ::prost::alloc::string::String,
}
include!("voidpin.v1.tonic.rs"); include!("voidpin.v1.tonic.rs");
// @@protoc_insertion_point(module) // @@protoc_insertion_point(module)

View File

@@ -105,6 +105,26 @@ pub mod void_pin_client {
req.extensions_mut().insert(GrpcMethod::new("voidpin.v1.VoidPin", "Copy")); req.extensions_mut().insert(GrpcMethod::new("voidpin.v1.VoidPin", "Copy"));
self.inner.unary(req, path, codec).await self.inner.unary(req, path, codec).await
} }
///
pub async fn paste(
&mut self,
request: impl tonic::IntoRequest<super::PasteRequest>,
) -> std::result::Result<tonic::Response<super::PasteResponse>, 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/Paste");
let mut req = request.into_request();
req.extensions_mut().insert(GrpcMethod::new("voidpin.v1.VoidPin", "Paste"));
self.inner.unary(req, path, codec).await
}
} }
} }
/// Generated server implementations. /// Generated server implementations.
@@ -119,6 +139,11 @@ pub mod void_pin_server {
&self, &self,
request: tonic::Request<super::CopyRequest>, request: tonic::Request<super::CopyRequest>,
) -> std::result::Result<tonic::Response<super::CopyResponse>, tonic::Status>; ) -> std::result::Result<tonic::Response<super::CopyResponse>, tonic::Status>;
///
async fn paste(
&self,
request: tonic::Request<super::PasteRequest>,
) -> std::result::Result<tonic::Response<super::PasteResponse>, tonic::Status>;
} }
/// ///
#[derive(Debug)] #[derive(Debug)]
@@ -244,6 +269,50 @@ pub mod void_pin_server {
}; };
Box::pin(fut) Box::pin(fut)
} }
"/voidpin.v1.VoidPin/Paste" => {
#[allow(non_camel_case_types)]
struct PasteSvc<T: VoidPin>(pub Arc<T>);
impl<T: VoidPin> tonic::server::UnaryService<super::PasteRequest>
for PasteSvc<T> {
type Response = super::PasteResponse;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<super::PasteRequest>,
) -> Self::Future {
let inner = Arc::clone(&self.0);
let fut = async move {
<T as VoidPin>::paste(&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 = PasteSvc(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 { Box::pin(async move {
Ok( Ok(

View File

@@ -1,4 +1,8 @@
use crate::{copy::LocalCopierState, state::State}; use crate::{
copy::LocalCopierState,
grpc::{PasteRequest, PasteResponse},
state::State,
};
#[derive(Clone)] #[derive(Clone)]
pub struct GrpcServer { pub struct GrpcServer {
@@ -21,10 +25,26 @@ impl crate::grpc::void_pin_server::VoidPin for GrpcServer {
self.state self.state
.local_copier() .local_copier()
.copy(&req.content) .copy(&req.content.as_bytes())
.await .await
.map_err(|e| tonic::Status::internal(e.to_string()))?; .map_err(|e| tonic::Status::internal(e.to_string()))?;
Ok(tonic::Response::new(crate::grpc::CopyResponse {})) Ok(tonic::Response::new(crate::grpc::CopyResponse {}))
} }
async fn paste(
&self,
_request: tonic::Request<PasteRequest>,
) -> std::result::Result<tonic::Response<PasteResponse>, tonic::Status> {
let output = self
.state
.local_copier()
.paste()
.await
.map_err(|e| tonic::Status::internal(e.to_string()))?;
Ok(tonic::Response::new(crate::grpc::PasteResponse {
content: String::from_utf8_lossy(&output).to_string(),
}))
}
} }

View File

@@ -7,7 +7,9 @@ use grpc::void_pin_server::VoidPinServer;
use grpc_server::GrpcServer; use grpc_server::GrpcServer;
use remote_copy::RemoteCopierState; use remote_copy::RemoteCopierState;
use state::State; use state::State;
use tokio::io::AsyncWriteExt;
use tonic::transport; use tonic::transport;
use tracing_subscriber::EnvFilter;
mod grpc { mod grpc {
include!("gen/voidpin.v1.rs"); include!("gen/voidpin.v1.rs");
@@ -33,6 +35,7 @@ enum Commands {
grpc: SocketAddr, grpc: SocketAddr,
}, },
Copy {}, Copy {},
Paste {},
Remote { Remote {
#[command(subcommand)] #[command(subcommand)]
command: RemoteCommands, command: RemoteCommands,
@@ -49,12 +52,27 @@ enum RemoteCommands {
)] )]
remote_host: String, remote_host: String,
}, },
Paste {
#[arg(
long = "remote-host",
env = "VOIDPIN_REMOTE",
default_value = "http://0.0.0.0:7900"
)]
remote_host: String,
},
} }
#[tokio::main] #[tokio::main]
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
dotenv::dotenv().ok(); dotenv::dotenv().ok();
tracing_subscriber::fmt::init(); tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::builder()
//.with_default_directive("error".parse().unwrap())
.from_env_lossy(),
)
.with_writer(std::io::stderr)
.init();
let cli = Command::parse(); let cli = Command::parse();
tracing::debug!("Starting cli"); tracing::debug!("Starting cli");
@@ -82,10 +100,7 @@ async fn main() -> anyhow::Result<()> {
} }
tracing::debug!(content = &input, "found content"); tracing::debug!(content = &input, "found content");
state state.remote_copier(&remote_host).copy(input).await?;
.remote_copier(&remote_host)
.copy(input.as_bytes())
.await?;
return Ok(()); return Ok(());
} }
@@ -103,6 +118,22 @@ async fn main() -> anyhow::Result<()> {
tracing::debug!(content = &input, "found content"); tracing::debug!(content = &input, "found content");
state.local_copier().copy(input.as_bytes()).await?; state.local_copier().copy(input.as_bytes()).await?;
} }
Commands::Paste {} => {
let mut stdout = tokio::io::stdout();
if let Ok(remote_host) = std::env::var("VOIDPIN_REMOTE") {
let output = state.remote_copier(&remote_host).paste().await?;
stdout.write_all(output.as_bytes()).await?;
stdout.flush().await?;
return Ok(());
}
let output = state.local_copier().paste().await?;
stdout.write_all(&output).await?;
stdout.flush().await?;
}
Commands::Remote { command } => match command { Commands::Remote { command } => match command {
RemoteCommands::Copy { remote_host } => { RemoteCommands::Copy { remote_host } => {
let mut input = String::new(); let mut input = String::new();
@@ -116,10 +147,14 @@ async fn main() -> anyhow::Result<()> {
} }
tracing::debug!(content = &input, "found content"); tracing::debug!(content = &input, "found content");
state state.remote_copier(&remote_host).copy(input).await?;
.remote_copier(&remote_host) }
.copy(input.as_bytes()) RemoteCommands::Paste { remote_host } => {
.await?; let output = state.remote_copier(&remote_host).paste().await?;
let mut stdout = tokio::io::stdout();
stdout.write_all(output.as_bytes()).await?;
stdout.flush().await?;
} }
}, },
} }

View File

@@ -1,6 +1,9 @@
use tonic::transport::{Channel, ClientTlsConfig}; use tonic::transport::{Channel, ClientTlsConfig};
use crate::{grpc::CopyRequest, state::State}; use crate::{
grpc::{CopyRequest, PasteRequest},
state::State,
};
#[derive(Default)] #[derive(Default)]
pub struct RemoteCopier { pub struct RemoteCopier {
@@ -14,7 +17,7 @@ impl RemoteCopier {
} }
} }
pub async fn copy(&self, input: &[u8]) -> anyhow::Result<()> { pub async fn copy(&self, input: String) -> anyhow::Result<()> {
let tls = ClientTlsConfig::new(); let tls = ClientTlsConfig::new();
let channel = Channel::from_shared(self.host.clone())? let channel = Channel::from_shared(self.host.clone())?
.tls_config(if self.host.starts_with("https") { .tls_config(if self.host.starts_with("https") {
@@ -37,6 +40,29 @@ impl RemoteCopier {
Ok(()) Ok(())
} }
pub async fn paste(&self) -> anyhow::Result<String> {
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 paste request");
let resp = client.paste(PasteRequest {}).await?;
let output = resp.into_inner().content;
tracing::info!(content = output, "received paste response");
Ok(output)
}
} }
pub trait RemoteCopierState { pub trait RemoteCopierState {

View File

@@ -5,6 +5,8 @@ base: "git@git.front.kjuulh.io:kjuulh/cuddle-rust-cli-plan.git"
vars: vars:
service: "voidpin" service: "voidpin"
registry: kasperhermansen registry: kasperhermansen
rust:
publish: {}
please: please:
project: project:
@@ -12,6 +14,6 @@ please:
repository: "voidpin" repository: "voidpin"
branch: "main" branch: "main"
settings: settings:
api_url: "https://git.front.kjuulh.io" api_url: "https://git.kjuulh.io"
actions: actions:
rust: rust: