Skip to content

Commit 9e81db9

Browse files
committed
refactor(api): Introduce api::json::ClientConnection
1 parent 85ac12e commit 9e81db9

File tree

2 files changed

+120
-107
lines changed

2 files changed

+120
-107
lines changed

src/api/json.rs

+113-102
Original file line numberDiff line numberDiff line change
@@ -27,114 +27,125 @@ pub enum JsonApiError {
2727
Recv(#[from] tokio::sync::oneshot::error::RecvError),
2828
}
2929

30-
pub async fn handle_request(
31-
request: HyperionMessage,
32-
source: &InputSourceHandle<InputMessage>,
33-
global: &Global,
34-
) -> Result<Option<HyperionResponse>, JsonApiError> {
35-
request.validate()?;
36-
37-
match request.command {
38-
HyperionCommand::ClearAll => {
39-
// Update state
40-
source.send(InputMessageData::ClearAll)?;
41-
}
42-
43-
HyperionCommand::Clear(message::Clear { priority }) => {
44-
// Update state
45-
source.send(InputMessageData::Clear { priority })?;
46-
}
47-
48-
HyperionCommand::Color(message::Color {
49-
priority,
50-
duration,
51-
color,
52-
origin: _,
53-
}) => {
54-
// TODO: Handle origin field
55-
56-
// Update state
57-
source.send(InputMessageData::SolidColor {
30+
/// A client connected to the JSON endpoint
31+
pub struct ClientConnection {
32+
source: InputSourceHandle<InputMessage>,
33+
}
34+
35+
impl ClientConnection {
36+
pub fn new(source: InputSourceHandle<InputMessage>) -> Self {
37+
Self { source }
38+
}
39+
40+
pub async fn handle_request(
41+
&self,
42+
request: HyperionMessage,
43+
global: &Global,
44+
) -> Result<Option<HyperionResponse>, JsonApiError> {
45+
request.validate()?;
46+
47+
match request.command {
48+
HyperionCommand::ClearAll => {
49+
// Update state
50+
self.source.send(InputMessageData::ClearAll)?;
51+
}
52+
53+
HyperionCommand::Clear(message::Clear { priority }) => {
54+
// Update state
55+
self.source.send(InputMessageData::Clear { priority })?;
56+
}
57+
58+
HyperionCommand::Color(message::Color {
5859
priority,
59-
duration: duration.map(|ms| chrono::Duration::milliseconds(ms as _)),
60+
duration,
6061
color,
61-
})?;
62-
}
63-
64-
HyperionCommand::Image(message::Image {
65-
priority,
66-
duration,
67-
imagewidth,
68-
imageheight,
69-
imagedata,
70-
origin: _,
71-
format: _,
72-
scale: _,
73-
name: _,
74-
}) => {
75-
// TODO: Handle origin, format, scale, name fields
76-
77-
let raw_image = RawImage::try_from((imagedata, imagewidth, imageheight))?;
78-
79-
source.send(InputMessageData::Image {
62+
origin: _,
63+
}) => {
64+
// TODO: Handle origin field
65+
66+
// Update state
67+
self.source.send(InputMessageData::SolidColor {
68+
priority,
69+
duration: duration.map(|ms| chrono::Duration::milliseconds(ms as _)),
70+
color,
71+
})?;
72+
}
73+
74+
HyperionCommand::Image(message::Image {
8075
priority,
81-
duration: duration.map(|ms| chrono::Duration::milliseconds(ms as _)),
82-
image: Arc::new(raw_image),
83-
})?;
84-
}
85-
86-
HyperionCommand::ServerInfo(message::ServerInfoRequest { subscribe: _ }) => {
87-
// TODO: Handle subscribe field
88-
89-
// Request priority information
90-
let (sender, receiver) = tokio::sync::oneshot::channel();
91-
source.send(InputMessageData::PrioritiesRequest {
92-
response: Arc::new(std::sync::Mutex::new(Some(sender))),
93-
})?;
94-
95-
// Receive priority information
96-
let priorities = receiver
97-
.await?
98-
.into_iter()
99-
.map(message::PriorityInfo::from)
100-
.collect();
101-
102-
// Just answer the serverinfo request, no need to update state
103-
return Ok(Some(HyperionResponse::server_info(
104-
request.tan,
105-
vec![],
106-
priorities,
107-
global
108-
.read_config(|config| {
109-
config
110-
.instances
111-
.iter()
112-
.map(|instance_config| (&instance_config.1.instance).into())
113-
.collect()
114-
})
115-
.await,
116-
)));
117-
}
118-
119-
HyperionCommand::Authorize(message::Authorize { subcommand, .. }) => match subcommand {
120-
message::AuthorizeCommand::TokenRequired => {
121-
// TODO: Perform actual authentication flow
122-
return Ok(Some(HyperionResponse::token_required(request.tan, false)));
76+
duration,
77+
imagewidth,
78+
imageheight,
79+
imagedata,
80+
origin: _,
81+
format: _,
82+
scale: _,
83+
name: _,
84+
}) => {
85+
// TODO: Handle origin, format, scale, name fields
86+
87+
let raw_image = RawImage::try_from((imagedata, imagewidth, imageheight))?;
88+
89+
self.source.send(InputMessageData::Image {
90+
priority,
91+
duration: duration.map(|ms| chrono::Duration::milliseconds(ms as _)),
92+
image: Arc::new(raw_image),
93+
})?;
12394
}
124-
_ => {
125-
return Err(JsonApiError::NotImplemented);
95+
96+
HyperionCommand::ServerInfo(message::ServerInfoRequest { subscribe: _ }) => {
97+
// TODO: Handle subscribe field
98+
99+
// Request priority information
100+
let (sender, receiver) = tokio::sync::oneshot::channel();
101+
self.source.send(InputMessageData::PrioritiesRequest {
102+
response: Arc::new(std::sync::Mutex::new(Some(sender))),
103+
})?;
104+
105+
// Receive priority information
106+
let priorities = receiver
107+
.await?
108+
.into_iter()
109+
.map(message::PriorityInfo::from)
110+
.collect();
111+
112+
// Just answer the serverinfo request, no need to update state
113+
return Ok(Some(HyperionResponse::server_info(
114+
request.tan,
115+
vec![],
116+
priorities,
117+
global
118+
.read_config(|config| {
119+
config
120+
.instances
121+
.iter()
122+
.map(|instance_config| (&instance_config.1.instance).into())
123+
.collect()
124+
})
125+
.await,
126+
)));
126127
}
127-
},
128128

129-
HyperionCommand::SysInfo => {
130-
return Ok(Some(HyperionResponse::sys_info(
131-
request.tan,
132-
global.read_config(|config| config.uuid()).await,
133-
)));
134-
}
129+
HyperionCommand::Authorize(message::Authorize { subcommand, .. }) => match subcommand {
130+
message::AuthorizeCommand::TokenRequired => {
131+
// TODO: Perform actual authentication flow
132+
return Ok(Some(HyperionResponse::token_required(request.tan, false)));
133+
}
134+
_ => {
135+
return Err(JsonApiError::NotImplemented);
136+
}
137+
},
138+
139+
HyperionCommand::SysInfo => {
140+
return Ok(Some(HyperionResponse::sys_info(
141+
request.tan,
142+
global.read_config(|config| config.uuid()).await,
143+
)));
144+
}
135145

136-
_ => return Err(JsonApiError::NotImplemented),
137-
};
146+
_ => return Err(JsonApiError::NotImplemented),
147+
};
138148

139-
Ok(None)
149+
Ok(None)
150+
}
140151
}

src/servers/json.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ pub async fn handle_client(
3636
let (mut writer, mut reader) = framed.split();
3737

3838
// unwrap: cannot fail because the priority is None
39-
let source = global
40-
.register_input_source(InputSourceName::Json { peer_addr }, None)
41-
.await
42-
.unwrap();
39+
let client_connection = json::ClientConnection::new(
40+
global
41+
.register_input_source(InputSourceName::Json { peer_addr }, None)
42+
.await
43+
.unwrap(),
44+
);
4345

4446
while let Some(request) = reader.next().await {
4547
trace!("({}) processing request: {:?}", peer_addr, request);
@@ -49,7 +51,7 @@ pub async fn handle_client(
4951
match request {
5052
Ok(rq) => {
5153
tan = rq.tan;
52-
Ok(json::handle_request(rq, &source, &global).await?)
54+
Ok(client_connection.handle_request(rq, &global).await?)
5355
}
5456
Err(error) => Err(JsonServerError::from(error)),
5557
}

0 commit comments

Comments
 (0)