Move filewatcher to own repo (#423)
This commit is contained in:
parent
4e2bed4131
commit
ea220f36a8
7 changed files with 3 additions and 784 deletions
|
|
@ -19,7 +19,9 @@ Currently the following pods are available:
|
|||
|
||||
- [clj-kondo](https://github.com/borkdude/clj-kondo/#babashka-pod): a Clojure
|
||||
linter
|
||||
- [pod-babashka-hsqldb](https://github.com/borkdude/pod-babashka-hsqldb): a pod
|
||||
- [pod-babashka-filewatcher](https://github.com/babashka/pod-babashka-hsqldb): a
|
||||
filewatcher pod based on Rust notify.
|
||||
- [pod-babashka-hsqldb](https://github.com/babashka/pod-babashka-hsqldb): a pod
|
||||
that allows you to create and fire queries at a
|
||||
[HSQLDB](http://www.hsqldb.org/) database.
|
||||
|
||||
|
|
@ -39,9 +41,6 @@ can be found [here](../examples/pods):
|
|||
allows you to create and fire queries at a [sqlite](https://www.sqlite.org/)
|
||||
database. Implemented in Python.
|
||||
|
||||
- [pod-babashka-filewatcher](../examples/pods/pod-babashka-filewatcher): a
|
||||
filewatcher pod. Implemented in Rust.
|
||||
|
||||
### Naming
|
||||
|
||||
When choosing a name for your pod, we suggest the following naming scheme:
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
/target
|
||||
292
examples/pods/pod-babashka-filewatcher/Cargo.lock
generated
292
examples/pods/pod-babashka-filewatcher/Cargo.lock
generated
|
|
@ -1,292 +0,0 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f59efc38004c988e4201d11d263b8171f49a2e7ec0bdbb71773433f271504a5e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fsevent-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fuchsia-zircon-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24e40d6fd5d64e2082e0c796495c8ef5ad667a96d03e5aaa0becfd9d47bcbfb8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "json"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fuchsia-zircon",
|
||||
"fuchsia-zircon-sys",
|
||||
"iovec",
|
||||
"kernel32-sys",
|
||||
"libc",
|
||||
"log",
|
||||
"miow",
|
||||
"net2",
|
||||
"slab",
|
||||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-extras"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
|
||||
dependencies = [
|
||||
"lazycell",
|
||||
"log",
|
||||
"mio",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
dependencies = [
|
||||
"kernel32-sys",
|
||||
"net2",
|
||||
"winapi 0.2.8",
|
||||
"ws2_32-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "4.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"filetime",
|
||||
"fsevent",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"libc",
|
||||
"mio",
|
||||
"mio-extras",
|
||||
"walkdir",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pod-babashka-filewatcher"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"json",
|
||||
"log",
|
||||
"notify",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
|
||||
[[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 = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
||||
[[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.8",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
[[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-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
[package]
|
||||
name = "pod-babashka-filewatcher"
|
||||
version = "0.1.0"
|
||||
authors = ["Michiel Borkent <michielborkent@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
notify = "4.0.12"
|
||||
json = "0.12.4"
|
||||
log = "0.4"
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# pod-babashka-filewatcher
|
||||
|
||||
## Compile
|
||||
|
||||
```
|
||||
$ cargo build --release
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
``` clojure
|
||||
(babashka.pods/load-pod "target/release/pod-babashka-filewatcher")
|
||||
(def chan (pod.babashka.filewatcher/watch "/tmp"))
|
||||
(require '[clojure.core.async :as async])
|
||||
(loop [] (prn (async/<!! chan)) (recur))
|
||||
;;=> ["changed" "/tmp"]
|
||||
;;=> ["changed" "/tmp"]
|
||||
```
|
||||
|
|
@ -1,320 +0,0 @@
|
|||
// from https://github.com/jasilven/redbush/blob/master/src/nrepl/bencode.rs
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::{self, Display};
|
||||
use std::hash::Hash;
|
||||
use std::hash::Hasher;
|
||||
use std::io::BufRead;
|
||||
use std::iter::Iterator;
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
|
||||
type Result<T> = std::result::Result<T, BencodeError>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BencodeError {
|
||||
Error(String),
|
||||
Io(std::io::Error),
|
||||
Eof(),
|
||||
Parse(std::num::ParseIntError),
|
||||
}
|
||||
|
||||
impl Display for BencodeError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
BencodeError::Error(s) => write!(f, "Bencode Error: {} ", s),
|
||||
BencodeError::Io(e) => write!(f, "Bencode Io: {}", e),
|
||||
BencodeError::Parse(e) => write!(f, "Bencode Parse: {}", e),
|
||||
BencodeError::Eof() => write!(f, "Bencode Eof"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for BencodeError {
|
||||
fn from(err: std::io::Error) -> BencodeError {
|
||||
BencodeError::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::num::ParseIntError> for BencodeError {
|
||||
fn from(err: std::num::ParseIntError) -> BencodeError {
|
||||
BencodeError::Parse(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq)]
|
||||
pub struct HMap(pub HashMap<Value, Value>);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Value {
|
||||
Map(HMap),
|
||||
List(Vec<Value>),
|
||||
Str(String),
|
||||
Int(i32),
|
||||
}
|
||||
|
||||
impl From<&str> for Value {
|
||||
fn from(s: &str) -> Self {
|
||||
Value::Str(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HashMap<Value, Value>> for Value {
|
||||
fn from(m: HashMap<Value, Value>) -> Self {
|
||||
Value::Map(HMap::new(m))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HashMap<&str, &str>> for Value {
|
||||
fn from(map: HashMap<&str, &str>) -> Self {
|
||||
let mut m = HashMap::new();
|
||||
for (k, v) in map {
|
||||
m.insert(Value::Str(k.to_string()), Value::Str(v.to_string()));
|
||||
}
|
||||
let hm = HMap::new(m);
|
||||
Value::Map(hm)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<HashMap<String, String>> for Value {
|
||||
type Error = BencodeError;
|
||||
|
||||
fn try_into(self) -> std::result::Result<HashMap<String, String>, Self::Error> {
|
||||
match self {
|
||||
Value::Map(hm) => {
|
||||
let mut map = HashMap::<String, String>::new();
|
||||
for key in hm.0.keys() {
|
||||
// safe to unwrap here
|
||||
map.insert(format!("{}", &key), format!("{}", &hm.get(key).unwrap()));
|
||||
}
|
||||
Ok(map)
|
||||
}
|
||||
_ => Err(BencodeError::Error("Expected HashMap Value".into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HMap {
|
||||
pub fn new(map: HashMap<Value, Value>) -> Self {
|
||||
HMap(map)
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &Value) -> Option<&Value> {
|
||||
self.0.get(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for HMap {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let mut keys: Vec<String> = self.0.keys().map(|k| format!("{:?}", k)).collect();
|
||||
let mut vals: Vec<String> = self.0.values().map(|v| format!("{:?}", v)).collect();
|
||||
keys.sort();
|
||||
vals.sort();
|
||||
keys.hash(state);
|
||||
vals.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for HMap {
|
||||
fn eq(&self, other: &HMap) -> bool {
|
||||
self.0.eq(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Value {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Value::Map(hm) => {
|
||||
let mut result = String::from("{");
|
||||
for (key, val) in hm.0.iter() {
|
||||
result.push_str(&format!("{} {} ", &key, &val));
|
||||
}
|
||||
let mut result = result.trim_end().to_string();
|
||||
result.push('}');
|
||||
write!(f, "{}", result)
|
||||
}
|
||||
Value::List(v) => {
|
||||
let mut result = String::from("[");
|
||||
for item in v {
|
||||
result.push_str(&item.to_string());
|
||||
result.push_str(", ");
|
||||
}
|
||||
let mut result = result
|
||||
.trim_end_matches(|c| c == ',' || c == ' ')
|
||||
.to_string();
|
||||
result.push(']');
|
||||
write!(f, "{}", result)
|
||||
}
|
||||
Value::Str(s) => write!(f, "{}", s),
|
||||
Value::Int(i) => write!(f, "{}", i),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn to_bencode(&self) -> String {
|
||||
match self {
|
||||
Value::Map(hm) => {
|
||||
let mut result = String::from("d");
|
||||
for (key, val) in hm.0.iter() {
|
||||
result.push_str(&format!("{}{}", key.to_bencode(), val.to_bencode()));
|
||||
}
|
||||
result.push('e');
|
||||
result
|
||||
}
|
||||
Value::List(v) => {
|
||||
let mut result = String::from("l");
|
||||
for item in v {
|
||||
result.push_str(&item.to_bencode());
|
||||
}
|
||||
result.push('e');
|
||||
result
|
||||
}
|
||||
Value::Str(s) => format!("{}:{}", s.len(), s),
|
||||
Value::Int(i) => format!("i{}e", i),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_bencode(reader: &mut dyn BufRead) -> Result<Option<Value>> {
|
||||
log::debug!("Parsing bencode from reader");
|
||||
|
||||
let mut buf = vec![];
|
||||
buf.resize(1, 0);
|
||||
match reader.read_exact(&mut buf[0..1]) {
|
||||
Ok(()) => match buf[0] {
|
||||
b'i' => match reader.read_until(b'e', &mut buf) {
|
||||
Ok(cnt) => {
|
||||
let s = String::from_utf8_lossy(&buf[1..cnt]);
|
||||
let n = i32::from_str(&s)?;
|
||||
Ok(Some(Value::Int(n)))
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
},
|
||||
b'd' => {
|
||||
let mut map = HashMap::new();
|
||||
loop {
|
||||
match parse_bencode(reader) {
|
||||
Ok(None) => return Ok(Some(Value::Map(HMap(map)))),
|
||||
Ok(Some(v)) => map.insert(v, parse_bencode(reader)?.unwrap()),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
}
|
||||
}
|
||||
b'l' => {
|
||||
let mut list = Vec::<Value>::new();
|
||||
loop {
|
||||
match parse_bencode(reader) {
|
||||
Ok(None) => return Ok(Some(Value::List(list))),
|
||||
Ok(Some(v)) => list.push(v),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
b'e' => Ok(None),
|
||||
b'0' => {
|
||||
reader.read_until(b':', &mut buf)?;
|
||||
Ok(Some(Value::Str("".to_string())))
|
||||
}
|
||||
_ => match reader.read_until(b':', &mut buf) {
|
||||
Ok(_) => {
|
||||
buf.resize(buf.len() - 1, 0);
|
||||
let mut s = String::from("");
|
||||
buf.iter().for_each(|i| s.push(*i as char));
|
||||
let cnt = usize::from_str(&s)?;
|
||||
buf.resize(cnt, 0);
|
||||
reader.read_exact(&mut buf[0..cnt])?;
|
||||
Ok(Some(Value::Str(
|
||||
String::from_utf8_lossy(&buf[..]).to_string(),
|
||||
)))
|
||||
}
|
||||
Err(e) => Err(BencodeError::Io(e)),
|
||||
},
|
||||
},
|
||||
Err(e) => match e.kind() {
|
||||
std::io::ErrorKind::UnexpectedEof => (Err(BencodeError::Eof())),
|
||||
_ => Err(BencodeError::Io(e)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::io::BufReader;
|
||||
|
||||
#[test]
|
||||
fn test_parse_bencode_num() {
|
||||
let left = vec![
|
||||
Value::Int(1),
|
||||
Value::Int(10),
|
||||
Value::Int(100_000),
|
||||
Value::Int(-1),
|
||||
Value::Int(-999),
|
||||
];
|
||||
let right = vec!["i1e", "i10e", "i100000e", "i-1e", "i-999e"];
|
||||
|
||||
for i in 0..left.len() {
|
||||
let mut bufread = BufReader::new(right[i].as_bytes());
|
||||
assert_eq!(left[i], parse_bencode(&mut bufread).unwrap().unwrap());
|
||||
assert_eq!(left[i].to_bencode(), right[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_bencode_str() {
|
||||
let left = vec![
|
||||
Value::Str("foo".to_string()),
|
||||
Value::Str("1234567890\n".to_string()),
|
||||
Value::Str("".to_string()),
|
||||
];
|
||||
let right = vec!["3:foo", "11:1234567890\n", "0:"];
|
||||
for i in 0..left.len() {
|
||||
let mut bufread = BufReader::new(right[i].as_bytes());
|
||||
assert_eq!(left[i], parse_bencode(&mut bufread).unwrap().unwrap());
|
||||
assert_eq!(left[i].to_bencode(), right[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_bencode_list() {
|
||||
let left = vec![
|
||||
(Value::List(vec![Value::Int(1), Value::Int(2), Value::Int(3)])),
|
||||
(Value::List(vec![
|
||||
Value::Int(1),
|
||||
Value::Str("foo".to_string()),
|
||||
Value::Int(3),
|
||||
])),
|
||||
(Value::List(vec![Value::Str("".to_string())])),
|
||||
];
|
||||
let right = vec!["li1ei2ei3ee", "li1e3:fooi3ee", "l0:e"];
|
||||
for i in 0..left.len() {
|
||||
let mut bufread = BufReader::new(right[i].as_bytes());
|
||||
assert_eq!(left[i], parse_bencode(&mut bufread).unwrap().unwrap());
|
||||
assert_eq!(left[i].to_bencode(), right[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_bencode_map() {
|
||||
let mut m1 = HashMap::new();
|
||||
m1.insert(Value::Str("bar".to_string()), Value::Str("baz".to_string()));
|
||||
let m1_c = m1.clone();
|
||||
let left1 = Value::Map(HMap::new(m1));
|
||||
|
||||
let mut m2 = HashMap::new();
|
||||
m2.insert(Value::Str("foo".to_string()), Value::Map(HMap::new(m1_c)));
|
||||
let left2 = Value::Map(HMap::new(m2));
|
||||
|
||||
let sright1 = "d3:bar3:baze".to_string();
|
||||
let mut right1 = BufReader::new(sright1.as_bytes());
|
||||
assert_eq!(left1, parse_bencode(&mut right1).unwrap().unwrap());
|
||||
assert_eq!(left1.to_bencode(), sright1);
|
||||
|
||||
let sright2 = "d3:food3:bar3:bazee".to_string();
|
||||
let mut right2 = BufReader::new(sright2.as_bytes());
|
||||
assert_eq!(left2, parse_bencode(&mut right2).unwrap().unwrap());
|
||||
assert_eq!(left2.to_bencode(), sright2);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
// see https://github.com/jasilven/redbush/blob/master/src/nrepl/mod.rs
|
||||
|
||||
mod bencode;
|
||||
use bencode::{Value};
|
||||
use bencode as bc;
|
||||
|
||||
use notify::{Watcher, RecursiveMode, watcher};
|
||||
use std::sync::mpsc::channel;
|
||||
use std::time::Duration;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::io::{Write, BufReader};
|
||||
|
||||
use json;
|
||||
|
||||
fn get_string(val: &bc::Value, key: &str) -> Option<String> {
|
||||
match val {
|
||||
bc::Value::Map(hm) => {
|
||||
match hm.get(&Value::from(key)) {
|
||||
Some(Value::Str(s)) =>
|
||||
Some(String::from(s)),
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(mut m: HashMap<Value,Value>, k: &str, v: &str) -> HashMap<Value,Value> {
|
||||
m.insert(Value::from(k), Value::from(v));
|
||||
m
|
||||
}
|
||||
|
||||
fn describe() {
|
||||
let namespace = HashMap::new();
|
||||
let mut namespace = insert(namespace, "name", "pod.babashka.filewatcher");
|
||||
let mut vars = Vec::new();
|
||||
let var_map = HashMap::new();
|
||||
let var_map = insert(var_map, "name", "watch");
|
||||
let var_map = insert(var_map, "async", "true");
|
||||
vars.push(Value::from(var_map));
|
||||
namespace.insert(Value::from("vars"),Value::List(vars));
|
||||
let describe_map = HashMap::new();
|
||||
let mut describe_map = insert(describe_map, "format", "json");
|
||||
let namespaces = vec![Value::from(namespace)];
|
||||
let namespaces = Value::List(namespaces);
|
||||
describe_map.insert(Value::from("namespaces"), namespaces);
|
||||
let describe_map = Value::from(describe_map);
|
||||
let bencode = describe_map.to_bencode();
|
||||
let stdout = io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
handle.write_all(bencode.as_bytes()).unwrap();
|
||||
handle.flush().unwrap();
|
||||
}
|
||||
|
||||
fn path_changed(id: &str, path: &str) {
|
||||
let reply = HashMap::new();
|
||||
let reply = insert(reply, "id", id);
|
||||
let value = vec!["changed", path];
|
||||
let value = json::stringify(value);
|
||||
let mut reply = insert(reply, "value", &value);
|
||||
let status = vec![Value::from("status")];
|
||||
reply.insert(Value::from("status"),Value::List(status));
|
||||
let bencode = Value::from(reply).to_bencode();
|
||||
let stdout = io::stdout();
|
||||
let mut handle = stdout.lock();
|
||||
handle.write_all(bencode.as_bytes()).unwrap();
|
||||
handle.flush().unwrap();
|
||||
}
|
||||
|
||||
fn watch(id: &str, path: &str) {
|
||||
let (tx, rx) = channel();
|
||||
let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap();
|
||||
watcher.watch(path, RecursiveMode::Recursive).unwrap();
|
||||
loop {
|
||||
match rx.recv() {
|
||||
Ok(_) => {
|
||||
path_changed(id, path);
|
||||
},
|
||||
Err(e) => panic!("watch error: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn handle_incoming(val: bc::Value) {
|
||||
let op = get_string(&val, "op").unwrap();
|
||||
match &op[..] {
|
||||
"describe" => {
|
||||
describe()
|
||||
|
||||
},
|
||||
"invoke" => {
|
||||
let var = get_string(&val, "var").unwrap();
|
||||
match &var[..] {
|
||||
"pod.babashka.filewatcher/watch" => {
|
||||
let args = get_string(&val, "args").unwrap();
|
||||
let args = json::parse(&args).unwrap();
|
||||
let path = &args[0];
|
||||
let path = path.as_str().unwrap();
|
||||
let id = get_string(&val, "id").unwrap();
|
||||
watch(&id, path);
|
||||
},
|
||||
_ => panic!(var)
|
||||
};
|
||||
},
|
||||
_ => panic!(op)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
|
||||
loop {
|
||||
let mut reader = BufReader::new(io::stdin());
|
||||
let val = bc::parse_bencode(&mut reader);
|
||||
match val {
|
||||
Ok(res) => {
|
||||
match res {
|
||||
Some(val) => {
|
||||
handle_incoming(val)
|
||||
}
|
||||
None => {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Err(bc::BencodeError::Eof()) => {
|
||||
return
|
||||
},
|
||||
Err(v) => panic!("{}", v)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue