1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use crate::HttpError;
use pretty_simple_display::{DebugPretty, DisplaySimple};
use serde::{Deserialize, Serialize};
#[cfg(not(target_arch = "wasm32"))]
use std::env;
#[cfg(not(target_arch = "wasm32"))]
use tracing::warn;
/// API credentials for authentication
#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
pub struct ApiCredentials {
/// Client ID for OAuth2
pub client_id: Option<String>,
/// Client secret for OAuth2
pub client_secret: Option<String>,
}
impl ApiCredentials {
/// Validates whether the required fields `client_id` and `client_secret` are present.
///
/// # Returns
///
/// * `true` - If both `client_id` and `client_secret` are `Some` (i.e., not `None`).
/// * `false` - If either `client_id` or `client_secret` is `None`.
///
pub fn is_valid(&self) -> bool {
self.client_id.is_some() && self.client_secret.is_some()
}
/// Creates a new instance of the struct with credentials initialized from environment variables.
///
/// # Returns
/// - `Ok(Self)`: If the credentials are properly configured and valid.
/// - `Err(HttpError::ConfigError)`: If the credentials are not properly set or invalid, with an appropriate
/// error message indicating the configuration issue.
///
/// # Note
/// - If the credentials are invalid or not set, a warning will be logged, and only public API endpoints
/// will be accessible.
/// - On WASM targets, this always returns an error since environment variables are not available.
///
#[cfg(not(target_arch = "wasm32"))]
pub fn new() -> Result<Self, HttpError> {
let creds = Self::default();
if creds.is_valid() {
Ok(creds)
} else {
warn!(
"API credentials are provided in environment variables, only public endpoints will be available."
);
Err(HttpError::ConfigError(
"API credentials are not properly set in environment variables".into(),
))
}
}
/// Creates a new instance of the struct (WASM version).
///
/// # Returns
/// - `Err(HttpError::ConfigError)`: Always returns an error on WASM since environment variables
/// are not available. Use `with_credentials` to set credentials manually.
///
#[cfg(target_arch = "wasm32")]
pub fn new() -> Result<Self, HttpError> {
Err(HttpError::ConfigError(
"Environment variables are not available in WASM. Use with_credentials() instead."
.into(),
))
}
/// Retrieves the client credentials (Client ID and Client Secret) required for OAuth2 authentication.
///
/// # Returns
/// - `Ok((String, String))`: A tuple containing the `client_id` and `client_secret` if they are both set.
/// - `Err(HttpError)`: An error of type `HttpError::ConfigError` if either `client_id` or `client_secret` is not set.
///
/// # Errors
/// Returns an `HttpError::ConfigError` with a message indicating that both `Client ID`
/// and `Client Secret` must be set for OAuth2 authentication when either or both are absent.
///
/// # Note
/// This function assumes that `client_id` and `client_secret` are optional fields.
/// Ensure they are properly configured before invoking this function.
pub fn get_client_credentials(&self) -> Result<(String, String), HttpError> {
if self.client_id.is_some() && self.client_secret.is_some() {
Ok((
self.client_id.clone().unwrap(),
self.client_secret.clone().unwrap(),
))
} else {
Err(HttpError::ConfigError(
"Client ID and Client Secret must be set for OAuth2 authentication".into(),
))
}
}
}
impl Default for ApiCredentials {
#[cfg(not(target_arch = "wasm32"))]
fn default() -> Self {
dotenv::dotenv().ok();
let client_id = env::var("DERIBIT_CLIENT_ID").ok();
let client_secret = env::var("DERIBIT_CLIENT_SECRET").ok();
Self {
client_id,
client_secret,
}
}
#[cfg(target_arch = "wasm32")]
fn default() -> Self {
Self {
client_id: None,
client_secret: None,
}
}
}