diff --git a/.vscode/launch.json b/.vscode/launch.json
deleted file mode 100644
index 31e7fe7..0000000
--- a/.vscode/launch.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- // Use IntelliSense to learn about possible attributes.
- // Hover to view descriptions of existing attributes.
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
- "version": "0.2.0",
- "configurations": [
- {
- "type": "lldb",
- "request": "launch",
- "name": "Debug unit tests in library 'webui-rs'",
- "cargo": {
- "args": [
- "test",
- "--no-run",
- "--lib",
- "--package=webui-rs"
- ],
- "filter": {
- "name": "webui-rs",
- "kind": "lib"
- }
- },
- "args": [],
- "cwd": "${workspaceFolder}"
- }
- ]
-}
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index d0aa3b0..9e76853 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,14 +3,1710 @@
version = 3
[[package]]
-name = "lazy_static"
+name = "addr2line"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+
+[[package]]
+name = "aes"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
+
+[[package]]
+name = "arbitrary"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
+dependencies = [
+ "derive_arbitrary",
+]
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
+name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "backtrace"
+version = "0.3.74"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+ "windows-targets",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
+
+[[package]]
+name = "bzip2"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
+dependencies = [
+ "bzip2-sys",
+ "libc",
+]
+
+[[package]]
+name = "bzip2-sys"
+version = "0.1.11+1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "cc"
+version = "1.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938"
+dependencies = [
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
+[[package]]
+name = "constant_time_eq"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
+
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc"
+version = "3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
+
+[[package]]
+name = "crc32fast"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "deflate64"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
+
+[[package]]
+name = "deranged"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
+dependencies = [
+ "powerfmt",
+]
+
+[[package]]
+name = "derive_arbitrary"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+
+[[package]]
+name = "flate2"
+version = "1.0.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+
+[[package]]
+name = "futures-io"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+
+[[package]]
+name = "futures-sink"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+
+[[package]]
+name = "futures-task"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+
+[[package]]
+name = "futures-util"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+dependencies = [
+ "futures-core",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "gimli"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
+
+[[package]]
+name = "h2"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "http"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
+dependencies = [
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
+
+[[package]]
+name = "hyper"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
+dependencies = [
+ "futures-util",
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
+dependencies = [
+ "bytes",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "idna"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4"
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
+[[package]]
+name = "jobserver"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.159"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+
+[[package]]
+name = "lockfree-object-pool"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "lzma-rs"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e"
+dependencies = [
+ "byteorder",
+ "crc",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "mio"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "wasi",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "native-tls"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
+dependencies = [
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
+[[package]]
+name = "object"
+version = "0.36.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
+name = "openssl"
+version = "0.10.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "pbkdf2"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
+dependencies = [
+ "digest",
+ "hmac",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
+
+[[package]]
+name = "portable-atomic"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.12.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-tls",
+ "hyper-util",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustls-pemfile",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "system-configuration",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "windows-registry",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom",
+ "libc",
+ "spin",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+
+[[package]]
+name = "rustix"
+version = "0.38.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rustls"
+version = "0.23.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8"
+dependencies = [
+ "once_cell",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55"
+
+[[package]]
+name = "rustls-webpki"
+version = "0.102.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
+dependencies = [
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "schannel"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "security-framework"
+version = "2.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.210"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.210"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.128"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "sha1"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "simd-adler32"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
+
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "socket2"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "syn"
+version = "2.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sync_wrapper"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "time"
+version = "0.3.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
+dependencies = [
+ "deranged",
+ "num-conv",
+ "powerfmt",
+ "serde",
+ "time-core",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
+
+[[package]]
+name = "tinyvec"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.40.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "socket2",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
+dependencies = [
+ "rustls",
+ "rustls-pki-types",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tower-service"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
+[[package]]
+name = "tracing"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+dependencies = [
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "url"
+version = "2.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+
+[[package]]
+name = "web-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
[[package]]
name = "webui-rs"
version = "0.1.0"
dependencies = [
- "lazy_static",
+ "reqwest",
+ "zip",
+]
+
+[[package]]
+name = "windows-registry"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
+dependencies = [
+ "windows-result",
+ "windows-strings",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
+dependencies = [
+ "windows-result",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "byteorder",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zip"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494"
+dependencies = [
+ "aes",
+ "arbitrary",
+ "bzip2",
+ "constant_time_eq",
+ "crc32fast",
+ "crossbeam-utils",
+ "deflate64",
+ "displaydoc",
+ "flate2",
+ "hmac",
+ "indexmap",
+ "lzma-rs",
+ "memchr",
+ "pbkdf2",
+ "rand",
+ "sha1",
+ "thiserror",
+ "time",
+ "zeroize",
+ "zopfli",
+ "zstd",
+]
+
+[[package]]
+name = "zopfli"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
+dependencies = [
+ "bumpalo",
+ "crc32fast",
+ "lockfree-object-pool",
+ "log",
+ "once_cell",
+ "simd-adler32",
+]
+
+[[package]]
+name = "zstd"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9"
+dependencies = [
+ "zstd-safe",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "7.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059"
+dependencies = [
+ "zstd-sys",
+]
+
+[[package]]
+name = "zstd-sys"
+version = "2.0.13+zstd.1.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa"
+dependencies = [
+ "cc",
+ "pkg-config",
]
diff --git a/Cargo.toml b/Cargo.toml
index 9ea2508..36b4994 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,5 +4,6 @@ version = "0.1.0"
build = "build.rs"
edition = "2021"
-[dependencies]
-lazy_static = "1.4.0"
+[build-dependencies]
+reqwest = { version = "0.12.7", features = ["blocking"] }
+zip = "2.2.0"
diff --git a/README.md b/README.md
index 0f9db4a..15c77b8 100644
--- a/README.md
+++ b/README.md
@@ -109,6 +109,12 @@ Think of WebUI like a WebView controller, but instead of embedding the WebView c
| Apple Safari | _not available_ | _coming soon_ | _not available_ |
| Opera | _coming soon_ | _coming soon_ | _coming soon_ |
+### Tests
+
+```
+cargo test --package webui-rs --lib -- tests --show-output
+```
+
### License
> Licensed under the MIT License.
diff --git a/bindings-updater/Cargo.lock b/bindings-updater/Cargo.lock
new file mode 100644
index 0000000..6c98bb4
--- /dev/null
+++ b/bindings-updater/Cargo.lock
@@ -0,0 +1,1385 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "backtrace"
+version = "0.3.74"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+ "windows-targets",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bindgen"
+version = "0.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
+dependencies = [
+ "bitflags",
+ "cexpr",
+ "clang-sys",
+ "itertools",
+ "log",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn",
+]
+
+[[package]]
+name = "bindings-updater"
+version = "0.1.0"
+dependencies = [
+ "bindgen",
+ "reqwest",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "bumpalo"
+version = "3.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+
+[[package]]
+name = "bytes"
+version = "1.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
+
+[[package]]
+name = "cc"
+version = "1.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clang-sys"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "either"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+
+[[package]]
+name = "futures-io"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+
+[[package]]
+name = "futures-sink"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+
+[[package]]
+name = "futures-task"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+
+[[package]]
+name = "futures-util"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+dependencies = [
+ "futures-core",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "gimli"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "h2"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
+name = "http"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
+dependencies = [
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
+
+[[package]]
+name = "hyper"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
+dependencies = [
+ "futures-util",
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
+dependencies = [
+ "bytes",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "idna"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4"
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
+[[package]]
+name = "js-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.159"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
+
+[[package]]
+name = "libloading"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
+dependencies = [
+ "cfg-if",
+ "windows-targets",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "mio"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "wasi",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "native-tls"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
+dependencies = [
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "object"
+version = "0.36.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
+name = "openssl"
+version = "0.10.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
+
+[[package]]
+name = "portable-atomic"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
+
+[[package]]
+name = "prettyplease"
+version = "0.2.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "reqwest"
+version = "0.12.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-tls",
+ "hyper-util",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustls-pemfile",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "system-configuration",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "windows-registry",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom",
+ "libc",
+ "spin",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustix"
+version = "0.38.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rustls"
+version = "0.23.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8"
+dependencies = [
+ "once_cell",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425"
+dependencies = [
+ "base64",
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55"
+
+[[package]]
+name = "rustls-webpki"
+version = "0.102.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
+dependencies = [
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "schannel"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "security-framework"
+version = "2.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.210"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.210"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.128"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "socket2"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "syn"
+version = "2.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sync_wrapper"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.40.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "socket2",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
+dependencies = [
+ "rustls",
+ "rustls-pki-types",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tower-service"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
+[[package]]
+name = "tracing"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+dependencies = [
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "url"
+version = "2.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+
+[[package]]
+name = "web-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "windows-registry"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
+dependencies = [
+ "windows-result",
+ "windows-strings",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
+dependencies = [
+ "windows-result",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "zeroize"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
diff --git a/bindings-updater/Cargo.toml b/bindings-updater/Cargo.toml
new file mode 100644
index 0000000..86b748d
--- /dev/null
+++ b/bindings-updater/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "bindings-updater"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+bindgen = "0.70.1"
+reqwest = { version = "0.12.7", features = ["blocking"] }
diff --git a/bindings-updater/src/main.rs b/bindings-updater/src/main.rs
new file mode 100644
index 0000000..fce750b
--- /dev/null
+++ b/bindings-updater/src/main.rs
@@ -0,0 +1,38 @@
+use std::path::PathBuf;
+use reqwest;
+
+fn main() {
+ let url = "https://github.com/webui-dev/webui/raw/refs/tags/2.5.0-beta.2/include/webui.h";
+
+ download(url);
+
+ // The bindgen::Builder is the main entry point
+ // to bindgen, and lets you build up options for
+ // the resulting bindings.
+ let bindings = bindgen::Builder::default()
+ // The input header we would like to generate
+ // bindings for.
+ .header("webui.h")
+ .allowlist_type("webui.*")
+ .allowlist_function("webui.*")
+ .rustified_enum("webui.*")
+ // Finish the builder and generate the bindings.
+ .generate()
+ // Unwrap the Result and panic on failure.
+ .expect("Unable to generate bindings");
+
+ bindings
+ .write_to_file("bindgen.rs")
+ .expect("Couldn't write bindings!");
+}
+
+fn download(url: &str) {
+ let mut response = reqwest::blocking::get(url).unwrap();
+ assert!(response.status().is_success());
+
+ let mut dest = {
+ let path = PathBuf::from("webui.h");
+ std::fs::File::create(&path).unwrap()
+ };
+ std::io::copy(&mut response, &mut dest).unwrap();
+}
\ No newline at end of file
diff --git a/build.rs b/build.rs
index 06453fb..bf8ca8c 100644
--- a/build.rs
+++ b/build.rs
@@ -1,15 +1,99 @@
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+use reqwest;
+use std::env;
+
+const BASE_URL: &str = "https://github.com/webui-dev/webui/releases/download/2.5.0-beta.2/";
+
fn main() {
// WebUI static lib
- #[cfg(not(target_os = "windows"))]
+
+ const LINUX_ARM: &str = "webui-linux-gcc-arm";
+ const LINUX_ARM64: &str = "webui-linux-gcc-arm64";
+ const LINUX_X64: &str = "webui-linux-gcc-x64";
+ const MACOS_ARM64: &str = "webui-macos-clang-arm64";
+ const MACOS_X64: &str = "webui-macos-clang-x64";
+ const WINDOWS_X64: &str = "webui-windows-msvc-x64";
+
+ let out_dir = env::var("OUT_DIR").unwrap();
+
+ let target;
+ #[cfg(target_os = "linux")]
{
- println!("cargo:rustc-link-search=native=./");
- }
+ #[cfg(target_arch = "aarch64")]
+ {
+ target = LINUX_ARM64;
+ }
+
+ #[cfg(target_arch = "arm")]
+ {
+ target = LINUX_ARM;
+ }
- println!("cargo:rustc-link-lib=webui-2-static");
+ #[cfg(target_arch = "x86_64")]
+ {
+ target = LINUX_X64;
+ }
+ }
#[cfg(target_os = "windows")]
{
+ target = WINDOWS_X64;
println!("cargo:rustc-link-lib=user32");
println!("cargo:rustc-link-lib=shell32");
}
+
+ #[cfg(target_os = "macos")]
+ {
+ #[cfg(target_arch = "aarch64")]
+ {
+ target = MACOS_ARM64;
+ }
+
+ #[cfg(target_arch = "x86_64")]
+ {
+ target = MACOS_X64;
+ }
+ }
+
+ download(target, &out_dir);
+
+ println!("cargo:rustc-link-search=native={}/{}", out_dir, target);
+
+ #[cfg(not(target_os = "windows"))]
+ {
+ println!("cargo:rustc-link-lib=webui-2-static");
+ }
+
+ #[cfg(target_os = "windows")]
+ {
+ println!("cargo:rustc-link-lib=dylib=webui-2");
+
+ let src = format!("{}/{}/webui-2.dll", out_dir, target);
+ let dst = format!("{}/../../../webui-2.dll", out_dir);
+
+ std::fs::copy(src, dst).unwrap();
+ }
+
}
+
+fn download(target: &str, cache_dir: &str) {
+ let url = format!("{}{}{}", BASE_URL, target, ".zip");
+
+ // check if directory exists
+ if let Err(_) = std::fs::create_dir_all(cache_dir) {
+ return;
+ }
+
+ let response = reqwest::blocking::get(url).unwrap();
+ let status = response.status();
+ if !status.is_success() {
+ panic!("Failed to download WebUI static lib: {}", status);
+ }
+
+ let zip = std::io::Cursor::new(response.bytes().unwrap());
+ let mut archive = zip::ZipArchive::new(zip).unwrap();
+ archive.extract(cache_dir).unwrap();
+
+}
\ No newline at end of file
diff --git a/examples/bindings.rs b/examples/bindings.rs
new file mode 100644
index 0000000..0208608
--- /dev/null
+++ b/examples/bindings.rs
@@ -0,0 +1,37 @@
+use webui_rs::webui;
+use webui_rs::Browser;
+use webui_rs::Window;
+
+const HTML: &str = r#"
+
+
+
+
+
+"#;
+
+fn main() {
+ let win = Window::new();
+
+ win.show_browser(HTML, Browser::Firefox);
+
+ win.bind("btn", |_| {
+ println!("Element clicked!");
+ });
+
+ win.bind("add", |event| {
+ let count = event.get_count();
+ if count < 2 {
+ return;
+ }
+
+ let a = event.get_int_at(0);
+ let b = event.get_int_at(1);
+
+ println!("{} + {} = {}", a, b, a + b);
+
+ event.return_int(a + b);
+ });
+
+ webui::wait();
+}
diff --git a/examples/call_js_from_rust.rs b/examples/call_js_from_rust.rs
deleted file mode 100644
index aab0b77..0000000
--- a/examples/call_js_from_rust.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-use webui_rs::webui::{wait, Event, Window};
-
-fn main() {
- let win = Window::new();
-
- // Declared function
- win.bind("my_button", log_to_js);
-
- win.show(
- r#"
-
-
-
-
- "#,
- );
-
- wait();
-}
-
-fn log_to_js(e: Event) {
- e.get_window().run_js(
- r#"
- console.log('Button clicked!')
- "#,
- );
-}
diff --git a/examples/call_rust_from_js.rs b/examples/call_rust_from_js.rs
deleted file mode 100644
index 6e4fb6e..0000000
--- a/examples/call_rust_from_js.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-use webui_rs::webui::{wait, Event, Window};
-
-fn main() {
- let win = Window::new();
-
- // Inline function
- win.bind("my_button", |_: Event| {
- println!("Button clicked!");
- });
-
- win.show(
- r#"
-
-
-
-
- "#,
- );
-
- wait();
-}
diff --git a/examples/direct_bindings.rs b/examples/direct_bindings.rs
index 4d35a7c..a6668d4 100644
--- a/examples/direct_bindings.rs
+++ b/examples/direct_bindings.rs
@@ -1,4 +1,4 @@
-use webui_rs::webui::bindgen::*;
+use webui_rs::bindgen::*;
fn main() {
// Scary! The bindgen exports are interfacing directly with the C library, so no guarantees!
diff --git a/examples/hello_world.rs b/examples/hello_world.rs
index 1cbc70e..04793b7 100644
--- a/examples/hello_world.rs
+++ b/examples/hello_world.rs
@@ -1,4 +1,4 @@
-use webui_rs::webui::{wait, Window};
+use webui_rs::{webui::wait, window::Window};
fn main() {
let win = Window::new();
diff --git a/examples/serve_a_file.rs b/examples/serve_a_file.rs
index 39fb99d..8658de7 100644
--- a/examples/serve_a_file.rs
+++ b/examples/serve_a_file.rs
@@ -1,4 +1,4 @@
-use webui_rs::webui::{wait, Window};
+use webui_rs::{webui::wait, window::Window};
fn main() {
let win = Window::new();
diff --git a/src/bindgen.rs b/src/bindgen.rs
new file mode 100644
index 0000000..928580f
--- /dev/null
+++ b/src/bindgen.rs
@@ -0,0 +1,493 @@
+/* automatically generated by rust-bindgen 0.70.1 */
+
+#[repr(u32)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub enum webui_browser {
+ NoBrowser = 0,
+ AnyBrowser = 1,
+ Chrome = 2,
+ Firefox = 3,
+ Edge = 4,
+ Safari = 5,
+ Chromium = 6,
+ Opera = 7,
+ Brave = 8,
+ Vivaldi = 9,
+ Epic = 10,
+ Yandex = 11,
+ ChromiumBased = 12,
+ Webview = 13,
+}
+#[repr(u32)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub enum webui_runtime {
+ None = 0,
+ Deno = 1,
+ NodeJS = 2,
+ Bun = 3,
+}
+#[repr(u32)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub enum webui_event {
+ WEBUI_EVENT_DISCONNECTED = 0,
+ WEBUI_EVENT_CONNECTED = 1,
+ WEBUI_EVENT_MOUSE_CLICK = 2,
+ WEBUI_EVENT_NAVIGATION = 3,
+ WEBUI_EVENT_CALLBACK = 4,
+}
+#[repr(u32)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub enum webui_config {
+ show_wait_connection = 0,
+ ui_event_blocking = 1,
+ folder_monitor = 2,
+ multi_client = 3,
+ use_cookies = 4,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct webui_event_t {
+ pub window: usize,
+ pub event_type: usize,
+ pub element: *mut ::std::os::raw::c_char,
+ pub event_number: usize,
+ pub bind_id: usize,
+ pub client_id: usize,
+ pub connection_id: usize,
+ pub cookies: *mut ::std::os::raw::c_char,
+}
+#[allow(clippy::unnecessary_operation, clippy::identity_op)]
+const _: () = {
+ ["Size of webui_event_t"][::std::mem::size_of::() - 64usize];
+ ["Alignment of webui_event_t"][::std::mem::align_of::() - 8usize];
+ ["Offset of field: webui_event_t::window"]
+ [::std::mem::offset_of!(webui_event_t, window) - 0usize];
+ ["Offset of field: webui_event_t::event_type"]
+ [::std::mem::offset_of!(webui_event_t, event_type) - 8usize];
+ ["Offset of field: webui_event_t::element"]
+ [::std::mem::offset_of!(webui_event_t, element) - 16usize];
+ ["Offset of field: webui_event_t::event_number"]
+ [::std::mem::offset_of!(webui_event_t, event_number) - 24usize];
+ ["Offset of field: webui_event_t::bind_id"]
+ [::std::mem::offset_of!(webui_event_t, bind_id) - 32usize];
+ ["Offset of field: webui_event_t::client_id"]
+ [::std::mem::offset_of!(webui_event_t, client_id) - 40usize];
+ ["Offset of field: webui_event_t::connection_id"]
+ [::std::mem::offset_of!(webui_event_t, connection_id) - 48usize];
+ ["Offset of field: webui_event_t::cookies"]
+ [::std::mem::offset_of!(webui_event_t, cookies) - 56usize];
+};
+extern "C" {
+ #[doc = " @brief Create a new WebUI window object.\n\n @return Returns the window number.\n\n @example size_t myWindow = webui_new_window();"]
+ pub fn webui_new_window() -> usize;
+}
+extern "C" {
+ #[doc = " @brief Create a new webui window object using a specified window number.\n\n @param window_number The window number (should be > 0, and < WEBUI_MAX_IDS)\n\n @return Returns the same window number if success.\n\n @example size_t myWindow = webui_new_window_id(123);"]
+ pub fn webui_new_window_id(window_number: usize) -> usize;
+}
+extern "C" {
+ #[doc = " @brief Get a free window number that can be used with\n `webui_new_window_id()`.\n\n @return Returns the first available free window number. Starting from 1.\n\n @example size_t myWindowNumber = webui_get_new_window_id();"]
+ pub fn webui_get_new_window_id() -> usize;
+}
+extern "C" {
+ #[doc = " @brief Bind an HTML element and a JavaScript object with a backend function. Empty\n element name means all events.\n\n @param window The window number\n @param element The HTML element / JavaScript object\n @param func The callback function\n\n @return Returns a unique bind ID.\n\n @example webui_bind(myWindow, \"myFunction\", myFunction);"]
+ pub fn webui_bind(
+ window: usize,
+ element: *const ::std::os::raw::c_char,
+ func: ::std::option::Option,
+ ) -> usize;
+}
+extern "C" {
+ #[doc = " @brief Get the recommended web browser ID to use. If you\n are already using one, this function will return the same ID.\n\n @param window The window number\n\n @return Returns a web browser ID.\n\n @example size_t browserID = webui_get_best_browser(myWindow);"]
+ pub fn webui_get_best_browser(window: usize) -> usize;
+}
+extern "C" {
+ #[doc = " @brief Show a window using embedded HTML, or a file. If the window is already\n open, it will be refreshed. This will refresh all windows in multi-client mode.\n\n @param window The window number\n @param content The HTML, URL, Or a local file\n\n @return Returns True if showing the window is successed.\n\n @example webui_show(myWindow, \"...\"); |\n webui_show(myWindow, \"index.html\"); | webui_show(myWindow, \"http://...\");"]
+ pub fn webui_show(window: usize, content: *const ::std::os::raw::c_char) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Show a window using embedded HTML, or a file. If the window is already\n open, it will be refreshed. Single client.\n\n @param e The event struct\n @param content The HTML, URL, Or a local file\n\n @return Returns True if showing the window is successed.\n\n @example webui_show_client(e, \"...\"); |\n webui_show_client(e, \"index.html\"); | webui_show_client(e, \"http://...\");"]
+ pub fn webui_show_client(e: *mut webui_event_t, content: *const ::std::os::raw::c_char)
+ -> bool;
+}
+extern "C" {
+ #[doc = " @brief Same as `webui_show()`. But using a specific web browser.\n\n @param window The window number\n @param content The HTML, Or a local file\n @param browser The web browser to be used\n\n @return Returns True if showing the window is successed.\n\n @example webui_show_browser(myWindow, \"...\", Chrome); |\n webui_show(myWindow, \"index.html\", Firefox);"]
+ pub fn webui_show_browser(
+ window: usize,
+ content: *const ::std::os::raw::c_char,
+ browser: usize,
+ ) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Same as `webui_show()`. But start only the web server and return the URL.\n No window will be shown.\n\n @param window The window number\n @param content The HTML, Or a local file\n\n @return Returns the url of this window server.\n\n @example const char* url = webui_start_server(myWindow, \"/full/root/path\");"]
+ pub fn webui_start_server(
+ window: usize,
+ content: *const ::std::os::raw::c_char,
+ ) -> *const ::std::os::raw::c_char;
+}
+extern "C" {
+ #[doc = " @brief Show a WebView window using embedded HTML, or a file. If the window is already\n open, it will be refreshed. Note: Win32 need `WebView2Loader.dll`.\n\n @param window The window number\n @param content The HTML, URL, Or a local file\n\n @return Returns True if showing the WebView window is successed.\n\n @example webui_show_wv(myWindow, \"...\"); | webui_show_wv(myWindow,\n \"index.html\"); | webui_show_wv(myWindow, \"http://...\");"]
+ pub fn webui_show_wv(window: usize, content: *const ::std::os::raw::c_char) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Set the window in Kiosk mode (Full screen).\n\n @param window The window number\n @param status True or False\n\n @example webui_set_kiosk(myWindow, true);"]
+ pub fn webui_set_kiosk(window: usize, status: bool);
+}
+extern "C" {
+ #[doc = " @brief Set the window with high-contrast support. Useful when you want to\n build a better high-contrast theme with CSS.\n\n @param window The window number\n @param status True or False\n\n @example webui_set_high_contrast(myWindow, true);"]
+ pub fn webui_set_high_contrast(window: usize, status: bool);
+}
+extern "C" {
+ #[doc = " @brief Get OS high contrast preference.\n\n @return Returns True if OS is using high contrast theme\n\n @example bool hc = webui_is_high_contrast();"]
+ pub fn webui_is_high_contrast() -> bool;
+}
+extern "C" {
+ #[doc = " @brief Check if a web browser is installed.\n\n @return Returns True if the specified browser is available\n\n @example bool status = webui_browser_exist(Chrome);"]
+ pub fn webui_browser_exist(browser: usize) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Wait until all opened windows get closed.\n\n @example webui_wait();"]
+ pub fn webui_wait();
+}
+extern "C" {
+ #[doc = " @brief Close a specific window only. The window object will still exist.\n All clients.\n\n @param window The window number\n\n @example webui_close(myWindow);"]
+ pub fn webui_close(window: usize);
+}
+extern "C" {
+ #[doc = " @brief Close a specific client.\n\n @param e The event struct\n\n @example webui_close_client(e);"]
+ pub fn webui_close_client(e: *mut webui_event_t);
+}
+extern "C" {
+ #[doc = " @brief Close a specific window and free all memory resources.\n\n @param window The window number\n\n @example webui_destroy(myWindow);"]
+ pub fn webui_destroy(window: usize);
+}
+extern "C" {
+ #[doc = " @brief Close all open windows. `webui_wait()` will return (Break).\n\n @example webui_exit();"]
+ pub fn webui_exit();
+}
+extern "C" {
+ #[doc = " @brief Set the web-server root folder path for a specific window.\n\n @param window The window number\n @param path The local folder full path\n\n @example webui_set_root_folder(myWindow, \"/home/Foo/Bar/\");"]
+ pub fn webui_set_root_folder(window: usize, path: *const ::std::os::raw::c_char) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Set the web-server root folder path for all windows. Should be used\n before `webui_show()`.\n\n @param path The local folder full path\n\n @example webui_set_default_root_folder(\"/home/Foo/Bar/\");"]
+ pub fn webui_set_default_root_folder(path: *const ::std::os::raw::c_char) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Set a custom handler to serve files. This custom handler should\n return full HTTP header and body.\n\n @param window The window number\n @param handler The handler function: `void myHandler(const char* filename,\n int* length)`\n\n @example webui_set_file_handler(myWindow, myHandlerFunction);"]
+ pub fn webui_set_file_handler(
+ window: usize,
+ handler: ::std::option::Option<
+ unsafe extern "C" fn(
+ filename: *const ::std::os::raw::c_char,
+ length: *mut ::std::os::raw::c_int,
+ ) -> *const ::std::os::raw::c_void,
+ >,
+ );
+}
+extern "C" {
+ #[doc = " @brief Check if the specified window is still running.\n\n @param window The window number\n\n @example webui_is_shown(myWindow);"]
+ pub fn webui_is_shown(window: usize) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Set the maximum time in seconds to wait for the window to connect.\n This effect `show()` and `wait()`. Value of `0` means wait forever.\n\n @param second The timeout in seconds\n\n @example webui_set_timeout(30);"]
+ pub fn webui_set_timeout(second: usize);
+}
+extern "C" {
+ #[doc = " @brief Set the default embedded HTML favicon.\n\n @param window The window number\n @param icon The icon as string: ``\n @param icon_type The icon type: `image/svg+xml`\n\n @example webui_set_icon(myWindow, \"\", \"image/svg+xml\");"]
+ pub fn webui_set_icon(
+ window: usize,
+ icon: *const ::std::os::raw::c_char,
+ icon_type: *const ::std::os::raw::c_char,
+ );
+}
+extern "C" {
+ #[doc = " @brief Encode text to Base64. The returned buffer need to be freed.\n\n @param str The string to encode (Should be null terminated)\n\n @return Returns the base64 encoded string\n\n @example char* base64 = webui_encode(\"Foo Bar\");"]
+ pub fn webui_encode(str_: *const ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char;
+}
+extern "C" {
+ #[doc = " @brief Decode a Base64 encoded text. The returned buffer need to be freed.\n\n @param str The string to decode (Should be null terminated)\n\n @return Returns the base64 decoded string\n\n @example char* str = webui_decode(\"SGVsbG8=\");"]
+ pub fn webui_decode(str_: *const ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char;
+}
+extern "C" {
+ #[doc = " @brief Safely free a buffer allocated by WebUI using `webui_malloc()`.\n\n @param ptr The buffer to be freed\n\n @example webui_free(myBuffer);"]
+ pub fn webui_free(ptr: *mut ::std::os::raw::c_void);
+}
+extern "C" {
+ #[doc = " @brief Safely allocate memory using the WebUI memory management system. It\n can be safely freed using `webui_free()` at any time.\n\n @param size The size of memory in bytes\n\n @example char* myBuffer = (char*)webui_malloc(1024);"]
+ pub fn webui_malloc(size: usize) -> *mut ::std::os::raw::c_void;
+}
+extern "C" {
+ #[doc = " @brief Safely send raw data to the UI. All clients.\n\n @param window The window number\n @param function The JavaScript function to receive raw data: `function\n myFunc(myData){}`\n @param raw The raw data buffer\n @param size The raw data size in bytes\n\n @example webui_send_raw(myWindow, \"myJavaScriptFunc\", myBuffer, 64);"]
+ pub fn webui_send_raw(
+ window: usize,
+ function: *const ::std::os::raw::c_char,
+ raw: *const ::std::os::raw::c_void,
+ size: usize,
+ );
+}
+extern "C" {
+ #[doc = " @brief Safely send raw data to the UI. Single client.\n\n @param e The event struct\n @param function The JavaScript function to receive raw data: `function\n myFunc(myData){}`\n @param raw The raw data buffer\n @param size The raw data size in bytes\n\n @example webui_send_raw_client(e, \"myJavaScriptFunc\", myBuffer, 64);"]
+ pub fn webui_send_raw_client(
+ e: *mut webui_event_t,
+ function: *const ::std::os::raw::c_char,
+ raw: *const ::std::os::raw::c_void,
+ size: usize,
+ );
+}
+extern "C" {
+ #[doc = " @brief Set a window in hidden mode. Should be called before `webui_show()`.\n\n @param window The window number\n @param status The status: True or False\n\n @example webui_set_hide(myWindow, True);"]
+ pub fn webui_set_hide(window: usize, status: bool);
+}
+extern "C" {
+ #[doc = " @brief Set the window size.\n\n @param window The window number\n @param width The window width\n @param height The window height\n\n @example webui_set_size(myWindow, 800, 600);"]
+ pub fn webui_set_size(
+ window: usize,
+ width: ::std::os::raw::c_uint,
+ height: ::std::os::raw::c_uint,
+ );
+}
+extern "C" {
+ #[doc = " @brief Set the window position.\n\n @param window The window number\n @param x The window X\n @param y The window Y\n\n @example webui_set_position(myWindow, 100, 100);"]
+ pub fn webui_set_position(window: usize, x: ::std::os::raw::c_uint, y: ::std::os::raw::c_uint);
+}
+extern "C" {
+ #[doc = " @brief Set the web browser profile to use. An empty `name` and `path` means\n the default user profile. Need to be called before `webui_show()`.\n\n @param window The window number\n @param name The web browser profile name\n @param path The web browser profile full path\n\n @example webui_set_profile(myWindow, \"Bar\", \"/Home/Foo/Bar\"); |\n webui_set_profile(myWindow, \"\", \"\");"]
+ pub fn webui_set_profile(
+ window: usize,
+ name: *const ::std::os::raw::c_char,
+ path: *const ::std::os::raw::c_char,
+ );
+}
+extern "C" {
+ #[doc = " @brief Set the web browser proxy server to use. Need to be called before `webui_show()`.\n\n @param window The window number\n @param proxy_server The web browser proxy_server\n\n @example webui_set_proxy(myWindow, \"http://127.0.0.1:8888\");"]
+ pub fn webui_set_proxy(window: usize, proxy_server: *const ::std::os::raw::c_char);
+}
+extern "C" {
+ #[doc = " @brief Get current URL of a running window.\n\n @param window The window number\n\n @return Returns the full URL string\n\n @example const char* url = webui_get_url(myWindow);"]
+ pub fn webui_get_url(window: usize) -> *const ::std::os::raw::c_char;
+}
+extern "C" {
+ #[doc = " @brief Open an URL in the native default web browser.\n\n @param url The URL to open\n\n @example webui_open_url(\"https://webui.me\");"]
+ pub fn webui_open_url(url: *const ::std::os::raw::c_char);
+}
+extern "C" {
+ #[doc = " @brief Allow a specific window address to be accessible from a public network.\n\n @param window The window number\n @param status True or False\n\n @example webui_set_public(myWindow, true);"]
+ pub fn webui_set_public(window: usize, status: bool);
+}
+extern "C" {
+ #[doc = " @brief Navigate to a specific URL. All clients.\n\n @param window The window number\n @param url Full HTTP URL\n\n @example webui_navigate(myWindow, \"http://domain.com\");"]
+ pub fn webui_navigate(window: usize, url: *const ::std::os::raw::c_char);
+}
+extern "C" {
+ #[doc = " @brief Navigate to a specific URL. Single client.\n\n @param e The event struct\n @param url Full HTTP URL\n\n @example webui_navigate_client(e, \"http://domain.com\");"]
+ pub fn webui_navigate_client(e: *mut webui_event_t, url: *const ::std::os::raw::c_char);
+}
+extern "C" {
+ #[doc = " @brief Free all memory resources. Should be called only at the end.\n\n @example\n webui_wait();\n webui_clean();"]
+ pub fn webui_clean();
+}
+extern "C" {
+ #[doc = " @brief Delete all local web-browser profiles folder. It should be called at the\n end.\n\n @example\n webui_wait();\n webui_delete_all_profiles();\n webui_clean();"]
+ pub fn webui_delete_all_profiles();
+}
+extern "C" {
+ #[doc = " @brief Delete a specific window web-browser local folder profile.\n\n @param window The window number\n\n @example\n webui_wait();\n webui_delete_profile(myWindow);\n webui_clean();\n\n @note This can break functionality of other windows if using the same\n web-browser."]
+ pub fn webui_delete_profile(window: usize);
+}
+extern "C" {
+ #[doc = " @brief Get the ID of the parent process (The web browser may re-create\n another new process).\n\n @param window The window number\n\n @return Returns the the parent process id as integer\n\n @example size_t id = webui_get_parent_process_id(myWindow);"]
+ pub fn webui_get_parent_process_id(window: usize) -> usize;
+}
+extern "C" {
+ #[doc = " @brief Get the ID of the last child process.\n\n @param window The window number\n\n @return Returns the the child process id as integer\n\n @example size_t id = webui_get_child_process_id(myWindow);"]
+ pub fn webui_get_child_process_id(window: usize) -> usize;
+}
+extern "C" {
+ #[doc = " @brief Get the network port of a running window.\n This can be useful to determine the HTTP link of `webui.js`\n\n @param window The window number\n\n @return Returns the network port of the window\n\n @example size_t port = webui_get_port(myWindow);"]
+ pub fn webui_get_port(window: usize) -> usize;
+}
+extern "C" {
+ #[doc = " @brief Set a custom web-server/websocket network port to be used by WebUI.\n This can be useful to determine the HTTP link of `webui.js` in case\n you are trying to use WebUI with an external web-server like NGNIX.\n\n @param window The window number\n @param port The web-server network port WebUI should use\n\n @return Returns True if the port is free and usable by WebUI\n\n @example bool ret = webui_set_port(myWindow, 8080);"]
+ pub fn webui_set_port(window: usize, port: usize) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Get an available usable free network port.\n\n @return Returns a free port\n\n @example size_t port = webui_get_free_port();"]
+ pub fn webui_get_free_port() -> usize;
+}
+extern "C" {
+ #[doc = " @brief Control the WebUI behaviour. It's recommended to be called at the beginning.\n\n @param option The desired option from `webui_config` enum\n @param status The status of the option, `true` or `false`\n\n @example webui_set_config(show_wait_connection, false);"]
+ pub fn webui_set_config(option: webui_config, status: bool);
+}
+extern "C" {
+ #[doc = " @brief Control if UI events comming from this window should be processed\n one a time in a single blocking thread `True`, or process every event in\n a new non-blocking thread `False`. This update single window. You can use\n `webui_set_config(ui_event_blocking, ...)` to update all windows.\n\n @param window The window number\n @param status The blocking status `true` or `false`\n\n @example webui_set_event_blocking(myWindow, true);"]
+ pub fn webui_set_event_blocking(window: usize, status: bool);
+}
+extern "C" {
+ #[doc = " @brief Get the HTTP mime type of a file.\n\n @return Returns the HTTP mime string\n\n @example const char* mime = webui_get_mime_type(\"foo.png\");"]
+ pub fn webui_get_mime_type(
+ file: *const ::std::os::raw::c_char,
+ ) -> *const ::std::os::raw::c_char;
+}
+extern "C" {
+ #[doc = " @brief Set the SSL/TLS certificate and the private key content, both in PEM\n format. This works only with `webui-2-secure` library. If set empty WebUI\n will generate a self-signed certificate.\n\n @param certificate_pem The SSL/TLS certificate content in PEM format\n @param private_key_pem The private key content in PEM format\n\n @return Returns True if the certificate and the key are valid.\n\n @example bool ret = webui_set_tls_certificate(\"-----BEGIN\n CERTIFICATE-----\\n...\", \"-----BEGIN PRIVATE KEY-----\\n...\");"]
+ pub fn webui_set_tls_certificate(
+ certificate_pem: *const ::std::os::raw::c_char,
+ private_key_pem: *const ::std::os::raw::c_char,
+ ) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Run JavaScript without waiting for the response. All clients.\n\n @param window The window number\n @param script The JavaScript to be run\n\n @example webui_run(myWindow, \"alert('Hello');\");"]
+ pub fn webui_run(window: usize, script: *const ::std::os::raw::c_char);
+}
+extern "C" {
+ #[doc = " @brief Run JavaScript without waiting for the response. Single client.\n\n @param e The event struct\n @param script The JavaScript to be run\n\n @example webui_run_client(e, \"alert('Hello');\");"]
+ pub fn webui_run_client(e: *mut webui_event_t, script: *const ::std::os::raw::c_char);
+}
+extern "C" {
+ #[doc = " @brief Run JavaScript and get the response back. Work only in single client mode.\n Make sure your local buffer can hold the response.\n\n @param window The window number\n @param script The JavaScript to be run\n @param timeout The execution timeout in seconds\n @param buffer The local buffer to hold the response\n @param buffer_length The local buffer size\n\n @return Returns True if there is no execution error\n\n @example bool err = webui_script(myWindow, \"return 4 + 6;\", 0, myBuffer, myBufferSize);"]
+ pub fn webui_script(
+ window: usize,
+ script: *const ::std::os::raw::c_char,
+ timeout: usize,
+ buffer: *mut ::std::os::raw::c_char,
+ buffer_length: usize,
+ ) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Run JavaScript and get the response back. Single client.\n Make sure your local buffer can hold the response.\n\n @param e The event struct\n @param script The JavaScript to be run\n @param timeout The execution timeout in seconds\n @param buffer The local buffer to hold the response\n @param buffer_length The local buffer size\n\n @return Returns True if there is no execution error\n\n @example bool err = webui_script_client(e, \"return 4 + 6;\", 0, myBuffer, myBufferSize);"]
+ pub fn webui_script_client(
+ e: *mut webui_event_t,
+ script: *const ::std::os::raw::c_char,
+ timeout: usize,
+ buffer: *mut ::std::os::raw::c_char,
+ buffer_length: usize,
+ ) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Chose between Deno and Nodejs as runtime for .js and .ts files.\n\n @param window The window number\n @param runtime Deno | Bun | Nodejs | None\n\n @example webui_set_runtime(myWindow, Deno);"]
+ pub fn webui_set_runtime(window: usize, runtime: usize);
+}
+extern "C" {
+ #[doc = " @brief Get how many arguments there are in an event.\n\n @param e The event struct\n\n @return Returns the arguments count.\n\n @example size_t count = webui_get_count(e);"]
+ pub fn webui_get_count(e: *mut webui_event_t) -> usize;
+}
+extern "C" {
+ #[doc = " @brief Get an argument as integer at a specific index.\n\n @param e The event struct\n @param index The argument position starting from 0\n\n @return Returns argument as integer\n\n @example long long int myNum = webui_get_int_at(e, 0);"]
+ pub fn webui_get_int_at(e: *mut webui_event_t, index: usize) -> ::std::os::raw::c_longlong;
+}
+extern "C" {
+ #[doc = " @brief Get the first argument as integer.\n\n @param e The event struct\n\n @return Returns argument as integer\n\n @example long long int myNum = webui_get_int(e);"]
+ pub fn webui_get_int(e: *mut webui_event_t) -> ::std::os::raw::c_longlong;
+}
+extern "C" {
+ #[doc = " @brief Get an argument as float at a specific index.\n\n @param e The event struct\n @param index The argument position starting from 0\n\n @return Returns argument as float\n\n @example double myNum = webui_get_float_at(e, 0);"]
+ pub fn webui_get_float_at(e: *mut webui_event_t, index: usize) -> f64;
+}
+extern "C" {
+ #[doc = " @brief Get the first argument as float.\n\n @param e The event struct\n\n @return Returns argument as float\n\n @example double myNum = webui_get_float(e);"]
+ pub fn webui_get_float(e: *mut webui_event_t) -> f64;
+}
+extern "C" {
+ #[doc = " @brief Get an argument as string at a specific index.\n\n @param e The event struct\n @param index The argument position starting from 0\n\n @return Returns argument as string\n\n @example const char* myStr = webui_get_string_at(e, 0);"]
+ pub fn webui_get_string_at(
+ e: *mut webui_event_t,
+ index: usize,
+ ) -> *const ::std::os::raw::c_char;
+}
+extern "C" {
+ #[doc = " @brief Get the first argument as string.\n\n @param e The event struct\n\n @return Returns argument as string\n\n @example const char* myStr = webui_get_string(e);"]
+ pub fn webui_get_string(e: *mut webui_event_t) -> *const ::std::os::raw::c_char;
+}
+extern "C" {
+ #[doc = " @brief Get an argument as boolean at a specific index.\n\n @param e The event struct\n @param index The argument position starting from 0\n\n @return Returns argument as boolean\n\n @example bool myBool = webui_get_bool_at(e, 0);"]
+ pub fn webui_get_bool_at(e: *mut webui_event_t, index: usize) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Get the first argument as boolean.\n\n @param e The event struct\n\n @return Returns argument as boolean\n\n @example bool myBool = webui_get_bool(e);"]
+ pub fn webui_get_bool(e: *mut webui_event_t) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Get the size in bytes of an argument at a specific index.\n\n @param e The event struct\n @param index The argument position starting from 0\n\n @return Returns size in bytes\n\n @example size_t argLen = webui_get_size_at(e, 0);"]
+ pub fn webui_get_size_at(e: *mut webui_event_t, index: usize) -> usize;
+}
+extern "C" {
+ #[doc = " @brief Get size in bytes of the first argument.\n\n @param e The event struct\n\n @return Returns size in bytes\n\n @example size_t argLen = webui_get_size(e);"]
+ pub fn webui_get_size(e: *mut webui_event_t) -> usize;
+}
+extern "C" {
+ #[doc = " @brief Return the response to JavaScript as integer.\n\n @param e The event struct\n @param n The integer to be send to JavaScript\n\n @example webui_return_int(e, 123);"]
+ pub fn webui_return_int(e: *mut webui_event_t, n: ::std::os::raw::c_longlong);
+}
+extern "C" {
+ #[doc = " @brief Return the response to JavaScript as float.\n\n @param e The event struct\n @param f The float number to be send to JavaScript\n\n @example webui_return_float(e, 123.456);"]
+ pub fn webui_return_float(e: *mut webui_event_t, f: f64);
+}
+extern "C" {
+ #[doc = " @brief Return the response to JavaScript as string.\n\n @param e The event struct\n @param n The string to be send to JavaScript\n\n @example webui_return_string(e, \"Response...\");"]
+ pub fn webui_return_string(e: *mut webui_event_t, s: *const ::std::os::raw::c_char);
+}
+extern "C" {
+ #[doc = " @brief Return the response to JavaScript as boolean.\n\n @param e The event struct\n @param n The boolean to be send to JavaScript\n\n @example webui_return_bool(e, true);"]
+ pub fn webui_return_bool(e: *mut webui_event_t, b: bool);
+}
+extern "C" {
+ #[doc = " @brief Bind a specific HTML element click event with a function. Empty element means all events.\n\n @param window The window number\n @param element The element ID\n @param func The callback as myFunc(Window, EventType, Element, EventNumber, BindID)\n\n @return Returns unique bind ID\n\n @example size_t id = webui_interface_bind(myWindow, \"myID\", myCallback);"]
+ pub fn webui_interface_bind(
+ window: usize,
+ element: *const ::std::os::raw::c_char,
+ func: ::std::option::Option<
+ unsafe extern "C" fn(
+ arg1: usize,
+ arg2: usize,
+ arg3: *mut ::std::os::raw::c_char,
+ arg4: usize,
+ arg5: usize,
+ ),
+ >,
+ ) -> usize;
+}
+extern "C" {
+ #[doc = " @brief When using `webui_interface_bind()`, you may need this function to easily set a response.\n\n @param window The window number\n @param event_number The event number\n @param response The response as string to be send to JavaScript\n\n @example webui_interface_set_response(myWindow, e->event_number, \"Response...\");"]
+ pub fn webui_interface_set_response(
+ window: usize,
+ event_number: usize,
+ response: *const ::std::os::raw::c_char,
+ );
+}
+extern "C" {
+ #[doc = " @brief Check if the app still running.\n\n @return Returns True if app is running\n\n @example bool status = webui_interface_is_app_running();"]
+ pub fn webui_interface_is_app_running() -> bool;
+}
+extern "C" {
+ #[doc = " @brief Get a unique window ID.\n\n @param window The window number\n\n @return Returns the unique window ID as integer\n\n @example size_t id = webui_interface_get_window_id(myWindow);"]
+ pub fn webui_interface_get_window_id(window: usize) -> usize;
+}
+extern "C" {
+ #[doc = " @brief Get an argument as string at a specific index.\n\n @param window The window number\n @param event_number The event number\n @param index The argument position\n\n @return Returns argument as string\n\n @example const char* myStr = webui_interface_get_string_at(myWindow, e->event_number, 0);"]
+ pub fn webui_interface_get_string_at(
+ window: usize,
+ event_number: usize,
+ index: usize,
+ ) -> *const ::std::os::raw::c_char;
+}
+extern "C" {
+ #[doc = " @brief Get an argument as integer at a specific index.\n\n @param window The window number\n @param event_number The event number\n @param index The argument position\n\n @return Returns argument as integer\n\n @example long long int myNum = webui_interface_get_int_at(myWindow, e->event_number, 0);"]
+ pub fn webui_interface_get_int_at(
+ window: usize,
+ event_number: usize,
+ index: usize,
+ ) -> ::std::os::raw::c_longlong;
+}
+extern "C" {
+ #[doc = " @brief Get an argument as float at a specific index.\n\n @param window The window number\n @param event_number The event number\n @param index The argument position\n\n @return Returns argument as float\n\n @example double myFloat = webui_interface_get_int_at(myWindow, e->event_number, 0);"]
+ pub fn webui_interface_get_float_at(window: usize, event_number: usize, index: usize) -> f64;
+}
+extern "C" {
+ #[doc = " @brief Get an argument as boolean at a specific index.\n\n @param window The window number\n @param event_number The event number\n @param index The argument position\n\n @return Returns argument as boolean\n\n @example bool myBool = webui_interface_get_bool_at(myWindow, e->event_number, 0);"]
+ pub fn webui_interface_get_bool_at(window: usize, event_number: usize, index: usize) -> bool;
+}
+extern "C" {
+ #[doc = " @brief Get the size in bytes of an argument at a specific index.\n\n @param window The window number\n @param event_number The event number\n @param index The argument position\n\n @return Returns size in bytes\n\n @example size_t argLen = webui_interface_get_size_at(myWindow, e->event_number, 0);"]
+ pub fn webui_interface_get_size_at(window: usize, event_number: usize, index: usize) -> usize;
+}
diff --git a/src/events.rs b/src/events.rs
new file mode 100644
index 0000000..f60efab
--- /dev/null
+++ b/src/events.rs
@@ -0,0 +1,247 @@
+use std::ffi::CString;
+use std::os::raw::c_char;
+
+use crate::bindgen::*;
+use crate::char_to_string;
+
+// Events
+pub type EventType = webui_event;
+
+// Implement into
+impl EventType {
+ pub fn from_usize(value: usize) -> EventType {
+ match value {
+ 0 => EventType::WEBUI_EVENT_DISCONNECTED,
+ 1 => EventType::WEBUI_EVENT_CONNECTED,
+ 2 => EventType::WEBUI_EVENT_MOUSE_CLICK,
+ 3 => EventType::WEBUI_EVENT_NAVIGATION,
+ 4 => EventType::WEBUI_EVENT_CALLBACK,
+ _ => EventType::WEBUI_EVENT_CALLBACK,
+ }
+ }
+}
+
+pub struct EventSimple {
+ pub win: usize,
+ pub event_type: EventType,
+ pub element: String,
+ pub event_number: usize,
+ pub bind_id: usize,
+}
+
+impl EventSimple {
+ pub fn set_response(&self, response: &str) {
+ // interface_set_response(self.window, self.event_number, response);
+ let response_c_str = CString::new(response).unwrap();
+ let response_c_char: *const c_char = response_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ webui_interface_set_response(self.win, self.event_number, response_c_char);
+ }
+ }
+
+ pub fn get_string_at(&self, index: usize) -> String {
+ unsafe {
+ let string = webui_interface_get_string_at(self.win, self.event_number, index);
+ char_to_string(string)
+ }
+ }
+
+ pub fn get_int_at(&self, index: usize) -> i64 {
+ unsafe { webui_interface_get_int_at(self.win, self.event_number, index) }
+ }
+
+ pub fn get_float_at(&self, index: usize) -> f64 {
+ unsafe { webui_interface_get_float_at(self.win, self.event_number, index) }
+ }
+
+ pub fn get_bool_at(&self, index: usize) -> bool {
+ unsafe { webui_interface_get_bool_at(self.win, self.event_number, index) }
+ }
+
+ pub fn get_size_at(&self, index: usize) -> usize {
+ unsafe { webui_interface_get_size_at(self.win, self.event_number, index) }
+ }
+}
+
+pub struct Event {
+ pub win: usize,
+ pub event_type: EventType,
+ pub element: String,
+ pub event_number: usize,
+ pub bind_id: usize,
+ pub client_id: usize,
+ pub connection_id: usize,
+ pub cookies: String,
+ event: *mut webui_event_t,
+}
+
+impl Event {
+ pub fn new(event: *mut webui_event_t) -> Event {
+ unsafe {
+ let win = (*event).window;
+ let event_type = EventType::from_usize((*event).event_type);
+ let element = char_to_string((*event).element);
+ let event_number = (*event).event_number;
+ let bind_id = (*event).bind_id;
+ let client_id = (*event).client_id;
+ let connection_id = (*event).connection_id;
+ let cookies = char_to_string((*event).cookies);
+
+ Event {
+ win,
+ event_type,
+ element,
+ event_number,
+ bind_id,
+ client_id,
+ connection_id,
+ cookies,
+ event,
+ }
+ }
+ }
+
+ pub fn show_client(&self, content: impl AsRef + Into>) -> bool {
+ unsafe {
+ // Content String to i8/u8
+ let content_c_str = CString::new(content).unwrap();
+ let content_c_char: *const c_char = content_c_str.as_ptr() as *const c_char;
+
+ webui_show_client(self.event, content_c_char)
+ }
+ }
+
+ pub fn close_client(self) {
+ unsafe {
+ webui_close_client(self.event);
+ }
+ }
+
+ pub fn send_raw(&self, function: &str, data: &[u8]) {
+ let size = data.len();
+ let raw = data.as_ptr() as *mut std::os::raw::c_void;
+ let function_c_str = CString::new(function).unwrap();
+ let function_c_char: *const c_char = function_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ webui_send_raw_client(self.event, function_c_char, raw, size);
+ }
+ }
+
+ pub fn navigate_client(&self, url: &str) {
+ let url_c_str = CString::new(url).unwrap();
+ let url_c_char: *const c_char = url_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ webui_navigate_client(self.event, url_c_char);
+ }
+ }
+
+ pub fn run(&self, script: &str) {
+ let script_c_str = CString::new(script).unwrap();
+ let script_c_char: *const c_char = script_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ webui_run_client(self.event, script_c_char);
+ }
+ }
+
+ pub fn script(&self, script: &str, timeout: usize, buffer_length: usize) -> Result {
+ let script_c_str = CString::new(script).unwrap();
+ let script_c_char: *const c_char = script_c_str.as_ptr() as *const c_char;
+
+ let buffer_c_str = CString::new(vec![0; buffer_length]).unwrap();
+ let buffer_c_char: *mut c_char = buffer_c_str.as_ptr() as *mut c_char;
+
+ unsafe {
+ match webui_script_client(
+ self.event,
+ script_c_char,
+ timeout,
+ buffer_c_char,
+ buffer_length,
+ ) {
+ true => Ok(char_to_string(buffer_c_char)),
+ false => Err(()),
+ }
+ }
+ }
+
+ pub fn get_count(&self) -> usize {
+ unsafe { webui_get_count(self.event) }
+ }
+
+ pub fn get_int_at(&self, index: usize) -> i64 {
+ unsafe { webui_get_int_at(self.event, index) }
+ }
+
+ pub fn get_int(&self) -> i64 {
+ unsafe { webui_get_int(self.event) }
+ }
+
+ pub fn get_float_at(&self, index: usize) -> f64 {
+ unsafe { webui_get_float_at(self.event, index) }
+ }
+
+ pub fn get_float(&self) -> f64 {
+ unsafe { webui_get_float(self.event) }
+ }
+
+ pub fn get_string_at(&self, index: usize) -> String {
+ unsafe {
+ let string = webui_get_string_at(self.event, index);
+ char_to_string(string)
+ }
+ }
+
+ pub fn get_string(&self) -> String {
+ unsafe {
+ let string = webui_get_string(self.event);
+ char_to_string(string)
+ }
+ }
+
+ pub fn get_bool_at(&self, index: usize) -> bool {
+ unsafe { webui_get_bool_at(self.event, index) }
+ }
+
+ pub fn get_bool(&self) -> bool {
+ unsafe { webui_get_bool(self.event) }
+ }
+
+ pub fn get_size_at(&self, index: usize) -> usize {
+ unsafe { webui_get_size_at(self.event, index) }
+ }
+
+ pub fn get_size(&self) -> usize {
+ unsafe { webui_get_size(self.event) }
+ }
+
+ pub fn return_int(&self, value: i64) {
+ unsafe {
+ webui_return_int(self.event, value);
+ }
+ }
+
+ pub fn return_float(&self, value: f64) {
+ unsafe {
+ webui_return_float(self.event, value);
+ }
+ }
+
+ pub fn return_string(&self, value: &str) {
+ let value_c_str = CString::new(value).unwrap();
+ let value_c_char: *const c_char = value_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ webui_return_string(self.event, value_c_char);
+ }
+ }
+
+ pub fn return_bool(&self, value: bool) {
+ unsafe {
+ webui_return_bool(self.event, value);
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 38df129..7ecfeb0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,32 @@
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
+
+pub mod bindgen;
+pub mod events;
pub mod webui;
+pub mod window;
+
+// Re-export
+// pub use bindgen::*;
+// pub use events::*;
+// pub use webui::*;
+pub use window::Window;
+
+use bindgen::{webui_browser, webui_config, webui_runtime};
+use std::ffi::CStr;
+
+// Browsers
+pub type Browser = webui_browser;
+// Runtimes
+pub type Runtime = webui_runtime;
+// Configs
+pub type Config = webui_config;
+
+fn char_to_string(c: *const i8) -> String {
+ let cstr = unsafe { CStr::from_ptr(c) };
+ let s: String = String::from_utf8_lossy(cstr.to_bytes()).to_string();
+ s
+}
#[cfg(test)]
mod tests {
@@ -6,7 +34,7 @@ mod tests {
#[test]
fn test_webui_window() {
- let win = webui::Window::new();
+ let win = window::Window::new();
assert_eq!(win.id, 1);
win.show("Hello World");
diff --git a/src/webui.rs b/src/webui.rs
index 94e527a..2da9804 100644
--- a/src/webui.rs
+++ b/src/webui.rs
@@ -9,374 +9,214 @@
*/
// Flags
-#![allow(unsafe_code)]
+// #![allow(unsafe_code)]
#![allow(dead_code)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
-pub mod bindgen;
-
// Modules
+use crate::char_to_string;
+use crate::events::EventSimple;
+use crate::events::EventType;
+use crate::Browser;
+use crate::Config;
use std::collections::HashMap;
-use std::ffi::CStr;
use std::ffi::CString;
use std::os::raw::c_char;
+use std::sync::LazyLock;
+use std::sync::Mutex;
+
+use crate::bindgen::*;
-use bindgen::*;
-use lazy_static::lazy_static;
-use std::sync::{Mutex, MutexGuard};
-
-// Consts
-pub const true_: u32 = 1;
-pub const false_: u32 = 0;
-pub const __bool_true_false_are_defined: u32 = 1;
-pub type size_t = ::std::os::raw::c_ulong;
-pub type wchar_t = ::std::os::raw::c_int;
-
-// Browsers
-pub enum WebUIBrowser {
- NoBrowser = 0,
- AnyBrowser = 1,
- Chrome,
- Firefox,
- Edge,
- Safari,
- Chromium,
- Opera,
- Brave,
- Vivaldi,
- Epic,
- Yandex,
- ChromiumBased,
+const WINDOWS: usize = 64;
+const ELEMENTS: usize = 64;
+
+pub struct BindStore {
+ func_store: Mutex<[[Option; ELEMENTS]; WINDOWS]>,
+ elements_map: Mutex>,
}
-impl Clone for WebUIBrowser {
- fn clone(&self) -> Self {
- *self
+impl BindStore {
+ pub fn new() -> BindStore {
+ BindStore {
+ func_store: Mutex::new([[None; ELEMENTS]; WINDOWS]),
+ elements_map: Mutex::new(HashMap::new()),
+ }
}
-}
-impl Copy for WebUIBrowser {}
+ fn save_string(&self, s: &str) -> usize {
+ let mut map = self.elements_map.lock().unwrap();
+ // Check if the string already exists in the map
+ if let Some(&index) = map.get(s) {
+ return index;
+ }
-impl WebUIBrowser {
- pub fn to_usize(&self) -> usize {
- *self as usize
+ // If the string does not exist, add it to the map and return the new index
+ let index = map.len();
+ map.insert(s.to_owned(), index);
+ index
}
-}
-// Impl equality operator
-impl PartialEq for WebUIBrowser {
- fn eq(&self, other: &Self) -> bool {
- self.to_usize() == other.to_usize()
+ fn find_string(&self, s: &str) -> isize {
+ let map = self.elements_map.lock().unwrap();
+ if let Some(&index) = map.get(s) {
+ index as isize
+ } else {
+ -1
+ }
}
-}
-
-// Runtimes
-pub enum WebUIRuntime {
- None = 0,
- Deno = 1,
- NodeJS = 2,
-}
-// Events
-pub enum WebUIEvent {
- WebUiEventDisconnected = 0,
- WebUiEventConnected = 1,
- WebUiEventMultiConnection = 2,
- WebUiEventUnwantedConnection = 3,
- WebUiEventMouseClick = 4,
- WebUiEventNavigation = 5,
- WebUiEventCallback = 6,
-}
+ pub fn add_function(&self, window: usize, element: &str, func: T) {
+ let element_index = self.save_string(element);
+ self.func_store.lock().unwrap()[window][element_index] = Some(func);
+ }
-// Implement into
-impl WebUIEvent {
- pub fn from_usize(value: usize) -> WebUIEvent {
- match value {
- 0 => WebUIEvent::WebUiEventDisconnected,
- 1 => WebUIEvent::WebUiEventConnected,
- 2 => WebUIEvent::WebUiEventMultiConnection,
- 3 => WebUIEvent::WebUiEventUnwantedConnection,
- 4 => WebUIEvent::WebUiEventMouseClick,
- 5 => WebUIEvent::WebUiEventNavigation,
- 6 => WebUIEvent::WebUiEventCallback,
- _ => WebUIEvent::WebUiEventCallback,
+ pub fn get_function(&self, window: usize, element: &str) -> Option {
+ let element_index = self.find_string(element);
+ if element_index < 0 {
+ return None;
}
+ self.func_store.lock().unwrap()[window][element_index as usize]
}
}
-pub struct JavaScript {
- pub timeout: usize,
- pub script: String,
- pub error: bool,
- pub data: String,
-}
+static mut BIND_STORE_SIMPLE: LazyLock> =
+ LazyLock::new(|| BindStore::new());
-// Window, EventType, Element, EventNumber, BindID
-pub struct Event {
- pub window: usize,
- pub event_type: WebUIEvent,
- pub element: *mut c_char,
- pub event_number: usize,
- pub bind_id: usize,
+// Function Implementations
+pub fn new_window() -> usize {
+ unsafe {
+ // GLOBAL_ARRAY = [[GlobalArray::None; COLS]; ROWS];
+ webui_new_window()
+ }
}
-impl Event {
- pub fn get_window(&self) -> Window {
- Window::from_id(self.window)
+pub fn new_window_id(id: usize) -> usize {
+ unsafe {
+ // GLOBAL_ARRAY = [[GlobalArray::None; COLS]; ROWS];
+ webui_new_window_id(id)
}
}
-pub struct Window {
- pub id: usize,
+pub fn get_new_window_id() -> usize {
+ unsafe { webui_get_new_window_id() }
}
-impl Default for Window {
- fn default() -> Self {
- Self::new()
- }
+pub fn is_high_contrast() -> bool {
+ unsafe { webui_is_high_contrast() }
}
-impl Window {
- pub fn new() -> Window {
- let id = new_window();
- Window { id }
- }
-
- pub fn from_id(id: usize) -> Window {
- Window { id }
- }
-
- pub fn show(&self, content: impl AsRef) -> bool {
- show(self.id, content.as_ref())
- }
-
- pub fn show_browser(&self, content: impl AsRef, browser: WebUIBrowser) -> bool {
- show_browser(self.id, content.as_ref(), browser)
- }
-
- pub fn is_shown(&self) -> bool {
- is_shown(self.id)
- }
-
- pub fn bind(&self, element: impl AsRef, func: fn(Event)) {
- bind(self.id, element.as_ref(), func);
- }
-
- pub fn run_js(&self, js: impl AsRef) -> JavaScript {
- let mut js = JavaScript {
- timeout: 0,
- script: js.as_ref().to_string(),
- error: false,
- data: "".to_string(),
- };
-
- run_js(self.id, &mut js);
-
- js
- }
-
- pub fn set_icon(&self, icon: impl AsRef, kind: impl AsRef) {
- set_icon(self.id, icon.as_ref(), kind.as_ref());
- }
-
- pub fn set_file_handler(
- &self,
- handler: unsafe extern "C" fn(*const i8, *mut i32) -> *const std::os::raw::c_void,
- ) {
- set_file_handler(self.id, handler);
- }
-
- pub fn set_runtime(&self, runtime: WebUIRuntime) {
- set_runtime(self.id, runtime);
- }
-
- pub fn close(&self) {
- close(self.id);
- }
-
- pub fn destroy(&self) {
- destroy(self.id);
+pub fn browser_exist(browser: Browser) {
+ unsafe {
+ webui_browser_exist(browser as usize);
}
}
-impl Drop for Window {
- fn drop(&mut self) {
- destroy(self.id);
+pub fn wait() {
+ unsafe {
+ webui_wait();
}
}
-// List of Rust user functions (2-dimensional array)
-// static mut func_list: [[Option:: ()>; 64]; 64] = [[64; 64]; 64];
-// static mut func_array: Vec> = vec![vec![]; 1024];
-// static mut elements_map = HashMap::::new();
-// static mut elements_map: HashMap::new();
-
-type FunctionType = fn(Event);
-const ROWS: usize = 64;
-const COLS: usize = 64;
-
-#[derive(Copy, Clone, Default)]
-enum GlobalArray {
- #[default]
- None,
- Some(FunctionType),
+pub fn exit() {
+ unsafe {
+ webui_exit();
+ }
}
-static mut GLOBAL_ARRAY: [[GlobalArray; COLS]; ROWS] = [[GlobalArray::None; COLS]; ROWS];
-
-lazy_static! {
- static ref ELEMENTS_MAP: Mutex> = Mutex::new(HashMap::new());
- // static mut func_array: Vec> = vec![vec![]; 1024];
-}
+pub fn set_default_root_folder(folder: &str) {
+ let folder_c_str = CString::new(folder).unwrap();
+ let folder_c_char: *const c_char = folder_c_str.as_ptr() as *const c_char;
-// Save a string in the map and return its index
-fn save_string(mut map: MutexGuard>, s: &str) -> usize {
- // Check if the string already exists in the map
- if let Some(&index) = map.get(s) {
- return index;
+ unsafe {
+ webui_set_default_root_folder(folder_c_char);
}
-
- // If the string does not exist, add it to the map and return the new index
- let index = map.len();
- map.insert(s.to_owned(), index);
- index
}
-// Search for a string in the map and return its index if found, or -1 if not found
-fn find_string(map: &HashMap, s: &str) -> isize {
- if let Some(&index) = map.get(s) {
- index as isize
- } else {
- -1
+pub fn set_timeout(seconds: usize) {
+ unsafe {
+ webui_set_timeout(seconds);
}
}
-fn char_to_string(c: *const i8) -> String {
- let cstr = unsafe { CStr::from_ptr(c) };
- let s: String = String::from_utf8_lossy(cstr.to_bytes()).to_string();
- s
-}
+pub fn encode(data: &str) -> String {
+ let data_c_str = CString::new(data).unwrap();
+ let data_c_char: *const c_char = data_c_str.as_ptr() as *const c_char;
-fn cstr_to_string(c: CString) -> String {
- let s: String = String::from_utf8_lossy(c.to_bytes()).to_string();
- s
+ unsafe {
+ let encoded = webui_encode(data_c_char);
+ char_to_string(encoded)
+ }
}
-pub fn run_js(win: usize, js: &mut JavaScript) {
- /// The WebUI Script Interface
- struct WebUIScriptIntf {
- timeout: usize,
- script: *mut i8,
- error: bool,
- data: *const i8,
- length: usize,
- }
+pub fn decode(data: &str) -> String {
+ let data_c_str = CString::new(data).unwrap();
+ let data_c_char: *const c_char = data_c_str.as_ptr() as *const c_char;
unsafe {
- // Script String to i8/u8
- let script_cpy = js.script.clone();
- let script_c_str = CString::new(script_cpy).unwrap();
- let script_c_char: *mut c_char = script_c_str.as_ptr() as *mut c_char;
-
- let wuisi = WebUIScriptIntf {
- timeout: js.timeout,
- script: script_c_char,
- data: script_c_char,
- error: false,
- length: 0,
- };
-
- webui_script(
- win,
- wuisi.script,
- wuisi.timeout,
- script_c_char,
- wuisi.length,
- );
-
- js.error = wuisi.error;
- js.data = char_to_string(wuisi.data);
+ let decoded = webui_decode(data_c_char);
+ char_to_string(decoded)
}
}
-pub fn new_window() -> usize {
+pub fn free(data: *mut std::os::raw::c_void) {
unsafe {
- GLOBAL_ARRAY = [[GlobalArray::None; COLS]; ROWS];
- webui_new_window()
+ webui_free(data);
}
}
-pub fn wait() {
- unsafe {
- webui_wait();
- }
+pub fn malloc(size: usize) -> *mut std::os::raw::c_void {
+ unsafe { webui_malloc(size) }
}
-pub fn set_timeout(seconds: usize) {
+pub fn open_url(url: &str) {
+ let url_c_str = CString::new(url).unwrap();
+ let url_c_char: *const c_char = url_c_str.as_ptr() as *const c_char;
+
unsafe {
- webui_set_timeout(seconds);
+ webui_open_url(url_c_char);
}
}
-pub fn exit() {
+pub fn clean() {
unsafe {
- webui_exit();
+ webui_clean();
}
}
-pub fn show(win: usize, content: impl AsRef + Into>) -> bool {
+pub fn delete_all_profiles() {
unsafe {
- // Content String to i8/u8
- let content_c_str = CString::new(content).unwrap();
- let content_c_char: *const c_char = content_c_str.as_ptr() as *const c_char;
-
- webui_show(win, content_c_char)
+ webui_delete_all_profiles();
}
}
-pub fn show_browser(
- win: usize,
- content: impl AsRef + Into>,
- browser: WebUIBrowser,
-) -> bool {
- let content_c_str = CString::new(content).unwrap();
- let content_c_char: *const c_char = content_c_str.as_ptr() as *const c_char;
-
- unsafe { webui_show_browser(win, content_c_char, browser as usize) }
-}
-
-pub fn is_shown(win: usize) -> bool {
- unsafe { webui_is_shown(win) }
+pub fn get_free_port() -> usize {
+ unsafe { webui_get_free_port() }
}
-pub fn set_icon(win: usize, icon: &str, kind: &str) {
- let icon_c_str = CString::new(icon).unwrap();
- let kind_c_str = CString::new(kind).unwrap();
- let icon_c_char: *const c_char = icon_c_str.as_ptr() as *const c_char;
- let kind_c_char: *const c_char = kind_c_str.as_ptr() as *const c_char;
-
+pub fn set_config(option: Config, enabled: bool) {
unsafe {
- webui_set_icon(win, icon_c_char, kind_c_char);
+ webui_set_config(option as webui_config, enabled);
}
}
-pub fn set_runtime(win: usize, runtime: WebUIRuntime) {
- unsafe {
- webui_set_runtime(win, runtime as usize);
- }
-}
+pub fn get_mime_type(file: &str) -> String {
+ let file_c_str = CString::new(file).unwrap();
+ let file_c_char: *const c_char = file_c_str.as_ptr() as *const c_char;
-pub fn close(win: usize) {
unsafe {
- webui_close(win);
+ let mime = webui_get_mime_type(file_c_char);
+ char_to_string(mime)
}
}
-pub fn destroy(win: usize) {
- unsafe {
- webui_destroy(win);
- }
+pub fn set_tls_certificate(cert_pem: &str, key_pem: &str) -> bool {
+ let cert_pem_c_str = CString::new(cert_pem).unwrap();
+ let key_pem_c_str = CString::new(key_pem).unwrap();
+ let cert_pem_c_char: *const c_char = cert_pem_c_str.as_ptr() as *const c_char;
+ let key_pem_c_char: *const c_char = key_pem_c_str.as_ptr() as *const c_char;
+
+ unsafe { webui_set_tls_certificate(cert_pem_c_char, key_pem_c_char) }
}
unsafe extern "C" fn events_handler(
@@ -386,46 +226,29 @@ unsafe extern "C" fn events_handler(
event_number: usize,
bind_id: usize,
) {
- let map = ELEMENTS_MAP.lock().unwrap();
-
- let element_index = find_string(&map, &char_to_string(element));
- if element_index < 0 {
- return;
- }
-
- let evt = Event {
- window,
- event_type: WebUIEvent::from_usize(event_type),
- element,
- event_number,
- bind_id,
- };
-
// Call the Rust user function
- let element_index_64 = element_index as usize;
unsafe {
let window_id = webui_interface_get_window_id(window);
- let window_id_64 = window_id;
- // func_list[window_id_64][element_index_64].expect("non-null function pointer")(E);
- // func_array[window_id_64][element_index_64](E);
- // if let Some(func) = GLOBAL_ARRAY[window_id_64][element_index_64] {
- // func(E.clone());
- // }
- if let GlobalArray::Some(func) = GLOBAL_ARRAY[window_id_64][element_index_64] {
+
+ if let Some(func) = BIND_STORE_SIMPLE.get_function(window_id, &char_to_string(element)) {
+ let evt = EventSimple {
+ win: window,
+ event_type: EventType::from_usize(event_type),
+ element: char_to_string(element),
+ event_number,
+ bind_id,
+ };
+
func(evt);
}
}
}
-pub fn bind(win: usize, element: &str, func: fn(Event)) {
- let map = ELEMENTS_MAP.lock().unwrap();
-
+pub fn interface_bind(win: usize, element: &str, func: fn(EventSimple)) -> usize {
// Element String to i8/u8
let element_c_str = CString::new(element).unwrap();
let element_c_char: *const c_char = element_c_str.as_ptr() as *const c_char;
- let element_index = save_string(map, element);
-
// Bind
unsafe {
let f: Option<
@@ -433,26 +256,18 @@ pub fn bind(win: usize, element: &str, func: fn(Event)) {
> = Some(events_handler);
let window_id = webui_interface_get_window_id(win);
- let window_id_64 = window_id;
- let element_index_64 = element_index;
-
- webui_interface_bind(win, element_c_char, f);
// Add the Rust user function to the list
- // let user_cb: Option = Some(func);
- // func_list[window_id_64][element_index_64] = user_cb;
- // func_array[window_id_64][element_index_64] = func;
- // GLOBAL_ARRAY[window_id_64][element_index_64] = Some(func as FunctionType);
+ BIND_STORE_SIMPLE.add_function(window_id, element, func);
- GLOBAL_ARRAY[window_id_64][element_index_64] = GlobalArray::Some(func as FunctionType);
+ webui_interface_bind(win, element_c_char, f)
}
}
-pub fn set_file_handler(
- win: usize,
- handler: unsafe extern "C" fn(*const i8, *mut i32) -> *const std::os::raw::c_void,
-) {
- unsafe {
- webui_set_file_handler(win, Some(handler));
- }
+pub fn interface_is_app_running() -> bool {
+ unsafe { webui_interface_is_app_running() }
+}
+
+pub fn interface_get_window_id(win: usize) -> usize {
+ unsafe { webui_interface_get_window_id(win) }
}
diff --git a/src/webui/bindgen.rs b/src/webui/bindgen.rs
deleted file mode 100644
index 9ce4df0..0000000
--- a/src/webui/bindgen.rs
+++ /dev/null
@@ -1,316 +0,0 @@
-// Event struct
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct webui_event_t {
- pub window: *mut ::std::os::raw::c_void,
- pub type_: ::std::os::raw::c_uint,
- pub element: *mut ::std::os::raw::c_char,
- pub data: *mut ::std::os::raw::c_char,
- pub response: *mut ::std::os::raw::c_char,
-}
-
-extern "C" {
- #[doc = " @brief Create a new WebUI window object.\n\n @return Returns the window number.\n\n @example size_t myWindow = webui_new_window();"]
- pub fn webui_new_window() -> usize;
-}
-extern "C" {
- #[doc = " @brief Create a new webui window object using a specified window number.\n\n @param window_number The window number (should be > 0, and < WEBUI_MAX_IDS)\n\n @return Returns the window number.\n\n @example size_t myWindow = webui_new_window_id(123);"]
- pub fn webui_new_window_id(window_number: usize) -> usize;
-}
-extern "C" {
- #[doc = " @brief Get a free window number that can be used with\n `webui_new_window_id()`.\n\n @return Returns the first available free window number. Starting from 1.\n\n @example size_t myWindowNumber = webui_get_new_window_id();"]
- pub fn webui_get_new_window_id() -> usize;
-}
-extern "C" {
- #[doc = " @brief Bind a specific html element click event with a function. Empty\n element means all events.\n\n @param window The window number\n @param element The HTML ID\n @param func The callback function\n\n @return Returns a unique bind ID.\n\n @example webui_bind(myWindow, \"myID\", myFunction);"]
- pub fn webui_bind(
- window: usize,
- element: *const ::std::os::raw::c_char,
- func: ::std::option::Option,
- ) -> usize;
-}
-extern "C" {
- #[doc = " @brief Show a window using embedded HTML, or a file. If the window is already\n open, it will be refreshed.\n\n @param window The window number\n @param content The HTML, URL, Or a local file\n\n @return Returns True if showing the window is successed.\n\n @example webui_show(myWindow, \"...\"); | webui_show(myWindow,\n \"index.html\"); | webui_show(myWindow, \"http://...\");"]
- pub fn webui_show(window: usize, content: *const ::std::os::raw::c_char) -> bool;
-}
-extern "C" {
- #[doc = " @brief Same as `webui_show()`. But using a specific web browser.\n\n @param window The window number\n @param content The HTML, Or a local file\n @param browser The web browser to be used\n\n @return Returns True if showing the window is successed.\n\n @example webui_show_browser(myWindow, \"...\", Chrome); |\n webui_show(myWindow, \"index.html\", Firefox);"]
- pub fn webui_show_browser(
- window: usize,
- content: *const ::std::os::raw::c_char,
- browser: usize,
- ) -> bool;
-}
-extern "C" {
- #[doc = " @brief Set the window in Kiosk mode (Full screen)\n\n @param window The window number\n @param status True or False\n\n @example webui_set_kiosk(myWindow, true);"]
- pub fn webui_set_kiosk(window: usize, status: bool);
-}
-extern "C" {
- #[doc = " @brief Wait until all opened windows get closed.\n\n @example webui_wait();"]
- pub fn webui_wait();
-}
-extern "C" {
- #[doc = " @brief Close a specific window only. The window object will still exist.\n\n @param window The window number\n\n @example webui_close(myWindow);"]
- pub fn webui_close(window: usize);
-}
-extern "C" {
- #[doc = " @brief Close a specific window and free all memory resources.\n\n @param window The window number\n\n @example webui_destroy(myWindow);"]
- pub fn webui_destroy(window: usize);
-}
-extern "C" {
- #[doc = " @brief Close all open windows. `webui_wait()` will return (Break).\n\n @example webui_exit();"]
- pub fn webui_exit();
-}
-extern "C" {
- #[doc = " @brief Set the web-server root folder path for a specific window.\n\n @param window The window number\n @param path The local folder full path\n\n @example webui_set_root_folder(myWindow, \"/home/Foo/Bar/\");"]
- pub fn webui_set_root_folder(window: usize, path: *const ::std::os::raw::c_char) -> bool;
-}
-extern "C" {
- #[doc = " @brief Set the web-server root folder path for all windows. Should be used\n before `webui_show()`.\n\n @param path The local folder full path\n\n @example webui_set_default_root_folder(\"/home/Foo/Bar/\");"]
- pub fn webui_set_default_root_folder(path: *const ::std::os::raw::c_char) -> bool;
-}
-extern "C" {
- #[doc = " @brief Set a custom handler to serve files.\n\n @param window The window number\n @param handler The handler function: `void myHandler(const char* filename,\n int* length)`\n\n @return Returns a unique bind ID.\n\n @example webui_set_file_handler(myWindow, myHandlerFunction);"]
- pub fn webui_set_file_handler(
- window: usize,
- handler: ::std::option::Option<
- unsafe extern "C" fn(
- filename: *const ::std::os::raw::c_char,
- length: *mut ::std::os::raw::c_int,
- ) -> *const ::std::os::raw::c_void,
- >,
- );
-}
-extern "C" {
- #[doc = " @brief Check if the specified window is still running.\n\n @param window The window number\n\n @example webui_is_shown(myWindow);"]
- pub fn webui_is_shown(window: usize) -> bool;
-}
-extern "C" {
- #[doc = " @brief Set the maximum time in seconds to wait for the browser to start.\n\n @param second The timeout in seconds\n\n @example webui_set_timeout(30);"]
- pub fn webui_set_timeout(second: usize);
-}
-extern "C" {
- #[doc = " @brief Set the default embedded HTML favicon.\n\n @param window The window number\n @param icon The icon as string: ``\n @param icon_type The icon type: `image/svg+xml`\n\n @example webui_set_icon(myWindow, \"\", \"image/svg+xml\");"]
- pub fn webui_set_icon(
- window: usize,
- icon: *const ::std::os::raw::c_char,
- icon_type: *const ::std::os::raw::c_char,
- );
-}
-extern "C" {
- #[doc = " @brief Base64 encoding. Use this to safely send text based data to the UI. If\n it fails it will return NULL.\n\n @param str The string to encode (Should be null terminated)\n\n @example webui_encode(\"Hello\");"]
- pub fn webui_encode(str_: *const ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char;
-}
-extern "C" {
- #[doc = " @brief Base64 decoding. Use this to safely decode received Base64 text from\n the UI. If it fails it will return NULL.\n\n @param str The string to decode (Should be null terminated)\n\n @example webui_decode(\"SGVsbG8=\");"]
- pub fn webui_decode(str_: *const ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char;
-}
-extern "C" {
- #[doc = " @brief Safely free a buffer allocated by WebUI using `webui_malloc()`.\n\n @param ptr The buffer to be freed\n\n @example webui_free(myBuffer);"]
- pub fn webui_free(ptr: *mut ::std::os::raw::c_void);
-}
-extern "C" {
- #[doc = " @brief Safely allocate memory using the WebUI memory management system. It\n can be safely freed using `webui_free()` at any time.\n\n @param size The size of memory in bytes\n\n @example char* myBuffer = (char*)webui_malloc(1024);"]
- pub fn webui_malloc(size: usize) -> *mut ::std::os::raw::c_void;
-}
-extern "C" {
- #[doc = " @brief Safely send raw data to the UI.\n\n @param window The window number\n @param function The JavaScript function to receive raw data: `function\n myFunc(myData){}`\n @param raw The raw data buffer\n @param size The raw data size in bytes\n\n @example webui_send_raw(myWindow, \"myJavascriptFunction\", myBuffer, 64);"]
- pub fn webui_send_raw(
- window: usize,
- function: *const ::std::os::raw::c_char,
- raw: *const ::std::os::raw::c_void,
- size: usize,
- );
-}
-extern "C" {
- #[doc = " @brief Set a window in hidden mode. Should be called before `webui_show()`.\n\n @param window The window number\n @param status The status: True or False\n\n @example webui_set_hide(myWindow, True);"]
- pub fn webui_set_hide(window: usize, status: bool);
-}
-extern "C" {
- #[doc = " @brief Set the window size.\n\n @param window The window number\n @param width The window width\n @param height The window height\n\n @example webui_set_size(myWindow, 800, 600);"]
- pub fn webui_set_size(
- window: usize,
- width: ::std::os::raw::c_uint,
- height: ::std::os::raw::c_uint,
- );
-}
-extern "C" {
- #[doc = " @brief Set the window position.\n\n @param window The window number\n @param x The window X\n @param y The window Y\n\n @example webui_set_position(myWindow, 100, 100);"]
- pub fn webui_set_position(window: usize, x: ::std::os::raw::c_uint, y: ::std::os::raw::c_uint);
-}
-extern "C" {
- #[doc = " @brief Set the web browser profile to use. An empty `name` and `path` means\n the default user profile. Need to be called before `webui_show()`.\n\n @param window The window number\n @param name The web browser profile name\n @param path The web browser profile full path\n\n @example webui_set_profile(myWindow, \"Bar\", \"/Home/Foo/Bar\"); |\n webui_set_profile(myWindow, \"\", \"\");"]
- pub fn webui_set_profile(
- window: usize,
- name: *const ::std::os::raw::c_char,
- path: *const ::std::os::raw::c_char,
- );
-}
-extern "C" {
- #[doc = " @brief Set the web browser proxy_server to use. Need to be called before `webui_show()`.\n\n @param window The window number\n @param proxy_server The web browser proxy_server\n\n @example webui_set_proxy(myWindow, \"http://127.0.0.1:8888\");"]
- pub fn webui_set_proxy(window: usize, proxy_server: *const ::std::os::raw::c_char);
-}
-extern "C" {
- #[doc = " @brief Get the full current URL.\n\n @param window The window number\n\n @return Returns the full URL string\n\n @example const char* url = webui_get_url(myWindow);"]
- pub fn webui_get_url(window: usize) -> *const ::std::os::raw::c_char;
-}
-extern "C" {
- #[doc = " @brief Allow a specific window address to be accessible from a public network\n\n @param window The window number\n @param status True or False\n\n @example webui_set_public(myWindow, true);"]
- pub fn webui_set_public(window: usize, status: bool);
-}
-extern "C" {
- #[doc = " @brief Navigate to a specific URL\n\n @param window The window number\n @param url Full HTTP URL\n\n @example webui_navigate(myWindow, \"http://domain.com\");"]
- pub fn webui_navigate(window: usize, url: *const ::std::os::raw::c_char);
-}
-extern "C" {
- #[doc = " @brief Free all memory resources. Should be called only at the end.\n\n @example\n webui_wait();\n webui_clean();"]
- pub fn webui_clean();
-}
-extern "C" {
- #[doc = " @brief Delete all local web-browser profiles folder. It should called at the\n end.\n\n @example\n webui_wait();\n webui_delete_all_profiles();\n webui_clean();"]
- pub fn webui_delete_all_profiles();
-}
-extern "C" {
- #[doc = " @brief Delete a specific window web-browser local folder profile.\n\n @param window The window number\n\n @example\n webui_wait();\n webui_delete_profile(myWindow);\n webui_clean();\n\n @note This can break functionality of other windows if using the same\n web-browser."]
- pub fn webui_delete_profile(window: usize);
-}
-extern "C" {
- #[doc = " @brief Get the ID of the parent process (The web browser may re-create\n another new process).\n\n @param window The window number\n\n @return Returns the the parent process id as integer\n\n @example size_t id = webui_get_parent_process_id(myWindow);"]
- pub fn webui_get_parent_process_id(window: usize) -> usize;
-}
-extern "C" {
- #[doc = " @brief Get the ID of the last child process.\n\n @param window The window number\n\n @return Returns the the child process id as integer\n\n @example size_t id = webui_get_child_process_id(myWindow);"]
- pub fn webui_get_child_process_id(window: usize) -> usize;
-}
-extern "C" {
- #[doc = " @brief Set a custom web-server network port to be used by WebUI.\n This can be useful to determine the HTTP link of `webui.js` in case\n you are trying to use WebUI with an external web-server like NGNIX\n\n @param window The window number\n @param port The web-server network port WebUI should use\n\n @return Returns True if the port is free and usable by WebUI\n\n @example bool ret = webui_set_port(myWindow, 8080);"]
- pub fn webui_set_port(window: usize, port: usize) -> bool;
-}
-extern "C" {
- #[doc = " @brief Set the SSL/TLS certificate and the private key content, both in PEM\n format. This works only with `webui-2-secure` library. If set empty WebUI\n will generate a self-signed certificate.\n\n @param certificate_pem The SSL/TLS certificate content in PEM format\n @param private_key_pem The private key content in PEM format\n\n @return Returns True if the certificate and the key are valid.\n\n @example bool ret = webui_set_tls_certificate(\"-----BEGIN\n CERTIFICATE-----\\n...\", \"-----BEGIN PRIVATE KEY-----\\n...\");"]
- pub fn webui_set_tls_certificate(
- certificate_pem: *const ::std::os::raw::c_char,
- private_key_pem: *const ::std::os::raw::c_char,
- ) -> bool;
-}
-extern "C" {
- #[doc = " @brief Run JavaScript without waiting for the response.\n\n @param window The window number\n @param script The JavaScript to be run\n\n @example webui_run(myWindow, \"alert('Hello');\");"]
- pub fn webui_run(window: usize, script: *const ::std::os::raw::c_char);
-}
-extern "C" {
- #[doc = " @brief Run JavaScript and get the response back.\n Make sure your local buffer can hold the response.\n\n @param window The window number\n @param script The JavaScript to be run\n @param timeout The execution timeout\n @param buffer The local buffer to hold the response\n @param buffer_length The local buffer size\n\n @return Returns True if there is no execution error\n\n @example bool err = webui_script(myWindow, \"return 4 + 6;\", 0, myBuffer, myBufferSize);"]
- pub fn webui_script(
- window: usize,
- script: *const ::std::os::raw::c_char,
- timeout: usize,
- buffer: *mut ::std::os::raw::c_char,
- buffer_length: usize,
- ) -> bool;
-}
-extern "C" {
- #[doc = " @brief Chose between Deno and Nodejs as runtime for .js and .ts files.\n\n @param window The window number\n @param runtime Deno | Nodejs\n\n @example webui_set_runtime(myWindow, Deno);"]
- pub fn webui_set_runtime(window: usize, runtime: usize);
-}
-extern "C" {
- #[doc = " @brief Get an argument as integer at a specific index\n\n @param e The event struct\n @param index The argument position starting from 0\n\n @return Returns argument as integer\n\n @example long long int myNum = webui_get_int_at(e, 0);"]
- pub fn webui_get_int_at(e: *mut webui_event_t, index: usize) -> ::std::os::raw::c_longlong;
-}
-extern "C" {
- #[doc = " @brief Get the first argument as integer\n\n @param e The event struct\n\n @return Returns argument as integer\n\n @example long long int myNum = webui_get_int(e);"]
- pub fn webui_get_int(e: *mut webui_event_t) -> ::std::os::raw::c_longlong;
-}
-extern "C" {
- #[doc = " @brief Get an argument as string at a specific index\n\n @param e The event struct\n @param index The argument position starting from 0\n\n @return Returns argument as string\n\n @example const char* myStr = webui_get_string_at(e, 0);"]
- pub fn webui_get_string_at(
- e: *mut webui_event_t,
- index: usize,
- ) -> *const ::std::os::raw::c_char;
-}
-extern "C" {
- #[doc = " @brief Get the first argument as string\n\n @param e The event struct\n\n @return Returns argument as string\n\n @example const char* myStr = webui_get_string(e);"]
- pub fn webui_get_string(e: *mut webui_event_t) -> *const ::std::os::raw::c_char;
-}
-extern "C" {
- #[doc = " @brief Get an argument as boolean at a specific index\n\n @param e The event struct\n @param index The argument position starting from 0\n\n @return Returns argument as boolean\n\n @example bool myBool = webui_get_bool_at(e, 0);"]
- pub fn webui_get_bool_at(e: *mut webui_event_t, index: usize) -> bool;
-}
-extern "C" {
- #[doc = " @brief Get the first argument as boolean\n\n @param e The event struct\n\n @return Returns argument as boolean\n\n @example bool myBool = webui_get_bool(e);"]
- pub fn webui_get_bool(e: *mut webui_event_t) -> bool;
-}
-extern "C" {
- #[doc = " @brief Get the size in bytes of an argument at a specific index\n\n @param e The event struct\n @param index The argument position starting from 0\n\n @return Returns size in bytes\n\n @example size_t argLen = webui_get_size_at(e, 0);"]
- pub fn webui_get_size_at(e: *mut webui_event_t, index: usize) -> usize;
-}
-extern "C" {
- #[doc = " @brief Get size in bytes of the first argument\n\n @param e The event struct\n\n @return Returns size in bytes\n\n @example size_t argLen = webui_get_size(e);"]
- pub fn webui_get_size(e: *mut webui_event_t) -> usize;
-}
-extern "C" {
- #[doc = " @brief Return the response to JavaScript as integer.\n\n @param e The event struct\n @param n The integer to be send to JavaScript\n\n @example webui_return_int(e, 123);"]
- pub fn webui_return_int(e: *mut webui_event_t, n: ::std::os::raw::c_longlong);
-}
-extern "C" {
- #[doc = " @brief Return the response to JavaScript as string.\n\n @param e The event struct\n @param n The string to be send to JavaScript\n\n @example webui_return_string(e, \"Response...\");"]
- pub fn webui_return_string(e: *mut webui_event_t, s: *const ::std::os::raw::c_char);
-}
-extern "C" {
- #[doc = " @brief Return the response to JavaScript as boolean.\n\n @param e The event struct\n @param n The boolean to be send to JavaScript\n\n @example webui_return_bool(e, true);"]
- pub fn webui_return_bool(e: *mut webui_event_t, b: bool);
-}
-extern "C" {
- #[doc = " @brief Bind a specific HTML element click event with a function. Empty element means all events.\n\n @param window The window number\n @param element The element ID\n @param func The callback as myFunc(Window, EventType, Element, EventNumber, BindID)\n\n @return Returns unique bind ID\n\n @example size_t id = webui_interface_bind(myWindow, \"myID\", myCallback);"]
- pub fn webui_interface_bind(
- window: usize,
- element: *const ::std::os::raw::c_char,
- func: ::std::option::Option<
- unsafe extern "C" fn(
- arg1: usize,
- arg2: usize,
- arg3: *mut ::std::os::raw::c_char,
- arg4: usize,
- arg5: usize,
- ),
- >,
- ) -> usize;
-}
-extern "C" {
- #[doc = " @brief When using `webui_interface_bind()`, you may need this function to easily set a response.\n\n @param window The window number\n @param event_number The event number\n @param response The response as string to be send to JavaScript\n\n @example webui_interface_set_response(myWindow, e->event_number, \"Response...\");"]
- pub fn webui_interface_set_response(
- window: usize,
- event_number: usize,
- response: *const ::std::os::raw::c_char,
- );
-}
-extern "C" {
- #[doc = " @brief Check if the app still running.\n\n @return Returns True if app is running\n\n @example bool status = webui_interface_is_app_running();"]
- pub fn webui_interface_is_app_running() -> bool;
-}
-extern "C" {
- #[doc = " @brief Get a unique window ID.\n\n @param window The window number\n\n @return Returns the unique window ID as integer\n\n @example size_t id = webui_interface_get_window_id(myWindow);"]
- pub fn webui_interface_get_window_id(window: usize) -> usize;
-}
-extern "C" {
- #[doc = " @brief Get an argument as string at a specific index\n\n @param window The window number\n @param event_number The event number\n @param index The argument position\n\n @return Returns argument as string\n\n @example const char* myStr = webui_interface_get_string_at(myWindow, e->event_number, 0);"]
- pub fn webui_interface_get_string_at(
- window: usize,
- event_number: usize,
- index: usize,
- ) -> *const ::std::os::raw::c_char;
-}
-extern "C" {
- #[doc = " @brief Get an argument as integer at a specific index\n\n @param window The window number\n @param event_number The event number\n @param index The argument position\n\n @return Returns argument as integer\n\n @example long long int myNum = webui_interface_get_int_at(myWindow, e->event_number, 0);"]
- pub fn webui_interface_get_int_at(
- window: usize,
- event_number: usize,
- index: usize,
- ) -> ::std::os::raw::c_longlong;
-}
-extern "C" {
- #[doc = " @brief Get an argument as boolean at a specific index\n\n @param window The window number\n @param event_number The event number\n @param index The argument position\n\n @return Returns argument as boolean\n\n @example bool myBool = webui_interface_get_bool_at(myWindow, e->event_number, 0);"]
- pub fn webui_interface_get_bool_at(window: usize, event_number: usize, index: usize) -> bool;
-}
-extern "C" {
- #[doc = " @brief Get the size in bytes of an argument at a specific index\n\n @param window The window number\n @param event_number The event number\n @param index The argument position\n\n @return Returns size in bytes\n\n @example size_t argLen = webui_interface_get_size_at(myWindow, e->event_number, 0);"]
- pub fn webui_interface_get_size_at(window: usize, event_number: usize, index: usize) -> usize;
-}
diff --git a/src/window.rs b/src/window.rs
new file mode 100644
index 0000000..80a9eb8
--- /dev/null
+++ b/src/window.rs
@@ -0,0 +1,322 @@
+// Flags
+// #![allow(unsafe_code)]
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
+
+// Modules
+use crate::char_to_string;
+use crate::events::Event;
+use crate::webui::BindStore;
+use crate::webui::*;
+use crate::Browser;
+use crate::Runtime;
+use std::ffi::CString;
+use std::os::raw::c_char;
+use std::sync::LazyLock;
+
+use crate::bindgen::*;
+
+const WINDOWS: usize = 64;
+const ELEMENTS: usize = 64;
+static mut BIND_STORE: LazyLock> = LazyLock::new(|| BindStore::new());
+
+pub struct Window {
+ pub id: usize,
+}
+
+impl Window {
+ pub fn new() -> Window {
+ let id = new_window();
+ Window { id }
+ }
+
+ pub fn from_id(id: usize) -> Window {
+ Window { id }
+ }
+
+ pub fn bind(&self, element: &str, func: fn(Event)) -> usize {
+ // Element String to i8/u8
+ let element_c_str = CString::new(element).unwrap();
+ let element_c_char: *const c_char = element_c_str.as_ptr() as *const c_char;
+
+ // Bind
+ unsafe {
+ let f: Option = Some(bind_events_handler);
+
+ let window_id = webui_interface_get_window_id(self.id);
+
+ // Add the Rust user function to the list
+ BIND_STORE.add_function(window_id, element, func);
+
+ webui_bind(self.id, element_c_char, f)
+ }
+ }
+
+ pub fn get_best_browser(&self) -> Browser {
+ unsafe {
+ match webui_get_best_browser(self.id) {
+ 0 => Browser::NoBrowser,
+ 1 => Browser::AnyBrowser,
+ 2 => Browser::Chrome,
+ 3 => Browser::Firefox,
+ 4 => Browser::Edge,
+ 5 => Browser::Safari,
+ 6 => Browser::Chromium,
+ 7 => Browser::Opera,
+ 8 => Browser::Brave,
+ 9 => Browser::Vivaldi,
+ 10 => Browser::Epic,
+ 11 => Browser::Yandex,
+ 12 => Browser::ChromiumBased,
+ 13 => Browser::Webview,
+ _ => Browser::NoBrowser,
+ }
+ }
+ }
+
+ pub fn show(&self, content: &str) -> bool {
+ unsafe {
+ // Content String to i8/u8
+ let content_c_str = CString::new(content).unwrap();
+ let content_c_char: *const c_char = content_c_str.as_ptr() as *const c_char;
+
+ webui_show(self.id, content_c_char)
+ }
+ }
+
+ pub fn show_browser(&self, content: &str, browser: Browser) -> bool {
+ let content_c_str = CString::new(content).unwrap();
+ let content_c_char: *const c_char = content_c_str.as_ptr() as *const c_char;
+
+ unsafe { webui_show_browser(self.id, content_c_char, browser as usize) }
+ }
+
+ pub fn start_server(&self, content: &str) -> String {
+ let content_c_str = CString::new(content).unwrap();
+ let content_c_char: *const c_char = content_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ let server = webui_start_server(self.id, content_c_char);
+ char_to_string(server)
+ }
+ }
+
+ pub fn show_wv(&self, content: &str) -> bool {
+ let content_c_str = CString::new(content).unwrap();
+ let content_c_char: *const c_char = content_c_str.as_ptr() as *const c_char;
+
+ unsafe { webui_show_wv(self.id, content_c_char) }
+ }
+
+ pub fn set_kiosk(&self, status: bool) {
+ unsafe {
+ webui_set_kiosk(self.id, status);
+ }
+ }
+
+ pub fn set_high_contrast(&self, status: bool) {
+ unsafe {
+ webui_set_high_contrast(self.id, status);
+ }
+ }
+
+ pub fn close(self) {
+ unsafe {
+ webui_close(self.id);
+ }
+ }
+
+ pub fn destroy(&self) {
+ unsafe {
+ webui_destroy(self.id);
+ }
+ }
+
+ pub fn set_root_folder(&self, folder: &str) {
+ let folder_c_str = CString::new(folder).unwrap();
+ let folder_c_char: *const c_char = folder_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ webui_set_root_folder(self.id, folder_c_char);
+ }
+ }
+
+ pub fn set_file_handler(
+ &self,
+ handler: unsafe extern "C" fn(*const i8, *mut i32) -> *const std::os::raw::c_void,
+ ) {
+ unsafe {
+ webui_set_file_handler(self.id, Some(handler));
+ }
+ }
+
+ pub fn is_shown(&self) -> bool {
+ unsafe { webui_is_shown(self.id) }
+ }
+
+ pub fn set_icon(&self, icon: &str, kind: &str) {
+ let icon_c_str = CString::new(icon).unwrap();
+ let kind_c_str = CString::new(kind).unwrap();
+ let icon_c_char: *const c_char = icon_c_str.as_ptr() as *const c_char;
+ let kind_c_char: *const c_char = kind_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ webui_set_icon(self.id, icon_c_char, kind_c_char);
+ }
+ }
+
+ pub fn send_raw(&self, function: &str, data: &[u8]) {
+ let size = data.len();
+ let raw = data.as_ptr() as *mut std::os::raw::c_void;
+ let function_c_str = CString::new(function).unwrap();
+ let function_c_char: *const c_char = function_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ webui_send_raw(self.id, function_c_char, raw, size);
+ }
+ }
+
+ pub fn set_hide(&self, status: bool) {
+ unsafe {
+ webui_set_hide(self.id, status);
+ }
+ }
+
+ pub fn set_size(&self, width: u32, height: u32) {
+ unsafe {
+ webui_set_size(self.id, width, height);
+ }
+ }
+
+ pub fn set_position(&self, x: u32, y: u32) {
+ unsafe {
+ webui_set_position(self.id, x, y);
+ }
+ }
+
+ pub fn set_profile(&self, name: &str, path: &str) {
+ let name_c_str = CString::new(name).unwrap();
+ let path_c_str = CString::new(path).unwrap();
+ let name_c_char: *const c_char = name_c_str.as_ptr() as *const c_char;
+ let path_c_char: *const c_char = path_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ webui_set_profile(self.id, name_c_char, path_c_char);
+ }
+ }
+
+ pub fn set_proxy(&self, proxy: &str) {
+ let proxy_c_str = CString::new(proxy).unwrap();
+ let proxy_c_char: *const c_char = proxy_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ webui_set_proxy(self.id, proxy_c_char);
+ }
+ }
+
+ pub fn get_url(&self) -> String {
+ unsafe {
+ let url = webui_get_url(self.id);
+ char_to_string(url)
+ }
+ }
+
+ pub fn set_public(&self, status: bool) {
+ unsafe {
+ webui_set_public(self.id, status);
+ }
+ }
+
+ pub fn navigate(&self, url: &str) {
+ let url_c_str = CString::new(url).unwrap();
+ let url_c_char: *const c_char = url_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ webui_navigate(self.id, url_c_char);
+ }
+ }
+
+ pub fn delete_profile(&self) {
+ unsafe {
+ webui_delete_profile(self.id);
+ }
+ }
+
+ pub fn get_parent_process_id(&self) -> usize {
+ unsafe { webui_get_parent_process_id(self.id) }
+ }
+
+ pub fn get_child_process_id(&self) -> usize {
+ unsafe { webui_get_child_process_id(self.id) }
+ }
+
+ pub fn get_port(&self) -> usize {
+ unsafe { webui_get_port(self.id) }
+ }
+
+ pub fn set_port(&self, port: usize) -> bool {
+ unsafe { webui_set_port(self.id, port) }
+ }
+
+ pub fn set_event_blocking(&self, status: bool) {
+ unsafe {
+ webui_set_event_blocking(self.id, status);
+ }
+ }
+
+ pub fn run(&self, script: &str) {
+ let script_c_str = CString::new(script).unwrap();
+ let script_c_char: *const c_char = script_c_str.as_ptr() as *const c_char;
+
+ unsafe {
+ webui_run(self.id, script_c_char);
+ }
+ }
+
+ pub fn script(&self, script: &str, timeout: usize, buffer_length: usize) -> Result {
+ let script_c_str = CString::new(script).unwrap();
+ let script_c_char: *const c_char = script_c_str.as_ptr() as *const c_char;
+
+ let buffer_c_str = CString::new(vec![0; buffer_length]).unwrap();
+ let buffer_c_char: *mut c_char = buffer_c_str.as_ptr() as *mut c_char;
+
+ unsafe {
+ match webui_script(
+ self.id,
+ script_c_char,
+ timeout,
+ buffer_c_char,
+ buffer_length,
+ ) {
+ true => Ok(char_to_string(buffer_c_char)),
+ false => Err(()),
+ }
+ }
+ }
+
+ pub fn set_runtime(&self, runtime: Runtime) {
+ unsafe {
+ webui_set_runtime(self.id, runtime as usize);
+ }
+ }
+}
+
+impl Drop for Window {
+ fn drop(&mut self) {
+ self.destroy();
+ }
+}
+
+unsafe extern "C" fn bind_events_handler(event: *mut webui_event_t) {
+ let evt = Event::new(event);
+
+ // Call the Rust user function
+ unsafe {
+ let window_id = webui_interface_get_window_id((*event).window);
+
+ if let Some(func) = BIND_STORE.get_function(window_id, &evt.element) {
+ func(evt);
+ }
+ }
+}