Add shared OAuth flows

This commit is contained in:
fawney19
2026-04-28 15:46:21 +08:00
parent 712b484bc8
commit 70f747d406
56 changed files with 5927 additions and 977 deletions

View File

@@ -0,0 +1,72 @@
use aether_contracts::ProxySnapshot;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OAuthNetworkPolicy {
DirectOnly,
DirectOrSystemProxy,
ProviderOperationProxy,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NetworkRequirement {
Optional,
RequiredProxyNode,
RequiredConfiguredProxy,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OAuthTimeouts {
pub connect_ms: u64,
pub read_ms: u64,
pub write_ms: u64,
pub total_ms: u64,
}
impl OAuthTimeouts {
pub const DIRECT_DEFAULT: Self = Self {
connect_ms: 30_000,
read_ms: 30_000,
write_ms: 30_000,
total_ms: 30_000,
};
pub const PROXY_DEFAULT: Self = Self {
connect_ms: 60_000,
read_ms: 60_000,
write_ms: 60_000,
total_ms: 60_000,
};
}
#[derive(Debug, Clone, PartialEq)]
pub struct OAuthNetworkContext {
pub policy: OAuthNetworkPolicy,
pub requirement: NetworkRequirement,
pub proxy: Option<ProxySnapshot>,
pub timeouts: OAuthTimeouts,
}
impl OAuthNetworkContext {
pub fn direct_identity() -> Self {
Self {
policy: OAuthNetworkPolicy::DirectOrSystemProxy,
requirement: NetworkRequirement::Optional,
proxy: None,
timeouts: OAuthTimeouts::DIRECT_DEFAULT,
}
}
pub fn provider_operation(proxy: Option<ProxySnapshot>) -> Self {
let timeouts = if proxy.is_some() {
OAuthTimeouts::PROXY_DEFAULT
} else {
OAuthTimeouts::DIRECT_DEFAULT
};
Self {
policy: OAuthNetworkPolicy::ProviderOperationProxy,
requirement: NetworkRequirement::Optional,
proxy,
timeouts,
}
}
}

View File

@@ -0,0 +1,74 @@
use crate::core::OAuthError;
use async_trait::async_trait;
use serde_json::Value;
use std::collections::BTreeMap;
use super::OAuthNetworkContext;
#[derive(Debug, Clone, PartialEq)]
pub struct OAuthHttpRequest {
pub request_id: String,
pub method: reqwest::Method,
pub url: String,
pub headers: BTreeMap<String, String>,
pub content_type: Option<String>,
pub json_body: Option<Value>,
pub body_bytes: Option<Vec<u8>>,
pub network: OAuthNetworkContext,
}
#[derive(Debug, Clone, PartialEq)]
pub struct OAuthHttpResponse {
pub status_code: u16,
pub body_text: String,
pub json_body: Option<Value>,
}
#[async_trait]
pub trait OAuthHttpExecutor: Send + Sync {
async fn execute(&self, request: OAuthHttpRequest) -> Result<OAuthHttpResponse, OAuthError>;
}
#[derive(Debug, Clone)]
pub struct ReqwestOAuthHttpExecutor {
client: reqwest::Client,
}
impl ReqwestOAuthHttpExecutor {
pub fn new(client: reqwest::Client) -> Self {
Self { client }
}
}
#[async_trait]
impl OAuthHttpExecutor for ReqwestOAuthHttpExecutor {
async fn execute(&self, request: OAuthHttpRequest) -> Result<OAuthHttpResponse, OAuthError> {
let mut builder = self
.client
.request(request.method.clone(), request.url.as_str());
for (name, value) in &request.headers {
builder = builder.header(name, value);
}
if let Some(json_body) = request.json_body.as_ref() {
builder = builder.json(json_body);
} else if let Some(body_bytes) = request.body_bytes.as_ref() {
builder = builder.body(body_bytes.clone());
}
let response = builder
.send()
.await
.map_err(|err| OAuthError::transport(err.to_string()))?;
let status_code = response.status().as_u16();
let body_text = response
.text()
.await
.map_err(|err| OAuthError::transport(err.to_string()))?;
let json_body = serde_json::from_str::<Value>(&body_text).ok();
Ok(OAuthHttpResponse {
status_code,
body_text,
json_body,
})
}
}

View File

@@ -0,0 +1,7 @@
mod context;
mod executor;
pub use context::{NetworkRequirement, OAuthNetworkContext, OAuthNetworkPolicy, OAuthTimeouts};
pub use executor::{
OAuthHttpExecutor, OAuthHttpRequest, OAuthHttpResponse, ReqwestOAuthHttpExecutor,
};