-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ea7ea40
commit 4b3db68
Showing
17 changed files
with
1,635 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
name: Deploy book to Pages | ||
|
||
on: | ||
push: | ||
branches: ["main"] | ||
|
||
workflow_dispatch: | ||
|
||
permissions: | ||
contents: read | ||
pages: write | ||
id-token: write | ||
|
||
concurrency: | ||
group: "pages" | ||
cancel-in-progress: false | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
env: | ||
MDBOOK_VERSION: 0.4 | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Install mdBook | ||
run: | | ||
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -y | sh | ||
rustup update | ||
cargo install --version ${MDBOOK_VERSION} mdbook | ||
- name: Setup Pages | ||
id: pages | ||
uses: actions/configure-pages@v4 | ||
- name: Build with mdBook | ||
run: mdbook build | ||
- name: Upload artifact | ||
uses: actions/upload-pages-artifact@v3 | ||
with: | ||
path: ./book | ||
|
||
deploy: | ||
environment: | ||
name: github-pages | ||
url: ${{ steps.deployment.outputs.page_url }} | ||
runs-on: ubuntu-latest | ||
needs: build | ||
steps: | ||
- name: Deploy to GitHub Pages | ||
id: deployment | ||
uses: actions/deploy-pages@v4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
book |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,16 @@ | ||
# guide | ||
Selium user guide | ||
# Selium User Guide | ||
|
||
Selium's user guide, built by [`mdBook`](https://github.com/rust-lang/mdBook). | ||
|
||
## Editing | ||
|
||
To render the book whilst making changes, mdBook has a built in web server to help: | ||
|
||
```bash | ||
mdbook serve --open | ||
``` | ||
|
||
## Deployment | ||
|
||
The rendered book is deployed to GitHub Pages using the `pages.yml` workflow. Any push to `main` | ||
will trigger this deployment. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[book] | ||
authors = ["Selium Developers"] | ||
language = "en" | ||
multilingual = false | ||
src = "src" | ||
title = "Selium User Guide" | ||
|
||
[output.html] | ||
default-theme = "ayu" | ||
preferred-dark-theme = "ayu" | ||
git-repository-url = "https://github.com/seliumlabs/selium" | ||
cname = "guide.selium.com" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Summary | ||
![Selium.com](selium.png) | ||
|
||
[Introduction](./introduction.md) | ||
|
||
# Getting Started | ||
|
||
- [First Steps](./getting_started/first_steps.md) | ||
- [Request/Reply](./getting_started/request_reply.md) | ||
- [Reusing Connections](./getting_started/reusing_connections.md) | ||
- [`Stream` and `Sink` traits](./getting_started/streams_and_sinks.md) | ||
- [Codecs](./getting_started/codecs.md) | ||
|
||
--- | ||
|
||
- [Selium Cloud](./cloud.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# Selium Cloud | ||
|
||
Selium Cloud (Beta) consists of a managed Selium Server, authentication, certificate | ||
management, dashboard and technical support. If you want a hands-free, production-ready | ||
solution for all of your software comms, backed by the people that made Selium, this is | ||
for you. | ||
|
||
## Getting Started | ||
|
||
#### 1. Sign up | ||
To get started with Selium Cloud, you'll [need an account!](https://www.selium.com/#CTA) | ||
Selium Cloud is free for life, and super affordable as you grow with us. | ||
|
||
#### 2. Create your first certificate | ||
Once you've got your account, login to the Selium Cloud dashboard at | ||
[cloud.selium.io](https://cloud.selium.io). From here, you can create TLS certificates | ||
for each client on your account. | ||
|
||
After logging in, you should see a screen like this: | ||
|
||
<img width="800" alt="Dashboard" src="https://github.com/seliumlabs/selium/assets/3638076/3ad412cf-7d8b-4f02-b632-e6728c7c9ce6"> | ||
|
||
To create a certificate, fill in a name for your client, e.g. "web1.example.com", then | ||
click the submit button. After a moment you should see a dialog box like this: | ||
|
||
<img width="800" alt="Add client" src="https://github.com/seliumlabs/selium/assets/3638076/cf2ab47c-86d3-4f4f-a94c-8b26ca425303"> | ||
|
||
**Make sure you download the private key as you cannot download it again!** | ||
|
||
Add the public and private keys to your project and you're ready to start using Selium. | ||
|
||
## Basic Usage | ||
|
||
Selium Cloud's API feels just like running your own Selium server. The main difference is | ||
when establishing a connection to the server. Instead of using `selium::custom()` to | ||
connect to your own server, use `selium::cloud()` to connect to the cloud: | ||
|
||
```rust | ||
let connection = selium::cloud() | ||
.with_cert_and_key( | ||
"./web1.example.com.der", | ||
"./web1.example.com.key.der", | ||
)? | ||
.connect() | ||
.await?; | ||
``` | ||
|
||
Note that when using `selium::cloud()`, you won't need to specify a CA path or endpoint. | ||
These details are baked into the Selium client for your convenience. | ||
|
||
#### Namespaces | ||
|
||
Each Selium Cloud account is linked to a unique _namespace_. This is used to distinguish | ||
your data from other accounts, and is linked to every certificate you create. You can find | ||
your namespace on the Selium Cloud dashboard: | ||
|
||
<img width="800" alt="Namespace" src="https://github.com/seliumlabs/selium/assets/3638076/f5b9761b-da92-4d5c-9611-471e92ddd20c"> | ||
|
||
To use your namespace, simply prepend it to every topic name. For example, to publish the | ||
topic "retail-transactions", you would code the following: | ||
|
||
```rust | ||
let mut publisher = connection | ||
.publisher("/example/retail-transactions") | ||
... | ||
.await?; | ||
``` | ||
|
||
### IMPORTANT NOTE! | ||
|
||
**You must compile your code with the `--release` flag for both testing and production | ||
use. This is so the Selium client knows to use the _production_ Certificate Authority!** | ||
|
||
If you don't do this, you will not be able to connect to Selium. | ||
|
||
> N.B. We know this isn't ideal, and likely we'll be removing this restriction in future | ||
> versions. We'd love your feedback on this too! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# Codecs | ||
Looking back at the previous chapters, you probably noticed lines like these ones: | ||
|
||
```rust | ||
let mut publisher = connection | ||
... | ||
.with_encoder(StringCodec) // allows you to exchange string messages between clients | ||
|
||
let mut subscriber = connection | ||
... | ||
.with_decoder(StringCodec) // use the same codec as the publisher | ||
``` | ||
|
||
If you've not worked with data streaming before, codecs might seem like a very strange | ||
concept indeed. However the answer is quite simple. The term _codecs_ is a portmanteau of | ||
_encoder_ and _decoder_. Thus a codec is simply a structure that can _encode_ frames of | ||
data on one side of a connection, and _decode_ them on the other. | ||
|
||
In the example above, we use `StringCodec`, which does exactly what it says on the tin - | ||
it _encodes_ strings to bytes and then _decodes_ those bytes back to strings. | ||
|
||
## Why do we need codecs? | ||
|
||
We need codecs because at the network level, computers only support sending raw bytes. | ||
However most data we work with are not raw bytes - they're strings, integers, booleans, | ||
enumerators, structures etc. In order to abstract away the pain of converting these types | ||
to bytes and back again, we use a codec that knows how to do it for us. | ||
|
||
## Can I send more than just strings? | ||
|
||
Yep! With the help of the `serde` crate, we support sending all manner of Rust types. | ||
In the example below, we use the `BincodeCodec` to send a stream of `StockEvent`s. | ||
|
||
You'll need to install `serde` with the _derive_ feature to follow this example: | ||
```bash | ||
$ cargo add -F derive serde | ||
``` | ||
|
||
```rust | ||
use futures::SinkExt; | ||
use selium::{prelude::*, std::codecs::BincodeCodec}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Debug, Serialize, Deserialize)] | ||
struct StockEvent { | ||
ticker: String, | ||
change: f64, | ||
} | ||
|
||
impl StockEvent { | ||
pub fn new(ticker: &str, change: f64) -> Self { | ||
Self { | ||
ticker: ticker.to_owned(), | ||
change, | ||
} | ||
} | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
let connection = selium::custom() | ||
.endpoint("127.0.0.1:7001") | ||
.with_certificate_authority("certs/client/ca.der")? | ||
.with_cert_and_key( | ||
"certs/client/localhost.der", | ||
"certs/client/localhost.key.der", | ||
)? | ||
.connect() | ||
.await?; | ||
|
||
let mut publisher = connection | ||
.publisher("/some/topic") | ||
.with_encoder(BincodeCodec::default()) | ||
.open() | ||
.await?; | ||
|
||
publisher.send(StockEvent::new("INTC", -9.0)).await?; | ||
publisher.finish().await?; | ||
|
||
Ok(()) | ||
} | ||
``` | ||
|
||
## Can I build my own codec? | ||
|
||
Yes, and you can use third party codecs like protocol buffers, SBE etc. We'll have a chapter on | ||
this coming soon. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
# 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: | ||
|
||
```bash | ||
# 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](https://crates.io/crates/selium-server). | ||
|
||
> For production deployments you can also download prebuilt binaries from | ||
> [GitHub](https://github.com/orgs/seliumlabs/packages?repo_name=selium). | ||
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: | ||
|
||
```bash | ||
# 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: | ||
|
||
```bash | ||
$ 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: | ||
|
||
```rust | ||
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! | ||
|
||
```bash | ||
# 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. | ||
|
||
```bash | ||
$ 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.](./request_reply.md) |
Oops, something went wrong.