use cluster::ClusterBucket;
use local::LocalBucket;
use pdk_core::log::error;
use pdk_core::policy_context::api::Tier;
use serde::{Deserialize, Serialize};
use Bucket::{Cluster, Local};
use super::distribution_formula::DistributionFormula;
pub mod cluster;
pub mod local;
#[derive(Debug)]
pub struct BucketFactory {
cluster: bool,
tiers: Vec<(String, Vec<Tier>)>,
}
impl BucketFactory {
pub fn new(cluster: bool, tiers: Vec<(String, Vec<Tier>)>) -> Self {
BucketFactory { cluster, tiers }
}
pub fn create(&self, now: u128, group_selector: &str) -> Bucket {
let tiers = self
.tiers
.iter()
.find(|item| item.0.eq(group_selector))
.map(|item| item.1.as_slice())
.unwrap_or(&[]);
match self.cluster {
true => Cluster(ClusterBucket::new(now, tiers)),
false => Local(LocalBucket::new(now, tiers)),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Bucket {
Cluster(ClusterBucket),
Local(LocalBucket),
}
impl Bucket {
pub fn request_allowed(&mut self, now: u128, amount: usize) -> RequestAllowed {
match self {
Cluster(bucket) => bucket.request_allowed(now, amount),
Local(bucket) => bucket.request_allowed(now, amount),
}
}
pub fn status(&self) -> Option<LimitStats> {
match self {
Cluster(bucket) => bucket.status(),
Local(bucket) => bucket.status(),
}
}
pub fn get_quota(
&mut self,
now: u128,
bucket: &Bucket,
formula: &DistributionFormula,
amount: usize,
) -> Vec<QuotaInfo> {
match (self, bucket) {
(Cluster(self_bucket), Cluster(bucket)) => {
self_bucket.get_quota(now, bucket, formula, amount)
}
_ => {
error!("Unexpected error: Quota request for non cluster buckets");
vec![]
}
}
}
pub fn update_quota(&mut self, quota: &[QuotaInfo]) {
match self {
Cluster(bucket) => bucket.update_quota(quota),
Local(_) => error!("Unexpected error: Quota update for non cluster buckets"),
}
}
}
pub enum RequestAllowed {
Allowed,
OutOfLocalQuota,
OutOfQuota,
}
#[derive(Clone)]
pub struct LimitStats {
left: u64,
max: u64,
reset: u128,
}
impl LimitStats {
fn new(left: u64, max: u64, reset: u128) -> Self {
Self { left, max, reset }
}
fn most_restrictive(stat1: LimitStats, stat2: LimitStats) -> LimitStats {
match (
(stat1.left == 0, stat1.reset),
(stat2.left == 0, stat2.reset),
) {
((true, _), (false, _)) => stat1,
((false, _), (true, _)) => stat2,
((_, reset1), (_, reset2)) if reset1 < reset2 => stat1,
_ => stat2,
}
}
pub fn remaining(&self) -> u64 {
self.left
}
pub fn limit(&self) -> u64 {
self.max
}
pub fn reset(&self, now: u128) -> u128 {
if now >= self.reset {
1u128
} else {
self.reset - now
}
}
}
#[derive(Debug)]
pub struct QuotaInfo {
given: u64,
remaining: u64,
reset: u128,
}
impl QuotaInfo {
pub fn new(given: u64, remaining: u64, reset: u128) -> Self {
QuotaInfo {
given,
remaining,
reset,
}
}
pub fn is_some(&self) -> bool {
self.given > 0
}
}