From 25fa9818961f23fb0b20361fb8707c358924c05c Mon Sep 17 00:00:00 2001 From: Simon Struck Date: Wed, 11 Nov 2020 23:36:23 +0100 Subject: [PATCH] First release --- .gitignore | 2 + Cargo.lock | 194 +++++++++++++++++++++++++++++++- Cargo.toml | 2 + LICENSE | 21 ++++ Readme.md | 37 ++++++ build_pack.sh | 29 +++++ build_push_run.sh | 2 +- images/wiriting_test_canvas.png | Bin 0 -> 34112 bytes release/install.sh | 18 +++ release/pipes-and-rust.service | 10 ++ res/index.html | 10 +- src/main.rs | 20 +++- 12 files changed, 335 insertions(+), 10 deletions(-) create mode 100644 LICENSE create mode 100644 Readme.md create mode 100755 build_pack.sh create mode 100644 images/wiriting_test_canvas.png create mode 100755 release/install.sh create mode 100644 release/pipes-and-rust.service diff --git a/.gitignore b/.gitignore index bba7b53..d642a68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target/ /.idea/ +/release/pipes-and-rust +/*.zip diff --git a/Cargo.lock b/Cargo.lock index 0da5e85..b2877d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,6 +70,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -103,7 +109,27 @@ checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "hermit-abi" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" +dependencies = [ + "bytes", + "fnv", + "itoa", ] [[package]] @@ -132,6 +158,12 @@ dependencies = [ "libc", ] +[[package]] +name = "itoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -154,6 +186,15 @@ version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" +[[package]] +name = "log" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" +dependencies = [ + "log 0.4.11", +] + [[package]] name = "log" version = "0.4.11" @@ -181,7 +222,7 @@ dependencies = [ "iovec", "kernel32-sys", "libc", - "log", + "log 0.4.11", "miow", "net2", "slab", @@ -195,7 +236,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" dependencies = [ "lazycell", - "log", + "log 0.4.11", "mio", "slab", ] @@ -223,6 +264,16 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "opaque-debug" version = "0.2.3" @@ -239,6 +290,8 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" name = "pipes-and-rust" version = "0.1.0" dependencies = [ + "rust-embed", + "simple-server", "ws", ] @@ -248,6 +301,24 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rand" version = "0.7.3" @@ -289,6 +360,53 @@ dependencies = [ "rand_core", ] +[[package]] +name = "rust-embed" +version = "5.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213acf1bc5a6dfcd70b62db1e9a7d06325c0e73439c312fcb8599d456d9686ee" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "5.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7903c2cf599db8f310b392332f38367ca4acc84420fa1aee3536299f433c10d5" +dependencies = [ + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97655158074ccb2d2cfb1ccb4c956ef0f4054e43a2c1e71146d4991e6961e105" +dependencies = [ + "walkdir", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" + [[package]] name = "sha-1" version = "0.8.2" @@ -301,12 +419,48 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "simple-server" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47624fcb3e3416bd7f764b2319875043ce22b0eff78f5c7684de07c88ba5761" +dependencies = [ + "http", + "httparse", + "log 0.3.9", + "num_cpus", + "scoped_threadpool", + "time", +] + [[package]] name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +[[package]] +name = "syn" +version = "1.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi 0.3.9", +] + [[package]] name = "tinyvec" version = "0.3.4" @@ -337,6 +491,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + [[package]] name = "url" version = "2.1.1" @@ -348,12 +508,29 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "walkdir" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +dependencies = [ + "same-file", + "winapi 0.3.9", + "winapi-util", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "winapi" version = "0.2.8" @@ -382,6 +559,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -397,7 +583,7 @@ dependencies = [ "byteorder", "bytes", "httparse", - "log", + "log 0.4.11", "mio", "mio-extras", "rand", diff --git a/Cargo.toml b/Cargo.toml index 5f9ccee..b1f70dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,5 @@ edition = "2018" [dependencies] ws = "0.9.1" +rust-embed = "5.6.0" +simple-server = "0.4.0" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..653576e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Simon Struck + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..e8e1768 --- /dev/null +++ b/Readme.md @@ -0,0 +1,37 @@ +# Pipes and Rust + +Draw on a html canvas directly from your reMarkable 2. + +![](images/wiriting_test_canvas.png) + +# Usage + +1. Install the software with one of the methods below. +2. Connect to http://remarkable (or device IP) +3. Done! + +# Requirements + +1. SSH access to the reMarkable for installation +2. (when building from source) Rust + +# Installation (from Binary) + +1. Download the [latest release](https://github.com/AnyTimeTraveler/pipes-and-rust/releases) +2. Set IP or hostname in `install.sh` +3. Run install.sh + +# Installation (from Source) + +1. Install [Rust](https://rustup.rs/) +2. Install [Cross](https://github.com/rust-embedded/cross) to build for armv7 +3. Set hostname in `build_push_run.sh` +4. Run `build_push_run.sh` with either 'debug' or 'release' as parameter + +# Credits + +This work is based on [pipes-and-paper](https://gitlab.com/afandian/pipes-and-paper) by Joe Wass and uses his code to read the stylus coordinates. + +# License + +MIT-License diff --git a/build_pack.sh b/build_pack.sh new file mode 100755 index 0000000..fbad243 --- /dev/null +++ b/build_pack.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env zsh + +if [ $# -ne 1 ]; then + echo "parameter 'debug' or 'release' required" + exit +fi + +build_type="$1" +arch="armv7-unknown-linux-musleabihf" +#arch="armv7-unknown-linux-gnueabihf" + +echo "Compiling..." +if [ "$build_type" = "release" ]; then + cross build --target "$arch" --release +else + cross build --target "$arch" +fi +echo "Done" + +# shellcheck disable=SC2181 +if [ $? -eq 0 ]; then + echo "Copying to directory..." + cp "./target/$arch/$build_type/pipes-and-rust" "release/pipes-and-rust" + echo "Done" +fi + +version="$(grep 'version' Cargo.toml | head -n 1 | cut -d\" -f2)" + +(cd release && zip "../pipes-and-rust-release-$version.zip" ./install.sh ./pipes-and-rust ./pipes-and-rust.service) diff --git a/build_push_run.sh b/build_push_run.sh index ad2e2e0..d75d57c 100755 --- a/build_push_run.sh +++ b/build_push_run.sh @@ -19,5 +19,5 @@ if [ $? -eq 0 ]; then ssh remarkable "killall pipes-and-rust" echo "Done" echo "Copying to device..." - scp "./target/$arch/$version/pipes-and-rust" "$host:" && echo "Done" && ssh "$host" "./pipes-and-rust" + scp "./target/$arch/$version/pipes-and-rust" "$host:/opt/pipes-and-rust" && echo "Done" && ssh "$host" "/opt/pipes-and-rust" fi diff --git a/images/wiriting_test_canvas.png b/images/wiriting_test_canvas.png new file mode 100644 index 0000000000000000000000000000000000000000..7712493eb7c1abf4d744bf4950662b08e3a3afd1 GIT binary patch literal 34112 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 H&bt2s#g{0I literal 0 HcmV?d00001 diff --git a/release/install.sh b/release/install.sh new file mode 100755 index 0000000..9add973 --- /dev/null +++ b/release/install.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env sh + +# Set hostname or ip address of your reMarkable +host="remarkable" + + + +ssh "$host" "mkdir -p /opt/" +echo "Copying files to device..." +scp "./pipes-and-rust" "$host:/opt/pipes-and-rust" || exit +scp "./pipes-and-rust.service" "$host:/lib/systemd/system/pipes-and-rust.service" || exit +echo "Done" + +echo "Installing service..." +ssh "$host" "systemctl daemon-reload" || exit +ssh "$host" "systemctl enable pipes-and-rust.service" || exit +ssh "$host" "systemctl start pipes-and-rust.service" || exit +echo "Done" diff --git a/release/pipes-and-rust.service b/release/pipes-and-rust.service new file mode 100644 index 0000000..8cd34d6 --- /dev/null +++ b/release/pipes-and-rust.service @@ -0,0 +1,10 @@ +[Unit] +Description=pipes-and-rust +After=home.mount + +[Service] +ExecStart=/opt/pipes-and-rust +Restart=never + +[Install] +WantedBy=multi-user.target diff --git a/res/index.html b/res/index.html index 528745c..775120a 100644 --- a/res/index.html +++ b/res/index.html @@ -6,7 +6,7 @@ - +
Status:
not yet connected
@@ -16,6 +16,7 @@
+

Enter to clear screen

diff --git a/src/main.rs b/src/main.rs index 9258940..bf41f49 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,28 @@ +extern crate simple_server; + use std::fs::File; use std::io::Read; use std::thread; +use rust_embed::RustEmbed; +use simple_server::Server; use ws::{listen, Message}; +#[derive(RustEmbed)] +#[folder = "res/"] +struct Asset; + fn main() { - println!("Listening..."); + let server = Server::new(|_, mut response| { + Ok(response.body(Vec::from(Asset::get("index.html").unwrap()))?) + }); + + thread::spawn(move || { + println!("Listening for http connections on port 80..."); + server.listen("0.0.0.0", "80"); + }); + + println!("Listening for websocket connections on port 55555..."); listen("0.0.0.0:55555", |out| { thread::Builder::new() .name(format!("connection_handler_{}", out.connection_id())) @@ -45,5 +62,4 @@ fn main() { Ok(()) } }).unwrap(); - println!("Ended!"); }