use crate::stdout::println;
use prikk_object::ObjectId;
use prikk_store::{
QueuedOperationContent, QueuedOperationEntry, QueuedPatchEntry, QueuedPathResolution,
RepositoryLayout,
};
use super::verification::escape_json_string;
pub(crate) enum QueueThresholdStatus {
None,
Warn,
HardLimit,
}
impl QueueThresholdStatus {
const fn as_str(&self) -> &'static str {
match self {
Self::None => "none",
Self::Warn => "warn",
Self::HardLimit => "hard-limit",
}
}
}
pub(crate) enum QueueTarget {
Ref(String),
MissingMetadata,
MalformedMetadata,
}
pub(crate) fn print_status_json(
layout: &RepositoryLayout,
active_wal_records: usize,
trailing_partial_wal_bytes: usize,
heads_main_ref_state: Option<ObjectId>,
queue_target: Option<&QueueTarget>,
threshold: Option<(&QueueThresholdStatus, usize, usize)>,
patches: &[QueuedPatchEntry],
) {
let mut json = String::new();
json.push_str("{\n");
json.push_str(" \"schema_version\": \"status-report-v1\",\n");
json.push_str(&format!(
" \"repository\": {},\n",
escape_json_string(&layout.prikk_dir().display().to_string())
));
json.push_str(&format!(
" \"active_wal_records\": {active_wal_records},\n"
));
json.push_str(&format!(
" \"trailing_partial_wal_bytes\": {trailing_partial_wal_bytes},\n"
));
match heads_main_ref_state {
Some(id) => json.push_str(&format!(
" \"heads_main_ref_state\": {},\n",
escape_json_string(&id.to_string())
)),
None => json.push_str(" \"heads_main_ref_state\": null,\n"),
}
json.push_str(" \"queue\": {\n");
json.push_str(&format!(" \"count\": {},\n", patches.len()));
match queue_target {
Some(QueueTarget::Ref(ref_name)) => {
json.push_str(&format!(
" \"target_ref\": {},\n",
escape_json_string(ref_name)
));
json.push_str(" \"target_ref_status\": null,\n");
}
Some(QueueTarget::MissingMetadata) => {
json.push_str(" \"target_ref\": null,\n");
json.push_str(" \"target_ref_status\": \"missing-metadata\",\n");
}
Some(QueueTarget::MalformedMetadata) => {
json.push_str(" \"target_ref\": null,\n");
json.push_str(" \"target_ref_status\": \"malformed-metadata\",\n");
}
None => {
json.push_str(" \"target_ref\": null,\n");
json.push_str(" \"target_ref_status\": null,\n");
}
}
match threshold {
Some((status, warn, limit)) => {
json.push_str(&format!(
" \"threshold_status\": {},\n",
escape_json_string(status.as_str())
));
json.push_str(&format!(" \"warn_threshold\": {warn},\n"));
json.push_str(&format!(" \"hard_limit\": {limit},\n"));
}
None => {
json.push_str(" \"threshold_status\": null,\n");
json.push_str(" \"warn_threshold\": null,\n");
json.push_str(" \"hard_limit\": null,\n");
}
}
json.push_str(" \"patches\": [");
for (index, patch) in patches.iter().enumerate() {
if index > 0 {
json.push(',');
}
json.push_str("\n {\"patch_id\": ");
json.push_str(&escape_json_string(&patch.patch_id.to_string()));
json.push_str(", \"operations\": [");
for (op_index, operation) in patch.operations.iter().enumerate() {
if op_index > 0 {
json.push(',');
}
json.push_str("\n ");
push_operation(&mut json, operation);
}
if !patch.operations.is_empty() {
json.push_str("\n ");
}
json.push_str("]}");
}
if !patches.is_empty() {
json.push_str("\n ");
}
json.push_str("]\n");
json.push_str(" }\n");
json.push('}');
println!("{json}");
}
fn push_operation(json: &mut String, operation: &QueuedOperationEntry) {
json.push_str("{\"kind\": ");
json.push_str(&escape_json_string(operation.kind));
json.push_str(", \"paths\": [");
for (index, path) in operation.paths.iter().enumerate() {
if index > 0 {
json.push(',');
}
match path {
QueuedPathResolution::Path(path) => {
json.push_str("{\"path\": ");
json.push_str(&escape_json_string(path));
json.push('}');
}
QueuedPathResolution::Unresolved { node_id } => {
json.push_str("{\"unresolved_node_id\": ");
json.push_str(&escape_json_string(node_id));
json.push('}');
}
}
}
json.push(']');
if let QueuedOperationContent::RenamePath { author_key_id } = &operation.content {
json.push_str(", \"author_key_id\": ");
json.push_str(&escape_json_string(author_key_id));
}
json.push('}');
}