what2watch/src/import_utils.rs

179 lines
4.9 KiB
Rust
Raw Normal View History

use sqlx::{query, query_scalar, SqlitePool};
use tokio::task::JoinSet;
use tokio_retry::Retry;
2023-07-03 22:20:19 +00:00
use crate::{
db_id::DbId, util::year_to_epoch, watches::handlers::add_new_watch_impl, ShowKind, Watch,
WatchQuest,
2023-07-03 22:20:19 +00:00
};
const USER_EXISTS_QUERY: &str = "select count(*) from witches where id = $1";
//-************************************************************************
// the omega user is the system ID, but has no actual power in the app
//-************************************************************************
const OMEGA_ID: u128 = u128::MAX;
#[derive(Debug, sqlx::FromRow, Clone)]
2023-07-03 22:20:19 +00:00
pub struct ImportMovieOmega {
pub title: String,
pub year: Option<String>,
pub length: Option<String>,
}
impl From<ImportMovieOmega> for Watch {
fn from(value: ImportMovieOmega) -> Self {
Watch {
title: value.title,
release_date: year_to_epoch(value.year.as_deref()),
length: value.length.and_then(|v| v.parse::<i64>().ok()),
id: DbId::new(),
kind: ShowKind::Movie,
metadata_url: None,
added_by: OMEGA_ID.into(),
}
}
}
2023-07-04 18:30:42 +00:00
impl From<&ImportMovieOmega> for Watch {
fn from(value: &ImportMovieOmega) -> Self {
Watch {
title: value.title.to_string(),
release_date: year_to_epoch(value.year.as_deref()),
length: value.length.as_ref().and_then(|v| v.parse::<i64>().ok()),
id: DbId::new(),
kind: ShowKind::Movie,
metadata_url: None,
added_by: OMEGA_ID.into(),
}
}
}
//-************************************************************************
// utility functions for building CLI tools, currently just for benchmarking
//-************************************************************************
2023-07-04 18:30:42 +00:00
pub async fn add_watch_omega(db_pool: &SqlitePool, movie: &ImportMovieOmega) -> Result<(), ()> {
2023-07-03 22:20:19 +00:00
let watch: Watch = movie.into();
if add_new_watch_impl(db_pool, &watch, None).await.is_ok() {
println!("{}", watch.id);
2023-07-04 18:30:42 +00:00
Ok(())
} else {
eprintln!("failed to add \"{}\"", watch.title);
2023-07-04 18:30:42 +00:00
Err(())
}
}
pub async fn add_watch_user(
db_pool: &SqlitePool,
watch: &Watch,
quest: WatchQuest,
) -> Result<(), ()> {
if add_new_watch_impl(db_pool, watch, Some(quest))
.await
.is_ok()
{
println!("{}", watch.id);
Ok(())
} else {
eprintln!("failed to add \"{}\"", watch.title);
Err(())
}
}
pub async fn add_user(
db_pool: &SqlitePool,
username: &str,
displayname: Option<&str>,
email: Option<&str>,
id: Option<DbId>,
) {
let pwhash = "you shall not password";
let id: DbId = id.unwrap_or_else(DbId::new);
if query(crate::signup::CREATE_QUERY)
.bind(id)
.bind(username)
.bind(displayname)
.bind(email)
.bind(pwhash)
.execute(db_pool)
.await
.is_ok()
{
println!("{id}");
} else {
eprintln!("failed to add user \"{username}\"");
}
}
pub async fn add_omega_watches(ww_db: &SqlitePool, movies: Vec<ImportMovieOmega>) {
ensure_omega(ww_db).await;
let mut set = JoinSet::new();
let retry_strategy = tokio_retry::strategy::ExponentialBackoff::from_millis(100)
.map(tokio_retry::strategy::jitter)
.take(4);
for movie in movies {
let db = ww_db.clone();
let title = movie.title.as_str();
let year = movie.year.clone().unwrap();
let len = movie.length.clone().unwrap();
let retry_strategy = retry_strategy.clone();
let key = format!("{title}{year}{len}");
set.spawn(async move {
(
key,
Retry::spawn(retry_strategy, || async {
add_watch_omega(&db, &movie).await
})
.await,
)
});
}
// stragglers
while (set.join_next().await).is_some() {}
}
pub async fn ensure_omega(db_pool: &SqlitePool) -> DbId {
if !check_omega_exists(db_pool).await {
add_user(
db_pool,
"The Omega User",
Some("I am the end of all watches."),
None,
Some(OMEGA_ID.into()),
)
.await
}
OMEGA_ID.into()
}
async fn check_omega_exists(db_pool: &SqlitePool) -> bool {
let id: DbId = OMEGA_ID.into();
let count = query_scalar(USER_EXISTS_QUERY)
.bind(id)
.fetch_one(db_pool)
.await
.unwrap_or(0);
count > 0
}
//-************************************************************************
//tests
//-************************************************************************
#[cfg(test)]
mod test {
use super::*;
#[tokio::test]
async fn ensure_omega_user() {
let p = crate::db::get_db_pool().await;
assert!(!check_omega_exists(&p).await);
ensure_omega(&p).await;
assert!(check_omega_exists(&p).await);
}
}