feat: 开放 Rust 补丁程序源代码和编译说明

This commit is contained in:
Del Wang
2025-04-08 23:07:26 +08:00
parent 0e43eefd38
commit d170fadbcc
26 changed files with 2510 additions and 0 deletions
+155
View File
@@ -0,0 +1,155 @@
use open_xiaoai::services::audio::config::AudioConfig;
use serde_json::json;
use std::time::Duration;
use tokio::time::sleep;
use tokio_tungstenite::connect_async;
use open_xiaoai::base::AppError;
use open_xiaoai::base::VERSION;
use open_xiaoai::services::audio::play::AudioPlayer;
use open_xiaoai::services::audio::record::AudioRecorder;
use open_xiaoai::services::connect::data::{Event, Request, Response, Stream};
use open_xiaoai::services::connect::handler::MessageHandler;
use open_xiaoai::services::connect::message::{MessageManager, WsStream};
use open_xiaoai::services::connect::rpc::RPC;
use open_xiaoai::services::monitor::instruction::InstructionMonitor;
use open_xiaoai::services::monitor::playing::PlayingMonitor;
struct AppClient;
impl AppClient {
pub async fn connect(url: &str) -> Result<WsStream, AppError> {
let (ws_stream, _) = connect_async(url).await?;
Ok(WsStream::Client(ws_stream))
}
pub async fn run() {
let url = std::env::args().nth(1).expect("❌ 请输入服务器地址");
println!("✅ 已启动");
loop {
let Ok(ws_stream) = AppClient::connect(&url).await else {
sleep(Duration::from_secs(1)).await;
continue;
};
println!("✅ 已连接: {:?}", url);
AppClient::init(ws_stream).await;
if let Err(e) = MessageManager::instance().process_messages().await {
eprintln!("❌ 消息处理异常: {}", e);
}
AppClient::dispose().await;
eprintln!("❌ 已断开连接");
}
}
async fn init(ws_stream: WsStream) {
MessageManager::instance().init(ws_stream).await;
MessageHandler::<Event>::instance()
.set_handler(on_event)
.await;
MessageHandler::<Stream>::instance()
.set_handler(on_stream)
.await;
let rpc = RPC::instance();
rpc.add_command("get_version", get_version).await;
rpc.add_command("run_shell", run_shell).await;
rpc.add_command("start_play", start_play).await;
rpc.add_command("stop_play", stop_play).await;
rpc.add_command("start_recording", start_recording).await;
rpc.add_command("stop_recording", stop_recording).await;
InstructionMonitor::start(|event| async move {
MessageManager::instance()
.send_event("instruction", Some(json!(event)))
.await
})
.await;
PlayingMonitor::instance()
.start(|event| async move {
MessageManager::instance()
.send_event("playing", Some(json!(event)))
.await
})
.await;
}
async fn dispose() {
MessageManager::instance().dispose().await;
let _ = AudioPlayer::instance().stop().await;
let _ = AudioRecorder::instance().stop_recording().await;
InstructionMonitor::stop().await;
PlayingMonitor::instance().stop().await;
}
}
async fn get_version(_: Request) -> Result<Response, AppError> {
let data = json!(VERSION.to_string());
Ok(Response::from_data(data))
}
async fn start_play(request: Request) -> Result<Response, AppError> {
let config = request
.payload
.and_then(|payload| serde_json::from_value::<AudioConfig>(payload).ok());
AudioPlayer::instance().start(config).await?;
Ok(Response::success())
}
async fn stop_play(_: Request) -> Result<Response, AppError> {
AudioPlayer::instance().stop().await?;
Ok(Response::success())
}
async fn start_recording(request: Request) -> Result<Response, AppError> {
let config = request
.payload
.and_then(|payload| serde_json::from_value::<AudioConfig>(payload).ok());
AudioRecorder::instance()
.start_recording(
|bytes| async {
MessageManager::instance()
.send_stream("record", bytes, None)
.await
},
config,
)
.await?;
Ok(Response::success())
}
async fn stop_recording(_: Request) -> Result<Response, AppError> {
AudioRecorder::instance().stop_recording().await?;
Ok(Response::success())
}
async fn run_shell(request: Request) -> Result<Response, AppError> {
let script = match request.payload {
Some(payload) => serde_json::from_value::<String>(payload)?,
_ => return Err("empty command".into()),
};
let res = open_xiaoai::utils::shell::run_shell(script.as_str()).await?;
Ok(Response::from_data(json!(res)))
}
async fn on_event(event: Event) -> Result<(), AppError> {
println!("🔥 收到事件: {:?}", event);
Ok(())
}
async fn on_stream(stream: Stream) -> Result<(), AppError> {
let Stream { tag, bytes, .. } = stream;
match tag.as_str() {
"play" => {
// 播放接收到的音频流
let _ = AudioPlayer::instance().play(bytes).await;
}
_ => {}
}
Ok(())
}
#[tokio::main]
async fn main() {
AppClient::run().await;
}