Skip to content

Commit 3e9a616

Browse files
committed
refactor(api): Simplify JSON tan handling
1 parent 046336c commit 3e9a616

File tree

4 files changed

+82
-111
lines changed

4 files changed

+82
-111
lines changed

src/api/json.rs

+40-64
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
component::ComponentName,
1010
global::{Global, InputMessage, InputMessageData, InputSourceHandle, Message},
1111
image::{RawImage, RawImageError},
12-
instance::{InstanceHandle, InstanceHandleError},
12+
instance::{InstanceHandle, InstanceHandleError, StartEffectError},
1313
};
1414

1515
/// Schema definitions as Serde serializable structures and enums
@@ -27,11 +27,13 @@ pub enum JsonApiError {
2727
#[error("error validating request: {0}")]
2828
Validation(#[from] validator::ValidationErrors),
2929
#[error("error receiving system response: {0}")]
30-
Recv(#[from] tokio::sync::oneshot::error::RecvError),
30+
Recv(#[from] oneshot::error::RecvError),
3131
#[error("error accessing the current instance: {0}")]
3232
Instance(#[from] InstanceHandleError),
3333
#[error("no current instance found")]
3434
InstanceNotFound,
35+
#[error(transparent)]
36+
StartEffect(#[from] StartEffectError),
3537
}
3638

3739
/// A client connected to the JSON endpoint
@@ -76,7 +78,7 @@ impl ClientConnection {
7678
&mut self,
7779
request: HyperionMessage,
7880
global: &Global,
79-
) -> Result<Option<HyperionResponse>, JsonApiError> {
81+
) -> Result<HyperionResponse, JsonApiError> {
8082
request.validate()?;
8183

8284
match request.command {
@@ -146,40 +148,23 @@ impl ClientConnection {
146148
}) => {
147149
// TODO: Handle origin, python_script, image_data
148150

149-
match self.current_instance(global).await {
150-
Ok(instance) => {
151-
let (tx, rx) = oneshot::channel();
152-
153-
instance
154-
.send(InputMessage::new(
155-
self.source.id(),
156-
ComponentName::All,
157-
InputMessageData::Effect {
158-
priority,
159-
duration: duration
160-
.map(|ms| chrono::Duration::milliseconds(ms as _)),
161-
effect: effect.into(),
162-
response: Arc::new(Mutex::new(Some(tx))),
163-
},
164-
))
165-
.await?;
166-
167-
return Ok(match rx.await {
168-
Ok(result) => match result {
169-
Ok(_) => None,
170-
Err(err) => Some(HyperionResponse::error(request.tan, err)),
171-
},
172-
Err(_) => Some(HyperionResponse::error(
173-
request.tan,
174-
"effect request dropped",
175-
)),
176-
});
177-
}
178-
179-
Err(err) => {
180-
return Ok(Some(HyperionResponse::error(request.tan, err)));
181-
}
182-
}
151+
let instance = self.current_instance(global).await?;
152+
let (tx, rx) = oneshot::channel();
153+
154+
instance
155+
.send(InputMessage::new(
156+
self.source.id(),
157+
ComponentName::All,
158+
InputMessageData::Effect {
159+
priority,
160+
duration: duration.map(|ms| chrono::Duration::milliseconds(ms as _)),
161+
effect: effect.into(),
162+
response: Arc::new(Mutex::new(Some(tx))),
163+
},
164+
))
165+
.await?;
166+
167+
return Ok(rx.await?.map(|_| HyperionResponse::success())?);
183168
}
184169

185170
HyperionCommand::ServerInfo(message::ServerInfoRequest { subscribe: _ }) => {
@@ -209,46 +194,37 @@ impl ClientConnection {
209194
.await;
210195

211196
// Just answer the serverinfo request, no need to update state
212-
return Ok(Some(
213-
global
214-
.read_config(|config| {
215-
let instances = config
216-
.instances
217-
.iter()
218-
.map(|instance_config| (&instance_config.1.instance).into())
219-
.collect();
220-
221-
HyperionResponse::server_info(
222-
request.tan,
223-
priorities,
224-
adjustments,
225-
effects,
226-
instances,
227-
)
228-
})
229-
.await,
230-
));
197+
return Ok(global
198+
.read_config(|config| {
199+
let instances = config
200+
.instances
201+
.iter()
202+
.map(|instance_config| (&instance_config.1.instance).into())
203+
.collect();
204+
205+
HyperionResponse::server_info(priorities, adjustments, effects, instances)
206+
})
207+
.await);
231208
}
232209

233210
HyperionCommand::Authorize(message::Authorize { subcommand, .. }) => match subcommand {
234211
message::AuthorizeCommand::AdminRequired => {
235212
// TODO: Perform actual authentication flow
236-
return Ok(Some(HyperionResponse::admin_required(request.tan, false)));
213+
return Ok(HyperionResponse::admin_required(false));
237214
}
238215
message::AuthorizeCommand::TokenRequired => {
239216
// TODO: Perform actual authentication flow
240-
return Ok(Some(HyperionResponse::token_required(request.tan, false)));
217+
return Ok(HyperionResponse::token_required(false));
241218
}
242219
_ => {
243220
return Err(JsonApiError::NotImplemented);
244221
}
245222
},
246223

247224
HyperionCommand::SysInfo => {
248-
return Ok(Some(HyperionResponse::sys_info(
249-
request.tan,
225+
return Ok(HyperionResponse::sys_info(
250226
global.read_config(|config| config.uuid()).await,
251-
)));
227+
));
252228
}
253229

254230
HyperionCommand::Instance(message::Instance {
@@ -258,18 +234,18 @@ impl ClientConnection {
258234
}) => {
259235
if global.get_instance(id).await.is_some() {
260236
self.set_current_instance(id);
261-
return Ok(Some(HyperionResponse::switch_to(request.tan, Some(id))));
237+
return Ok(HyperionResponse::switch_to(Some(id)));
262238
} else {
263239
// Note: it's an "Ok" but should be an Err. Find out how to represent errors
264240
// better
265-
return Ok(Some(HyperionResponse::switch_to(request.tan, None)));
241+
return Ok(HyperionResponse::switch_to(None));
266242
}
267243
}
268244

269245
_ => return Err(JsonApiError::NotImplemented),
270246
};
271247

272-
Ok(None)
248+
Ok(HyperionResponse::success())
273249
}
274250
}
275251

src/api/json/message.rs

+34-38
Original file line numberDiff line numberDiff line change
@@ -703,95 +703,91 @@ pub enum HyperionResponseInfo {
703703
}
704704

705705
impl HyperionResponse {
706-
fn success_info(tan: Option<i32>, info: HyperionResponseInfo) -> Self {
706+
pub fn with_tan(mut self, tan: Option<i32>) -> Self {
707+
self.tan = tan;
708+
self
709+
}
710+
711+
fn success_info(info: HyperionResponseInfo) -> Self {
707712
Self {
708713
success: true,
709-
tan,
714+
tan: None,
710715
error: None,
711716
info: Some(info),
712717
}
713718
}
714719

715720
/// Return a success response
716-
pub fn success(tan: Option<i32>) -> Self {
721+
pub fn success() -> Self {
717722
Self {
718723
success: true,
719-
tan,
724+
tan: None,
720725
error: None,
721726
info: None,
722727
}
723728
}
724729

725730
/// Return an error response
726-
pub fn error(tan: Option<i32>, error: impl std::fmt::Display) -> Self {
731+
pub fn error(error: impl std::fmt::Display) -> Self {
727732
Self {
728733
success: false,
729-
tan,
734+
tan: None,
730735
error: Some(error.to_string()),
731736
info: None,
732737
}
733738
}
734739

735740
/// Return an error response
736-
pub fn error_info(
737-
tan: Option<i32>,
738-
error: impl std::fmt::Display,
739-
info: HyperionResponseInfo,
740-
) -> Self {
741+
pub fn error_info(error: impl std::fmt::Display, info: HyperionResponseInfo) -> Self {
741742
Self {
742743
success: false,
743-
tan,
744+
tan: None,
744745
error: Some(error.to_string()),
745746
info: Some(info),
746747
}
747748
}
748749

749750
/// Return a server information response
750751
pub fn server_info(
751-
tan: Option<i32>,
752752
priorities: Vec<PriorityInfo>,
753753
adjustment: Vec<ChannelAdjustment>,
754754
effects: Vec<EffectDefinition>,
755755
instances: Vec<InstanceInfo>,
756756
) -> Self {
757-
Self::success_info(
758-
tan,
759-
HyperionResponseInfo::ServerInfo(ServerInfo {
760-
priorities,
761-
// TODO: Actual autoselect value
762-
priorities_autoselect: true,
763-
adjustment,
764-
effects,
765-
led_devices: LedDevicesInfo::new(),
766-
grabbers: GrabbersInfo::new(),
767-
// TODO: Actual video mode
768-
video_mode: VideoMode::Mode2D,
769-
instances,
770-
hostname: hostname(),
771-
}),
772-
)
757+
Self::success_info(HyperionResponseInfo::ServerInfo(ServerInfo {
758+
priorities,
759+
// TODO: Actual autoselect value
760+
priorities_autoselect: true,
761+
adjustment,
762+
effects,
763+
led_devices: LedDevicesInfo::new(),
764+
grabbers: GrabbersInfo::new(),
765+
// TODO: Actual video mode
766+
video_mode: VideoMode::Mode2D,
767+
instances,
768+
hostname: hostname(),
769+
}))
773770
}
774771

775-
pub fn admin_required(tan: Option<i32>, admin_required: bool) -> Self {
776-
Self::success_info(tan, HyperionResponseInfo::AdminRequired { admin_required })
772+
pub fn admin_required(admin_required: bool) -> Self {
773+
Self::success_info(HyperionResponseInfo::AdminRequired { admin_required })
777774
}
778775

779-
pub fn token_required(tan: Option<i32>, required: bool) -> Self {
780-
Self::success_info(tan, HyperionResponseInfo::TokenRequired { required })
776+
pub fn token_required(required: bool) -> Self {
777+
Self::success_info(HyperionResponseInfo::TokenRequired { required })
781778
}
782779

783-
pub fn sys_info(tan: Option<i32>, id: uuid::Uuid) -> Self {
780+
pub fn sys_info(id: uuid::Uuid) -> Self {
784781
// TODO: Properly fill out this response
785-
Self::success_info(tan, HyperionResponseInfo::SysInfo(SysInfo::new(id)))
782+
Self::success_info(HyperionResponseInfo::SysInfo(SysInfo::new(id)))
786783
}
787784

788-
pub fn switch_to(tan: Option<i32>, id: Option<i32>) -> Self {
785+
pub fn switch_to(id: Option<i32>) -> Self {
789786
if let Some(id) = id {
790787
// Switch successful
791-
Self::success_info(tan, HyperionResponseInfo::SwitchTo { instance: Some(id) })
788+
Self::success_info(HyperionResponseInfo::SwitchTo { instance: Some(id) })
792789
} else {
793790
Self::error_info(
794-
tan,
795791
"selected hyperion instance not found",
796792
HyperionResponseInfo::SwitchTo { instance: None },
797793
)

src/servers/json.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ pub async fn handle_client(
5757
Err(error) => Err(JsonServerError::from(error)),
5858
}
5959
} {
60-
Ok(None) => json::message::HyperionResponse::success(tan),
61-
Ok(Some(response)) => response,
60+
Ok(response) => response,
6261
Err(error) => {
6362
error!(error = %error, "error processing request");
6463

65-
json::message::HyperionResponse::error(tan, &error)
64+
json::message::HyperionResponse::error(&error)
6665
}
67-
};
66+
}
67+
.with_tan(tan);
6868

6969
trace!(response = ?reply, "sending response");
7070

src/web/session.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -116,21 +116,20 @@ impl Session {
116116
let api = match self.json_api(global).await {
117117
Ok(api) => api,
118118
Err(error) => {
119-
return HyperionResponse::error(tan, &error);
119+
return HyperionResponse::error(&error).with_tan(tan);
120120
}
121121
};
122122

123123
let response = match api.handle_request(request, global).await {
124-
Ok(None) => HyperionResponse::success(tan),
125-
Ok(Some(response)) => response,
124+
Ok(response) => response,
126125
Err(error) => {
127126
error!(error = %error, "error processing request");
128-
HyperionResponse::error(tan, &error)
127+
HyperionResponse::error(&error)
129128
}
130129
};
131130

132131
trace!(response = ?response, "ws response");
133-
response
132+
response.with_tan(tan)
134133
}
135134
}
136135

0 commit comments

Comments
 (0)