use std::collections::HashMap;
use std::sync::Arc;
use anyhow::Result;
use indexmap::IndexMap;
use kcmc::ok_response::OkModelingCmdResponse;
use kcmc::websocket::BatchResponse;
use kcmc::websocket::ModelingBatch;
use kcmc::websocket::OkWebSocketResponseData;
use kcmc::websocket::SuccessWebSocketResponse;
use kcmc::websocket::WebSocketRequest;
use kcmc::websocket::WebSocketResponse;
use kittycad_modeling_cmds::ImportFiles;
use kittycad_modeling_cmds::ModelingCmd;
use kittycad_modeling_cmds::websocket::ModelingCmdReq;
use kittycad_modeling_cmds::{self as kcmc};
use tokio::sync::RwLock;
use uuid::Uuid;
use crate::SourceRange;
use crate::engine::AsyncTasks;
use crate::engine::EngineStats;
use crate::errors::KclError;
use crate::exec::DefaultPlanes;
use crate::execution::IdGenerator;
#[derive(Debug, Clone)]
pub struct EngineConnection {
batch: Arc<RwLock<Vec<(WebSocketRequest, SourceRange)>>>,
batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
ids_of_async_commands: Arc<RwLock<IndexMap<Uuid, SourceRange>>>,
responses: Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>>,
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
stats: EngineStats,
async_tasks: AsyncTasks,
}
impl EngineConnection {
pub fn new() -> Result<EngineConnection> {
Ok(EngineConnection {
batch: Arc::new(RwLock::new(Vec::new())),
batch_end: Arc::new(RwLock::new(IndexMap::new())),
ids_of_async_commands: Arc::new(RwLock::new(IndexMap::new())),
responses: Arc::new(RwLock::new(IndexMap::new())),
default_planes: Default::default(),
stats: Default::default(),
async_tasks: AsyncTasks::new(),
})
}
}
#[async_trait::async_trait]
impl crate::engine::EngineManager for EngineConnection {
fn batch(&self) -> Arc<RwLock<Vec<(WebSocketRequest, SourceRange)>>> {
self.batch.clone()
}
fn batch_end(&self) -> Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>> {
self.batch_end.clone()
}
fn responses(&self) -> Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>> {
self.responses.clone()
}
fn stats(&self) -> &EngineStats {
&self.stats
}
fn ids_of_async_commands(&self) -> Arc<RwLock<IndexMap<Uuid, SourceRange>>> {
self.ids_of_async_commands.clone()
}
fn async_tasks(&self) -> AsyncTasks {
self.async_tasks.clone()
}
fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
self.default_planes.clone()
}
async fn clear_scene_post_hook(
&self,
_id_generator: &mut IdGenerator,
_source_range: SourceRange,
) -> Result<(), KclError> {
Ok(())
}
async fn get_debug(&self) -> Option<OkWebSocketResponseData> {
None
}
async fn fetch_debug(&self) -> Result<(), KclError> {
unimplemented!();
}
async fn inner_fire_modeling_cmd(
&self,
id: uuid::Uuid,
source_range: SourceRange,
cmd: WebSocketRequest,
id_to_source_range: HashMap<Uuid, SourceRange>,
) -> Result<(), KclError> {
self.ids_of_async_commands.write().await.swap_remove(&id);
let response = self
.inner_send_modeling_cmd(id, source_range, cmd, id_to_source_range)
.await?;
self.responses().write().await.insert(id, response);
Ok(())
}
async fn inner_send_modeling_cmd(
&self,
id: uuid::Uuid,
_source_range: SourceRange,
cmd: WebSocketRequest,
_id_to_source_range: HashMap<Uuid, SourceRange>,
) -> Result<WebSocketResponse, KclError> {
match cmd {
WebSocketRequest::ModelingCmdBatchReq(ModelingBatch {
ref requests,
batch_id: _,
responses: _,
}) => {
let mut responses = HashMap::with_capacity(requests.len());
for request in requests {
responses.insert(
request.cmd_id,
BatchResponse::Success {
response: OkModelingCmdResponse::Empty {},
},
);
}
Ok(WebSocketResponse::Success(SuccessWebSocketResponse {
request_id: Some(id),
resp: OkWebSocketResponseData::ModelingBatch { responses },
success: true,
}))
}
WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
cmd: ModelingCmd::ImportFiles(ImportFiles { .. }),
cmd_id,
}) => Ok(WebSocketResponse::Success(SuccessWebSocketResponse {
request_id: Some(id),
resp: OkWebSocketResponseData::Modeling {
modeling_response: OkModelingCmdResponse::ImportFiles(
kittycad_modeling_cmds::output::ImportFiles::builder()
.object_id(cmd_id.into())
.build(),
),
},
success: true,
})),
WebSocketRequest::ModelingCmdReq(_) => Ok(WebSocketResponse::Success(SuccessWebSocketResponse {
request_id: Some(id),
resp: OkWebSocketResponseData::Modeling {
modeling_response: OkModelingCmdResponse::Empty {},
},
success: true,
})),
_ => Ok(WebSocketResponse::Success(SuccessWebSocketResponse {
request_id: Some(id),
resp: OkWebSocketResponseData::Modeling {
modeling_response: OkModelingCmdResponse::Empty {},
},
success: true,
})),
}
}
async fn close(&self) {}
}