Skip to content

Commit

Permalink
lesson 18 immortal
Browse files Browse the repository at this point in the history
  • Loading branch information
alembiq committed Jul 3, 2024
1 parent c4977be commit 9d1e890
Show file tree
Hide file tree
Showing 10 changed files with 941 additions and 56 deletions.
825 changes: 795 additions & 30 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
[16](https://www.dropbox.com/scl/fi/3hf3ystbijpvu57f48yua/Lecture-16.MP4?rlkey=qntbm0gmjrt5xr3hjom3drktl&st=t3t5gzuj&dl=0&authuser=0)
[17](https://www.dropbox.com/scl/fi/m182zj2hjvn95dckx3616/Lecture-17.MP4?rlkey=9k5f1qub18fkme81v6x1jzozk&st=pg3833ad&dl=0&authuser=0)
[18](https://www.dropbox.com/scl/fi/zglhfknjwa39ywefwjox7/Lecture-18.MP4?rlkey=fmb6j1fmzk1zr1imyxbrivipr&st=iutxkn02&dl=0&authuser=0)
19 20
[19](https://www.dropbox.com/scl/fi/of3f02n3xdcuwfostpciu/Lecture-19.MP4?rlkey=068dvc8udx5nd6508s04j2xvw&st=88l3kw9v&dl=0&authuser=0)
20

- **DevStreams**:
[1](https://www.dropbox.com/scl/fi/t7wfwubrl0361bjwxd5vx/DevStream-1.MP4?rlkey=4i319jzky1eqa3omcbpziuqum&st=t93zhcji&dl=0&authuser=0)
Expand Down
20 changes: 20 additions & 0 deletions files/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[workspace]

members = [
"lesson01",
"lesson02",
"lesson05",
"lesson07",
"lesson09",
"lesson11/shared",
"lesson11/client",
"lesson11/server",
"lesson13/client13",
"lesson13/server13",
"lesson13/shared13",
"lesson15",
"lesson16",
"lesson17",
"lesson18",
]
resolver = "2"
67 changes: 67 additions & 0 deletions files/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
[![Rust](https://github.com/alembiq/rust-developer/actions/workflows/rust.yml/badge.svg)](https://github.com/alembiq/rust-developer/actions/workflows/rust.yml)


# Some random notes and links ;)
## Course related links
- [classroom](https://classroom.google.com/c/NjU2NTMyOTI1NDY3)
- [wiki](https://robot-dreams-rust.mag.wiki/)
- [demo homeworks](https://github.com/Global-Classes-CZE/rust_developer)
#### Recordings
- **Lessons**: [01](https://www.dropbox.com/scl/fi/lxzebh9t16gbuv1nv7v30/Lecture-1.MP4?rlkey=undugghhtnh09leavcgaijn39&st=of9h4va9&dl=0&authuser=0)
[02](https://www.dropbox.com/scl/fi/c5lfm2csaaf7vyz7mgz4c/Lecture-2.MP4?rlkey=pp2w2v2ig054mwf528ogysw4w&st=szbwx2i8&dl=0&authuser=0)
[03](https://www.dropbox.com/scl/fi/e1w9x1p7uqcy2187zgunc/Lecture-3.MP4?rlkey=ocl82uzyoftcwum80wbhlomau&st=u7ybpxv1&dl=0&authuser=0)
[04](https://www.dropbox.com/scl/fi/nfg8qzqlsz7wj7o4kw23p/Lecture-4.MP4?rlkey=gm1h6c3zsd2uqj9f5dah6h46k&st=6z34788w&dl=0&authuser=0)
[05](https://www.dropbox.com/scl/fi/7tlhvg0835y86zi54i9lm/Lecture-5.MP4?rlkey=kkzoq6xq9246meb5316zi33kq&st=84ijzbfy&dl=0&authuser=0)
[06](https://www.dropbox.com/scl/fi/lvm9n122m6c4rvlus5n8h/Lecture-6.MP4?rlkey=v7pvm0dk4khinpzh5984s9uyw&st=kbw3xtjp&dl=0&authuser=0)
[07](https://www.dropbox.com/scl/fi/vzhb43f02dpu6ole88jry/Lecture-7.MP4?rlkey=250sy13x9fk3oi4c4dsqh2kla&st=z2m6j0xt&dl=0&authuser=0)
[08](https://www.dropbox.com/scl/fi/6k06qmchswe25r99827fc/Lecture-8.MP4?rlkey=zlub7hiaxaio9rlhf8o3hvz1a&st=acznjiz9&dl=0&authuser=0)
[09](https://www.dropbox.com/scl/fi/pflqn1qat4de3qy0alm74/Lecture-9.MP4?rlkey=plthacxnqaerwzdebjy3y4g2d&st=6v63rh1j&dl=0&authuser=0)
[10](https://www.dropbox.com/scl/fi/5u4kfw7vkpx4p1q2h1x5d/Lecture-10.MP4?rlkey=i685dq56v03x3vl838a6hlv56&st=x3w2bjpr&dl=0&authuser=0)
[11](https://www.dropbox.com/scl/fi/d4x7w3teq2ay7x1f9ax3m/Lecture-11.MP4?rlkey=4r2zjeejkscxa4x39pv2fnlkw&st=defy23bb&dl=0&authuser=0)
[12](https://www.dropbox.com/scl/fi/af36dxkz7zloj7m5q29qa/Lecture-12.MP4?rlkey=y5lg76g08u21yrm2ib8i0bpfg&st=xh8g60jm&dl=0&authuser=0)
[13](https://www.dropbox.com/scl/fi/hbp7mcyfp99iv0219v9vq/Lecture-13.MP4?rlkey=0799t0it8opno8ea685zllmmv&st=64awwmen&dl=0&authuser=0)
[14](https://www.dropbox.com/scl/fi/u3dttgbaxgqdf8kh6fx3g/Lecture-14.MP4?rlkey=sbkut7t8m3xc45ppwsymv7zuj&st=xon10nni&dl=0&authuser=0)
[15](https://www.dropbox.com/scl/fi/qpdeda3kx646jnwaf8j1s/Lecture-15.MP4?rlkey=b4ng5msydqt5zpm3pz05lqmm7&st=edb0in9i&dl=0&authuser=0)
[16](https://www.dropbox.com/scl/fi/3hf3ystbijpvu57f48yua/Lecture-16.MP4?rlkey=qntbm0gmjrt5xr3hjom3drktl&st=t3t5gzuj&dl=0&authuser=0)
[17](https://www.dropbox.com/scl/fi/m182zj2hjvn95dckx3616/Lecture-17.MP4?rlkey=9k5f1qub18fkme81v6x1jzozk&st=pg3833ad&dl=0&authuser=0)
[18](https://www.dropbox.com/scl/fi/zglhfknjwa39ywefwjox7/Lecture-18.MP4?rlkey=fmb6j1fmzk1zr1imyxbrivipr&st=iutxkn02&dl=0&authuser=0)
[19](https://www.dropbox.com/scl/fi/of3f02n3xdcuwfostpciu/Lecture-19.MP4?rlkey=068dvc8udx5nd6508s04j2xvw&st=88l3kw9v&dl=0&authuser=0)
20

- **DevStreams**:
[1](https://www.dropbox.com/scl/fi/t7wfwubrl0361bjwxd5vx/DevStream-1.MP4?rlkey=4i319jzky1eqa3omcbpziuqum&st=t93zhcji&dl=0&authuser=0)
[2](https://www.dropbox.com/scl/fi/n8mk9lfylmgtpfnnr15lr/DevStream-2.MP4?rlkey=3ixyjsujkif074729ttavj4l8&st=c1c3hfu7&dl=0&authuser=0)
3

#### Classmates homeworks ;)
- [abergasov](https://github.com/abergasov/rd_rust)
- [bhoglo](https://github.com/bhoglo/projects/)
- [bieleluk](https://github.com/bieleluk/rust-developer)
- [b-rowan](https://github.com/b-rowan/braiins-rust-course)
- [czJanKrejci](https://github.com/czJanKrejci/RustDeveloper)
- [HarryRybacki](https://github.com/HarryRybacki/rust_developer)
- [Hugoargui](https://github.com/Hugoargui/rust/)
- [i4nf0x](https://github.com/i4nf0x/rust_course/)
- [JakubKuljovsky](https://github.com/JakubKuljovsky/rust_homeworks)
- [jiri-sedlacek](https://github.com/jiri-sedlacek/rust_course)
- Ma5thewbond [1](https://github.com/ma5thewbond/rust_01_helloworld) [5](https://github.com/ma5thewbond/rust_05_csv_parser/tree/main) [7](https://github.com/ma5thewbond/rust_07_threads)
[9](https://github.com/ma5thewbond/rust_09_networking) [15](https://github.com/ma5thewbond/rust_15_async_chat)
- [moribusV](https://github.com/moribusV/rustCourse/)
- [nlukic97](https://github.com/nlukic97/rust1)
- [oceanbreath](https://github.com/oceanbreath/rust_course)
- [smoofy24](https://github.com/smoofy24/Rust_project)
- [Standazwicky](https://github.com/Standazwicky/rust_homeworks)

# Tools/links
- [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021)

## Environment
So far, I'm running these:
- [Rust on NixOs](https://nixos.wiki/wiki/Rust)
- [Rust overlay](https://github.com/oxalica/rust-overlay)
- [direnv to get `nix develop` to VS terminal](https://marketplace.visualstudio.com/items?itemName=mkhl.direnv)

Alternatives I didn't look into yet
- [crane](https://github.com/ipetkov/crane)
- [naersk](https://github.com/nix-community/naersk)
- [fenix](https://github.com/nix-community/fenix)
4 changes: 2 additions & 2 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
openssl
pkg-config
bacon
# rust-bin.stable.latest.default
rust-bin.beta.latest.default
rust-bin.stable.latest.default
# rust-bin.beta.latest.default
];
};
}
Expand Down
3 changes: 3 additions & 0 deletions lesson18/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ parking_lot = "0.12.3"
eyre = "0.6.12"
prometheus = "0.13.4"
lazy_static = "1.5.0"
actix-web = "4.8.0"
futures = "0.3.30"
tokio = { version = "1.38.0", features = ["full"] }
2 changes: 1 addition & 1 deletion lesson18/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Server and client that can send messages, files and images (yes, those are also
## Usage
You can simply run the `server` and it will start listening on 127.0.0.1:11111. Or you can start it on a specific IP and port - `server18 10.0.42.101:1234`. The same parameter works also for the `client`, it also tries to connect to the same default as server unless you provide server address specifically.

The server also provides some [Prometheus](https://prometheus.io/) metrics you can scrape on `your_ip:9090/metrics`. This will allow you to monitor number of messages processed by the chat app, same as number of active clients and all the client over the runtime of the server.
The server also provides some [Prometheus](https://prometheus.io/) metrics you can scrape on `your_ip:11112/metrics`. This will allow you to monitor number of messages processed by the chat app, same as number of active clients and all the client over the runtime of the server.

# Requirements for this homework ;)

Expand Down
2 changes: 1 addition & 1 deletion lesson18/docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ services:
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
ports:
- "3123:3000"
- "3000:3000"
depends_on:
- prometheus
2 changes: 1 addition & 1 deletion lesson18/docker/prometheus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ global:
scrape_configs:
- job_name: 'rust_application'
static_configs:
- targets: ['<url>:10002']
- targets: ['<url>:11112']
69 changes: 49 additions & 20 deletions lesson18/src/bin/server18.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,77 @@
use std::collections::HashMap;
use std::env;
use std::io::Result as IoResult;
use std::net::{SocketAddr, TcpListener, TcpStream};
use std::sync::Arc;
use std::thread;

use actix_web::{http::StatusCode, web, App, HttpResponse, HttpServer, Responder};
use eyre::{bail, Result};
use parking_lot::Mutex;
// use prometheus::{Gauge, Opts, Registry, Counter};
use lazy_static::lazy_static;
use parking_lot::Mutex;
use prometheus::{
self, register_int_counter, register_int_gauge, Encoder, IntCounter, IntGauge, TextEncoder,
self, gather, register_int_counter, register_int_gauge, Encoder, IntCounter, IntGauge,
Registry, TextEncoder,
};

use lesson18::{incoming_message, outgoing_message, server_address, timestamp, MessageType};

lazy_static! {
static ref REGISTRY: Registry = Registry::new();
static ref COUNTER_MESSAGE_TEXT: IntCounter =
register_int_counter!("message_text", "Text messages delivered").unwrap();
static ref COUNTER_MESSAGE_FILE: IntCounter =
register_int_counter!("message_file", "Files delivered").unwrap();
static ref COUNTER_MESSAGE_IMAGE: IntCounter =
register_int_counter!("message_image", "Images delivered").unwrap();
static ref COUNTER_CLIENTS: IntCounter =
register_int_counter!("clients", "Clients over time").unwrap();
register_int_counter!("clients_runtime", "Clients over time").unwrap();
static ref GAUGE_CLIENTS: IntGauge =
register_int_gauge!("clients_current", "Active clients").unwrap();
}

fn main() -> Result<()> {
/// Generates Prometheus metrics
async fn metrics() -> impl Responder {
let encoder = TextEncoder::new();
let mut buf = vec![];

if let Err(e) = encoder.encode(&gather(), &mut buf) {
eprintln!("Failed to collect metrics: {e}");
return HttpResponse::build(StatusCode::INTERNAL_SERVER_ERROR)
.body("Failed to collect metrics!");
}
HttpResponse::build(StatusCode::OK).body(String::from_utf8(buf).unwrap())
}

/// Webserver for /metrics
async fn metrics_http() -> IoResult<()> {
let _ = HttpServer::new(|| App::new().route("/metrics", web::get().to(metrics)))
.bind("0.0.0.0:11112")
.expect("Failed to bind metrics endpoint")
.run()
.await;

Ok(())
}

#[tokio::main]
async fn main() -> Result<()> {
let server_address: String = server_address(env::args().collect());
println!("{} Starting server on {}!", timestamp(), server_address);

// Register & measure some metrics.
let mut buffer = Vec::new();
let encoder = TextEncoder::new();
// Gather the metrics.
let metric_families = prometheus::gather();
// Encode them to send.
encoder.encode(&metric_families, &mut buffer).unwrap();
let output = String::from_utf8(buffer.clone()).unwrap();
println!("{output:?}");
let metrics_handle = tokio::spawn(async {
let _ = metrics_http().await;
});
let server_handle = tokio::spawn(async {
let _ = listen_and_accept(server_address);
});

metrics_handle.await.unwrap();
server_handle.await.unwrap();

// Listen and process clients
listen_and_accept(server_address)?;
//TODO find a way how to terminate the server ;)
// listen_and_accept(server_address);

Ok(())
}
Expand Down Expand Up @@ -79,32 +107,33 @@ fn listen_and_accept(address: String) -> Result<()> {
Ok(msg) => msg,
Err(e) => {
eprintln!("{} {addr} stream interrupted: {e}", timestamp());
// TODO announce disconnected client to everyone and remove everywhere?
GAUGE_CLIENTS.dec();
break;
}
};

// message other clients
let mut clients_lock = clients_clone.lock();
let mut peers_to_remove = vec![];
let peers_to_remove = vec![];
for (peer_addr, peer_stream) in clients_lock.iter_mut() {
if *peer_addr == addr {
continue;
}

if let Err(e) = outgoing_message(peer_stream, &message) {
eprintln!("{} failed to send message: {message:?} -> {e}", timestamp());
peers_to_remove.push(*peer_addr);
}
}

// remove dead clients
for peer_addr in peers_to_remove {
clients_lock.remove(&peer_addr);
println!("remove dead client {}", &peer_addr);
}

drop(clients_lock);

//MESSAGE SNEAKPEAK
//MESSAGE SNEAKPEAK and COUNTERS
match message {
MessageType::Text(text) => {
println!("{} {addr}: {text:?}", timestamp());
Expand Down

0 comments on commit 9d1e890

Please sign in to comment.