mod metrics;
mod migration;
pub(crate) mod render;
mod schema;
mod snapshot;
use crate::cli::{
CanisterTarget, DiagnosticArtifactArgs, DiagnosticSourceMetadataArgs, MetricsArgs,
SchemaMigrationCommand,
};
use crate::icp::{IcpCallKind, call_query_hex, call_update_hex};
use ic_host_text::escape::terminal_text;
use icydb::__macro::RpcMethod;
use serde::de::DeserializeOwned;
pub(crate) fn run_metrics_command(args: MetricsArgs) -> Result<(), String> {
metrics::run_metrics_command(args)
}
pub(crate) fn run_schema_show_command(target: CanisterTarget) -> Result<(), String> {
schema::run_schema_show_command(target)
}
pub(crate) fn run_diagnostic_artifact_command(args: DiagnosticArtifactArgs) -> Result<(), String> {
schema::run_diagnostic_artifact_command(args)
}
pub(crate) fn run_diagnostic_source_metadata_command(
args: DiagnosticSourceMetadataArgs,
) -> Result<(), String> {
schema::run_diagnostic_source_metadata_command(args)
}
pub(crate) fn load_schema_report(
environment: &str,
canister: &str,
) -> Result<Vec<icydb::db::EntitySchemaDescription>, String> {
schema::load_schema_report(environment, canister)
}
pub(crate) fn run_schema_migration_command(command: SchemaMigrationCommand) -> Result<(), String> {
migration::run_schema_migration_command(command)
}
pub(crate) fn run_snapshot_command(target: CanisterTarget) -> Result<(), String> {
snapshot::run_snapshot_command(target)
}
fn call_endpoint<T: serde::Serialize + DeserializeOwned>(
environment: &str,
canister: &str,
endpoint: RpcMethod,
arguments: impl serde::Serialize,
label: &str,
kind: IcpCallKind,
) -> Result<T, String> {
let method = endpoint.name();
let arguments = endpoint
.encode_request(
arguments,
icydb::wire::limits(icydb::wire::MAX_REQUEST_BYTES),
)
.map_err(|error| error.to_string())?;
let response = match kind {
IcpCallKind::Query => call_query_hex(environment, canister, method, &arguments, |stderr| {
method_error("query", environment, canister, method, stderr)
}),
IcpCallKind::Update => {
call_update_hex(environment, canister, method, &arguments, |stderr| {
method_error("update", environment, canister, method, stderr)
})
}
}?;
decode_endpoint_result(&response, label, environment, canister, endpoint, kind)
}
pub(crate) fn decode_endpoint_result<T: serde::Serialize + DeserializeOwned>(
bytes: &[u8],
label: &str,
environment: &str,
canister: &str,
endpoint: RpcMethod,
kind: IcpCallKind,
) -> Result<T, String> {
let response = endpoint
.decode_response::<Result<T, icydb::Error>>(
bytes,
icydb::wire::limits(icydb::wire::MAX_REPLY_BYTES),
)
.map_err(|error| {
kind.reply_error(crate::diagnostic::render_wire_decode_error(endpoint, error))
})?;
response.map_err(|error| {
method_error(
label,
environment,
canister,
endpoint.name(),
&crate::diagnostic::render_error(&error),
)
})
}
fn method_error(
label: &str,
environment: &str,
canister: &str,
method: &str,
detail: &str,
) -> String {
format!(
"IcyDB {label} method '{method}' failed on canister '{canister}' in environment '{environment}': {detail}",
canister = terminal_text(canister),
environment = terminal_text(environment),
)
}
#[cfg(test)]
pub(crate) mod support_tests;