use async_trait::async_trait;
use schemars::{Schema, schema_for, JsonSchema};
use ::serde::{Deserialize, Serialize};
use tracing::info;
use crate::{message::Message, node::{NodeContext, NodeErr, NodeOut, NodeType, Routing}};
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq,)]
#[serde(rename = "debug")]
pub struct DebugProcessNode{
#[serde(default = "DebugProcessNode::default_print", skip_serializing_if = "std::ops::Not::not")]
pub print: bool,
}
impl DebugProcessNode {
fn default_print() -> bool { false }
}
impl Default for DebugProcessNode {
fn default() -> Self {
DebugProcessNode { print: false}
}
}
#[async_trait]
#[typetag::serde]
impl NodeType for DebugProcessNode {
fn type_name(&self) -> String {
"debug".to_string()
}
fn schema(&self) -> Schema {
schema_for!(DebugProcessNode)
}
#[tracing::instrument(name = "debug_node_process", skip(self, context))]
async fn process(
&self,
input: Message,
context: &mut NodeContext,
) -> Result<NodeOut, NodeErr> {
if self.print {
println!("**** DEBUG ****: Got message {:?}, context {:?}", input, context.get_all_state());
}
info!("**** DEBUGGER ****: Got message {:?}, context {:?}", input, context.get_all_state());
Ok(NodeOut::with_routing(input, Routing::FollowGraph))
}
fn clone_box(&self) -> Box<dyn NodeType> {
Box::new(self.clone())
}
}
#[cfg(test)]
mod debug_tests {
use super::*;
use dashmap::DashMap;
use serde_json::json;
use schemars::schema_for;
use crate::executor::Executor;
use crate::channel::manager::ChannelManager;
use crate::flow::manager::NodeKind;
use crate::flow::state::InMemoryState;
use crate::node::Routing;
use crate::process::manager::{BuiltInProcess, ProcessManager};
use crate::secret::{EmptySecretsManager, SecretsManager};
#[tokio::test]
async fn serde_roundtrip_json_and_yaml() {
let node = DebugProcessNode{print:true};
let j = serde_json::to_string(&node).expect("serialize to JSON");
let node2: DebugProcessNode = serde_json::from_str(&j).expect("deserialize JSON");
assert_eq!(node, node2);
let y = serde_yaml_bw::to_string(&node).expect("serialize to YAML");
let node3: DebugProcessNode = serde_yaml_bw::from_str(&y).expect("deserialize YAML");
assert_eq!(node, node3);
let schema = schema_for!(DebugProcessNode);
let obj = schema.as_object().expect("Expected schema to be an object");
let title = obj.get("title")
.and_then(|v| v.as_str())
.expect("Expected 'title' to be a string");
assert_eq!(title,"debug");
}
#[test]
fn type_name_is_debug() {
let node = DebugProcessNode{print:true};
assert_eq!(node.type_name(), "debug");
}
#[tokio::test]
async fn process_echoes_message_and_no_connections() {
let original = Message::new(
"msg1",
json!({ "foo": "bar", "n": 42 }),
"sess-123".to_string(),
);
let mut ctx = NodeContext::new(
"123".to_string(),
InMemoryState::new(),
DashMap::new(),
Executor::dummy(),
ChannelManager::dummy(),
ProcessManager::dummy(),
SecretsManager(EmptySecretsManager::new()),
None,
);
let node = DebugProcessNode{print:true};
let out = node.process(original.clone(), &mut ctx)
.await
.expect("process should succeed");
let msgs = out.message(); let routing = out.routing();
assert_eq!(msgs, original);
assert_eq!(routing, &Routing::FollowGraph);
}
#[test]
fn debug_node_yaml_example() {
let kind = NodeKind::Process {
process: BuiltInProcess::Debug(DebugProcessNode{print: true}),
};
let yaml = serde_yaml_bw::to_string(&kind).unwrap();
println!("\n>> debug‐node YAML:\n{}", yaml);
}
}