proper productionize project
This commit is contained in:
@@ -1,15 +1,12 @@
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{Value, json};
|
||||
use serde_json::Value;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio_postgres::NoTls;
|
||||
use tracing::warn;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct OverlaySettings {
|
||||
pub title: String,
|
||||
#[serde(default = "default_font_scale")]
|
||||
pub font_scale: u16,
|
||||
pub show_danmaku: bool,
|
||||
@@ -37,7 +34,6 @@ pub struct OverlaySettings {
|
||||
impl Default for OverlaySettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
title: "洛星瓷专用弹幕猪!".into(),
|
||||
font_scale: default_font_scale(),
|
||||
show_danmaku: true,
|
||||
show_enter: true,
|
||||
@@ -61,10 +57,6 @@ impl Default for OverlaySettings {
|
||||
|
||||
impl OverlaySettings {
|
||||
pub fn sanitize(mut self) -> Self {
|
||||
self.title = self.title.trim().chars().take(48).collect();
|
||||
if self.title.is_empty() {
|
||||
self.title = Self::default().title;
|
||||
}
|
||||
self.max_visible = self.max_visible.clamp(1, 12);
|
||||
self.font_scale = self.font_scale.clamp(50, 300);
|
||||
self.collapse_after_seconds = self.collapse_after_seconds.clamp(2, 120);
|
||||
@@ -95,45 +87,6 @@ fn default_particle_speed() -> u16 {
|
||||
100
|
||||
}
|
||||
|
||||
pub async fn load_settings(
|
||||
database_url: &str,
|
||||
room_id: &str,
|
||||
defaults: OverlaySettings,
|
||||
) -> Result<OverlaySettings, String> {
|
||||
let (client, connection) = tokio_postgres::connect(database_url, NoTls)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
tokio::spawn(async move {
|
||||
let _ = connection.await;
|
||||
});
|
||||
let row = client
|
||||
.query_opt(
|
||||
"SELECT settings FROM overlay_settings WHERE room_id=$1",
|
||||
&[&room_id],
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(row
|
||||
.and_then(|row| serde_json::from_value::<OverlaySettings>(row.get::<_, Value>(0)).ok())
|
||||
.unwrap_or(defaults)
|
||||
.sanitize())
|
||||
}
|
||||
|
||||
pub async fn save_settings(
|
||||
database_url: &str,
|
||||
room_id: &str,
|
||||
settings: &OverlaySettings,
|
||||
) -> Result<(), String> {
|
||||
let (client, connection) = tokio_postgres::connect(database_url, NoTls)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
tokio::spawn(async move {
|
||||
let _ = connection.await;
|
||||
});
|
||||
client.execute("INSERT INTO overlay_settings(room_id,settings,updated_at) VALUES($1,$2,now()) ON CONFLICT(room_id) DO UPDATE SET settings=EXCLUDED.settings,updated_at=now()", &[&room_id, &json!(settings)]).await.map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GiftMeta {
|
||||
@@ -276,17 +229,6 @@ impl GiftCatalog {
|
||||
*self.by_name.write().await = names;
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
pub fn spawn_refresh(self, room_id: String, interval_seconds: u64, timeout_seconds: u64) {
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(interval_seconds)).await;
|
||||
if let Err(error) = self.refresh(&room_id, timeout_seconds).await {
|
||||
warn!(%error, "gift catalog refresh failed; retaining the last successful cache");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_catalog(
|
||||
@@ -441,6 +383,7 @@ fn normalize_name(name: &str) -> String {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn parses_current_gift_panel_fields_and_indexes_by_id_and_name() {
|
||||
@@ -497,7 +440,6 @@ mod tests {
|
||||
#[test]
|
||||
fn settings_are_bounded_before_persistence() {
|
||||
let settings = OverlaySettings {
|
||||
title: " ".into(),
|
||||
font_scale: 999,
|
||||
max_visible: 99,
|
||||
collapse_after_seconds: 1,
|
||||
@@ -510,7 +452,6 @@ mod tests {
|
||||
..OverlaySettings::default()
|
||||
}
|
||||
.sanitize();
|
||||
assert_eq!(settings.title, "洛星瓷专用弹幕猪!");
|
||||
assert_eq!(settings.font_scale, 300);
|
||||
assert_eq!(settings.max_visible, 12);
|
||||
assert_eq!(settings.collapse_after_seconds, 2);
|
||||
@@ -532,6 +473,7 @@ mod tests {
|
||||
fn old_saved_settings_receive_new_field_defaults() {
|
||||
let mut value = json!(OverlaySettings::default());
|
||||
let object = value.as_object_mut().expect("settings object");
|
||||
object.insert("title".into(), json!("旧版弹幕栏标题"));
|
||||
object.remove("fontScale");
|
||||
object.remove("unfoldDurationMs");
|
||||
object.remove("particleCount");
|
||||
|
||||
Reference in New Issue
Block a user