use std::collections::HashMap;
use base64::engine::general_purpose::STANDARD_NO_PAD;
use base64::Engine as _;
use serde::{Deserialize, Serialize};
use super::detail::ErrorDetail;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct WireError {
pub code: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub details: Option<Vec<WireErrorDetail>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct WireErrorDetail {
#[serde(rename = "type")]
pub type_url: String,
pub value: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub debug: Option<serde_json::Value>,
}
impl WireErrorDetail {
#[must_use]
pub fn from_detail(detail: &ErrorDetail) -> Self {
let debug = detail
.wire_json()
.and_then(|j| serde_json::from_str::<serde_json::Value>(j).ok());
Self {
type_url: detail.type_name().to_string(),
value: STANDARD_NO_PAD.encode(detail.value()),
debug,
}
}
#[must_use]
pub fn to_detail(&self) -> ErrorDetail {
let value = STANDARD_NO_PAD.decode(&self.value).unwrap_or_default();
let type_url = if self.type_url.contains('/') {
self.type_url.clone()
} else {
format!("type.googleapis.com/{}", self.type_url)
};
let detail = ErrorDetail::from_raw(type_url, value);
match &self.debug {
Some(dbg) => detail.with_wire_json(dbg.to_string()),
None => detail,
}
}
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
pub struct EndStreamResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<WireError>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, Vec<String>>>,
}