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(())
}
}
|