use serde_json::Value;
use crate::types::InteractionResponse;
pub trait ResponseExt {
fn json(&self) -> Value;
fn response_type(&self) -> u8 {
self.json()["type"].as_u64().unwrap_or_default() as u8
}
fn text(&self) -> Option<String> {
let json = self.json();
if let Some(content) = json["data"]["content"].as_str() {
return Some(content.to_string());
}
let texts: Vec<_> = components_of(&json)
.into_iter()
.filter(|component| component["type"] == 10)
.filter_map(|component| component["content"].as_str().map(str::to_string))
.collect();
(!texts.is_empty()).then(|| texts.join("\n"))
}
fn is_ephemeral(&self) -> bool {
self.json()["data"]["flags"]
.as_u64()
.is_some_and(|flags| flags & 64 != 0)
}
fn components(&self) -> Vec<Value> {
components_of(&self.json())
}
fn button(&self, label: &str) -> Option<Value> {
self.components()
.into_iter()
.find(|component| component["label"] == label)
}
fn custom_id(&self, label: &str) -> Option<String> {
self.button(label)?["custom_id"]
.as_str()
.map(str::to_string)
}
fn embeds(&self) -> Vec<Value> {
array(&self.json()["data"]["embeds"])
}
fn choices(&self) -> Vec<Value> {
array(&self.json()["data"]["choices"])
}
}
impl ResponseExt for InteractionResponse {
fn json(&self) -> Value {
serde_json::to_value(self).expect("responses serialize")
}
}
impl ResponseExt for Value {
fn json(&self) -> Value {
self.clone()
}
}
fn array(value: &Value) -> Vec<Value> {
value.as_array().cloned().unwrap_or_default()
}
fn components_of(json: &Value) -> Vec<Value> {
fn walk(value: &Value, out: &mut Vec<Value>) {
match value {
Value::Object(map) => {
if map.get("type").is_some_and(Value::is_u64) {
out.push(value.clone());
}
map.values().for_each(|value| walk(value, out));
}
Value::Array(items) => items.iter().for_each(|value| walk(value, out)),
_ => {}
}
}
let mut out = Vec::new();
walk(&json["data"]["components"], &mut out);
out
}