use std::ffi::{CStr, CString};
use mpdclient_sys::{
mpd_message_get_channel, mpd_message_get_text, mpd_recv_message, mpd_recv_pair_named,
mpd_return_pair, mpd_run_send_message, mpd_run_subscribe, mpd_run_unsubscribe,
mpd_send_channels, mpd_send_read_messages,
};
use crate::{Connection, error::Result};
#[derive(Debug)]
pub struct Channel<'a> {
connection: &'a Connection,
}
impl<'a> Channel<'a> {
pub(crate) fn new(connection: &'a Connection) -> Self {
Self { connection }
}
pub fn subscribe(&self, channel: &str) -> Result<()> {
let channel = CString::new(channel)?;
self.connection.get_bool_error(|| unsafe {
mpd_run_subscribe(self.connection.connection(), channel.as_ptr())
})?;
Ok(())
}
pub fn unsubscribe(&self, channel: &str) -> Result<()> {
let channel = CString::new(channel)?;
self.connection.get_bool_error(|| unsafe {
mpd_run_unsubscribe(self.connection.connection(), channel.as_ptr())
})?;
Ok(())
}
pub fn read_subscriptions(&self) -> Result<MessageIter<'_>> {
self.connection
.get_bool_error(|| unsafe { mpd_send_read_messages(self.connection.connection()) })?;
Ok(MessageIter {
connection: self.connection,
})
}
pub fn channel_write(&self, channel: &str, msg: &str) -> Result<()> {
let channel = CString::new(channel)?;
let msg = CString::new(msg)?;
self.connection.get_bool_error(|| unsafe {
mpd_run_send_message(self.connection.connection(), channel.as_ptr(), msg.as_ptr())
})
}
pub fn list(&self) -> Result<Vec<String>> {
self.connection
.get_bool_error(|| unsafe { mpd_send_channels(self.connection.connection()) })?;
let channel_str = CString::new("channel")?;
let mut channel_pair = self.connection.get_error(|| unsafe {
mpd_recv_pair_named(self.connection.connection(), channel_str.as_ptr())
})?;
let mut channels = Vec::new();
while !channel_pair.is_null() {
channels.push(
unsafe { CStr::from_ptr((*channel_pair).value) }
.to_string_lossy()
.to_string(),
);
unsafe { mpd_return_pair(self.connection.connection(), channel_pair) };
channel_pair = self.connection.get_error(|| unsafe {
mpd_recv_pair_named(self.connection.connection(), channel_str.as_ptr())
})?;
}
Ok(channels)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct Message {
pub channel: String,
pub text: String,
}
pub struct MessageIter<'a> {
connection: &'a Connection,
}
impl Iterator for MessageIter<'_> {
type Item = Result<Message>;
fn next(&mut self) -> Option<Self::Item> {
let msg = self
.connection
.get_error(|| unsafe { mpd_recv_message(self.connection.connection()) });
match msg {
Ok(msg) => {
if msg.is_null() {
return None;
}
let channel = unsafe { CStr::from_ptr(mpd_message_get_channel(msg)) }
.to_string_lossy()
.to_string();
let text = unsafe { CStr::from_ptr(mpd_message_get_text(msg)) }
.to_string_lossy()
.to_string();
Some(Ok(Message { channel, text }))
}
Err(err) => Some(Err(err)),
}
}
}