Compare commits

...

64 Commits

Author SHA1 Message Date
2a4ff386e0 Merge branch 'main' into coredump-clientstate 2024-06-10 18:21:14 -07:00
2be00f8f52 Merge branch 'main' into coredump-clientstate 2024-06-03 11:14:29 -07:00
5d66fc496f Merge branch 'main' into coredump-clientstate 2024-05-31 10:31:46 -07:00
764675d411 Merge branch 'main' into coredump-clientstate 2024-05-30 14:22:03 -07:00
4482b0fee4 Hoist upload_coredump to resolve scoping issues 2024-05-30 14:21:37 -07:00
a604660feb Revert to original state
I added a bunch of structs to be able to implement clientstate, but then was able to resolve these by upgrading ts-rs. The import statement had a lot of entries in the intermediate state. This reverts to the prior state in the codebase. No need for a reformatting change.
2024-05-30 14:11:52 -07:00
0465aa06d3 Merge branch 'main' into coredump-clientstate 2024-05-29 22:44:36 -07:00
62302ccfda WIP coredump json upload
I need @paultag or someone to help guide me through passing the coredump around properly.
2024-05-29 22:42:11 -07:00
313e586510 Remove window.Zoo for now
We're going to come back and do the xstate state capture after the update to xstate 5 which will provide a native api for both accessing xstate state and restoring state, which will be useful for debugging.
2024-05-29 22:40:28 -07:00
0b9f707063 WIP Upload json 2024-05-29 17:32:45 -07:00
fb7b0aadfb prettier fmt coredump.ts 2024-05-29 17:29:09 -07:00
cf54905539 prettier fmt 2024-05-29 17:28:30 -07:00
2fb318b154 Attach Zoo to window 2024-05-29 12:30:23 -07:00
9366f68a88 window.Zoo 2024-05-29 12:24:46 -07:00
6985678e25 Editor Manager 2024-05-29 12:24:34 -07:00
c56319fb74 Engine Command Manage console.log
Make coredump console log output more readable and traceable.
2024-05-29 09:33:39 -07:00
ec20e9752f Rust gimme JSON
This brings the code back to my original intent and strategy when I started building out this solution: gather all the JSON we may need under `client_state` and pass it back. 🎉
2024-05-29 09:17:04 -07:00
88b94c985f Finish KCL Manager coredump 2024-05-28 20:29:00 -07:00
d455189cb1 Simplify kcl_manager in Rust
MOAR JSON
2024-05-28 20:28:04 -07:00
27974dee04 Simplify XState representation in Rust 2024-05-28 19:54:37 -07:00
51acd5d6bf Simplify ModelingMachine expectations in Rust 2024-05-28 18:04:40 -07:00
48774ba8bf Capturing Scene Infra in CoreDump
️ Using JavaScript 
2024-05-28 13:31:43 -07:00
5a4834f37c More serde_json::Value less predefined struct 2024-05-28 12:16:17 -07:00
e30b634974 Add kclManager AST and kclErrors 2024-05-28 11:44:41 -07:00
6c9d0378f0 Update Cargo.lock 2024-05-28 09:24:54 -07:00
717838c702 Merge branch 'main' into coredump-clientstate 2024-05-28 09:24:46 -07:00
a92acc68a8 TODO? more singletons
Should we log anything from these?
2024-05-27 23:45:04 -07:00
0ca7095777 Gather KCL Manager info for CoreDump 2024-05-27 23:44:00 -07:00
8ce3b32f75 Update Cargo.lock 2024-05-27 23:42:01 -07:00
c0826690a1 Merge branch 'main' into coredump-clientstate 2024-05-27 15:47:25 -07:00
1fa03a8d58 Output clientState as JSON 2024-05-24 00:39:48 -07:00
9ea92d5a6d coredump engine command manager
Complete?!?
2024-05-24 00:22:13 -07:00
81bf96d52f Update Cargo.lock 2024-05-23 22:51:56 -07:00
3bbd63eb5d Merge branch 'main' into coredump-clientstate 2024-05-23 22:44:46 -07:00
2b0af61b09 deepClone types 2024-05-23 22:38:45 -07:00
a671fcb128 fmt 2024-05-23 19:07:21 -07:00
cbb5f67364 Remove token debug
Not sure why I committed this anyway
2024-05-23 19:07:21 -07:00
3a64f29ca6 Add sample artifact map 2024-05-23 19:07:21 -07:00
4cbf2d19b5 Not using HashMap...yet
serde_json::Value to the rescue. Thanks @paultag
2024-05-23 19:07:21 -07:00
64457cd2c2 serde_json::Value 💖 save us 2024-05-23 19:07:21 -07:00
4571ea4e08 WIP ArtifactMap dump 2024-05-23 19:07:21 -07:00
b586b38ad9 coredump typescript implementation
Connection state
2024-05-23 19:07:21 -07:00
8766861d07 Enable connection type dump 2024-05-23 19:07:21 -07:00
abe70f4406 Update coredump.fixture.json 2024-05-23 19:07:21 -07:00
a4452f775b Add serde_json with new support for ts-rs 2024-05-23 19:07:21 -07:00
b06158ba4e Patch ts-rs to 8.1.0 with paultag's fixes 2024-05-23 19:06:16 -07:00
7a42e9e868 Pull in more types 2024-05-23 19:04:33 -07:00
4e856abbcb Types for Engine Manager and Connection state 2024-05-23 19:04:33 -07:00
fef8139a3e Parse out XState Services 2024-05-23 19:01:48 -07:00
b578a88808 Need to upgrade ts-rs to 8.1 for serde json types 2024-05-23 19:01:48 -07:00
a33c15b667 Change _unused to meta 2024-05-23 19:01:48 -07:00
bdf1eef0d5 Properly import ClientState 2024-05-23 19:01:48 -07:00
41d900ad93 migrate over a few more app infos 2024-05-23 19:01:48 -07:00
5796ce02c3 Remove dummy response 2024-05-23 19:01:48 -07:00
229a89fb1d Convert AppInfo to CoreDumpInfo 2024-05-23 19:01:48 -07:00
6343545496 WIP Filling out state data 2024-05-23 19:01:48 -07:00
779b7038dd Include all the state objects 2024-05-23 19:01:48 -07:00
10cbfddc41 Add singleton base structure definitiions 2024-05-23 19:01:48 -07:00
958b68f06f Add XState base structure definitions 2024-05-23 19:01:48 -07:00
522dfdcbcc Removed unused reference 2024-05-23 19:01:48 -07:00
0ac1cbfcf9 Start to implement the ClienState struct
Signed-off-by: Paul R. Tagliamonte <paul@kittycad.io>
2024-05-23 19:01:01 -07:00
950f27ce2a Add client_state to coredump fixture 2024-05-23 19:01:01 -07:00
62e6559177 Create coredump.fixture.json
With data from #2316
2024-05-23 19:01:01 -07:00
8fbacd0363 WIP client state core dump plumbing 2024-05-23 19:01:01 -07:00
9 changed files with 681 additions and 22 deletions

1
src-tauri/Cargo.lock generated
View File

@ -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",

View File

@ -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)
} }

View File

@ -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)

View File

@ -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",

View File

@ -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"] }

View File

@ -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!()

View File

@ -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 {
![Screenshot]({}) ![Screenshot]({})
<details>
<summary><b>Core Dump</b></summary> <summary><b>Core Dump</b></summary>
```json ![Coredump]({})
{}
```
</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();

View File

@ -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

View 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": {}
}
}