1
use serde::{Deserialize, Serialize};
2

            
3
use crate::common::*;
4

            
5
use crate::commands::*;
6
use crate::filter::Filter;
7

            
8
// TODO: SingleLineString
9

            
10
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11
pub enum Request {
12
    CommandList(Vec<Request>),
13

            
14
    // -- Query Commands -- //
15
    ClearError,
16
    CurrentSong,
17
    Idle(Option<Vec<SubSystem>>),
18
    Status,
19
    Stats,
20

            
21
    // -- Playback Commands -- //
22
    Consume(BoolOrOneshot),
23
    Crossfade(Seconds),
24
    MixRampDb(f32),
25
    MixRampDelay(Seconds),
26
    Random(bool),
27
    Repeat(bool),
28
    SetVol(VolumeValue),
29
    GetVol,
30
    Single(BoolOrOneshot),
31
    ReplayGainMode(ReplayGainModeMode),
32
    ReplayGainStatus,
33
    Volume(VolumeValue),
34

            
35
    // -- Playback Control Commands -- //
36
    Next,
37
    Pause(Option<bool>),
38
    Play(SongPosition),
39
    PlayId(SongId),
40
    Previous,
41
    Seek(SongPosition, TimeWithFractions),
42
    SeekId(SongId, TimeWithFractions),
43
    SeekCur(SeekMode, TimeWithFractions),
44
    Stop,
45

            
46
    // -- Queue Commands -- //
47
    // TODO: relative mode
48
    Add(String, Option<SongPosition>),
49
    // TODO: relative mode
50
    AddId(String, Option<SongPosition>),
51
    Clear,
52
    Delete(OneOrRange),
53
    DeleteId(SongId),
54
    // TODO: account for relative moves
55
    Move(OneOrRange, AbsouluteRelativeSongPosition),
56
    // TODO: account for relative moves
57
    MoveId(SongId, AbsouluteRelativeSongPosition),
58
    Playlist,
59
    PlaylistFind(Filter, Option<Sort>, Option<WindowRange>),
60
    PlaylistId(SongId),
61
    PlaylistInfo(Option<OneOrRange>),
62
    PlaylistSearch(Filter, Option<Sort>, Option<WindowRange>),
63
    // TODO: which type of range?
64
    PlChanges(Version, Option<WindowRange>),
65
    // TODO: which type of range?
66
    PlChangesPosId(Version, Option<WindowRange>),
67
    // TODO: which type of range?
68
    Prio(Priority, WindowRange),
69
    PrioId(Priority, Vec<SongId>),
70
    RangeId(SongId, TimeInterval),
71
    Shuffle(Option<OneOrRange>),
72
    Swap(SongPosition, SongPosition),
73
    SwapId(SongId, SongId),
74
    AddTagId(SongId, TagName, TagValue),
75
    ClearTagId(SongId, TagName),
76

            
77
    // -- Stored Playlist Commands -- //
78
    ListPlaylist(PlaylistName, Option<WindowRange>),
79
    ListPlaylistInfo(PlaylistName, Option<WindowRange>),
80
    SearchPlaylist(PlaylistName, Filter, Option<WindowRange>),
81
    ListPlaylists,
82
    Load(PlaylistName, Option<WindowRange>, Option<SongPosition>),
83
    PlaylistAdd(PlaylistName, Uri, Option<SongPosition>),
84
    PlaylistClear(PlaylistName),
85
    PlaylistDelete(PlaylistName, OneOrRange),
86
    PlaylistLength(PlaylistName),
87
    // TODO: which type of range?
88
    PlaylistMove(PlaylistName, Option<OneOrRange>, SongPosition),
89
    Rename(PlaylistName, PlaylistName),
90
    Rm(PlaylistName),
91
    Save(PlaylistName, Option<SaveMode>),
92

            
93
    // -- Music Database Commands -- //
94
    AlbumArt(Uri, Offset),
95
    Count(Filter, Option<GroupType>),
96
    GetFingerprint(Uri),
97
    Find(Filter, Option<Sort>, Option<WindowRange>),
98
    FindAdd(
99
        Filter,
100
        Option<Sort>,
101
        Option<WindowRange>,
102
        Option<SongPosition>,
103
    ),
104
    List(TagName, Filter, Option<GroupType>),
105
    #[deprecated]
106
    ListAll(Option<Uri>),
107
    #[deprecated]
108
    ListAllInfo(Option<Uri>),
109
    ListFiles(Option<Uri>),
110
    LsInfo(Option<Uri>),
111
    ReadComments(Uri),
112
    ReadPicture(Uri, Offset),
113
    Search(Filter, Option<Sort>, Option<WindowRange>),
114
    SearchAdd(
115
        Filter,
116
        Option<Sort>,
117
        Option<WindowRange>,
118
        Option<SongPosition>,
119
    ),
120
    SearchAddPl(
121
        PlaylistName,
122
        Filter,
123
        Option<Sort>,
124
        Option<WindowRange>,
125
        Option<SongPosition>,
126
    ),
127
    SearchCount(Filter, Option<GroupType>),
128
    Update(Option<Uri>),
129
    Rescan(Option<Uri>),
130

            
131
    // -- Mount and Neighbor Commands -- //
132
    Mount(Path, Uri),
133
    Unmount(Path),
134
    ListMounts,
135
    ListNeighbors,
136

            
137
    // -- Sticker Commands -- //
138
    StickerGet(StickerType, Uri, String),
139
    StickerSet(StickerType, Uri, String, String),
140
    StickerInc(StickerType, Uri, String, usize),
141
    StickerDec(StickerType, Uri, String, usize),
142
    StickerDelete(StickerType, Uri, String),
143
    StickerList(StickerType, Uri),
144
    StickerFind(StickerType, Uri, String, Option<Sort>, Option<WindowRange>),
145
    StickerFindValue(
146
        StickerType,
147
        Uri,
148
        String,
149
        String,
150
        Option<Sort>,
151
        Option<WindowRange>,
152
    ),
153
    StickerNames,
154
    StickerTypes,
155
    StickerNamesTypes(Option<StickerType>),
156

            
157
    // -- Connection Commands -- //
158
    Close,
159
    Kill,
160
    Password(String),
161
    Ping,
162
    BinaryLimit(u64),
163
    TagTypes,
164
    TagTypesDisable(Vec<TagName>),
165
    TagTypesEnable(Vec<TagName>),
166
    TagTypesClear,
167
    TagTypesAll,
168
    TagTypesAvailable,
169
    TagTypesReset(Vec<TagName>),
170
    Protocol,
171
    ProtocolDisable(Vec<Feature>),
172
    ProtocolEnable(Vec<Feature>),
173
    ProtocolClear,
174
    ProtocolAll,
175
    ProtocolAvailable,
176

            
177
    // -- Partition Commands -- //
178
    Partition(PartitionName),
179
    ListPartitions,
180
    NewPartition(PartitionName),
181
    DelPartition(PartitionName),
182
    MoveOutput(String),
183

            
184
    // -- Audio Output Commands -- //
185
    DisableOutput(AudioOutputId),
186
    EnableOutput(AudioOutputId),
187
    ToggleOutput(AudioOutputId),
188
    Outputs,
189
    OutputSet(AudioOutputId, String, String),
190

            
191
    // -- Reflection Commands -- //
192
    Config,
193
    Commands,
194
    NotCommands,
195
    UrlHandlers,
196
    Decoders,
197

            
198
    // -- Client to Client Commands -- //
199
    Subscribe(ChannelName),
200
    Unsubscribe(ChannelName),
201
    Channels,
202
    ReadMessages,
203
    SendMessage(ChannelName, String),
204
}
205

            
206
// pub enum RequestParserError {
207
//     SyntaxError(u64, String),
208
//     MissingCommandListEnd(u64),
209
//     NestedCommandList(u64),
210
//     UnexpectedCommandListEnd(u64),
211
//     UnexpectedEOF,
212
//     MissingNewline,
213
// }
214

            
215
// TODO: upon encountering an error, there should be a function that lets you skip to the next OK,
216
//       and continue execution. Maybe "parse_next_or_skip(&str) -> RequestParserResponse", which
217
//       could skip stuff internally? Or do we want to report back the error with the entire command
218
//       and let the library user decide what to do?
219

            
220
impl Request {
221
    pub fn parse_next(raw: &str) -> RequestParserResult<'_> {
222
        let (line, rest) = raw
223
            .split_once('\n')
224
            .ok_or(RequestParserError::UnexpectedEOF)?;
225
        let mut parts = line.split_whitespace();
226

            
227
        match parts
228
            .next()
229
            .ok_or(RequestParserError::SyntaxError(0, line.to_string()))?
230
            .trim()
231
        {
232
            "command_list_begin" => {
233
                let mut commands = Vec::new();
234
                let mut i = 1;
235
                loop {
236
                    i += 1;
237
                    let (line, rest) = rest
238
                        .split_once('\n')
239
                        .ok_or(RequestParserError::MissingCommandListEnd(i))?;
240
                    match line.trim() {
241
                        "command_list_begin" => {
242
                            return Err(RequestParserError::NestedCommandList(i));
243
                        }
244
                        "command_list_end" => {
245
                            return Ok((Request::CommandList(commands), rest));
246
                        }
247
                        input => {
248
                            let (command, _) = Request::parse_next(input)?;
249
                            commands.push(command);
250
                        }
251
                    }
252
                }
253
            }
254
            "command_list_end" => Err(RequestParserError::UnexpectedCommandListEnd(0)),
255

            
256
            /* querying mpd status */
257
            ClearError::COMMAND => ClearError::parse_request(parts),
258
            CurrentSong::COMMAND => CurrentSong::parse_request(parts),
259
            Idle::COMMAND => Idle::parse_request(parts),
260
            Status::COMMAND => Status::parse_request(parts),
261
            Stats::COMMAND => Stats::parse_request(parts),
262

            
263
            /* playback options */
264
            Consume::COMMAND => Consume::parse_request(parts),
265
            Crossfade::COMMAND => Crossfade::parse_request(parts),
266
            MixRampDb::COMMAND => MixRampDb::parse_request(parts),
267
            MixRampDelay::COMMAND => MixRampDelay::parse_request(parts),
268
            Random::COMMAND => Random::parse_request(parts),
269
            Repeat::COMMAND => Repeat::parse_request(parts),
270
            SetVol::COMMAND => SetVol::parse_request(parts),
271
            GetVol::COMMAND => GetVol::parse_request(parts),
272
            Single::COMMAND => Single::parse_request(parts),
273
            ReplayGainMode::COMMAND => ReplayGainMode::parse_request(parts),
274
            ReplayGainStatus::COMMAND => ReplayGainStatus::parse_request(parts),
275
            Volume::COMMAND => Volume::parse_request(parts),
276

            
277
            /* playback control */
278
            Next::COMMAND => Next::parse_request(parts),
279
            Pause::COMMAND => Pause::parse_request(parts),
280
            Play::COMMAND => Play::parse_request(parts),
281
            PlayId::COMMAND => PlayId::parse_request(parts),
282
            Previous::COMMAND => Previous::parse_request(parts),
283
            Seek::COMMAND => Seek::parse_request(parts),
284
            SeekId::COMMAND => SeekId::parse_request(parts),
285
            SeekCur::COMMAND => SeekCur::parse_request(parts),
286
            Stop::COMMAND => Stop::parse_request(parts),
287

            
288
            /* queue */
289
            Add::COMMAND => Add::parse_request(parts),
290
            AddId::COMMAND => AddId::parse_request(parts),
291
            Clear::COMMAND => Clear::parse_request(parts),
292
            Delete::COMMAND => Delete::parse_request(parts),
293
            DeleteId::COMMAND => DeleteId::parse_request(parts),
294
            Move::COMMAND => Move::parse_request(parts),
295
            MoveId::COMMAND => MoveId::parse_request(parts),
296
            Playlist::COMMAND => Playlist::parse_request(parts),
297
            PlaylistFind::COMMAND => PlaylistFind::parse_request(parts),
298
            PlaylistId::COMMAND => PlaylistId::parse_request(parts),
299
            PlaylistInfo::COMMAND => PlaylistInfo::parse_request(parts),
300
            PlaylistSearch::COMMAND => PlaylistSearch::parse_request(parts),
301
            PlChanges::COMMAND => PlChanges::parse_request(parts),
302
            PlChangesPosId::COMMAND => PlChangesPosId::parse_request(parts),
303
            Prio::COMMAND => Prio::parse_request(parts),
304
            PrioId::COMMAND => PrioId::parse_request(parts),
305
            RangeId::COMMAND => RangeId::parse_request(parts),
306
            Shuffle::COMMAND => Shuffle::parse_request(parts),
307
            Swap::COMMAND => Swap::parse_request(parts),
308
            SwapId::COMMAND => SwapId::parse_request(parts),
309
            AddTagId::COMMAND => AddTagId::parse_request(parts),
310
            ClearTagId::COMMAND => ClearTagId::parse_request(parts),
311

            
312
            /* stored playlists */
313
            ListPlaylist::COMMAND => ListPlaylist::parse_request(parts),
314
            ListPlaylistInfo::COMMAND => ListPlaylistInfo::parse_request(parts),
315
            SearchPlaylist::COMMAND => SearchPlaylist::parse_request(parts),
316
            ListPlaylists::COMMAND => ListPlaylists::parse_request(parts),
317
            Load::COMMAND => Load::parse_request(parts),
318
            PlaylistAdd::COMMAND => PlaylistAdd::parse_request(parts),
319
            PlaylistClear::COMMAND => PlaylistClear::parse_request(parts),
320
            PlaylistDelete::COMMAND => PlaylistDelete::parse_request(parts),
321
            PlaylistLength::COMMAND => PlaylistLength::parse_request(parts),
322
            PlaylistMove::COMMAND => PlaylistMove::parse_request(parts),
323
            Rename::COMMAND => Rename::parse_request(parts),
324
            Rm::COMMAND => Rm::parse_request(parts),
325
            Save::COMMAND => Save::parse_request(parts),
326

            
327
            /* music database */
328
            AlbumArt::COMMAND => AlbumArt::parse_request(parts),
329
            Count::COMMAND => Count::parse_request(parts),
330
            GetFingerprint::COMMAND => GetFingerprint::parse_request(parts),
331
            Find::COMMAND => Find::parse_request(parts),
332
            FindAdd::COMMAND => FindAdd::parse_request(parts),
333
            List::COMMAND => List::parse_request(parts),
334
            ListAll::COMMAND => ListAll::parse_request(parts),
335
            ListAllInfo::COMMAND => ListAllInfo::parse_request(parts),
336
            ListFiles::COMMAND => ListFiles::parse_request(parts),
337
            LsInfo::COMMAND => LsInfo::parse_request(parts),
338
            ReadComments::COMMAND => ReadComments::parse_request(parts),
339
            ReadPicture::COMMAND => ReadPicture::parse_request(parts),
340
            Search::COMMAND => Search::parse_request(parts),
341
            SearchAdd::COMMAND => SearchAdd::parse_request(parts),
342
            SearchAddPl::COMMAND => SearchAddPl::parse_request(parts),
343
            SearchCount::COMMAND => SearchCount::parse_request(parts),
344
            Update::COMMAND => Update::parse_request(parts),
345
            Rescan::COMMAND => Rescan::parse_request(parts),
346

            
347
            /* mounts and neighbors */
348
            Mount::COMMAND => Mount::parse_request(parts),
349
            Unmount::COMMAND => Unmount::parse_request(parts),
350
            ListMounts::COMMAND => ListMounts::parse_request(parts),
351
            ListNeighbors::COMMAND => ListNeighbors::parse_request(parts),
352

            
353
            /* stickers */
354
            StickerGet::COMMAND => StickerGet::parse_request(parts),
355
            StickerSet::COMMAND => StickerSet::parse_request(parts),
356
            StickerInc::COMMAND => StickerInc::parse_request(parts),
357
            StickerDec::COMMAND => StickerDec::parse_request(parts),
358
            StickerDelete::COMMAND => StickerDelete::parse_request(parts),
359
            StickerList::COMMAND => StickerList::parse_request(parts),
360
            StickerFind::COMMAND => StickerFind::parse_request(parts),
361
            StickerNames::COMMAND => StickerNames::parse_request(parts),
362
            StickerTypes::COMMAND => StickerTypes::parse_request(parts),
363
            StickerNamesTypes::COMMAND => StickerNamesTypes::parse_request(parts),
364

            
365
            /* connection settings */
366
            Close::COMMAND => Close::parse_request(parts),
367
            Kill::COMMAND => Kill::parse_request(parts),
368
            Password::COMMAND => Password::parse_request(parts),
369
            Ping::COMMAND => Ping::parse_request(parts),
370
            BinaryLimit::COMMAND => BinaryLimit::parse_request(parts),
371
            TagTypes::COMMAND => TagTypes::parse_request(parts),
372
            TagTypesDisable::COMMAND => TagTypesDisable::parse_request(parts),
373
            TagTypesEnable::COMMAND => TagTypesEnable::parse_request(parts),
374
            TagTypesClear::COMMAND => TagTypesClear::parse_request(parts),
375
            TagTypesAll::COMMAND => TagTypesAll::parse_request(parts),
376
            TagTypesAvailable::COMMAND => TagTypesAvailable::parse_request(parts),
377
            TagTypesReset::COMMAND => TagTypesReset::parse_request(parts),
378
            Protocol::COMMAND => Protocol::parse_request(parts),
379
            ProtocolDisable::COMMAND => ProtocolDisable::parse_request(parts),
380
            ProtocolEnable::COMMAND => ProtocolEnable::parse_request(parts),
381
            ProtocolClear::COMMAND => ProtocolClear::parse_request(parts),
382
            ProtocolAll::COMMAND => ProtocolAll::parse_request(parts),
383
            ProtocolAvailable::COMMAND => ProtocolAvailable::parse_request(parts),
384

            
385
            /* partition commands */
386
            Partition::COMMAND => Partition::parse_request(parts),
387
            ListPartitions::COMMAND => ListPartitions::parse_request(parts),
388
            NewPartition::COMMAND => NewPartition::parse_request(parts),
389
            DelPartition::COMMAND => DelPartition::parse_request(parts),
390
            MoveOutput::COMMAND => MoveOutput::parse_request(parts),
391

            
392
            /* audio output devices */
393
            DisableOutput::COMMAND => DisableOutput::parse_request(parts),
394
            EnableOutput::COMMAND => EnableOutput::parse_request(parts),
395
            ToggleOutput::COMMAND => ToggleOutput::parse_request(parts),
396
            Outputs::COMMAND => Outputs::parse_request(parts),
397
            OutputSet::COMMAND => OutputSet::parse_request(parts),
398

            
399
            /* reflection */
400
            Config::COMMAND => Config::parse_request(parts),
401
            Commands::COMMAND => Commands::parse_request(parts),
402
            NotCommands::COMMAND => NotCommands::parse_request(parts),
403
            UrlHandlers::COMMAND => UrlHandlers::parse_request(parts),
404
            Decoders::COMMAND => Decoders::parse_request(parts),
405

            
406
            /* client to client */
407
            Subscribe::COMMAND => Subscribe::parse_request(parts),
408
            Unsubscribe::COMMAND => Unsubscribe::parse_request(parts),
409
            Channels::COMMAND => Channels::parse_request(parts),
410
            ReadMessages::COMMAND => ReadMessages::parse_request(parts),
411
            SendMessage::COMMAND => SendMessage::parse_request(parts),
412

            
413
            _ => unimplemented!(),
414
        }
415
    }
416
}