310 lines
8.0 KiB
Rust
310 lines
8.0 KiB
Rust
use crate::util;
|
|
use leptos::*;
|
|
use leptos_use::{core::ConnectionReadyState, use_websocket, UseWebsocketReturn};
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_json::json;
|
|
use std::{alloc::handle_alloc_error, rc::Rc, time::Duration};
|
|
|
|
#[derive(Serialize)]
|
|
#[serde(untagged)]
|
|
enum SurrealId {
|
|
String(String),
|
|
Integer(u32),
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct SurrealRequest {
|
|
id: SurrealId,
|
|
method: String,
|
|
params: Vec<SurrealParams>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
#[serde(untagged)]
|
|
enum SurrealParams {
|
|
Participant,
|
|
SigninParam(SigninParam),
|
|
CreatePersonParam(CreatePersonParam),
|
|
CreateTimeParam(CreateTimeParam),
|
|
String(String),
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct SigninParam {
|
|
user: String,
|
|
pass: String,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct CreatePersonParam {
|
|
name: String,
|
|
group: String,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub struct CreateTimeParam {
|
|
person_id: String,
|
|
time: u64,
|
|
}
|
|
|
|
impl CreateTimeParam {
|
|
pub fn new(person_id: String, minutes: u64, seconds: u64, miliseconds: u64) -> Self {
|
|
Self {
|
|
person_id,
|
|
time: minutes * 60 * 1000 + seconds * 1000 + miliseconds * 10,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
pub struct Participant {
|
|
pub id: String,
|
|
pub name: String,
|
|
pub group: String,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct ParticipantsContext {
|
|
pub read: ReadSignal<Vec<Participant>>,
|
|
write: WriteSignal<Vec<Participant>>,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct SurrealContext {
|
|
pub message: Signal<Option<String>>,
|
|
send: Rc<dyn Fn(&str)>,
|
|
pub ready_state: Signal<ConnectionReadyState>,
|
|
pub authenticated: ReadSignal<bool>,
|
|
pub set_authenticated: WriteSignal<bool>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone)]
|
|
struct SurrealResponse {
|
|
id: Option<u32>,
|
|
result: SurrealResult,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
struct SurrealAction {
|
|
id: String,
|
|
action: String,
|
|
result: Participant,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone)]
|
|
#[serde(untagged)]
|
|
enum SurrealResult {
|
|
String(String),
|
|
Participants(Vec<Participant>),
|
|
Action(SurrealAction),
|
|
Null,
|
|
}
|
|
|
|
impl SurrealContext {
|
|
pub fn new(
|
|
message: Signal<Option<String>>,
|
|
send: Rc<dyn Fn(&str)>,
|
|
ready_state: Signal<ConnectionReadyState>,
|
|
authenticated: ReadSignal<bool>,
|
|
set_authenticated: WriteSignal<bool>,
|
|
) -> Self {
|
|
Self {
|
|
message,
|
|
send,
|
|
ready_state,
|
|
authenticated,
|
|
set_authenticated,
|
|
}
|
|
}
|
|
|
|
/// Send a string to surrealDB
|
|
#[inline(always)]
|
|
pub fn send(&self, message: &str) {
|
|
(self.send)(message)
|
|
}
|
|
|
|
/// sigin SurrealDB
|
|
pub fn signin(&self, pass: String) {
|
|
log::debug!("Signing into surrealdb");
|
|
|
|
let request = SurrealRequest {
|
|
id: SurrealId::Integer(0),
|
|
method: String::from("signin"),
|
|
params: vec![SurrealParams::SigninParam(SigninParam {
|
|
user: String::from("root"),
|
|
pass,
|
|
})],
|
|
};
|
|
|
|
self.send(&json!(request).to_string());
|
|
}
|
|
|
|
pub fn add_person(&self, name: String, group: String) -> Result<(), String> {
|
|
if name.is_empty() {
|
|
return Err(String::from("Name cannot be empty"));
|
|
}
|
|
|
|
let request = SurrealRequest {
|
|
id: SurrealId::Integer(10),
|
|
method: String::from("create"),
|
|
params: vec![
|
|
SurrealParams::String(String::from("person")),
|
|
SurrealParams::CreatePersonParam(CreatePersonParam {
|
|
name,
|
|
group: "group:".to_owned() + &group,
|
|
}),
|
|
],
|
|
};
|
|
|
|
Ok(self.send(&json!(request).to_string()))
|
|
}
|
|
|
|
pub fn add_time(&self, body: CreateTimeParam, event: String) -> Result<(), String> {
|
|
let request = SurrealRequest {
|
|
id: SurrealId::Integer(20),
|
|
method: String::from("create"),
|
|
params: vec![
|
|
SurrealParams::String(event),
|
|
SurrealParams::CreateTimeParam(body),
|
|
],
|
|
};
|
|
|
|
Ok(self.send(&json!(request).to_string()))
|
|
}
|
|
}
|
|
|
|
pub fn init_surrealdb() {
|
|
// Initialize a connection to surrealDB
|
|
let UseWebsocketReturn {
|
|
ready_state,
|
|
message,
|
|
send,
|
|
..
|
|
} = use_websocket("ws://localhost:80/rpc");
|
|
|
|
// Create reactive signals for the websocket connection to surrealDB
|
|
let (participants, set_participants) = create_signal::<Vec<Participant>>(vec![]);
|
|
let (authenticated, set_authenticated) = create_signal::<bool>(false);
|
|
|
|
// Bind the websocket connection to a context
|
|
let websocket = SurrealContext::new(
|
|
message,
|
|
Rc::new(send.clone()),
|
|
ready_state,
|
|
authenticated,
|
|
set_authenticated,
|
|
);
|
|
|
|
provide_context(websocket);
|
|
provide_context(ParticipantsContext {
|
|
read: participants,
|
|
write: set_participants,
|
|
});
|
|
|
|
// Watch for a message recieved from the surrealDB connection
|
|
create_effect(move |prev_value| {
|
|
let msg = message.get();
|
|
|
|
if prev_value != Some(msg.clone()) {
|
|
match msg {
|
|
Some(ref text) => {
|
|
log::debug!("{:?}", text);
|
|
surrealdb_response(text.to_string());
|
|
}
|
|
None => (),
|
|
}
|
|
}
|
|
|
|
msg
|
|
});
|
|
}
|
|
|
|
/// Function to execute when SurrealDB returns a message
|
|
fn surrealdb_response(response: String) {
|
|
let response: SurrealResponse = match serde_json::from_str(&response) {
|
|
Ok(res) => res,
|
|
Err(err) => {
|
|
log::warn!("{}", err);
|
|
return;
|
|
}
|
|
};
|
|
|
|
match response.id {
|
|
Some(0) => use_surrealdb(response.clone()),
|
|
Some(1) => get_participants(),
|
|
Some(2) => log::debug!("Subscribed to live timings"),
|
|
Some(5) => got_participants(response.result.clone()),
|
|
Some(_) => (),
|
|
None => (),
|
|
}
|
|
|
|
match response.result {
|
|
SurrealResult::Action(action) => handle_action(action),
|
|
_ => (),
|
|
}
|
|
}
|
|
|
|
/// Function to execute when DB signin is succesful
|
|
fn use_surrealdb(_response: SurrealResponse) {
|
|
util::toast::add_toast(
|
|
"Succesfully signed into DB".to_string(),
|
|
"success".to_string(),
|
|
);
|
|
|
|
let websocket = expect_context::<SurrealContext>();
|
|
|
|
websocket.set_authenticated.set(true);
|
|
|
|
let request = SurrealRequest {
|
|
id: SurrealId::Integer(1),
|
|
method: String::from("use"),
|
|
params: vec![
|
|
SurrealParams::String(String::from("wrb")),
|
|
SurrealParams::String(String::from("timings")),
|
|
],
|
|
};
|
|
|
|
websocket.send(&json!(request).to_string())
|
|
}
|
|
|
|
/// Function to get all participants and subscribe to changes
|
|
fn get_participants() {
|
|
let websocket = expect_context::<SurrealContext>();
|
|
|
|
let request = SurrealRequest {
|
|
id: SurrealId::Integer(5),
|
|
method: String::from("select"),
|
|
params: vec![SurrealParams::String(String::from("person"))],
|
|
};
|
|
|
|
websocket.send(&json!(request).to_string());
|
|
|
|
let request = SurrealRequest {
|
|
id: SurrealId::Integer(2),
|
|
method: String::from("live"),
|
|
params: vec![SurrealParams::String(String::from("person"))],
|
|
};
|
|
|
|
websocket.send(&json!(request).to_string());
|
|
}
|
|
|
|
/// Function that will execute when participants are recieved
|
|
fn got_participants(result: SurrealResult) {
|
|
let participants_context = expect_context::<ParticipantsContext>();
|
|
|
|
if let SurrealResult::Participants(mut value) = result {
|
|
let mut participants = participants_context.read.get();
|
|
participants.append(&mut value);
|
|
participants_context.write.set(participants);
|
|
}
|
|
}
|
|
|
|
/// Function to call when an action is recieved from surrealDB
|
|
fn handle_action(action: SurrealAction) {
|
|
let participants_context = expect_context::<ParticipantsContext>();
|
|
|
|
let mut participants = participants_context.read.get();
|
|
participants.push(action.result);
|
|
participants_context.write.set(participants);
|
|
}
|