Skip to content

Commit

Permalink
update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
muhamadazmy committed Nov 28, 2023
1 parent 22735e5 commit 23ab5c1
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 21 deletions.
38 changes: 32 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
[![Rust](https://github.com/threefoldtech/rmb-rs/actions/workflows/rust.yaml/badge.svg)](https://github.com/threefoldtech/rmb-rs/actions/workflows/rust.yaml)

# Reliable Message Bus

Reliable message bus is a secure communication panel that allows `bots` to communicate together in a `chat` like way. It makes it very easy to host a service or a set of functions to be used by anyone, even if your service is running behind NAT.

Out of the box RMB provides the following:

- Guarantee authenticity of the messages. You are always sure that the received message is from whoever is pretending to be
- End to End encryption
- Support for 3rd party hosted relays. Anyone can host a relay and people can use it safely since there is no way messages can be inspected while using e2e. That's similar to `home` servers by `matrix`

## Why

RMB is developed by ThreefoldTech to create a global network of nodes that are available to host capacity. Each node will act like a single bot where you can ask to host your capacity. This enforced a unique set of requirements:

- Communication needed to be reliable
- Minimize and completely eliminate message loss
- Reduce downtime
Expand All @@ -18,33 +22,42 @@ RMB is developed by ThreefoldTech to create a global network of nodes that are a
- Fast request response time

Starting from this we came up with a more detailed requirements:

- User (or rather bots) need their identity maintained by `tfchain` (a blockchain) hence each bot needs an account on tfchain to be able to use `rmb`
- Then each message then can be signed by the `bot` keys, hence make it easy to verify the identity of the sender of a message. This is done both ways.
- To support federation (using 3rd party relays) we needed to add e2e encryption to make sure messages that are surfing the public internet can't be sniffed
- e2e encryption is done by deriving an encryption key from the same identity seed, and share the public key on `tfchain` hence it's available to everyone to use

## Specification

For details about protocol itself please check the [docs](docs/readme.md)

## How to use

There are many ways to use `rmb` because it was built for `bots` and software to communicate. Hence, there is no mobile app for it for example, but instead a set of libraries where you can use to connect to the network, make chitchats with other bots then exit.

Or you can keep the connection forever to answer other bots requests if you are providing a service.

### If there is a library in your preferred language

Then you are in luck, follow the library documentations to implement a service bot, or to make requests to other bots.

#### known libraries
- Golang [rmb-sdk-go](https://github.com/threefoldtech/rmb-sdk-go)
- Typescript [rmb-sdk-ts](https://github.com/threefoldtech/rmb-sdk-ts)

- Golang [rmb-sdk-go](https://github.com/threefoldtech/tfgrid-sdk-go/tree/development/rmb-sdk-go)
- Typescript [rmb-sdk-ts](https://github.com/threefoldtech/tfgrid-sdk-ts)

### Well, I am not that lucky

In that case:

- Implement a library in your preferred language
- If it's too much to do all the signing, verification, e2e in your language then use `rmb-peer`

## What is rmb-peer

think of `rmb-peer` as a gateway that stands between you and the `relay`. `rmb-peer` uses your mnemonics (your identity secret key) to assume your identity and it connects to the relay on your behalf, it maintains the connection forever and takes care of

- reconnecting if connection was lost
- verifying received messages
- decrypting received messages
Expand All @@ -55,9 +68,11 @@ Then it provide a simple (plain-text) api over `redis`. means to send messages (
> More details about the structure of the messages are also in the [docs](docs/readme.md) page
## Download

Please check the latest [releases](https://github.com/threefoldtech/rmb-rs/releases) normally you only need the `rmb-peer` binary, unless you want to host your own relay.

## Build from source

### Perquisites

- download Rustup and install Rust, run the following in your terminal, then follow the on-screen instructions:
Expand Down Expand Up @@ -93,43 +108,54 @@ This allows you to compile Rust programs that can run on Linux systems that do n

- Redis:
- Install Redis server using the apt package manager:

```bash
sudo apt update
sudo apt install redis-server
```

- Configure Redis server by editing the `/etc/redis/redis.conf` file (optional)
- Enable Redis server to start automatically on boot:

```bash
sudo systemctl enable redis-server
```

- Start Redis server using systemd:

```bash
sudo systemctl start redis-server
```

### Building

```bash
git clone [email protected]:threefoldtech/rmb-rs.git
cd rmb-rs
cargo build --release --target=x86_64-unknown-linux-musl
```

### Troubleshooting

- If you encounter an error like the one below, it is likely that the `protoc` version installed by your package manager is too old.

```bash
--- stderr
types.proto: This file contains proto3 optional fields, but --experimental_allow_proto3_optional was not set.
codegen failed: parse and typecheck
```

**Solution**: The best way to ensure that you’re using the latest release of `protoc` is installing from pre-compiled binaries. See perquisites.


- A peer must use a unique `mnemonic` or keys. It's not correct if multiple peers uses the same mnemonic this will make it impossible to route messages correctly. It's possible for the same peer to make multiple connections to the same `relay` given that it uses different `session ids`. A session id identify the connection and hence make routing messages possible.
- A single peer on the other hand can make multiple connections to multiple relays for redundancy given that his data on the tfchain must reflect that

> RUNNING MULTIPLE PEERS WITH THE SAME MNEMONIC MUST BE AVOIDED UNLESS FOLLOWING THE GUIDE LINES ABOVE

### Running tests

While inside the repository

```bash
cargo test
```
26 changes: 23 additions & 3 deletions docs/code-guide.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
# Coding guides

> This document will always be `work in progress` and will get updated every time something comes up
# Coding guides
This documents will maintain the coding guide for this project. We will try to keep it up-to-date with what we find more useful and cleaner.

## module structure

in rust there are multiple ways to create a (sub)module in your crate

- `<module>.rs` A single file module. can be imported in `main.rs` or `lib.rs` with the keyword `mod`
- `<module>/mod.rs` A directory module. Uses mod.rs as the module `entrypoint` always. Other sub-modules can be created next to mod.rs and can be made available by using the `mod` keyword again in the `mod.rs` file.

We will agree to use the 2nd way (directory) but with the following restrictions:

- `mod.rs` will have all `traits` and `concrete types` used by the traits.
- `<implementation>.rs` file next to `mod.rs` that can include implementation for the module trait.
z

### Example

Following is an example of `animal` module.

```
Expand All @@ -25,6 +31,7 @@ animal/
> File names are always in `snake_case` but avoid the `_` as much as possible because they basically look ugly in file tree. For example we prefer the name `dog.rs` over `dog_animal.rs` because we already can tell from the module name that it's a `dog` __animal__. Hence in the identity module for example the name `ed25519.rs` is preferred over `ed25519_identity.rs` because that's already inferred from the module name.
The `mod.rs` file then can contain

```rust
pub mod dog;
pub mod cat;
Expand All @@ -44,6 +51,7 @@ where
```

The `dog.rs` file then can contain

```rust
use super::{Animal, Food};

Expand All @@ -64,10 +72,13 @@ impl Animal<DogFood> for Dog {
```

A user of the module now can do

```
use animal::dog::{Dog, DogFood};
```

For common implementation that are usually used in your modules, a `pub use` can be added in `mod.rs` to make it easier to import your type. For example

```rust
// dog is brought directly from animal crate
use animal::Dog;
Expand All @@ -76,16 +87,19 @@ use animal::cat::Cat;
```

## naming conventions

following the rust guide lines for name

- `file names` are short snake case. avoid `_` if otherwise name will not be descriptive. Check note about file names above.
- `trait`, `struct`, `enum` names are all `CamelCase`
- `fn`, `variables` names are snake case

Note, names of functions and variables need to be `descriptive` but **short** at the same time. Also avoid the `_` until absolutely necessary. A variable with a single `word` name is better if it doesn't cause confusion with other variables in the same context.
Note, names of functions and variables need to be `descriptive` but __short__ at the same time. Also avoid the `_` until absolutely necessary. A variable with a single `word` name is better if it doesn't cause confusion with other variables in the same context.

The name of the variable should never include the `type`.

## `error` Handling

We agreed to use `anyhow` crate in this project. Please read the docs for [`anyhow`](https://docs.rs/anyhow/1.0.57/anyhow/)

To unify the practice by default we import both `Result` and `Context` from `anyhow`
Expand All @@ -112,27 +126,33 @@ fn might_fail2() -> Result<()> {
```

## `logs`

logging is important to trace the errors that cannot be propagated and also for debug messages that can help spotting a problem. We always gonna use `log` crate. as

```rust
log::debug!(); // for debug messages
log::info!(); // info messages
```

Note only `errors` that can **NOT** be propagated are logged.
Note only `errors` that can __NOT__ be propagated are logged.

> NOTE: All log messages start with lowercase.
>
## function signatures

For function inputs (arguments) `generic` types are preferred if available over concrete types. This most obvious with `string` types. depending on the function behavior

### Examples

This is bad

```rust
fn call1(key: String);
fn call2(key: &str);
```

and preferred to use

```rust
// in case function will need to take ownership of the string.
fn call1<k: Into<String>>(k: K);
Expand Down
Loading

0 comments on commit 23ab5c1

Please sign in to comment.