Include the cause chain when go2rtc cannot be reached
reqwest's Display is only "error sending request for url (...)" - the reason is one or two sources down, and "connection refused" versus "timed out" is the entire content of the message. This error is relayed to the cloud and then to a viewer, so it is the only explanation anyone gets for a camera that will not play. It now reads "could not reach go2rtc at http://127.0.0.1:1984: ...", naming go2rtc explicitly, because by far the likeliest cause is that it is not running and an error mentioning only a port sends whoever reads it looking at the network instead.
This commit is contained in:
+30
-1
@@ -62,6 +62,29 @@ fn checked_stream_name(name: &str) -> anyhow::Result<&str> {
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
/// Flattens an error's `source` chain into one line.
|
||||
///
|
||||
/// Needed because reqwest's own `Display` is just "error sending request for
|
||||
/// url (...)" - the reason lives one or two sources down, and "connection
|
||||
/// refused" versus "timed out" is the whole content of the message. This
|
||||
/// error travels to the cloud and then to a viewer, so it is the only
|
||||
/// explanation anyone gets.
|
||||
fn with_causes(err: &(dyn std::error::Error + 'static)) -> String {
|
||||
let mut out = err.to_string();
|
||||
let mut source = err.source();
|
||||
while let Some(cause) = source {
|
||||
let text = cause.to_string();
|
||||
// Skip a cause that only repeats what we already said, which hyper's
|
||||
// wrappers do.
|
||||
if !out.contains(&text) {
|
||||
out.push_str(": ");
|
||||
out.push_str(&text);
|
||||
}
|
||||
source = cause.source();
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Posts the browser's offer to go2rtc and returns its answer SDP.
|
||||
pub async fn negotiate(api_listen: &str, camera_stream: &str, offer_sdp: &str) -> anyhow::Result<String> {
|
||||
let base = local_api_base(api_listen)?;
|
||||
@@ -73,7 +96,13 @@ pub async fn negotiate(api_listen: &str, camera_stream: &str, offer_sdp: &str) -
|
||||
.body(offer_sdp.to_string())
|
||||
.timeout(NEGOTIATION_TIMEOUT)
|
||||
.send()
|
||||
.await?;
|
||||
.await
|
||||
.map_err(|err| {
|
||||
// Names go2rtc explicitly. The most likely cause by far is that
|
||||
// it is not running, and an error mentioning only a port sends
|
||||
// whoever reads it looking at the network.
|
||||
anyhow::anyhow!("could not reach go2rtc at {base}: {}", with_causes(&err))
|
||||
})?;
|
||||
|
||||
// go2rtc answers 201 rather than 200 here, so this checks the class and
|
||||
// not a single code.
|
||||
|
||||
Reference in New Issue
Block a user