Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 9 additions & 16 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ use tower_http::cors::{Any, CorsLayer};
use tower_http::trace::TraceLayer;
use tracing::Span;
mod color;
mod routes;
mod models;
mod redis_migrations;
mod repository;
mod routes;

use models::*;

use tokio::sync::broadcast;


use crate::repository::Repository;

#[tokio::main]
async fn main() {
Expand All @@ -23,31 +23,24 @@ async fn main() {
.allow_headers(Any)
.allow_methods(Any);

let redis_string = env::var("REDIS_STRING").expect("REDIS_STRING is not set");
let jwt_key = env::var("JWT_KEY").expect("JWT_KEY is not set");
let client = redis::Client::open(redis_string.to_owned()).expect("Could not connect to redis");
let manager = redis::aio::ConnectionManager::new(client.clone())
.await
.unwrap();

let instance_properties = InstanceProperties {
demo: env::var("INSTANCE_DEMO").unwrap_or("false".to_owned()) == "true",
donation: env::var("INSTANCE_DONATION_PAYPAL")
.map(|id| Some(vec![DonationMethod::PayPal(id)]))
.unwrap_or(None),
s3_host: env::var("S3_HOST").unwrap_or("".to_owned()),
};
let jwt_key = env::var("JWT_KEY").expect("JWT_KEY is not set");
let redis_string = env::var("REDIS_STRING").expect("REDIS_STRING is not set");

let (redis_task_tx, redis_task_rx) = broadcast::channel::<Timer>(10);
let repository = Repository::new(redis_string).await;

let state: SharedState = Arc::new(AppState {
redis: manager.clone(),
repository,
jwt_key,
instance_properties,
redis_task_rx,
});

routes::ws::spawn_global_redis_listener_task(manager, client, redis_task_tx);

let app = Router::new()
.nest("/api/ws", routes::ws::routes())
.nest("/api/timer", routes::timer::routes(state.clone()))
Expand Down
108 changes: 52 additions & 56 deletions src/models.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,6 @@
use crate::repository::{DisplayOptions, Repository, Segment, Timer, TimerMetadata};
use serde::{Deserialize, Serialize};
use crate::color::Color;
use std::sync::Arc;
use tokio::sync::broadcast;

//main.rs
fn default_zero() -> u32 {
0
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Segment {
label: String,
time: u32,
sound: bool,
color: Option<Color>,
#[serde(default = "default_zero")]
count_to: u32,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum PreStartBehaviour {
ShowZero,
RunNormally,
}

impl Default for PreStartBehaviour {
fn default() -> Self {
PreStartBehaviour::ShowZero
}
}

#[derive(Serialize, Deserialize, Clone, Default, Debug)]
pub struct DisplayOptions {
#[serde(default)]
clock: bool,
#[serde(default)]
pre_start_behaviour: PreStartBehaviour,
}

#[derive(Serialize, Deserialize, Clone, Default, Debug)]
pub struct Timer {
// Return after TimerRequest
pub segments: Vec<Segment>,
pub repeat: bool,
pub display_options: Option<DisplayOptions>,
pub start_at: u64,
pub stop_at: Option<u64>,
pub password: String,
pub id: String, // 5 random chars
}

#[derive(Serialize, Clone)]
#[serde(tag = "type", content = "data")]
Expand All @@ -60,17 +12,16 @@ pub enum DonationMethod {
pub struct InstanceProperties {
pub demo: bool,
pub donation: Option<Vec<DonationMethod>>,
pub s3_host: String,
}

pub type SharedState = Arc<AppState>;
pub struct AppState {
pub redis: redis::aio::ConnectionManager,
pub repository: Repository,
pub jwt_key: String,
pub instance_properties: InstanceProperties,
pub redis_task_rx: broadcast::Receiver<Timer>,
}


//timer.rs

#[derive(Serialize, Deserialize, Debug)]
Expand All @@ -81,6 +32,7 @@ pub struct TimerResponse {
pub display_options: DisplayOptions,
pub start_at: u64,
pub stop_at: Option<u64>,
pub metadata: TimerMetadata,
}

impl Into<TimerResponse> for Timer {
Expand All @@ -89,9 +41,10 @@ impl Into<TimerResponse> for Timer {
segments: self.segments,
id: self.id,
repeat: self.repeat,
display_options: self.display_options.unwrap_or(DisplayOptions::default()),
display_options: self.display_options,
start_at: self.start_at,
stop_at: self.stop_at,
metadata: self.metadata,
}
}
}
Expand All @@ -104,20 +57,36 @@ pub struct TimerCreationResponse {

#[derive(Serialize, Deserialize)]
pub struct TimerCreationRequest {
// Get from User
pub segments: Vec<Segment>,
pub id: String,
pub password: String,
pub repeat: bool,
pub start_at: u64,
pub metadata: TimerMetadata,
pub display_options: DisplayOptions,
}

impl TimerCreationRequest {
pub fn into(self, hashed_password: String) -> Timer {
Timer {
segments: self.segments,
repeat: self.repeat,
display_options: self.display_options,
start_at: self.start_at,
stop_at: None,
password: hashed_password,
id: self.id,
metadata: self.metadata,
}
}
}

#[derive(Serialize, Deserialize)]
pub struct TimerUpdateRequest {
// Get from User
pub segments: Vec<Segment>,
pub repeat: bool,
pub display_options: Option<DisplayOptions>,
pub display_options: DisplayOptions,
pub metadata: TimerMetadata,
pub start_at: u64,
pub stop_at: Option<u64>,
}
Expand All @@ -139,3 +108,30 @@ pub struct Claims {
pub struct TokenResponse {
pub token: String,
}

///
/// Websocket
///

#[derive(Serialize, Deserialize, Debug)]
pub struct WsTimerResponse {
pub segments: Vec<Segment>,
pub id: String,
pub repeat: bool,
pub display_options: DisplayOptions,
pub start_at: u64,
pub stop_at: Option<u64>,
}

impl Into<WsTimerResponse> for Timer {
fn into(self) -> WsTimerResponse {
WsTimerResponse {
segments: self.segments,
id: self.id,
repeat: self.repeat,
display_options: self.display_options,
start_at: self.start_at,
stop_at: self.stop_at,
}
}
}
48 changes: 48 additions & 0 deletions src/redis_migrations/display_options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use serde::Deserialize;

use crate::repository::DisplayOptions;

use super::pre_start_behaviour::RedisPreStartBehaviour;

#[derive(Deserialize, Clone)]
#[serde(untagged)]
pub enum RedisDisplayOptions {
V0(DisplayOptionsV0),
}

impl Into<DisplayOptions> for RedisDisplayOptions {
fn into(self) -> DisplayOptions {
match self {
RedisDisplayOptions::V0(v0) => v0.into(),
}
}
}

impl Into<DisplayOptions> for Option<RedisDisplayOptions> {
fn into(self) -> DisplayOptions {
self.map(|o| o.into()).unwrap_or(DisplayOptions::default())
}
}

#[derive(Deserialize, Clone)]
pub struct DisplayOptionsV0 {
#[serde(default)]
clock: bool,
#[serde(default)]
pre_start_behaviour: RedisPreStartBehaviour,
}

impl Into<DisplayOptions> for DisplayOptionsV0 {
fn into(self) -> DisplayOptions {
DisplayOptions {
clock: self.clock,
pre_start_behaviour: self.pre_start_behaviour.into(),
}
}
}

impl Into<DisplayOptions> for Option<DisplayOptionsV0> {
fn into(self) -> DisplayOptions {
self.map(|o| o.into()).unwrap_or(DisplayOptions::default())
}
}
8 changes: 8 additions & 0 deletions src/redis_migrations/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
mod display_options;
mod pre_start_behaviour;
mod segment;
mod tests;
mod timer;
mod timer_metadata;

pub use timer::RedisTimer;
71 changes: 71 additions & 0 deletions src/redis_migrations/pre_start_behaviour.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use serde::Deserialize;

use crate::repository::PreStartBehaviour;

#[derive(Deserialize, Clone)]
#[serde(untagged)]
pub enum RedisPreStartBehaviour {
V1(PreStartBehaviourV1),
V0(PreStartBehaviourV0),
}

impl Into<PreStartBehaviour> for RedisPreStartBehaviour {
fn into(self) -> PreStartBehaviour {
match self {
RedisPreStartBehaviour::V0(v0) => v0.into(),
RedisPreStartBehaviour::V1(v1) => v1.into(),
}
}
}

impl Default for RedisPreStartBehaviour {
fn default() -> Self {
Self::V1(PreStartBehaviourV1::default())
}
}

/// === V1 ===
#[derive(Deserialize, Clone)]
pub enum PreStartBehaviourV1 {
ShowFirstSegment,
ShowLastSegment,
RunNormally,
}

impl Default for PreStartBehaviourV1 {
fn default() -> Self {
PreStartBehaviourV1::ShowFirstSegment
}
}

impl Into<PreStartBehaviour> for PreStartBehaviourV1 {
fn into(self) -> PreStartBehaviour {
match self {
PreStartBehaviourV1::RunNormally => PreStartBehaviour::RunNormally,
PreStartBehaviourV1::ShowFirstSegment => PreStartBehaviour::ShowFirstSegment,
PreStartBehaviourV1::ShowLastSegment => PreStartBehaviour::ShowLastSegment,
}
}
}

/// === V0 ===
#[derive(Deserialize, Clone)]
pub enum PreStartBehaviourV0 {
ShowZero,
RunNormally,
}

impl Default for PreStartBehaviourV0 {
fn default() -> Self {
PreStartBehaviourV0::ShowZero
}
}

impl Into<PreStartBehaviour> for PreStartBehaviourV0 {
fn into(self) -> PreStartBehaviour {
match self {
PreStartBehaviourV0::RunNormally => PreStartBehaviour::RunNormally,
PreStartBehaviourV0::ShowZero => PreStartBehaviour::ShowFirstSegment,
}
}
}
43 changes: 43 additions & 0 deletions src/redis_migrations/segment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use serde::Deserialize;

use crate::{color::Color, repository::Segment};

#[derive(Deserialize, Clone)]
#[serde(untagged)]
pub enum RedisSegment {
V0(SegmentV0),
}

impl Into<Segment> for RedisSegment {
fn into(self) -> Segment {
match self {
RedisSegment::V0(v0) => v0.into(),
}
}
}

fn default_zero() -> u32 {
0
}

#[derive(Deserialize, Clone)]
pub struct SegmentV0 {
label: String,
time: u32,
sound: bool,
color: Option<Color>,
#[serde(default = "default_zero")]
count_to: u32,
}

impl Into<Segment> for SegmentV0 {
fn into(self) -> Segment {
Segment {
label: self.label,
time: self.time,
sound: self.sound,
color: self.color,
count_to: self.count_to,
}
}
}
Loading