feat(runtime): replace tokio+reqwest with asupersync async runtime
- Add HTTP adapter layer (src/http.rs) wrapping asupersync h1 client - Migrate gitlab client, graphql, and ollama to HTTP adapter - Swap entrypoint from #[tokio::main] to RuntimeBuilder::new().block_on() - Rewrite signal handler for asupersync (RuntimeHandle::spawn + ctrl_c()) - Migrate rate limiter sleeps to asupersync::time::sleep(wall_now(), d) - Add asupersync-native HTTP integration tests - Convert timeline_seed_tests to RuntimeBuilder pattern Phases 1-3 of asupersync migration (atomic: code won't compile without all pieces).
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
use reqwest::Client;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use tracing::warn;
|
||||
|
||||
use crate::core::error::LoreError;
|
||||
use crate::http::Client;
|
||||
|
||||
pub struct GraphqlClient {
|
||||
http: Client,
|
||||
@@ -21,13 +21,8 @@ pub struct GraphqlQueryResult {
|
||||
|
||||
impl GraphqlClient {
|
||||
pub fn new(base_url: &str, token: &str) -> Self {
|
||||
let http = Client::builder()
|
||||
.timeout(Duration::from_secs(30))
|
||||
.build()
|
||||
.unwrap_or_else(|_| Client::new());
|
||||
|
||||
Self {
|
||||
http,
|
||||
http: Client::with_timeout(Duration::from_secs(30)),
|
||||
base_url: base_url.trim_end_matches('/').to_string(),
|
||||
token: token.to_string(),
|
||||
}
|
||||
@@ -45,23 +40,13 @@ impl GraphqlClient {
|
||||
"variables": variables,
|
||||
});
|
||||
|
||||
let bearer = format!("Bearer {}", self.token);
|
||||
let response = self
|
||||
.http
|
||||
.post(&url)
|
||||
.header("Authorization", format!("Bearer {}", self.token))
|
||||
.header("Content-Type", "application/json")
|
||||
.json(&body)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| LoreError::GitLabNetworkError {
|
||||
base_url: self.base_url.clone(),
|
||||
kind: crate::core::error::NetworkErrorKind::Other,
|
||||
detail: Some(format!("{e:?}")),
|
||||
})?;
|
||||
.post_json(&url, &[("Authorization", bearer.as_str())], &body)
|
||||
.await?;
|
||||
|
||||
let status = response.status();
|
||||
|
||||
match status.as_u16() {
|
||||
match response.status {
|
||||
401 | 403 => return Err(LoreError::GitLabAuthFailed),
|
||||
404 => {
|
||||
return Err(LoreError::GitLabNotFound {
|
||||
@@ -73,14 +58,13 @@ impl GraphqlClient {
|
||||
return Err(LoreError::GitLabRateLimited { retry_after });
|
||||
}
|
||||
s if s >= 400 => {
|
||||
return Err(LoreError::Other(format!("GraphQL HTTP {status}")));
|
||||
return Err(LoreError::Other(format!("GraphQL HTTP {s}")));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let json: Value = response
|
||||
.json()
|
||||
.await
|
||||
.map_err(|e| LoreError::Other(format!("Failed to parse GraphQL response: {e}")))?;
|
||||
|
||||
let errors = json.get("errors").and_then(|e| e.as_array());
|
||||
@@ -117,12 +101,8 @@ impl GraphqlClient {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_retry_after(response: &reqwest::Response) -> u64 {
|
||||
let header = match response
|
||||
.headers()
|
||||
.get("retry-after")
|
||||
.and_then(|v| v.to_str().ok())
|
||||
{
|
||||
fn parse_retry_after(response: &crate::http::Response) -> u64 {
|
||||
let header = match response.header("retry-after") {
|
||||
Some(s) => s,
|
||||
None => return 60,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user