Skip to content

Commit

Permalink
Merge pull request #30 from omnia-network/release-1.4.0
Browse files Browse the repository at this point in the history
chore: release v1.4.0
  • Loading branch information
ilbertt authored Mar 21, 2024
2 parents 366243f + 1c4e8aa commit b48d8e8
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 31 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 56 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# IC WebSocket Gateway

[![GitHub Release](https://img.shields.io/github/v/release/omnia-network/ic-websocket-gateway)](https://github.com/omnia-network/ic-websocket-gateway/releases)
[![GitHub License](https://img.shields.io/github/license/omnia-network/ic-websocket-gateway)](https://github.com/omnia-network/ic-websocket-gateway/blob/main/LICENSE)
[![Docker Pulls](https://img.shields.io/docker/pulls/omniadevs/ic-websocket-gateway?logo=docker)](https://hub.docker.com/r/omniadevs/ic-websocket-gateway)

WebSockets enable web applications to maintain a full-duplex connection between the backend and the frontend. This allows for many different use-cases, such as notifications, dynamic content updates (e.g., showing new comments/likes on a post), collaborative editing, etc.

At the moment, the Internet Computer does not natively support WebSocket connections and developers need to resort to work-arounds in the frontend to enable a similar functionality. This results in a poor developer experience and an overload of the backend canister.
Expand All @@ -8,12 +12,10 @@ This repository contains the implementation of a WebSocket Gateway enabling clie

# Running the WS Gateway

## Prerequisites
## Standalone

Make sure you have the **Rust toolchain** installed. You can find instructions [here](https://www.rust-lang.org/tools/install).

## Standalone

1. Run the gateway:

In **debug** mode:
Expand All @@ -39,25 +41,57 @@ Make sure you have the **Rust toolchain** installed. You can find instructions [
2024-03-14T11:19:33.650018Z INFO ic_websocket_gateway::manager: Start accepting incoming connections
```

### Options available
### Arguments available

There are some command line arguments that you can set when running the gateway:
| Argument | Description | Default |
| --- | --- | --- |
| `--gateway-address` | The **IP:port** on which the gateway will listen for incoming connections. | `0.0.0.0:8080` |
| `--ic-network-url` | The URL of the IC network to which the gateway will connect. | `http://127.0.0.1:4943` |
| `--polling-interval` | The interval (in **milliseconds**) at which the gateway will poll the canisters for new messages. | `100` |
| `--prometheus-endpoint` | The **IP:port** on which the gateway will expose Prometheus metrics. | `0.0.0.0:9090` |
| `--tls-certificate-pem-path` | The path to the TLS certificate file. See [Obtain a TLS certificate](#obtain-a-tls-certificate) for more details. | _empty_ |
| `--tls-certificate-key-pem-path` | The path to the TLS private key file. See [Obtain a TLS certificate](#obtain-a-tls-certificate) for more details. | _empty_ |
| `--opentelemetry-collector-endpoint` | OpenTelemetry collector endpoint. See [Tracing telemetry](#tracing-telemetry) for more details. | _empty_ |

## Docker

A [Dockerfile](./Dockerfile) is provided, together with the files [docker-compose.yml](./docker-compose.yml), [docker-compose-local.yml](./docker-compose-local.yml) and [docker-compose-prod.yml](./docker-compose-prod.yml) to run the gateway according to the needs. Make sure you have [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/) installed.
Make sure you have [Docker](https://docs.docker.com/get-docker/) installed.

A [Dockerfile](./Dockerfile) is provided. To build the image, run:

```bash
docker build -t ic-websocket-gateway .
```

Then, run the gateway with the following command:

```bash
docker run -p 8080:8080 ic-websocket-gateway
```

A Docker image is also available at [omniadevs/ic-websocket-gateway](https://hub.docker.com/r/omniadevs/ic-websocket-gateway), that you can run with the following command:

A Docker image is also available at [omniadevs/ic-websocket-gateway](https://hub.docker.com/r/omniadevs/ic-websocket-gateway). This is the image used in the [docker-compose.yml](./docker-compose.yml) file.
```bash
docker run -p 8080:8080 omniadevs/ic-websocket-gateway
```

Have a look at the [Arguments available](#arguments-available) to configure the gateway for your needs.

## Docker Compose

Make sure you have [Docker Compose](https://docs.docker.com/compose/install/) installed.

The following compose files are available:

- [docker-compose.yml](./docker-compose.yml)
- [docker-compose-local.yml](./docker-compose-local.yml)
- [docker-compose-prod.yml](./docker-compose-prod.yml)

The following sections describe how to use the different compose files to run the gateway with Docker Compose.

### Local

To run the gateway in a local environment with Docker Compose, follow these steps:
1. To run all the required local structure you can execute the [start_local_docker_environment.sh](./scripts/start_local_docker_environment.sh) with the command:

Expand All @@ -71,18 +105,24 @@ To run the gateway in a local environment with Docker Compose, follow these step
docker compose -f docker-compose.yml -f docker-compose-local.yml --env-file .env.local up -d --build
```

2. To stop and clean all the local environment a bash script [stop_local_docker_environment.sh](./scripts/stop_local_docker_environment.sh) is provided. You can execute it with the command:
2. To stop and clean all the local environment, the bash script [stop_local_docker_environment.sh](./scripts/stop_local_docker_environment.sh) is provided. You can execute it with the command:

```
./scripts/stop_local_docker_environment.sh
```

3. The Gateway will print its principal in the container logs, just as explained above.
4. If you want to verify that all is started correctly a bash script [run_test_canister.sh](./scripts/run_test_canister.sh) is provided. This assumes that the gateway is already running.
3. The Gateway will print its principal in the container logs, just as explained in the [Standalone](#standalone) section.
4. If you want to verify that everything started correctly, the bash script [run_test_canister.sh](./scripts/run_test_canister.sh) is provided. This script assumes that the gateway is already running and reachable locally. You can execute it with the command:

```
./scripts/run_test_canister.sh
```

### Production

To run the gateway in a prod environment with Docker Compose, follow these steps:
This configuration uses the [omniadevs/ic-websocket-gateway](https://hub.docker.com/r/omniadevs/ic-websocket-gateway) image.

To run the gateway in a production environment with Docker Compose, follow these steps:
1. Set the environment variables:

```
Expand All @@ -91,26 +131,26 @@ To run the gateway in a prod environment with Docker Compose, follow these steps

2. To run the [docker-compose-prod.yml](./docker-compose-prod.yml) file you need a public domain (that you will put in the `DOMAIN_NAME` environment variable) and a TLS certificate for that domain (because it is configured to make the gateway run with TLS enabled). See [Obtain a TLS certificate](#obtain-a-tls-certificate) for more details.
3. Open the `443` port (or the port that you set in the `LISTEN_PORT` environment variable) on your server and make it reachable from the Internet.
4. To run all the required production structure you can execute the [start_prod_docker_environment.sh](./scripts/start_prod_docker_environment.sh) with the command:
4. To run all the required production containers you can execute the [start_prod_docker_environment.sh](./scripts/start_prod_docker_environment.sh) with the command:

```
./scripts/start_prod_docker_environment.sh
```

This script firstly generated the `telemetry/prometheus/prometheus-prod.yml` config file starting from the `telemetry/prometheus/prometheus-template.yml` (step required to perform the variable substitution) and then simply run the gateway with the following command:
This script first generates the `telemetry/prometheus/prometheus-prod.yml` config file from the `telemetry/prometheus/prometheus-template.yml` template (step required to perform the environment variables substitution) and then runs the gateway with the following command:

```
docker compose -f docker-compose.yml -f docker-compose-prod.yml --env-file .env up -d --build
docker compose -f docker-compose.yml -f docker-compose-prod.yml --env-file .env up -d
```

5. To stop and clean all the local environment a bash script [stop_prod_docker_environment.sh](./scripts/stop_prod_docker_environment.sh) is provided. You can execute it with the command:
5. To stop and clean the containers, the bash script [stop_prod_docker_environment.sh](./scripts/stop_prod_docker_environment.sh) is provided. You can execute it with the command:

```
./scripts/stop_prod_docker_environment.sh
```
6. The Gateway will print its principal in the container logs, just as explained above.
6. The Gateway will print its principal in the container logs, just as explained in the [Standalone](#standalone) section.

### Obtain a TLS certificate
#### Obtain a TLS certificate

1. Buy a domain name and point it to the server where you are running the gateway.
2. Make sure the `.env` file is configured with the correct domain name, see above.
Expand Down
2 changes: 1 addition & 1 deletion src/ic-websocket-gateway/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ic_websocket_gateway"
version = "1.3.3"
version = "1.4.0"
edition.workspace = true
rust-version.workspace = true
repository.workspace = true
Expand Down
24 changes: 12 additions & 12 deletions src/ic-websocket-gateway/src/gateway_metrics.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
use std::error::Error;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::time::Duration;
use metrics::{describe_gauge, describe_histogram, gauge};
use metrics_exporter_prometheus::PrometheusBuilder;
use metrics_util::{MetricKindMask};
use metrics_util::MetricKindMask;
use std::error::Error;
use std::net::SocketAddr;
use std::str::FromStr;
use std::time::Duration;

pub fn init_metrics(port: Option<u16>) -> Result<(), Box<dyn Error>> {
let builder = PrometheusBuilder::new()
.with_http_listener(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), port.unwrap_or(9000)));
pub fn init_metrics(address: &str) -> Result<(), Box<dyn Error>> {
let builder = PrometheusBuilder::new().with_http_listener(SocketAddr::from_str(address)?);

// Set the idle timeout for counters and histograms to 30 seconds then the metrics are removed from the registry
builder
.idle_timeout(
MetricKindMask::ALL,
Some(Duration::from_secs(30)),
)
.idle_timeout(MetricKindMask::ALL, Some(Duration::from_secs(30)))
.install()
.expect("failed to install Prometheus recorder");

describe_gauge!("clients_connected", "The number of clients currently connected");
describe_gauge!(
"clients_connected",
"The number of clients currently connected"
);
describe_gauge!("active_pollers", "The number of pollers currently active");
describe_histogram!(
"connection_duration",
Expand Down
6 changes: 5 additions & 1 deletion src/ic-websocket-gateway/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ struct DeploymentInfo {
/// Time interval (in milliseconds) at which the canisters are polled.
polling_interval: u64,

#[structopt(long, default_value = "0.0.0.0:9000")]
/// Prometheus endpoint on which the metrics are exposed.
prometheus_endpoint: String,

#[structopt(long)]
tls_certificate_pem_path: Option<String>,

Expand Down Expand Up @@ -79,7 +83,7 @@ async fn main() -> Result<(), String> {
)
.expect("could not init tracing");

init_metrics(None).expect("could not init metrics");
init_metrics(&deployment_info.prometheus_endpoint).expect("could not init metrics");

// must be printed after initializing tracing to ensure that the info are captured
info!("Deployment info: {:?}", deployment_info);
Expand Down

0 comments on commit b48d8e8

Please sign in to comment.