use serde::{Deserialize, Serialize}; use crate::common::types::*; use crate::filter::Filter; // TODO: SingleLineString #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum Request { CommandList(Vec), // -- Query Commands -- // ClearError, CurrentSong, Idle(Option>), Status, Stats, // -- Playback Commands -- // Consume(BoolOrOneshot), Crossfade(Seconds), MixRampDb(f32), MixRampDelay(Seconds), Random(bool), Repeat(bool), SetVol(VolumeValue), GetVol, Single(BoolOrOneshot), ReplayGainMode(ReplayGainModeMode), ReplayGainStatus, Volume(VolumeValue), // -- Playback Control Commands -- // Next, Pause(Option), Play(SongPosition), PlayId(SongId), Previous, Seek(SongPosition, TimeWithFractions), SeekId(SongId, TimeWithFractions), SeekCur(SeekMode, TimeWithFractions), Stop, // -- Queue Commands -- // // TODO: relative mode Add(String, Option), // TODO: relative mode AddId(String, Option), Clear, Delete(OneOrRange), DeleteId(SongId), // TODO: account for relative moves Move(OneOrRange, AbsouluteRelativeSongPosition), // TODO: account for relative moves MoveId(SongId, AbsouluteRelativeSongPosition), Playlist, PlaylistFind(Filter, Option, Option), PlaylistId(SongId), PlaylistInfo(Option), PlaylistSearch(Filter, Option, Option), // TODO: which type of range? PlChanges(PlaylistVersion, Option), // TODO: which type of range? PlChangesPosId(PlaylistVersion, Option), // TODO: which type of range? Prio(Priority, WindowRange), PrioId(Priority, Vec), RangeId(SongId, TimeInterval), Shuffle(Option), Swap(SongPosition, SongPosition), SwapId(SongId, SongId), AddTagId(SongId, TagName, TagValue), ClearTagId(SongId, TagName), // -- Stored Playlist Commands -- // ListPlaylist(PlaylistName, Option), ListPlaylistInfo(PlaylistName, Option), SearchPlaylist(PlaylistName, Filter, Option), ListPlaylists, Load(PlaylistName, Option, Option), PlaylistAdd(PlaylistName, Uri, Option), PlaylistClear(PlaylistName), PlaylistDelete(PlaylistName, OneOrRange), PlaylistLength(PlaylistName), // TODO: which type of range? PlaylistMove(PlaylistName, Option, SongPosition), Rename(PlaylistName, PlaylistName), Rm(PlaylistName), Save(PlaylistName, Option), // -- Music Database Commands -- // AlbumArt(Uri, Offset), Count(Filter, Option), GetFingerprint(Uri), Find(Filter, Option, Option), FindAdd( Filter, Option, Option, Option, ), List(TagName, Option, Vec, Option), #[deprecated] ListAll(Option), #[deprecated] ListAllInfo(Option), ListFiles(Option), LsInfo(Option), ReadComments(Uri), ReadPicture(Uri, Offset), Search(Filter, Option, Option), SearchAdd( Filter, Option, Option, Option, ), SearchAddPl( PlaylistName, Filter, Option, Option, Option, ), SearchCount(Filter, Option), Update(Option), Rescan(Option), // -- Mount and Neighbor Commands -- // Mount(MountPath, Uri), Unmount(MountPath), ListMounts, ListNeighbors, // -- Sticker Commands -- // StickerGet(StickerType, Uri, String), StickerSet(StickerType, Uri, String, String), StickerInc(StickerType, Uri, String, usize), StickerDec(StickerType, Uri, String, usize), StickerDelete(StickerType, Uri, String), StickerList(StickerType, Uri), StickerFind(StickerType, Uri, String, Option, Option), StickerFindValue( StickerType, Uri, String, String, Option, Option, ), StickerNames, StickerTypes, StickerNamesTypes(Option), // -- Connection Commands -- // Close, Kill, Password(String), Ping, BinaryLimit(u64), TagTypes, TagTypesDisable(Vec), TagTypesEnable(Vec), TagTypesClear, TagTypesAll, TagTypesAvailable, TagTypesReset(Vec), Protocol, ProtocolDisable(Vec), ProtocolEnable(Vec), ProtocolClear, ProtocolAll, ProtocolAvailable, // -- Partition Commands -- // Partition(PartitionName), ListPartitions, NewPartition(PartitionName), DelPartition(PartitionName), MoveOutput(String), // -- Audio Output Commands -- // DisableOutput(AudioOutputId), EnableOutput(AudioOutputId), ToggleOutput(AudioOutputId), Outputs, OutputSet(AudioOutputId, String, String), // -- Reflection Commands -- // Config, Commands, NotCommands, UrlHandlers, Decoders, // -- Client to Client Commands -- // Subscribe(ChannelName), Unsubscribe(ChannelName), Channels, ReadMessages, SendMessage(ChannelName, String), } impl Request { // pub enum RequestParserError { // SyntaxError(u64, String), // MissingCommandListEnd(u64), // NestedCommandList(u64), // UnexpectedCommandListEnd(u64), // UnexpectedEOF, // MissingNewline, // } // TODO: upon encountering an error, there should be a function that lets you skip to the next OK, // and continue execution. Maybe "parse_next_or_skip(&str) -> RequestParserResponse", which // could skip stuff internally? Or do we want to report back the error with the entire command // and let the library user decide what to do? // impl Request { // pub fn parse_next(raw: &str) -> Result { // let (line, rest) = raw // .split_once('\n') // .ok_or(RequestParserError::UnexpectedEOF)?; // let mut parts = RequestTokenizer::new(line); // match parts // .next() // .ok_or(RequestParserError::SyntaxError(0, line.to_string()))? // .trim() // { // "command_list_begin" => { // let mut commands = Vec::new(); // let mut i = 1; // loop { // i += 1; // let (line, rest) = rest // .split_once('\n') // .ok_or(RequestParserError::MissingCommandListEnd(i))?; // match line.trim() { // "command_list_begin" => { // return Err(RequestParserError::NestedCommandList(i)); // } // "command_list_end" => { // return Ok((Request::CommandList(commands), rest)); // } // input => { // let (command, _) = Request::parse_next(input)?; // commands.push(command); // } // } // } // } // "command_list_end" => Err(RequestParserError::UnexpectedCommandListEnd(0)), // /* querying mpd status */ // ClearError::COMMAND => ClearError::parse_request(parts), // CurrentSong::COMMAND => CurrentSong::parse_request(parts), // Idle::COMMAND => Idle::parse_request(parts), // Status::COMMAND => Status::parse_request(parts), // Stats::COMMAND => Stats::parse_request(parts), // /* playback options */ // Consume::COMMAND => Consume::parse_request(parts), // Crossfade::COMMAND => Crossfade::parse_request(parts), // MixRampDb::COMMAND => MixRampDb::parse_request(parts), // MixRampDelay::COMMAND => MixRampDelay::parse_request(parts), // Random::COMMAND => Random::parse_request(parts), // Repeat::COMMAND => Repeat::parse_request(parts), // SetVol::COMMAND => SetVol::parse_request(parts), // GetVol::COMMAND => GetVol::parse_request(parts), // Single::COMMAND => Single::parse_request(parts), // ReplayGainMode::COMMAND => ReplayGainMode::parse_request(parts), // ReplayGainStatus::COMMAND => ReplayGainStatus::parse_request(parts), // Volume::COMMAND => Volume::parse_request(parts), // /* playback control */ // Next::COMMAND => Next::parse_request(parts), // Pause::COMMAND => Pause::parse_request(parts), // Play::COMMAND => Play::parse_request(parts), // PlayId::COMMAND => PlayId::parse_request(parts), // Previous::COMMAND => Previous::parse_request(parts), // Seek::COMMAND => Seek::parse_request(parts), // SeekId::COMMAND => SeekId::parse_request(parts), // SeekCur::COMMAND => SeekCur::parse_request(parts), // Stop::COMMAND => Stop::parse_request(parts), // /* queue */ // Add::COMMAND => Add::parse_request(parts), // AddId::COMMAND => AddId::parse_request(parts), // Clear::COMMAND => Clear::parse_request(parts), // Delete::COMMAND => Delete::parse_request(parts), // DeleteId::COMMAND => DeleteId::parse_request(parts), // Move::COMMAND => Move::parse_request(parts), // MoveId::COMMAND => MoveId::parse_request(parts), // Playlist::COMMAND => Playlist::parse_request(parts), // PlaylistFind::COMMAND => PlaylistFind::parse_request(parts), // PlaylistId::COMMAND => PlaylistId::parse_request(parts), // PlaylistInfo::COMMAND => PlaylistInfo::parse_request(parts), // PlaylistSearch::COMMAND => PlaylistSearch::parse_request(parts), // PlChanges::COMMAND => PlChanges::parse_request(parts), // PlChangesPosId::COMMAND => PlChangesPosId::parse_request(parts), // Prio::COMMAND => Prio::parse_request(parts), // PrioId::COMMAND => PrioId::parse_request(parts), // RangeId::COMMAND => RangeId::parse_request(parts), // Shuffle::COMMAND => Shuffle::parse_request(parts), // Swap::COMMAND => Swap::parse_request(parts), // SwapId::COMMAND => SwapId::parse_request(parts), // AddTagId::COMMAND => AddTagId::parse_request(parts), // ClearTagId::COMMAND => ClearTagId::parse_request(parts), // /* stored playlists */ // ListPlaylist::COMMAND => ListPlaylist::parse_request(parts), // ListPlaylistInfo::COMMAND => ListPlaylistInfo::parse_request(parts), // SearchPlaylist::COMMAND => SearchPlaylist::parse_request(parts), // ListPlaylists::COMMAND => ListPlaylists::parse_request(parts), // Load::COMMAND => Load::parse_request(parts), // PlaylistAdd::COMMAND => PlaylistAdd::parse_request(parts), // PlaylistClear::COMMAND => PlaylistClear::parse_request(parts), // PlaylistDelete::COMMAND => PlaylistDelete::parse_request(parts), // PlaylistLength::COMMAND => PlaylistLength::parse_request(parts), // PlaylistMove::COMMAND => PlaylistMove::parse_request(parts), // Rename::COMMAND => Rename::parse_request(parts), // Rm::COMMAND => Rm::parse_request(parts), // Save::COMMAND => Save::parse_request(parts), // /* music database */ // AlbumArt::COMMAND => AlbumArt::parse_request(parts), // Count::COMMAND => Count::parse_request(parts), // GetFingerprint::COMMAND => GetFingerprint::parse_request(parts), // Find::COMMAND => Find::parse_request(parts), // FindAdd::COMMAND => FindAdd::parse_request(parts), // List::COMMAND => List::parse_request(parts), // ListAll::COMMAND => ListAll::parse_request(parts), // ListAllInfo::COMMAND => ListAllInfo::parse_request(parts), // ListFiles::COMMAND => ListFiles::parse_request(parts), // LsInfo::COMMAND => LsInfo::parse_request(parts), // ReadComments::COMMAND => ReadComments::parse_request(parts), // ReadPicture::COMMAND => ReadPicture::parse_request(parts), // Search::COMMAND => Search::parse_request(parts), // SearchAdd::COMMAND => SearchAdd::parse_request(parts), // SearchAddPl::COMMAND => SearchAddPl::parse_request(parts), // SearchCount::COMMAND => SearchCount::parse_request(parts), // Update::COMMAND => Update::parse_request(parts), // Rescan::COMMAND => Rescan::parse_request(parts), // /* mounts and neighbors */ // Mount::COMMAND => Mount::parse_request(parts), // Unmount::COMMAND => Unmount::parse_request(parts), // ListMounts::COMMAND => ListMounts::parse_request(parts), // ListNeighbors::COMMAND => ListNeighbors::parse_request(parts), // /* stickers */ // StickerGet::COMMAND => StickerGet::parse_request(parts), // StickerSet::COMMAND => StickerSet::parse_request(parts), // StickerInc::COMMAND => StickerInc::parse_request(parts), // StickerDec::COMMAND => StickerDec::parse_request(parts), // StickerDelete::COMMAND => StickerDelete::parse_request(parts), // StickerList::COMMAND => StickerList::parse_request(parts), // StickerFind::COMMAND => StickerFind::parse_request(parts), // StickerNames::COMMAND => StickerNames::parse_request(parts), // StickerTypes::COMMAND => StickerTypes::parse_request(parts), // StickerNamesTypes::COMMAND => StickerNamesTypes::parse_request(parts), // /* connection settings */ // Close::COMMAND => Close::parse_request(parts), // Kill::COMMAND => Kill::parse_request(parts), // Password::COMMAND => Password::parse_request(parts), // Ping::COMMAND => Ping::parse_request(parts), // BinaryLimit::COMMAND => BinaryLimit::parse_request(parts), // TagTypes::COMMAND => TagTypes::parse_request(parts), // TagTypesDisable::COMMAND => TagTypesDisable::parse_request(parts), // TagTypesEnable::COMMAND => TagTypesEnable::parse_request(parts), // TagTypesClear::COMMAND => TagTypesClear::parse_request(parts), // TagTypesAll::COMMAND => TagTypesAll::parse_request(parts), // TagTypesAvailable::COMMAND => TagTypesAvailable::parse_request(parts), // TagTypesReset::COMMAND => TagTypesReset::parse_request(parts), // Protocol::COMMAND => Protocol::parse_request(parts), // ProtocolDisable::COMMAND => ProtocolDisable::parse_request(parts), // ProtocolEnable::COMMAND => ProtocolEnable::parse_request(parts), // ProtocolClear::COMMAND => ProtocolClear::parse_request(parts), // ProtocolAll::COMMAND => ProtocolAll::parse_request(parts), // ProtocolAvailable::COMMAND => ProtocolAvailable::parse_request(parts), // /* partition commands */ // Partition::COMMAND => Partition::parse_request(parts), // ListPartitions::COMMAND => ListPartitions::parse_request(parts), // NewPartition::COMMAND => NewPartition::parse_request(parts), // DelPartition::COMMAND => DelPartition::parse_request(parts), // MoveOutput::COMMAND => MoveOutput::parse_request(parts), // /* audio output devices */ // DisableOutput::COMMAND => DisableOutput::parse_request(parts), // EnableOutput::COMMAND => EnableOutput::parse_request(parts), // ToggleOutput::COMMAND => ToggleOutput::parse_request(parts), // Outputs::COMMAND => Outputs::parse_request(parts), // OutputSet::COMMAND => OutputSet::parse_request(parts), // /* reflection */ // Config::COMMAND => Config::parse_request(parts), // Commands::COMMAND => Commands::parse_request(parts), // NotCommands::COMMAND => NotCommands::parse_request(parts), // UrlHandlers::COMMAND => UrlHandlers::parse_request(parts), // Decoders::COMMAND => Decoders::parse_request(parts), // /* client to client */ // Subscribe::COMMAND => Subscribe::parse_request(parts), // Unsubscribe::COMMAND => Unsubscribe::parse_request(parts), // Channels::COMMAND => Channels::parse_request(parts), // ReadMessages::COMMAND => ReadMessages::parse_request(parts), // SendMessage::COMMAND => SendMessage::parse_request(parts), // _ => unimplemented!(), // } // } }