Compare commits

..

5 Commits

Author SHA1 Message Date
8b5ab06b67 Add more console.log 2023-09-20 18:18:35 -04:00
94b606d2d9 Cache the width/height with the engine manager 2023-09-20 17:33:37 -04:00
2a2cc44baa appease the format gods 2023-09-20 15:58:49 -04:00
2d31f5b0e0 Fix typing 2023-09-20 15:54:42 -04:00
bb12eec7f9 Use useRef to store the Engine
useRef is a React Hook that lets you reference a value that’s not needed
for rendering. The value is set to the initial value on startup, and
will hang on to 'current' for us. We can store the Engine in the ref,
and React will take care of persisting it for us.

Signed-off-by: Paul Tagliamonte <paul@kittycad.io>
2023-09-20 15:44:06 -04:00
12 changed files with 98 additions and 161 deletions

View File

@ -1,6 +1,6 @@
{
"name": "untitled-app",
"version": "0.9.0",
"version": "0.8.2",
"private": true,
"dependencies": {
"@codemirror/autocomplete": "^6.9.0",
@ -10,7 +10,7 @@
"@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.7.13",
"@headlessui/tailwindcss": "^0.2.0",
"@kittycad/lib": "^0.0.38",
"@kittycad/lib": "^0.0.37",
"@lezer/javascript": "^1.4.7",
"@open-rpc/client-js": "^1.8.1",
"@react-hook/resize-observer": "^1.2.6",

View File

@ -8,7 +8,7 @@
},
"package": {
"productName": "kittycad-modeling",
"version": "0.9.0"
"version": "0.8.2"
},
"tauri": {
"allowlist": {

View File

@ -1,4 +1,4 @@
import { useLayoutEffect } from 'react'
import { useRef, useLayoutEffect } from 'react'
import { _executor } from '../lang/executor'
import { useStore } from '../useStore'
import { EngineCommandManager } from '../lang/std/engineConnection'
@ -28,6 +28,11 @@ export function useSetupEngineManager(
const quadWidth = Math.round(width / 4) * 4
const height = streamHeight ? streamHeight : 0
const quadHeight = Math.round(height / 4) * 4
const eng = useRef<{
engine: EngineCommandManager
width: number
height: number
} | null>(null)
useLayoutEffect(() => {
setStreamDimensions({
@ -35,19 +40,37 @@ export function useSetupEngineManager(
streamHeight: quadHeight,
})
if (!width || !height) return
const eng = new EngineCommandManager({
setMediaStream,
setIsStreamReady,
width: quadWidth,
height: quadHeight,
token,
})
setEngineCommandManager(eng)
eng.waitForReady.then(() => {
if (eng.current) {
// Before we go further, we're going to check to see if the
// width/height is the same as the last go-around. If it is, we
// can continue as normal, but if it's different, we should be
// clearing out the manager and going again.
let c = eng.current
if (width !== c.width || height !== c.height) {
eng.current = null
}
}
if (eng.current === null) {
eng.current = {
engine: new EngineCommandManager({
setMediaStream,
setIsStreamReady,
width: quadWidth,
height: quadHeight,
token,
}),
width: width,
height: height,
}
}
setEngineCommandManager(eng.current.engine)
eng.current.engine.waitForReady.then(() => {
executeCode()
})
return () => {
eng?.tearDown()
eng.current?.engine?.tearDown()
}
}, [quadWidth, quadHeight])
}

View File

@ -68,12 +68,12 @@ export class EngineConnection {
constructor({
url,
token,
onWebsocketOpen = () => {},
onNewTrack = () => {},
onEngineConnectionOpen = () => {},
onConnectionStarted = () => {},
onClose = () => {},
onDataChannelOpen = () => {},
onWebsocketOpen = () => { },
onNewTrack = () => { },
onEngineConnectionOpen = () => { },
onConnectionStarted = () => { },
onClose = () => { },
onDataChannelOpen = () => { },
}: {
url: string
token?: string
@ -364,8 +364,10 @@ export class EngineConnection {
// fix responsiveness for clients that had a weird network hiccup.
const connectionTimeoutMs = VITE_KC_CONNECTION_TIMEOUT_MS
console.log('setting timeout for connection')
setTimeout(() => {
if (this.isReady()) {
console.log('timeout fired but we were ready')
return
}
console.log('engine connection timeout on connection, retrying')
@ -531,8 +533,8 @@ export class EngineCommandManager {
outSequence = 1
inSequence = 1
engineConnection?: EngineConnection
waitForReady: Promise<void> = new Promise(() => {})
private resolveReady = () => {}
waitForReady: Promise<void> = new Promise(() => { })
private resolveReady = () => { }
subscriptions: {
[event: string]: {
@ -561,6 +563,7 @@ export class EngineCommandManager {
this.resolveReady = resolve
})
const url = `${VITE_KC_API_WS_MODELING_URL}?video_res_width=${width}&video_res_height=${height}`
console.log('new eng conn')
this.engineConnection = new EngineConnection({
url,
token,
@ -777,7 +780,6 @@ export class EngineCommandManager {
lastMessage = command.cmd.type
}
if (!this.engineConnection?.isReady()) {
console.log('socket not ready')
return Promise.resolve()
}
if (command.type !== 'modeling_cmd_req') return Promise.resolve()
@ -824,7 +826,6 @@ export class EngineCommandManager {
this.sourceRangeMap[id] = range
if (!this.engineConnection?.isReady()) {
console.log('socket not ready')
return Promise.resolve()
}
this.engineConnection?.send(command)
@ -842,7 +843,7 @@ export class EngineCommandManager {
command: Models['ModelingCmd_type'],
range?: SourceRange
) {
let resolve: (val: any) => void = () => {}
let resolve: (val: any) => void = () => { }
const promise = new Promise((_resolve, reject) => {
resolve = _resolve
})

View File

@ -226,20 +226,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "bigdecimal"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "454bca3db10617b88b566f205ed190aedb0e0e6dd4cad61d3988a72e8c5594cb"
dependencies = [
"autocfg",
"libm",
"num-bigint",
"num-integer",
"num-traits",
"serde",
]
[[package]]
name = "bincode"
version = "1.3.3"
@ -1411,14 +1397,13 @@ dependencies = [
[[package]]
name = "kittycad"
version = "0.2.26"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2623ee601ce203476229df3f9d3a14664cb43e3f7455e9ac8ed91aacaa6163d"
checksum = "d9cf962b1e81a0b4eb923a727e761b40672cbacc7f5f0b75e13579d346352bc7"
dependencies = [
"anyhow",
"async-trait",
"base64 0.21.4",
"bigdecimal 0.4.1",
"bytes",
"chrono",
"data-encoding",
@ -1480,12 +1465,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "libm"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
@ -2450,8 +2429,7 @@ version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c"
dependencies = [
"bigdecimal 0.3.1",
"bigdecimal 0.4.1",
"bigdecimal",
"bytes",
"chrono",
"dyn-clone",

View File

@ -3,11 +3,10 @@
use std::sync::Arc;
use anyhow::{anyhow, Result};
use anyhow::Result;
use dashmap::DashMap;
use futures::{SinkExt, StreamExt};
use kittycad::types::{OkWebSocketResponseData, WebSocketRequest, WebSocketResponse};
use tokio::sync::{mpsc, oneshot};
use tokio_tungstenite::tungstenite::Message as WsMsg;
use crate::{
@ -15,11 +14,10 @@ use crate::{
errors::{KclError, KclErrorDetails},
};
type WebSocketTcpWrite = futures::stream::SplitSink<tokio_tungstenite::WebSocketStream<reqwest::Upgraded>, WsMsg>;
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct EngineConnection {
engine_req_tx: mpsc::Sender<ToEngineReq>,
tcp_read_handle: Arc<tokio::task::JoinHandle<Result<()>>>,
tcp_write: futures::stream::SplitSink<tokio_tungstenite::WebSocketStream<reqwest::Upgraded>, WsMsg>,
tcp_read_handle: tokio::task::JoinHandle<Result<()>>,
responses: Arc<DashMap<uuid::Uuid, WebSocketResponse>>,
}
@ -48,36 +46,7 @@ impl TcpRead {
}
}
/// Requests to send to the engine, and a way to await a response.
struct ToEngineReq {
/// The request to send
req: WebSocketRequest,
/// If this resolves to Ok, the request was sent.
/// If this resolves to Err, the request could not be sent.
/// If this has not yet resolved, the request has not been sent yet.
request_sent: oneshot::Sender<Result<()>>,
}
impl EngineConnection {
/// Start waiting for incoming engine requests, and send each one over the WebSocket to the engine.
async fn start_write_actor(mut tcp_write: WebSocketTcpWrite, mut engine_req_rx: mpsc::Receiver<ToEngineReq>) {
while let Some(req) = engine_req_rx.recv().await {
let ToEngineReq { req, request_sent } = req;
let res = Self::inner_send_to_engine(req, &mut tcp_write).await;
let _ = request_sent.send(res);
}
}
/// Send the given `request` to the engine via the WebSocket connection `tcp_write`.
async fn inner_send_to_engine(request: WebSocketRequest, tcp_write: &mut WebSocketTcpWrite) -> Result<()> {
let msg = serde_json::to_string(&request).map_err(|e| anyhow!("could not serialize json: {e}"))?;
tcp_write
.send(WsMsg::Text(msg))
.await
.map_err(|e| anyhow!("could not send json over websocket: {e}"))?;
Ok(())
}
pub async fn new(ws: reqwest::Upgraded) -> Result<EngineConnection> {
let ws_stream = tokio_tungstenite::WebSocketStream::from_raw_socket(
ws,
@ -87,8 +56,6 @@ impl EngineConnection {
.await;
let (tcp_write, tcp_read) = ws_stream.split();
let (engine_req_tx, engine_req_rx) = mpsc::channel(10);
tokio::task::spawn(Self::start_write_actor(tcp_write, engine_req_rx));
let mut tcp_read = TcpRead { stream: tcp_read };
@ -113,11 +80,18 @@ impl EngineConnection {
});
Ok(EngineConnection {
engine_req_tx,
tcp_read_handle: Arc::new(tcp_read_handle),
tcp_write,
tcp_read_handle,
responses,
})
}
pub async fn tcp_send(&mut self, msg: WebSocketRequest) -> Result<()> {
let msg = serde_json::to_string(&msg)?;
self.tcp_write.send(WsMsg::Text(msg)).await?;
Ok(())
}
}
#[async_trait::async_trait(?Send)]
@ -125,7 +99,7 @@ impl EngineManager for EngineConnection {
/// Send a modeling command.
/// Do not wait for the response message.
fn send_modeling_cmd(
&self,
&mut self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
cmd: kittycad::types::ModelingCmd,
@ -136,19 +110,12 @@ impl EngineManager for EngineConnection {
/// Send a modeling command and wait for the response message.
async fn send_modeling_cmd_get_response(
&self,
&mut self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
cmd: kittycad::types::ModelingCmd,
) -> Result<OkWebSocketResponseData, KclError> {
let (tx, rx) = oneshot::channel();
// Send the request to the engine, via the actor.
self.engine_req_tx
.send(ToEngineReq {
req: WebSocketRequest::ModelingCmdReq { cmd, cmd_id: id },
request_sent: tx,
})
self.tcp_send(WebSocketRequest::ModelingCmdReq { cmd, cmd_id: id })
.await
.map_err(|e| {
KclError::Engine(KclErrorDetails {
@ -157,32 +124,17 @@ impl EngineManager for EngineConnection {
})
})?;
// Wait for the request to be sent.
rx.await
.map_err(|e| {
KclError::Engine(KclErrorDetails {
message: format!("could not send request to the engine actor: {e}"),
source_ranges: vec![source_range],
})
})?
.map_err(|e| {
KclError::Engine(KclErrorDetails {
message: format!("could not send request to the engine: {e}"),
source_ranges: vec![source_range],
})
})?;
// Wait for the response.
loop {
if let Some(resp) = self.responses.get(&id) {
return if let Some(data) = &resp.resp {
Ok(data.clone())
if let Some(data) = &resp.resp {
return Ok(data.clone());
} else {
Err(KclError::Engine(KclErrorDetails {
return Err(KclError::Engine(KclErrorDetails {
message: format!("Modeling command failed: {:?}", resp.errors),
source_ranges: vec![source_range],
}))
};
}));
}
}
}
}

View File

@ -6,7 +6,7 @@ use kittycad::types::OkWebSocketResponseData;
use crate::errors::KclError;
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct EngineConnection {}
impl EngineConnection {
@ -18,7 +18,7 @@ impl EngineConnection {
#[async_trait::async_trait(?Send)]
impl crate::engine::EngineManager for EngineConnection {
fn send_modeling_cmd(
&self,
&mut self,
_id: uuid::Uuid,
_source_range: crate::executor::SourceRange,
_cmd: kittycad::types::ModelingCmd,
@ -27,7 +27,7 @@ impl crate::engine::EngineManager for EngineConnection {
}
async fn send_modeling_cmd_get_response(
&self,
&mut self,
_id: uuid::Uuid,
_source_range: crate::executor::SourceRange,
_cmd: kittycad::types::ModelingCmd,

View File

@ -35,7 +35,7 @@ impl EngineConnection {
#[async_trait::async_trait(?Send)]
impl crate::engine::EngineManager for EngineConnection {
fn send_modeling_cmd(
&self,
&mut self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
cmd: kittycad::types::ModelingCmd,
@ -60,7 +60,7 @@ impl crate::engine::EngineManager for EngineConnection {
}
async fn send_modeling_cmd_get_response(
&self,
&mut self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
cmd: kittycad::types::ModelingCmd,

View File

@ -32,11 +32,11 @@ use anyhow::Result;
pub use conn_mock::EngineConnection;
#[async_trait::async_trait(?Send)]
pub trait EngineManager: Clone {
pub trait EngineManager {
/// Send a modeling command.
/// Do not wait for the response message.
fn send_modeling_cmd(
&self,
&mut self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
cmd: kittycad::types::ModelingCmd,
@ -44,7 +44,7 @@ pub trait EngineManager: Clone {
/// Send a modeling command and wait for the response message.
async fn send_modeling_cmd_get_response(
&self,
&mut self,
id: uuid::Uuid,
source_range: crate::executor::SourceRange,
cmd: kittycad::types::ModelingCmd,

View File

@ -67,7 +67,6 @@ fn inner_line_to(
y: to[1],
z: 0.0,
},
relative: false,
},
},
)?;
@ -202,7 +201,6 @@ fn inner_line(data: LineData, sketch_group: Box<SketchGroup>, args: &mut Args) -
LineData::Point(to) => *to,
};
let delta = inner_args;
let to = [from.x + inner_args[0], from.y + inner_args[1]];
let id = uuid::Uuid::new_v4();
@ -213,11 +211,10 @@ fn inner_line(data: LineData, sketch_group: Box<SketchGroup>, args: &mut Args) -
path: sketch_group.id,
segment: kittycad::types::PathSegment::Line {
end: Point3D {
x: delta[0],
y: delta[1],
x: to[0],
y: to[1],
z: 0.0,
},
relative: true,
},
},
)?;
@ -352,15 +349,10 @@ fn inner_angled_line(
AngledLineData::AngleWithTag { angle, length, .. } => (*angle, *length),
AngledLineData::AngleAndLength(angle_and_length) => (angle_and_length[0], angle_and_length[1]),
};
//double check me on this one - mike
let delta: [f64; 2] = [
length * f64::cos(angle.to_radians()),
length * f64::sin(angle.to_radians()),
let to: [f64; 2] = [
from.x + length * f64::cos(angle.to_radians()),
from.y + length * f64::sin(angle.to_radians()),
];
let relative = true;
let to: [f64; 2] = [from.x + delta[0], from.y + delta[1]];
let id = uuid::Uuid::new_v4();
@ -386,11 +378,10 @@ fn inner_angled_line(
path: sketch_group.id,
segment: kittycad::types::PathSegment::Line {
end: Point3D {
x: delta[0],
y: delta[1],
x: to[0],
y: to[1],
z: 0.0,
},
relative,
},
},
)?;
@ -841,14 +832,9 @@ fn inner_arc(data: ArcData, sketch_group: Box<SketchGroup>, args: &mut Args) ->
angle_end: angle_end.degrees(),
center: center.into(),
radius,
relative: false,
},
},
)?;
// TODO: Dont do this (move path pen) - mike
// lets review what the needs are here and see if any existing arc endpoints can accomplish this
// Move the path pen to the end of the arc.
// Since that is where we want to draw the next path.
// TODO: the engine should automatically move the pen to the end of the arc.
@ -941,8 +927,6 @@ fn inner_bezier_curve(
BezierData::Points { to, control1, control2 } => (to, control1, control2),
};
let relative = true;
let delta = to;
let to = [from.x + to[0], from.y + to[1]];
let id = uuid::Uuid::new_v4();
@ -953,21 +937,20 @@ fn inner_bezier_curve(
path: sketch_group.id,
segment: kittycad::types::PathSegment::Bezier {
control1: Point3D {
x: control1[0],
y: control1[1],
x: from.x + control1[0],
y: from.y + control1[1],
z: 0.0,
},
control2: Point3D {
x: control2[0],
y: control2[1],
x: from.x + control2[0],
y: from.y + control2[1],
z: 0.0,
},
end: Point3D {
x: delta[0],
y: delta[1],
x: to[0],
y: to[1],
z: 0.0,
},
relative,
},
},
)?;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -1530,10 +1530,10 @@
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
"@kittycad/lib@^0.0.38":
version "0.0.38"
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-0.0.38.tgz#50474266f679990bd414c30f884f2d42a0d5dba9"
integrity sha512-Lv9P7jqVRoGgOnCsRCsG8OwZH5n3scxXYrElR+5/Rsd6/KIarLB4bSBngJrXebOnmTw5md0OPeY+b3ZDbZFDeg==
"@kittycad/lib@^0.0.37":
version "0.0.37"
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-0.0.37.tgz#ec4f6c4fb5d06402a19339f3374036b6582d2265"
integrity sha512-P8p9FeLV79/0Lfd0RioBta1drzhmpROnU4YV38+zsAA4LhibQCTjeekRkxVvHztGumPxz9pPsAeeLJyuz2RWKQ==
dependencies:
node-fetch "3.3.2"
openapi-types "^12.0.0"