agentmux_srv/server/service/
workspace_lifecycle.rs1use crate::backend::service::{self, WebCallType, WebReturnType};
9use crate::backend::wcore;
10
11use super::super::AppState;
12use super::reducer_helpers::{
13 compensate_via_reducer, dispatch_to_reducer, publish_events, mstore_workspace_exists,
14};
15
16pub(crate) async fn handle_create_workspace(state: &AppState, call: &WebCallType) -> WebReturnType {
17 let store = &state.mstore;
18 let args = &call.args;
19 let name: String = service::get_arg(args, 0).unwrap_or_default();
20 let events = dispatch_to_reducer(
21 state,
22 agentmux_common::ipc::Command::CreateWorkspace { name: name.clone() },
23 )
24 .await;
25 let workspace_id = events.iter().find_map(|e| match e {
26 agentmux_common::ipc::Event::WorkspaceCreated { workspace_id, .. } => {
27 Some(workspace_id.clone())
28 }
29 _ => None,
30 });
31 let mut apply_err: Option<String> = None;
37 for ev in &events {
38 if let Err(e) = crate::persist_subscriber::apply_event_to_mstore(ev, store) {
39 apply_err = Some(e.to_string());
40 break;
41 }
42 }
43 if let Some(err) = apply_err {
44 if let Some(id) = workspace_id.as_ref() {
45 compensate_via_reducer(
46 state,
47 agentmux_common::ipc::Command::DeleteWorkspace {
48 workspace_id: id.clone(),
49 force: false,
53 },
54 store,
55 )
56 .await;
57 }
58 return WebReturnType::error(format!(
59 "CreateWorkspace: SQLite write failed: {}",
60 err
61 ));
62 }
63 publish_events(state, &events);
64 match workspace_id {
65 Some(id) => match wcore::get_workspace(store, &id) {
66 Ok(ws) => {
67 WebReturnType::success(serde_json::to_value(&ws).unwrap_or_default())
68 }
69 Err(e) => WebReturnType::error(format!(
70 "CreateWorkspace: post-write read failed: {}",
71 e
72 )),
73 },
74 None => WebReturnType::error(
75 "CreateWorkspace: reducer did not emit WorkspaceCreated".to_string(),
76 ),
77 }
78}
79
80pub(crate) async fn handle_get_workspace(state: &AppState, call: &WebCallType) -> WebReturnType {
81 let store = &state.mstore;
82 let args = &call.args;
83 let ws_id: String = match service::get_arg(args, 0) {
84 Ok(v) => v,
85 Err(e) => return WebReturnType::error(e),
86 };
87 match wcore::get_workspace(store, &ws_id) {
92 Ok(ws) => WebReturnType::success(serde_json::to_value(&ws).unwrap_or_default()),
93 Err(e) => WebReturnType::error(e.to_string()),
94 }
95}
96
97pub(crate) async fn handle_delete_workspace(state: &AppState, call: &WebCallType) -> WebReturnType {
98 let store = &state.mstore;
99 let args = &call.args;
100 let ws_id: String = match service::get_arg(args, 0) {
101 Ok(v) => v,
102 Err(e) => return WebReturnType::error(e),
103 };
104 let exists_in_mstore = match mstore_workspace_exists(store, &ws_id) {
128 Ok(v) => v,
129 Err(e) => {
130 return WebReturnType::error(format!(
131 "DeleteWorkspace: SQLite read failed: {}",
132 e
133 ))
134 }
135 };
136 if !exists_in_mstore {
137 let exists_in_state = state
138 .srv_state
139 .lock()
140 .await
141 .workspaces
142 .contains_key(&ws_id);
143 if !exists_in_state {
144 return WebReturnType::error(format!(
145 "DeleteWorkspace: workspace not found: {}",
146 ws_id
147 ));
148 }
149 }
150 match crate::sagas::delete_workspace::run(state, ws_id.clone()).await {
151 Ok(_) => WebReturnType::success_empty(),
152 Err(e) => WebReturnType::error(format!("DeleteWorkspace failed: {}", e)),
153 }
154}
155
156pub(crate) async fn handle_update_workspace(state: &AppState, call: &WebCallType) -> WebReturnType {
161 let store = &state.mstore;
162 let args = &call.args;
163 let ws_id: String = match service::get_arg(args, 0) {
164 Ok(v) => v,
165 Err(e) => return WebReturnType::error(e),
166 };
167 let name: Option<String> = service::get_optional_arg(args, 1).unwrap_or(None);
168 let Some(name) = name else {
169 return WebReturnType::success_empty();
170 };
171 let events = dispatch_to_reducer(
172 state,
173 agentmux_common::ipc::Command::RenameWorkspace {
174 workspace_id: ws_id.clone(),
175 name,
176 },
177 )
178 .await;
179 if let Some(err_msg) = events.iter().find_map(|e| match e {
180 agentmux_common::ipc::Event::Error { message, .. } => Some(message.clone()),
181 _ => None,
182 }) {
183 return WebReturnType::error(err_msg);
184 }
185 for ev in &events {
186 if let Err(e) = crate::persist_subscriber::apply_event_to_mstore(ev, store) {
187 return WebReturnType::error(format!(
188 "UpdateWorkspace: SQLite write failed: {}",
189 e
190 ));
191 }
192 }
193 publish_events(state, &events);
194 WebReturnType::success_empty()
195}