freechat/json-api/src/rtc.rs
shockrah 7c8bc8b4fc - Removing warning
! Increasing wait time on client mock script to avoid firing too early
2021-05-01 19:16:18 -07:00

140 lines
3.9 KiB
Rust

/*
* This whole module contains functions that are optionally built for those
* (((weirdos))) that don't want rtc capabilities.
*
* General configuration things
* RTC server should run on the same system
*
* Features TODO: make this fully module so that rtc & api can run on seperate
* servers if need be. This can be configured with .env most likely and the rtc
* private api can probably be a really simple auth'd REST API,
* prolly don't even need much in the way of authentication as long as the API key
* is sufficiently large & securely transferred on both parties behalf
*/
use std::time::{SystemTime, UNIX_EPOCH};
use mysql_async::Pool;
use tokio_tungstenite::connect_async;
use tokio_tungstenite::tungstenite::{Error, Message};
use futures::{StreamExt, SinkExt};
use serde::Serialize;
use serde_json::json;
use jsonwebtoken::{
Header, Algorithm, EncodingKey
};
use url::Url;
lazy_static! {
static ref HMAC_SECRET: Vec<u8> = {
let path = match std::env::var("WSS_HMAC_PATH") {
Ok(p) => p,
Err(_) => "wss-hmac.secret".into()
};
std::fs::read(path).expect("Couldn't get HMAC secret")
};
static ref WSS_KEY: EncodingKey = {
EncodingKey::from_secret(&HMAC_SECRET)
};
}
macro_rules! event {
($type:expr, $payload:expr) => {
json!({"type": $type, $type: $payload})
}
}
#[derive(Serialize)]
struct Claim {
nbf: i64
}
fn make_url() -> Url {
let claim = Claim {
nbf: SystemTime::now()
.duration_since(UNIX_EPOCH).unwrap()
.as_secs() as i64
};
let header = Header::new(Algorithm::HS512);
let jwt = jsonwebtoken::encode(&header, &claim, &WSS_KEY).unwrap();
let base = "ws://localhost:5648/jwt";
let mut url = Url::parse(base).unwrap();
url.query_pairs_mut().append_pair("jwt", jwt.as_str());
url
}
async fn notify<P>(event_name: &str, payload: P)
-> Result<(), Error> where
P: Serialize
{
// Flow: Connect -> Pick out stream -> Send Data over stream
// The stream/connection is destroyed by the end of this call
let (ws, _) = connect_async(make_url()).await?;
let (mut write, _) = ws.split();
let event = event!(event_name, &payload);
let msg = event.to_string();
write.send(Message::text(msg)).await?;
Ok(())
}
pub async fn new_message(p: &Pool, message: db::Message) {
let uname = match db::Member::get(p, message.author_id).await {
Ok(response) => {
match response {
db::Response::Row(user) => user.name,
_ => String::new()
}
},
Err(e) => {
eprintln!("[HTTP-RTC] Couldn't fetch username {}", e);
String::new()
}
};
let message = db::UserMessage {
id: message.id,
time: message.time,
content: message.content,
content_type: message.content_type,
author_id: message.author_id,
channel_id: message.channel_id,
name: uname,
};
if let Err(e) = notify("new-message", message).await {
eprintln!("[API-RTC] Unable to connect to RTC server: {}", e);
}
}
pub async fn delete_channel(id: u64) {
#[derive(Serialize)]
struct DeletedChannel {
id: u64
}
let channel = DeletedChannel { id };
if let Err(e) = notify("delete-channel", channel).await {
eprintln!("[API-RTC] Unable to connect to RTC server: {}", e);
}
}
pub async fn create_channel(channel: db::Channel) {
if let Err(e) = notify("create-channel", channel).await {
eprintln!("[API-RTC] Unable to connect to RTC server: {}", e);
}
}
pub async fn update_nickname<'s>(id: u64, name: &'s str) {
#[derive(Serialize)]
struct NewNick<'n> {
id: u64,
name: &'n str
}
let user = NewNick { id, name };
if let Err(e) = notify("update-nick", user).await {
eprintln!("[API-RTC] Unable to connect to RTC server: {}", e);
}
}