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