use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum RateLimitTier {
Standard,
Premium,
Enterprise,
Noop,
#[serde(other)]
Unknown,
}
impl std::fmt::Display for RateLimitTier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Standard => write!(f, "standard"),
Self::Premium => write!(f, "premium"),
Self::Enterprise => write!(f, "enterprise"),
Self::Noop => write!(f, "noop"),
Self::Unknown => write!(f, "unknown"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseRateLimitTierError(String);
impl std::fmt::Display for ParseRateLimitTierError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Invalid rate limit tier: {}", self.0)
}
}
impl std::error::Error for ParseRateLimitTierError {}
impl std::str::FromStr for RateLimitTier {
type Err = ParseRateLimitTierError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"standard" => Ok(Self::Standard),
"premium" => Ok(Self::Premium),
"enterprise" => Ok(Self::Enterprise),
"noop" => Ok(Self::Noop),
_ => Ok(Self::Unknown),
}
}
}
impl TryFrom<&str> for RateLimitTier {
type Error = ParseRateLimitTierError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
value.parse()
}
}
impl TryFrom<String> for RateLimitTier {
type Error = ParseRateLimitTierError;
fn try_from(value: String) -> Result<Self, Self::Error> {
value.parse()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "strict", serde(deny_unknown_fields))]
pub struct ApiKeyInfo {
pub name: String,
pub scopes: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub last_used_at: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "strict", serde(deny_unknown_fields))]
pub struct RateLimitInfo {
pub tier: RateLimitTier,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub limit: Option<i64>,
pub current_count: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub remaining: Option<i64>,
pub reset_in_seconds: i64,
pub reset_at: DateTime<Utc>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "strict", serde(deny_unknown_fields))]
pub struct UsageApiKeyResponse {
pub api_key: ApiKeyInfo,
pub rate_limit: RateLimitInfo,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AuthenticationMethod {
OAuth,
}
impl std::fmt::Display for AuthenticationMethod {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::OAuth => write!(f, "oauth"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseAuthenticationMethodError(String);
impl std::fmt::Display for ParseAuthenticationMethodError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Invalid authentication method: {}", self.0)
}
}
impl std::error::Error for ParseAuthenticationMethodError {}
impl std::str::FromStr for AuthenticationMethod {
type Err = ParseAuthenticationMethodError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"oauth" => Ok(Self::OAuth),
_ => Err(ParseAuthenticationMethodError(s.to_string())),
}
}
}
impl TryFrom<&str> for AuthenticationMethod {
type Error = ParseAuthenticationMethodError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
value.parse()
}
}
impl TryFrom<String> for AuthenticationMethod {
type Error = ParseAuthenticationMethodError;
fn try_from(value: String) -> Result<Self, Self::Error> {
value.parse()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "strict", serde(deny_unknown_fields))]
pub struct UsageOAuthResponse {
pub authentication_method: AuthenticationMethod,
pub message: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum UsageResponse {
ApiKey(UsageApiKeyResponse),
OAuth(UsageOAuthResponse),
}