nectar
is a Tokio codec providing a partial Telnet protocol (RFC 854)
implementation.
Supports primary negotiation options: DO, DONT, WILL, WONT. Supports subnegotiation (NAWS, custom byte sequences). Aims to implement some of the popular MUD protocol extensions.
Simply use cargo add nectar
in your root project directory.
You must also be using tokio-utils
with the codec
feature enabled, as well as
tokio
.
See the Tokio docs if you wish to dive deeper into codecs. Essentially it is just a way to encode and decode the underlying TCP Stream in a structured manner - in this case, our structure being the Telnet protocol.
See the echo_server directory for a working example
with commented code. If you have cloned the nectar
repository, you can run
the echo server with cargo and then connect with telnet localhost 5000
.
Note: Make sure you check the dependencies in the example Cargo.toml
file.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = SocketAddr::from(([127, 0, 0, 1], 5000));
let listener = TcpListener::bind(addr).await?;
println!("telnet server started on: {}", addr);
// Standard Tokio setup - we accept new connections and pass the
// stream off to our handler function where the real work happens.
loop {
while let Ok((stream, _)) = listener.accept().await {
tokio::spawn(async move {
if let Err(e) = handler(stream).await {
eprintln!("error: {}", e);
}
});
}
}
}
async fn handler(stream: TcpStream) -> Result<(), Box<dyn std::error::Error>> {
// We construct a 'Frame', which is just a wrapper around the underlying
// stream that is decoded by the `nectar::TelnetCodec`.
let mut frame = Framed::new(stream, TelnetCodec::new(1024));
// In a real application, you would want to handle Some(Err(_)) and None
// variants, but for this example we'll be succinct for simplicities sake.
while let Some(Ok(msg)) = frame.next().await {
match msg {
// We'll keep it simple and only match against the Message event.
TelnetEvent::Message(string) => {
// Let's echo back what we received.
frame.send(TelnetEvent::Message(string)).await?;
}
_ => break,
}
}
}
You can check out the Blossom
source code for an example of nectar
in a more complex, real-world scenario.
nectar source code is dual-licensed under either
at your option.