feat: ✨ rtc peer connection offer
This commit is contained in:
parent
7434d131c4
commit
0aa65f0f60
17 changed files with 389 additions and 59 deletions
|
@ -1,8 +1,11 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
|
resolver = "3"
|
||||||
members = [
|
members = [
|
||||||
"client",
|
"client", "protocol",
|
||||||
"server",
|
"server",
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
serde = "1.0.219"
|
chrono = { version = "0.4.40", features = ["serde"] }
|
||||||
|
serde = { version = "1.0.219", features = ["derive"]}
|
||||||
|
serde_json = "1.0.140"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "rust_communication"
|
name = "rust_communication_client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
@ -7,7 +7,31 @@ edition = "2024"
|
||||||
console_error_panic_hook = "0.1.7"
|
console_error_panic_hook = "0.1.7"
|
||||||
leptos = { version = "0.7.8", features = ["csr"] }
|
leptos = { version = "0.7.8", features = ["csr"] }
|
||||||
wasm-bindgen-futures = "0.4.50"
|
wasm-bindgen-futures = "0.4.50"
|
||||||
web-sys = { version = "0.3.77", features = ["AudioBuffer", "AudioBufferSourceNode", "AudioContext", "HtmlAudioElement","MediaDevices", "MediaStream", "MediaStreamConstraints", "MediaStreamTrack", "MediaTrackConstraints", "MediaTrackConstraintSet", "Navigator", "Window"] }
|
reqwest = { version = "0.12.15", features = ["json"] }
|
||||||
|
web-sys = { version = "0.3.77", features = [
|
||||||
|
"AudioBuffer",
|
||||||
|
"AudioBufferSourceNode",
|
||||||
|
"AudioContext",
|
||||||
|
"HtmlAudioElement",
|
||||||
|
"MediaDevices",
|
||||||
|
"MediaStream",
|
||||||
|
"MediaStreamConstraints",
|
||||||
|
"MediaStreamTrack",
|
||||||
|
"MediaTrackConstraints",
|
||||||
|
"MediaTrackConstraintSet",
|
||||||
|
"Navigator",
|
||||||
|
"RtcConfiguration",
|
||||||
|
"RtcIceServer",
|
||||||
|
"RtcPeerConnection",
|
||||||
|
# "RtcSdpType",
|
||||||
|
"RtcSessionDescription",
|
||||||
|
"RtcSessionDescriptionInit",
|
||||||
|
"Window",
|
||||||
|
] }
|
||||||
|
protocol = { path = "../protocol" }
|
||||||
|
serde = { workspace = true }
|
||||||
|
serde_json = { workspace = true }
|
||||||
|
chrono = { workspace = true }
|
||||||
|
|
||||||
[profile]
|
[profile]
|
||||||
|
|
||||||
|
|
25
client/assets/main.css
Normal file
25
client/assets/main.css
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
/* font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; */
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 5%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.98);
|
||||||
|
color: silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 2%;
|
||||||
|
width: 7cap;
|
||||||
|
height: 3cap;
|
||||||
|
border-radius: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border-radius: 1%;
|
||||||
|
width: 10cap;
|
||||||
|
height: 2cap;
|
||||||
|
}
|
|
@ -1,6 +1,11 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head></head>
|
|
||||||
<h1>"Hello"</h1>
|
<head>
|
||||||
<body></body>
|
<link data-trunk rel="css" href="assets/main.css" />
|
||||||
|
</head>
|
||||||
|
<h1>"Hello"</h1>
|
||||||
|
|
||||||
|
<body></body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
use leptos::{
|
use leptos::{
|
||||||
IntoView, ev,
|
IntoView,
|
||||||
html::{ElementChild, button},
|
attr::Value,
|
||||||
|
ev,
|
||||||
|
html::{ElementChild, button, form, input},
|
||||||
logging::log,
|
logging::log,
|
||||||
prelude::{OnAttribute, Read, Show, ShowProps, ToChildren},
|
prelude::{BindAttribute, Get, OnAttribute, Read, Show, ShowProps, ToChildren, signal},
|
||||||
server::LocalResource,
|
server::LocalResource,
|
||||||
task::spawn_local,
|
task::spawn_local,
|
||||||
};
|
};
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
use web_sys::{
|
use web_sys::HtmlAudioElement;
|
||||||
HtmlAudioElement, MediaStream, MediaStreamConstraints, MediaStreamTrack, MediaTrackConstraints,
|
|
||||||
wasm_bindgen::{JsCast, JsValue},
|
use crate::{media::audio, rtc::offer, signal::start_signalling};
|
||||||
window,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn app() -> impl IntoView {
|
pub fn app() -> impl IntoView {
|
||||||
let audio_stream = LocalResource::new(|| media());
|
let audio_stream = LocalResource::new(|| audio());
|
||||||
let props = ShowProps::builder()
|
let props = ShowProps::builder()
|
||||||
.when(move || audio_stream.read().is_some())
|
.when(move || audio_stream.read().is_some())
|
||||||
.children(ToChildren::to_children(move || {
|
.children(ToChildren::to_children(move || {
|
||||||
|
@ -38,47 +38,42 @@ pub fn app() -> impl IntoView {
|
||||||
}))
|
}))
|
||||||
.fallback(|| button().child("Sad Button"))
|
.fallback(|| button().child("Sad Button"))
|
||||||
.build();
|
.build();
|
||||||
Show(props)
|
(Show(props), signalling(), rtc())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn media() -> MediaStream {
|
fn signalling() -> impl IntoView {
|
||||||
let media_devices = window().unwrap().navigator().media_devices().unwrap();
|
let signalling_server_input_data = signal(String::new());
|
||||||
let media_stream_constraints = MediaStreamConstraints::new();
|
let signalling_trigger = move || {
|
||||||
let media_track_constraints = MediaTrackConstraints::new();
|
spawn_local(start_signalling(
|
||||||
|
"Zurna Dürüm".to_string(),
|
||||||
|
signalling_server_input_data.0.get(),
|
||||||
|
))
|
||||||
|
};
|
||||||
|
let signalling_server_input = form()
|
||||||
|
.child(
|
||||||
|
input()
|
||||||
|
.bind(Value, signalling_server_input_data)
|
||||||
|
.placeholder("0.0.0.0:4546")
|
||||||
|
.r#type("text"),
|
||||||
|
)
|
||||||
|
.on(ev::submit, move |event| {
|
||||||
|
event.prevent_default();
|
||||||
|
signalling_trigger()
|
||||||
|
});
|
||||||
|
|
||||||
media_stream_constraints.set_audio(&JsValue::TRUE);
|
let signalling_submit_button = button()
|
||||||
|
.on(ev::click, move |_| signalling_trigger())
|
||||||
media_track_constraints.set_echo_cancellation(&JsValue::FALSE);
|
.child("Signal");
|
||||||
media_track_constraints.set_noise_suppression(&JsValue::FALSE);
|
(signalling_server_input, signalling_submit_button)
|
||||||
media_track_constraints.set_auto_gain_control(&JsValue::FALSE);
|
}
|
||||||
|
|
||||||
let media_stream_promise = media_devices
|
fn rtc() -> impl IntoView {
|
||||||
.get_user_media_with_constraints(&media_stream_constraints)
|
let rtc_trigger = || {
|
||||||
.unwrap();
|
spawn_local(offer());
|
||||||
let media_stream = JsFuture::from(media_stream_promise)
|
};
|
||||||
.await
|
|
||||||
.unwrap()
|
let rtc_start_button = button()
|
||||||
.dyn_into::<MediaStream>()
|
.on(ev::click, move |_| rtc_trigger())
|
||||||
.unwrap();
|
.child("RTC Offer");
|
||||||
let audio_stream_tracks = media_stream.get_audio_tracks();
|
rtc_start_button
|
||||||
let audio_stream_tracks = audio_stream_tracks
|
|
||||||
.iter()
|
|
||||||
.map(|audio_track| audio_track.dyn_into::<MediaStreamTrack>().unwrap())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
log!(
|
|
||||||
"{:#?}\n audio_stream_track_count = {}",
|
|
||||||
audio_stream_tracks,
|
|
||||||
audio_stream_tracks.len()
|
|
||||||
);
|
|
||||||
let audio_stream_track = audio_stream_tracks.first().unwrap();
|
|
||||||
let audio_stream_track_apply_constraints_promise = audio_stream_track
|
|
||||||
.apply_constraints_with_constraints(&media_track_constraints)
|
|
||||||
.unwrap();
|
|
||||||
JsFuture::from(audio_stream_track_apply_constraints_promise)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let audio_stream = MediaStream::new().unwrap();
|
|
||||||
log!("{:#?}", audio_stream_track.get_constraints());
|
|
||||||
audio_stream.add_track(audio_stream_track);
|
|
||||||
audio_stream
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
pub mod gui;
|
pub mod gui;
|
||||||
|
pub mod media;
|
||||||
|
pub mod rtc;
|
||||||
|
pub mod signal;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use leptos::mount::mount_to_body;
|
use leptos::mount::mount_to_body;
|
||||||
use rust_communication::gui::app;
|
use rust_communication_client::gui::app;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
|
|
49
client/src/media.rs
Normal file
49
client/src/media.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
use leptos::logging::log;
|
||||||
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
use web_sys::{
|
||||||
|
MediaStream, MediaStreamConstraints, MediaStreamTrack, MediaTrackConstraints,
|
||||||
|
wasm_bindgen::{JsCast, JsValue},
|
||||||
|
window,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub async fn audio() -> MediaStream {
|
||||||
|
let media_devices = window().unwrap().navigator().media_devices().unwrap();
|
||||||
|
let media_stream_constraints = MediaStreamConstraints::new();
|
||||||
|
let media_track_constraints = MediaTrackConstraints::new();
|
||||||
|
|
||||||
|
media_stream_constraints.set_audio(&JsValue::TRUE);
|
||||||
|
|
||||||
|
media_track_constraints.set_echo_cancellation(&JsValue::FALSE);
|
||||||
|
media_track_constraints.set_noise_suppression(&JsValue::FALSE);
|
||||||
|
media_track_constraints.set_auto_gain_control(&JsValue::FALSE);
|
||||||
|
|
||||||
|
let media_stream_promise = media_devices
|
||||||
|
.get_user_media_with_constraints(&media_stream_constraints)
|
||||||
|
.unwrap();
|
||||||
|
let media_stream = JsFuture::from(media_stream_promise)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.dyn_into::<MediaStream>()
|
||||||
|
.unwrap();
|
||||||
|
let audio_stream_tracks = media_stream.get_audio_tracks();
|
||||||
|
let audio_stream_tracks = audio_stream_tracks
|
||||||
|
.iter()
|
||||||
|
.map(|audio_track| audio_track.dyn_into::<MediaStreamTrack>().unwrap())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
log!(
|
||||||
|
"{:#?}\n audio_stream_track_count = {}",
|
||||||
|
audio_stream_tracks,
|
||||||
|
audio_stream_tracks.len()
|
||||||
|
);
|
||||||
|
let audio_stream_track = audio_stream_tracks.first().unwrap();
|
||||||
|
let audio_stream_track_apply_constraints_promise = audio_stream_track
|
||||||
|
.apply_constraints_with_constraints(&media_track_constraints)
|
||||||
|
.unwrap();
|
||||||
|
JsFuture::from(audio_stream_track_apply_constraints_promise)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let audio_stream = MediaStream::new().unwrap();
|
||||||
|
log!("{:#?}", audio_stream_track.get_constraints());
|
||||||
|
audio_stream.add_track(audio_stream_track);
|
||||||
|
audio_stream
|
||||||
|
}
|
38
client/src/rtc.rs
Normal file
38
client/src/rtc.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
use leptos::logging::log;
|
||||||
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
use web_sys::{
|
||||||
|
RtcConfiguration, RtcIceServer, RtcPeerConnection, RtcSessionDescriptionInit,
|
||||||
|
js_sys::{Array, Reflect},
|
||||||
|
wasm_bindgen::{JsCast, JsValue},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub async fn offer() {
|
||||||
|
let ice_server_addresses = vec![JsValue::from("stun:stun.l.google.com:19302")]
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Array>();
|
||||||
|
let ice_server = RtcIceServer::new();
|
||||||
|
ice_server.set_urls(&JsValue::from(ice_server_addresses));
|
||||||
|
let ice_servers = vec![ice_server].into_iter().collect::<Array>();
|
||||||
|
let rtc_configuration = RtcConfiguration::new();
|
||||||
|
rtc_configuration.set_ice_servers(&ice_servers);
|
||||||
|
let peer_connection = RtcPeerConnection::new_with_configuration(&rtc_configuration).unwrap();
|
||||||
|
let peer_connection_create_offer_promise = peer_connection.create_offer();
|
||||||
|
let rtc_session_offer = JsFuture::from(peer_connection_create_offer_promise)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
log!("{:#?}", rtc_session_offer);
|
||||||
|
let rtc_session_offer = rtc_session_offer
|
||||||
|
.as_ref()
|
||||||
|
.unchecked_ref::<RtcSessionDescriptionInit>();
|
||||||
|
log!("{:#?}", rtc_session_offer);
|
||||||
|
JsFuture::from(peer_connection.set_local_description(rtc_session_offer))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let rtc_session_offer = Reflect::get(&rtc_session_offer, &JsValue::from_str("sdp"))
|
||||||
|
.unwrap()
|
||||||
|
.as_string()
|
||||||
|
.unwrap();
|
||||||
|
log!("{}", rtc_session_offer);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn answer() {}
|
26
client/src/signal.rs
Normal file
26
client/src/signal.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
use chrono::DateTime;
|
||||||
|
use leptos::logging::log;
|
||||||
|
use protocol::Signal;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
pub async fn start_signalling(username: String, signal_address: String) {
|
||||||
|
log!("Start Signalling");
|
||||||
|
log!("{}\n{}", username, signal_address);
|
||||||
|
let request_client = reqwest::Client::new();
|
||||||
|
let signal = Signal {
|
||||||
|
username,
|
||||||
|
time: DateTime::default(),
|
||||||
|
};
|
||||||
|
let body = json!(signal);
|
||||||
|
match request_client.post(signal_address).json(&body).send().await {
|
||||||
|
Ok(signal_response) => log!("{:#?}", signal_response),
|
||||||
|
Err(err_val) => {
|
||||||
|
log!("Error: Signal Post | {}", err_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_offer() {}
|
||||||
|
pub async fn receive_offer() {}
|
||||||
|
pub async fn send_answer() {}
|
||||||
|
pub async fn receive_answer() {}
|
8
protocol/Cargo.toml
Normal file
8
protocol/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "protocol"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = { workspace = true }
|
||||||
|
chrono = { workspace = true }
|
8
protocol/src/lib.rs
Normal file
8
protocol/src/lib.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct Signal {
|
||||||
|
pub username: String,
|
||||||
|
pub time: DateTime<Utc>,
|
||||||
|
}
|
|
@ -1,6 +1,13 @@
|
||||||
[package]
|
[package]
|
||||||
name = "server"
|
name = "rust_communication_server"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
axum = { version = "0.8.3", features = ["json"] }
|
||||||
|
axum-macros = "0.5.0"
|
||||||
|
tokio = "1.42.1"
|
||||||
|
webrtc = "0.12.0"
|
||||||
|
serde = { workspace = true }
|
||||||
|
chrono = { workspace = true }
|
||||||
|
protocol = { path = "../protocol" }
|
||||||
|
|
74
server/src/lib.rs
Normal file
74
server/src/lib.rs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
use utils::naive_toml_parser;
|
||||||
|
|
||||||
|
pub mod signal;
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
|
const SERVER_CONFIG_FILE_LOCATION: &str = "./configs/server_config.toml";
|
||||||
|
const DATABASE_CONFIG_FILE_LOCATION: &str = "./configs/database_config.toml";
|
||||||
|
|
||||||
|
pub static SERVER_CONFIG: LazyLock<ServerConfig> = LazyLock::new(ServerConfig::default);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DatabaseConfig {
|
||||||
|
pub address: String,
|
||||||
|
pub username: String,
|
||||||
|
pub password: String,
|
||||||
|
pub database: String,
|
||||||
|
pub backend: String,
|
||||||
|
pub connection_pool_size: u32,
|
||||||
|
}
|
||||||
|
impl Default for DatabaseConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
let (header, mut database_configs) = naive_toml_parser(DATABASE_CONFIG_FILE_LOCATION);
|
||||||
|
|
||||||
|
if header == "[database_config]" {
|
||||||
|
Self {
|
||||||
|
address: database_configs.pop_front().unwrap().parse().unwrap(),
|
||||||
|
username: database_configs.pop_front().unwrap().parse().unwrap(),
|
||||||
|
password: database_configs.pop_front().unwrap().parse().unwrap(),
|
||||||
|
database: database_configs.pop_front().unwrap().parse().unwrap(),
|
||||||
|
backend: database_configs.pop_front().unwrap().parse().unwrap(),
|
||||||
|
connection_pool_size: database_configs.pop_front().unwrap().parse().unwrap(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Database Config File Must Include [database_config] at the First Line")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ServerConfig {
|
||||||
|
pub address: String,
|
||||||
|
pub otp_time_limit: usize,
|
||||||
|
pub login_token_expiration_time_limit: usize,
|
||||||
|
pub login_token_refresh_time_limit: usize,
|
||||||
|
pub concurrency_limit: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ServerConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
let (header, mut server_configs) = naive_toml_parser(SERVER_CONFIG_FILE_LOCATION);
|
||||||
|
let value_or_max = |value: String| value.parse().map_or(usize::MAX, |value| value);
|
||||||
|
let value_or_semaphore_max = |value: String| {
|
||||||
|
value
|
||||||
|
.parse()
|
||||||
|
.map_or(tokio::sync::Semaphore::MAX_PERMITS, |value| value)
|
||||||
|
};
|
||||||
|
|
||||||
|
if header == "[server_config]" {
|
||||||
|
Self {
|
||||||
|
address: server_configs.pop_front().unwrap().parse().unwrap(),
|
||||||
|
otp_time_limit: value_or_max(server_configs.pop_front().unwrap()),
|
||||||
|
login_token_expiration_time_limit: value_or_max(
|
||||||
|
server_configs.pop_front().unwrap(),
|
||||||
|
),
|
||||||
|
login_token_refresh_time_limit: value_or_max(server_configs.pop_front().unwrap()),
|
||||||
|
concurrency_limit: value_or_semaphore_max(server_configs.pop_front().unwrap()),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Server Config File Must Include [server_config] at the First Line")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,8 @@
|
||||||
fn main() {
|
use rust_communication_server::signal::start_signalling;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
|
|
||||||
|
tokio::spawn(start_signalling()).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
36
server/src/signal.rs
Normal file
36
server/src/signal.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use std::sync::{Arc, LazyLock, RwLock};
|
||||||
|
|
||||||
|
use axum::{
|
||||||
|
Json, Router,
|
||||||
|
http::StatusCode,
|
||||||
|
response::IntoResponse,
|
||||||
|
routing::{get, post},
|
||||||
|
};
|
||||||
|
use axum_macros::debug_handler;
|
||||||
|
use protocol::Signal;
|
||||||
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
|
static SIGNALS: LazyLock<Arc<RwLock<Vec<Signal>>>> =
|
||||||
|
LazyLock::new(|| Arc::new(RwLock::new(vec![])));
|
||||||
|
|
||||||
|
pub async fn start_signalling() {
|
||||||
|
let route = route();
|
||||||
|
let listener = TcpListener::bind("0.0.0.0:4546").await.unwrap();
|
||||||
|
axum::serve(listener, route).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn route() -> Router {
|
||||||
|
Router::new()
|
||||||
|
.route("/alive", get(alive))
|
||||||
|
.route("/", post(signal))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn alive() -> impl IntoResponse {
|
||||||
|
StatusCode::OK
|
||||||
|
}
|
||||||
|
|
||||||
|
#[debug_handler]
|
||||||
|
async fn signal(Json(signal): Json<Signal>) -> impl IntoResponse {
|
||||||
|
SIGNALS.write().unwrap().push(signal);
|
||||||
|
StatusCode::OK
|
||||||
|
}
|
24
server/src/utils.rs
Normal file
24
server/src/utils.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use std::{collections::VecDeque, fs::File, io::Read};
|
||||||
|
|
||||||
|
pub fn naive_toml_parser(file_location: &str) -> (String, VecDeque<String>) {
|
||||||
|
let mut toml_file = File::open(file_location).unwrap();
|
||||||
|
let mut toml_ingredients = String::default();
|
||||||
|
toml_file.read_to_string(&mut toml_ingredients).unwrap();
|
||||||
|
let mut toml_ingredients = toml_ingredients.lines().collect::<VecDeque<&str>>();
|
||||||
|
|
||||||
|
let header = toml_ingredients.pop_front().unwrap().trim_end().to_string();
|
||||||
|
let parsed = toml_ingredients
|
||||||
|
.iter()
|
||||||
|
.map(|ingredient| {
|
||||||
|
ingredient
|
||||||
|
.split_once('=')
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
.replace('"', "")
|
||||||
|
.trim()
|
||||||
|
.to_string()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
(header, parsed)
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue