1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
use futures; use futures::Async; use std; use std::io::Result as IoResult; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; use tokio_io::{AsyncRead, AsyncWrite}; use std::fs::{File, OpenOptions}; use std::rc::Rc; use super::{BoxedNewPeerFuture, Peer, Result}; use super::{once, ConstructParams, PeerConstructor, Specifier}; #[derive(Clone, Debug)] pub struct ReadFile(pub PathBuf); impl Specifier for ReadFile { fn construct(&self, _: ConstructParams) -> PeerConstructor { fn gp(p: &Path) -> Result<Peer> { let f = File::open(p)?; Ok(Peer::new(ReadFileWrapper(f), super::trivial_peer::DevNull, None)) } once(Box::new(futures::future::result(gp(&self.0))) as BoxedNewPeerFuture) } specifier_boilerplate!(noglobalstate singleconnect no_subspec); } specifier_class!( name = ReadFileClass, target = ReadFile, prefixes = ["readfile:"], arg_handling = into, overlay = false, StreamOriented, SingleConnect, help = r#" Synchronously read a file. Argument is a file path. Blocking on operations with the file pauses the whole process Example: Serve the file once per connection, ignore all replies. websocat ws-l:127.0.0.1:8000 readfile:hello.json "# ); #[derive(Clone, Debug)] pub struct WriteFile(pub PathBuf); impl Specifier for WriteFile { fn construct(&self, _: ConstructParams) -> PeerConstructor { fn gp(p: &Path) -> Result<Peer> { let f = File::create(p)?; Ok(Peer::new(super::trivial_peer::DevNull, WriteFileWrapper(f), None)) } once(Box::new(futures::future::result(gp(&self.0))) as BoxedNewPeerFuture) } specifier_boilerplate!(noglobalstate singleconnect no_subspec); } specifier_class!( name = WriteFileClass, target = WriteFile, prefixes = ["writefile:"], arg_handling = into, overlay = false, StreamOriented, SingleConnect, help = r#" Synchronously truncate and write a file. Blocking on operations with the file pauses the whole process Example: websocat ws-l:127.0.0.1:8000 writefile:data.txt "# ); #[derive(Clone, Debug)] pub struct AppendFile(pub PathBuf); impl Specifier for AppendFile { fn construct(&self, _: ConstructParams) -> PeerConstructor { fn gp(p: &Path) -> Result<Peer> { let f = OpenOptions::new().create(true).append(true).open(p)?; Ok(Peer::new(super::trivial_peer::DevNull, WriteFileWrapper(f), None)) } once(Box::new(futures::future::result(gp(&self.0))) as BoxedNewPeerFuture) } specifier_boilerplate!(noglobalstate singleconnect no_subspec); } specifier_class!( name = AppendFileClass, target = AppendFile, prefixes = ["appendfile:"], arg_handling = into, overlay = false, StreamOriented, SingleConnect, help = r#" Synchronously append a file. Blocking on operations with the file pauses the whole process Example: Logging all incoming data from WebSocket clients to one file websocat -u ws-l:127.0.0.1:8000 reuse:appendfile:log.txt "# ); pub struct ReadFileWrapper(pub File); impl AsyncRead for ReadFileWrapper {} impl Read for ReadFileWrapper { fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> { self.0.read(buf) } } struct WriteFileWrapper(File); impl AsyncWrite for WriteFileWrapper { fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> { Ok(Async::Ready(())) } } impl Write for WriteFileWrapper { fn write(&mut self, buf: &[u8]) -> IoResult<usize> { self.0.write(buf) } fn flush(&mut self) -> IoResult<()> { self.0.flush() } }