about summary refs log tree commit diff stats
path: root/pkgs/by-name/mp/mpdpopm/src/messanges/mod.rs
blob: c5320dd9288a570013f6a7b2d36847a9aec923bb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use anyhow::{Context, Result, anyhow, bail, ensure};
use clap::{Parser, Subcommand};
use shlex::Shlex;
use tracing::info;

use crate::{
    clients::{Client, IdleClient},
    dj::{Dj, algorithms::Discovery},
};

pub const COMMAND_CHANNEL: &str = "unwoundstack.com:commands";

#[derive(Parser)]
struct Commands {
    #[command(subcommand)]
    command: SubCommand,
}

#[derive(Parser)]
enum SubCommand {
    Dj {
        #[command(subcommand)]
        command: DjCommand,
    },
}

#[derive(Subcommand)]
enum DjCommand {
    Start {},
    Stop {},
}

pub(crate) struct MessageQueue {
    dj: Option<Dj<Discovery>>,
}

impl MessageQueue {
    pub(crate) fn new() -> Self {
        Self { dj: None }
    }

    pub(crate) async fn advance_dj(&mut self, client: &mut Client) -> Result<()> {
        if let Some(dj) = self.dj.as_mut() {
            dj.add_track(client).await?;
        }

        Ok(())
    }

    /// Read messages off the commands channel & dispatch 'em
    pub(crate) async fn check_messages(
        &mut self,
        client: &mut Client,
        idle_client: &mut IdleClient,
    ) -> Result<()> {
        let m = idle_client
            .get_messages()
            .await
            .context("Failed to `get_messages` from client")?;

        for (chan, msgs) in m {
            ensure!(chan == COMMAND_CHANNEL, "Unknown channel: `{}`", chan);

            for msg in msgs {
                self.process(client, msg).await?;
            }
        }

        Ok(())
    }

    /// Process a single command
    pub(crate) async fn process(&mut self, client: &mut Client, msg: String) -> Result<()> {
        let split = {
            let mut shl = Shlex::new(&msg);
            let res: Vec<_> = shl.by_ref().collect();

            if shl.had_error {
                bail!("Failed to parse command '{msg}'")
            }

            assert_eq!(shl.line_no, 1, "A unexpected newline appeared");
            assert!(!res.is_empty());

            let mut base = vec!["base".to_owned()];
            base.extend(res);
            base
        };

        let args = Commands::parse_from(split);

        match args.command {
            SubCommand::Dj { command } => match command {
                DjCommand::Start {} => {
                    info!("Dj started");
                    self.dj = Some(Dj::new(Discovery::new()));
                    self.advance_dj(client).await?;
                }
                DjCommand::Stop {} => {
                    self.dj
                        .take()
                        .ok_or_else(|| anyhow!("Tried to disable already disabled dj mode"))?;
                    info!("Dj stopped");
                }
            },
        }

        Ok(())
    }
}