1
use std::str::FromStr;
2

            
3
use serde::{Deserialize, Serialize};
4

            
5
use crate::common::*;
6

            
7
use crate::commands::*;
8
use crate::filter::Filter;
9

            
10
// TODO: SingleLineString
11

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

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

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

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

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

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

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

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

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

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

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

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

            
193
    // -- Reflection Commands -- //
194
    Config,
195
    Commands,
196
    NotCommands,
197
    UrlHandlers,
198
    Decoders,
199

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

            
208
// impl From<Request> for Vec<u8> {
209
//     fn from(val: Request) -> Self {
210
//         todo!()
211
//     }
212
// }
213

            
214
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
215
pub enum SaveMode {
216
    Create,
217
    Append,
218
    Replace,
219
}
220
impl FromStr for SaveMode {
221
    type Err = ();
222
    fn from_str(s: &str) -> Result<Self, Self::Err> {
223
        match s {
224
            "create" => Ok(Self::Create),
225
            "append" => Ok(Self::Append),
226
            "replace" => Ok(Self::Replace),
227
            _ => Err(()),
228
        }
229
    }
230
}
231

            
232
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
233
pub enum SeekMode {
234
    Relative,
235
    RelativeReverse,
236
    Absolute,
237
}
238

            
239
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
240
pub enum ReplayGainModeMode {
241
    Off,
242
    Track,
243
    Album,
244
    Auto,
245
}
246
impl FromStr for ReplayGainModeMode {
247
    type Err = ();
248
    fn from_str(s: &str) -> Result<Self, Self::Err> {
249
        match s {
250
            "off" => Ok(Self::Off),
251
            "track" => Ok(Self::Track),
252
            "album" => Ok(Self::Album),
253
            "auto" => Ok(Self::Auto),
254
            _ => Err(()),
255
        }
256
    }
257
}
258

            
259
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
260
pub struct VolumeValue(u32);
261
impl VolumeValue {
262
    pub fn new(volume: u32) -> Result<Self, ()> {
263
        match volume {
264
            0..=100 => Ok(Self(volume)),
265
            _ => Err(()),
266
        }
267
    }
268
}
269
impl From<VolumeValue> for u32 {
270
    fn from(val: VolumeValue) -> Self {
271
        val.0
272
    }
273
}
274
impl FromStr for VolumeValue {
275
    type Err = ();
276
    fn from_str(s: &str) -> Result<Self, Self::Err> {
277
        let volume = s.parse().map_err(|_| ())?;
278
        VolumeValue::new(volume)
279
    }
280
}
281

            
282
// TODO: fill out
283
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
284
pub enum GroupType {
285
    Artist,
286
    Album,
287
    AlbumArtist,
288
    Date,
289
    Genre,
290
    Track,
291
    Composer,
292
    Performer,
293
    Conductor,
294
    Comment,
295
    Disc,
296
    Filename,
297
    Any,
298
}
299

            
300
impl FromStr for GroupType {
301
    type Err = ();
302
    fn from_str(s: &str) -> Result<Self, Self::Err> {
303
        match s {
304
            "artist" => Ok(Self::Artist),
305
            "album" => Ok(Self::Album),
306
            "albumartist" => Ok(Self::AlbumArtist),
307
            "date" => Ok(Self::Date),
308
            "genre" => Ok(Self::Genre),
309
            "track" => Ok(Self::Track),
310
            "composer" => Ok(Self::Composer),
311
            "performer" => Ok(Self::Performer),
312
            "conductor" => Ok(Self::Conductor),
313
            "comment" => Ok(Self::Comment),
314
            "disc" => Ok(Self::Disc),
315
            "filename" => Ok(Self::Filename),
316
            "any" => Ok(Self::Any),
317
            _ => Err(()),
318
        }
319
    }
320
}
321

            
322
// trait RequestCommand {
323
//     // The command name used within the protocol
324
//     const COMMAND: &'static str;
325

            
326
//     // A function to parse the remaining parts of the command, split by whitespace
327
//     fn parse(parts: SplitWhitespace<'_>) -> RequestParserResponse<'_>;
328
// }
329

            
330
// type RequestParserResponse<'a> = Result<(Request, &'a str), RequestParserError>;
331

            
332
// pub enum RequestParserError {
333
//     SyntaxError(u64, String),
334
//     MissingCommandListEnd(u64),
335
//     NestedCommandList(u64),
336
//     UnexpectedCommandListEnd(u64),
337
//     UnexpectedEOF,
338
//     MissingNewline,
339
// }
340

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

            
346
impl Request {
347
    pub fn parse_next(raw: &str) -> RequestParserResult<'_> {
348
        let (line, rest) = raw
349
            .split_once('\n')
350
            .ok_or(RequestParserError::UnexpectedEOF)?;
351
        let mut parts = line.split_whitespace();
352

            
353
        match parts
354
            .next()
355
            .ok_or(RequestParserError::SyntaxError(0, line.to_string()))?
356
            .trim()
357
        {
358
            "command_list_begin" => {
359
                let mut commands = Vec::new();
360
                let mut i = 1;
361
                loop {
362
                    i += 1;
363
                    let (line, rest) = rest
364
                        .split_once('\n')
365
                        .ok_or(RequestParserError::MissingCommandListEnd(i))?;
366
                    match line.trim() {
367
                        "command_list_begin" => {
368
                            return Err(RequestParserError::NestedCommandList(i))
369
                        }
370
                        "command_list_end" => {
371
                            return Ok((Request::CommandList(commands), rest));
372
                        }
373
                        input => {
374
                            let (command, _) = Request::parse_next(input)?;
375
                            commands.push(command);
376
                        }
377
                    }
378
                }
379
            }
380
            "command_list_end" => Err(RequestParserError::UnexpectedCommandListEnd(0)),
381

            
382
            /* querying mpd status */
383
            ClearError::COMMAND => ClearError::parse_request(parts),
384
            CurrentSong::COMMAND => CurrentSong::parse_request(parts),
385
            Idle::COMMAND => Idle::parse_request(parts),
386
            Status::COMMAND => Status::parse_request(parts),
387
            Stats::COMMAND => Stats::parse_request(parts),
388

            
389
            /* playback options */
390
            Consume::COMMAND => Consume::parse_request(parts),
391
            Crossfade::COMMAND => Crossfade::parse_request(parts),
392
            MixRampDb::COMMAND => MixRampDb::parse_request(parts),
393
            MixRampDelay::COMMAND => MixRampDelay::parse_request(parts),
394
            Random::COMMAND => Random::parse_request(parts),
395
            Repeat::COMMAND => Repeat::parse_request(parts),
396
            SetVol::COMMAND => SetVol::parse_request(parts),
397
            GetVol::COMMAND => GetVol::parse_request(parts),
398
            Single::COMMAND => Single::parse_request(parts),
399
            ReplayGainMode::COMMAND => ReplayGainMode::parse_request(parts),
400
            ReplayGainStatus::COMMAND => ReplayGainStatus::parse_request(parts),
401
            Volume::COMMAND => Volume::parse_request(parts),
402

            
403
            /* playback control */
404
            Next::COMMAND => Next::parse_request(parts),
405
            Pause::COMMAND => Pause::parse_request(parts),
406
            Play::COMMAND => Play::parse_request(parts),
407
            PlayId::COMMAND => PlayId::parse_request(parts),
408
            Previous::COMMAND => Previous::parse_request(parts),
409
            Seek::COMMAND => Seek::parse_request(parts),
410
            SeekId::COMMAND => SeekId::parse_request(parts),
411
            SeekCur::COMMAND => SeekCur::parse_request(parts),
412
            Stop::COMMAND => Stop::parse_request(parts),
413

            
414
            /* queue */
415
            Add::COMMAND => Add::parse_request(parts),
416
            AddId::COMMAND => AddId::parse_request(parts),
417
            Clear::COMMAND => Clear::parse_request(parts),
418
            Delete::COMMAND => Delete::parse_request(parts),
419
            DeleteId::COMMAND => DeleteId::parse_request(parts),
420
            Move::COMMAND => Move::parse_request(parts),
421
            MoveId::COMMAND => MoveId::parse_request(parts),
422
            Playlist::COMMAND => Playlist::parse_request(parts),
423
            PlaylistFind::COMMAND => PlaylistFind::parse_request(parts),
424
            PlaylistId::COMMAND => PlaylistId::parse_request(parts),
425
            PlaylistInfo::COMMAND => PlaylistInfo::parse_request(parts),
426
            PlaylistSearch::COMMAND => PlaylistSearch::parse_request(parts),
427
            PlChanges::COMMAND => PlChanges::parse_request(parts),
428
            PlChangesPosId::COMMAND => PlChangesPosId::parse_request(parts),
429
            Prio::COMMAND => Prio::parse_request(parts),
430
            PrioId::COMMAND => PrioId::parse_request(parts),
431
            RangeId::COMMAND => RangeId::parse_request(parts),
432
            Shuffle::COMMAND => Shuffle::parse_request(parts),
433
            Swap::COMMAND => Swap::parse_request(parts),
434
            SwapId::COMMAND => SwapId::parse_request(parts),
435
            AddTagId::COMMAND => AddTagId::parse_request(parts),
436
            ClearTagId::COMMAND => ClearTagId::parse_request(parts),
437

            
438
            /* stored playlists */
439
            ListPlaylist::COMMAND => ListPlaylist::parse_request(parts),
440
            ListPlaylistInfo::COMMAND => ListPlaylistInfo::parse_request(parts),
441
            SearchPlaylist::COMMAND => SearchPlaylist::parse_request(parts),
442
            ListPlaylists::COMMAND => ListPlaylists::parse_request(parts),
443
            Load::COMMAND => Load::parse_request(parts),
444
            PlaylistAdd::COMMAND => PlaylistAdd::parse_request(parts),
445
            PlaylistClear::COMMAND => PlaylistClear::parse_request(parts),
446
            PlaylistDelete::COMMAND => PlaylistDelete::parse_request(parts),
447
            PlaylistLength::COMMAND => PlaylistLength::parse_request(parts),
448
            PlaylistMove::COMMAND => PlaylistMove::parse_request(parts),
449
            Rename::COMMAND => Rename::parse_request(parts),
450
            Rm::COMMAND => Rm::parse_request(parts),
451
            Save::COMMAND => Save::parse_request(parts),
452

            
453
            /* music database */
454
            AlbumArt::COMMAND => AlbumArt::parse_request(parts),
455
            Count::COMMAND => Count::parse_request(parts),
456
            GetFingerprint::COMMAND => GetFingerprint::parse_request(parts),
457
            Find::COMMAND => Find::parse_request(parts),
458
            FindAdd::COMMAND => FindAdd::parse_request(parts),
459
            List::COMMAND => List::parse_request(parts),
460
            ListAll::COMMAND => ListAll::parse_request(parts),
461
            ListAllInfo::COMMAND => ListAllInfo::parse_request(parts),
462
            ListFiles::COMMAND => ListFiles::parse_request(parts),
463
            LsInfo::COMMAND => LsInfo::parse_request(parts),
464
            ReadComments::COMMAND => ReadComments::parse_request(parts),
465
            ReadPicture::COMMAND => ReadPicture::parse_request(parts),
466
            Search::COMMAND => Search::parse_request(parts),
467
            SearchAdd::COMMAND => SearchAdd::parse_request(parts),
468
            SearchAddPl::COMMAND => SearchAddPl::parse_request(parts),
469
            SearchCount::COMMAND => SearchCount::parse_request(parts),
470
            Update::COMMAND => Update::parse_request(parts),
471
            Rescan::COMMAND => Rescan::parse_request(parts),
472

            
473
            /* mounts and neighbors */
474
            Mount::COMMAND => Mount::parse_request(parts),
475
            Unmount::COMMAND => Unmount::parse_request(parts),
476
            ListMounts::COMMAND => ListMounts::parse_request(parts),
477
            ListNeighbors::COMMAND => ListNeighbors::parse_request(parts),
478

            
479
            /* stickers */
480
            StickerGet::COMMAND => StickerGet::parse_request(parts),
481
            StickerSet::COMMAND => StickerSet::parse_request(parts),
482
            StickerInc::COMMAND => StickerInc::parse_request(parts),
483
            StickerDec::COMMAND => StickerDec::parse_request(parts),
484
            StickerDelete::COMMAND => StickerDelete::parse_request(parts),
485
            StickerList::COMMAND => StickerList::parse_request(parts),
486
            StickerFind::COMMAND => StickerFind::parse_request(parts),
487
            StickerNames::COMMAND => StickerNames::parse_request(parts),
488
            StickerTypes::COMMAND => StickerTypes::parse_request(parts),
489
            StickerNamesTypes::COMMAND => StickerNamesTypes::parse_request(parts),
490

            
491
            /* connection settings */
492
            Close::COMMAND => Close::parse_request(parts),
493
            Kill::COMMAND => Kill::parse_request(parts),
494
            Password::COMMAND => Password::parse_request(parts),
495
            Ping::COMMAND => Ping::parse_request(parts),
496
            BinaryLimit::COMMAND => BinaryLimit::parse_request(parts),
497
            TagTypes::COMMAND => TagTypes::parse_request(parts),
498
            TagTypesDisable::COMMAND => TagTypesDisable::parse_request(parts),
499
            TagTypesEnable::COMMAND => TagTypesEnable::parse_request(parts),
500
            TagTypesClear::COMMAND => TagTypesClear::parse_request(parts),
501
            TagTypesAll::COMMAND => TagTypesAll::parse_request(parts),
502
            TagTypesAvailable::COMMAND => TagTypesAvailable::parse_request(parts),
503
            TagTypesReset::COMMAND => TagTypesReset::parse_request(parts),
504
            Protocol::COMMAND => Protocol::parse_request(parts),
505
            ProtocolDisable::COMMAND => ProtocolDisable::parse_request(parts),
506
            ProtocolEnable::COMMAND => ProtocolEnable::parse_request(parts),
507
            ProtocolClear::COMMAND => ProtocolClear::parse_request(parts),
508
            ProtocolAll::COMMAND => ProtocolAll::parse_request(parts),
509
            ProtocolAvailable::COMMAND => ProtocolAvailable::parse_request(parts),
510

            
511
            /* partition commands */
512
            Partition::COMMAND => Partition::parse_request(parts),
513
            ListPartitions::COMMAND => ListPartitions::parse_request(parts),
514
            NewPartition::COMMAND => NewPartition::parse_request(parts),
515
            DelPartition::COMMAND => DelPartition::parse_request(parts),
516
            MoveOutput::COMMAND => MoveOutput::parse_request(parts),
517

            
518
            /* audio output devices */
519
            DisableOutput::COMMAND => DisableOutput::parse_request(parts),
520
            EnableOutput::COMMAND => EnableOutput::parse_request(parts),
521
            ToggleOutput::COMMAND => ToggleOutput::parse_request(parts),
522
            Outputs::COMMAND => Outputs::parse_request(parts),
523
            OutputSet::COMMAND => OutputSet::parse_request(parts),
524

            
525
            /* reflection */
526
            Config::COMMAND => Config::parse_request(parts),
527
            Commands::COMMAND => Commands::parse_request(parts),
528
            NotCommands::COMMAND => NotCommands::parse_request(parts),
529
            UrlHandlers::COMMAND => UrlHandlers::parse_request(parts),
530
            Decoders::COMMAND => Decoders::parse_request(parts),
531

            
532
            /* client to client */
533
            Subscribe::COMMAND => Subscribe::parse_request(parts),
534
            Unsubscribe::COMMAND => Unsubscribe::parse_request(parts),
535
            Channels::COMMAND => Channels::parse_request(parts),
536
            ReadMessages::COMMAND => ReadMessages::parse_request(parts),
537
            SendMessage::COMMAND => SendMessage::parse_request(parts),
538

            
539
            _ => unimplemented!(),
540
        }
541
    }
542
}