summaryrefslogtreecommitdiff
path: root/src/serve.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/serve.rs')
-rw-r--r--src/serve.rs223
1 files changed, 96 insertions, 127 deletions
diff --git a/src/serve.rs b/src/serve.rs
index 95ce9b1..7014641 100644
--- a/src/serve.rs
+++ b/src/serve.rs
@@ -1,6 +1,6 @@
+use crate::errors::Error;
use lazy_static::lazy_static;
-use rocket::http::Status;
-use rocket::response::{status, Redirect};
+use rocket::response::Redirect;
use rspotify::spotify::client::{ApiError, Spotify};
use rspotify::spotify::oauth2::{SpotifyClientCredentials, SpotifyOAuth};
use rspotify::spotify::util::process_token;
@@ -13,47 +13,12 @@ lazy_static! {
}
#[get("/callback/<name>/<url>")]
-pub fn get_tracks(name: String, url: String) -> Result<(), status::Custom<String>> {
- let mut guard = CACHE.lock().or(Err(status::Custom(
- Status::InternalServerError,
- String::from("failed to lock cache mutex"),
- )))?;
- let mut oauth = guard.remove(&name).ok_or(status::Custom(
- Status::NotFound,
- String::from("uuid not found in cache"),
- ))?;
- println!("auth: {:?} url: {}", oauth, url);
- let token_info = process_token(&mut oauth, &mut ("?code=".to_owned() + url.as_ref()));
- let client_credential = SpotifyClientCredentials::default()
- .token_info(token_info.unwrap())
- .build();
-
- let spotify = Spotify::default()
- .client_credentials_manager(client_credential)
- .build();
- let user_id = spotify.current_user().unwrap().id;
- let mut client = crate::CLIENT.lock().or(Err(status::Custom(
- Status::InternalServerError,
- String::from("failed to lock cache mutex"),
- )))?;
- client
- .execute(
- "INSERT INTO suser (user_name) VALUES ($1) ON CONFLICT (user_name) DO NOTHING;",
- &[&user_id],
- )
- .unwrap();
- let uid = get_uid(user_id.as_ref(), &mut client).ok_or(status::Custom(
- Status::NotFound,
- format!("username {} not found", user_id),
- ))?;
- client
- .execute("DELETE FROM user_track WHERE user_id = $1;", &[&uid])
- .unwrap();
- drop(client);
+pub fn get_tracks(name: String, url: String) -> Result<(), Error> {
+ let (uid, spotify_uid, spotify) = autenth_user(name.as_ref(), url)?;
let chunk_size = 50;
let mut playlist_index = 0;
loop {
- match spotify.user_playlists(user_id.as_ref(), Some(chunk_size), Some(playlist_index)) {
+ match spotify.user_playlists(spotify_uid.as_ref(), Some(chunk_size), Some(playlist_index)) {
Ok(playlists) => {
playlist_index += chunk_size;
if playlists.items.is_empty() {
@@ -65,7 +30,7 @@ pub fn get_tracks(name: String, url: String) -> Result<(), status::Custom<String
loop {
match spotify.user_playlist_tracks(
- user_id.as_ref(),
+ spotify_uid.as_ref(),
&playlist.id,
None,
Some(chunk_size),
@@ -78,49 +43,9 @@ pub fn get_tracks(name: String, url: String) -> Result<(), status::Custom<String
break;
}
for track in tracks.items {
- //println!("{:?}", track.track.name);
- let mut client = crate::CLIENT.lock().or(Err(
- status::Custom(Status::InternalServerError, String::new()),
- ))?;
-
- if track.track.id.is_none() {
- println!("{:#?}", track);
- continue;
- }
- print!(" {} ", track.track.id.clone().unwrap());
- client
- .execute(
- "INSERT INTO track (track_code, name, artist, popularity)
- VALUES ($1, $2, $3, $4)
- ON CONFLICT DO NOTHING
- ",
- &[&(track.track.id.clone().unwrap()), &track.track.name, &track.track.artists[0].name, &(track.track.popularity as i32)],
- )
- .unwrap();
- let tid: i32 = client
- .query(
- "SELECT track_id FROM track where track_code = $1;",
- &[&(track.track.id.clone().unwrap())],
- )
- .unwrap()[0]
- .get(0);
- println!("uid: {} tid: {}", uid, tid);
- client
- .execute(
- "INSERT INTO user_track (track_id, user_id, count)
- VALUES ($1, $2, $3)
- ON CONFLICT
- ON CONSTRAINT track_user_pkey
- DO NOTHING;",
- &[&tid, &uid, &0],
- )
- .unwrap();
- client
- .execute(
- "UPDATE user_track SET count = count + 1 WHERE track_id = $1 AND user_id = $2;",
- &[&tid, &uid],
- )
- .unwrap();
+ if let Err(e) = insert_track(uid, track.track) {
+ println!("failed to load track to db: {:?}", e)
+ };
}
}
Err(e) => match e.downcast::<ApiError>() {
@@ -152,52 +77,100 @@ pub fn get_tracks(name: String, url: String) -> Result<(), status::Custom<String
Ok(())
}
+fn autenth_user(name: &str, url: String) -> Result<(i32, String, Spotify), Error> {
+ let mut guard = CACHE.lock()?;
+ let mut oauth = guard.remove(name)?;
+ println!("auth: {:?} url: {}", oauth, url);
+ let token_info = process_token(&mut oauth, &mut ("?code=".to_owned() + url.as_ref()));
+ let client_credential = SpotifyClientCredentials::default()
+ .token_info(token_info?)
+ .build();
+
+ let spotify = Spotify::default()
+ .client_credentials_manager(client_credential)
+ .build();
+ let user_id = spotify
+ .current_user()
+ .map_err(|e| format!("failed to load currentuser {:?}", e))?
+ .id;
+ let mut client = crate::CLIENT.lock()?;
+ client.execute(
+ "INSERT INTO suser (user_name) VALUES ($1) ON CONFLICT (user_name) DO NOTHING;",
+ &[&user_id],
+ )?;
+ let uid = get_uid(user_id.as_ref(), &mut client)?;
+ //reset user_track relation
+ client.execute("DELETE FROM user_track WHERE user_id = $1;", &[&uid])?;
+ Ok((uid, user_id, spotify))
+}
+
+use rspotify::spotify::model::track::FullTrack;
+fn insert_track(user_id: i32, track: FullTrack) -> Result<(), Error> {
+ let mut client = crate::CLIENT.lock()?;
+
+ if track.id.is_none() {
+ println!("{:#?}", track);
+ return Err("failed to load get track information".into());
+ }
+ print!(" {} ", track.id.clone()?);
+ client.execute(
+ "INSERT INTO track (track_code, name, artist, popularity)
+ VALUES ($1, $2, $3, $4)
+ ON CONFLICT DO NOTHING
+ ",
+ &[
+ &(track.id.clone()?),
+ &track.name,
+ &track.artists[0].name,
+ &(track.popularity as i32),
+ ],
+ )?;
+ let track_id: i32 = client.query(
+ "SELECT track_id FROM track where track_code = $1;",
+ &[&(track.id?)],
+ )?[0]
+ .get(0);
+ println!("uid: {} tid: {}", user_id, track_id);
+ client.execute(
+ "
+ INSERT INTO user_track_raw (track_id, user_id, count)
+ VALUES ($1, $2, $3)
+ ON CONFLICT
+ ON CONSTRAINT track_user_pkey
+ DO NOTHING;
+ UPDATE user_track SET count = count + 1 WHERE track_id = $1 AND user_id = $2;
+ ",
+ &[&track_id, &user_id, &0],
+ )?;
+ Ok(())
+}
+
#[get("/token/<name>")]
-pub fn token(name: String) -> Result<Redirect, status::Custom<String>> {
+pub fn token(name: String) -> Result<Redirect, Error> {
let state = rspotify::spotify::util::generate_random_string(16);
let oauth = SpotifyOAuth::default();
- //let callback = oauth.redirect_uri.clone();
let oauth = oauth
.scope("playlist-read-private, playlist-read-collaborative, user-read-private, user-follow-read, user-library-read")
- //.redirect_uri(format!("{}/{}", callback, &state).as_ref())
.build();
let auth_url = oauth.get_authorize_url(Some(&state), None);
- match CACHE.lock() {
- Ok(mut guard) => {
- guard.insert(name, oauth);
- Ok(Redirect::to(auth_url))
- }
- Err(_) => Err(status::Custom(
- Status::ImATeapot,
- "Internal Server Error".to_owned(),
- )),
- }
+ let mut guard = CACHE.lock()?;
+ guard.insert(name, oauth);
+ Ok(Redirect::to(auth_url))
}
-fn get_uid(name: &str, client: &mut postgres::Client) -> Option<i32> {
- match client.query("SELECT user_id FROM suser where user_name = $1;", &[&name]) {
- Ok(rows) => match rows.len() {
- 0 => None,
- x => {
- let x: i32 = rows[0].get(0);
- Some(x)
- }
- },
- _ => None,
- }
+fn get_uid(name: &str, client: &mut postgres::Client) -> Result<i32, Error> {
+ let x: i32 = client
+ .query_one("SELECT user_id FROM suser where user_name = $1;", &[&name])?
+ .get(0);
+ Ok(x)
}
#[get("/match/<name1>/<name2>")]
-pub fn match_users(name1: String, name2: String) -> Result<String, status::NotFound<String>> {
- let mut client = crate::CLIENT.lock().unwrap();
- let uid1 = get_uid(name1.as_ref(), &mut client)
- .ok_or(status::NotFound(format!("username {} not found", name1)))?;
- let uid2 = get_uid(name2.as_ref(), &mut client)
- .ok_or(status::NotFound(format!("username {} not found", name2)))?;
+pub fn match_users(name1: String, name2: String) -> Result<String, Error> {
+ let mut client = crate::CLIENT.lock()?;
let mut songs = String::new();
- for row in client
- .query(
- "
+ for row in client.query(
+ "
WITH users AS (
SELECT *
FROM ( VALUES
@@ -213,19 +186,15 @@ pub fn match_users(name1: String, name2: String) -> Result<String, status::NotFo
FROM user_track
JOIN suser USING (user_id)
JOIN track USING (track_id)
- WHERE suser.user_id IN (SELECT * FROM users)
+ WHERE suser.user_name IN (SELECT * FROM users)
GROUP BY track_id
HAVING COUNT(track_id) = (SELECT COUNT(*) FROM users)
ORDER BY SUM(score) DESC
) AS _ USING (track_id)
;
",
- &[&uid1, &uid2],
- )
- .unwrap()
- {
- //let song = row.get(0);
- println!("{:?}", row.columns());
+ &[&name1.as_str(), &name2.as_str()],
+ )? {
let name: String = row.get(1);
let artist: String = row.get(2);
songs = format!("{}{} by {}\n", songs, name, artist);
@@ -234,10 +203,10 @@ pub fn match_users(name1: String, name2: String) -> Result<String, status::NotFo
}
#[get("/user")]
-pub fn get_users() -> Result<String, status::NotFound<String>> {
- let mut client = crate::CLIENT.lock().unwrap();
+pub fn get_users() -> Result<String, Error> {
+ let mut client = crate::CLIENT.lock()?;
let mut users = String::new();
- for row in client.query("SELECT user_name FROM suser", &[]).unwrap() {
+ for row in client.query("SELECT user_name FROM suser", &[])? {
let user: String = row.get(0);
users = format!("{}{}\n", users, user);
}