Compare commits
	
		
			64 Commits
		
	
	
		
			franknoiro
			...
			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" | ||||
| dependencies = [ | ||||
|  "chrono", | ||||
|  "serde_json", | ||||
|  "thiserror", | ||||
|  "ts-rs-macros", | ||||
|  "url", | ||||
|  | ||||
| @ -25,7 +25,7 @@ import type { Program } from '../wasm-lib/kcl/bindings/Program' | ||||
| import type { Token } from '../wasm-lib/kcl/bindings/Token' | ||||
| import { Coords2d } from './std/sketch' | ||||
| 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 openWindow from 'lib/openWindow' | ||||
| import { DefaultPlanes } from 'wasm-lib/kcl/bindings/DefaultPlanes' | ||||
| @ -335,9 +335,9 @@ export function programMemoryInit(): ProgramMemory { | ||||
| export async function coreDump( | ||||
|   coreDumpManager: CoreDumpManager, | ||||
|   openGithubIssue: boolean = false | ||||
| ): Promise<AppInfo> { | ||||
| ): Promise<CoreDumpInfo> { | ||||
|   try { | ||||
|     const dump: AppInfo = await coredump(coreDumpManager) | ||||
|     const dump: CoreDumpInfo = await coredump(coreDumpManager) | ||||
|     if (openGithubIssue && 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. | ||||
|   screenshot(): Promise<string> { | ||||
|     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" | ||||
| dependencies = [ | ||||
|  "chrono", | ||||
|  "serde_json", | ||||
|  "thiserror", | ||||
|  "ts-rs-macros", | ||||
|  "url", | ||||
|  | ||||
| @ -37,7 +37,7 @@ sha2 = "0.10.8" | ||||
| thiserror = "1.0.61" | ||||
| toml = "0.8.14" | ||||
| # 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"] } | ||||
| uuid = { version = "1.8.0", features = ["v4", "js", "serde"] } | ||||
| validator = { version = "0.18.1", features = ["derive"] } | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| use anyhow::Result; | ||||
|  | ||||
| use crate::coredump::CoreDump; | ||||
| use serde_json::Value as JValue; | ||||
|  | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct CoreDumper {} | ||||
| @ -55,6 +56,10 @@ impl CoreDump for CoreDumper { | ||||
|         Ok(crate::coredump::WebrtcStats::default()) | ||||
|     } | ||||
|  | ||||
|     async fn get_client_state(&self) -> Result<JValue> { | ||||
|         Ok(JValue::default()) | ||||
|     } | ||||
|  | ||||
|     async fn screenshot(&self) -> Result<String> { | ||||
|         // Take a screenshot of the engine. | ||||
|         todo!() | ||||
|  | ||||
| @ -9,6 +9,9 @@ use anyhow::Result; | ||||
| use base64::Engine; | ||||
| use schemars::JsonSchema; | ||||
| 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)] | ||||
| pub trait CoreDump: Clone { | ||||
| @ -27,6 +30,8 @@ pub trait CoreDump: Clone { | ||||
|  | ||||
|     async fn get_webrtc_stats(&self) -> Result<WebrtcStats>; | ||||
|  | ||||
|     async fn get_client_state(&self) -> Result<JValue>; | ||||
|  | ||||
|     /// Return a screenshot of the app. | ||||
|     async fn screenshot(&self) -> Result<String>; | ||||
|  | ||||
| @ -53,19 +58,21 @@ pub trait CoreDump: Clone { | ||||
|             .map_err(|e| anyhow::anyhow!(e.to_string()))?; | ||||
|  | ||||
|         if links.is_empty() { | ||||
|             anyhow::bail!("Failed to upload screenshot"); | ||||
|             anyhow::bail!("Failed to upload coredump"); | ||||
|         } | ||||
|  | ||||
|         Ok(links[0].clone()) | ||||
|     } | ||||
|  | ||||
|     /// Dump the app info. | ||||
|     async fn dump(&self) -> Result<AppInfo> { | ||||
|         let webrtc_stats = self.get_webrtc_stats().await?; | ||||
|         let os = self.os().await?; | ||||
|         let screenshot_url = self.upload_screenshot().await?; | ||||
|     async fn dump(&self) -> Result<CoreDumpInfo> { | ||||
|         let os: OsInfo = self.os().await?; | ||||
|         let webrtc_stats: WebrtcStats = self.get_webrtc_stats().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()?, | ||||
|             git_rev: git_rev::try_revision_string!().map_or_else(|| "unknown".to_string(), |s| s.to_string()), | ||||
|             timestamp: chrono::Utc::now(), | ||||
| @ -74,18 +81,48 @@ pub trait CoreDump: Clone { | ||||
|             webrtc_stats, | ||||
|             github_issue_url: None, | ||||
|             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 Core Dump Info structure. | ||||
| #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] | ||||
| #[ts(export)] | ||||
| #[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. | ||||
|     pub version: String, | ||||
|     /// The git revision of the app. | ||||
| @ -109,11 +146,14 @@ pub struct AppInfo { | ||||
|  | ||||
|     /// Engine pool the client is connected to. | ||||
|     pub pool: String, | ||||
|  | ||||
|     /// The client state (singletons and xstate) | ||||
|     pub client_state: JValue, | ||||
| } | ||||
|  | ||||
| impl AppInfo { | ||||
| impl CoreDumpInfo { | ||||
|     /// 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 labels = ["coredump", "bug", tauri_or_browser_label]; | ||||
|         let body = format!( | ||||
| @ -121,16 +161,11 @@ impl AppInfo { | ||||
|  | ||||
|  | ||||
|  | ||||
| <details> | ||||
| <summary><b>Core Dump</b></summary> | ||||
|  | ||||
| ```json | ||||
| {} | ||||
| ``` | ||||
| </details> | ||||
|  | ||||
| "#, | ||||
|             screenshot_url, | ||||
|             serde_json::to_string_pretty(&self)? | ||||
|             screenshot_url, coredump_url | ||||
|         ); | ||||
|         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 crate::{coredump::CoreDump, wasm::JsFuture}; | ||||
| use serde_json::Value as JValue; | ||||
|  | ||||
| #[wasm_bindgen(module = "/../../lib/coredump.ts")] | ||||
| extern "C" { | ||||
| @ -31,6 +32,9 @@ extern "C" { | ||||
|     #[wasm_bindgen(method, js_name = getWebrtcStats, catch)] | ||||
|     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)] | ||||
|     fn screenshot(this: &CoreDumpManager) -> Result<js_sys::Promise, js_sys::Error>; | ||||
| } | ||||
| @ -123,6 +127,27 @@ impl CoreDump for CoreDumper { | ||||
|         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> { | ||||
|         let promise = self | ||||
|             .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
	