First Steps

Selium comprises a client library and a server binary. In order to use Selium, there are 3 basic steps:

  1. Create TLS certificates for your client and server
  2. Run the server binary
  3. Integrate the client library into your project

Step 1 - TLS Certificates

First we need some certs to validate the client and server. Selium uses mutual TLS (mTLS) to validate both parties cryptographically, making things nice and secure.

We've built a tool to make this easy, so let's install that, then mint our certs:

# Install the selium-tools CLI
$ cargo install selium-tools
# Use this CLI to create our certificates
$ selium-tools gen-certs

You should now have a directory in the current path called certs/. Inside we have certs for the client and server, which you can move to a more convenient location if you like - the paths are configurable in code. Both the client/ and server/ directories include a copy of the certificate authority, which you'll need if you want to create more client certificates later.

Step 2 - Start the Selium Server

The Selium server allows us to exchange messages between clients. For this example we'll grab a copy from crates.io.

For production deployments you can also download prebuilt binaries from GitHub.

Let's start a new server with our freshly minted certs. In the same directory as your certs/ folder, open a new terminal and run the following commands:

# Install Selium server
$ cargo install selium-server
# Run the server
$ selium-server --bind-addr=127.0.0.1:7001

The selium-server command will not produce any output by default, but that doesn't mean it isn't working! You can increase logging using the verbosity flag:

$ selium-server -v # Warnings only
$ selium-server -vv # Info
$ selium-server -vvv # Debug
$ selium-server -vvvv # Trace

Step 3 - Implement the Selium Client

Selium Client is a composable library API for the Selium Server. Let's have a look at a minimal example:

use futures::{SinkExt, StreamExt};
use selium::{prelude::*, std::codecs::StringCodec};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let connection = selium::custom() // connect to your own Selium server
        .endpoint("127.0.0.1:7001") // your Selium server's address
        .with_certificate_authority("certs/client/ca.der")? // your Selium cert authority
        .with_cert_and_key(
            "certs/client/localhost.der",
            "certs/client/localhost.key.der",
        )? // your client certificates
        .connect()
        .await?;

    let mut publisher = connection
        .publisher("/some/topic") // choose a topic to group similar messages together
        .with_encoder(StringCodec) // allows you to exchange string messages between clients
        .open() // opens a new stream for sending data
        .await?;

    let mut subscriber = connection
        .subscriber("/some/topic") // subscribe to the publisher's topic
        .with_decoder(StringCodec) // use the same codec as the publisher
        .open() // opens a new stream for receiving data
        .await?;

    // Send a message and close the publisher
    publisher.send("Hello, world!".into()).await?;
    publisher.finish().await?;

    // Receive the message
    if let Some(Ok(message)) = subscriber.next().await {
        println!("Received message: {message}");
    }

    Ok(())
}

There's a lot to take in here, but for the moment let's just get this baby running!

# Create a new Cargo project
$ cargo new --bin hello-selium

# Move into our project
$ cd hello-selium

# Add the crate dependencies
$ cargo add futures
$ cargo add -F std selium
$ cargo add -F macros,rt tokio

Now copy and paste the code above into hello-selium/src/main.rs.

Now let's execute the project and start exchanging some messages! Make sure your server is still running from the previous step.

$ cargo run
Received message: Hello, world!

Next Steps

We've just setup a working Selium publish/subscribe project, but you can also use RPC too.