Skip to content

Commit

Permalink
feat(station): add external canister endpoints (#311)
Browse files Browse the repository at this point in the history
Adds the implementation of the endpoints to search and get external
canisters information.
  • Loading branch information
keplervital authored Aug 12, 2024
1 parent a9e8411 commit f2b583a
Show file tree
Hide file tree
Showing 19 changed files with 948 additions and 73 deletions.
14 changes: 13 additions & 1 deletion apps/wallet/src/generated/station/station.did
Original file line number Diff line number Diff line change
Expand Up @@ -2287,8 +2287,10 @@ type ExternalCanisterCallerMethodsPrivileges = record {

// The caller privileges for the external canister.
type ExternalCanisterCallerPrivileges = record {
// The external canister retource id.
// The external canister entry id.
id : UUID;
// The canister id.
canister_id : principal;
// Wether or not the caller can edit the external canister.
can_change : bool;
// The list of methods that the caller can call on the external canister.
Expand All @@ -2305,14 +2307,24 @@ type GetExternalCanisterResult = variant {
Err : Error;
};

// The input type for sorting the results of listing external canisters.
type ListExternalCanistersSortInput = variant {
// Sort by the name of the external canister.
Name : SortByDirection;
};

// Input type for listing external canisters with the given filters.
type ListExternalCanistersInput = record {
// The principal id of the external canister to search for.
canister_ids : opt vec principal;
// The labels to use for filtering the external canisters.
labels : opt vec text;
// The current state of the external canisters to use for filtering (e.g. `Active`, `Archived`).
states : opt vec ExternalCanisterState;
// The pagination parameters.
paginate : opt PaginationInput;
// The sort parameters.
sort_by : opt ListExternalCanistersSortInput;
};

// Result type for listing external canisters.
Expand Down
4 changes: 4 additions & 0 deletions apps/wallet/src/generated/station/station.did.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ export interface ExternalCanisterCallerMethodsPrivileges {
export interface ExternalCanisterCallerPrivileges {
'id' : UUID,
'can_change' : boolean,
'canister_id' : Principal,
'can_call' : Array<ExternalCanisterCallerMethodsPrivileges>,
}
export interface ExternalCanisterChangeRequestPolicyRule {
Expand Down Expand Up @@ -571,6 +572,8 @@ export type ListAddressBookEntriesResult = {
} |
{ 'Err' : Error };
export interface ListExternalCanistersInput {
'sort_by' : [] | [ListExternalCanistersSortInput],
'states' : [] | [Array<ExternalCanisterState>],
'canister_ids' : [] | [Array<Principal>],
'labels' : [] | [Array<string>],
'paginate' : [] | [PaginationInput],
Expand All @@ -584,6 +587,7 @@ export type ListExternalCanistersResult = {
}
} |
{ 'Err' : Error };
export type ListExternalCanistersSortInput = { 'Name' : SortByDirection };
export interface ListNotificationsInput {
'status' : [] | [NotificationStatus],
'to_dt' : [] | [TimestampRFC3339],
Expand Down
8 changes: 7 additions & 1 deletion apps/wallet/src/generated/station/station.did.js
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,7 @@ export const idlFactory = ({ IDL }) => {
const ExternalCanisterCallerPrivileges = IDL.Record({
'id' : UUID,
'can_change' : IDL.Bool,
'canister_id' : IDL.Principal,
'can_call' : IDL.Vec(ExternalCanisterCallerMethodsPrivileges),
});
const ExternalCanister = IDL.Record({
Expand Down Expand Up @@ -986,7 +987,13 @@ export const idlFactory = ({ IDL }) => {
}),
'Err' : Error,
});
const SortByDirection = IDL.Variant({ 'Asc' : IDL.Null, 'Desc' : IDL.Null });
const ListExternalCanistersSortInput = IDL.Variant({
'Name' : SortByDirection,
});
const ListExternalCanistersInput = IDL.Record({
'sort_by' : IDL.Opt(ListExternalCanistersSortInput),
'states' : IDL.Opt(IDL.Vec(ExternalCanisterState)),
'canister_ids' : IDL.Opt(IDL.Vec(IDL.Principal)),
'labels' : IDL.Opt(IDL.Vec(IDL.Text)),
'paginate' : IDL.Opt(PaginationInput),
Expand Down Expand Up @@ -1100,7 +1107,6 @@ export const idlFactory = ({ IDL }) => {
}),
'Err' : Error,
});
const SortByDirection = IDL.Variant({ 'Asc' : IDL.Null, 'Desc' : IDL.Null });
const ListRequestsSortBy = IDL.Variant({
'ExpirationDt' : SortByDirection,
'LastModificationDt' : SortByDirection,
Expand Down
14 changes: 13 additions & 1 deletion core/station/api/spec.did
Original file line number Diff line number Diff line change
Expand Up @@ -2287,8 +2287,10 @@ type ExternalCanisterCallerMethodsPrivileges = record {

// The caller privileges for the external canister.
type ExternalCanisterCallerPrivileges = record {
// The external canister retource id.
// The external canister entry id.
id : UUID;
// The canister id.
canister_id : principal;
// Wether or not the caller can edit the external canister.
can_change : bool;
// The list of methods that the caller can call on the external canister.
Expand All @@ -2305,14 +2307,24 @@ type GetExternalCanisterResult = variant {
Err : Error;
};

// The input type for sorting the results of listing external canisters.
type ListExternalCanistersSortInput = variant {
// Sort by the name of the external canister.
Name : SortByDirection;
};

// Input type for listing external canisters with the given filters.
type ListExternalCanistersInput = record {
// The principal id of the external canister to search for.
canister_ids : opt vec principal;
// The labels to use for filtering the external canisters.
labels : opt vec text;
// The current state of the external canisters to use for filtering (e.g. `Active`, `Archived`).
states : opt vec ExternalCanisterState;
// The pagination parameters.
paginate : opt PaginationInput;
// The sort parameters.
sort_by : opt ListExternalCanistersSortInput;
};

// Result type for listing external canisters.
Expand Down
16 changes: 12 additions & 4 deletions core/station/api/src/external_canister.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
AllowDTO, CanisterInstallMode, PaginationInput, RequestPolicyRuleDTO, Sha256HashDTO,
TimestampRfc3339, UuidDTO, ValidationMethodResourceTargetDTO,
SortDirection, TimestampRfc3339, UuidDTO, ValidationMethodResourceTargetDTO,
};
use candid::{CandidType, Deserialize, Nat, Principal};

Expand Down Expand Up @@ -193,6 +193,7 @@ pub struct ExternalCanisterCallerMethodPrivilegesDTO {
#[derive(CandidType, serde::Serialize, Deserialize, Debug, Clone)]
pub struct ExternalCanisterCallerPrivilegesDTO {
pub id: UuidDTO,
pub canister_id: Principal,
pub can_change: bool,
pub can_call: Vec<ExternalCanisterCallerMethodPrivilegesDTO>,
}
Expand All @@ -203,11 +204,18 @@ pub struct GetExternalCanisterResponse {
pub privileges: ExternalCanisterCallerPrivilegesDTO,
}

#[derive(CandidType, serde::Serialize, Deserialize, Debug, Clone)]
pub enum ListExternalCanistersSortInput {
Name(SortDirection),
}

#[derive(CandidType, serde::Serialize, Deserialize, Debug, Clone)]
pub struct ListExternalCanistersInput {
pub canister_ids: Option<Vec<Principal>>,
pub labels: Option<Vec<String>>,
pub states: Option<Vec<ExternalCanisterStateDTO>>,
pub paginate: Option<PaginationInput>,
pub sort_by: Option<ListExternalCanistersSortInput>,
}

#[derive(CandidType, serde::Serialize, Deserialize, Debug, Clone)]
Expand All @@ -220,13 +228,13 @@ pub struct ListExternalCanistersResponse {

#[derive(CandidType, serde::Serialize, Deserialize, Debug, Clone)]
pub struct GetExternalCanisterFiltersInputWithName {
prefix: Option<String>,
pub prefix: Option<String>,
}

#[derive(CandidType, serde::Serialize, Deserialize, Debug, Clone)]
pub struct GetExternalCanisterFiltersInput {
with_name: Option<GetExternalCanisterFiltersInputWithName>,
with_labels: Option<bool>,
pub with_name: Option<GetExternalCanisterFiltersInputWithName>,
pub with_labels: Option<bool>,
}

#[derive(CandidType, serde::Serialize, Deserialize, Debug, Clone)]
Expand Down
12 changes: 9 additions & 3 deletions core/station/impl/results.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ benches:
heap_increase: 0
stable_memory_increase: 0
scopes: {}
list_external_canisters_with_all_statuses:
total:
instructions: 3462083192
heap_increase: 19
stable_memory_increase: 0
scopes: {}
repository_batch_insert_100_requests:
total:
instructions: 490157820
heap_increase: 0
stable_memory_increase: 241
stable_memory_increase: 240
scopes: {}
repository_filter_all_request_ids_by_default_filters:
total:
Expand All @@ -25,13 +31,13 @@ benches:
scopes: {}
service_filter_all_requests_with_creation_time_filters:
total:
instructions: 1151272167
instructions: 1151272168
heap_increase: 0
stable_memory_increase: 16
scopes: {}
service_filter_all_requests_with_default_filters:
total:
instructions: 6015172658
instructions: 6015172659
heap_increase: 3
stable_memory_increase: 16
scopes: {}
Expand Down
79 changes: 72 additions & 7 deletions core/station/impl/src/controllers/external_canister.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use lazy_static::lazy_static;
use orbit_essentials::api::ApiResult;
use orbit_essentials::with_middleware;
use station_api::{
GetExternalCanisterFiltersInput, GetExternalCanisterFiltersResponse, GetExternalCanisterInput,
GetExternalCanisterResponse, ListExternalCanistersInput, ListExternalCanistersResponse,
ExternalCanisterCallerPrivilegesDTO, GetExternalCanisterFiltersInput,
GetExternalCanisterFiltersResponse, GetExternalCanisterInput, GetExternalCanisterResponse,
ListExternalCanistersInput, ListExternalCanistersResponse,
};
use std::sync::Arc;

Expand Down Expand Up @@ -69,22 +70,86 @@ impl ExternalCanisterController {
&self,
input: GetExternalCanisterInput,
) -> ApiResult<GetExternalCanisterResponse> {
unimplemented!("get_external_canister")
let ctx = call_context();
let external_canister = self
.canister_service
.get_external_canister_by_canister_id(&input.canister_id)?;
let external_canister_policies = self
.canister_service
.get_external_canister_request_policies(&external_canister.canister_id);
let external_canister_permissions = self
.canister_service
.get_external_canister_permissions(&external_canister.canister_id);
let caller_privileges = self
.canister_service
.get_caller_privileges_for_external_canister(
&external_canister.id,
&external_canister.canister_id,
&ctx,
);

Ok(GetExternalCanisterResponse {
canister: external_canister
.into_dto(external_canister_permissions, external_canister_policies),
privileges: caller_privileges.into(),
})
}

#[with_middleware(guard = authorize(&call_context(), &[Resource::ExternalCanister(ExternalCanisterResourceAction::List)]))]
async fn list_external_canisters(
&self,
_input: ListExternalCanistersInput,
input: ListExternalCanistersInput,
) -> ApiResult<ListExternalCanistersResponse> {
unimplemented!("list_external_canisters")
let ctx = call_context();
let result = self.canister_service.list_external_canisters(input, &ctx)?;

let mut privileges = Vec::new();
for external_canister in &result.items {
let caller_privileges = self
.canister_service
.get_caller_privileges_for_external_canister(
&external_canister.id,
&external_canister.canister_id,
&ctx,
);

privileges.push(ExternalCanisterCallerPrivilegesDTO::from(caller_privileges));
}

Ok(ListExternalCanistersResponse {
canisters: result
.items
.into_iter()
.map(|external_canister| {
let policies = self
.canister_service
.get_external_canister_permissions(&external_canister.canister_id);
let permissions = self
.canister_service
.get_external_canister_request_policies(&external_canister.canister_id);

external_canister.into_dto(policies, permissions)
})
.collect(),
next_offset: result.next_offset,
total: result.total,
privileges,
})
}

#[with_middleware(guard = authorize(&call_context(), &[Resource::ExternalCanister(ExternalCanisterResourceAction::List)]))]
async fn get_external_canister_filters(
&self,
_input: GetExternalCanisterFiltersInput,
input: GetExternalCanisterFiltersInput,
) -> ApiResult<GetExternalCanisterFiltersResponse> {
unimplemented!("get_external_canister_filters")
let ctx = call_context();
let filters = self
.canister_service
.available_external_canisters_filters(input, &ctx);

Ok(GetExternalCanisterFiltersResponse {
names: filters.names,
labels: filters.labels,
})
}
}
10 changes: 10 additions & 0 deletions core/station/impl/src/controllers/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,19 @@ async fn initialize(input: Option<SystemInstall>) {
#[cfg(all(feature = "canbench", not(test)))]
#[ic_cdk_macros::init]
pub async fn mock_init() {
use crate::core::write_system_info;
use crate::models::SystemInfo;
use candid::Principal;

// Initialize the random number generator with a fixed seed to ensure deterministic
// results across runs of the benchmarks.
orbit_essentials::utils::initialize_rng_from_seed([0u8; 32]);

// Initialize the system info.
let mut system = SystemInfo::default();
system.set_upgrader_canister_id(Principal::from_slice(&[25; 29]));

write_system_info(system);
}

#[post_upgrade]
Expand Down
2 changes: 1 addition & 1 deletion core/station/impl/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub mod test_utils {
pub const UPGRADER_CANISTER_ID: [u8; 29] = [25; 29];

pub fn init_canister_system() -> SystemInfo {
let mut system = SystemInfo::default();
let mut system: SystemInfo = SystemInfo::default();
system
.set_upgrader_canister_id(Principal::from_slice(self::UPGRADER_CANISTER_ID.as_slice()));

Expand Down
6 changes: 6 additions & 0 deletions core/station/impl/src/core/utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use candid::Principal;

use super::authorization::Authorization;
use super::CallContext;
use crate::errors::PaginationError;
Expand Down Expand Up @@ -113,6 +115,10 @@ pub(crate) fn format_unique_string(text: &str) -> String {
deunicode::deunicode(text).to_lowercase().replace(' ', "")
}

/// The minimum principal value that can be used.
pub const MIN_PRINCIPAL: Principal = Principal::from_slice(&[0; 29]);
pub const MAX_PRINCIPAL: Principal = Principal::from_slice(&[255; 29]);

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading

0 comments on commit f2b583a

Please sign in to comment.