random ud
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
||||
1229
Cargo.lock
generated
Normal file
1229
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
Cargo.toml
Normal file
14
Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "http_core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "Core traits and types for building API clients with http_derive"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
awc = "3"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
toml = "0.9.5"
|
||||
urlencoding = "2"
|
||||
|
||||
114
src/lib.rs
Normal file
114
src/lib.rs
Normal file
@ -0,0 +1,114 @@
|
||||
use async_trait::async_trait;
|
||||
use serde::{ Deserialize, Serialize };
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::fs;
|
||||
|
||||
/// A trait every API request type should implement (via macro).
|
||||
/// Provides info about the HTTP protocol, URLs, and supported methods.
|
||||
pub trait HasHttp {
|
||||
/// Methods this request supports (GET, POST, etc.)
|
||||
fn http_methods() -> &'static [&'static str];
|
||||
|
||||
/// Production endpoint (base URL).
|
||||
fn live_url() -> &'static str;
|
||||
|
||||
/// Sandbox endpoint (base URL).
|
||||
fn sandbox_url() -> &'static str;
|
||||
}
|
||||
|
||||
/// Trait implemented by all request types that can be sent to an HTTP API.
|
||||
/// Usually derived via `#[derive(HttpRequest)]`.
|
||||
#[async_trait]
|
||||
pub trait Queryable: HasHttp + Send + Sync {
|
||||
/// The response type for this query.
|
||||
type R;
|
||||
/// The error type for this query.
|
||||
type E: std::error::Error + Send + Sync + 'static;
|
||||
|
||||
/// Send the query, with flexibility for environment and overrides.
|
||||
///
|
||||
/// - `override_url`: if `Some`, use this instead of live/sandbox.
|
||||
/// - `sandbox`: if true, use sandbox_url.
|
||||
/// - `method_override`: optional HTTP method override (GET, POST, etc.).
|
||||
/// - `headers`: optional headers.
|
||||
async fn send(
|
||||
&self,
|
||||
override_url: Option<&str>,
|
||||
sandbox: bool,
|
||||
method_override: Option<&str>,
|
||||
headers: Option<Vec<(&str, &str)>>,
|
||||
) -> Result<Self::R, Self::E>;
|
||||
}
|
||||
|
||||
/// Trait for dispatching API calls in bulk or single-shot mode.
|
||||
///
|
||||
/// Implemented automatically for generated enums by the `#[api_dispatch]` macro.
|
||||
#[async_trait]
|
||||
pub trait ApiDispatch {
|
||||
/// Send all queries represented by this enum variant.
|
||||
///
|
||||
/// - `client`: A preconfigured `awc::Client`
|
||||
/// - `keys`: A shared API key store (depends on your app crate)
|
||||
async fn send_all(
|
||||
&self,
|
||||
client: &awc::Client,
|
||||
keys: &HashMap<String, crate::Keys>, // ⚠️ placeholder, you may need to re-export Keys
|
||||
override_url: Option<&str>,
|
||||
sandbox: bool,
|
||||
method_override: Option<&str>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct Key {
|
||||
pub key: String,
|
||||
pub secret: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct Keys {
|
||||
pub keys: HashMap<String, Key>,
|
||||
}
|
||||
|
||||
impl Keys {
|
||||
/// Convenience method to get a key by name (e.g. "alpaca")
|
||||
pub fn get(&self, name: &str) -> Option<&Key> {
|
||||
self.keys.get(name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads API keys from ~/.config/keys or fallback ./keys directory.
|
||||
/// Each `.toml` file should contain a `Key { key, secret }` struct.
|
||||
/// The filename (without `.toml`) becomes the key name in the map.
|
||||
pub fn load_api_keys() -> Result<Keys, Box<dyn std::error::Error>> {
|
||||
let home_dir = std::env::var("HOME")?;
|
||||
let config_dir = Path::new(&home_dir).join(".config/keys");
|
||||
let fallback_dir = Path::new("keys");
|
||||
|
||||
let dir_path = if config_dir.exists() {
|
||||
config_dir
|
||||
} else {
|
||||
fallback_dir.to_path_buf()
|
||||
};
|
||||
|
||||
let mut keys_map = HashMap::new();
|
||||
|
||||
for entry in fs::read_dir(dir_path)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
||||
if path.extension().and_then(|s| s.to_str()) == Some("toml") {
|
||||
let contents = fs::read_to_string(&path)?;
|
||||
let key: Key = toml::from_str(&contents)?;
|
||||
|
||||
if let Some(stem) = path.file_stem().and_then(|s| s.to_str()) {
|
||||
keys_map.insert(stem.to_string(), key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Keys { keys: keys_map })
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user