I've been mucking with tokio for a few weeks in the pursuit of writing a protocol using tokio_uds. There are several issues with the following code:
framed.for_each is called over and over from a single response.
The socket only sends 1 real message, but the Decoder decodes the exact same event as many times as it can until it fills up the bounded channel.
Nothing is ever received over the channel (rx.for_each never prints anything), though it appears to be written until it fills up.
I need to use a UnixStream and not a UnixListener because there's some data I must put over the socket first to 'subscribe' to the service and let it know what to send.
use byteorder::{ByteOrder, LittleEndian};
use bytes::{Buf, BufMut, Bytes, BytesMut, IntoBuf};
use futures::prelude::*;
use futures::sync::mpsc::{self, Receiver, Sender};
use futures::Stream;
use tokio::prelude::*;
use tokio_codec::{Decoder, Encoder, FramedRead};
use tokio_uds::UnixStream;
fn subscribe(tx: Sender<event::Evt>, events: Vec<Event>) -> io::Result<()> {
let fut = UnixStream::connect(socket_path()?)
.and_then(move |stream| {
// some setup
tokio::io::write_all(stream, buf)
})
.and_then(|(stream, _buf)| {
let buf = [0_u8; 30]; // <i3-ipc (6 bytes)><len (4 bytes)><type (4 bytes)><{success:true} 16 bytes>
tokio::io::read_exact(stream, buf)
})
.and_then(|(stream, initial)| {
if &initial[0..6] != MAGIC.as_bytes() {
panic!("Magic str not received");
}
// decoding initial response and returning stream
future::ok(stream)
})
.and_then(move |stream| {
let framed = FramedRead::new(stream, EvtCodec);
let sender = framed
.for_each(move |evt| {
let tx = tx.clone();
tx.send(evt).wait(); // this line is called continuously until buffer fills
Ok(())
})
.map_err(|err| println!("{}", err));
tokio::spawn(sender);
Ok(())
})
.map(|_| ())
.map_err(|e| eprintln!("{:?}", e));
tokio::run(fut);
Ok(())
}
fn test_sub() -> io::Result<()> {
let (tx, rx) = mpsc::channel(5);
subscribe(tx, vec![Event::Window])?;
let fut = rx.for_each(|e: event::Evt| {
println!("received"); // never reaches
future::ok(())
});
tokio::spawn(fut);
Ok(())
}
My Decoder:
pub struct EvtCodec;
/// decoding: "<i3-ipc><payload len: u32><msg type: u32><payload>"
impl Decoder for EvtCodec {
type Item = event::Evt;
type Error = io::Error;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, io::Error> {
if src.len() > 14 {
if &src[0..6] != MAGIC.as_bytes() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Expected 'i3-ipc' but received: {:?}", &src[0..6]),
));
}
let payload_len = LittleEndian::read_u32(&src[6..10]) as usize;
let evt_type = LittleEndian::read_u32(&src[10..14]);
dbg!(&src.len()); // 878
dbg!(payload_len); // 864
if src.len() < 14 + payload_len {
Ok(None)
} else {
let evt = decode_evt(evt_type, src[14..].as_mut().to_vec())?;
dbg!(&evt); // correctly prints out a well-formed event
Ok(Some(evt))
}
} else {
Ok(None)
}
}
}
I saw that you resolved your other issue, and I'd be really interested to see how you solved this problem. Here's how I fixed it on my TCP Tokio side project:
use byteorder::{ByteOrder, LittleEndian};
use bytes::{Buf, BufMut, Bytes, BytesMut, IntoBuf};
use futures::prelude::*;
use futures::sync::mpsc::{self, Receiver, Sender};
use futures::Stream;
use tokio::prelude::*;
use tokio_codec::{Decoder, Encoder, FramedRead};
use tokio_uds::UnixStream;
fn subscribe(tx: Sender<event::Evt>, rx: Receiver<event::Evt>, events: Vec<Event>) -> io::Result<()> {
let fut = UnixStream::connect(socket_path()?)
.and_then(move |stream| {
// some setup
tokio::io::write_all(stream, buf)
})
.and_then(|(stream, _buf)| {
let buf = [0_u8; 30]; // <i3-ipc (6 bytes)><len (4 bytes)><type (4 bytes)><{success:true} 16 bytes>
tokio::io::read_exact(stream, buf)
})
.and_then(|(stream, initial)| {
if &initial[0..6] != MAGIC.as_bytes() {
panic!("Magic str not received");
}
// decoding initial response and returning stream
future::ok(stream)
})
.and_then(move |stream| {
let framed = FramedRead::new(stream, EvtCodec);
let (writer, reader) = framed.split();
// Connect your framed reader to the channel
let sink = rx.forward(writer.sink_map_err(|_| ()));
tokio::spawn(sink.map(|_| ()));
let sender = reader
.for_each(move |evt| {
let tx = tx.clone();
tx.send(evt).wait(); // this line is called continuously until buffer fills
Ok(())
})
.map_err(|err| println!("{}", err));
tokio::spawn(sender);
Ok(())
})
.map(|_| ())
.map_err(|e| eprintln!("{:?}", e));
tokio::run(fut);
Ok(())
}
fn test_sub() -> io::Result<()> {
let (tx, rx) = mpsc::channel(5);
subscribe(tx, rx, vec![Event::Window])?;
let fut = rx.for_each(|e: event::Evt| {
println!("received"); // never reaches
future::ok(())
});
tokio::spawn(fut);
Ok(())
}
And the Decoder with the buffer clear:
pub struct EvtCodec;
/// decoding: "<i3-ipc><payload len: u32><msg type: u32><payload>"
impl Decoder for EvtCodec {
type Item = event::Evt;
type Error = io::Error;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, io::Error> {
if src.len() > 14 {
if &src[0..6] != MAGIC.as_bytes() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Expected 'i3-ipc' but received: {:?}", &src[0..6]),
));
}
let payload_len = LittleEndian::read_u32(&src[6..10]) as usize;
let evt_type = LittleEndian::read_u32(&src[10..14]);
dbg!(&src.len()); // 878
dbg!(payload_len); // 864
if src.len() < 14 + payload_len {
Ok(None)
} else {
let evt = decode_evt(evt_type, src[14..].as_mut().to_vec())?;
dbg!(&evt); // correctly prints out a well-formed event
src.clear(); // Clears the buffer, so you don't have to keep decoding the same packet over and over.
Ok(Some(evt))
}
} else {
Ok(None)
}
}
}
Hope this helps!
EDIT:
According to a user on the rust subreddit that commented after I included this solution in a blog post, src.clear() is probably the wrong answer for me. I should instead be using `src.advance(14+payload_len)
linking the reddit comment here
Related
I'm trying to make a Tic-Tac-Toe game with a custom board size. I want this to be very hard to break, so I use recursion to get the board measurements if the input is invalid or an error occurs. However, this doesn't seem very clean to me, and I was wondering if there's a better/more rusty way of achieving the same thing.
Code in main function
let board_size_str = get_board_size_string();
let (x_pos, width, height) = get_board_measurement(&board_size_str);
Functions
fn get_board_size_string() -> String {
println!("Select the size of the board in the following format: 5x5 or 7x7");
println!("The size can be from 3x3 to 30x30");
print!("Size: ");
std::io::stdout().flush().expect("Failed to flush stdout!");
let mut board_size_str = String::new();
std::io::stdin().read_line(&mut board_size_str).expect("Failed to read board size!");
println!();
board_size_str
}
fn get_board_measurement(board_size_str: &str) -> (usize, i64, i64) {
let x_pos = get_x_pos(board_size_str);
let width = get_board_width(board_size_str, x_pos);
let height = get_board_height(board_size_str, x_pos);
(x_pos, width, height)
}
fn get_x_pos(board_size_str: &str) -> usize {
let x_pos_option = board_size_str.chars().position(|c| c == 'x');
match x_pos_option {
Some(x_pos) => x_pos,
None => {
println!("Board size must contain an x!");
let board_size_str = get_board_size_string();
get_x_pos(&board_size_str)
}
}
}
fn get_board_width(board_size_str: &str, x_pos: usize) -> i64 {
let width_result = board_size_str[..x_pos].parse::<i64>();
match width_result {
Ok(width) => width,
Err(_) => {
println!("Invalid board width!");
let board_size_str = get_board_size_string();
get_board_width(&board_size_str, get_x_pos(&board_size_str))
}
}
}
fn get_board_height(board_size_str: &str, x_pos: usize) -> i64 {
let height_result = board_size_str[x_pos + 1..].trim().parse::<i64>();
match height_result {
Ok(height) => height,
Err(_) => {
println!("Invalid board height!");
let board_size_str = get_board_size_string();
get_board_height(&board_size_str, get_x_pos(&board_size_str))
}
}
}
Just use an iterative loop?
fn get_x_pos(board_size_str: &str) -> usize {
loop {
let board_size_str = get_board_size_string();
let x_pos_option = board_size_str.chars().position(|c| c == 'x');
if let Some(x_pos) = x_pos_option {
break x_pos
}
}
}
Though the structure is strange because a correct board size is a correct pattern ( 'x' ) so it's not like splitting that into three unrelated routines makes any sense, even if two of them do delegate the localisation of the x separator.
With your method you can input something like 52xkf, get an error, input 24x36, and I think you'll get a 52x36 board rather than the 24x36 you might expect, which is just odd. Would be a lot easier to just do the entire thing in a single pseudo-step:
fn parse_board_size() -> (usize, usize) {
loop {
let s = get_board_size_string();
let Some((w_s, h_s)) = s.split_once('x') else {
// complain about a missing `x` here
continue;
};
match (w_s.parse(), h_s.parse()) {
(Ok(w), Ok(s)) => {
// can add more validation here,
// or as pattern guards
return (w, s);
}
(Ok(_), Err(h_error)) => {
// h was incorrect
}
(Err(w_error), Ok(_)) => {
// w was incorrect
}
(Err(w_error), Err(h_error)) => {
// both were incorrect
}
}
}
}
Alternatively for the parsing if you don't care about custom-reporting each error case individually you can lean on Option e.g.
fn parse_board_size() -> (usize, usize) {
loop {
let s = get_board_size_string();
let Some((w_s, h_s)) = s.split_once('x') else {
// complain about a missing `x` here
continue;
};
if let Some(r) = w_s.parse().ok().zip(h_s.parse().ok()) {
break r;
}
// report generic parsing error
}
}
How to convert a hyper::Response object into the bytes that would be sent over the network for it, including all parts of the response (the status code, version, headers, and body)?
Here is what I came up with for now:
async fn response_to_bytes(response: Response<Full<Bytes>>) -> Vec<u8> {
let (
response::Parts {
status,
version,
headers,
extensions: _, // TODO: should we be using this?
..
},
body,
) = response.into_parts();
// Enough for body + headers of length 64 each + 64 bytes for status line.
// This will probably be more than enough most of the time.
let mut bytes =
BytesMut::with_capacity(body.size_hint().lower() as usize + 64 * headers.len() + 64);
let version = match version {
Version::HTTP_09 => "HTTP/0.9",
Version::HTTP_10 => "HTTP/1.0",
Version::HTTP_11 => "HTTP/1.1",
Version::HTTP_2 => "HTTP/2",
Version::HTTP_3 => "HTTP/3",
_ => "HTTP/1.1", // TODO: handle this case.
};
// Status line.
bytes.put(version.as_bytes()); // HTTP/1.1
bytes.put(&b" "[..]);
bytes.put(status.as_str().as_bytes()); // 200
bytes.put(&b" "[..]);
if let Some(reason) = status.canonical_reason() {
bytes.put(reason.as_bytes()); // OK
} else {
bytes.put(&b"LOL"[..]); // TODO: ?
}
// Headers.
for (name, value) in headers.into_iter() {
if let Some(name) = name {
bytes.put(&b"\r\n"[..]);
bytes.put(name.as_str().as_bytes());
bytes.put(&b": "[..]);
} else {
// TODO: are multiple values for the same header comma delimited?
bytes.put(&b","[..])
}
bytes.put(value.as_bytes())
}
bytes.put(&b"\r\n\r\n"[..]);
// Body.
bytes.put(body.collect().await.unwrap().to_bytes()); // Unwrap Infallible.
bytes.to_vec()
}
I am prototyping channel based system and when converting code to use async tasks, I came across the error that &mut self needs to have an appropriate lifetime.
I have tried setting the &mut self to &'static self but that does not work. I have tried to wrap the entire code in an async block returning Future<Output=()> + 'static which also did not work.
Here is the code:
struct RequestManager {
connection_state: ConnectionState,
backoff: u64,
exponent: u32,
maximum: u64,
}
impl RequestManager {
async fn run(&mut self, mut feed_queue: Receiver<FeedItem>) {
let (mut fetch_result_sender, mut fetch_result_receiver) = channel(5);
let (mut fetch_request_sender, mut fetch_request_receiver) = channel::<FeedItem>(5);
let request_sender = mpsc::Sender::clone(&fetch_result_sender);
tokio::spawn(async move {
loop {
match self.connection_state {
ConnectionState::Closed => {
while let Some(feed) = fetch_request_receiver.recv().await {
let mut request_sender = mpsc::Sender::clone(&request_sender);
tokio::spawn(async move {
let response = make_request(&feed.feed_address).await;
if let Err(_) = response {
self.connection_state =
ConnectionState::HalfOpen(feed.feed_address);
} else {
let response = read_response_body(response.unwrap()).await;
let result = FetchResult { body: response };
if let Err(e) = request_sender.send(result).await {
eprintln!("could not send fetch result: {}", e);
}
}
});
}
}
ConnectionState::HalfOpen(url) => {
let response = make_request(&url).await;
if let Err(_) = response {
self.connection_state = ConnectionState::Open(url);
} else {
let response = read_response_body(response.unwrap()).await;
let result = FetchResult { body: response };
// // TODO: sends to task/feedService
connection_state = ConnectionState::Closed;
if let Err(e) = fetch_result_sender.send(result).await {
eprintln!("could not send fetch result: {}", e);
}
}
}
ConnectionState::Open(url) => {
let new_backoff = calculate_backoff();
delay_for(Duration::from_secs(new_backoff));
self.connection_state = ConnectionState::HalfOpen(url)
}
}
}
});
}
}
My first Rust program compiles and runs:
use structopt::StructOpt;
use pcap::{Device,Capture};
use std::process::exit;
#[derive(StructOpt)]
struct Cli {
/// the capture device
device: String,
}
fn main() {
let devices = Device::list();
let args = Cli::from_args();
let mut optdev :Option<Device> = None;
for d in devices.unwrap() {
//println!("device: {:?}", d);
if d.name == args.device {
optdev = Some(d);
}
}
let dev = match optdev {
None => {
println!("Device {} not found.", args.device);
exit(1);
},
Some(dev) => dev,
};
let mut cap = Capture::from_device(dev).unwrap()
.promisc(true)
.snaplen(100)
.open().unwrap();
while let Ok(packet) = cap.next() {
println!("received packet! {:?}", packet);
}
}
I have some complex code which iterates through the Vec of devices, testing each one's .name property against args.device.
I'm guessing that there is a method of 'looking-up' an entry in a Vec, such that I can replace all the optdev lines with something like:
let dev = match devices.unwrap().look_up(.name == args.device) {
None => {
println!("Device {} not found.", args.device);
exit(1);
},
Some(dev) => dev,
};
What is the syntax for such a look_up()?
Or is there a more idiomatic way of doing this?
What is the syntax for such a look_up()?
Iterator::find. Since the operation is not specific to vectors (or slices), it doesn't live there, and is applicable to any iterator instead.
It'd look something like this:
let dev = match devices.unwrap().into_iter().find(|d| d.name == args.device) {
None => {
println!("Device {} not found.", args.device);
exit(1);
},
Some(dev) => dev,
};
or
let dev = if let Some(dev) = devices.unwrap().into_iter().find(|d| d.name == args.device) {
dev
} else {
println!("Device {} not found.", args.device);
exit(1);
};
(side-note: you may also want to use eprintln for, well, error reporting).
Though a somewhat cleaner error handling could be along the lines of (note: not tested so there might be semantic or syntactic mistakes):
use std::fmt;
use std:errors::Error;
#[derive(Debug)]
struct NoDevice(String);
impl fmt::Display for NoDevice {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Device {} not found", self.0)
}
}
impl Error for NoDevice {}
fn main() -> Result<(), Box<dyn Error>> {
let devices = Device::list()?;
let args = Cli::from_args();
let dev = devices.into_iter()
.find(|d| d.name == args.device)
.ok_or_else(|| NoDevice(args.device))?
let mut cap = Capture::from_device(dev)?
.promisc(true)
.snaplen(100)
.open()?;
while let Ok(packet) = cap.next() {
println!("received packet! {:?}", packet);
}
}
I have a function which returns Future. It accepts another function which accepts one argument and returns Future. Second function can be implemented as combinators chain passed into first function. It looks like this:
use bb8::{Pool, RunError};
use bb8_postgres::PostgresConnectionManager;
use tokio_postgres::{error::Error, Client, NoTls};
#[derive(Clone)]
pub struct DataManager(Pool<PostgresConnectionManager<NoTls>>);
impl DataManager {
pub fn new(pool: Pool<PostgresConnectionManager<NoTls>>) -> Self {
Self(pool)
}
pub fn create_user(
&self,
reg_req: UserRequest,
) -> impl Future<Item = User, Error = RunError<Error>> {
let sql = "long and awesome sql";
let query = move |mut conn: Client| { // function which accepts one argument and returns Future
conn.prepare(sql).then(move |r| match r {
Ok(select) => {
let f = conn
.query(&select, &[®_req.email, ®_req.password])
.collect()
.map(|mut rows| {
let row = rows.remove(0);
row.into()
})
.then(move |r| match r {
Ok(v) => Ok((v, conn)),
Err(e) => Err((e, conn)),
});
Either::A(f)
}
Err(e) => Either::B(future::err((e, conn))),
})
};
self.0.run(query) // function which returns Future and accepts another function
}
}
But I want to write code of create_user as a struct implementing Future.
struct UserCreator(Pool<PostgresConnectionManager<NoTls>>, UserRequest);
impl UserCreator {
fn new(pool: Pool<PostgresConnectionManager<NoTls>>, reg_req: UserRequest) -> Self {
Self(pool, reg_req)
}
}
How to implement Future for this struct that works as first function? Please help me with an example.
Now I tried to make it like this, but nothing is computed and execution always blocks.
impl Future for UserCreator {
type Item = User;
type Error = RunError<Error>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
// Code which which works like `DataManager.create_user`
let sql = "long and awesome sql";
let reg_req = &self.1;
let query = move |mut conn: Client| {
conn.prepare(sql).then(move |r| match r {
Ok(select) => {
let f = conn
.query(&select, &[®_req.email, ®_req.password])
.collect()
.map(|mut rows| {
let row = rows.remove(0);
row.into()
})
.then(move |r| match r {
Ok(v) => Ok((v, conn)),
Err(e) => Err((e, conn)),
});
Either::A(f)
}
Err(e) => Either::B(future::err((e, conn))),
})
};
self.0.run(query).poll()
}
}