Skip to content

Commit

Permalink
Refactor client request handling module (#418)
Browse files Browse the repository at this point in the history
Resolves #415

## Changes
- update player's playback state upon receiving new player event from the integrated client
- move `ClientRequest` and `PlayerRequest` from `event` module to `client::request` module
- clean up client request handling codes, update comments/documentations
  • Loading branch information
aome510 authored Apr 20, 2024
1 parent 23024c9 commit f37a9d2
Show file tree
Hide file tree
Showing 14 changed files with 380 additions and 452 deletions.
51 changes: 15 additions & 36 deletions spotify_player/src/cli/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ use tracing::Instrument;

use crate::{
cli::Request,
client::Client,
client::{Client, PlayerRequest},
config::get_cache_folder_path,
event::PlayerRequest,
state::{Context, ContextId, Playback, SharedState, SimplifiedPlayback},
state::{Context, ContextId, Playback, PlaybackMetadata, SharedState},
};
use rspotify::{
model::*,
Expand All @@ -25,8 +24,8 @@ use rspotify::{
use super::*;

pub async fn start_socket(client: Client, socket: UdpSocket, state: Option<SharedState>) {
// initialize the receive buffer to be 4096 bytes
let mut buf = [0; MAX_REQUEST_SIZE];

loop {
match socket.recv_from(&mut buf).await {
Err(err) => tracing::warn!("Failed to receive from the socket: {err:#}"),
Expand Down Expand Up @@ -95,7 +94,6 @@ async fn current_playback(
match state {
Some(ref state) => Ok(state.player.read().current_playback()),
None => client
.spotify
.current_playback(None, None::<Vec<_>>)
.await
.context("get current playback"),
Expand All @@ -107,11 +105,8 @@ async fn handle_socket_request(
state: &Option<SharedState>,
request: super::Request,
) -> Result<Vec<u8>> {
if client.spotify.session().await.is_invalid() {
if let Some(state) = state {
tracing::info!("Spotify client's session is invalid, re-creating a new session...");
client.new_session(state).await?;
}
if let Some(state) = state {
client.check_valid_session(state).await?;
}

match request {
Expand All @@ -127,7 +122,7 @@ async fn handle_socket_request(
let id = match data {
IdOrName::Id(id) => id,
IdOrName::Name(name) => {
let devices = client.spotify.device().await?;
let devices = client.device().await?;
match devices
.into_iter()
.find(|d| d.name == name)
Expand All @@ -141,7 +136,7 @@ async fn handle_socket_request(
}
};

client.spotify.transfer_playback(&id, None).await?;
client.transfer_playback(&id, None).await?;
Ok(Vec::new())
}
Request::Like { unlike } => {
Expand All @@ -158,12 +153,9 @@ async fn handle_socket_request(

if let Some(id) = track.and_then(|t| t.id.to_owned()) {
if unlike {
client
.spotify
.current_user_saved_tracks_delete([id])
.await?;
client.current_user_saved_tracks_delete([id]).await?;
} else {
client.spotify.current_user_saved_tracks_add([id]).await?;
client.current_user_saved_tracks_add([id]).await?;
}
}

Expand All @@ -187,7 +179,7 @@ async fn handle_get_key_request(
serde_json::to_vec(&playback)?
}
Key::Devices => {
let devices = client.spotify.device().await?;
let devices = client.device().await?;
serde_json::to_vec(&devices)?
}
Key::UserPlaylists => {
Expand All @@ -211,7 +203,7 @@ async fn handle_get_key_request(
serde_json::to_vec(&artists)?
}
Key::Queue => {
let queue = client.spotify.current_user_queue().await?;
let queue = client.current_user_queue().await?;
serde_json::to_vec(&queue)?
}
})
Expand Down Expand Up @@ -326,11 +318,8 @@ async fn handle_playback_request(
let playback = match state {
Some(state) => state.player.read().buffered_playback.clone(),
None => {
let playback = client
.spotify
.current_playback(None, None::<Vec<_>>)
.await?;
playback.as_ref().map(SimplifiedPlayback::from_playback)
let playback = client.current_playback(None, None::<Vec<_>>).await?;
playback.as_ref().map(PlaybackMetadata::from_playback)
}
};

Expand Down Expand Up @@ -413,7 +402,6 @@ async fn handle_playback_request(
// the function scope is from the application's state (cached) or the `current_playback` API.
// Therefore, we need to make an additional API request to get the playback's progress.
let progress = client
.spotify
.current_playback(None, None::<Vec<_>>)
.await?
.context("no active playback found!")?
Expand Down Expand Up @@ -457,7 +445,7 @@ async fn handle_playback_request(
}

async fn handle_playlist_request(client: &Client, command: PlaylistCommand) -> Result<String> {
let uid = client.spotify.current_user().await?.id;
let uid = client.current_user().await?.id;

match command {
PlaylistCommand::New {
Expand All @@ -467,7 +455,6 @@ async fn handle_playlist_request(client: &Client, command: PlaylistCommand) -> R
description,
} => {
let resp = client
.spotify
.user_playlist_create(
uid,
name.as_str(),
Expand All @@ -483,7 +470,6 @@ async fn handle_playlist_request(client: &Client, command: PlaylistCommand) -> R
}
PlaylistCommand::Delete { id } => {
let following = client
.spotify
.playlist_check_follow(id.to_owned(), &[uid])
.await
.context(format!("Could not find playlist '{}'", id.id()))?
Expand All @@ -492,7 +478,7 @@ async fn handle_playlist_request(client: &Client, command: PlaylistCommand) -> R

// Won't delete if not following
if following {
client.spotify.playlist_unfollow(id.to_owned()).await?;
client.playlist_unfollow(id.to_owned()).await?;
Ok(format!("Playlist '{id}' was deleted/unfollowed"))
} else {
Ok(format!(
Expand All @@ -518,14 +504,12 @@ async fn handle_playlist_request(client: &Client, command: PlaylistCommand) -> R
} => playlist_import(client, import_from, import_to, delete).await,
PlaylistCommand::Fork { id } => {
let from = client
.spotify
.playlist(id.to_owned(), None, None)
.await
.context(format!("Cannot import from {}.", id.id()))?;
let from_desc = from.description.unwrap_or_default();

let to = client
.spotify
.user_playlist_create(
uid,
&from.name,
Expand Down Expand Up @@ -568,7 +552,6 @@ async fn handle_playlist_request(client: &Client, command: PlaylistCommand) -> R
}

let pl_follow = client
.spotify
.playlist_check_follow(to_id.as_ref(), &[uid.as_ref()])
.await?
.pop()
Expand Down Expand Up @@ -682,7 +665,6 @@ async fn playlist_import(

if track_buff.len() == TRACK_BUFFER_CAP {
client
.spotify
.playlist_remove_all_occurrences_of_items(
import_to.as_ref(),
track_buff,
Expand All @@ -695,7 +677,6 @@ async fn playlist_import(

if !track_buff.is_empty() {
client
.spotify
.playlist_remove_all_occurrences_of_items(import_to.as_ref(), track_buff, None)
.await?;
}
Expand All @@ -717,7 +698,6 @@ async fn playlist_import(

if track_buff.len() == TRACK_BUFFER_CAP {
client
.spotify
.playlist_add_items(import_to.as_ref(), track_buff, None)
.await?;
track_buff = Vec::new();
Expand All @@ -728,7 +708,6 @@ async fn playlist_import(

if !track_buff.is_empty() {
client
.spotify
.playlist_add_items(import_to.as_ref(), track_buff, None)
.await?;
}
Expand Down
3 changes: 2 additions & 1 deletion spotify_player/src/cli/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use super::*;
use anyhow::{Context, Result};
use clap::{ArgMatches, Id};
use clap_complete::{generate, Shell};
use rspotify::clients::BaseClient;
use std::net::UdpSocket;

fn receive_response(socket: &UdpSocket) -> Result<Response> {
Expand Down Expand Up @@ -159,7 +160,7 @@ fn try_connect_to_client(socket: &UdpSocket, configs: &state::Configs) -> Result
// create a Spotify API client
let client =
client::Client::new(session, auth_config, configs.app_config.client_id.clone());
rt.block_on(client.init_token())?;
rt.block_on(client.refresh_token())?;

// create a client socket for handling CLI commands
let client_socket = rt.block_on(tokio::net::UdpSocket::bind(("127.0.0.1", port)))?;
Expand Down
13 changes: 6 additions & 7 deletions spotify_player/src/client/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ use anyhow::Context;
use rspotify::model::PlayableItem;
use tracing::Instrument;

use crate::{event::ClientRequest, state::*};
use crate::state::*;

#[cfg(feature = "lyric-finder")]
use crate::utils::map_join;

use super::ClientRequest;

struct PlayerEventHandlerState {
add_track_to_queue_req_timer: std::time::Instant,
}
Expand All @@ -18,12 +20,9 @@ pub async fn start_client_handler(
client_sub: flume::Receiver<ClientRequest>,
) {
while let Ok(request) = client_sub.recv_async().await {
if client.spotify.session().await.is_invalid() {
tracing::info!("Spotify client's session is invalid, re-creating a new session...");
if let Err(err) = client.new_session(&state).await {
tracing::error!("Failed to create a new session: {err:#}");
continue;
}
if let Err(err) = client.check_valid_session(&state).await {
tracing::error!("{err:#}");
continue;
}

let state = state.clone();
Expand Down
Loading

0 comments on commit f37a9d2

Please sign in to comment.