Skip to content

Commit 820681c

Browse files
committed
rate_limit_config
1 parent 2f8fabf commit 820681c

File tree

20 files changed

+193
-104
lines changed

20 files changed

+193
-104
lines changed

lib/api_auth/src/github.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ async fn post_inner(
5656
// If not on Bencher Cloud, then at least one organization must have a valid Bencher Plus license
5757
if !context.is_bencher_cloud
5858
&& LicenseUsage::get_for_server(
59-
conn_lock!(context),
59+
&context.database.connection,
6060
&context.licensor,
6161
Some(PlanLevel::Enterprise),
62-
)?
62+
)
63+
.await?
6364
.is_empty()
6465
{
6566
return Err(payment_required_error(

lib/api_organizations/src/projects.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ async fn post_inner(
219219
QueryProject::is_visibility_public(visibility)?;
220220
#[cfg(feature = "plus")]
221221
PlanKind::check_for_organization(
222-
conn_lock!(context),
222+
context,
223223
context.biller.as_ref(),
224224
&context.licensor,
225225
&query_organization,

lib/api_projects/src/projects.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ async fn patch_inner(
284284
QueryProject::is_visibility_public(visibility)?;
285285
#[cfg(feature = "plus")]
286286
PlanKind::check_for_project(
287-
conn_lock!(context),
287+
context,
288288
context.biller.as_ref(),
289289
&context.licensor,
290290
&query_project,

lib/bencher_config/src/config_tx.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,12 @@ fn into_context(
196196
&security.secret_key,
197197
);
198198

199+
#[cfg(feature = "plus")]
200+
let rate_limit = plus
201+
.as_ref()
202+
.and_then(|plus| plus.rate_limit.map(Into::into))
203+
.unwrap_or_default();
204+
199205
info!(&log, "Configuring Bencher Plus");
200206
#[cfg(feature = "plus")]
201207
let Plus {
@@ -222,6 +228,8 @@ fn into_context(
222228
},
223229
restart_tx,
224230
#[cfg(feature = "plus")]
231+
rate_limit,
232+
#[cfg(feature = "plus")]
225233
github,
226234
#[cfg(feature = "plus")]
227235
stats,

lib/bencher_json/src/system/config/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub use plus::{
2222
JsonCloud,
2323
},
2424
litestream::{JsonLitestream, JsonReplica},
25+
rate_limit::JsonRateLimit,
2526
stats::JsonStats,
2627
JsonPlus,
2728
};

lib/bencher_json/src/system/config/plus/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,20 @@ use serde::{Deserialize, Serialize};
88
pub mod cloud;
99
pub mod github;
1010
pub mod litestream;
11+
pub mod rate_limit;
1112
pub mod stats;
1213

1314
pub use cloud::JsonCloud;
1415
pub use github::JsonGitHub;
1516
pub use litestream::JsonLitestream;
17+
pub use rate_limit::JsonRateLimit;
1618
pub use stats::JsonStats;
1719

1820
#[derive(Debug, Clone, Serialize, Deserialize)]
1921
#[cfg_attr(feature = "schema", derive(JsonSchema))]
2022
pub struct JsonPlus {
23+
#[serde(skip_serializing_if = "Option::is_none")]
24+
pub rate_limit: Option<JsonRateLimit>,
2125
#[serde(skip_serializing_if = "Option::is_none")]
2226
pub github: Option<JsonGitHub>,
2327
#[serde(alias = "disaster_recovery", skip_serializing_if = "Option::is_none")]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#[cfg(feature = "schema")]
2+
use schemars::JsonSchema;
3+
use serde::{Deserialize, Serialize};
4+
5+
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
6+
#[cfg_attr(feature = "schema", derive(JsonSchema))]
7+
pub struct JsonRateLimit {
8+
pub window: Option<u32>,
9+
pub unclaimed: Option<u32>,
10+
pub claimed: Option<u32>,
11+
}

lib/bencher_json/src/system/config/plus/stats.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize};
55
#[derive(Debug, Clone, Serialize, Deserialize)]
66
#[cfg_attr(feature = "schema", derive(JsonSchema))]
77
pub struct JsonStats {
8-
// Number of seconds from midnight
8+
/// Number of seconds from midnight
99
pub offset: Option<u32>,
10+
/// Enable stats collection
1011
pub enabled: Option<bool>,
1112
}

lib/bencher_schema/src/context/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use crate::model::project::QueryProject;
1414
mod database;
1515
mod indexer;
1616
mod messenger;
17+
#[cfg(feature = "plus")]
18+
mod rate_limit;
1719
mod rbac;
1820
#[cfg(feature = "plus")]
1921
mod stats;
@@ -24,6 +26,8 @@ pub use indexer::{IndexError, Indexer};
2426
#[cfg(feature = "plus")]
2527
pub use messenger::ServerStatsBody;
2628
pub use messenger::{Body, ButtonBody, Email, Message, Messenger, NewUserBody};
29+
#[cfg(feature = "plus")]
30+
pub use rate_limit::RateLimit;
2731
pub use rbac::{Rbac, RbacError};
2832
#[cfg(feature = "plus")]
2933
pub use stats::StatsSettings;
@@ -36,6 +40,8 @@ pub struct ApiContext {
3640
pub database: Database,
3741
pub restart_tx: Sender<()>,
3842
#[cfg(feature = "plus")]
43+
pub rate_limit: RateLimit,
44+
#[cfg(feature = "plus")]
3945
pub github: Option<GitHub>,
4046
#[cfg(feature = "plus")]
4147
pub indexer: Option<Indexer>,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use std::time::Duration;
2+
3+
use bencher_json::{system::config::JsonRateLimit, DateTime};
4+
5+
const DAY: Duration = Duration::from_secs(24 * 60 * 60);
6+
const UNCLAIMED_RATE_LIMIT: u32 = u8::MAX as u32;
7+
const CLAIMED_RATE_LIMIT: u32 = u16::MAX as u32;
8+
9+
pub struct RateLimit {
10+
pub window: Duration,
11+
pub unclaimed: u32,
12+
pub claimed: u32,
13+
}
14+
15+
impl From<JsonRateLimit> for RateLimit {
16+
fn from(json: JsonRateLimit) -> Self {
17+
let JsonRateLimit {
18+
window,
19+
unclaimed,
20+
claimed,
21+
} = json;
22+
Self {
23+
window: window.map(u64::from).map_or(DAY, Duration::from_secs),
24+
unclaimed: unclaimed.unwrap_or(UNCLAIMED_RATE_LIMIT),
25+
claimed: claimed.unwrap_or(CLAIMED_RATE_LIMIT),
26+
}
27+
}
28+
}
29+
30+
impl Default for RateLimit {
31+
fn default() -> Self {
32+
Self {
33+
window: DAY,
34+
unclaimed: UNCLAIMED_RATE_LIMIT,
35+
claimed: CLAIMED_RATE_LIMIT,
36+
}
37+
}
38+
}
39+
40+
impl RateLimit {
41+
pub fn window(&self) -> (DateTime, DateTime) {
42+
let end_time = chrono::Utc::now();
43+
let start_time = end_time - self.window;
44+
(start_time.into(), end_time.into())
45+
}
46+
}

0 commit comments

Comments
 (0)