Add batch support to current KCL implementation (#1871)
* wip * wip * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * more batch shit Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * push up mods Signed-off-by: Jess Frazelle <github@jessfraz.com> * go back to batch id Signed-off-by: Jess Frazelle <github@jessfraz.com> * add unlocks back Signed-off-by: Jess Frazelle <github@jessfraz.com> * remove logging Signed-off-by: Jess Frazelle <github@jessfraz.com> * port to wasm Signed-off-by: Jess Frazelle <github@jessfraz.com> * use a trait Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * snapshojts Signed-off-by: Jess Frazelle <github@jessfraz.com> * artifact map fix Signed-off-by: Jess Frazelle <github@jessfraz.com> * cleanup Signed-off-by: Jess Frazelle <github@jessfraz.com> * remove the blur Signed-off-by: Jess Frazelle <github@jessfraz.com> * hacks on hacks Signed-off-by: Jess Frazelle <github@jessfraz.com> * artifact map clean up * tweak * fix so extrudes work * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * start of id to source range infra Signed-off-by: Jess Frazelle <github@jessfraz.com> * basic map to ids and source ranges Signed-off-by: Jess Frazelle <github@jessfraz.com> * make typescript happy Signed-off-by: Jess Frazelle <github@jessfraz.com> * flush at end of exxecute Signed-off-by: Jess Frazelle <github@jessfraz.com> * small thing for flush Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * trigger ci --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: 49lf <ircsurfer33@gmail.com> Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 221 KiB |
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 221 KiB |
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 221 KiB |
Before Width: | Height: | Size: 259 KiB After Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 221 KiB |
Before Width: | Height: | Size: 221 KiB After Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 221 KiB After Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 50 KiB |
@ -4,7 +4,6 @@ import { getNormalisedCoordinates } from '../lib/utils'
|
||||
import Loading from './Loading'
|
||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||
import { useModelingContext } from 'hooks/useModelingContext'
|
||||
import { useKclContext } from 'lang/KclProvider'
|
||||
import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp'
|
||||
import { NetworkHealthState, useNetworkStatus } from './NetworkHealthIndicator'
|
||||
import { butName } from 'lib/cameraControls'
|
||||
@ -29,7 +28,6 @@ export const Stream = ({ className = '' }: { className?: string }) => {
|
||||
}))
|
||||
const { settings } = useSettingsAuthContext()
|
||||
const { state } = useModelingContext()
|
||||
const { isExecuting } = useKclContext()
|
||||
const { overallState } = useNetworkStatus()
|
||||
const isNetworkOkay = overallState === NetworkHealthState.Ok
|
||||
|
||||
@ -103,7 +101,7 @@ export const Stream = ({ className = '' }: { className?: string }) => {
|
||||
controls={false}
|
||||
onPlay={() => setIsLoading(false)}
|
||||
onMouseMoveCapture={handleMouseMove}
|
||||
className={`w-full cursor-pointer h-full ${isExecuting && 'blur-md'}`}
|
||||
className="w-full cursor-pointer h-full"
|
||||
disablePictureInPicture
|
||||
style={{ transitionDuration: '200ms', transitionProperty: 'filter' }}
|
||||
id="video-stream"
|
||||
|
@ -13,10 +13,16 @@ interface CommandInfo {
|
||||
range: SourceRange
|
||||
pathToNode: PathToNode
|
||||
parentId?: string
|
||||
additionalData?: {
|
||||
type: 'cap'
|
||||
info: 'start' | 'end'
|
||||
}
|
||||
additionalData?:
|
||||
| {
|
||||
type: 'cap'
|
||||
info: 'start' | 'end'
|
||||
}
|
||||
| {
|
||||
type: 'batch-ids'
|
||||
ids: string[]
|
||||
info?: null
|
||||
}
|
||||
}
|
||||
|
||||
type WebSocketResponse = Models['OkWebSocketResponseData_type']
|
||||
@ -792,7 +798,7 @@ failed cmd type was ${artifactThatFailed?.commandType}`
|
||||
export type EngineCommand = Models['WebSocketRequest_type']
|
||||
type ModelTypes = Models['OkModelingCmdResponse_type']['type']
|
||||
|
||||
type CommandTypes = Models['ModelingCmd_type']['type']
|
||||
type CommandTypes = Models['ModelingCmd_type']['type'] | 'batch'
|
||||
|
||||
type UnreliableResponses = Extract<
|
||||
Models['OkModelingCmdResponse_type'],
|
||||
@ -1073,6 +1079,27 @@ export class EngineCommandManager {
|
||||
}
|
||||
const modelingResponse = message.data.modeling_response
|
||||
const command = this.artifactMap[id]
|
||||
if (
|
||||
command?.type === 'pending' &&
|
||||
command.commandType === 'batch' &&
|
||||
command?.additionalData?.type === 'batch-ids'
|
||||
) {
|
||||
command.additionalData.ids.forEach((id) => {
|
||||
this.handleModelingCommand(message, id)
|
||||
})
|
||||
// batch artifact is just a container, we don't need to keep it
|
||||
// once we process all the commands inside it
|
||||
const resolve = command.resolve
|
||||
delete this.artifactMap[id]
|
||||
resolve({
|
||||
id,
|
||||
commandType: command.commandType,
|
||||
range: command.range,
|
||||
data: modelingResponse,
|
||||
raw: message,
|
||||
})
|
||||
return
|
||||
}
|
||||
const sceneCommand = this.sceneCommandArtifacts[id]
|
||||
this.addCommandLog({
|
||||
type: 'receive-reliable',
|
||||
@ -1400,11 +1427,13 @@ export class EngineCommandManager {
|
||||
range,
|
||||
command,
|
||||
ast,
|
||||
idToRangeMap,
|
||||
}: {
|
||||
id: string
|
||||
range: SourceRange
|
||||
command: EngineCommand | string
|
||||
ast: Program
|
||||
idToRangeMap?: { [key: string]: SourceRange }
|
||||
}): Promise<any> {
|
||||
if (this.engineConnection === undefined) {
|
||||
return Promise.resolve()
|
||||
@ -1427,10 +1456,22 @@ export class EngineCommandManager {
|
||||
this.engineConnection?.send(command)
|
||||
if (typeof command !== 'string' && command.type === 'modeling_cmd_req') {
|
||||
return this.handlePendingCommand(id, command?.cmd, ast, range)
|
||||
} else if (
|
||||
typeof command !== 'string' &&
|
||||
command.type === 'modeling_cmd_batch_req'
|
||||
) {
|
||||
return this.handlePendingBatchCommand(id, command.requests, idToRangeMap)
|
||||
} else if (typeof command === 'string') {
|
||||
const parseCommand: EngineCommand = JSON.parse(command)
|
||||
if (parseCommand.type === 'modeling_cmd_req')
|
||||
if (parseCommand.type === 'modeling_cmd_req') {
|
||||
return this.handlePendingCommand(id, parseCommand?.cmd, ast, range)
|
||||
} else if (parseCommand.type === 'modeling_cmd_batch_req') {
|
||||
return this.handlePendingBatchCommand(
|
||||
id,
|
||||
parseCommand.requests,
|
||||
idToRangeMap
|
||||
)
|
||||
}
|
||||
}
|
||||
throw Error('shouldnt reach here')
|
||||
}
|
||||
@ -1491,10 +1532,48 @@ export class EngineCommandManager {
|
||||
}
|
||||
return promise
|
||||
}
|
||||
async handlePendingBatchCommand(
|
||||
id: string,
|
||||
commands: Models['ModelingCmdReq_type'][],
|
||||
idToRangeMap?: { [key: string]: SourceRange },
|
||||
ast?: Program,
|
||||
range?: SourceRange
|
||||
) {
|
||||
let resolve: (val: any) => void = () => {}
|
||||
const promise = new Promise((_resolve, reject) => {
|
||||
resolve = _resolve
|
||||
})
|
||||
|
||||
if (!idToRangeMap) {
|
||||
throw new Error('idToRangeMap is required for batch commands')
|
||||
}
|
||||
|
||||
// Add the overall batch command to the artifact map just so we can track all of the
|
||||
// individual commands that are part of the batch.
|
||||
// we'll delete this artifact once all of the individual commands have been processed.
|
||||
this.artifactMap[id] = {
|
||||
range: range || [0, 0],
|
||||
pathToNode: [],
|
||||
type: 'pending',
|
||||
commandType: 'batch',
|
||||
additionalData: { type: 'batch-ids', ids: commands.map((c) => c.cmd_id) },
|
||||
parentId: undefined,
|
||||
promise,
|
||||
resolve,
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
commands.map((c) =>
|
||||
this.handlePendingCommand(c.cmd_id, c.cmd, ast, idToRangeMap[c.cmd_id])
|
||||
)
|
||||
)
|
||||
return promise
|
||||
}
|
||||
sendModelingCommandFromWasm(
|
||||
id: string,
|
||||
rangeStr: string,
|
||||
commandStr: string
|
||||
commandStr: string,
|
||||
idToRangeStr: string
|
||||
): Promise<any> {
|
||||
if (this.engineConnection === undefined) {
|
||||
return Promise.resolve()
|
||||
@ -1512,6 +1591,8 @@ export class EngineCommandManager {
|
||||
throw new Error('commandStr is undefined')
|
||||
}
|
||||
const range: SourceRange = JSON.parse(rangeStr)
|
||||
const idToRangeMap: { [key: string]: SourceRange } =
|
||||
JSON.parse(idToRangeStr)
|
||||
|
||||
// We only care about the modeling command response.
|
||||
return this.sendModelingCommand({
|
||||
@ -1519,6 +1600,7 @@ export class EngineCommandManager {
|
||||
range,
|
||||
command: commandStr,
|
||||
ast: this.getAst(),
|
||||
idToRangeMap,
|
||||
}).then(({ raw }) => JSON.stringify(raw))
|
||||
}
|
||||
commandResult(id: string): Promise<any> {
|
||||
|
1175
src/wasm-lib/Cargo.lock
generated
@ -59,7 +59,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
kittycad = { version = "0.2.61", default-features = false, features = ["js", "requests"] }
|
||||
kittycad = { version = "0.2.62", default-features = false, features = ["js", "requests"] }
|
||||
kittycad-execution-plan = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||
kittycad-execution-plan-macros = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||
kittycad-execution-plan-traits = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "derive-docs"
|
||||
description = "A tool for generating documentation from Rust derive macros"
|
||||
version = "0.1.11"
|
||||
version = "0.1.12"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
@ -23,6 +23,7 @@ serde_tokenstream = "0.2"
|
||||
syn = { version = "2.0.53", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0.81"
|
||||
expectorate = "1.1.0"
|
||||
openapitor = { git = "https://github.com/KittyCAD/kittycad.rs", branch = "main" }
|
||||
pretty_assertions = "1.4.0"
|
||||
rustfmt-wrapper = "0.2.1"
|
||||
|
@ -764,7 +764,11 @@ fn generate_code_block_test(fn_name: &str, code_block: &str, index: usize) -> pr
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
|
||||
// Create the client.
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// Set a local engine address if it's set.
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
|
@ -1,7 +1,27 @@
|
||||
use anyhow::Result;
|
||||
use quote::quote;
|
||||
|
||||
use crate::{do_stdlib, parse_array_type};
|
||||
|
||||
fn clean_text(s: &str) -> String {
|
||||
// Add newlines after end-braces at <= two levels of indentation.
|
||||
if cfg!(not(windows)) {
|
||||
let regex = regex::Regex::new(r"(})(\n\s{0,8}[^} ])").unwrap();
|
||||
regex.replace_all(s, "$1\n$2").to_string()
|
||||
} else {
|
||||
let regex = regex::Regex::new(r"(})(\r\n\s{0,8}[^} ])").unwrap();
|
||||
regex.replace_all(s, "$1\r\n$2").to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Format a TokenStream as a string and run `rustfmt` on the result.
|
||||
fn get_text_fmt(output: &proc_macro2::TokenStream) -> Result<String> {
|
||||
// Format the file with rustfmt.
|
||||
let content = rustfmt_wrapper::rustfmt(output).unwrap();
|
||||
|
||||
Ok(clean_text(&content))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_inner_array_type() {
|
||||
for (expected, input) in [
|
||||
@ -47,7 +67,7 @@ fn test_stdlib_line_to() {
|
||||
let _expected = quote! {};
|
||||
|
||||
assert!(errors.is_empty());
|
||||
expectorate::assert_contents("tests/lineTo.gen", &openapitor::types::get_text_fmt(&item).unwrap());
|
||||
expectorate::assert_contents("tests/lineTo.gen", &get_text_fmt(&item).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -88,7 +108,7 @@ fn test_stdlib_min() {
|
||||
let _expected = quote! {};
|
||||
|
||||
assert!(errors.is_empty());
|
||||
expectorate::assert_contents("tests/min.gen", &openapitor::types::get_text_fmt(&item).unwrap());
|
||||
expectorate::assert_contents("tests/min.gen", &get_text_fmt(&item).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -115,7 +135,7 @@ fn test_stdlib_show() {
|
||||
let _expected = quote! {};
|
||||
|
||||
assert!(errors.is_empty());
|
||||
expectorate::assert_contents("tests/show.gen", &openapitor::types::get_text_fmt(&item).unwrap());
|
||||
expectorate::assert_contents("tests/show.gen", &get_text_fmt(&item).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -143,7 +163,7 @@ fn test_stdlib_box() {
|
||||
let _expected = quote! {};
|
||||
|
||||
assert!(errors.is_empty());
|
||||
expectorate::assert_contents("tests/box.gen", &openapitor::types::get_text_fmt(&item).unwrap());
|
||||
expectorate::assert_contents("tests/box.gen", &get_text_fmt(&item).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -170,7 +190,7 @@ fn test_stdlib_option() {
|
||||
.unwrap();
|
||||
|
||||
assert!(errors.is_empty());
|
||||
expectorate::assert_contents("tests/option.gen", &openapitor::types::get_text_fmt(&item).unwrap());
|
||||
expectorate::assert_contents("tests/option.gen", &get_text_fmt(&item).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -203,7 +223,7 @@ fn test_stdlib_array() {
|
||||
.unwrap();
|
||||
|
||||
assert!(errors.is_empty());
|
||||
expectorate::assert_contents("tests/array.gen", &openapitor::types::get_text_fmt(&item).unwrap());
|
||||
expectorate::assert_contents("tests/array.gen", &get_text_fmt(&item).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -230,10 +250,7 @@ fn test_stdlib_option_input_format() {
|
||||
.unwrap();
|
||||
|
||||
assert!(errors.is_empty());
|
||||
expectorate::assert_contents(
|
||||
"tests/option_input_format.gen",
|
||||
&openapitor::types::get_text_fmt(&item).unwrap(),
|
||||
);
|
||||
expectorate::assert_contents("tests/option_input_format.gen", &get_text_fmt(&item).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -260,10 +277,7 @@ fn test_stdlib_return_vec_sketch_group() {
|
||||
.unwrap();
|
||||
|
||||
assert!(errors.is_empty());
|
||||
expectorate::assert_contents(
|
||||
"tests/return_vec_sketch_group.gen",
|
||||
&openapitor::types::get_text_fmt(&item).unwrap(),
|
||||
);
|
||||
expectorate::assert_contents("tests/return_vec_sketch_group.gen", &get_text_fmt(&item).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -290,10 +304,7 @@ fn test_stdlib_return_vec_box_sketch_group() {
|
||||
.unwrap();
|
||||
|
||||
assert!(errors.is_empty());
|
||||
expectorate::assert_contents(
|
||||
"tests/return_vec_box_sketch_group.gen",
|
||||
&openapitor::types::get_text_fmt(&item).unwrap(),
|
||||
);
|
||||
expectorate::assert_contents("tests/return_vec_box_sketch_group.gen", &get_text_fmt(&item).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -326,10 +337,7 @@ fn test_stdlib_doc_comment_with_code() {
|
||||
.unwrap();
|
||||
|
||||
assert!(errors.is_empty());
|
||||
expectorate::assert_contents(
|
||||
"tests/doc_comment_with_code.gen",
|
||||
&openapitor::types::get_text_fmt(&item).unwrap(),
|
||||
);
|
||||
expectorate::assert_contents("tests/doc_comment_with_code.gen", &get_text_fmt(&item).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -364,7 +372,7 @@ fn test_stdlib_doc_comment_with_code_on_ignored_function() {
|
||||
assert!(errors.is_empty());
|
||||
expectorate::assert_contents(
|
||||
"tests/doc_comment_with_code_on_ignored_function.gen",
|
||||
&openapitor::types::get_text_fmt(&item).unwrap(),
|
||||
&get_text_fmt(&item).unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,11 @@ mod test_examples_show {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
@ -55,7 +59,11 @@ mod test_examples_show {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
|
@ -15,7 +15,11 @@ mod test_examples_show {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
|
@ -15,7 +15,11 @@ mod test_examples_my_func {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
@ -55,7 +59,11 @@ mod test_examples_my_func {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
|
@ -16,7 +16,11 @@ mod test_examples_import {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
@ -57,7 +61,11 @@ mod test_examples_import {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
|
@ -15,7 +15,11 @@ mod test_examples_line_to {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
@ -55,7 +59,11 @@ mod test_examples_line_to {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
|
@ -15,7 +15,11 @@ mod test_examples_min {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
@ -55,7 +59,11 @@ mod test_examples_min {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
|
@ -15,7 +15,11 @@ mod test_examples_show {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
|
@ -16,7 +16,11 @@ mod test_examples_import {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
|
@ -16,7 +16,11 @@ mod test_examples_import {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
|
@ -16,7 +16,11 @@ mod test_examples_import {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
|
@ -15,7 +15,11 @@ mod test_examples_show {
|
||||
.tcp_keepalive(std::time::Duration::from_secs(600))
|
||||
.http1_only();
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
.commands_ws(None, None, None, None, None, Some(false))
|
||||
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 70 KiB |
@ -18,8 +18,8 @@ chrono = "0.4.35"
|
||||
clap = { version = "4.5.3", features = ["cargo", "derive", "env", "unicode"], optional = true }
|
||||
dashmap = "5.5.3"
|
||||
databake = { version = "0.1.7", features = ["derive"] }
|
||||
derive-docs = { version = "0.1.11" }
|
||||
#derive-docs = { path = "../derive-docs" }
|
||||
#derive-docs = { version = "0.1.12" }
|
||||
derive-docs = { path = "../derive-docs" }
|
||||
futures = { version = "0.3.30" }
|
||||
gltf-json = "1.4.0"
|
||||
kittycad = { workspace = true }
|
||||
|
@ -75,6 +75,7 @@ pub async fn modify_ast_for_sketch(
|
||||
// Let's get the path info.
|
||||
let resp = engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
SourceRange::default(),
|
||||
ModelingCmd::PathGetInfo { path_id: sketch_id },
|
||||
@ -99,6 +100,7 @@ pub async fn modify_ast_for_sketch(
|
||||
for segment in &path_info.segments {
|
||||
if let Some(command_id) = &segment.command_id {
|
||||
let h = engine.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
SourceRange::default(),
|
||||
ModelingCmd::CurveGetControlPoints { curve_id: *command_id },
|
||||
|
@ -29,6 +29,7 @@ pub struct EngineConnection {
|
||||
responses: Arc<DashMap<uuid::Uuid, WebSocketResponse>>,
|
||||
tcp_read_handle: Arc<TcpReadHandle>,
|
||||
socket_health: Arc<Mutex<SocketHealth>>,
|
||||
batch: Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>,
|
||||
}
|
||||
|
||||
pub struct TcpRead {
|
||||
@ -154,27 +155,30 @@ impl EngineConnection {
|
||||
}),
|
||||
responses,
|
||||
socket_health,
|
||||
batch: Arc::new(Mutex::new(Vec::new())),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl EngineManager for EngineConnection {
|
||||
async fn send_modeling_cmd(
|
||||
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>> {
|
||||
self.batch.clone()
|
||||
}
|
||||
|
||||
async fn inner_send_modeling_cmd(
|
||||
&self,
|
||||
id: uuid::Uuid,
|
||||
source_range: crate::executor::SourceRange,
|
||||
cmd: kittycad::types::ModelingCmd,
|
||||
cmd: kittycad::types::WebSocketRequest,
|
||||
_id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
||||
) -> 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.clone(),
|
||||
cmd_id: id,
|
||||
},
|
||||
req: cmd.clone(),
|
||||
request_sent: tx,
|
||||
})
|
||||
.await
|
||||
|
@ -1,27 +1,38 @@
|
||||
//! Functions for setting up our WebSocket and WebRTC connections for communications with the
|
||||
//! engine.
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use anyhow::Result;
|
||||
use kittycad::types::OkWebSocketResponseData;
|
||||
use kittycad::types::{OkWebSocketResponseData, WebSocketRequest};
|
||||
|
||||
use crate::errors::KclError;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EngineConnection {}
|
||||
pub struct EngineConnection {
|
||||
batch: Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>,
|
||||
}
|
||||
|
||||
impl EngineConnection {
|
||||
pub async fn new() -> Result<EngineConnection> {
|
||||
Ok(EngineConnection {})
|
||||
Ok(EngineConnection {
|
||||
batch: Arc::new(Mutex::new(Vec::new())),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl crate::engine::EngineManager for EngineConnection {
|
||||
async fn send_modeling_cmd(
|
||||
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>> {
|
||||
self.batch.clone()
|
||||
}
|
||||
|
||||
async fn inner_send_modeling_cmd(
|
||||
&self,
|
||||
_id: uuid::Uuid,
|
||||
_source_range: crate::executor::SourceRange,
|
||||
_cmd: kittycad::types::ModelingCmd,
|
||||
_cmd: kittycad::types::WebSocketRequest,
|
||||
_id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
||||
) -> Result<OkWebSocketResponseData, KclError> {
|
||||
Ok(OkWebSocketResponseData::Modeling {
|
||||
modeling_response: kittycad::types::OkModelingCmdResponse::Empty {},
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Functions for setting up our WebSocket and WebRTC connections for communications with the
|
||||
//! engine.
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use anyhow::Result;
|
||||
use kittycad::types::WebSocketRequest;
|
||||
@ -19,12 +19,14 @@ extern "C" {
|
||||
id: String,
|
||||
rangeStr: String,
|
||||
cmdStr: String,
|
||||
idToRangeStr: String,
|
||||
) -> Result<js_sys::Promise, js_sys::Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EngineConnection {
|
||||
manager: Arc<EngineCommandManager>,
|
||||
batch: Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>>,
|
||||
}
|
||||
|
||||
// Safety: WebAssembly will only ever run in a single-threaded context.
|
||||
@ -35,17 +37,23 @@ impl EngineConnection {
|
||||
pub async fn new(manager: EngineCommandManager) -> Result<EngineConnection, JsValue> {
|
||||
Ok(EngineConnection {
|
||||
manager: Arc::new(manager),
|
||||
batch: Arc::new(Mutex::new(Vec::new())),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl crate::engine::EngineManager for EngineConnection {
|
||||
async fn send_modeling_cmd(
|
||||
fn batch(&self) -> Arc<Mutex<Vec<(WebSocketRequest, crate::executor::SourceRange)>>> {
|
||||
self.batch.clone()
|
||||
}
|
||||
|
||||
async fn inner_send_modeling_cmd(
|
||||
&self,
|
||||
id: uuid::Uuid,
|
||||
source_range: crate::executor::SourceRange,
|
||||
cmd: kittycad::types::ModelingCmd,
|
||||
cmd: kittycad::types::WebSocketRequest,
|
||||
id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
||||
) -> Result<kittycad::types::OkWebSocketResponseData, KclError> {
|
||||
let source_range_str = serde_json::to_string(&source_range).map_err(|e| {
|
||||
KclError::Engine(KclErrorDetails {
|
||||
@ -53,17 +61,22 @@ impl crate::engine::EngineManager for EngineConnection {
|
||||
source_ranges: vec![source_range],
|
||||
})
|
||||
})?;
|
||||
let ws_msg = WebSocketRequest::ModelingCmdReq { cmd, cmd_id: id };
|
||||
let cmd_str = serde_json::to_string(&ws_msg).map_err(|e| {
|
||||
let cmd_str = serde_json::to_string(&cmd).map_err(|e| {
|
||||
KclError::Engine(KclErrorDetails {
|
||||
message: format!("Failed to serialize modeling command: {:?}", e),
|
||||
source_ranges: vec![source_range],
|
||||
})
|
||||
})?;
|
||||
let id_to_source_range_str = serde_json::to_string(&id_to_source_range).map_err(|e| {
|
||||
KclError::Engine(KclErrorDetails {
|
||||
message: format!("Failed to serialize id to source range: {:?}", e),
|
||||
source_ranges: vec![source_range],
|
||||
})
|
||||
})?;
|
||||
|
||||
let promise = self
|
||||
.manager
|
||||
.send_modeling_cmd_from_wasm(id.to_string(), source_range_str, cmd_str)
|
||||
.send_modeling_cmd_from_wasm(id.to_string(), source_range_str, cmd_str, id_to_source_range_str)
|
||||
.map_err(|e| {
|
||||
KclError::Engine(KclErrorDetails {
|
||||
message: e.to_string().into(),
|
||||
|
@ -8,13 +8,177 @@ pub mod conn_mock;
|
||||
#[cfg(feature = "engine")]
|
||||
pub mod conn_wasm;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use kittycad::types::{OkWebSocketResponseData, WebSocketRequest};
|
||||
|
||||
use crate::errors::{KclError, KclErrorDetails};
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
/// Get the batch of commands to be sent to the engine.
|
||||
fn batch(&self) -> Arc<Mutex<Vec<(kittycad::types::WebSocketRequest, crate::executor::SourceRange)>>>;
|
||||
|
||||
/// Send a modeling command and wait for the response message.
|
||||
async fn send_modeling_cmd(
|
||||
async fn inner_send_modeling_cmd(
|
||||
&self,
|
||||
id: uuid::Uuid,
|
||||
source_range: crate::executor::SourceRange,
|
||||
cmd: kittycad::types::ModelingCmd,
|
||||
cmd: kittycad::types::WebSocketRequest,
|
||||
id_to_source_range: std::collections::HashMap<uuid::Uuid, crate::executor::SourceRange>,
|
||||
) -> Result<kittycad::types::OkWebSocketResponseData, crate::errors::KclError>;
|
||||
|
||||
async fn send_modeling_cmd(
|
||||
&self,
|
||||
flush_batch: bool,
|
||||
id: uuid::Uuid,
|
||||
source_range: crate::executor::SourceRange,
|
||||
cmd: kittycad::types::ModelingCmd,
|
||||
) -> Result<kittycad::types::OkWebSocketResponseData, crate::errors::KclError> {
|
||||
let req = WebSocketRequest::ModelingCmdReq {
|
||||
cmd: cmd.clone(),
|
||||
cmd_id: id,
|
||||
};
|
||||
|
||||
if !flush_batch {
|
||||
self.batch().lock().unwrap().push((req.clone(), source_range));
|
||||
}
|
||||
|
||||
// If the batch only has this one command that expects a return value,
|
||||
// fire it right away, or if we want to flush batch queue.
|
||||
let is_sending = (is_cmd_with_return_values(&cmd) && self.batch().lock().unwrap().len() == 1)
|
||||
|| flush_batch
|
||||
|| is_cmd_with_return_values(&cmd);
|
||||
|
||||
// Return a fake modeling_request empty response.
|
||||
if !is_sending {
|
||||
return Ok(OkWebSocketResponseData::Modeling {
|
||||
modeling_response: kittycad::types::OkModelingCmdResponse::Empty {},
|
||||
});
|
||||
}
|
||||
|
||||
// Flush the batch queue.
|
||||
self.flush_batch(source_range).await
|
||||
}
|
||||
|
||||
/// Force flush the batch queue.
|
||||
async fn flush_batch(
|
||||
&self,
|
||||
source_range: crate::executor::SourceRange,
|
||||
) -> Result<kittycad::types::OkWebSocketResponseData, crate::errors::KclError> {
|
||||
// Return early if we have no commands to send.
|
||||
if self.batch().lock().unwrap().is_empty() {
|
||||
return Ok(OkWebSocketResponseData::Modeling {
|
||||
modeling_response: kittycad::types::OkModelingCmdResponse::Empty {},
|
||||
});
|
||||
}
|
||||
|
||||
let batched_requests = WebSocketRequest::ModelingCmdBatchReq {
|
||||
requests: self.batch().lock().unwrap().iter().fold(vec![], |mut acc, (val, _)| {
|
||||
let WebSocketRequest::ModelingCmdReq { cmd, cmd_id } = val else {
|
||||
return acc;
|
||||
};
|
||||
acc.push(kittycad::types::ModelingCmdReq {
|
||||
cmd: cmd.clone(),
|
||||
cmd_id: *cmd_id,
|
||||
});
|
||||
acc
|
||||
}),
|
||||
batch_id: uuid::Uuid::new_v4(),
|
||||
};
|
||||
|
||||
let final_req = if self.batch().lock().unwrap().len() == 1 {
|
||||
// We can unwrap here because we know the batch has only one element.
|
||||
self.batch().lock().unwrap().first().unwrap().0.clone()
|
||||
} else {
|
||||
batched_requests
|
||||
};
|
||||
|
||||
// Create the map of original command IDs to source range.
|
||||
// This is for the wasm side, kurt needs it for selections.
|
||||
let mut id_to_source_range = std::collections::HashMap::new();
|
||||
for (req, range) in self.batch().lock().unwrap().iter() {
|
||||
match req {
|
||||
WebSocketRequest::ModelingCmdReq { cmd: _, cmd_id } => {
|
||||
id_to_source_range.insert(*cmd_id, *range);
|
||||
}
|
||||
_ => {
|
||||
return Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("The request is not a modeling command: {:?}", req),
|
||||
source_ranges: vec![*range],
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Throw away the old batch queue.
|
||||
self.batch().lock().unwrap().clear();
|
||||
|
||||
// We pop off the responses to cleanup our mappings.
|
||||
let id_final = match final_req {
|
||||
WebSocketRequest::ModelingCmdBatchReq { requests: _, batch_id } => batch_id,
|
||||
WebSocketRequest::ModelingCmdReq { cmd: _, cmd_id } => cmd_id,
|
||||
_ => {
|
||||
return Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("The final request is not a modeling command: {:?}", final_req),
|
||||
source_ranges: vec![source_range],
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
self.inner_send_modeling_cmd(id_final, source_range, final_req, id_to_source_range)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_cmd_with_return_values(cmd: &kittycad::types::ModelingCmd) -> bool {
|
||||
let (kittycad::types::ModelingCmd::Export { .. }
|
||||
| kittycad::types::ModelingCmd::Extrude { .. }
|
||||
| kittycad::types::ModelingCmd::SketchModeDisable { .. }
|
||||
| kittycad::types::ModelingCmd::ObjectBringToFront { .. }
|
||||
| kittycad::types::ModelingCmd::SelectWithPoint { .. }
|
||||
| kittycad::types::ModelingCmd::HighlightSetEntity { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetChildUuid { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetNumChildren { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetParentId { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetAllChildUuids { .. }
|
||||
| kittycad::types::ModelingCmd::CameraDragMove { .. }
|
||||
| kittycad::types::ModelingCmd::CameraDragEnd { .. }
|
||||
| kittycad::types::ModelingCmd::DefaultCameraGetSettings { .. }
|
||||
| kittycad::types::ModelingCmd::DefaultCameraZoom { .. }
|
||||
| kittycad::types::ModelingCmd::SelectGet { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetAllEdgeFaces { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetAllOppositeEdges { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetOppositeEdge { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetNextAdjacentEdge { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetPrevAdjacentEdge { .. }
|
||||
| kittycad::types::ModelingCmd::GetEntityType { .. }
|
||||
| kittycad::types::ModelingCmd::CurveGetControlPoints { .. }
|
||||
| kittycad::types::ModelingCmd::CurveGetType { .. }
|
||||
| kittycad::types::ModelingCmd::MouseClick { .. }
|
||||
| kittycad::types::ModelingCmd::TakeSnapshot { .. }
|
||||
| kittycad::types::ModelingCmd::PathGetInfo { .. }
|
||||
| kittycad::types::ModelingCmd::PathGetCurveUuidsForVertices { .. }
|
||||
| kittycad::types::ModelingCmd::PathGetVertexUuids { .. }
|
||||
| kittycad::types::ModelingCmd::CurveGetEndPoints { .. }
|
||||
| kittycad::types::ModelingCmd::FaceIsPlanar { .. }
|
||||
| kittycad::types::ModelingCmd::FaceGetPosition { .. }
|
||||
| kittycad::types::ModelingCmd::FaceGetGradient { .. }
|
||||
| kittycad::types::ModelingCmd::PlaneIntersectAndProject { .. }
|
||||
| kittycad::types::ModelingCmd::ImportFiles { .. }
|
||||
| kittycad::types::ModelingCmd::Mass { .. }
|
||||
| kittycad::types::ModelingCmd::Volume { .. }
|
||||
| kittycad::types::ModelingCmd::Density { .. }
|
||||
| kittycad::types::ModelingCmd::SurfaceArea { .. }
|
||||
| kittycad::types::ModelingCmd::CenterOfMass { .. }
|
||||
| kittycad::types::ModelingCmd::GetSketchModePlane { .. }
|
||||
| kittycad::types::ModelingCmd::EntityGetDistance { .. }
|
||||
| kittycad::types::ModelingCmd::EntityLinearPattern { .. }
|
||||
| kittycad::types::ModelingCmd::EntityCircularPattern { .. }
|
||||
| kittycad::types::ModelingCmd::Solid3DGetExtrusionFaceInfo { .. }) = cmd
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
true
|
||||
}
|
||||
|
@ -1010,6 +1010,7 @@ pub async fn execute(
|
||||
// Before we even start executing the program, set the units.
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::SetSceneUnits {
|
||||
@ -1221,6 +1222,9 @@ pub async fn execute(
|
||||
}
|
||||
}
|
||||
|
||||
// Flush the batch queue.
|
||||
ctx.engine.flush_batch(SourceRange::default()).await?;
|
||||
|
||||
Ok(memory.clone())
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,10 @@ impl Args {
|
||||
id: uuid::Uuid,
|
||||
cmd: kittycad::types::ModelingCmd,
|
||||
) -> Result<OkWebSocketResponseData, KclError> {
|
||||
self.ctx.engine.send_modeling_cmd(id, self.source_range, cmd).await
|
||||
self.ctx
|
||||
.engine
|
||||
.send_modeling_cmd(false, id, self.source_range, cmd)
|
||||
.await
|
||||
}
|
||||
|
||||
fn make_user_val_from_json(&self, j: serde_json::Value) -> Result<MemoryItem, KclError> {
|
||||
|
@ -21,9 +21,11 @@ async fn execute_and_snapshot(code: &str, units: kittycad::types::UnitLength) ->
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
|
||||
// Create the client.
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// uncomment to use a local server
|
||||
//client.set_base_url("http://system76-pc:8080/");
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// Set a local engine address if it's set.
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
@ -45,6 +47,7 @@ async fn execute_and_snapshot(code: &str, units: kittycad::types::UnitLength) ->
|
||||
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
kcl_lib::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -60,6 +63,7 @@ async fn execute_and_snapshot(code: &str, units: kittycad::types::UnitLength) ->
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
kcl_lib::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::TakeSnapshot {
|
||||
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 100 KiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 99 KiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
@ -25,7 +25,11 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid
|
||||
let token = std::env::var("KITTYCAD_API_TOKEN").expect("KITTYCAD_API_TOKEN not set");
|
||||
|
||||
// Create the client.
|
||||
let client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
let mut client = kittycad::Client::new_from_reqwest(token, http_client, ws_client);
|
||||
// Set a local engine address if it's set.
|
||||
if let Ok(addr) = std::env::var("LOCAL_ENGINE_ADDR") {
|
||||
client.set_base_url(addr);
|
||||
}
|
||||
|
||||
let ws = client
|
||||
.modeling()
|
||||
@ -49,6 +53,7 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid
|
||||
let plane_id = uuid::Uuid::new_v4();
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
plane_id,
|
||||
SourceRange::default(),
|
||||
ModelingCmd::MakePlane {
|
||||
@ -67,6 +72,7 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid
|
||||
// You can however get path info without sketch mode.
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
SourceRange::default(),
|
||||
ModelingCmd::SketchModeEnable {
|
||||
@ -82,6 +88,7 @@ async fn setup(code: &str, name: &str) -> Result<(ExecutorContext, Program, uuid
|
||||
// We can't get control points of an existing sketch without being in edit mode.
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
SourceRange::default(),
|
||||
ModelingCmd::EditModeEnter { target: sketch_id },
|
||||
|