huskies: merge 1187 story status chat command shows that project's status
This commit is contained in:
@@ -147,11 +147,16 @@ impl BotContext {
|
||||
pub async fn active_project_url(&self) -> Option<String> {
|
||||
let ap = self.gateway_active_project.as_ref()?;
|
||||
let name = ap.read().await.clone();
|
||||
self.project_url(&name).await
|
||||
}
|
||||
|
||||
/// Return the base URL for a named project from the live gateway store.
|
||||
pub async fn project_url(&self, name: &str) -> Option<String> {
|
||||
let store = self.gateway_projects_store.as_ref()?;
|
||||
store
|
||||
.read()
|
||||
.await
|
||||
.get(&name)
|
||||
.get(name)
|
||||
.and_then(|entry| entry.url.clone())
|
||||
}
|
||||
|
||||
@@ -162,18 +167,28 @@ impl BotContext {
|
||||
/// `rpc_response` frame. Returns an error message string if the
|
||||
/// connection or command fails.
|
||||
pub async fn proxy_bot_command(&self, command: &str, args: &str) -> Option<String> {
|
||||
let base_url = self.active_project_url().await?;
|
||||
Some(Self::run_proxy_bot_command(&base_url, command, args).await)
|
||||
}
|
||||
|
||||
/// Run the `bot.command` WebSocket RPC call against `base_url` and return
|
||||
/// the Markdown response, or an error message string on failure.
|
||||
///
|
||||
/// `pub(crate)` so callers that need to target a project by name (rather
|
||||
/// than always the active one, as [`Self::proxy_bot_command`] does — e.g.
|
||||
/// the `status <project>` command) can resolve their own URL and reuse
|
||||
/// this transport logic.
|
||||
pub(crate) async fn run_proxy_bot_command(base_url: &str, command: &str, args: &str) -> String {
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use tokio_tungstenite::tungstenite::Message as WsMsg;
|
||||
|
||||
let base_url = self.active_project_url().await?;
|
||||
|
||||
// Convert http(s):// → ws(s)://
|
||||
let ws_base = if let Some(rest) = base_url.strip_prefix("https://") {
|
||||
format!("wss://{rest}")
|
||||
} else if let Some(rest) = base_url.strip_prefix("http://") {
|
||||
format!("ws://{rest}")
|
||||
} else {
|
||||
base_url.clone()
|
||||
base_url.to_string()
|
||||
};
|
||||
let ws_url = format!("{ws_base}/ws");
|
||||
|
||||
@@ -188,7 +203,7 @@ impl BotContext {
|
||||
});
|
||||
let request_text = match serde_json::to_string(&request) {
|
||||
Ok(t) => t,
|
||||
Err(e) => return Some(format!("Failed to serialize RPC request: {e}")),
|
||||
Err(e) => return format!("Failed to serialize RPC request: {e}"),
|
||||
};
|
||||
|
||||
let connect_timeout = std::time::Duration::from_secs(5);
|
||||
@@ -200,21 +215,19 @@ impl BotContext {
|
||||
{
|
||||
Ok(Ok((stream, _))) => stream,
|
||||
Ok(Err(e)) => {
|
||||
return Some(format!(
|
||||
"Failed to connect to project server at {ws_url}: {e}"
|
||||
));
|
||||
return format!("Failed to connect to project server at {ws_url}: {e}");
|
||||
}
|
||||
Err(_) => {
|
||||
return Some(format!(
|
||||
return format!(
|
||||
"Project server at {ws_url} is unreachable (connect timed out after {connect_timeout:?})"
|
||||
));
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let (mut sink, mut stream) = ws_stream.split();
|
||||
|
||||
if let Err(e) = sink.send(WsMsg::Text(request_text.into())).await {
|
||||
return Some(format!("Failed to send RPC request: {e}"));
|
||||
return format!("Failed to send RPC request: {e}");
|
||||
}
|
||||
|
||||
let response_timeout = std::time::Duration::from_secs(30);
|
||||
@@ -243,24 +256,24 @@ impl BotContext {
|
||||
.and_then(|r| r.get("response"))
|
||||
.and_then(|v| v.as_str())
|
||||
.map(String::from)
|
||||
.or_else(|| {
|
||||
Some("Command succeeded with no response text".to_string())
|
||||
.unwrap_or_else(|| {
|
||||
"Command succeeded with no response text".to_string()
|
||||
});
|
||||
} else {
|
||||
let err = frame
|
||||
.get("error")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("unknown error");
|
||||
return Some(format!("Project server command failed: {err}"));
|
||||
return format!("Project server command failed: {err}");
|
||||
}
|
||||
}
|
||||
Ok(WsMsg::Close(_)) => break,
|
||||
Err(e) => return Some(format!("WebSocket error: {e}")),
|
||||
Err(e) => return format!("WebSocket error: {e}"),
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
Some("Project server did not respond in time (connection closed or timed out)".to_string())
|
||||
"Project server did not respond in time (connection closed or timed out)".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user