v0.1.0-pre.044
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# file: Cargo.toml
|
||||
# version: 4
|
||||
# version: 5
|
||||
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
@@ -14,7 +14,7 @@ members = [
|
||||
"kb-onchain-transport",
|
||||
"kb-store",
|
||||
"kb-wallet",
|
||||
"kb-app-demo",
|
||||
"kb-app-demo-desktop",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
|
||||
@@ -47,7 +47,8 @@
|
||||
"kb-onchain-transport",
|
||||
"kb-wallet",
|
||||
"kb-pipeline",
|
||||
"kb_app_demo",
|
||||
"kb-pipeline-demo-scenarios",
|
||||
"kb-app-demo-desktop",
|
||||
"kb_executor_metadata_metaplex_token_metadata",
|
||||
"kb_executor_metadata_spl_name_service",
|
||||
"kb_executor_spl_account_compression",
|
||||
@@ -104,7 +105,7 @@
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb_app_demo"
|
||||
"kb-app-demo-desktop"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -147,42 +148,42 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_kb_app_demo_debug",
|
||||
"name": "file_kb-app-demo-desktop_debug",
|
||||
"enabled": true,
|
||||
"sink": "file",
|
||||
"level": "debug",
|
||||
"path": "logs/devnet/kb_app_demo/debug.log",
|
||||
"path": "logs/devnet/kb-app-demo-desktop/debug.log",
|
||||
"rotation": "daily",
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb_app_demo"
|
||||
"kb-app-demo-desktop"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_kb_app_demo_info",
|
||||
"name": "file_kb-app-demo-desktop_info",
|
||||
"enabled": true,
|
||||
"sink": "file",
|
||||
"level": "info",
|
||||
"path": "logs/devnet/kb_app_demo/info.log",
|
||||
"path": "logs/devnet/kb-app-demo-desktop/info.log",
|
||||
"rotation": "daily",
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb_app_demo"
|
||||
"kb-app-demo-desktop"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_kb_app_demo_error",
|
||||
"name": "file_kb-app-demo-desktop_error",
|
||||
"enabled": true,
|
||||
"sink": "file",
|
||||
"level": "error",
|
||||
"path": "logs/devnet/kb_app_demo/error.jsonl",
|
||||
"path": "logs/devnet/kb-app-demo-desktop/error.jsonl",
|
||||
"rotation": "daily",
|
||||
"format": "json",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb_app_demo"
|
||||
"kb-app-demo-desktop"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -936,7 +937,8 @@
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb-pipeline"
|
||||
"kb-pipeline",
|
||||
"kb-pipeline-demo-scenarios"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -949,7 +951,8 @@
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb-pipeline"
|
||||
"kb-pipeline",
|
||||
"kb-pipeline-demo-scenarios"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -962,7 +965,8 @@
|
||||
"format": "json",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb-pipeline"
|
||||
"kb-pipeline",
|
||||
"kb-pipeline-demo-scenarios"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1662,7 +1666,7 @@
|
||||
"format": "compact",
|
||||
"ansi": true,
|
||||
"targets": [
|
||||
"kb_app_demo",
|
||||
"kb-app-demo-desktop",
|
||||
"kb-lib.decoder.metadata.metaplex_token_metadata",
|
||||
"kb-lib.decoder.solana.core",
|
||||
"kb-lib.decoder.spl.associated_token_account",
|
||||
@@ -1691,6 +1695,7 @@
|
||||
"kb-lib.materializer.token",
|
||||
"kb-lib.materializer.transaction",
|
||||
"kb-pipeline",
|
||||
"kb-pipeline-demo-scenarios",
|
||||
"kb-onchain-transport",
|
||||
"kb-store",
|
||||
"kb-wallet"
|
||||
@@ -1745,7 +1750,7 @@
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb_app_demo"
|
||||
"kb-app-demo-desktop"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1788,42 +1793,42 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_kb_app_demo_debug",
|
||||
"name": "file_kb-app-demo-desktop_debug",
|
||||
"enabled": true,
|
||||
"sink": "file",
|
||||
"level": "debug",
|
||||
"path": "logs/mainnet_research/kb_app_demo/debug.log",
|
||||
"path": "logs/mainnet_research/kb-app-demo-desktop/debug.log",
|
||||
"rotation": "daily",
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb_app_demo"
|
||||
"kb-app-demo-desktop"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_kb_app_demo_info",
|
||||
"name": "file_kb-app-demo-desktop_info",
|
||||
"enabled": true,
|
||||
"sink": "file",
|
||||
"level": "info",
|
||||
"path": "logs/mainnet_research/kb_app_demo/info.log",
|
||||
"path": "logs/mainnet_research/kb-app-demo-desktop/info.log",
|
||||
"rotation": "daily",
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb_app_demo"
|
||||
"kb-app-demo-desktop"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_kb_app_demo_error",
|
||||
"name": "file_kb-app-demo-desktop_error",
|
||||
"enabled": true,
|
||||
"sink": "file",
|
||||
"level": "error",
|
||||
"path": "logs/mainnet_research/kb_app_demo/error.jsonl",
|
||||
"path": "logs/mainnet_research/kb-app-demo-desktop/error.jsonl",
|
||||
"rotation": "daily",
|
||||
"format": "json",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb_app_demo"
|
||||
"kb-app-demo-desktop"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2577,7 +2582,8 @@
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb-pipeline"
|
||||
"kb-pipeline",
|
||||
"kb-pipeline-demo-scenarios"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2590,7 +2596,8 @@
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb-pipeline"
|
||||
"kb-pipeline",
|
||||
"kb-pipeline-demo-scenarios"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -2603,7 +2610,8 @@
|
||||
"format": "json",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb-pipeline"
|
||||
"kb-pipeline",
|
||||
"kb-pipeline-demo-scenarios"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -3503,7 +3511,7 @@
|
||||
"format": "compact",
|
||||
"ansi": true,
|
||||
"targets": [
|
||||
"kb_app_demo",
|
||||
"kb-app-demo-desktop",
|
||||
"kb-lib.decoder.metadata.metaplex_token_metadata",
|
||||
"kb-lib.decoder.solana.core",
|
||||
"kb-lib.decoder.spl.associated_token_account",
|
||||
@@ -3532,6 +3540,7 @@
|
||||
"kb-lib.materializer.token",
|
||||
"kb-lib.materializer.transaction",
|
||||
"kb-pipeline",
|
||||
"kb-pipeline-demo-scenarios",
|
||||
"kb-onchain-transport",
|
||||
"kb-store",
|
||||
"kb-wallet"
|
||||
@@ -3586,7 +3595,7 @@
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb_app_demo"
|
||||
"kb-app-demo-desktop"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -3629,42 +3638,42 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_kb_app_demo_debug",
|
||||
"name": "file_kb-app-demo-desktop_debug",
|
||||
"enabled": true,
|
||||
"sink": "file",
|
||||
"level": "debug",
|
||||
"path": "logs/mainnet/kb_app_demo/debug.log",
|
||||
"path": "logs/mainnet/kb-app-demo-desktop/debug.log",
|
||||
"rotation": "daily",
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb_app_demo"
|
||||
"kb-app-demo-desktop"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_kb_app_demo_info",
|
||||
"name": "file_kb-app-demo-desktop_info",
|
||||
"enabled": true,
|
||||
"sink": "file",
|
||||
"level": "info",
|
||||
"path": "logs/mainnet/kb_app_demo/info.log",
|
||||
"path": "logs/mainnet/kb-app-demo-desktop/info.log",
|
||||
"rotation": "daily",
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb_app_demo"
|
||||
"kb-app-demo-desktop"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "file_kb_app_demo_error",
|
||||
"name": "file_kb-app-demo-desktop_error",
|
||||
"enabled": true,
|
||||
"sink": "file",
|
||||
"level": "error",
|
||||
"path": "logs/mainnet/kb_app_demo/error.jsonl",
|
||||
"path": "logs/mainnet/kb-app-demo-desktop/error.jsonl",
|
||||
"rotation": "daily",
|
||||
"format": "json",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb_app_demo"
|
||||
"kb-app-demo-desktop"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -4418,7 +4427,8 @@
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb-pipeline"
|
||||
"kb-pipeline",
|
||||
"kb-pipeline-demo-scenarios"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -4431,7 +4441,8 @@
|
||||
"format": "human",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb-pipeline"
|
||||
"kb-pipeline",
|
||||
"kb-pipeline-demo-scenarios"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -4444,7 +4455,8 @@
|
||||
"format": "json",
|
||||
"ansi": false,
|
||||
"targets": [
|
||||
"kb-pipeline"
|
||||
"kb-pipeline",
|
||||
"kb-pipeline-demo-scenarios"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
33
kb-app-demo-desktop/Cargo.toml
Normal file
33
kb-app-demo-desktop/Cargo.toml
Normal file
@@ -0,0 +1,33 @@
|
||||
# file: kb-app-demo-desktop/Cargo.toml
|
||||
# version: 1
|
||||
|
||||
[package]
|
||||
name = "kb-app-demo-desktop"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "kb_app_demo_desktop"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "kb-app-demo-desktop"
|
||||
path = "src/main.rs"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build.workspace = true
|
||||
|
||||
[dependencies]
|
||||
fs2.workspace = true
|
||||
kb-core = { path = "../kb-core" }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
tauri.workspace = true
|
||||
tokio.workspace = true
|
||||
tracing.workspace = true
|
||||
ts-rs.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
12
kb-app-demo-desktop/build.rs
Normal file
12
kb-app-demo-desktop/build.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
// file: kb-app-demo-desktop/build.rs
|
||||
// version: 1
|
||||
|
||||
//! Build script for the desktop demo application.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
12
kb-app-demo-desktop/capabilities/default.json
Normal file
12
kb-app-demo-desktop/capabilities/default.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "Default desktop demo capability",
|
||||
"windows": [
|
||||
"splash",
|
||||
"main"
|
||||
],
|
||||
"permissions": [
|
||||
"core:default"
|
||||
]
|
||||
}
|
||||
BIN
kb-app-demo-desktop/frontend/fonts/DOS_Amazigh.ttf
Normal file
BIN
kb-app-demo-desktop/frontend/fonts/DOS_Amazigh.ttf
Normal file
Binary file not shown.
BIN
kb-app-demo-desktop/frontend/imgs/logo.png
Normal file
BIN
kb-app-demo-desktop/frontend/imgs/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
BIN
kb-app-demo-desktop/frontend/imgs/splash.png
Normal file
BIN
kb-app-demo-desktop/frontend/imgs/splash.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 611 KiB |
18
kb-app-demo-desktop/frontend/main.html
Normal file
18
kb-app-demo-desktop/frontend/main.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/main.html -->
|
||||
<!-- version: 1 -->
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Khadhroony Bot3</title>
|
||||
<style>body{font-family:sans-serif;margin:0;background:#111827;color:#f9fafb}main{max-width:900px;margin:8rem auto;padding:2rem}code{color:#93c5fd}</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Khadhroony Bot3</h1>
|
||||
<p>La fenêtre splash de <code>kb-app-demo-desktop</code> est migrée.</p>
|
||||
<p>La fenêtre principale sera complétée dans la prochaine tranche.</p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
8
kb-app-demo-desktop/frontend/sass/splash.scss
Normal file
8
kb-app-demo-desktop/frontend/sass/splash.scss
Normal file
@@ -0,0 +1,8 @@
|
||||
/* file: kb-app-demo-desktop/frontend/sass/splash.scss */
|
||||
/* version: 1 */
|
||||
html, body { width: 100%; height: 100%; margin: 0; background: transparent; overflow: hidden; }
|
||||
body { display: grid; place-items: center; font-family: sans-serif; }
|
||||
#splash-container { width: 100%; height: 100%; display: grid; place-content: center; justify-items: center; gap: 1rem; opacity: 0; background: radial-gradient(circle, #1f2937, #030712); color: #f9fafb; }
|
||||
#splash-container img { width: min(55vw, 420px); max-height: 55vh; object-fit: contain; }
|
||||
#splash-container h1 { margin: 0; letter-spacing: .08em; }
|
||||
#messages-container { min-height: 1.5rem; color: #d1d5db; }
|
||||
19
kb-app-demo-desktop/frontend/splash.html
Normal file
19
kb-app-demo-desktop/frontend/splash.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/splash.html -->
|
||||
<!-- version: 1 -->
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Chargement — Khadhroony Bot3</title>
|
||||
<link rel="stylesheet" href="sass/splash.scss" />
|
||||
</head>
|
||||
<body>
|
||||
<main id="splash-container">
|
||||
<img src="imgs/splash.png" alt="Khadhroony Bot3" />
|
||||
<h1>Khadhroony Bot3</h1>
|
||||
<div id="messages-container" aria-live="polite"></div>
|
||||
</main>
|
||||
<script type="module" src="ts/splash.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
40
kb-app-demo-desktop/frontend/ts/splash.ts
Normal file
40
kb-app-demo-desktop/frontend/ts/splash.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/splash.ts
|
||||
// version: 1
|
||||
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
|
||||
type SplashOrder = {
|
||||
order: string;
|
||||
msg: string | null;
|
||||
status: string | null;
|
||||
duration_ms: number | null;
|
||||
};
|
||||
|
||||
const container = document.querySelector<HTMLElement>("#splash-container");
|
||||
const messages = document.querySelector<HTMLElement>("#messages-container");
|
||||
|
||||
function duration(order: SplashOrder): number {
|
||||
if (typeof order.duration_ms !== "number" || !Number.isFinite(order.duration_ms) || order.duration_ms <= 0) {
|
||||
return 500;
|
||||
}
|
||||
return order.duration_ms;
|
||||
}
|
||||
|
||||
async function applyOrder(order: SplashOrder): Promise<void> {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
if (order.order === "add_msg" && messages && order.msg) {
|
||||
messages.textContent = order.msg;
|
||||
messages.dataset.status = order.status ?? "info";
|
||||
return;
|
||||
}
|
||||
if (order.order === "fadein" || order.order === "fadeout") {
|
||||
container.style.transition = `opacity ${duration(order)}ms ease-in-out`;
|
||||
container.style.opacity = order.order === "fadein" ? "1" : "0";
|
||||
}
|
||||
}
|
||||
|
||||
void listen<SplashOrder>("splash", event => {
|
||||
void applyOrder(event.payload);
|
||||
});
|
||||
BIN
kb-app-demo-desktop/icons/favicon.ico
Normal file
BIN
kb-app-demo-desktop/icons/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 448 KiB |
BIN
kb-app-demo-desktop/icons/favicon.png
Normal file
BIN
kb-app-demo-desktop/icons/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
34
kb-app-demo-desktop/package.json
Normal file
34
kb-app-demo-desktop/package.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "kb-app-demo-desktop",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@andypf/json-viewer": "^2.8",
|
||||
"@fltsci/tauri-plugin-tracing": "^0.3",
|
||||
"@fortawesome/fontawesome-free": "^7.2",
|
||||
"@tauri-apps/api": "^2.11",
|
||||
"bootstrap": "^5.3",
|
||||
"datatables.net-bs5": "^2.3",
|
||||
"datatables.net-select-bs5": "^3.1",
|
||||
"echarts": "^6.1",
|
||||
"markdown-it": "^14.2",
|
||||
"resize-observer-polyfill": "^1.5",
|
||||
"simplebar": "^6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2.11",
|
||||
"@types/bootstrap": "^5.2",
|
||||
"@types/markdown-it": "^14.1",
|
||||
"@types/node": "^25.9",
|
||||
"sass-embedded": "^1.100",
|
||||
"typescript": "^5.9",
|
||||
"vite": "^8.1"
|
||||
}
|
||||
}
|
||||
7
kb-app-demo-desktop/src/constants.rs
Normal file
7
kb-app-demo-desktop/src/constants.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
// file: kb-app-demo-desktop/src/constants.rs
|
||||
// version: 1
|
||||
|
||||
//! Constants for the desktop demo application.
|
||||
|
||||
/// Canonical tracing target for the desktop demo application.
|
||||
pub(crate) const TRACING_TARGET: &str = "kb-app-demo-desktop";
|
||||
93
kb-app-demo-desktop/src/lib.rs
Normal file
93
kb-app-demo-desktop/src/lib.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
// file: kb-app-demo-desktop/src/lib.rs
|
||||
// version: 1
|
||||
|
||||
//! Tauri desktop demo application for `khadhroony-bot3`.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
mod constants;
|
||||
mod splash;
|
||||
|
||||
use tauri::Manager; // rust-rules: trait-import
|
||||
|
||||
/// Runs the desktop demo application.
|
||||
pub async fn run() -> kb_core::Result<()> {
|
||||
let builder = tauri::Builder::default().setup(|app| {
|
||||
let splash_window = match app.get_webview_window("splash") {
|
||||
std::option::Option::Some(window) => window,
|
||||
std::option::Option::None => {
|
||||
return std::result::Result::Err(std::boxed::Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::NotFound,
|
||||
"splash window is missing",
|
||||
)));
|
||||
},
|
||||
};
|
||||
let main_window = match app.get_webview_window("main") {
|
||||
std::option::Option::Some(window) => window,
|
||||
std::option::Option::None => {
|
||||
return std::result::Result::Err(std::boxed::Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::NotFound,
|
||||
"main window is missing",
|
||||
)));
|
||||
},
|
||||
};
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let started_at = tokio::time::Instant::now();
|
||||
crate::emit_splash_order(
|
||||
&splash_window,
|
||||
"fadein",
|
||||
std::option::Option::None,
|
||||
std::option::Option::None,
|
||||
std::option::Option::Some(crate::SPLASH_FADE_MS),
|
||||
);
|
||||
crate::emit_splash_order(
|
||||
&splash_window,
|
||||
"add_msg",
|
||||
std::option::Option::Some("Initialisation de Khadhroony Bot3..."),
|
||||
std::option::Option::Some("info"),
|
||||
std::option::Option::None,
|
||||
);
|
||||
crate::wait_until_minimum(started_at, crate::SPLASH_MINIMUM_MS).await;
|
||||
crate::emit_splash_order(
|
||||
&splash_window,
|
||||
"fadeout",
|
||||
std::option::Option::None,
|
||||
std::option::Option::None,
|
||||
std::option::Option::Some(crate::SPLASH_FADE_MS),
|
||||
);
|
||||
tokio::time::sleep(std::time::Duration::from_millis(crate::SPLASH_CLOSE_WAIT_MS)).await;
|
||||
if let std::result::Result::Err(error) = splash_window.destroy() {
|
||||
tracing::error!(target: crate::TRACING_TARGET, "cannot destroy splash window: {error:?}");
|
||||
}
|
||||
if let std::result::Result::Err(error) = main_window.show() {
|
||||
tracing::error!(target: crate::TRACING_TARGET, "cannot show main window: {error:?}");
|
||||
}
|
||||
if let std::result::Result::Err(error) = main_window.set_focus() {
|
||||
tracing::error!(target: crate::TRACING_TARGET, "cannot focus main window: {error:?}");
|
||||
}
|
||||
});
|
||||
return std::result::Result::Ok(());
|
||||
});
|
||||
let run_result = builder.run(tauri::generate_context!());
|
||||
return match run_result {
|
||||
std::result::Result::Ok(()) => std::result::Result::Ok(()),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(kb_core::Error::tauri(format!(
|
||||
"cannot run desktop demo application: {error:?}"
|
||||
))),
|
||||
};
|
||||
}
|
||||
|
||||
/// Minimum startup splash duration before fade-out begins.
|
||||
pub(crate) use self::splash::SPLASH_MINIMUM_MS;
|
||||
/// Splash fade duration.
|
||||
pub(crate) use self::splash::SPLASH_FADE_MS;
|
||||
/// Delay after fade-out before destroying the splash window.
|
||||
pub(crate) use self::splash::SPLASH_CLOSE_WAIT_MS;
|
||||
/// Emits one order to the splash frontend.
|
||||
pub(crate) use self::splash::emit_splash_order;
|
||||
/// Waits for the minimum splash duration.
|
||||
pub(crate) use self::splash::wait_until_minimum;
|
||||
/// Canonical tracing target for the desktop demo application.
|
||||
pub(crate) use self::constants::TRACING_TARGET;
|
||||
42
kb-app-demo-desktop/src/main.rs
Normal file
42
kb-app-demo-desktop/src/main.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
// file: kb-app-demo-desktop/src/main.rs
|
||||
// version: 1
|
||||
|
||||
//! Binary entry point for the desktop demo application.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![warn(missing_docs)]
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use fs2::FileExt; // rust-rules: trait-import
|
||||
|
||||
/// Starts the single desktop demo application instance.
|
||||
#[tokio::main]
|
||||
async fn main() -> std::process::ExitCode {
|
||||
let mut lock_path = std::env::temp_dir();
|
||||
lock_path.push("com_sasedev_kb_app_demo_desktop.lock");
|
||||
let lock_file = match std::fs::File::create(&lock_path) {
|
||||
std::result::Result::Ok(file) => file,
|
||||
std::result::Result::Err(error) => {
|
||||
eprintln!("cannot create application lock '{}': {error}", lock_path.display());
|
||||
return std::process::ExitCode::FAILURE;
|
||||
},
|
||||
};
|
||||
if let std::result::Result::Err(error) = lock_file.try_lock_exclusive() {
|
||||
if error.kind() == std::io::ErrorKind::WouldBlock {
|
||||
eprintln!("another kb-app-demo-desktop instance is already running");
|
||||
return std::process::ExitCode::FAILURE;
|
||||
}
|
||||
eprintln!("cannot acquire application lock '{}': {error}", lock_path.display());
|
||||
return std::process::ExitCode::FAILURE;
|
||||
}
|
||||
let _lock_file = lock_file;
|
||||
let run_result = kb_app_demo_desktop::run().await;
|
||||
return match run_result {
|
||||
std::result::Result::Ok(()) => std::process::ExitCode::SUCCESS,
|
||||
std::result::Result::Err(error) => {
|
||||
eprintln!("application error: {error}");
|
||||
std::process::ExitCode::FAILURE
|
||||
},
|
||||
};
|
||||
}
|
||||
84
kb-app-demo-desktop/src/splash.rs
Normal file
84
kb-app-demo-desktop/src/splash.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
// file: kb-app-demo-desktop/src/splash.rs
|
||||
// version: 1
|
||||
|
||||
//! Splash-window payloads and startup sequencing helpers.
|
||||
|
||||
use tauri::Emitter; // rust-rules: trait-import
|
||||
use ts_rs::TS; // rust-rules: derive-import
|
||||
|
||||
/// Minimum splash duration before the main window is shown.
|
||||
pub(crate) const SPLASH_MINIMUM_MS: u64 = 900;
|
||||
/// Splash fade duration.
|
||||
pub(crate) const SPLASH_FADE_MS: u32 = 500;
|
||||
/// Delay after fade-out before destroying the splash window.
|
||||
pub(crate) const SPLASH_CLOSE_WAIT_MS: u64 = 550;
|
||||
|
||||
/// Command sent from Rust to the splash frontend.
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_app_demo_desktop/splash/SplashOrder.ts")]
|
||||
pub(crate) struct SplashOrder {
|
||||
/// Command name.
|
||||
pub(crate) order: std::string::String,
|
||||
/// Optional message.
|
||||
pub(crate) msg: std::option::Option<std::string::String>,
|
||||
/// Optional status.
|
||||
pub(crate) status: std::option::Option<std::string::String>,
|
||||
/// Optional animation duration in milliseconds.
|
||||
pub(crate) duration_ms: std::option::Option<u32>,
|
||||
}
|
||||
|
||||
/// Emits one splash command.
|
||||
pub(crate) fn emit_splash_order(
|
||||
splash_window: &tauri::WebviewWindow,
|
||||
order: &str,
|
||||
msg: std::option::Option<&str>,
|
||||
status: std::option::Option<&str>,
|
||||
duration_ms: std::option::Option<u32>,
|
||||
) {
|
||||
let payload = SplashOrder {
|
||||
order: order.to_string(),
|
||||
msg: msg.map(std::string::ToString::to_string),
|
||||
status: status.map(std::string::ToString::to_string),
|
||||
duration_ms,
|
||||
};
|
||||
let emit_result = splash_window.emit("splash", payload);
|
||||
if let std::result::Result::Err(error) = emit_result {
|
||||
tracing::error!(target: crate::TRACING_TARGET, "cannot emit splash order '{order}': {error:?}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Waits until the configured minimum splash duration has elapsed.
|
||||
pub(crate) async fn wait_until_minimum(start: tokio::time::Instant, minimum_ms: u64) {
|
||||
let minimum = std::time::Duration::from_millis(minimum_ms);
|
||||
let elapsed = start.elapsed();
|
||||
if elapsed >= minimum {
|
||||
return;
|
||||
}
|
||||
tokio::time::sleep(minimum - elapsed).await;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn splash_order_serializes_duration_ms() {
|
||||
let order = super::SplashOrder {
|
||||
order: "fadein".to_string(),
|
||||
msg: std::option::Option::None,
|
||||
status: std::option::Option::None,
|
||||
duration_ms: std::option::Option::Some(500),
|
||||
};
|
||||
let value_result = serde_json::to_value(order);
|
||||
let value = match value_result {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("cannot serialize splash order: {error}"),
|
||||
};
|
||||
assert_eq!(value["duration_ms"], serde_json::json!(500));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn splash_timing_is_ordered() {
|
||||
assert!(super::SPLASH_MINIMUM_MS > 0);
|
||||
assert!(super::SPLASH_FADE_MS > 0);
|
||||
assert!(super::SPLASH_CLOSE_WAIT_MS >= u64::from(super::SPLASH_FADE_MS));
|
||||
}
|
||||
}
|
||||
50
kb-app-demo-desktop/tauri.conf.json
Normal file
50
kb-app-demo-desktop/tauri.conf.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Khadhroony Bot3 Demo Desktop",
|
||||
"version": "0.1.0",
|
||||
"identifier": "com.sasedev.kb-app-demo-desktop",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"devUrl": "http://localhost:1420",
|
||||
"beforeBuildCommand": "npm run build",
|
||||
"frontendDist": "./dist"
|
||||
},
|
||||
"app": {
|
||||
"windows": [
|
||||
{
|
||||
"label": "splash",
|
||||
"url": "splash.html",
|
||||
"title": "Chargement — Khadhroony Bot3",
|
||||
"width": 960,
|
||||
"height": 637,
|
||||
"resizable": false,
|
||||
"decorations": false,
|
||||
"transparent": true,
|
||||
"center": true,
|
||||
"alwaysOnTop": true
|
||||
},
|
||||
{
|
||||
"label": "main",
|
||||
"url": "main.html",
|
||||
"title": "Khadhroony Bot3",
|
||||
"width": 1200,
|
||||
"height": 768,
|
||||
"minWidth": 800,
|
||||
"minHeight": 600,
|
||||
"center": true,
|
||||
"visible": false
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"icon": [
|
||||
"icons/favicon.png",
|
||||
"icons/favicon.ico"
|
||||
]
|
||||
}
|
||||
}
|
||||
31
kb-app-demo-desktop/tsconfig.json
Normal file
31
kb-app-demo-desktop/tsconfig.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": [
|
||||
"ES2020",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"types": [
|
||||
"vite/client",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"frontend",
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
||||
84
kb-app-demo-desktop/vite.config.ts
Normal file
84
kb-app-demo-desktop/vite.config.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
// file: kb-app-demo-desktop/vite.config.ts
|
||||
// version: 2
|
||||
|
||||
import { defineConfig, normalizePath } from "vite";
|
||||
import { NodePackageImporter } from "sass-embedded";
|
||||
import { resolve } from "path";
|
||||
|
||||
const host = process.env.TAURI_DEV_HOST;
|
||||
|
||||
export default defineConfig(() => ({
|
||||
|
||||
envPrefix: ['VITE_', 'TAURI_ENV_*'],
|
||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||
//
|
||||
// 1. prevent Vite from obscuring rust errors
|
||||
clearScreen: false,
|
||||
root: 'frontend', // Set this to your frontend directory
|
||||
publicDir: 'public',
|
||||
build: {
|
||||
outDir: './dist', // Output directory for the build
|
||||
emptyOutDir: true,
|
||||
rollupOptions: {
|
||||
input: {
|
||||
"splash": normalizePath(resolve(__dirname, 'frontend/splash.html')),
|
||||
"main": normalizePath(resolve(__dirname, 'frontend/main.html'))
|
||||
},
|
||||
output: {
|
||||
entryFileNames: 'js/[name]-[hash].js',
|
||||
chunkFileNames: 'js/chunks/[name]-[hash].js',
|
||||
assetFileNames: (assetInfo) => {
|
||||
const originalName = assetInfo.name ?? '';
|
||||
const ext = originalName.substring(originalName.lastIndexOf('.') + 1).toLowerCase();
|
||||
if (ext === 'js') {
|
||||
return 'js/[name]-[hash][extname]';
|
||||
}
|
||||
// CSS
|
||||
if (ext === 'css') {
|
||||
return 'css/[name]-[hash][extname]';
|
||||
}
|
||||
if (['eot', 'otf', 'ttf', 'woff', 'woff2'].includes(ext)) {
|
||||
return 'fonts/[name]-[hash][extname]';
|
||||
}
|
||||
if (['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp', 'ico'].includes(ext)) {
|
||||
return 'imgs/[name][extname]';
|
||||
}
|
||||
if (['mp4', 'webm'].includes(ext)) {
|
||||
return 'videos/[name][extname]';
|
||||
}
|
||||
return 'otherassets/[name][extname]';
|
||||
},
|
||||
},
|
||||
},
|
||||
minify: true,
|
||||
sourcemap: false,
|
||||
cssCodeSplit: true
|
||||
},
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
quietDeps: true,
|
||||
silenceDeprecations: ["import", "color-functions", "global-builtin",],
|
||||
verbose: false,
|
||||
api: 'modern',
|
||||
importers: [new NodePackageImporter()],
|
||||
}
|
||||
}
|
||||
},
|
||||
// 2. tauri expects a fixed port, fail if that port is not available
|
||||
server: {
|
||||
port: 1420,
|
||||
strictPort: false,
|
||||
host: host || false,
|
||||
hmr: host
|
||||
? {
|
||||
protocol: "ws",
|
||||
host,
|
||||
port: 1421,
|
||||
}
|
||||
: undefined,
|
||||
watch: {
|
||||
ignored: ["**/src/**"],
|
||||
},
|
||||
},
|
||||
}));
|
||||
@@ -1,23 +0,0 @@
|
||||
# file: kb-app-demo/Cargo.toml
|
||||
# version: 2
|
||||
|
||||
[package]
|
||||
name = "kb-app-demo"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[dependencies]
|
||||
kb-config = { path = "../kb-config" }
|
||||
kb-core = { path = "../kb-core" }
|
||||
kb-lib = { path = "../kb-lib" }
|
||||
kb-logging = { path = "../kb-logging" }
|
||||
kb-pipeline = { path = "../kb-pipeline" }
|
||||
kb-program-ids = { path = "../kb-program-ids" }
|
||||
kb-onchain-transport = { path = "../kb-onchain-transport" }
|
||||
kb-store = { path = "../kb-store" }
|
||||
kb-wallet = { path = "../kb-wallet" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -1,18 +0,0 @@
|
||||
// file: kb-app-demo/src/main.rs
|
||||
// version: 2
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
//! Minimal migration smoke-test application.
|
||||
|
||||
fn main() {
|
||||
println!("khadhroony-bot3 workspace scaffold");
|
||||
println!("logging target: {}", kb_logging::tracing_target());
|
||||
println!(
|
||||
"pipeline: {} v{}",
|
||||
kb_pipeline::CORE_EXTRACTION_PROCESSOR_NAME,
|
||||
kb_pipeline::CORE_EXTRACTION_PROCESSOR_VERSION
|
||||
);
|
||||
}
|
||||
@@ -1319,7 +1319,7 @@ mod tests {
|
||||
&& target.path == format!("logs/{directory}/app.log")
|
||||
&& target.level == "debug"
|
||||
&& target.format == "human"
|
||||
&& target.targets == std::vec!["kb_app_demo".to_string()];
|
||||
&& target.targets == std::vec!["kb-app-demo-desktop".to_string()];
|
||||
}));
|
||||
for crate_name in &operational_crates {
|
||||
for (suffix, level, format) in [
|
||||
|
||||
Reference in New Issue
Block a user