switch api server sse to axum builtin
This commit is contained in:
@@ -2,7 +2,10 @@ use axum::{
|
||||
Json,
|
||||
extract::{Extension, Path, State, rejection::JsonRejection},
|
||||
http::StatusCode,
|
||||
response::Response,
|
||||
response::{
|
||||
IntoResponse, Response,
|
||||
sse::{Event, Sse},
|
||||
},
|
||||
};
|
||||
use module_custom_world::{
|
||||
CustomWorldThemeMode, empty_agent_anchor_content_json, empty_agent_asset_coverage_json,
|
||||
@@ -34,10 +37,11 @@ use spacetime_client::{
|
||||
CustomWorldResultPreviewBlockerRecord, CustomWorldSupportedActionRecord,
|
||||
CustomWorldWorkSummaryRecord, SpacetimeClientError,
|
||||
};
|
||||
use std::convert::Infallible;
|
||||
|
||||
use crate::{
|
||||
api_response::json_success_body, auth::AuthenticatedAccessToken, http_error::AppError,
|
||||
request_context::RequestContext, sse::SseEventBuffer, state::AppState,
|
||||
request_context::RequestContext, state::AppState,
|
||||
};
|
||||
|
||||
pub async fn get_custom_world_library(
|
||||
@@ -576,17 +580,23 @@ pub async fn stream_custom_world_agent_message(
|
||||
let session_response = map_custom_world_agent_session_response(session);
|
||||
let reply_text = resolve_stream_reply_text(&session_response);
|
||||
|
||||
// 这里先用“一次性构造完整 SSE 文本”的最小兼容方案,
|
||||
// 复用 Stage 7 的同步 deterministic 写表逻辑,保证前端当前的 reader 协议可直接消费。
|
||||
let mut sse = SseEventBuffer::new();
|
||||
sse.push_json("reply_delta", &json!({ "text": reply_text }))
|
||||
.map_err(|error| custom_world_error_response(&request_context, error))?;
|
||||
sse.push_json("session", &json!({ "session": session_response }))
|
||||
.map_err(|error| custom_world_error_response(&request_context, error))?;
|
||||
sse.push_json("done", &json!({ "ok": true }))
|
||||
.map_err(|error| custom_world_error_response(&request_context, error))?;
|
||||
// 这里仍保持“一次性返回完整事件序列”的兼容语义;
|
||||
// SSE 编码、标准响应头与 body frame 交给 Axum 内建实现维护。
|
||||
let events = vec![
|
||||
custom_world_sse_json_event("reply_delta", json!({ "text": reply_text }))
|
||||
.map_err(|error| custom_world_error_response(&request_context, error))?,
|
||||
custom_world_sse_json_event("session", json!({ "session": session_response }))
|
||||
.map_err(|error| custom_world_error_response(&request_context, error))?,
|
||||
custom_world_sse_json_event("done", json!({ "ok": true }))
|
||||
.map_err(|error| custom_world_error_response(&request_context, error))?,
|
||||
];
|
||||
let stream = tokio_stream::iter(
|
||||
events
|
||||
.into_iter()
|
||||
.map(|event| Ok::<Event, Infallible>(event)),
|
||||
);
|
||||
|
||||
Ok(sse.into_response())
|
||||
Ok(Sse::new(stream).into_response())
|
||||
}
|
||||
|
||||
pub async fn get_custom_world_agent_operation(
|
||||
@@ -983,6 +993,18 @@ fn custom_world_error_response(request_context: &RequestContext, error: AppError
|
||||
error.into_response_with_context(Some(request_context))
|
||||
}
|
||||
|
||||
fn custom_world_sse_json_event(event_name: &str, payload: Value) -> Result<Event, AppError> {
|
||||
Event::default()
|
||||
.event(event_name)
|
||||
.json_data(payload)
|
||||
.map_err(|error| {
|
||||
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_details(json!({
|
||||
"provider": "sse",
|
||||
"message": format!("SSE payload 序列化失败:{error}"),
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_author_display_name(_authenticated: &AuthenticatedAccessToken) -> String {
|
||||
"玩家".to_string()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user