Skip to content

Commit

Permalink
Use client_credentials grant
Browse files Browse the repository at this point in the history
  • Loading branch information
rxdn committed Oct 28, 2024
1 parent 551e9d8 commit fa38e06
Show file tree
Hide file tree
Showing 18 changed files with 120 additions and 234 deletions.
4 changes: 0 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions patreon-proxy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,17 @@ edition = "2021"

[dependencies]
tokio = { version = "1", features = ["full"] }
tokio-postgres = { version = "0.7", features = ["with-chrono-0_4"] }
thiserror = "1"
chrono = { version = "0.4", features = ["serde"] }
reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
serde = { version = "1", features = ["derive"] }
serde-enum-str = "0.4"
serde_json = "1"
warp = { version = "0.3", default-features = false }
rustls = "0.21"
# rustls = "0.21"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
sentry = "0.31"
sentry-tracing = "0.31"
envy = "0.4"
deadpool-postgres = "0.10"
url = "2"
6 changes: 4 additions & 2 deletions patreon-proxy/envvars.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
- PATREON_CAMPAIGN_ID
- PATREON_CLIENT_ID
- PATREON_CLIENT_SECRET
- PATREON_REDIRECT_URI
- SERVER_ADDR
- DATABASE_URI
- RUST_LOG
- DEBUG_MODE
- JSON_LOG
- SENTRY_DSON
98 changes: 39 additions & 59 deletions patreon-proxy/src/main.rs → patreon-proxy/src/bin/main.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,34 @@
mod config;
mod database;
mod error;
mod http;
mod patreon;

use config::Config;
use database::Database;
use patreon::oauth;
use patreon::Entitlement;
use patreon::Poller;

use std::collections::HashMap;
use std::str::FromStr;
use std::sync::{Arc, RwLock};

use chrono::prelude::*;

use patreon_proxy::patreon::oauth::OauthClient;
use patreon_proxy::patreon::{Entitlement, Poller, Tokens};
use patreon_proxy::{http, Config, Result};
use sentry::types::Dsn;
use sentry_tracing::EventFilter;
use std::time::Duration;
use std::time::{Duration, Instant};
use tokio::time::sleep;

use crate::error::Error;
use tracing::log::{debug, error, info};
use tracing::{debug, error, info};
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::EnvFilter;

#[tokio::main]
pub async fn main() -> Result<(), Error> {
let config = Config::new().expect("Failed to load config from environment variables");
pub async fn main() -> Result<()> {
let config = Arc::new(Config::new().expect("Failed to load config from environment variables"));

let _guard = configure_observability(&config);

info!("Connecting to database...");
let db_client = Database::connect(&config).await?;
db_client.create_schema().await?;
info!("Database connection established");

let mut tokens = Arc::new(
db_client
.get_tokens(config.patreon_client_id.clone())
.await?,
);
tokens = Arc::new(handle_refresh(&tokens, &config, &db_client).await?);
let oauth_client = OauthClient::new(Arc::clone(&config))?;

let tokens = attempt_grant(&oauth_client, Some(10)).await?;
let expires_at = Instant::now() + Duration::from_secs(tokens.expires_in as u64);

let mut poller = Poller::new(config.patreon_campaign_id.clone(), Arc::clone(&tokens));
let mut poller = Poller::new(config.patreon_campaign_id.clone(), tokens);

let mut server_started = false;

Expand All @@ -60,11 +43,11 @@ pub async fn main() -> Result<(), Error> {
info!("Starting loop");

// Patreon issues tokens that last 1 month, but I have noticed some issues refreshing them close to the deadline
if (current_time_seconds() + (86400 * 3)) > tokens.expires {
if (expires_at - Instant::now()) < Duration::from_secs(86400 * 3) {
info!("Needs new credentials");
tokens = Arc::new(handle_refresh(&tokens, &config, &db_client).await?);
poller.tokens = Arc::clone(&tokens);
info!("Retrieved new credentials");
let tokens = attempt_grant(&oauth_client, None).await?;
poller = Poller::new(config.patreon_campaign_id.clone(), tokens);
info!(?expires_at, "Retrieved new credentials");
}

info!("Polling");
Expand Down Expand Up @@ -99,33 +82,30 @@ pub async fn main() -> Result<(), Error> {
}
}

fn current_time_seconds() -> i64 {
Utc::now().timestamp()
}
async fn attempt_grant(oauth_client: &OauthClient, max_retries: Option<usize>) -> Result<Tokens> {
let mut retries = 0usize;

async fn handle_refresh(
tokens: &database::Tokens,
config: &Config,
db_client: &Database,
) -> Result<database::Tokens, Error> {
info!("handle_refresh called");
let new_tokens = oauth::refresh_tokens(
tokens.refresh_token.clone(),
config.patreon_client_id.clone(),
config.patreon_client_secret.clone(),
)
.await?;

let tokens = database::Tokens::new(
new_tokens.access_token,
new_tokens.refresh_token,
current_time_seconds() + new_tokens.expires_in,
);
db_client
.update_tokens(config.patreon_client_id.clone(), &tokens)
.await?;

Ok(tokens)
loop {
info!("Attempting to refresh credentials");

let err = match oauth_client.grant_credentials().await {
Ok(tokens) => return Ok(tokens),
Err(e) => {
error!(error = %e, "Failed to refresh credentials, waiting 30s");
e
}
};

retries += 1;
if let Some(max) = max_retries {
if retries >= max {
error!("Failed to refresh credentials after {} attempts", max);
return Err(err);
}
}

sleep(Duration::from_secs(30)).await;
}
}

fn configure_observability(config: &Config) -> sentry::ClientInitGuard {
Expand Down
2 changes: 0 additions & 2 deletions patreon-proxy/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ pub struct Config {
pub patreon_campaign_id: String,
pub patreon_client_id: String,
pub patreon_client_secret: String,
pub patreon_redirect_uri: String,
pub server_addr: String,
pub database_uri: String,
pub sentry_dsn: Option<String>,
#[serde(default)]
pub debug_mode: bool,
Expand Down
89 changes: 0 additions & 89 deletions patreon-proxy/src/database/database.rs

This file was deleted.

5 changes: 0 additions & 5 deletions patreon-proxy/src/database/mod.rs

This file was deleted.

5 changes: 0 additions & 5 deletions patreon-proxy/src/database/sql/patreon_keys/get_tokens.sql

This file was deleted.

6 changes: 0 additions & 6 deletions patreon-proxy/src/database/sql/patreon_keys/insert_tokens.sql

This file was deleted.

7 changes: 0 additions & 7 deletions patreon-proxy/src/database/sql/patreon_keys/schema.sql

This file was deleted.

15 changes: 0 additions & 15 deletions patreon-proxy/src/database/tokens.rs

This file was deleted.

10 changes: 2 additions & 8 deletions patreon-proxy/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,14 @@ pub enum Error {
#[error("Error while operating on JSON: {0}")]
JsonError(#[from] serde_json::Error),

#[error("Error while performing database operation: {0}")]
DatabaseError(#[from] tokio_postgres::Error),
#[error("Error requesting Patreon. Status: {0}")]
PatreonError(reqwest::StatusCode),

#[error("Error while parsing URL: {0}")]
UrlParseError(#[from] url::ParseError),

#[error("Error while creating database pool: {0}")]
CreatePoolError(#[from] deadpool_postgres::CreatePoolError),

#[error("{0}")]
ParseIntError(#[from] std::num::ParseIntError),

#[error("Error while managing database pool: {0}")]
PoolError(#[from] deadpool_postgres::PoolError),
}

impl<T> From<Error> for Result<T> {
Expand Down
8 changes: 8 additions & 0 deletions patreon-proxy/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
mod config;
pub use config::Config;

mod error;
pub use error::{Error, Result};

pub mod http;
pub mod patreon;
4 changes: 3 additions & 1 deletion patreon-proxy/src/patreon/entitlement.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use chrono::{DateTime, Months, Utc};
use serde::Serialize;

use super::{models::MemberAttributes, tier::TIERS_PREMIUM_LEGACY, tier::TIERS_WHITELABEL_LEGACY, Tier};
use super::{
models::MemberAttributes, tier::TIERS_PREMIUM_LEGACY, tier::TIERS_WHITELABEL_LEGACY, Tier,
};

#[derive(Debug, Clone, Serialize)]
pub struct Entitlement {
Expand Down
1 change: 1 addition & 0 deletions patreon-proxy/src/patreon/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod poller;
mod tier;

pub use entitlement::Entitlement;
pub use models::Tokens;
pub use models::PledgeResponse;
pub use poller::Poller;
pub use tier::Tier;
Loading

0 comments on commit fa38e06

Please sign in to comment.