use crate::{
cdk::types::Principal,
ids::{CanisterRole, ManagedCanisterBinding},
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RootCapabilityCallerAuthority {
FleetSubnetRoot { canister_id: Principal },
ComponentMember(RootCapabilityMemberAuthority),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RootCapabilityMemberAuthority {
canister_id: Principal,
parent_canister_id: Principal,
role: CanisterRole,
}
impl RootCapabilityMemberAuthority {
#[must_use]
pub const fn canister_id(&self) -> Principal {
self.canister_id
}
}
impl From<ManagedCanisterBinding> for RootCapabilityMemberAuthority {
fn from(member: ManagedCanisterBinding) -> Self {
match member {
ManagedCanisterBinding::Component(binding) => Self {
canister_id: binding.canister_id,
parent_canister_id: binding.fleet_subnet_root,
role: binding.role,
},
ManagedCanisterBinding::ComponentChild(binding) => Self {
canister_id: binding.canister_id,
parent_canister_id: binding.parent_canister_id,
role: binding.role,
},
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RootCapabilityParentAuthority {
FleetSubnetRoot { canister_id: Principal },
ComponentMember { canister_id: Principal },
}
impl From<RootCapabilityMemberAuthority> for RootCapabilityParentAuthority {
fn from(member: RootCapabilityMemberAuthority) -> Self {
Self::ComponentMember {
canister_id: member.canister_id,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
struct RootCapabilityTargetAuthority {
canister_id: Principal,
parent_canister_id: Principal,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RootCapabilityAuthority {
caller: RootCapabilityCallerAuthority,
provision_parent: Option<RootCapabilityParentAuthority>,
target: Option<RootCapabilityTargetAuthority>,
}
impl RootCapabilityAuthority {
#[must_use]
pub const fn new(caller: RootCapabilityCallerAuthority) -> Self {
Self {
caller,
provision_parent: None,
target: None,
}
}
#[must_use]
pub const fn with_provision_parent(mut self, parent: RootCapabilityParentAuthority) -> Self {
self.provision_parent = Some(parent);
self
}
#[must_use]
pub fn with_target(mut self, target: ManagedCanisterBinding) -> Self {
self.target = Some(RootCapabilityTargetAuthority::from(target));
self
}
pub(super) const fn caller_canister_id(&self) -> Principal {
match &self.caller {
RootCapabilityCallerAuthority::FleetSubnetRoot { canister_id } => *canister_id,
RootCapabilityCallerAuthority::ComponentMember(member) => member.canister_id,
}
}
pub(super) const fn caller_is_fleet_subnet_root(&self) -> bool {
matches!(
&self.caller,
RootCapabilityCallerAuthority::FleetSubnetRoot { .. }
)
}
pub(super) const fn caller_parent_canister_id(&self) -> Option<Principal> {
match &self.caller {
RootCapabilityCallerAuthority::FleetSubnetRoot { .. } => None,
RootCapabilityCallerAuthority::ComponentMember(member) => {
Some(member.parent_canister_id)
}
}
}
pub(super) const fn caller_role(&self) -> Option<&CanisterRole> {
match &self.caller {
RootCapabilityCallerAuthority::FleetSubnetRoot { .. } => None,
RootCapabilityCallerAuthority::ComponentMember(member) => Some(&member.role),
}
}
pub(super) fn provision_parent_canister_id(&self) -> Option<Principal> {
self.provision_parent.as_ref().map(|parent| match parent {
RootCapabilityParentAuthority::FleetSubnetRoot { canister_id }
| RootCapabilityParentAuthority::ComponentMember { canister_id } => *canister_id,
})
}
pub(super) const fn has_provision_parent(&self) -> bool {
self.provision_parent.is_some()
}
pub(super) fn target_canister_id(&self) -> Option<Principal> {
self.target.as_ref().map(|target| target.canister_id)
}
pub(super) fn target_parent_canister_id(&self) -> Option<Principal> {
self.target.as_ref().map(|target| target.parent_canister_id)
}
pub(super) const fn has_target(&self) -> bool {
self.target.is_some()
}
}
impl From<ManagedCanisterBinding> for RootCapabilityTargetAuthority {
fn from(member: ManagedCanisterBinding) -> Self {
match member {
ManagedCanisterBinding::Component(binding) => Self {
canister_id: binding.canister_id,
parent_canister_id: binding.fleet_subnet_root,
},
ManagedCanisterBinding::ComponentChild(binding) => Self {
canister_id: binding.canister_id,
parent_canister_id: binding.parent_canister_id,
},
}
}
}