Crate netty_rs[][src]

Netty-rs allows exposes a simple-to-use API used to create stateful application level network protocols as both a client or server.

Netty-rs allows requires consumers specify how to handle messages in different circumstances. Whenever specifying this the same API is used by using Connection. This very simple API allows consumers to specify restful protocols of varying complexity. Each message-and-reply chain is in their own channel which does not and is not impacted by messages sent or received in other message-and-reply chains.

The situations where how to handle messages need to be specified are:

  1. When a consumer sends a message it can choose to wait for a reply and handle it in a custom way.
  2. When acting as a server consumers need to specify how to handshake with new connections, which allows custom authentication of clients among any other handshake related action.
  3. When acting as a server consumers need to specify how to handle non-reply messages from connections that have already been authenticated.

The main API is accessed through the Networker struct.

Netty-rs uses the DirectoryService trait in order to allow consumers to either implement their own directory service for example a DNS or use the SimpleDirectoryService struct that implements this trait.

Example

fn generate_challenge() -> Vec<u8> {
   // Generate the challenge ...
}

fn verify_challenge(a: &Vec<u8>) -> bool {
   // Verify challenge answer ...
}

fn sign(c: &Vec<u8>) -> Vec<u8> {
   // Sign the challenge
}

// Enum for the different types of messages we want to send
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
enum Content {
   Init,
   Challenge(Vec<u8>),
   Answer(Vec<u8>),
   Accept,
   Deny,
   Request,
   Response(i32),
   ProtocolError,
}

let ds = SimpleDirectoryService::new();
let networker = Networker::new("127.0.0.1:8080".parse().unwrap(), ds,
   |handshake_msg: NetworkMessage<Content>, mut con: Connection<Content, MyError>| async move {
      // Perhaps you authenticate by producing a challenge and then
      // waiting for a response
      let challenge = generate_challenge();
      let message = handshake_msg.reply(Content::Challenge(challenge));
      let timeout = Duration::from_secs(2);
      // On timeout or other errors we just abort this whole process
      let response = con.send_message_await_reply(message, Some(timeout)).await?;
      if let Content::Answer(a) = &response.content {
          if verify_challenge(a) {
              let accept_msg = response.reply(Content::Accept);
              con.send_message(accept_msg).await?;
          } else {
              let deny_msg = response.reply(Content::Deny);
              con.send_message(deny_msg).await?;
          }
      } else {
          let deny_msg = response.reply(Content::Deny);
          con.send_message(deny_msg).await?;
      }
      // Return the id of this client
      let inner = Arc::try_unwrap(handshake_msg.from).unwrap_or_else(|e| (*e).clone());
       Ok(inner)
   },
   |message: NetworkMessage<Content>, mut con: Connection<Content, MyError>| async move {
       if let Content::Request = message.content {
           // Respond with the magical number for the meaning of life
           let response = message.reply(Content::Response(42));
           con.send_message(response).await?;
       } else {
           let response = message.reply(Content::ProtocolError);
           con.send_message(response).await?;
       }
       Ok(())
   }).await.map_err(|_| MyError)?;
networker.listen(true).await.map_err(|_| MyError)?;
// Send a message to ourselves
let first_message = NetworkMessage::new(
   Arc::new("127.0.0.1:8080".to_string()),
   Arc::new("127.0.0.1:8080".to_string()),
   Content::Init,
);
let timeout = Duration::from_secs(2);
let action = Action::new(
   |msg: NetworkMessage<Content>, mut con: Connection<Content, MyError>| {
       async move {
           if let Content::Challenge(c) = &msg.content {
               let answer = sign(c);
               let resp = msg.reply(Content::Answer(answer));
               let timeout = Duration::from_secs(2);
               let accept = con.send_message_await_reply(resp, Some(timeout)).await?;
               if let Content::Accept = accept.content {
                   Ok(())
               } else {
                   Err(MyError.into())
               }
           } else {
               Err(MyError.into())
           }
       }
       .boxed()
   },
);
networker
   .send_message(first_message, Some(timeout), Some(action))
   .await.map_err(|_| MyError)?;
Result::<(), MyError>::Ok(())

Structs

Action

Action contains a closure that handles the communication on a channel

Connection

A connection serves as the main API to specify how a network conversation should look. It allows sending messages to the recipiant and awaiting their response using the two methods send_message and send_message_await_reply.

Error

Error returned by netty-rs

NetworkMessage

This struct represents the network messages sent and received, it can be created either from the new new constructor if a fresh message is desired. If a reply is desired then the reply method should be used.

Networker

This struct is the main API for using netty. It allows the creation of a server and the ability to send messages to clients.

SimpleDirectoryService

Directory service that translates Strings and socket addresses to socket addresses Strings have to be in the format of “127.0.0.1:8080”

Traits

DirectoryService

Netty-rs uses a pluggable directory service to translate from an id to an IP address and port number. This is provided via this trait. A SimpleDirectoryService struct is provided which translates from any type that implements ToSocketAddrs. This includes strings which are in the format of for example “127.0.0.1:8080”, which will allow consumers to easily use strings or IP addresses as identifiers. If a more complicated lookup is required then implementing this trait is always avaliable.

HandlerError

Marker trait for errors that are returned by the handlers

NetworkContent

Marker trait for the content contained in the NetworkMessage struct