use axum::{
extract::{Path, State},
http::StatusCode,
Json,
};
use std::sync::Arc;
use vibelang_core::{GroupId, GroupMessage};
use crate::{
models::{ErrorResponse, Group, GroupUpdate, ParamSet},
AppState,
};
async fn resolve_group_id(
state: &Arc<AppState>,
identifier: &str,
) -> Result<GroupId, (StatusCode, Json<ErrorResponse>)> {
if let Ok(num_id) = identifier.parse::<u32>() {
let group_id = GroupId::new(num_id);
let exists = state.with_state(|s| s.groups.contains_key(&group_id)).await;
if exists {
return Ok(group_id);
}
}
let found = state
.with_state(|s| {
s.groups
.iter()
.find(|(_, gs)| gs.name == identifier)
.map(|(id, _)| *id)
})
.await;
match found {
Some(id) => Ok(id),
None => Err((
StatusCode::NOT_FOUND,
Json(ErrorResponse::not_found(&format!(
"Group '{}' not found",
identifier
))),
)),
}
}
fn group_to_api(
_id: &GroupId,
state: &vibelang_core::GroupState,
all_groups: &std::collections::HashMap<GroupId, vibelang_core::GroupState>,
) -> Group {
let name = state.name.clone();
let path = name.clone();
let children: Vec<String> = all_groups
.iter()
.filter(|(_, gs)| gs.parent.as_ref() == Some(&state.id))
.map(|(_, child_state)| child_state.name.clone())
.collect();
let parent_path = state
.parent
.as_ref()
.and_then(|parent_id| all_groups.get(parent_id).map(|gs| gs.name.clone()));
Group {
name,
path,
parent_path,
children,
node_id: state.node_id.raw() as i32,
audio_bus: state.audio_bus.raw() as i32,
link_synth_node_id: state.link_synth_node_id.map(|n| n.raw() as i32),
muted: state.muted,
soloed: state.soloed,
params: state.params.iter().map(|(k, v)| (k.clone(), *v)).collect(),
synth_node_ids: None, source_location: None, }
}
pub async fn list_groups(State(state): State<Arc<AppState>>) -> Json<Vec<Group>> {
let groups = state
.with_state(|s| {
s.groups
.iter()
.map(|(id, gs)| group_to_api(id, gs, &s.groups))
.collect::<Vec<_>>()
})
.await;
Json(groups)
}
pub async fn get_group(
State(state): State<Arc<AppState>>,
Path(id): Path<String>,
) -> Result<Json<Group>, (StatusCode, Json<ErrorResponse>)> {
let group_id = resolve_group_id(&state, &id).await?;
let group = state
.with_state(|s| {
s.groups
.get(&group_id)
.map(|gs| group_to_api(&group_id, gs, &s.groups))
})
.await;
match group {
Some(g) => Ok(Json(g)),
None => Err((
StatusCode::NOT_FOUND,
Json(ErrorResponse::not_found(&format!(
"Group '{}' not found",
id
))),
)),
}
}
pub async fn update_group(
State(state): State<Arc<AppState>>,
Path(id): Path<String>,
Json(update): Json<GroupUpdate>,
) -> Result<Json<Group>, (StatusCode, Json<ErrorResponse>)> {
let group_id = resolve_group_id(&state, &id).await?;
for (param_name, value) in update.params {
if let Err(e) = state
.send(
GroupMessage::SetParam {
id: group_id,
param: param_name,
value,
}
.into(),
)
.await
{
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
Json(ErrorResponse::internal(&format!(
"Failed to update param: {}",
e
))),
));
}
}
get_group(State(state), Path(id)).await
}
pub async fn mute_group(
State(state): State<Arc<AppState>>,
Path(id): Path<String>,
) -> Result<StatusCode, (StatusCode, Json<ErrorResponse>)> {
let group_id = resolve_group_id(&state, &id).await?;
if let Err(e) = state
.send(
GroupMessage::Mute {
id: group_id,
muted: true,
}
.into(),
)
.await
{
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
Json(ErrorResponse::internal(&format!(
"Failed to mute group: {}",
e
))),
));
}
Ok(StatusCode::OK)
}
pub async fn unmute_group(
State(state): State<Arc<AppState>>,
Path(id): Path<String>,
) -> Result<StatusCode, (StatusCode, Json<ErrorResponse>)> {
let group_id = resolve_group_id(&state, &id).await?;
if let Err(e) = state
.send(
GroupMessage::Mute {
id: group_id,
muted: false,
}
.into(),
)
.await
{
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
Json(ErrorResponse::internal(&format!(
"Failed to unmute group: {}",
e
))),
));
}
Ok(StatusCode::OK)
}
pub async fn solo_group(
State(state): State<Arc<AppState>>,
Path(id): Path<String>,
) -> Result<StatusCode, (StatusCode, Json<ErrorResponse>)> {
let group_id = resolve_group_id(&state, &id).await?;
if let Err(e) = state
.send(
GroupMessage::Solo {
id: group_id,
solo: true,
}
.into(),
)
.await
{
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
Json(ErrorResponse::internal(&format!(
"Failed to solo group: {}",
e
))),
));
}
Ok(StatusCode::OK)
}
pub async fn unsolo_group(
State(state): State<Arc<AppState>>,
Path(id): Path<String>,
) -> Result<StatusCode, (StatusCode, Json<ErrorResponse>)> {
let group_id = resolve_group_id(&state, &id).await?;
if let Err(e) = state
.send(
GroupMessage::Solo {
id: group_id,
solo: false,
}
.into(),
)
.await
{
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
Json(ErrorResponse::internal(&format!(
"Failed to unsolo group: {}",
e
))),
));
}
Ok(StatusCode::OK)
}
pub async fn set_group_param(
State(state): State<Arc<AppState>>,
Path((id, param)): Path<(String, String)>,
Json(req): Json<ParamSet>,
) -> Result<StatusCode, (StatusCode, Json<ErrorResponse>)> {
let group_id = resolve_group_id(&state, &id).await?;
if let Err(e) = state
.send(
GroupMessage::SetParam {
id: group_id,
param,
value: req.value,
}
.into(),
)
.await
{
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
Json(ErrorResponse::internal(&format!(
"Failed to set param: {}",
e
))),
));
}
Ok(StatusCode::OK)
}