@@ -64,7 +64,7 @@ dependencies = [ | |||||
"mime", | "mime", | ||||
"percent-encoding", | "percent-encoding", | ||||
"pin-project-lite", | "pin-project-lite", | ||||
"rand 0.9.0", | |||||
"rand", | |||||
"sha1", | "sha1", | ||||
"smallvec", | "smallvec", | ||||
"tokio", | "tokio", | ||||
@@ -239,6 +239,21 @@ dependencies = [ | |||||
"alloc-no-stdlib", | "alloc-no-stdlib", | ||||
] | ] | ||||
[[package]] | |||||
name = "android-tzdata" | |||||
version = "0.1.1" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" | |||||
[[package]] | |||||
name = "android_system_properties" | |||||
version = "0.1.5" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" | |||||
dependencies = [ | |||||
"libc", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "anyhow" | name = "anyhow" | ||||
version = "1.0.97" | version = "1.0.97" | ||||
@@ -326,12 +341,6 @@ version = "3.17.0" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" | checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" | ||||
[[package]] | |||||
name = "byteorder" | |||||
version = "1.5.0" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" | |||||
[[package]] | [[package]] | ||||
name = "bytes" | name = "bytes" | ||||
version = "1.10.1" | version = "1.10.1" | ||||
@@ -364,6 +373,20 @@ version = "1.0.0" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | ||||
[[package]] | |||||
name = "chrono" | |||||
version = "0.4.40" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" | |||||
dependencies = [ | |||||
"android-tzdata", | |||||
"iana-time-zone", | |||||
"js-sys", | |||||
"num-traits", | |||||
"wasm-bindgen", | |||||
"windows-link", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "convert_case" | name = "convert_case" | ||||
version = "0.4.0" | version = "0.4.0" | ||||
@@ -435,12 +458,6 @@ dependencies = [ | |||||
"typenum", | "typenum", | ||||
] | ] | ||||
[[package]] | |||||
name = "data-encoding" | |||||
version = "2.8.0" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" | |||||
[[package]] | [[package]] | ||||
name = "deranged" | name = "deranged" | ||||
version = "0.4.1" | version = "0.4.1" | ||||
@@ -603,17 +620,6 @@ version = "0.3.31" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" | ||||
[[package]] | |||||
name = "futures-macro" | |||||
version = "0.3.31" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" | |||||
dependencies = [ | |||||
"proc-macro2", | |||||
"quote", | |||||
"syn", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "futures-sink" | name = "futures-sink" | ||||
version = "0.3.31" | version = "0.3.31" | ||||
@@ -634,8 +640,6 @@ checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" | |||||
dependencies = [ | dependencies = [ | ||||
"futures-core", | "futures-core", | ||||
"futures-io", | "futures-io", | ||||
"futures-macro", | |||||
"futures-sink", | |||||
"futures-task", | "futures-task", | ||||
"memchr", | "memchr", | ||||
"pin-project-lite", | "pin-project-lite", | ||||
@@ -653,17 +657,6 @@ dependencies = [ | |||||
"version_check", | "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 0.11.0+wasi-snapshot-preview1", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "getrandom" | name = "getrandom" | ||||
version = "0.3.2" | version = "0.3.2" | ||||
@@ -778,6 +771,30 @@ dependencies = [ | |||||
"tokio-native-tls", | "tokio-native-tls", | ||||
] | ] | ||||
[[package]] | |||||
name = "iana-time-zone" | |||||
version = "0.1.63" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" | |||||
dependencies = [ | |||||
"android_system_properties", | |||||
"core-foundation-sys", | |||||
"iana-time-zone-haiku", | |||||
"js-sys", | |||||
"log", | |||||
"wasm-bindgen", | |||||
"windows-core", | |||||
] | |||||
[[package]] | |||||
name = "iana-time-zone-haiku" | |||||
version = "0.1.2" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" | |||||
dependencies = [ | |||||
"cc", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "icu_collections" | name = "icu_collections" | ||||
version = "1.5.0" | version = "1.5.0" | ||||
@@ -1127,6 +1144,15 @@ version = "0.1.0" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" | ||||
[[package]] | |||||
name = "num-traits" | |||||
version = "0.2.19" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" | |||||
dependencies = [ | |||||
"autocfg", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "object" | name = "object" | ||||
version = "0.36.7" | version = "0.36.7" | ||||
@@ -1272,38 +1298,17 @@ version = "5.2.0" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" | checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" | ||||
[[package]] | |||||
name = "rand" | |||||
version = "0.8.5" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" | |||||
dependencies = [ | |||||
"libc", | |||||
"rand_chacha 0.3.1", | |||||
"rand_core 0.6.4", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "rand" | name = "rand" | ||||
version = "0.9.0" | version = "0.9.0" | ||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" | checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" | ||||
dependencies = [ | dependencies = [ | ||||
"rand_chacha 0.9.0", | |||||
"rand_core 0.9.3", | |||||
"rand_chacha", | |||||
"rand_core", | |||||
"zerocopy", | "zerocopy", | ||||
] | ] | ||||
[[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 0.6.4", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "rand_chacha" | name = "rand_chacha" | ||||
version = "0.9.0" | version = "0.9.0" | ||||
@@ -1311,16 +1316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" | checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" | ||||
dependencies = [ | dependencies = [ | ||||
"ppv-lite86", | "ppv-lite86", | ||||
"rand_core 0.9.3", | |||||
] | |||||
[[package]] | |||||
name = "rand_core" | |||||
version = "0.6.4" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" | |||||
dependencies = [ | |||||
"getrandom 0.2.15", | |||||
"rand_core", | |||||
] | ] | ||||
[[package]] | [[package]] | ||||
@@ -1329,7 +1325,7 @@ version = "0.9.3" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" | checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" | ||||
dependencies = [ | dependencies = [ | ||||
"getrandom 0.3.2", | |||||
"getrandom", | |||||
] | ] | ||||
[[package]] | [[package]] | ||||
@@ -1685,7 +1681,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" | checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" | ||||
dependencies = [ | dependencies = [ | ||||
"fastrand", | "fastrand", | ||||
"getrandom 0.3.2", | |||||
"getrandom", | |||||
"once_cell", | "once_cell", | ||||
"rustix", | "rustix", | ||||
"windows-sys 0.59.0", | "windows-sys 0.59.0", | ||||
@@ -1791,18 +1787,6 @@ dependencies = [ | |||||
"tokio", | "tokio", | ||||
] | ] | ||||
[[package]] | |||||
name = "tokio-tungstenite" | |||||
version = "0.20.1" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" | |||||
dependencies = [ | |||||
"futures-util", | |||||
"log", | |||||
"tokio", | |||||
"tungstenite", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "tokio-util" | name = "tokio-util" | ||||
version = "0.7.14" | version = "0.7.14" | ||||
@@ -1860,25 +1844,6 @@ version = "0.2.5" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" | ||||
[[package]] | |||||
name = "tungstenite" | |||||
version = "0.20.1" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" | |||||
dependencies = [ | |||||
"byteorder", | |||||
"bytes", | |||||
"data-encoding", | |||||
"http", | |||||
"httparse", | |||||
"log", | |||||
"rand 0.8.5", | |||||
"sha1", | |||||
"thiserror", | |||||
"url", | |||||
"utf-8", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "typenum" | name = "typenum" | ||||
version = "1.18.0" | version = "1.18.0" | ||||
@@ -1917,12 +1882,6 @@ dependencies = [ | |||||
"percent-encoding", | "percent-encoding", | ||||
] | ] | ||||
[[package]] | |||||
name = "utf-8" | |||||
version = "0.7.6" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" | |||||
[[package]] | [[package]] | ||||
name = "utf16_iter" | name = "utf16_iter" | ||||
version = "1.0.5" | version = "1.0.5" | ||||
@@ -2059,13 +2018,13 @@ dependencies = [ | |||||
"actix-cors", | "actix-cors", | ||||
"actix-web", | "actix-web", | ||||
"anyhow", | "anyhow", | ||||
"futures-util", | |||||
"chrono", | |||||
"once_cell", | |||||
"reqwest", | "reqwest", | ||||
"serde", | "serde", | ||||
"serde_json", | "serde_json", | ||||
"serialport", | "serialport", | ||||
"tokio", | "tokio", | ||||
"tokio-tungstenite", | |||||
"winapi", | "winapi", | ||||
] | ] | ||||
@@ -2091,6 +2050,65 @@ version = "0.4.0" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" | ||||
[[package]] | |||||
name = "windows-core" | |||||
version = "0.61.0" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" | |||||
dependencies = [ | |||||
"windows-implement", | |||||
"windows-interface", | |||||
"windows-link", | |||||
"windows-result", | |||||
"windows-strings", | |||||
] | |||||
[[package]] | |||||
name = "windows-implement" | |||||
version = "0.60.0" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" | |||||
dependencies = [ | |||||
"proc-macro2", | |||||
"quote", | |||||
"syn", | |||||
] | |||||
[[package]] | |||||
name = "windows-interface" | |||||
version = "0.59.1" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" | |||||
dependencies = [ | |||||
"proc-macro2", | |||||
"quote", | |||||
"syn", | |||||
] | |||||
[[package]] | |||||
name = "windows-link" | |||||
version = "0.1.1" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" | |||||
[[package]] | |||||
name = "windows-result" | |||||
version = "0.3.2" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" | |||||
dependencies = [ | |||||
"windows-link", | |||||
] | |||||
[[package]] | |||||
name = "windows-strings" | |||||
version = "0.4.0" | |||||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" | |||||
dependencies = [ | |||||
"windows-link", | |||||
] | |||||
[[package]] | [[package]] | ||||
name = "windows-sys" | name = "windows-sys" | ||||
version = "0.48.0" | version = "0.48.0" | ||||
@@ -12,8 +12,8 @@ actix-web = "4.4" | |||||
actix-cors = "0.6" | actix-cors = "0.6" | ||||
tokio = { version = "1.0", features = ["full"] } | tokio = { version = "1.0", features = ["full"] } | ||||
reqwest = { version = "0.11", features = ["blocking", "json"] } | reqwest = { version = "0.11", features = ["blocking", "json"] } | ||||
tokio-tungstenite = "0.20" | |||||
futures-util = "0.3" | |||||
once_cell = "1.18" | |||||
chrono = "0.4" | |||||
[profile.release] | [profile.release] | ||||
opt-level = 3 | opt-level = 3 | ||||
@@ -1,19 +0,0 @@ | |||||
{ | |||||
"scale_type": "001", | |||||
"serial_port": "/dev/ttyS1", | |||||
"baud_rate": 9600, | |||||
"mqtt": { | |||||
"client_id": "weight_reader", | |||||
"host": "10.180.4.100", | |||||
"port": 1883, | |||||
<<<<<<< HEAD | |||||
"username": "auseft", | |||||
"password": "1q2w3E**", | |||||
======= | |||||
"username": "admin", | |||||
"password": "Auseft@2025", | |||||
>>>>>>> c2a749df78e5f78ad42f2fefc374d641c881253b | |||||
"keep_alive_secs": 60, | |||||
"topic_prefix": "weight/data" | |||||
} | |||||
} |
@@ -1,191 +1,173 @@ | |||||
use anyhow::{Context, Result}; | |||||
use serde::{Serialize, Deserialize}; | use serde::{Serialize, Deserialize}; | ||||
use serde_json; | use serde_json; | ||||
use std::io::{self, Read}; | |||||
use std::io::{self, Read, Write}; | |||||
use std::time::Duration; | use std::time::Duration; | ||||
use serialport; | use serialport; | ||||
use actix_web::{web, App, HttpServer, HttpResponse}; | use actix_web::{web, App, HttpServer, HttpResponse}; | ||||
use actix_cors::Cors; | use actix_cors::Cors; | ||||
use std::fs; | |||||
use futures_util::{SinkExt, StreamExt}; | |||||
use tokio::net::TcpListener; | |||||
use tokio_tungstenite::accept_async; | |||||
use tokio::sync::broadcast; | |||||
use std::fs::{self, OpenOptions}; | |||||
use std::sync::Mutex; | |||||
use once_cell::sync::Lazy; | |||||
use chrono::Local; | |||||
use anyhow::{Context, Result}; | |||||
#[derive(Serialize, Deserialize)] | #[derive(Serialize, Deserialize)] | ||||
struct WeightData { | struct WeightData { | ||||
weight: String, | weight: String, | ||||
timestamp: u64, | timestamp: u64, | ||||
is_read: bool, | |||||
} | } | ||||
#[derive(Serialize)] | |||||
struct MacResponse { | |||||
mac_address: String, | |||||
} | |||||
#[derive(Serialize)] | |||||
struct ScaleTypeResponse { | |||||
scale_type: String, | |||||
} | |||||
#[derive(Deserialize)] | |||||
#[derive(Serialize, Deserialize)] | |||||
struct Config { | struct Config { | ||||
scale_type: String, | scale_type: String, | ||||
serial_port: String, | serial_port: String, | ||||
baud_rate: u32, | baud_rate: u32, | ||||
} | } | ||||
// 读取配置文件 | |||||
fn read_config() -> Result<Config> { | fn read_config() -> Result<Config> { | ||||
let config_path = "config.json"; | |||||
let content = fs::read_to_string(config_path) | |||||
.with_context(|| format!("无法读取配置文件 {}", config_path))?; | |||||
let config: Config = serde_json::from_str(&content) | |||||
.with_context(|| format!("配置文件格式错误 {}", config_path))?; | |||||
let config_str = fs::read_to_string("config.json")?; | |||||
let config: Config = serde_json::from_str(&config_str)?; | |||||
Ok(config) | Ok(config) | ||||
} | } | ||||
fn get_mac_address() -> String { | |||||
match read_config() { | |||||
Ok(config) => config.scale_type, | |||||
Err(_) => String::from("Unknown") | |||||
// 写入日志到文件 | |||||
fn write_log(message: &str) { | |||||
let now = Local::now(); | |||||
let log_message = format!("[{}] {}\n", now.format("%Y-%m-%d %H:%M:%S"), message); | |||||
let log_file = "weight_service.log"; | |||||
if let Err(e) = OpenOptions::new() | |||||
.create(true) | |||||
.append(true) | |||||
.open(log_file) | |||||
.and_then(|mut file| file.write_all(log_message.as_bytes())) | |||||
{ | |||||
eprintln!("写入日志失败: {}", e); | |||||
} | } | ||||
} | } | ||||
fn get_scale_type() -> String { | |||||
match read_config() { | |||||
Ok(config) => config.scale_type, | |||||
Err(_) => String::from("Unknown") | |||||
} | |||||
} | |||||
// 使用全局静态变量来存储重量数据 | |||||
static WEIGHT_DATA: Lazy<Mutex<WeightData>> = Lazy::new(|| { | |||||
Mutex::new(WeightData { | |||||
weight: "0".to_string(), | |||||
timestamp: 0, | |||||
is_read: false, | |||||
}) | |||||
}); | |||||
// HTTP处理函数 | |||||
// 获取MAC地址的HTTP处理函数 | |||||
async fn get_mac() -> HttpResponse { | async fn get_mac() -> HttpResponse { | ||||
let mac = get_mac_address(); | |||||
println!("HTTP请求:获取MAC地址 = {}", mac); | |||||
let response = MacResponse { | |||||
mac_address: mac, | |||||
}; | |||||
let response = serde_json::json!({ | |||||
"mac": "00:11:22:33:44:55" // 这里替换为实际的MAC地址获取逻辑 | |||||
}); | |||||
HttpResponse::Ok().json(response) | HttpResponse::Ok().json(response) | ||||
} | } | ||||
// 新增的HTTP处理函数 | |||||
// 获取秤类型的HTTP处理函数 | |||||
async fn get_scale() -> HttpResponse { | async fn get_scale() -> HttpResponse { | ||||
let scale_type = get_scale_type(); | |||||
println!("HTTP请求:获取天平类型 = {}", scale_type); | |||||
let response = ScaleTypeResponse { | |||||
scale_type, | |||||
let config = match read_config() { | |||||
Ok(config) => config, | |||||
Err(_) => return HttpResponse::InternalServerError().finish(), | |||||
}; | }; | ||||
let response = serde_json::json!({ | |||||
"scale_type": config.scale_type | |||||
}); | |||||
HttpResponse::Ok().json(response) | HttpResponse::Ok().json(response) | ||||
} | } | ||||
// WebSocket测试客户端函数 | |||||
async fn test_websocket_client() -> Result<()> { | |||||
println!("开始测试WebSocket客户端..."); | |||||
// 连接到WebSocket服务器 | |||||
println!("正在连接到WebSocket服务器..."); | |||||
let (ws_stream, _) = tokio_tungstenite::connect_async("ws://127.0.0.1:8081") | |||||
.await | |||||
.context("无法连接到WebSocket服务器")?; | |||||
println!("已成功连接到WebSocket服务器"); | |||||
let (_, mut read) = ws_stream.split(); | |||||
// 持续接收消息 | |||||
println!("等待接收数据..."); | |||||
while let Some(message) = read.next().await { | |||||
match message { | |||||
Ok(msg) => { | |||||
if let Ok(text) = msg.into_text() { | |||||
println!("收到原始数据: {}", text); | |||||
// 尝试解析JSON数据 | |||||
match serde_json::from_str::<WeightData>(&text) { | |||||
Ok(weight_data) => { | |||||
println!("收到重量数据: {} (时间戳: {})", weight_data.weight, weight_data.timestamp); | |||||
} | |||||
Err(e) => { | |||||
println!("JSON解析错误: {}", e); | |||||
println!("原始数据: {}", text); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
Err(e) => { | |||||
eprintln!("WebSocket接收错误: {}", e); | |||||
break; | |||||
} | |||||
} | |||||
// 获取重量数据的HTTP处理函数 | |||||
async fn get_weight() -> HttpResponse { | |||||
let mut weight_data = WEIGHT_DATA.lock().unwrap(); | |||||
if weight_data.is_read { | |||||
// 如果数据已读,返回 null | |||||
write_log("接口调用: /weight - 数据已读,返回 null"); | |||||
HttpResponse::Ok().json(serde_json::json!({"weight": null})) | |||||
} else { | |||||
// 标记为已读并返回数据 | |||||
write_log(&format!("接口调用: /weight - 返回数据: {}", weight_data.weight)); | |||||
weight_data.is_read = true; | |||||
HttpResponse::Ok().json(&*weight_data) | |||||
} | } | ||||
Ok(()) | |||||
} | } | ||||
// 模拟串口数据发送 | |||||
async fn simulate_serial_data() -> Result<()> { | |||||
println!("开始模拟串口数据发送..."); | |||||
// 串口数据处理函数 | |||||
async fn run_serial() -> Result<()> { | |||||
// 读取配置文件 | |||||
let config = read_config()?; | |||||
// 创建一个TCP连接到WebSocket服务器 | |||||
println!("正在连接到WebSocket服务器..."); | |||||
let (ws_stream, _) = tokio_tungstenite::connect_async("ws://127.0.0.1:8081") | |||||
.await | |||||
.context("无法连接到WebSocket服务器")?; | |||||
println!("已成功连接到WebSocket服务器"); | |||||
let (mut write, _) = ws_stream.split(); | |||||
write_log(&format!("正在打开串口 {}...", config.serial_port)); | |||||
// 打开配置的串口 | |||||
println!("正在尝试打开串口 {}...", config.serial_port); | |||||
let mut port = serialport::new(&config.serial_port, config.baud_rate) | |||||
.timeout(Duration::from_millis(1000)) | |||||
.open() | |||||
.with_context(|| format!("无法打开串口 {}", config.serial_port))?; | |||||
// 模拟每秒发送一个随机重量数据 | |||||
let mut interval = tokio::time::interval(Duration::from_secs(1)); | |||||
let mut counter = 0; | |||||
write_log("串口打开成功"); | |||||
println!("串口打开成功"); | |||||
let mut buf = [0u8; 1024]; | |||||
let mut accumulated_data = String::new(); | |||||
println!("开始发送模拟数据 (按Ctrl+C退出)..."); | |||||
loop { | loop { | ||||
interval.tick().await; | |||||
counter += 1; | |||||
// 生成一个模拟的重量值(10.5 - 20.5之间的随机数) | |||||
let weight = format!("{:.1}", 10.5 + (counter % 10) as f32); | |||||
// 创建数据结构 | |||||
let weight_data = WeightData { | |||||
weight: weight.clone(), | |||||
timestamp: std::time::SystemTime::now() | |||||
.duration_since(std::time::UNIX_EPOCH) | |||||
.unwrap() | |||||
.as_secs(), | |||||
}; | |||||
// 序列化并发送数据 | |||||
if let Ok(json_data) = serde_json::to_string(&weight_data) { | |||||
println!("发送模拟数据: {} (JSON: {})", weight, json_data); | |||||
if let Err(e) = write.send(tokio_tungstenite::tungstenite::Message::Text(json_data)).await { | |||||
eprintln!("发送数据错误: {}", e); | |||||
break; | |||||
match port.read(&mut buf) { | |||||
Ok(bytes_read) if bytes_read > 0 => { | |||||
// 将读取的数据转换为字符串并添加到累积的数据中 | |||||
if let Ok(data) = String::from_utf8(buf[..bytes_read].to_vec()) { | |||||
accumulated_data.push_str(&data); | |||||
// 检查是否有完整的行 | |||||
if accumulated_data.contains('\n') { | |||||
// 处理所有完整的行 | |||||
for line in accumulated_data.lines() { | |||||
let trimmed_data = line.trim(); | |||||
if !trimmed_data.is_empty() { | |||||
write_log(&format!("收到串口数据: {}", trimmed_data)); | |||||
println!("收到串口数据: {}", trimmed_data); | |||||
// 更新内存中的数据(直接覆盖) | |||||
let mut weight_data = WEIGHT_DATA.lock().unwrap(); | |||||
weight_data.weight = trimmed_data.to_string(); | |||||
weight_data.timestamp = std::time::SystemTime::now() | |||||
.duration_since(std::time::UNIX_EPOCH) | |||||
.unwrap() | |||||
.as_secs(); | |||||
weight_data.is_read = false; // 新数据未读 | |||||
} | |||||
} | |||||
// 清除已处理的数据 | |||||
accumulated_data.clear(); | |||||
} | |||||
} | |||||
} | } | ||||
println!("数据发送成功"); | |||||
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => { | |||||
// 超时是正常的,继续尝试读取 | |||||
continue; | |||||
} | |||||
Err(e) => { | |||||
let error_msg = format!("串口读取错误: {}", e); | |||||
write_log(&error_msg); | |||||
eprintln!("{}", error_msg); | |||||
return Err(e.into()); | |||||
} | |||||
_ => {} | |||||
} | } | ||||
// 等待一小段时间 | |||||
tokio::time::sleep(Duration::from_secs(1)).await; | |||||
} | } | ||||
Ok(()) | |||||
} | } | ||||
#[actix_web::main] | #[actix_web::main] | ||||
async fn main() -> Result<()> { | async fn main() -> Result<()> { | ||||
// 检查命令行参数 | |||||
let args: Vec<String> = std::env::args().collect(); | |||||
if args.len() > 1 { | |||||
match args[1].as_str() { | |||||
"--test-client" => return test_websocket_client().await, | |||||
"--simulate" => return simulate_serial_data().await, | |||||
_ => {} | |||||
} | |||||
} | |||||
write_log("程序启动..."); | |||||
println!("程序启动..."); | println!("程序启动..."); | ||||
// 启动HTTP服务器 | // 启动HTTP服务器 | ||||
write_log("正在启动HTTP服务器..."); | |||||
println!("正在启动HTTP服务器..."); | println!("正在启动HTTP服务器..."); | ||||
// 创建HTTP服务器 | // 创建HTTP服务器 | ||||
@@ -200,175 +182,27 @@ async fn main() -> Result<()> { | |||||
App::new() | App::new() | ||||
.wrap(cors) // 添加CORS中间件 | .wrap(cors) // 添加CORS中间件 | ||||
.route("/mac", web::get().to(get_mac)) | .route("/mac", web::get().to(get_mac)) | ||||
.route("/scale", web::get().to(get_scale)) // 新增的路由 | |||||
.route("/scale", web::get().to(get_scale)) | |||||
.route("/weight", web::get().to(get_weight)) | |||||
}) | }) | ||||
.bind(("0.0.0.0", 8080))? | .bind(("0.0.0.0", 8080))? | ||||
.run(); | .run(); | ||||
write_log("HTTP服务器已启动,监听在 http://127.0.0.1:8080"); | |||||
println!("HTTP服务器已启动,监听在 http://127.0.0.1:8080"); | println!("HTTP服务器已启动,监听在 http://127.0.0.1:8080"); | ||||
// 在新线程中运行WebSocket和串口服务 | |||||
let _websocket_handle = tokio::spawn(async { | |||||
if let Err(e) = run_websocket_and_serial().await { | |||||
eprintln!("WebSocket/串口服务错误: {}", e); | |||||
// 在新线程中运行串口服务 | |||||
let _serial_handle = tokio::spawn(async { | |||||
if let Err(e) = run_serial().await { | |||||
let error_msg = format!("串口服务错误: {}", e); | |||||
write_log(&error_msg); | |||||
eprintln!("{}", error_msg); | |||||
} | } | ||||
}); | }); | ||||
// 等待HTTP服务器结束 | // 等待HTTP服务器结束 | ||||
server.await?; | server.await?; | ||||
Ok(()) | |||||
} | |||||
// WebSocket和串口处理函数 | |||||
async fn run_websocket_and_serial() -> Result<()> { | |||||
// 读取配置 | |||||
let config = read_config()?; | |||||
// 创建一个广播通道,用于向所有WebSocket客户端发送数据 | |||||
let (tx, _rx) = broadcast::channel::<String>(100); | |||||
// 启动WebSocket服务器 | |||||
let listener = TcpListener::bind("127.0.0.1:8081").await?; | |||||
println!("WebSocket服务器已启动,监听在 ws://127.0.0.1:8081"); | |||||
// 在单独的任务中处理串口数据 | |||||
let tx_serial = tx.clone(); | |||||
let _serial_handle = tokio::spawn(async move { | |||||
// 打开配置的串口 | |||||
println!("正在尝试打开串口 {}...", config.serial_port); | |||||
let mut port = serialport::new(&config.serial_port, config.baud_rate) | |||||
.timeout(Duration::from_millis(1000)) | |||||
.open() | |||||
.with_context(|| format!("无法打开串口 {}", config.serial_port))?; | |||||
println!("成功打开串口 {}!", config.serial_port); | |||||
println!("正在读取数据... (按 Ctrl+C 退出)"); | |||||
// 增加缓冲区大小并使用String来累积数据 | |||||
let mut serial_buf: Vec<u8> = vec![0; 1024]; | |||||
let mut accumulated_data = String::new(); | |||||
loop { | |||||
match port.read(serial_buf.as_mut_slice()) { | |||||
Ok(t) => { | |||||
if t > 0 { | |||||
// 将新数据添加到累积的字符串中 | |||||
if let Ok(data) = String::from_utf8(serial_buf[..t].to_vec()) { | |||||
accumulated_data.push_str(&data); | |||||
// 检查是否有完整的数据行(以换行符或回车符结束) | |||||
if accumulated_data.contains('\n') || accumulated_data.contains('\r') { | |||||
// 处理累积的数据 | |||||
let lines: Vec<&str> = accumulated_data | |||||
.split(|c| c == '\n' || c == '\r') | |||||
.filter(|s| !s.is_empty()) | |||||
.collect(); | |||||
for line in lines { | |||||
let trimmed_data = line.trim(); | |||||
if !trimmed_data.is_empty() { | |||||
println!("收到串口数据: {}", trimmed_data); | |||||
// 创建带时间戳的数据结构 | |||||
let weight_data = WeightData { | |||||
weight: trimmed_data.to_string(), | |||||
timestamp: std::time::SystemTime::now() | |||||
.duration_since(std::time::UNIX_EPOCH) | |||||
.unwrap() | |||||
.as_secs(), | |||||
}; | |||||
// 序列化数据 | |||||
if let Ok(json_data) = serde_json::to_string(&weight_data) { | |||||
println!("发送串口数据到WebSocket: {}", json_data); | |||||
// 发送数据到所有WebSocket客户端 | |||||
if let Err(e) = tx_serial.send(json_data) { | |||||
eprintln!("发送数据到广播通道失败: {}", e); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
// 清除已处理的数据 | |||||
accumulated_data.clear(); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => { | |||||
// 超时是正常的,继续尝试读取 | |||||
continue; | |||||
} | |||||
Err(e) => { | |||||
eprintln!("串口读取错误: {}", e); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
Ok::<_, anyhow::Error>(()) | |||||
}); | |||||
// 处理WebSocket连接 | |||||
while let Ok((stream, addr)) = listener.accept().await { | |||||
println!("新的WebSocket连接: {}", addr); | |||||
let ws_stream = accept_async(stream).await.expect("Failed to accept WebSocket"); | |||||
let tx = tx.clone(); | |||||
// 为每个WebSocket连接创建一个新任务 | |||||
tokio::spawn(async move { | |||||
println!("开始处理WebSocket连接: {}", addr); | |||||
let (mut ws_sender, mut ws_receiver) = ws_stream.split(); | |||||
let mut rx = tx.subscribe(); | |||||
// 创建两个任务:一个用于接收消息,一个用于发送消息 | |||||
let mut send_task = tokio::spawn(async move { | |||||
println!("[{}] 等待接收广播数据...", addr); | |||||
while let Ok(msg) = rx.recv().await { | |||||
println!("[{}] 准备发送数据: {}", addr, msg); | |||||
if let Err(e) = ws_sender.send(tokio_tungstenite::tungstenite::Message::Text(msg.clone())).await { | |||||
eprintln!("[{}] 发送WebSocket消息失败: {}", addr, e); | |||||
break; | |||||
} | |||||
println!("[{}] 成功发送数据", addr); | |||||
} | |||||
}); | |||||
let tx_clone = tx.clone(); | |||||
let mut recv_task = tokio::spawn(async move { | |||||
println!("[{}] 开始监听WebSocket消息...", addr); | |||||
while let Some(result) = ws_receiver.next().await { | |||||
match result { | |||||
Ok(msg) => { | |||||
if let Ok(text) = msg.into_text() { | |||||
println!("[{}] 收到WebSocket消息: {}", addr, text); | |||||
// 将收到的消息广播给所有客户端 | |||||
if let Err(e) = tx_clone.send(text.clone()) { | |||||
eprintln!("[{}] 广播消息失败: {}", addr, e); | |||||
} | |||||
} | |||||
} | |||||
Err(e) => { | |||||
eprintln!("[{}] WebSocket接收错误: {}", addr, e); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
}); | |||||
// 等待任意一个任务结束 | |||||
tokio::select! { | |||||
_ = (&mut send_task) => { | |||||
println!("[{}] 发送任务结束", addr); | |||||
} | |||||
_ = (&mut recv_task) => { | |||||
println!("[{}] 接收任务结束", addr); | |||||
} | |||||
} | |||||
println!("[{}] WebSocket连接结束", addr); | |||||
}); | |||||
} | |||||
write_log("程序退出"); | |||||
Ok(()) | Ok(()) | ||||
} | } |
@@ -0,0 +1,22 @@ | |||||
[2025-04-03 16:11:59] 程序启动... | |||||
[2025-04-03 16:11:59] 正在启动HTTP服务器... | |||||
[2025-04-03 16:11:59] HTTP服务器已启动,监听在 http://127.0.0.1:8080 | |||||
[2025-04-03 16:11:59] 正在打开串口 com1... | |||||
[2025-04-03 16:11:59] 串口打开成功 | |||||
[2025-04-03 16:12:09] 接口调用: /weight - 返回数据: 0 | |||||
[2025-04-03 16:12:11] 接口调用: /weight - 数据已读,返回 null | |||||
[2025-04-03 16:12:13] 接口调用: /weight - 数据已读,返回 null | |||||
[2025-04-03 16:12:15] 接口调用: /weight - 数据已读,返回 null | |||||
[2025-04-03 16:12:16] 收到串口数据: 8.142(8) g | |||||
[2025-04-03 16:12:17] 接口调用: /weight - 返回数据: 8.142(8) g | |||||
[2025-04-03 16:12:19] 接口调用: /weight - 数据已读,返回 null | |||||
[2025-04-03 16:12:20] 收到串口数据: 8.142(8) g | |||||
[2025-04-03 16:12:21] 接口调用: /weight - 返回数据: 8.142(8) g | |||||
[2025-04-03 16:12:23] 接口调用: /weight - 数据已读,返回 null | |||||
[2025-04-03 16:12:25] 接口调用: /weight - 数据已读,返回 null | |||||
[2025-04-03 16:12:27] 接口调用: /weight - 数据已读,返回 null | |||||
[2025-04-03 16:12:31] 接口调用: /weight - 数据已读,返回 null | |||||
[2025-04-03 16:12:33] 接口调用: /weight - 数据已读,返回 null | |||||
[2025-04-03 16:12:35] 接口调用: /weight - 数据已读,返回 null | |||||
[2025-04-03 16:12:37] 接口调用: /weight - 数据已读,返回 null | |||||
[2025-04-03 16:12:39] 接口调用: /weight - 数据已读,返回 null |