Skip to content

Commit

Permalink
feat: setup rate-limit canister
Browse files Browse the repository at this point in the history
  • Loading branch information
IDX GitLab Automation committed Oct 10, 2024
1 parent bc4d5b7 commit 2d6a3fe
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 0 deletions.
32 changes: 32 additions & 0 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ members = [
"rs/boundary_node/certificate_issuance/certificate_orchestrator",
"rs/boundary_node/discower_bowndary",
"rs/boundary_node/ic_boundary",
"rs/boundary_node/prober",
"rs/boundary_node/rate_limits",
"rs/boundary_node/rate_limits/api",
"rs/boundary_node/rate_limits/canister_client",
"rs/boundary_node/systemd_journal_gatewayd_shim",
"rs/canister_client",
"rs/canister_client/sender",
Expand Down
21 changes: 21 additions & 0 deletions rs/boundary_node/rate_limits/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "rate_limits"
version.workspace = true
authors.workspace = true
edition.workspace = true
description.workspace = true
documentation.workspace = true

[dependencies]
candid = { workspace = true }
ciborium = { workspace = true }
ic-cdk = { workspace = true }
ic-cdk-macros = { workspace = true }
ic-cdk-timers = { workspace = true }
ic-stable-structures = { workspace = true }
rate-limits-api = { path = "./api" }
serde = { workspace = true }

[lib]
crate-type = ["cdylib"]
path = "canister/canister.rs"
14 changes: 14 additions & 0 deletions rs/boundary_node/rate_limits/api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "rate-limits-api"
version.workspace = true
authors.workspace = true
edition.workspace = true
description.workspace = true
documentation.workspace = true

[dependencies]
candid = {workspace = true}
serde = {workspace = true}

[lib]
path = "src/lib.rs"
28 changes: 28 additions & 0 deletions rs/boundary_node/rate_limits/api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use candid::CandidType;
use serde::Deserialize;

pub type Version = u64;
pub type Timestamp = u64;
pub type RuleId = String;

pub type GetConfigResponse = Result<ConfigResponse, String>;

#[derive(CandidType, Deserialize, Debug)]
pub struct ConfigResponse {
pub version: Version,
pub active_since: Timestamp,
pub config: OutputConfig,
}

#[derive(CandidType, Deserialize, Debug)]
pub struct OutputConfig {
pub rules: Vec<OutputRule>,
}

#[derive(CandidType, Deserialize, Debug)]
pub struct OutputRule {
pub id: RuleId,
pub rule_raw: Option<Vec<u8>>,
pub description: Option<String>,
pub disclosed_at: Option<Timestamp>,
}
23 changes: 23 additions & 0 deletions rs/boundary_node/rate_limits/canister/canister.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use rate_limits_api::{GetConfigResponse, Version};
use storage::VERSION;
use types::{ConfigResponse, OutputConfig};
mod storage;
mod types;

#[ic_cdk_macros::update]
fn get_config(version: Option<Version>) -> GetConfigResponse {
let test_version_inc = VERSION.with(|v| {
let mut ver = v.borrow_mut();
let current_version = ver.get(&()).unwrap_or(0);
ver.insert((), current_version + 1);
current_version
});

let response = ConfigResponse {
version: version.unwrap_or(test_version_inc),
active_since: 1,
config: OutputConfig { rules: vec![] },
};

Ok(response.into())
}
31 changes: 31 additions & 0 deletions rs/boundary_node/rate_limits/canister/storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use std::cell::RefCell;

use ic_stable_structures::{
memory_manager::{MemoryId, MemoryManager, VirtualMemory},
DefaultMemoryImpl, StableBTreeMap,
};

use crate::types::Version;

// Stable Memory
type Memory = VirtualMemory<DefaultMemoryImpl>;

type StableMap<K, V> = StableBTreeMap<K, V, Memory>;
type _StableSet<T> = StableMap<T, ()>;
type StableValue<T> = StableMap<(), T>;

const MEMORY_ID_VERSION: u8 = 0;

// Memory
thread_local! {
static MEMORY_MANAGER: RefCell<MemoryManager<DefaultMemoryImpl>> =
RefCell::new(MemoryManager::init(DefaultMemoryImpl::default()));
}

thread_local! {
pub static VERSION: RefCell<StableValue<Version>> = RefCell::new(
StableValue::init(
MEMORY_MANAGER.with(|m| m.borrow().get(MemoryId::new(MEMORY_ID_VERSION))),
)
);
}
49 changes: 49 additions & 0 deletions rs/boundary_node/rate_limits/canister/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
pub type Version = u64;
pub type Timestamp = u64;
pub type RuleId = String;

pub struct ConfigResponse {
pub version: Version,
pub active_since: Timestamp,
pub config: OutputConfig,
}

pub struct OutputConfig {
pub rules: Vec<OutputRule>,
}

pub struct OutputRule {
pub id: RuleId,
pub rule_raw: Option<Vec<u8>>,
pub description: Option<String>,
pub disclosed_at: Option<Timestamp>,
}

impl From<OutputRule> for rate_limits_api::OutputRule {
fn from(value: OutputRule) -> Self {
rate_limits_api::OutputRule {
description: value.description,
disclosed_at: value.disclosed_at,
id: value.id,
rule_raw: value.rule_raw,
}
}
}

impl From<OutputConfig> for rate_limits_api::OutputConfig {
fn from(value: OutputConfig) -> Self {
rate_limits_api::OutputConfig {
rules: value.rules.into_iter().map(|r| r.into()).collect(),
}
}
}

impl From<ConfigResponse> for rate_limits_api::ConfigResponse {
fn from(value: ConfigResponse) -> Self {
rate_limits_api::ConfigResponse {
version: value.version,
active_since: value.active_since,
config: value.config.into(),
}
}
}
13 changes: 13 additions & 0 deletions rs/boundary_node/rate_limits/canister_client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "canister_client"
version.workspace = true
authors.workspace = true
edition.workspace = true
description.workspace = true
documentation.workspace = true

[dependencies]
rate-limits-api = { path = "../api" }
ic-agent = { workspace = true }
tokio = { workspace = true }
candid = { workspace = true }
33 changes: 33 additions & 0 deletions rs/boundary_node/rate_limits/canister_client/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use candid::{Decode, Encode, Principal};
use ic_agent::{identity::AnonymousIdentity, Agent};
use rate_limits_api::GetConfigResponse;

const RATE_LIMIT_CANISTER_ID: &str = "zwbmv-jyaaa-aaaab-qacaa-cai";
const IC_DOMAIN: &str = "https://ic0.app";

#[tokio::main]
async fn main() {
let agent = Agent::builder()
.with_url(IC_DOMAIN)
.with_identity(AnonymousIdentity {})
.build()
.expect("failed to build the agent");

agent.fetch_root_key().await.unwrap();

let canister_id = Principal::from_text(RATE_LIMIT_CANISTER_ID).unwrap();

// let args = Encode!(&Some(1u64)).unwrap();
let args = Encode!(&None::<u64>).unwrap();

let response = agent
.update(&canister_id, "get_config")
.with_arg(args)
.call_and_wait()
.await
.expect("update call failed");

let decoded = Decode!(&response, GetConfigResponse).expect("failed to decode candid response");

println!("get_config response: {decoded:#?}");
}
21 changes: 21 additions & 0 deletions rs/boundary_node/rate_limits/dfx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"version": 1,
"canisters": {
"rate_limit_canister": {
"type": "rust",
"package": "rate_limits",
"candid": "canister/interface.did"
}
},
"defaults": {
"build": {
"packtool": ""
}
},
"networks": {
"local": {
"bind": "127.0.0.1:8080",
"type": "ephemeral"
}
}
}

0 comments on commit 2d6a3fe

Please sign in to comment.