2022-10-22 17:58:40 +05:30
#[ macro_use ]
extern crate rocket ;
use std ::path ::Path ;
2023-08-08 18:13:23 +05:30
use std ::sync ::Arc ;
2022-10-22 17:58:40 +05:30
use std ::thread ::sleep ;
2023-08-08 18:13:23 +05:30
use std ::time ::{ Duration , Instant , SystemTime , UNIX_EPOCH } ;
2022-10-22 17:58:40 +05:30
use diesel ::connection ::SimpleConnection ;
2023-08-08 18:13:23 +05:30
use once_cell ::sync ::Lazy ;
2022-10-25 14:43:34 +05:30
use rocket ::fairing ::{ AdHoc , Fairing , Info , Kind } ;
use rocket ::http ::Header ;
2023-08-08 18:13:23 +05:30
use rocket ::{ Build , Request , Response , Rocket } ;
2022-10-22 17:58:40 +05:30
use rocket_sync_db_pools ::database ;
2023-08-08 18:13:23 +05:30
use tokio ::sync ::Mutex ;
2022-10-22 17:58:40 +05:30
use tokio ::time ::interval ;
use structs ::{ Segment , Sponsor } ;
2023-08-08 18:13:23 +05:30
use crate ::routes ::{ fake_is_user_vip , fake_user_info , skip_segments , skip_segments_by_id } ;
2022-10-22 17:58:40 +05:30
mod models ;
mod routes ;
mod schema ;
mod structs ;
#[ database( " sponsorblock " ) ]
pub struct Db ( diesel ::PgConnection ) ;
async fn run_migrations ( rocket : Rocket < Build > ) -> Rocket < Build > {
use diesel_migrations ::{ embed_migrations , EmbeddedMigrations , MigrationHarness } ;
const MIGRATIONS : EmbeddedMigrations = embed_migrations! ( " migrations/ " ) ;
Db ::get_one ( & rocket )
. await
. expect ( " Failed to get a database connection " )
. run ( | c | {
MigrationHarness ::run_pending_migrations ( c , MIGRATIONS )
. expect ( " Failed to run migrations " ) ;
2023-08-08 18:13:23 +05:30
} )
. await ;
2022-10-22 17:58:40 +05:30
rocket
}
2022-10-25 14:43:34 +05:30
pub struct CORS ;
#[ rocket::async_trait ]
impl Fairing for CORS {
fn info ( & self ) -> Info {
Info {
name : " Add CORS headers to responses " ,
kind : Kind ::Response ,
}
}
async fn on_response < ' r > ( & self , request : & ' r Request < '_ > , response : & mut Response < ' r > ) {
response . set_header ( Header ::new ( " Access-Control-Allow-Origin " , " * " ) ) ;
2023-08-08 18:13:23 +05:30
response . set_header ( Header ::new (
" Access-Control-Allow-Methods " ,
" POST, GET, PATCH, OPTIONS " ,
) ) ;
2022-10-25 14:43:34 +05:30
response . set_header ( Header ::new ( " Access-Control-Allow-Headers " , " * " ) ) ;
response . set_header ( Header ::new ( " Access-Control-Allow-Credentials " , " true " ) ) ;
if request . method ( ) = = rocket ::http ::Method ::Options {
response . set_streamed_body ( tokio ::io ::empty ( ) ) ;
response . set_status ( rocket ::http ::Status ::Ok ) ;
}
}
}
2023-08-08 18:13:23 +05:30
static LAST_UPDATE : Lazy < Arc < Mutex < SystemTime > > > =
Lazy ::new ( | | Arc ::new ( Mutex ::new ( SystemTime ::UNIX_EPOCH ) ) ) ;
2022-10-22 17:58:40 +05:30
#[ launch ]
fn rocket ( ) -> Rocket < Build > {
rocket ::build ( )
. attach ( Db ::fairing ( ) )
. attach ( AdHoc ::on_ignite ( " Diesel Migrations " , run_migrations ) )
. attach ( AdHoc ::on_liftoff ( " background database " , | rocket | {
Box ::pin ( async move {
let mut interval = interval ( Duration ::from_secs ( 30 ) ) ;
let path = Path ::new ( " mirror/sponsorTimes.csv " ) ;
// Get an actual DB connection
let db = Db ::get_one ( rocket ) . await . unwrap ( ) ;
tokio ::spawn ( async move {
loop {
interval . tick ( ) . await ;
2023-08-08 18:13:23 +05:30
let mut lock_guard = LAST_UPDATE . lock ( ) . await ;
let locked_last_updated_time = & mut * lock_guard ;
2022-10-22 17:58:40 +05:30
// see if file exists
2023-08-08 18:13:23 +05:30
if path . exists ( ) & & ( * locked_last_updated_time = = UNIX_EPOCH | | locked_last_updated_time . elapsed ( ) . unwrap_or_default ( ) . as_secs ( ) > 60 ) {
2022-10-22 17:58:40 +05:30
// Check last modified time
let last_modified = path . metadata ( ) . unwrap ( ) . modified ( ) . unwrap ( ) ;
// Check if file was modified since last update
2023-08-08 18:13:23 +05:30
if * locked_last_updated_time = = UNIX_EPOCH | | last_modified > * locked_last_updated_time {
2022-10-22 17:58:40 +05:30
// Use COPY FROM to import the CSV file
let start = Instant ::now ( ) ;
println! ( " Importing database... " ) ;
// Execute a query of some kind
2022-10-30 21:36:27 +05:30
let res = db . run ( move | c | {
2022-10-24 17:27:11 +05:30
let result = c . batch_execute ( " BEGIN; DROP TABLE IF EXISTS \" sponsorTimesTemp \" ; CREATE UNLOGGED TABLE \" sponsorTimesTemp \" (LIKE \" sponsorTimes \" INCLUDING defaults INCLUDING constraints INCLUDING indexes); COPY \" sponsorTimesTemp \" FROM '/mirror/sponsorTimes.csv' DELIMITER ',' CSV HEADER; DROP TABLE \" sponsorTimes \" ; ALTER TABLE \" sponsorTimesTemp \" RENAME TO \" sponsorTimes \" ; COMMIT; " ) ;
2022-10-23 01:36:48 +05:30
if result . is_err ( ) {
2022-10-30 21:36:27 +05:30
c . batch_execute ( " ROLLBACK; " ) . unwrap ( ) ;
2022-10-23 01:36:48 +05:30
eprintln! ( " Failed to import database: {} " , result . err ( ) . unwrap ( ) ) ;
2022-10-30 21:36:27 +05:30
return false ;
2022-10-23 01:36:48 +05:30
}
2022-10-24 17:27:11 +05:30
println! ( " Imported database in {} ms " , start . elapsed ( ) . as_millis ( ) ) ;
// Vacuum the database
let result = c . batch_execute ( " VACUUM \" sponsorTimes \" ; " ) ;
if result . is_err ( ) {
eprintln! ( " Failed to vacuum database: {} " , result . err ( ) . unwrap ( ) ) ;
2022-10-30 21:36:27 +05:30
return false ;
2022-10-24 17:27:11 +05:30
}
2022-10-30 21:36:27 +05:30
true
2022-10-22 17:58:40 +05:30
} ) . await ;
2022-10-30 21:36:27 +05:30
if res {
2023-08-08 18:13:23 +05:30
* LAST_UPDATE . lock ( ) . await = last_modified ;
2022-10-22 17:58:40 +05:30
}
}
sleep ( Duration ::from_secs ( 60 ) ) ;
}
}
} ) ;
} )
} )
2022-10-25 14:43:34 +05:30
) . attach ( CORS )
2022-10-30 08:12:59 +05:30
. mount ( " / " , routes! [ skip_segments , skip_segments_by_id , fake_is_user_vip , fake_user_info ] )
2022-10-22 17:58:40 +05:30
}