feat: align browser callback runtime and export flows

Consolidate the browser task runtime around the callback path, add safer artifact opening for Zhihu exports, and cover the new service/browser flows with focused tests and supporting docs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
木炎
2026-04-06 21:44:53 +08:00
parent 0dd655712c
commit bdf8e12246
55 changed files with 14440 additions and 1053 deletions

View File

@@ -293,25 +293,14 @@ impl BrowserCallbackExecutor for LiveBrowserCallbackHost {
self.result_timeout
};
eprintln!(
"callback_host: execute action={} fire_and_forget={} timeout={:?}",
request.action, is_fire_and_forget, timeout
);
let started = Instant::now();
while started.elapsed() < timeout {
if let Some(result) = self.host.take_result() {
eprintln!(
"callback_host: received callback={} payload_keys={:?}",
result.callback,
result.payload.as_object().map(|m| m.keys().collect::<Vec<_>>())
);
if let Some(response) =
normalize_callback_result(&request, result, started.elapsed())
{
return Ok(response);
}
eprintln!("callback_host: callback did not match action={}, continuing to wait", request.action);
}
thread::sleep(COMMAND_POLL_INTERVAL);
}
@@ -325,11 +314,6 @@ impl BrowserCallbackExecutor for LiveBrowserCallbackHost {
}));
}
eprintln!(
"callback_host: timeout waiting for callback on action={} after {:?}",
request.action,
started.elapsed()
);
Err(PipeError::Timeout)
}
}
@@ -354,7 +338,6 @@ fn normalize_loopback_origin(origin: &str) -> String {
}
fn bootstrap_helper_page(browser_ws_url: &str, request_url: &str, helper_url: &str) -> Result<(), PipeError> {
eprintln!("callback_host: connecting to browser ws {browser_ws_url}");
let (mut websocket, _) = connect(browser_ws_url)
.map_err(|err| PipeError::Protocol(format!("browser websocket connect failed: {err}")))?;
configure_bootstrap_socket(&mut websocket)?;
@@ -370,11 +353,9 @@ fn bootstrap_helper_page(browser_ws_url: &str, request_url: &str, helper_url: &s
helper_url,
])
.to_string();
eprintln!("callback_host: sending bootstrap command: {payload}");
websocket
.send(Message::Text(payload.into()))
.map_err(|err| PipeError::Protocol(format!("helper bootstrap send failed: {err}")))?;
eprintln!("callback_host: bootstrap command sent, waiting for helper page at {helper_url}");
Ok(())
}
@@ -426,17 +407,11 @@ fn wait_for_helper_ready(host: &BrowserCallbackHost, ready_timeout: Duration) ->
let started = Instant::now();
while started.elapsed() < ready_timeout {
if host.is_ready() {
eprintln!("callback_host: helper page ready after {:?}", started.elapsed());
return Ok(());
}
thread::sleep(HELPER_POLL_INTERVAL);
}
eprintln!(
"callback_host: helper page did NOT become ready within {:?} — the browser may have \
ignored the sgBrowerserOpenPage command or could not reach the helper URL",
ready_timeout,
);
Err(PipeError::Timeout)
}
@@ -483,11 +458,6 @@ fn handle_request(stream: &mut TcpStream, host: &BrowserCallbackHost) -> Result<
let payload: IncomingCallbackEvent = serde_json::from_slice(&request.body).map_err(|err| {
PipeError::Protocol(format!("invalid callback host event payload: {err}"))
})?;
eprintln!(
"callback_host: received event callback={} request_url={}",
payload.callback,
payload.request_url
);
host.push_result(CallbackResult {
callback: payload.callback,
request_url: payload.request_url,
@@ -499,22 +469,10 @@ fn handle_request(stream: &mut TcpStream, host: &BrowserCallbackHost) -> Result<
}
("GET", COMMANDS_ENDPOINT_PATH) => {
let envelope = host.current_command_envelope();
if envelope.ok {
if let Some(ref cmd) = envelope.command {
eprintln!(
"callback_host: delivering command to helper action={} args_count={}",
cmd.action,
cmd.args.len()
);
}
}
write_json_response(stream, &envelope)
}
("POST", COMMAND_ACK_ENDPOINT_PATH) => {
let acked = host.acknowledge_in_flight_command();
if let Some(ref cmd) = acked {
eprintln!("callback_host: command ACKed by helper action={}", cmd.action);
}
host.acknowledge_in_flight_command();
write_json_response(stream, &json!({ "ok": true }))
}
_ => write_http_response(stream, 404, "text/plain; charset=utf-8", b"not found"),
@@ -1063,8 +1021,7 @@ mod tests {
{
break;
}
Err(err) => {
eprintln!("fake browser ws server read: {err}");
Err(_) => {
break;
}
}