Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 657fc063 authored by WILLIAMS Harvey's avatar WILLIAMS Harvey
Browse files

README, Start of async bridge

parent 2e422bd2
Branches
No related tags found
No related merge requests found
......@@ -30,6 +30,8 @@ Are you...
This repository might be helpful for you!
Setting up the simple case of sending and receiving messages in a systems language is theoretically straightforward. However, building a distributed application in Rust comes with some pitfalls, especially for those still getting comfortable with ownership, concurrency and lifetimes. These examples serve as good idiomatic starting point as a way to approach this.
# Structure
`/` Rust library containing the Network interface, nothing else.
......@@ -58,7 +60,3 @@ To delve into the details of this code, some background may be useful:
- Basic understanding of writing async rust code. Although you can still write your own application code in a synchronous manner, we opt to use it here to simplify the handling of network events.
- Familiarity with the [actor model/pattern](https://en.wikipedia.org/wiki/Actor_model) of writing async code (see [here](https://ryhl.io/blog/actors-with-tokio/) for a good starting point).
# Avoiding async rust
TODO - Building an async bridge
# async-bridge: WORK-IN-PROGRESS
In this respository, we use async code for tasks involving message passing and polling connections. That said, it may be desirable to avoid introducing async for your application logic built on top.
Reasons behind this could include avoiding idiosyncrasies and pitfalls that come with Rust's flavour of async, or just simplfiying your execution model. The tokio guide has an [excellent article](https://tokio.rs/tokio/topics/bridging) on strategies to accomplish this. In `wrapped.rs` we take the latter approach.
\ No newline at end of file
use libp2p_net::Libp2pConnector;
use rust_networking_examples::Network;
use tokio::runtime::Builder;
use tokio::sync::{mpsc, oneshot};
enum Message {
Send {
to: String,
message: Vec<u8>
},
RequestReceiver {
respond_to: oneshot::Sender< mpsc::Receiver<(String, Vec<u8>)> >
}
}
#[derive(Clone)]
pub struct WrappedConnector {
sender: mpsc::Sender<Message>,
}
impl WrappedConnector {
pub fn new() -> WrappedConnector {
// Set up a channel for communicating.
let (sender, mut receiver) = mpsc::channel(1024);
// Build the runtime for the new thread.
//
// The runtime is created before spawning the thread
// to more cleanly forward errors if the `unwrap()`
// panics.
let rt = Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
std::thread::spawn(move || {
rt.block_on(async move {
// Create the connector
let mut connector = Libp2pConnector::new();
// Here we can called functions on Connector, as its within an async context!
while let Some(message) = receiver.recv().await {
match message {
Message::Send { to, message } => {
connector.send(&to, message)
},
Message::RequestReceiver { respond_to } => {
let _ = respond_to.send(connector.recv().await);
},
}
}
// Once all senders have gone out of scope,
// the `.recv()` call returns None and it will
// exit from the while loop and shut down the
// thread.
});
});
WrappedConnector { sender }
}
pub fn send(&mut self, to: String, message: Vec<u8>) {
self.sender.try_send(Message::Send { to, message }).expect("Async runtime should be running and accepting messages");
}
pub fn recv(&mut self) -> mpsc::Receiver<(String, Vec<u8>)> {
// Create a oneshot channel
let (respond_to, receiver) = oneshot::channel();
self.sender.try_send(Message::RequestReceiver { respond_to }).expect("Async runtime should be running and accepting messages");
// Here we can use .blocking_recv() outside an async runtime
receiver.blocking_recv().expect("Should have received it")
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment