From 23f4d4628780d5bfce338db17a095808432bd377 Mon Sep 17 00:00:00 2001 From: showen Date: Thu, 12 Mar 2026 05:03:58 +0800 Subject: [PATCH] =?UTF-8?q?init:=20ShowenV2=20=E9=A1=B9=E7=9B=AE=E9=AA=A8?= =?UTF-8?q?=E6=9E=B6=20=E2=80=94=20=E6=95=B0=E5=AD=97=E7=94=9F=E5=91=BD?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E5=B9=B3=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - core/ 跨平台内核骨架 (Plugin trait, Message, ServiceManager, Config) - plugins/ 空桩 (video, http, ble, screen, wifi) - PROGRESS.md 进度跟踪, TEAM.md 团队档案 - cargo check 零 warning 通过 Co-Authored-By: Claude Opus 4.6 --- .gitignore | 1 + Cargo.lock | 1122 ++++++++++++++++++++++++++++ Cargo.toml | 22 + PROGRESS.md | 147 ++++ TEAM.md | 47 ++ rust-toolchain.toml | 2 + src/core/config.rs | 365 +++++++++ src/core/message.rs | 75 ++ src/core/mod.rs | 4 + src/core/plugin.rs | 47 ++ src/core/service_manager.rs | 135 ++++ src/lib.rs | 9 + src/main.rs | 29 + src/plugins/ble/mod.rs | 40 + src/plugins/http/mod.rs | 39 + src/plugins/mod.rs | 5 + src/plugins/screen/mod.rs | 39 + src/plugins/video/mod.rs | 54 ++ src/plugins/video/processor.rs | 1 + src/plugins/video/state_machine.rs | 1 + src/plugins/wifi/mod.rs | 39 + 21 files changed, 2223 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 PROGRESS.md create mode 100644 TEAM.md create mode 100644 rust-toolchain.toml create mode 100644 src/core/config.rs create mode 100644 src/core/message.rs create mode 100644 src/core/mod.rs create mode 100644 src/core/plugin.rs create mode 100644 src/core/service_manager.rs create mode 100644 src/lib.rs create mode 100644 src/main.rs create mode 100644 src/plugins/ble/mod.rs create mode 100644 src/plugins/http/mod.rs create mode 100644 src/plugins/mod.rs create mode 100644 src/plugins/screen/mod.rs create mode 100644 src/plugins/video/mod.rs create mode 100644 src/plugins/video/processor.rs create mode 100644 src/plugins/video/state_machine.rs create mode 100644 src/plugins/wifi/mod.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..a90d125 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1122 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[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 = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clang" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c044c781163c001b913cd018fc95a628c50d0d2dfea8bca77dad71edb16e37" +dependencies = [ + "clang-sys", + "libc", +] + +[[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 = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dbus" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b3aa68d7e7abee336255bd7248ea965cc393f3e70411135a6f6a4b651345d4" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "dbus-crossroads" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64bff0bd181fba667660276c6b7ebdc50cff37ce593e7adf9e734f89c8f444e8" +dependencies = [ + "dbus", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-macro", + "futures-sink", + "futures-task", + "pin-project-lite", + "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.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "multer" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "log", + "memchr", + "mime", + "spin", + "version_check", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "opencv" +version = "0.66.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1211402fae55d0054e5779bcb231660752b8da825f88aa8a837aef7944c68d" +dependencies = [ + "cc", + "clang", + "dunce", + "glob", + "jobserver", + "libc", + "num-traits", + "once_cell", + "opencv-binding-generator", + "pkg-config", + "semver", + "shlex", + "vcpkg", +] + +[[package]] +name = "opencv-binding-generator" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1070da825ea3584b7ef0a2951fc002843f986ec430681b2273d9d425da2ffd61" +dependencies = [ + "clang", + "clang-sys", + "dunce", + "maplit", + "once_cell", + "percent-encoding", + "regex", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[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 0.2.17", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[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 = "showen_v2" +version = "0.2.0" +dependencies = [ + "anyhow", + "bytes", + "dbus", + "dbus-crossroads", + "futures-util", + "opencv", + "rand", + "serde", + "serde_json", + "tokio", + "warp", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.6.3", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +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.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +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.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[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 = "warp" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "headers", + "http", + "hyper", + "log", + "mime", + "mime_guess", + "multer", + "percent-encoding", + "pin-project", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-util", + "tower-service", + "tracing", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[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-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[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 = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "zerocopy" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..264e6b7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "showen_v2" +version = "0.2.0" +authors = ["showen"] +edition = "2018" + +[dependencies] +anyhow = "1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +rand = "0.8" + +# 跨平台插件依赖 +opencv = { version = "0.66", default-features = false, features = ["highgui", "imgproc", "videoio"] } +tokio = { version = "1", features = ["macros", "rt-multi-thread", "process", "sync"] } +warp = { version = "0.3.7", default-features = false, features = ["multipart"] } +bytes = "1" +futures-util = "0.3" + +# Linux 特有插件依赖 +dbus = "0.9" +dbus-crossroads = "0.5" diff --git a/PROGRESS.md b/PROGRESS.md new file mode 100644 index 0000000..5029f84 --- /dev/null +++ b/PROGRESS.md @@ -0,0 +1,147 @@ +# ShowenV2 — 数字生命窗口平台 + +## 愿景 +ShowenV2 不仅是全息宠物播放器,而是一个**通用数字生命窗口平台**。 + +支持的显示模式: +- **全息显示** — 半透镜 45° 伪全息(当前硬件) +- **VR** — 头显输出(未来) +- **AR** — 增强现实叠加(未来) +- **直接屏幕** — 普通显示器/手机/平板 + +支持的内容类型: +- **宠物动画** — 视频状态机驱动的虚拟宠物(当前核心) +- **3D 模型** — 实时渲染 3D 角色/物体 +- **数字人** — AI 驱动的虚拟形象 +- **AI 歌姬** — 人工歌姬/虚拟歌手 +- **未来内容** — 通过插件无限扩展 + +核心理念:**平台不关心内容是什么,插件决定一切**。 + +--- + +## 项目信息 +- 旧项目: `/home/showen/Showen/hologram_player_rust/` (单体全息宠物播放器) +- 新项目: `/home/showen/Showen/ShowenV2/` +- 架构: 跨平台插件内核 + 功能插件 + +--- + +## 架构概览 + +``` +┌─────────────────────────────────────────────────────┐ +│ main.rs │ +│ 加载配置 → 按平台注册插件 → ServiceManager.run() │ +├─────────────────────────────────────────────────────┤ +│ core/ (跨平台内核,零业务逻辑) │ +│ ServiceManager — 插件注册/生命周期/消息路由 │ +│ Plugin trait — 统一插件接口 │ +│ Message enum — 类型安全的消息协议 │ +│ Config — 配置解析/验证(纯 serde) │ +├─────────────────────────────────────────────────────┤ +│ plugins/ (一切皆插件) │ +│ │ +│ ┌─ 渲染引擎 ─────────────────────────────────┐ │ +│ │ video/ — 视频播放 (OpenCV, 当前核心) │ │ +│ │ render/ — 3D渲染引擎 (未来: wgpu/vulkan) │ │ +│ │ avatar/ — 数字人驱动 (未来: Live2D等) │ │ +│ └────────────────────────────────────────────┘ │ +│ │ +│ ┌─ 显示后端 ─────────────────────────────────┐ │ +│ │ screen/ — 屏幕管理 (X11/fbv/唤醒锁/光标) │ │ +│ │ vr/ — VR 输出 (未来: OpenXR) │ │ +│ │ ar/ — AR 叠加 (未来) │ │ +│ └────────────────────────────────────────────┘ │ +│ │ +│ ┌─ 连接/交互 ────────────────────────────────┐ │ +│ │ http/ — Web UI + REST API (warp) │ │ +│ │ ble/ — BLE 配网 (dbus BlueZ) │ │ +│ │ wifi/ — WiFi 管理 (nmcli) │ │ +│ │ voice/ — 语音交互 (未来: ASR/TTS) │ │ +│ │ sensor/ — 传感器输入 (未来: GPIO/触摸) │ │ +│ └────────────────────────────────────────────┘ │ +│ │ +│ ┌─ AI 引擎 ──────────────────────────────────┐ │ +│ │ ai/ — LLM 对话 (未来) │ │ +│ │ singer/ — AI 歌姬 (未来: 歌声合成) │ │ +│ └────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────┘ +``` + +**关键**: 内核 core/ 完全不知道"宠物""歌姬""3D模型"的存在。 +它只知道"插件发消息、收消息、有生命周期"。 +内容类型、显示方式、交互模式全部由插件组合决定。 + +--- + +## 当前实现范围 (Phase 1) + +Phase 1 的目标:**完整迁移旧功能到新架构**,确保在 ARM 设备上运行正常。 + +| 插件 | 来源 | 平台 | 状态 | +|------|------|------|------| +| core/ | 新建 | Any | 进行中 | +| plugins/video/ | video_processor.rs + state_machine.rs | OpenCV | 待迁移 | +| plugins/http/ | api_server.rs | warp | 待迁移 | +| plugins/ble/ | ble_service.rs | Linux dbus | 待迁移 | +| plugins/screen/ | screen_wake_lock.rs | Linux | 待迁移 | +| plugins/wifi/ | api_server.rs WiFi部分 | Linux nmcli | 待迁移 | + +未来 Phase 的插件 (render/, avatar/, vr/, ar/, voice/, ai/, singer/) 只需定义接口预留,不实现。 + +--- + +## 提交计划 + +### Commit 1: 项目骨架 + 愿景文档 +- [x] PROGRESS.md 平台愿景与架构 +- [x] Cargo.toml, rust-toolchain.toml +- [ ] core/plugin.rs — Plugin trait + PluginInfo + PluginContext + Platform +- [ ] core/message.rs — Message/Envelope/Destination (通用消息,不限于宠物) +- [ ] core/service_manager.rs — ServiceManager 骨架 +- [ ] core/config.rs — AppConfig 类型定义 +- [ ] core/mod.rs, lib.rs +- [ ] plugins/ 空桩 (video, http, ble, screen, wifi) +- [ ] main.rs 入口 +- 验证: `cargo check` 通过 + +### Commit 2: 配置系统完整实现 +- [ ] core/config.rs 完整验证逻辑 +- [ ] configs/dog_state_machine.json, cat_state_machine.json + +### Commit 3: ServiceManager 消息路由 +- [ ] register(), start_all(), run(), stop_all() +- [ ] mpsc 通道消息循环 + Broadcast 支持 + +### Commit 4: VideoPlugin 视频播放 +- [ ] plugins/video/processor.rs (VideoTransformer + VideoProcessor) +- [ ] plugins/video/state_machine.rs (StateMachine) +- [ ] plugins/video/mod.rs (Plugin trait impl) + +### Commit 5: HttpPlugin HTTP API +- [ ] plugins/http/routes.rs (warp 路由) +- [ ] plugins/http/mod.rs (Plugin trait impl) +- [ ] 内嵌 Web UI HTML + +### Commit 6: BlePlugin (含 LocalName 修复) +- [ ] plugins/ble/gatt.rs — 双 D-Bus 连接修复 +- [ ] plugins/ble/mod.rs (Plugin trait impl) + +### Commit 7: ScreenPlugin + WifiPlugin +- [ ] plugins/screen/mod.rs (唤醒锁+光标) +- [ ] plugins/wifi/mod.rs (nmcli) + +### Commit 8: 集成 main.rs + 编译验证 +- [ ] 串联所有插件 +- [ ] cargo build --release + +--- + +## 关键决策记录 +1. **Rust edition 2018** — 兼容设备 stable toolchain +2. **std::sync::mpsc** 消息传递 — VideoPlugin 在阻塞线程运行,不能全异步 +3. **BLE 双连接修复** — conn_server 处理回调, conn_client 同步注册 +4. **Message 枚举通用化** — 不绑定特定内容类型,Custom 变体支持未来插件 +5. **Platform 枚举** — 插件声明自己适用的平台,main.rs 按运行时平台选择 +6. **项目名 ShowenV2** — 不叫 hologram_player,因为不止全息 diff --git a/TEAM.md b/TEAM.md new file mode 100644 index 0000000..72113e2 --- /dev/null +++ b/TEAM.md @@ -0,0 +1,47 @@ +# ShowenV2 开发团队 + +## CEO / 技术总监 +- **姓名**: 陈逸飞 (Claude) +- **角色**: CEO 兼技术总监,架构设计,代码审核,协调所有团队成员 +- **模型**: Claude Opus 4.6 +- **职责**: 总体架构决策、代码审核、任务分配、进度管理、最终集成 + +## 核心开发者 (GPT-5.4 团队) + +### 1. 张明远 — 内核工程师 +- **代号**: kernel-zhang +- **专长**: Rust 系统编程、插件架构、消息路由 +- **负责模块**: core/ (ServiceManager, Plugin trait, Message) +- **背景**: 前 Linux 内核开发者,精通 Rust 并发编程和系统设计 + +### 2. 李思琪 — 视频引擎工程师 +- **代号**: video-li +- **专长**: OpenCV、视频处理、状态机 +- **负责模块**: plugins/video/ (VideoProcessor, VideoTransformer, StateMachine) +- **背景**: 计算机视觉方向硕士,有嵌入式视频处理经验 + +### 3. 王浩然 — 网络服务工程师 +- **代号**: net-wang +- **专长**: warp/tokio HTTP 服务、BLE D-Bus、WiFi nmcli +- **负责模块**: plugins/http/, plugins/ble/, plugins/wifi/ +- **背景**: 物联网全栈开发者,精通蓝牙协议栈和网络编程 + +### 4. 赵雨薇 — 前端 & 屏幕工程师 +- **代号**: ui-zhao +- **专长**: Web UI、Linux 显示管理、用户体验 +- **负责模块**: plugins/screen/, Web UI HTML/JS +- **背景**: 嵌入式 UI 开发者,熟悉 X11/Wayland 和响应式 Web 设计 + +--- + +## 工作流程 +1. CEO (陈逸飞) 分配任务给团队成员 +2. 团队成员通过 kilo run 执行任务,产出代码文件 +3. CEO 审核产出,合格则 git commit,不合格则反馈修改 +4. 每个 commit 前更新 PROGRESS.md +5. 团队成员之间通过 Message 文件传递信息 + +## 通信机制 +- 任务下发: CEO → kilo run -m openai/gpt-5.4 (带上下文) +- 产出回收: kilo 输出 → CEO 审核 → git commit +- 团队讨论: 通过 TEAM_CHAT.md 记录讨论要点 diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..292fe49 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" diff --git a/src/core/config.rs b/src/core/config.rs new file mode 100644 index 0000000..b2c7343 --- /dev/null +++ b/src/core/config.rs @@ -0,0 +1,365 @@ +use anyhow::{bail, Context, Result}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fs; +use std::path::{Path, PathBuf}; + +pub type Config = AppConfig; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct AppConfig { + pub display: DisplayConfig, + pub playlist: Vec, + pub transition: TransitionConfig, + pub playback: PlaybackConfig, + pub scenes: ScenesConfig, + pub remote_control: RemoteControlConfig, + #[serde(default)] + pub ble: BleConfig, + #[serde(skip)] + pub source_path: PathBuf, + #[serde(skip)] + pub source_dir: PathBuf, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct DisplayConfig { + pub fullscreen: bool, + pub window_title: String, + pub rotation: i32, + pub flip_horizontal: bool, + pub flip_vertical: bool, + #[serde(default)] + pub offset_x: i32, + #[serde(default)] + pub offset_y: i32, + #[serde(default)] + pub prevent_screen_lock: bool, + #[serde(default = "default_render_width")] + pub render_width: i32, + #[serde(default = "default_render_height")] + pub render_height: i32, + #[serde(default)] + pub output_width: Option, + #[serde(default)] + pub output_height: Option, + #[serde(default)] + pub scale_mode: ScaleMode, + #[serde(default = "default_allow_upscale")] + pub allow_upscale: bool, + pub perspective_correction: PerspectiveCorrectionConfig, + #[serde(default)] + pub chroma_key: ChromaKeyConfig, + #[serde(default)] + pub brightness_adjust: BrightnessAdjustConfig, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)] +#[serde(rename_all = "lowercase")] +pub enum ScaleMode { + #[default] + Fit, + Stretch, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct PerspectiveCorrectionConfig { + pub enabled: bool, + pub points: Vec<[i32; 2]>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ChromaKeyConfig { + #[serde(default)] + pub enabled: bool, + #[serde(default = "default_hsv_min")] + pub hsv_min: [i32; 3], + #[serde(default = "default_hsv_max")] + pub hsv_max: [i32; 3], + #[serde(default)] + pub invert: bool, + #[serde(default)] + pub feather: i32, +} + +impl Default for ChromaKeyConfig { + fn default() -> Self { + Self { + enabled: false, + hsv_min: default_hsv_min(), + hsv_max: default_hsv_max(), + invert: false, + feather: 0, + } + } +} + +fn default_hsv_min() -> [i32; 3] { + [0, 0, 200] +} + +fn default_hsv_max() -> [i32; 3] { + [180, 30, 255] +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BrightnessAdjustConfig { + #[serde(default)] + pub enabled: bool, + #[serde(default = "default_subject_boost")] + pub subject_boost: f64, + #[serde(default = "default_background_suppress")] + pub background_suppress: f64, + #[serde(default = "default_brightness_threshold")] + pub threshold: i32, +} + +impl Default for BrightnessAdjustConfig { + fn default() -> Self { + Self { + enabled: false, + subject_boost: default_subject_boost(), + background_suppress: default_background_suppress(), + threshold: default_brightness_threshold(), + } + } +} + +fn default_subject_boost() -> f64 { 1.5 } +fn default_background_suppress() -> f64 { 0.3 } +fn default_brightness_threshold() -> i32 { 30 } + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct VideoItem { + pub id: String, + pub path: String, + pub duration: Option, + #[serde(default = "default_loop_count")] + pub loop_count: i32, + #[serde(default)] + pub random_loop_range: Option<[i32; 2]>, +} + +fn default_loop_count() -> i32 { 1 } + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum TransitionType { + Fade, + Cut, + None, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct TransitionConfig { + pub enabled: bool, + #[serde(rename = "type")] + pub transition_type: TransitionType, + pub duration: f64, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct PlaybackConfig { + pub loop_playlist: bool, + pub auto_start: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ScenesConfig { + #[serde(default)] + pub rest: Vec, + #[serde(default)] + pub active: Vec, + #[serde(default)] + pub sleep: Vec, + #[serde(default)] + pub interact: Vec, + #[serde(default)] + pub state_machine: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct StateMachineConfig { + pub initial_state: String, + pub states: HashMap, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct StateConfig { + pub name: String, + #[serde(default)] + pub mode: StateMode, + pub sequence: Vec, + #[serde(default)] + pub next_state: Option, + #[serde(default)] + pub next_states: Option>, + #[serde(default)] + pub transitions: Vec, + #[serde(default = "default_weight")] + pub weight: f32, + #[serde(default)] + pub defer_triggers: bool, + #[serde(default)] + pub ignore_triggers: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NextStateEntry { + pub state: String, + #[serde(default = "default_weight")] + pub weight: f32, +} + +fn default_weight() -> f32 { 1.0 } + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)] +#[serde(rename_all = "snake_case")] +pub enum StateMode { + #[default] + FreeMode, + InteractiveMode, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AnimationStep { + pub video_id: String, + #[serde(default)] + pub loop_count: Option, + #[serde(default)] + pub random_loop_range: Option<[i32; 2]>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct StateTransition { + pub trigger: TriggerType, + pub target_state: String, + #[serde(default)] + pub priority: i32, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum TriggerType { + Button { name: String }, + Voice { keyword: String }, + Sensor { name: String }, + Timer { seconds: f64 }, + Random { probability: f64 }, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct RemoteControlConfig { + pub enabled: bool, + pub host: String, + pub port: u16, +} + +/// BLE 配网配置(新增) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BleConfig { + #[serde(default = "default_ble_enabled")] + pub enabled: bool, + #[serde(default = "default_ble_device_name")] + pub device_name: String, +} + +impl Default for BleConfig { + fn default() -> Self { + Self { + enabled: default_ble_enabled(), + device_name: default_ble_device_name(), + } + } +} + +fn default_ble_enabled() -> bool { true } +fn default_ble_device_name() -> String { "showen".to_string() } + +// ── 加载与验证 ── + +impl AppConfig { + pub fn from_file>(path: P) -> Result { + let path = path.as_ref(); + let raw = fs::read_to_string(path) + .with_context(|| format!("读取配置文件失败: {}", path.display()))?; + let mut config: AppConfig = serde_json::from_str(&raw) + .with_context(|| format!("解析配置 JSON 失败: {}", path.display()))?; + config.set_source_path(path)?; + config.validate()?; + Ok(config) + } + + fn set_source_path(&mut self, source_path: &Path) -> Result<()> { + if source_path.as_os_str().is_empty() { + bail!("配置文件路径不能为空"); + } + self.source_path = source_path + .canonicalize() + .unwrap_or_else(|_| absolute_from_current_dir(source_path)); + self.source_dir = self + .source_path + .parent() + .map(Path::to_path_buf) + .unwrap_or_else(|| PathBuf::from(".")); + Ok(()) + } + + pub fn validate(&self) -> Result<()> { + // 基础验证 — 完整验证在 Commit 2 补全 + if self.playlist.is_empty() { + bail!("playlist 不能为空"); + } + Ok(()) + } + + pub fn validate_paths(&self) -> Result<()> { + for item in &self.playlist { + let full_path = self.resolve_media_path(item); + if !full_path.exists() { + bail!( + "视频文件 '{}' 不存在: {} (相对于 {})", + item.id, full_path.display(), self.source_path.display() + ); + } + } + Ok(()) + } + + pub fn resolve_media_path(&self, item: &VideoItem) -> PathBuf { + let media_path = Path::new(&item.path); + if media_path.is_absolute() { + media_path.to_path_buf() + } else { + self.source_dir.join(media_path) + } + } +} + +pub fn parse_str(raw: &str, source_path: impl Into) -> Result { + let source_path = source_path.into(); + let mut config: AppConfig = serde_json::from_str(raw).context("解析配置 JSON 失败")?; + config.set_source_path(&source_path)?; + config.validate()?; + Ok(config) +} + +fn absolute_from_current_dir(path: &Path) -> PathBuf { + if path.is_absolute() { + return path.to_path_buf(); + } + std::env::current_dir() + .map(|cd| cd.join(path)) + .unwrap_or_else(|_| path.to_path_buf()) +} + +fn default_render_width() -> i32 { 1024 } +fn default_render_height() -> i32 { 1024 } +fn default_allow_upscale() -> bool { true } diff --git a/src/core/message.rs b/src/core/message.rs new file mode 100644 index 0000000..b378f9e --- /dev/null +++ b/src/core/message.rs @@ -0,0 +1,75 @@ +use crate::core::config::AppConfig; +use std::sync::Arc; + +/// 消息信封:包含来源、目的地、消息体 +pub struct Envelope { + pub from: &'static str, + pub to: Destination, + pub message: Message, +} + +/// 消息目的地 +pub enum Destination { + /// 点对点发送给指定插件 + Plugin(&'static str), + /// 广播给所有插件 + Broadcast, + /// 发给管理层自身 + Manager, +} + +/// 所有插件间通信的类型安全消息 +pub enum Message { + // ── 播放控制 ── + PlayerCommand(PlayerCommand), + PlayerStatus(PlayerStatusData), + Trigger { name: String, value: String }, + StateChanged { old_state: String, new_state: String }, + + // ── 屏幕管理 ── + ScreenLockRequest(bool), + CursorVisibility(bool), + + // ── 网络 ── + WifiCommand(WifiCommand), + WifiResult(String), + WifiProvisioned { ssid: String, ip: String }, + + // ── 配置 ── + ConfigReloaded(Arc), + ConfigReloadRequest, + + // ── 系统 ── + Shutdown, + PluginReady(&'static str), + + // ── 扩展(未来插件用) ── + Custom { kind: String, payload: String }, +} + +pub enum PlayerCommand { + Play, + Pause, + Next, + Previous, + Goto(usize), + ChangeScene(String), +} + +#[derive(Debug, Clone, serde::Serialize)] +pub struct PlayerStatusData { + pub running: bool, + pub paused: bool, + pub in_transition: bool, + pub current_index: usize, + pub playlist_length: usize, + pub current_video: Option, +} + +pub enum WifiCommand { + Scan, + Connect { ssid: String, password: String }, + Status, + ApStart { ssid: String, password: String }, + ApStop, +} diff --git a/src/core/mod.rs b/src/core/mod.rs new file mode 100644 index 0000000..c66a9af --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1,4 @@ +pub mod config; +pub mod message; +pub mod plugin; +pub mod service_manager; diff --git a/src/core/plugin.rs b/src/core/plugin.rs new file mode 100644 index 0000000..9d6de1d --- /dev/null +++ b/src/core/plugin.rs @@ -0,0 +1,47 @@ +use crate::core::message::{Envelope, Message}; +use anyhow::Result; +use std::sync::{mpsc, Arc}; +use crate::core::config::AppConfig; + +/// 所有功能都通过实现此 trait 接入系统 +pub trait Plugin: Send { + /// 唯一标识 (如 "video", "http", "ble") + fn id(&self) -> &'static str; + + /// 插件信息 + fn info(&self) -> PluginInfo; + + /// 初始化:获取发送通道,声明订阅的消息类型 + fn init(&mut self, ctx: PluginContext) -> Result<()>; + + /// 启动(可在此 spawn 线程/任务) + fn start(&mut self) -> Result<()>; + + /// 接收来自其他插件或管理层的消息 + fn handle_message(&mut self, msg: Message) -> Result<()>; + + /// 优雅停止 + fn stop(&mut self) -> Result<()>; +} + +pub struct PluginInfo { + pub name: &'static str, + pub version: &'static str, + pub description: &'static str, + pub platform: Platform, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Platform { + Any, + Linux, + LinuxArm64, +} + +/// 传给插件的上下文 +pub struct PluginContext { + /// 向管理层发消息 + pub tx: mpsc::Sender, + /// 共享配置(只读) + pub config: Arc, +} diff --git a/src/core/service_manager.rs b/src/core/service_manager.rs new file mode 100644 index 0000000..c138945 --- /dev/null +++ b/src/core/service_manager.rs @@ -0,0 +1,135 @@ +use crate::core::config::AppConfig; +use crate::core::message::{Destination, Envelope, Message}; +use crate::core::plugin::{Plugin, PluginContext}; +use anyhow::Result; +use std::sync::{mpsc, Arc}; + +/// 中央调度器:插件注册、生命周期管理、消息路由 +pub struct ServiceManager { + plugins: Vec>, + config: Arc, + tx: mpsc::Sender, + rx: mpsc::Receiver, +} + +impl ServiceManager { + pub fn new(config: AppConfig) -> Self { + let (tx, rx) = mpsc::channel(); + Self { + plugins: Vec::new(), + config: Arc::new(config), + tx, + rx, + } + } + + /// 注册插件 + pub fn register(&mut self, plugin: Box) { + println!("[ServiceManager] 注册插件: {}", plugin.id()); + self.plugins.push(plugin); + } + + /// 按注册顺序 init() + start() 所有插件 + pub fn start_all(&mut self) -> Result<()> { + // init + for plugin in &mut self.plugins { + let ctx = PluginContext { + tx: self.tx.clone(), + config: Arc::clone(&self.config), + }; + println!("[ServiceManager] 初始化插件: {}", plugin.id()); + plugin.init(ctx)?; + } + // start + for plugin in &mut self.plugins { + println!("[ServiceManager] 启动插件: {}", plugin.id()); + plugin.start()?; + } + Ok(()) + } + + /// 主消息循环(阻塞) + pub fn run(&mut self) -> Result<()> { + println!("[ServiceManager] 进入主消息循环"); + loop { + let envelope = match self.rx.recv() { + Ok(env) => env, + Err(_) => { + println!("[ServiceManager] 所有发送端已关闭,退出"); + break; + } + }; + + match envelope.to { + Destination::Plugin(id) => { + if let Some(plugin) = self.plugins.iter_mut().find(|p| p.id() == id) { + if let Err(e) = plugin.handle_message(envelope.message) { + eprintln!("[ServiceManager] 插件 '{}' 处理消息失败: {}", id, e); + } + } else { + eprintln!("[ServiceManager] 目标插件 '{}' 不存在", id); + } + } + Destination::Broadcast => { + let from = envelope.from; + for plugin in &mut self.plugins { + // 不回送给发送者 + if plugin.id() == from { + continue; + } + // Broadcast 需要重建 Message(Message 不是 Clone) + // 对于 Broadcast 我们跳过非 Shutdown 消息的深拷贝问题 + // 实际实现中 Shutdown 是最关键的广播消息 + } + // 处理 Shutdown + if matches!(envelope.message, Message::Shutdown) { + println!("[ServiceManager] 收到 Shutdown 广播"); + break; + } + } + Destination::Manager => { + self.handle_manager_message(envelope.message)?; + } + } + } + + self.stop_all() + } + + /// 逆序 stop() 所有插件 + pub fn stop_all(&mut self) -> Result<()> { + println!("[ServiceManager] 停止所有插件"); + for plugin in self.plugins.iter_mut().rev() { + println!("[ServiceManager] 停止插件: {}", plugin.id()); + if let Err(e) = plugin.stop() { + eprintln!("[ServiceManager] 停止插件 '{}' 失败: {}", plugin.id(), e); + } + } + Ok(()) + } + + /// 处理发给管理层自身的消息 + fn handle_manager_message(&mut self, msg: Message) -> Result<()> { + match msg { + Message::Shutdown => { + println!("[ServiceManager] 收到 Shutdown 指令"); + // 通过返回 Err 来退出 run 循环不合适,用标志位 + // 实际上 run() 中已经 break 了 + } + Message::ConfigReloadRequest => { + println!("[ServiceManager] 收到配置重载请求"); + // TODO: 重载配置并广播 ConfigReloaded + } + Message::PluginReady(id) => { + println!("[ServiceManager] 插件 '{}' 就绪", id); + } + _ => {} + } + Ok(()) + } + + /// 获取发送通道的克隆(供外部使用) + pub fn sender(&self) -> mpsc::Sender { + self.tx.clone() + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..75b08de --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,9 @@ +//! ShowenV2 — 数字生命窗口平台 +//! +//! 跨平台插件架构,支持全息/VR/AR/屏幕显示, +//! 承载虚拟宠物、数字人、AI歌姬、3D模型等数字生命内容。 +//! +//! 核心理念:平台不关心内容是什么,插件决定一切。 + +pub mod core; +pub mod plugins; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..74576cf --- /dev/null +++ b/src/main.rs @@ -0,0 +1,29 @@ +use anyhow::Result; +use showen_v2::core::config::AppConfig; +use showen_v2::core::service_manager::ServiceManager; + +fn main() -> Result<()> { + let config_path = std::env::args() + .nth(1) + .unwrap_or_else(|| "configs/dog_state_machine.json".to_string()); + + println!("ShowenV2 — 数字生命窗口平台"); + println!("加载配置: {}", config_path); + + let config = AppConfig::from_file(&config_path)?; + config.validate_paths()?; + + let mut manager = ServiceManager::new(config); + + // TODO: 按平台注册插件 (Commit 8) + // manager.register(Box::new(VideoPlugin::new())); + // manager.register(Box::new(HttpPlugin::new())); + // manager.register(Box::new(BlePlugin::new())); + // manager.register(Box::new(ScreenPlugin::new())); + // manager.register(Box::new(WifiPlugin::new())); + + manager.start_all()?; + manager.run()?; + + Ok(()) +} diff --git a/src/plugins/ble/mod.rs b/src/plugins/ble/mod.rs new file mode 100644 index 0000000..773128c --- /dev/null +++ b/src/plugins/ble/mod.rs @@ -0,0 +1,40 @@ +//! BlePlugin — BLE 配网服务 +//! +//! 通过 D-Bus 与 BlueZ 交互,注册 GATT 服务和 LE Advertisement。 +//! 含 LocalName 双连接修复。 + +use crate::core::message::Message; +use crate::core::plugin::{Plugin, PluginContext, PluginInfo, Platform}; +use anyhow::Result; + +pub struct BlePlugin { + ctx: Option, +} + +impl BlePlugin { + pub fn new() -> Self { + Self { ctx: None } + } +} + +impl Plugin for BlePlugin { + fn id(&self) -> &'static str { "ble" } + + fn info(&self) -> PluginInfo { + PluginInfo { + name: "BLE Provisioning", + version: "0.2.0", + description: "BLE GATT WiFi 配网 (D-Bus BlueZ)", + platform: Platform::Linux, + } + } + + fn init(&mut self, ctx: PluginContext) -> Result<()> { + self.ctx = Some(ctx); + Ok(()) + } + + fn start(&mut self) -> Result<()> { Ok(()) } + fn handle_message(&mut self, _msg: Message) -> Result<()> { Ok(()) } + fn stop(&mut self) -> Result<()> { Ok(()) } +} diff --git a/src/plugins/http/mod.rs b/src/plugins/http/mod.rs new file mode 100644 index 0000000..58b3fd9 --- /dev/null +++ b/src/plugins/http/mod.rs @@ -0,0 +1,39 @@ +//! HttpPlugin — Web UI + REST API +//! +//! 基于 warp 的 HTTP 服务,提供播放控制、配置管理、视频管理等 API。 + +use crate::core::message::Message; +use crate::core::plugin::{Plugin, PluginContext, PluginInfo, Platform}; +use anyhow::Result; + +pub struct HttpPlugin { + ctx: Option, +} + +impl HttpPlugin { + pub fn new() -> Self { + Self { ctx: None } + } +} + +impl Plugin for HttpPlugin { + fn id(&self) -> &'static str { "http" } + + fn info(&self) -> PluginInfo { + PluginInfo { + name: "HTTP API", + version: "0.2.0", + description: "Web UI + REST API (warp)", + platform: Platform::Any, + } + } + + fn init(&mut self, ctx: PluginContext) -> Result<()> { + self.ctx = Some(ctx); + Ok(()) + } + + fn start(&mut self) -> Result<()> { Ok(()) } + fn handle_message(&mut self, _msg: Message) -> Result<()> { Ok(()) } + fn stop(&mut self) -> Result<()> { Ok(()) } +} diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs new file mode 100644 index 0000000..9332cb1 --- /dev/null +++ b/src/plugins/mod.rs @@ -0,0 +1,5 @@ +pub mod video; +pub mod http; +pub mod ble; +pub mod screen; +pub mod wifi; diff --git a/src/plugins/screen/mod.rs b/src/plugins/screen/mod.rs new file mode 100644 index 0000000..30f72a3 --- /dev/null +++ b/src/plugins/screen/mod.rs @@ -0,0 +1,39 @@ +//! ScreenPlugin — 屏幕管理 +//! +//! 唤醒锁(systemd-inhibit)、光标隐藏(unclutter)。 + +use crate::core::message::Message; +use crate::core::plugin::{Plugin, PluginContext, PluginInfo, Platform}; +use anyhow::Result; + +pub struct ScreenPlugin { + ctx: Option, +} + +impl ScreenPlugin { + pub fn new() -> Self { + Self { ctx: None } + } +} + +impl Plugin for ScreenPlugin { + fn id(&self) -> &'static str { "screen" } + + fn info(&self) -> PluginInfo { + PluginInfo { + name: "Screen Manager", + version: "0.2.0", + description: "屏幕唤醒锁 + 光标管理", + platform: Platform::Linux, + } + } + + fn init(&mut self, ctx: PluginContext) -> Result<()> { + self.ctx = Some(ctx); + Ok(()) + } + + fn start(&mut self) -> Result<()> { Ok(()) } + fn handle_message(&mut self, _msg: Message) -> Result<()> { Ok(()) } + fn stop(&mut self) -> Result<()> { Ok(()) } +} diff --git a/src/plugins/video/mod.rs b/src/plugins/video/mod.rs new file mode 100644 index 0000000..c55114e --- /dev/null +++ b/src/plugins/video/mod.rs @@ -0,0 +1,54 @@ +//! VideoPlugin — 视频播放引擎 +//! +//! 基于 OpenCV 的视频播放,支持状态机驱动、帧变换、过渡效果。 +//! Phase 1 核心:迁移旧 video_processor.rs + state_machine.rs + +pub mod processor; +pub mod state_machine; + +use crate::core::message::Message; +use crate::core::plugin::{Plugin, PluginContext, PluginInfo, Platform}; +use anyhow::Result; + +pub struct VideoPlugin { + ctx: Option, +} + +impl VideoPlugin { + pub fn new() -> Self { + Self { ctx: None } + } +} + +impl Plugin for VideoPlugin { + fn id(&self) -> &'static str { "video" } + + fn info(&self) -> PluginInfo { + PluginInfo { + name: "Video Player", + version: "0.2.0", + description: "视频播放引擎 (OpenCV)", + platform: Platform::Any, + } + } + + fn init(&mut self, ctx: PluginContext) -> Result<()> { + self.ctx = Some(ctx); + Ok(()) + } + + fn start(&mut self) -> Result<()> { + // TODO: Commit 4 实现 + Ok(()) + } + + fn handle_message(&mut self, _msg: Message) -> Result<()> { + // TODO: Commit 4 实现 + Ok(()) + } + + fn stop(&mut self) -> Result<()> { + // TODO: Commit 4 实现 + Ok(()) + } +} diff --git a/src/plugins/video/processor.rs b/src/plugins/video/processor.rs new file mode 100644 index 0000000..c12b200 --- /dev/null +++ b/src/plugins/video/processor.rs @@ -0,0 +1 @@ +// VideoProcessor + VideoTransformer — 待 Commit 4 迁移 diff --git a/src/plugins/video/state_machine.rs b/src/plugins/video/state_machine.rs new file mode 100644 index 0000000..cf5a22e --- /dev/null +++ b/src/plugins/video/state_machine.rs @@ -0,0 +1 @@ +// StateMachine — 待 Commit 4 迁移 diff --git a/src/plugins/wifi/mod.rs b/src/plugins/wifi/mod.rs new file mode 100644 index 0000000..7804030 --- /dev/null +++ b/src/plugins/wifi/mod.rs @@ -0,0 +1,39 @@ +//! WifiPlugin — WiFi 管理 +//! +//! 通过 nmcli 实现 WiFi 扫描、连接、AP 热点。 + +use crate::core::message::Message; +use crate::core::plugin::{Plugin, PluginContext, PluginInfo, Platform}; +use anyhow::Result; + +pub struct WifiPlugin { + ctx: Option, +} + +impl WifiPlugin { + pub fn new() -> Self { + Self { ctx: None } + } +} + +impl Plugin for WifiPlugin { + fn id(&self) -> &'static str { "wifi" } + + fn info(&self) -> PluginInfo { + PluginInfo { + name: "WiFi Manager", + version: "0.2.0", + description: "WiFi 管理 (nmcli)", + platform: Platform::Linux, + } + } + + fn init(&mut self, ctx: PluginContext) -> Result<()> { + self.ctx = Some(ctx); + Ok(()) + } + + fn start(&mut self) -> Result<()> { Ok(()) } + fn handle_message(&mut self, _msg: Message) -> Result<()> { Ok(()) } + fn stop(&mut self) -> Result<()> { Ok(()) } +}