Compare commits
	
		
			64 Commits
		
	
	
		
			pierremtb/
			...
			coredump-c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 2a4ff386e0 | |||
| 2be00f8f52 | |||
| 5d66fc496f | |||
| 764675d411 | |||
| 4482b0fee4 | |||
| a604660feb | |||
| 0465aa06d3 | |||
| 62302ccfda | |||
| 313e586510 | |||
| 0b9f707063 | |||
| fb7b0aadfb | |||
| cf54905539 | |||
| 2fb318b154 | |||
| 9366f68a88 | |||
| 6985678e25 | |||
| c56319fb74 | |||
| ec20e9752f | |||
| 88b94c985f | |||
| d455189cb1 | |||
| 27974dee04 | |||
| 51acd5d6bf | |||
| 48774ba8bf | |||
| 5a4834f37c | |||
| e30b634974 | |||
| 6c9d0378f0 | |||
| 717838c702 | |||
| a92acc68a8 | |||
| 0ca7095777 | |||
| 8ce3b32f75 | |||
| c0826690a1 | |||
| 1fa03a8d58 | |||
| 9ea92d5a6d | |||
| 81bf96d52f | |||
| 3bbd63eb5d | |||
| 2b0af61b09 | |||
| a671fcb128 | |||
| cbb5f67364 | |||
| 3a64f29ca6 | |||
| 4cbf2d19b5 | |||
| 64457cd2c2 | |||
| 4571ea4e08 | |||
| b586b38ad9 | |||
| 8766861d07 | |||
| abe70f4406 | |||
| a4452f775b | |||
| b06158ba4e | |||
| 7a42e9e868 | |||
| 4e856abbcb | |||
| fef8139a3e | |||
| b578a88808 | |||
| a33c15b667 | |||
| bdf1eef0d5 | |||
| 41d900ad93 | |||
| 5796ce02c3 | |||
| 229a89fb1d | |||
| 6343545496 | |||
| 779b7038dd | |||
| 10cbfddc41 | |||
| 958b68f06f | |||
| 522dfdcbcc | |||
| 0ac1cbfcf9 | |||
| 950f27ce2a | |||
| 62e6559177 | |||
| 8fbacd0363 | 
							
								
								
									
										1
									
								
								src-tauri/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								src-tauri/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -6016,6 +6016,7 @@ version = "8.1.0" | |||||||
| source = "git+https://github.com/Aleph-Alpha/ts-rs#f898578d80d3e2a54080c1c046c45f9eaa2435c3" | source = "git+https://github.com/Aleph-Alpha/ts-rs#f898578d80d3e2a54080c1c046c45f9eaa2435c3" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "chrono", |  "chrono", | ||||||
|  |  "serde_json", | ||||||
|  "thiserror", |  "thiserror", | ||||||
|  "ts-rs-macros", |  "ts-rs-macros", | ||||||
|  "url", |  "url", | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ import type { Program } from '../wasm-lib/kcl/bindings/Program' | |||||||
| import type { Token } from '../wasm-lib/kcl/bindings/Token' | import type { Token } from '../wasm-lib/kcl/bindings/Token' | ||||||
| import { Coords2d } from './std/sketch' | import { Coords2d } from './std/sketch' | ||||||
| import { fileSystemManager } from 'lang/std/fileSystemManager' | import { fileSystemManager } from 'lang/std/fileSystemManager' | ||||||
| import { AppInfo } from 'wasm-lib/kcl/bindings/AppInfo' | import { CoreDumpInfo } from 'wasm-lib/kcl/bindings/CoreDumpInfo' | ||||||
| import { CoreDumpManager } from 'lib/coredump' | import { CoreDumpManager } from 'lib/coredump' | ||||||
| import openWindow from 'lib/openWindow' | import openWindow from 'lib/openWindow' | ||||||
| import { DefaultPlanes } from 'wasm-lib/kcl/bindings/DefaultPlanes' | import { DefaultPlanes } from 'wasm-lib/kcl/bindings/DefaultPlanes' | ||||||
| @ -335,9 +335,9 @@ export function programMemoryInit(): ProgramMemory { | |||||||
| export async function coreDump( | export async function coreDump( | ||||||
|   coreDumpManager: CoreDumpManager, |   coreDumpManager: CoreDumpManager, | ||||||
|   openGithubIssue: boolean = false |   openGithubIssue: boolean = false | ||||||
| ): Promise<AppInfo> { | ): Promise<CoreDumpInfo> { | ||||||
|   try { |   try { | ||||||
|     const dump: AppInfo = await coredump(coreDumpManager) |     const dump: CoreDumpInfo = await coredump(coreDumpManager) | ||||||
|     if (openGithubIssue && dump.github_issue_url) { |     if (openGithubIssue && dump.github_issue_url) { | ||||||
|       openWindow(dump.github_issue_url) |       openWindow(dump.github_issue_url) | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -144,6 +144,282 @@ export class CoreDumpManager { | |||||||
|       }) |       }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   // Currently just a placeholder to begin loading singleton and xstate data into | ||||||
|  |   getClientState(): Promise<string> { | ||||||
|  |     /** | ||||||
|  |      * Deep clone a JavaScript Object | ||||||
|  |      * - NOTE: this function thows on parse errors from things like circular references | ||||||
|  |      * - It is also syncronous and could be more performant | ||||||
|  |      * - There is a whole rabbit hole to explore here if you like. | ||||||
|  |      * - This works for our use case. | ||||||
|  |      * @param {object} obj - The object to clone. | ||||||
|  |      */ | ||||||
|  |     const deepClone = (obj: any) => JSON.parse(JSON.stringify(obj)) | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Check if a function is private method | ||||||
|  |      */ | ||||||
|  |     const isPrivateMethod = (key: string) => { | ||||||
|  |       return key.length && key[0] === '_' | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     console.warn('CoreDump: Gathering client state') | ||||||
|  |  | ||||||
|  |     // Initialize the clientState object | ||||||
|  |     let clientState = { | ||||||
|  |       // singletons | ||||||
|  |       engine_command_manager: { | ||||||
|  |         artifact_map: {}, | ||||||
|  |         command_logs: [], | ||||||
|  |         engine_connection: { state: { type: '' } }, | ||||||
|  |         default_planes: {}, | ||||||
|  |         scene_command_artifacts: {}, | ||||||
|  |       }, | ||||||
|  |       kcl_manager: { | ||||||
|  |         ast: {}, | ||||||
|  |         kcl_errors: [], | ||||||
|  |       }, | ||||||
|  |       scene_infra: {}, | ||||||
|  |       scene_entities_manager: {}, | ||||||
|  |       editor_manager: {}, | ||||||
|  |       // xstate | ||||||
|  |       auth_machine: {}, | ||||||
|  |       command_bar_machine: {}, | ||||||
|  |       file_machine: {}, | ||||||
|  |       home_machine: {}, | ||||||
|  |       modeling_machine: {}, | ||||||
|  |       settings_machine: {}, | ||||||
|  |     } | ||||||
|  |     console.log('CoreDump: initialized clientState', clientState) | ||||||
|  |     console.info('CoreDump: globalThis.window', globalThis.window) | ||||||
|  |  | ||||||
|  |     try { | ||||||
|  |       // Singletons | ||||||
|  |  | ||||||
|  |       // engine_command_manager | ||||||
|  |       console.log('CoreDump: engineCommandManager', this.engineCommandManager) | ||||||
|  |  | ||||||
|  |       // artifact map - this.engineCommandManager.artifactMap | ||||||
|  |       if (this.engineCommandManager?.artifactMap) { | ||||||
|  |         console.log( | ||||||
|  |           'CoreDump: Engine Command Manager artifact map', | ||||||
|  |           this.engineCommandManager.artifactMap | ||||||
|  |         ) | ||||||
|  |         clientState.engine_command_manager.artifact_map = deepClone( | ||||||
|  |           this.engineCommandManager.artifactMap | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // command logs - this.engineCommandManager.commandLogs | ||||||
|  |       if (this.engineCommandManager?.commandLogs) { | ||||||
|  |         console.log( | ||||||
|  |           'CoreDump: Engine Command Manager command logs', | ||||||
|  |           this.engineCommandManager.commandLogs | ||||||
|  |         ) | ||||||
|  |         clientState.engine_command_manager.command_logs = deepClone( | ||||||
|  |           this.engineCommandManager.commandLogs | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // default planes - this.engineCommandManager.defaultPlanes | ||||||
|  |       if (this.engineCommandManager?.defaultPlanes) { | ||||||
|  |         console.log( | ||||||
|  |           'CoreDump: Engine Command Manager default planes', | ||||||
|  |           this.engineCommandManager.defaultPlanes | ||||||
|  |         ) | ||||||
|  |         clientState.engine_command_manager.default_planes = deepClone( | ||||||
|  |           this.engineCommandManager.defaultPlanes | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // engine connection state | ||||||
|  |       if (this.engineCommandManager?.engineConnection?.state) { | ||||||
|  |         clientState.engine_command_manager.engine_connection.state = | ||||||
|  |           this.engineCommandManager.engineConnection.state | ||||||
|  |         console.log( | ||||||
|  |           'CoreDump: Engine Command Manager engine connection state', | ||||||
|  |           this.engineCommandManager.engineConnection.state | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // in sequence - this.engineCommandManager.inSequence | ||||||
|  |       if (this.engineCommandManager?.inSequence) { | ||||||
|  |         console.log( | ||||||
|  |           'CoreDump: Engine Command Manager in sequence', | ||||||
|  |           this.engineCommandManager.inSequence | ||||||
|  |         ) | ||||||
|  |         clientState.engine_command_manager.in_sequence = | ||||||
|  |           this.engineCommandManager.inSequence | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // out sequence - this.engineCommandManager.outSequence | ||||||
|  |       if (this.engineCommandManager?.inSequence) { | ||||||
|  |         console.log( | ||||||
|  |           'CoreDump: Engine Command Manager out sequence', | ||||||
|  |           this.engineCommandManager.outSequence | ||||||
|  |         ) | ||||||
|  |         clientState.engine_command_manager.out_sequence = | ||||||
|  |           this.engineCommandManager.inSequence | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // scene command artifacts - this.engineCommandManager.sceneCommandArtifacts | ||||||
|  |       if (this.engineCommandManager?.sceneCommandArtifacts) { | ||||||
|  |         console.log( | ||||||
|  |           'CoreDump: Engine Command Manager scene command artifacts', | ||||||
|  |           this.engineCommandManager.sceneCommandArtifacts | ||||||
|  |         ) | ||||||
|  |         clientState.engine_command_manager.scene_command_artifacts = deepClone( | ||||||
|  |           this.engineCommandManager.sceneCommandArtifacts | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // KCL Manager - globalThis?.window?.kclManager | ||||||
|  |       const kclManager = globalThis?.window?.kclManager | ||||||
|  |       console.log('CoreDump: kclManager', kclManager) | ||||||
|  |  | ||||||
|  |       if (kclManager) { | ||||||
|  |         // KCL Manager AST | ||||||
|  |         console.log('CoreDump: KCL Manager AST', kclManager?.ast) | ||||||
|  |         if (kclManager?.ast) { | ||||||
|  |           clientState.kcl_manager.ast = deepClone(kclManager.ast) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // KCL Errors | ||||||
|  |         console.log('CoreDump: KCL Errors', kclManager?.kclErrors) | ||||||
|  |         if (kclManager?.kclErrors) { | ||||||
|  |           clientState.kcl_manager.kcl_errors = deepClone(kclManager.kclErrors) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // KCL isExecuting | ||||||
|  |         console.log('CoreDump: KCL isExecuting', kclManager?.isExecuting) | ||||||
|  |         if (kclManager?.isExecuting) { | ||||||
|  |           clientState.kcl_manager.isExecuting = kclManager.isExecuting | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // KCL logs | ||||||
|  |         console.log('CoreDump: KCL logs', kclManager?.logs) | ||||||
|  |         if (kclManager?.logs) { | ||||||
|  |           clientState.kcl_manager.logs = deepClone(kclManager.logs) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // KCL programMemory | ||||||
|  |         console.log('CoreDump: KCL programMemory', kclManager?.programMemory) | ||||||
|  |         if (kclManager?.programMemory) { | ||||||
|  |           clientState.kcl_manager.programMemory = deepClone( | ||||||
|  |             kclManager.programMemory | ||||||
|  |           ) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // KCL wasmInitFailed | ||||||
|  |         console.log('CoreDump: KCL wasmInitFailed', kclManager?.wasmInitFailed) | ||||||
|  |         if (kclManager?.wasmInitFailed) { | ||||||
|  |           clientState.kcl_manager.wasmInitFailed = kclManager.wasmInitFailed | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // Scene Infra - globalThis?.window?.sceneInfra | ||||||
|  |       const sceneInfra = globalThis?.window?.sceneInfra | ||||||
|  |       console.log('CoreDump: Scene Infra', sceneInfra) | ||||||
|  |  | ||||||
|  |       if (sceneInfra) { | ||||||
|  |         const sceneInfraSkipKeys = ['camControls'] | ||||||
|  |         const sceneInfraKeys = Object.keys(sceneInfra) | ||||||
|  |           .sort() | ||||||
|  |           .filter((entry) => { | ||||||
|  |             return ( | ||||||
|  |               typeof sceneInfra[entry] !== 'function' && | ||||||
|  |               !sceneInfraSkipKeys.includes(entry) | ||||||
|  |             ) | ||||||
|  |           }) | ||||||
|  |  | ||||||
|  |         console.log('CoreDump: Scene Infra keys', sceneInfraKeys) | ||||||
|  |         sceneInfraKeys.forEach((key: string) => { | ||||||
|  |           console.log('CoreDump: Scene Infra', key, sceneInfra[key]) | ||||||
|  |           try { | ||||||
|  |             clientState.scene_infra[key] = sceneInfra[key] | ||||||
|  |           } catch (error) { | ||||||
|  |             console.error( | ||||||
|  |               'CoreDump: unable to parse Scene Infra ' + key + ' data due to ', | ||||||
|  |               error | ||||||
|  |             ) | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // Scene Entities Manager - globalThis?.window?.sceneEntitiesManager | ||||||
|  |       const sceneEntitiesManager = globalThis?.window?.sceneEntitiesManager | ||||||
|  |       console.log('CoreDump: sceneEntitiesManager', sceneEntitiesManager) | ||||||
|  |  | ||||||
|  |       if (sceneEntitiesManager) { | ||||||
|  |         // Scene Entities Manager active segments | ||||||
|  |         console.log( | ||||||
|  |           'CoreDump: Scene Entities Manager active segments', | ||||||
|  |           sceneEntitiesManager?.activeSegments | ||||||
|  |         ) | ||||||
|  |         if (sceneEntitiesManager?.activeSegments) { | ||||||
|  |           clientState.scene_entities_manager.activeSegments = deepClone( | ||||||
|  |             sceneEntitiesManager.activeSegments | ||||||
|  |           ) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // Editor Manager - globalThis?.window?.editorManager | ||||||
|  |       const editorManager = globalThis?.window?.editorManager | ||||||
|  |       console.log('CoreDump: editorManager', editorManager) | ||||||
|  |  | ||||||
|  |       if (editorManager) { | ||||||
|  |         const editorManagerSkipKeys = ['camControls'] | ||||||
|  |         const editorManagerKeys = Object.keys(editorManager) | ||||||
|  |           .sort() | ||||||
|  |           .filter((entry) => { | ||||||
|  |             return ( | ||||||
|  |               typeof editorManager[entry] !== 'function' && | ||||||
|  |               !isPrivateMethod(entry) && | ||||||
|  |               !editorManagerSkipKeys.includes(entry) | ||||||
|  |             ) | ||||||
|  |           }) | ||||||
|  |  | ||||||
|  |         console.log('CoreDump: Editor Manager keys', editorManagerKeys) | ||||||
|  |         editorManagerKeys.forEach((key: string) => { | ||||||
|  |           console.log('CoreDump: Editor Manager', key, editorManager[key]) | ||||||
|  |           try { | ||||||
|  |             clientState.editor_manager[key] = deepClone(editorManager[key]) | ||||||
|  |           } catch (error) { | ||||||
|  |             console.error( | ||||||
|  |               'CoreDump: unable to parse Editor Manager ' + | ||||||
|  |                 key + | ||||||
|  |                 ' data due to ', | ||||||
|  |               error | ||||||
|  |             ) | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // enableMousePositionLogs - Not coredumped | ||||||
|  |       // See https://github.com/KittyCAD/modeling-app/issues/2338#issuecomment-2136441998 | ||||||
|  |       console.log( | ||||||
|  |         'CoreDump: enableMousePositionLogs [not coredumped]', | ||||||
|  |         globalThis?.window?.enableMousePositionLogs | ||||||
|  |       ) | ||||||
|  |  | ||||||
|  |       // XState Machines | ||||||
|  |       console.log( | ||||||
|  |         'CoreDump: xstate services', | ||||||
|  |         globalThis?.window?.__xstate__?.services | ||||||
|  |       ) | ||||||
|  |  | ||||||
|  |       console.log('CoreDump: final clientState', clientState) | ||||||
|  |  | ||||||
|  |       const clientStateJson = JSON.stringify(clientState) | ||||||
|  |       console.log('CoreDump: final clientState JSON', clientStateJson) | ||||||
|  |  | ||||||
|  |       return Promise.resolve(clientStateJson) | ||||||
|  |     } catch (error) { | ||||||
|  |       console.error('CoreDump: unable to return data due to ', error) | ||||||
|  |       return Promise.reject(JSON.stringify(error)) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   // Return a data URL (png format) of the screenshot of the current page. |   // Return a data URL (png format) of the screenshot of the current page. | ||||||
|   screenshot(): Promise<string> { |   screenshot(): Promise<string> { | ||||||
|     return screenshot(this.htmlRef) |     return screenshot(this.htmlRef) | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								src/wasm-lib/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								src/wasm-lib/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -3161,6 +3161,7 @@ version = "8.1.0" | |||||||
| source = "git+https://github.com/Aleph-Alpha/ts-rs#be0349d5fb07a8ccab713887a61e90e3bc773c7a" | source = "git+https://github.com/Aleph-Alpha/ts-rs#be0349d5fb07a8ccab713887a61e90e3bc773c7a" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "chrono", |  "chrono", | ||||||
|  |  "serde_json", | ||||||
|  "thiserror", |  "thiserror", | ||||||
|  "ts-rs-macros", |  "ts-rs-macros", | ||||||
|  "url", |  "url", | ||||||
|  | |||||||
| @ -37,7 +37,7 @@ sha2 = "0.10.8" | |||||||
| thiserror = "1.0.61" | thiserror = "1.0.61" | ||||||
| toml = "0.8.14" | toml = "0.8.14" | ||||||
| # TODO: change this to a cargo release once 8.1.1 comes out | # TODO: change this to a cargo release once 8.1.1 comes out | ||||||
| ts-rs = { git = "https://github.com/Aleph-Alpha/ts-rs", features = ["uuid-impl", "url-impl", "chrono-impl", "no-serde-warnings"] } | ts-rs = { git = "https://github.com/Aleph-Alpha/ts-rs", features = ["uuid-impl", "url-impl", "chrono-impl", "no-serde-warnings", "serde-json-impl"] } | ||||||
| url = { version = "2.5.0", features = ["serde"] } | url = { version = "2.5.0", features = ["serde"] } | ||||||
| uuid = { version = "1.8.0", features = ["v4", "js", "serde"] } | uuid = { version = "1.8.0", features = ["v4", "js", "serde"] } | ||||||
| validator = { version = "0.18.1", features = ["derive"] } | validator = { version = "0.18.1", features = ["derive"] } | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ | |||||||
| use anyhow::Result; | use anyhow::Result; | ||||||
|  |  | ||||||
| use crate::coredump::CoreDump; | use crate::coredump::CoreDump; | ||||||
|  | use serde_json::Value as JValue; | ||||||
|  |  | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| pub struct CoreDumper {} | pub struct CoreDumper {} | ||||||
| @ -55,6 +56,10 @@ impl CoreDump for CoreDumper { | |||||||
|         Ok(crate::coredump::WebrtcStats::default()) |         Ok(crate::coredump::WebrtcStats::default()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async fn get_client_state(&self) -> Result<JValue> { | ||||||
|  |         Ok(JValue::default()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     async fn screenshot(&self) -> Result<String> { |     async fn screenshot(&self) -> Result<String> { | ||||||
|         // Take a screenshot of the engine. |         // Take a screenshot of the engine. | ||||||
|         todo!() |         todo!() | ||||||
|  | |||||||
| @ -9,6 +9,9 @@ use anyhow::Result; | |||||||
| use base64::Engine; | use base64::Engine; | ||||||
| use schemars::JsonSchema; | use schemars::JsonSchema; | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
|  | /// "Value" would be OK. This is imported as "JValue" throughout the rest of this crate. | ||||||
|  | use serde_json::Value as JValue; | ||||||
|  | use uuid::Uuid; | ||||||
|  |  | ||||||
| #[async_trait::async_trait(?Send)] | #[async_trait::async_trait(?Send)] | ||||||
| pub trait CoreDump: Clone { | pub trait CoreDump: Clone { | ||||||
| @ -27,6 +30,8 @@ pub trait CoreDump: Clone { | |||||||
|  |  | ||||||
|     async fn get_webrtc_stats(&self) -> Result<WebrtcStats>; |     async fn get_webrtc_stats(&self) -> Result<WebrtcStats>; | ||||||
|  |  | ||||||
|  |     async fn get_client_state(&self) -> Result<JValue>; | ||||||
|  |  | ||||||
|     /// Return a screenshot of the app. |     /// Return a screenshot of the app. | ||||||
|     async fn screenshot(&self) -> Result<String>; |     async fn screenshot(&self) -> Result<String>; | ||||||
|  |  | ||||||
| @ -53,19 +58,21 @@ pub trait CoreDump: Clone { | |||||||
|             .map_err(|e| anyhow::anyhow!(e.to_string()))?; |             .map_err(|e| anyhow::anyhow!(e.to_string()))?; | ||||||
|  |  | ||||||
|         if links.is_empty() { |         if links.is_empty() { | ||||||
|             anyhow::bail!("Failed to upload screenshot"); |             anyhow::bail!("Failed to upload coredump"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Ok(links[0].clone()) |         Ok(links[0].clone()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Dump the app info. |     /// Dump the app info. | ||||||
|     async fn dump(&self) -> Result<AppInfo> { |     async fn dump(&self) -> Result<CoreDumpInfo> { | ||||||
|         let webrtc_stats = self.get_webrtc_stats().await?; |         let os: OsInfo = self.os().await?; | ||||||
|         let os = self.os().await?; |         let webrtc_stats: WebrtcStats = self.get_webrtc_stats().await?; | ||||||
|         let screenshot_url = self.upload_screenshot().await?; |         let client_state: JValue = self.get_client_state().await?; | ||||||
|  |         let screenshot_url: String = self.upload_screenshot().await?; | ||||||
|  |  | ||||||
|         let mut app_info = AppInfo { |         let mut core_dump_info: CoreDumpInfo = CoreDumpInfo { | ||||||
|  |             id: uuid::Uuid::new_v4(), | ||||||
|             version: self.version()?, |             version: self.version()?, | ||||||
|             git_rev: git_rev::try_revision_string!().map_or_else(|| "unknown".to_string(), |s| s.to_string()), |             git_rev: git_rev::try_revision_string!().map_or_else(|| "unknown".to_string(), |s| s.to_string()), | ||||||
|             timestamp: chrono::Utc::now(), |             timestamp: chrono::Utc::now(), | ||||||
| @ -74,18 +81,48 @@ pub trait CoreDump: Clone { | |||||||
|             webrtc_stats, |             webrtc_stats, | ||||||
|             github_issue_url: None, |             github_issue_url: None, | ||||||
|             pool: self.pool()?, |             pool: self.pool()?, | ||||||
|  |             client_state, | ||||||
|         }; |         }; | ||||||
|         app_info.set_github_issue_url(&screenshot_url)?; |  | ||||||
|  |  | ||||||
|         Ok(app_info) |         // (Re)Create the zoo client. | ||||||
|  |         let mut zooClient = kittycad::Client::new(self.token()?); | ||||||
|  |         zooClient.set_base_url(&self.base_api_url()?); | ||||||
|  |  | ||||||
|  |         let json = serde_json::to_string_pretty(&core_dump_info).unwrap(); | ||||||
|  |  | ||||||
|  |         // Upload the coredump. | ||||||
|  |         let result: Vec<String> = zooClient | ||||||
|  |             .meta() | ||||||
|  |             .create_debug_uploads(vec![kittycad::types::multipart::Attachment { | ||||||
|  |                 name: "".to_string(), | ||||||
|  |                 filename: Some(format!(r#"modeling-app/coredump-{}.json)"#, core_dump_info.id,)), | ||||||
|  |                 content_type: Some("application/json".to_string()), | ||||||
|  |                 data: json.into(), | ||||||
|  |             }]) | ||||||
|  |             .await?; | ||||||
|  |  | ||||||
|  |         if result.is_empty() { | ||||||
|  |             anyhow::bail!("Failed to upload coredump"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         println!("{:?}", result); | ||||||
|  |          | ||||||
|  |         let coredump_url: String = result[0].clone(); | ||||||
|  |  | ||||||
|  |         core_dump_info.set_github_issue_url(&screenshot_url, &coredump_url)?; | ||||||
|  |  | ||||||
|  |         Ok(core_dump_info) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /// The app info structure. | /// The app info structure. | ||||||
|  | /// The Core Dump Info structure. | ||||||
| #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||||
| #[ts(export)] | #[ts(export)] | ||||||
| #[serde(rename_all = "snake_case")] | #[serde(rename_all = "snake_case")] | ||||||
| pub struct AppInfo { | pub struct CoreDumpInfo { | ||||||
|  |     /// The unique id for the coredump - this helps correlate screenshot with coredump data | ||||||
|  |     pub id: Uuid, | ||||||
|     /// The version of the app. |     /// The version of the app. | ||||||
|     pub version: String, |     pub version: String, | ||||||
|     /// The git revision of the app. |     /// The git revision of the app. | ||||||
| @ -109,11 +146,14 @@ pub struct AppInfo { | |||||||
|  |  | ||||||
|     /// Engine pool the client is connected to. |     /// Engine pool the client is connected to. | ||||||
|     pub pool: String, |     pub pool: String, | ||||||
|  |  | ||||||
|  |     /// The client state (singletons and xstate) | ||||||
|  |     pub client_state: JValue, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl AppInfo { | impl CoreDumpInfo { | ||||||
|     /// Set the github issue url. |     /// Set the github issue url. | ||||||
|     pub fn set_github_issue_url(&mut self, screenshot_url: &str) -> Result<()> { |     pub fn set_github_issue_url(&mut self, screenshot_url: &str, coredump_url: &str) -> Result<()> { | ||||||
|         let tauri_or_browser_label = if self.tauri { "tauri" } else { "browser" }; |         let tauri_or_browser_label = if self.tauri { "tauri" } else { "browser" }; | ||||||
|         let labels = ["coredump", "bug", tauri_or_browser_label]; |         let labels = ["coredump", "bug", tauri_or_browser_label]; | ||||||
|         let body = format!( |         let body = format!( | ||||||
| @ -121,16 +161,11 @@ impl AppInfo { | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| <details> |  | ||||||
| <summary><b>Core Dump</b></summary> | <summary><b>Core Dump</b></summary> | ||||||
|  |  | ||||||
| ```json |  | ||||||
| {} |  | ||||||
| ``` |  | ||||||
| </details> |  | ||||||
| "#, | "#, | ||||||
|             screenshot_url, |             screenshot_url, coredump_url | ||||||
|             serde_json::to_string_pretty(&self)? |  | ||||||
|         ); |         ); | ||||||
|         let urlencoded: String = form_urlencoded::byte_serialize(body.as_bytes()).collect(); |         let urlencoded: String = form_urlencoded::byte_serialize(body.as_bytes()).collect(); | ||||||
|  |  | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ use anyhow::Result; | |||||||
| use wasm_bindgen::prelude::wasm_bindgen; | use wasm_bindgen::prelude::wasm_bindgen; | ||||||
|  |  | ||||||
| use crate::{coredump::CoreDump, wasm::JsFuture}; | use crate::{coredump::CoreDump, wasm::JsFuture}; | ||||||
|  | use serde_json::Value as JValue; | ||||||
|  |  | ||||||
| #[wasm_bindgen(module = "/../../lib/coredump.ts")] | #[wasm_bindgen(module = "/../../lib/coredump.ts")] | ||||||
| extern "C" { | extern "C" { | ||||||
| @ -31,6 +32,9 @@ extern "C" { | |||||||
|     #[wasm_bindgen(method, js_name = getWebrtcStats, catch)] |     #[wasm_bindgen(method, js_name = getWebrtcStats, catch)] | ||||||
|     fn get_webrtc_stats(this: &CoreDumpManager) -> Result<js_sys::Promise, js_sys::Error>; |     fn get_webrtc_stats(this: &CoreDumpManager) -> Result<js_sys::Promise, js_sys::Error>; | ||||||
|  |  | ||||||
|  |     #[wasm_bindgen(method, js_name = getClientState, catch)] | ||||||
|  |     fn get_client_state(this: &CoreDumpManager) -> Result<js_sys::Promise, js_sys::Error>; | ||||||
|  |  | ||||||
|     #[wasm_bindgen(method, js_name = screenshot, catch)] |     #[wasm_bindgen(method, js_name = screenshot, catch)] | ||||||
|     fn screenshot(this: &CoreDumpManager) -> Result<js_sys::Promise, js_sys::Error>; |     fn screenshot(this: &CoreDumpManager) -> Result<js_sys::Promise, js_sys::Error>; | ||||||
| } | } | ||||||
| @ -123,6 +127,27 @@ impl CoreDump for CoreDumper { | |||||||
|         Ok(stats) |         Ok(stats) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async fn get_client_state(&self) -> Result<JValue> { | ||||||
|  |         let promise = self | ||||||
|  |             .manager | ||||||
|  |             .get_client_state() | ||||||
|  |             .map_err(|e| anyhow::anyhow!("Failed to get promise from get client state: {:?}", e))?; | ||||||
|  |  | ||||||
|  |         let value = JsFuture::from(promise) | ||||||
|  |             .await | ||||||
|  |             .map_err(|e| anyhow::anyhow!("Failed to get response from client state: {:?}", e))?; | ||||||
|  |  | ||||||
|  |         // Parse the value as a string. | ||||||
|  |         let s = value | ||||||
|  |             .as_string() | ||||||
|  |             .ok_or_else(|| anyhow::anyhow!("Failed to get string from response from client stat: `{:?}`", value))?; | ||||||
|  |  | ||||||
|  |         let client_state: JValue = | ||||||
|  |             serde_json::from_str(&s).map_err(|e| anyhow::anyhow!("Failed to parse client state: {:?}", e))?; | ||||||
|  |  | ||||||
|  |         Ok(client_state) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     async fn screenshot(&self) -> Result<String> { |     async fn screenshot(&self) -> Result<String> { | ||||||
|         let promise = self |         let promise = self | ||||||
|             .manager |             .manager | ||||||
|  | |||||||
							
								
								
									
										316
									
								
								src/wasm-lib/tests/cordump/inputs/coredump.fixture.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								src/wasm-lib/tests/cordump/inputs/coredump.fixture.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,316 @@ | |||||||
|  | { | ||||||
|  |   "version": "0.20.1", | ||||||
|  |   "git_rev": "3a05211d306ca045ace2e7bf10b7f8138e1daad5", | ||||||
|  |   "timestamp": "2024-05-07T20:06:34.655Z", | ||||||
|  |   "tauri": false, | ||||||
|  |   "os": { | ||||||
|  |     "platform": "Mac OS", | ||||||
|  |     "version": "10.15.7", | ||||||
|  |     "browser": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" | ||||||
|  |   }, | ||||||
|  |   "webrtc_stats": { | ||||||
|  |     "packets_lost": 0, | ||||||
|  |     "frames_received": 672, | ||||||
|  |     "frame_width": 1440.0, | ||||||
|  |     "frame_height": 712.0, | ||||||
|  |     "frame_rate": 58.0, | ||||||
|  |     "key_frames_decoded": 7, | ||||||
|  |     "frames_dropped": 77, | ||||||
|  |     "pause_count": 0, | ||||||
|  |     "total_pauses_duration": 0.0, | ||||||
|  |     "freeze_count": 12, | ||||||
|  |     "total_freezes_duration": 3.057, | ||||||
|  |     "pli_count": 6, | ||||||
|  |     "jitter": 0.011 | ||||||
|  |   }, | ||||||
|  |   "pool": "", | ||||||
|  |   "client_state": { | ||||||
|  |     "engine_command_manager": { | ||||||
|  |       "artifact_map": { | ||||||
|  |         "ac7a8c52-7437-42e6-ae2a-25c54d0b4a16": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "make_plane", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "79cc6dfc-7205-41b2-922f-0d0279f5a30d", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "83a2e866-d8e1-47d9-afae-d55a64cd5b40": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "plane_set_color", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "79cc6dfc-7205-41b2-922f-0d0279f5a30d", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "c92d7e84-a03e-456e-aad0-3e302ae0ffb6": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "make_plane", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "79cc6dfc-7205-41b2-922f-0d0279f5a30d", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "a9abb9b8-54b1-4042-8ab3-e67c7ddb4cb3": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "plane_set_color", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "79cc6dfc-7205-41b2-922f-0d0279f5a30d", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "bafb884d-ee93-48f5-a667-91d1bdb8178a": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "make_plane", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "79cc6dfc-7205-41b2-922f-0d0279f5a30d", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "6b7f539b-c4ca-4e62-a971-147e1abaca7b": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "plane_set_color", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "79cc6dfc-7205-41b2-922f-0d0279f5a30d", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "6ddaaaa3-b080-4cb3-b08e-8fe277312ccc": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "make_plane", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "79cc6dfc-7205-41b2-922f-0d0279f5a30d", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "f1ef28b0-49b3-45f8-852d-772648149785": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "make_plane", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "79cc6dfc-7205-41b2-922f-0d0279f5a30d", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "7c532be8-f07d-456b-8643-53808df86823": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "make_plane", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "79cc6dfc-7205-41b2-922f-0d0279f5a30d", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "cf38f826-6d15-45f4-9c64-a6e9e4909e75": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "make_plane", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "91f1be72-4267-40a4-9923-9c5b5a0ec29c", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "d69e6248-9e0f-4bc8-bc6e-d995931e8886": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "plane_set_color", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "91f1be72-4267-40a4-9923-9c5b5a0ec29c", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "cdb44075-ac6d-4626-b321-26d022f5f7f0": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "make_plane", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "91f1be72-4267-40a4-9923-9c5b5a0ec29c", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "44f81391-0f2d-49f3-92b9-7dfc8446d571": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "plane_set_color", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "91f1be72-4267-40a4-9923-9c5b5a0ec29c", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "7b893ecf-8887-49c3-b978-392813d5f625": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "make_plane", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "91f1be72-4267-40a4-9923-9c5b5a0ec29c", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "61247d28-04ba-4768-85b0-fbc582151dbd": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "plane_set_color", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "91f1be72-4267-40a4-9923-9c5b5a0ec29c", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "1318f5af-76a9-4161-9f6a-d410831fd098": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "make_plane", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "91f1be72-4267-40a4-9923-9c5b5a0ec29c", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "908d264c-5989-4030-b2f4-5dfb52fda71a": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "make_plane", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "91f1be72-4267-40a4-9923-9c5b5a0ec29c", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "0de4c253-ee21-4385-93bd-b93264f7eb60": { | ||||||
|  |           "type": "result", | ||||||
|  |           "range": [0, 0], | ||||||
|  |           "pathToNode": [], | ||||||
|  |           "commandType": "make_plane", | ||||||
|  |           "data": { "type": "empty" }, | ||||||
|  |           "raw": { | ||||||
|  |             "success": true, | ||||||
|  |             "request_id": "91f1be72-4267-40a4-9923-9c5b5a0ec29c", | ||||||
|  |             "resp": { | ||||||
|  |               "type": "modeling", | ||||||
|  |               "data": { "modeling_response": { "type": "empty" } } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "engine_connection": { | ||||||
|  |         "state": { | ||||||
|  |           "type": "connection-established" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "kcl_manager": {}, | ||||||
|  |     "scene_infra": {}, | ||||||
|  |     "auth_machine": {}, | ||||||
|  |     "command_bar_machine": {}, | ||||||
|  |     "file_machine": {}, | ||||||
|  |     "home_machine": {}, | ||||||
|  |     "modeling_machine": {}, | ||||||
|  |     "settings_machine": {} | ||||||
|  |   } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	