use crate::peer_meta::PeerMetaInfo;
use crate::{AppInfo, FullStateDump, StorageInfo};
use holo_hash::*;
use holochain_types::prelude::*;
use holochain_types::websocket::AllowedOrigins;
use holochain_zome_types::cell::CellId;
use kitsune2_api::Url;
use std::collections::{BTreeMap, HashMap};
#[derive(Debug, serde::Serialize, serde::Deserialize, SerializedBytes)]
#[serde(tag = "type", content = "value", rename_all = "snake_case")]
pub enum AdminRequest {
AddAdminInterfaces(Vec<crate::config::AdminInterfaceConfig>),
GetDnaDefinition(Box<CellId>),
UpdateCoordinators(Box<UpdateCoordinatorsPayload>),
InstallApp(Box<InstallAppPayload>),
UninstallApp {
installed_app_id: InstalledAppId,
#[serde(default)]
force: bool,
},
ListDnas,
GenerateAgentPubKey,
ListCellIds,
ListApps {
status_filter: Option<AppStatusFilter>,
},
EnableApp {
installed_app_id: InstalledAppId,
},
DisableApp {
installed_app_id: InstalledAppId,
},
AttachAppInterface {
port: Option<u16>,
danger_bind_addr: Option<String>,
allowed_origins: AllowedOrigins,
installed_app_id: Option<InstalledAppId>,
},
ListAppInterfaces,
DumpState {
cell_id: Box<CellId>,
},
DumpConductorState,
DumpFullState {
cell_id: Box<CellId>,
dht_ops_cursor: Option<u64>,
},
DumpNetworkMetrics {
#[serde(default)]
dna_hash: Option<DnaHash>,
#[serde(default)]
include_dht_summary: bool,
},
DumpNetworkStats,
AddAgentInfo {
agent_infos: Vec<String>,
},
AgentInfo {
dna_hashes: Option<Vec<DnaHash>>,
},
PeerMetaInfo {
url: Url,
dna_hashes: Option<Vec<DnaHash>>,
},
GrantZomeCallCapability(Box<GrantZomeCallCapabilityPayload>),
RevokeZomeCallCapability {
action_hash: ActionHash,
cell_id: CellId,
},
ListCapabilityGrants {
installed_app_id: String,
include_revoked: bool,
},
DeleteCloneCell(Box<DeleteCloneCellPayload>),
StorageInfo,
IssueAppAuthenticationToken(IssueAppAuthenticationTokenPayload),
RevokeAppAuthenticationToken(AppAuthenticationToken),
#[cfg(feature = "unstable-migration")]
GetCompatibleCells(DnaHash),
}
#[derive(Debug, serde::Serialize, serde::Deserialize, SerializedBytes)]
#[cfg_attr(test, derive(Clone))]
#[serde(tag = "type", content = "value", rename_all = "snake_case")]
pub enum AdminResponse {
Error(ExternalApiWireError),
DnaDefinitionReturned(DnaDef),
CoordinatorsUpdated,
AppInstalled(AppInfo),
AppUninstalled,
AdminInterfacesAdded,
AgentPubKeyGenerated(AgentPubKey),
DnasListed(Vec<DnaHash>),
CellIdsListed(Vec<CellId>),
AppsListed(Vec<AppInfo>),
AppInterfaceAttached {
port: u16,
},
AppInterfacesListed(Vec<AppInterfaceInfo>),
AppEnabled(AppInfo),
AppDisabled,
StateDumped(String),
FullStateDumped(FullStateDump),
ConductorStateDumped(String),
NetworkMetricsDumped(HashMap<DnaHash, Kitsune2NetworkMetrics>),
NetworkStatsDumped(HolochainTransportStats),
AgentInfoAdded,
AgentInfo(Vec<String>),
PeerMetaInfo(BTreeMap<DnaHash, BTreeMap<String, PeerMetaInfo>>),
ZomeCallCapabilityGranted(ActionHash),
ZomeCallCapabilityRevoked,
CapabilityGrantsInfo(AppCapGrantInfo),
CloneCellDeleted,
StorageInfo(StorageInfo),
AppAuthenticationTokenIssued(AppAuthenticationTokenIssued),
AppAuthenticationTokenRevoked,
#[cfg(feature = "unstable-migration")]
CompatibleCells(CompatibleCells),
}
#[cfg(feature = "unstable-migration")]
pub type CompatibleCells =
std::collections::BTreeSet<(InstalledAppId, std::collections::BTreeSet<CellId>)>;
#[derive(Debug, serde::Serialize, serde::Deserialize, SerializedBytes, Clone)]
#[serde(tag = "type", content = "value", rename_all = "snake_case")]
pub enum ExternalApiWireError {
InternalError(String),
Deserialization(String),
DnaReadError(String),
RibosomeError(String),
ZomeCallAuthenticationFailed(String),
ZomeCallUnauthorized(String),
CountersigningSessionError(String),
}
impl ExternalApiWireError {
pub fn internal<T: std::fmt::Display>(e: T) -> Self {
ExternalApiWireError::InternalError(e.to_string())
}
}
#[derive(Debug, serde::Serialize, serde::Deserialize, SerializedBytes, Clone)]
#[serde(rename_all = "snake_case")]
pub enum AppStatusFilter {
Enabled,
Disabled,
}
#[derive(Debug, serde::Serialize, serde::Deserialize, SerializedBytes, Clone)]
pub struct AppInterfaceInfo {
pub port: u16,
pub allowed_origins: AllowedOrigins,
pub installed_app_id: Option<InstalledAppId>,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct IssueAppAuthenticationTokenPayload {
pub installed_app_id: InstalledAppId,
#[serde(default = "default_expiry_seconds")]
pub expiry_seconds: u64,
#[serde(default = "default_single_use")]
pub single_use: bool,
}
fn default_expiry_seconds() -> u64 {
30
}
fn default_single_use() -> bool {
true
}
impl IssueAppAuthenticationTokenPayload {
pub fn for_installed_app_id(installed_app_id: InstalledAppId) -> Self {
installed_app_id.into()
}
pub fn expiry_seconds(mut self, expiry_seconds: u64) -> Self {
self.expiry_seconds = expiry_seconds;
self
}
pub fn single_use(mut self, single_use: bool) -> Self {
self.single_use = single_use;
self
}
}
impl From<InstalledAppId> for IssueAppAuthenticationTokenPayload {
fn from(installed_app_id: InstalledAppId) -> Self {
Self {
installed_app_id,
expiry_seconds: 30,
single_use: true,
}
}
}
pub type AppAuthenticationToken = Vec<u8>;
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct AppAuthenticationTokenIssued {
pub token: AppAuthenticationToken,
pub expires_at: Option<Timestamp>,
}
#[cfg(test)]
mod tests {
use crate::{AdminRequest, AdminResponse, ExternalApiWireError};
use serde::Deserialize;
#[test]
fn admin_request_serialization() {
use rmp_serde::Deserializer;
let request = AdminRequest::DisableApp {
installed_app_id: "some_id".to_string(),
};
let serialized_request = holochain_serialized_bytes::encode(&request).unwrap();
assert_eq!(
serialized_request,
vec![
130, 164, 116, 121, 112, 101, 171, 100, 105, 115, 97, 98, 108, 101, 95, 97, 112,
112, 165, 118, 97, 108, 117, 101, 129, 176, 105, 110, 115, 116, 97, 108, 108, 101,
100, 95, 97, 112, 112, 95, 105, 100, 167, 115, 111, 109, 101, 95, 105, 100
]
);
let json_expected = r#"{"type":"disable_app","value":{"installed_app_id":"some_id"}}"#;
let mut deserializer = Deserializer::new(&*serialized_request);
let json_value: serde_json::Value = Deserialize::deserialize(&mut deserializer).unwrap();
let json_actual = serde_json::to_string(&json_value).unwrap();
assert_eq!(json_actual, json_expected);
let response = AdminResponse::Error(ExternalApiWireError::RibosomeError(
"error_text".to_string(),
));
let serialized_response = holochain_serialized_bytes::encode(&response).unwrap();
assert_eq!(
serialized_response,
vec![
130, 164, 116, 121, 112, 101, 165, 101, 114, 114, 111, 114, 165, 118, 97, 108, 117,
101, 130, 164, 116, 121, 112, 101, 174, 114, 105, 98, 111, 115, 111, 109, 101, 95,
101, 114, 114, 111, 114, 165, 118, 97, 108, 117, 101, 170, 101, 114, 114, 111, 114,
95, 116, 101, 120, 116
]
);
let json_expected =
r#"{"type":"error","value":{"type":"ribosome_error","value":"error_text"}}"#;
let mut deserializer = Deserializer::new(&*serialized_response);
let json_value: serde_json::Value = Deserialize::deserialize(&mut deserializer).unwrap();
let json_actual = serde_json::to_string(&json_value).unwrap();
assert_eq!(json_actual, json_expected);
}
}