mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
Add shared OAuth flows
This commit is contained in:
72
crates/aether-oauth/src/network/context.rs
Normal file
72
crates/aether-oauth/src/network/context.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
74
crates/aether-oauth/src/network/executor.rs
Normal file
74
crates/aether-oauth/src/network/executor.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
||||
7
crates/aether-oauth/src/network/mod.rs
Normal file
7
crates/aether-oauth/src/network/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
mod context;
|
||||
mod executor;
|
||||
|
||||
pub use context::{NetworkRequirement, OAuthNetworkContext, OAuthNetworkPolicy, OAuthTimeouts};
|
||||
pub use executor::{
|
||||
OAuthHttpExecutor, OAuthHttpRequest, OAuthHttpResponse, ReqwestOAuthHttpExecutor,
|
||||
};
|
||||
Reference in New Issue
Block a user