mirror of
https://github.com/NotAShelf/mpvrc.git
synced 2026-04-17 08:19:51 +00:00
server: use configurable socket path; remove unused import
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Icf8542f6d43f2a4c6424714886afb8416a6a6964
This commit is contained in:
parent
f3f5b9de93
commit
637dc564fe
2 changed files with 46 additions and 38 deletions
17
src/lib.rs
17
src/lib.rs
|
|
@ -42,12 +42,15 @@
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
pub mod interactive;
|
pub mod interactive;
|
||||||
|
|
||||||
use serde_json::{Value, json};
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
use serde_json::{Value, json};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::{
|
||||||
use tokio::net::UnixStream;
|
io::{AsyncReadExt, AsyncWriteExt},
|
||||||
use tracing::{debug, error};
|
net::UnixStream,
|
||||||
|
};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
pub const SOCKET_PATH: &str = "/tmp/mpvsocket";
|
pub const SOCKET_PATH: &str = "/tmp/mpvsocket";
|
||||||
const SOCKET_TIMEOUT_SECS: u64 = 5;
|
const SOCKET_TIMEOUT_SECS: u64 = 5;
|
||||||
|
|
@ -459,10 +462,12 @@ pub async fn loadfile(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use serde_json::json;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mrc_error_display() {
|
fn test_mrc_error_display() {
|
||||||
let error = MrcError::InvalidInput("test message".to_string());
|
let error = MrcError::InvalidInput("test message".to_string());
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
use std::env;
|
use std::{env, io::Read, sync::Arc};
|
||||||
use std::io::Read;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use mrc::{MrcError, Result as MrcResult, SOCKET_PATH, commands::Commands};
|
||||||
use native_tls::{Identity, TlsAcceptor as NativeTlsAcceptor};
|
use native_tls::{Identity, TlsAcceptor as NativeTlsAcceptor};
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokio_native_tls::TlsAcceptor;
|
use tokio_native_tls::TlsAcceptor;
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
|
|
||||||
use mrc::{MrcError, Result as MrcResult, commands::Commands};
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(author, version, about)]
|
#[command(author, version, about)]
|
||||||
struct Config {
|
struct Config {
|
||||||
|
|
@ -18,13 +15,22 @@ struct Config {
|
||||||
bind: String,
|
bind: String,
|
||||||
|
|
||||||
/// Path to MPV IPC socket
|
/// Path to MPV IPC socket
|
||||||
#[arg(short, long, default_value = "/tmp/mpvsocket")]
|
#[arg(short, long)]
|
||||||
socket: String,
|
socket: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
fn socket_path(&self) -> String {
|
||||||
|
self.socket
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| SOCKET_PATH.to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_connection(
|
async fn handle_connection(
|
||||||
stream: tokio::net::TcpStream,
|
stream: tokio::net::TcpStream,
|
||||||
acceptor: Arc<TlsAcceptor>,
|
acceptor: Arc<TlsAcceptor>,
|
||||||
|
socket_path: String,
|
||||||
) -> MrcResult<()> {
|
) -> MrcResult<()> {
|
||||||
let mut stream = acceptor
|
let mut stream = acceptor
|
||||||
.accept(stream)
|
.accept(stream)
|
||||||
|
|
@ -88,7 +94,7 @@ async fn handle_connection(
|
||||||
|
|
||||||
info!("Processing command: {}", command);
|
info!("Processing command: {}", command);
|
||||||
|
|
||||||
let (status_code, response_body) = match process_command(command).await {
|
let (status_code, response_body) = match process_command(command, &socket_path).await {
|
||||||
Ok(response) => ("200 OK", response),
|
Ok(response) => ("200 OK", response),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error processing command '{}': {}", command, e);
|
error!("Error processing command '{}': {}", command, e);
|
||||||
|
|
@ -108,23 +114,23 @@ async fn handle_connection(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_command(command: &str) -> MrcResult<String> {
|
async fn process_command(command: &str, socket_path: &str) -> MrcResult<String> {
|
||||||
let parts: Vec<&str> = command.split_whitespace().collect();
|
let parts: Vec<&str> = command.split_whitespace().collect();
|
||||||
|
|
||||||
match parts.as_slice() {
|
match parts.as_slice() {
|
||||||
["pause"] => {
|
["pause"] => {
|
||||||
Commands::pause().await?;
|
Commands::pause(Some(socket_path)).await?;
|
||||||
Ok("Paused playback\n".to_string())
|
Ok("Paused playback\n".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
["play"] => {
|
["play"] => {
|
||||||
Commands::play(None).await?;
|
Commands::play(None, Some(socket_path)).await?;
|
||||||
Ok("Resumed playback\n".to_string())
|
Ok("Resumed playback\n".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
["play", index] => {
|
["play", index] => {
|
||||||
if let Ok(idx) = index.parse::<usize>() {
|
if let Ok(idx) = index.parse::<usize>() {
|
||||||
Commands::play(Some(idx)).await?;
|
Commands::play(Some(idx), Some(socket_path)).await?;
|
||||||
Ok(format!("Playing from index {}\n", idx))
|
Ok(format!("Playing from index {}\n", idx))
|
||||||
} else {
|
} else {
|
||||||
Err(MrcError::InvalidInput(format!("Invalid index: {}", index)))
|
Err(MrcError::InvalidInput(format!("Invalid index: {}", index)))
|
||||||
|
|
@ -132,23 +138,23 @@ async fn process_command(command: &str) -> MrcResult<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
["stop"] => {
|
["stop"] => {
|
||||||
Commands::stop().await?;
|
Commands::stop(Some(socket_path)).await?;
|
||||||
Ok("Stopped playback\n".to_string())
|
Ok("Stopped playback\n".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
["next"] => {
|
["next"] => {
|
||||||
Commands::next().await?;
|
Commands::next(Some(socket_path)).await?;
|
||||||
Ok("Skipped to next item\n".to_string())
|
Ok("Skipped to next item\n".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
["prev"] => {
|
["prev"] => {
|
||||||
Commands::prev().await?;
|
Commands::prev(Some(socket_path)).await?;
|
||||||
Ok("Skipped to previous item\n".to_string())
|
Ok("Skipped to previous item\n".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
["seek", seconds] => {
|
["seek", seconds] => {
|
||||||
if let Ok(sec) = seconds.parse::<f64>() {
|
if let Ok(sec) = seconds.parse::<f64>() {
|
||||||
Commands::seek_to(sec).await?;
|
Commands::seek_to(sec, Some(socket_path)).await?;
|
||||||
Ok(format!("Seeking to {} seconds\n", sec))
|
Ok(format!("Seeking to {} seconds\n", sec))
|
||||||
} else {
|
} else {
|
||||||
Err(MrcError::InvalidInput(format!(
|
Err(MrcError::InvalidInput(format!(
|
||||||
|
|
@ -159,22 +165,18 @@ async fn process_command(command: &str) -> MrcResult<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
["clear"] => {
|
["clear"] => {
|
||||||
Commands::clear_playlist().await?;
|
Commands::clear_playlist(Some(socket_path)).await?;
|
||||||
Ok("Cleared playlist\n".to_string())
|
Ok("Cleared playlist\n".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
["list"] => {
|
["list"] => match mrc::get_property("playlist", Some(socket_path)).await? {
|
||||||
// For server response, we need to capture the output differently
|
|
||||||
// since Commands::list_playlist() prints to stdout
|
|
||||||
match mrc::get_property("playlist", None).await? {
|
|
||||||
Some(data) => {
|
Some(data) => {
|
||||||
let pretty_json =
|
let pretty_json =
|
||||||
serde_json::to_string_pretty(&data).map_err(MrcError::ParseError)?;
|
serde_json::to_string_pretty(&data).map_err(MrcError::ParseError)?;
|
||||||
Ok(format!("Playlist: {}\n", pretty_json))
|
Ok(format!("Playlist: {}\n", pretty_json))
|
||||||
}
|
}
|
||||||
None => Ok("Playlist is empty\n".to_string()),
|
None => Ok("Playlist is empty\n".to_string()),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
|
|
||||||
_ => Err(MrcError::InvalidInput(format!(
|
_ => Err(MrcError::InvalidInput(format!(
|
||||||
"Unknown command: {}. Available commands: pause, play [index], stop, next, prev, seek <seconds>, clear, list",
|
"Unknown command: {}. Available commands: pause, play [index], stop, next, prev, seek <seconds>, clear, list",
|
||||||
|
|
@ -205,15 +207,16 @@ fn create_tls_acceptor() -> MrcResult<TlsAcceptor> {
|
||||||
async fn main() -> MrcResult<()> {
|
async fn main() -> MrcResult<()> {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
let config = Config::parse();
|
let config = Config::parse();
|
||||||
|
let socket_path = config.socket_path();
|
||||||
|
|
||||||
if !std::path::Path::new(&config.socket).exists() {
|
if !std::path::Path::new(&socket_path).exists() {
|
||||||
error!(
|
error!(
|
||||||
"Error: MPV socket not found at '{}'. Is MPV running?",
|
"Error: MPV socket not found at '{}'. Is MPV running?",
|
||||||
config.socket
|
socket_path
|
||||||
);
|
);
|
||||||
return Err(MrcError::ConnectionError(std::io::Error::new(
|
return Err(MrcError::ConnectionError(std::io::Error::new(
|
||||||
std::io::ErrorKind::NotFound,
|
std::io::ErrorKind::NotFound,
|
||||||
format!("MPV socket not found at '{}'", config.socket),
|
format!("MPV socket not found at '{}'", socket_path),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,7 +234,7 @@ async fn main() -> MrcResult<()> {
|
||||||
info!("New connection accepted.");
|
info!("New connection accepted.");
|
||||||
|
|
||||||
let acceptor = Arc::clone(&acceptor);
|
let acceptor = Arc::clone(&acceptor);
|
||||||
tokio::spawn(handle_connection(stream, acceptor));
|
tokio::spawn(handle_connection(stream, acceptor, socket_path.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue