mockforge_core/graph/
relationships.rs1use crate::graph::{EdgeType, GraphEdge};
7use crate::request_chaining::{ChainDefinition, ChainLink};
8use std::collections::HashMap;
9
10pub fn discover_chain_relationships(chains: &[ChainDefinition]) -> Vec<GraphEdge> {
12 let mut edges = Vec::new();
13
14 for chain in chains {
15 for link in &chain.links {
16 let link_node_id = format!("chain_link:{}:{}", chain.id, link.request.id);
17
18 for dep_id in &link.request.depends_on {
20 let dep_node_id = format!("chain_link:{}:{}", chain.id, dep_id);
21 edges.push(GraphEdge {
22 from: dep_node_id,
23 to: link_node_id.clone(),
24 edge_type: EdgeType::Dependency,
25 label: Some("depends on".to_string()),
26 metadata: HashMap::new(),
27 });
28 }
29
30 if let Some(service_call) = discover_service_call_from_url(&link.request.url) {
32 edges.push(service_call);
33 }
34 }
35 }
36
37 edges
38}
39
40fn discover_service_call_from_url(url: &str) -> Option<GraphEdge> {
42 if url.contains("://") {
46 None
49 } else {
50 None
51 }
52}
53
54pub fn discover_state_transitions(
56 state_machines: &[crate::intelligent_behavior::rules::StateMachine],
57) -> Vec<GraphEdge> {
58 use serde_json;
59 let mut edges = Vec::new();
60
61 for state_machine in state_machines {
62 for transition in &state_machine.transitions {
63 let from_node_id =
68 format!("state:{}:{}", state_machine.resource_type, transition.from_state);
69 let to_node_id =
70 format!("state:{}:{}", state_machine.resource_type, transition.to_state);
71
72 edges.push(GraphEdge {
73 from: from_node_id,
74 to: to_node_id,
75 edge_type: EdgeType::StateTransition,
76 label: Some(format!("{} → {}", transition.from_state, transition.to_state)),
77 metadata: {
78 let mut meta = HashMap::new();
79 meta.insert(
80 "resource_type".to_string(),
81 serde_json::Value::String(state_machine.resource_type.clone()),
82 );
83 meta.insert(
84 "probability".to_string(),
85 serde_json::Value::Number(
86 serde_json::Number::from_f64(transition.probability)
87 .unwrap_or_else(|| serde_json::Number::from(0)),
88 ),
89 );
90 meta
91 },
92 });
93 }
94 }
95
96 edges
97}
98
99pub fn extract_endpoint_ids_from_chain(chain: &ChainDefinition) -> Vec<String> {
101 chain.links.iter().map(|link| link.request.id.clone()).collect()
102}
103
104pub fn group_endpoints_by_service(
106 endpoints: &[(String, String)], ) -> HashMap<String, Vec<String>> {
108 let mut service_groups: HashMap<String, Vec<String>> = HashMap::new();
109
110 for (endpoint_id, url) in endpoints {
111 let service_name = extract_service_name_from_url(url);
114 service_groups
115 .entry(service_name)
116 .or_insert_with(Vec::new)
117 .push(endpoint_id.clone());
118 }
119
120 service_groups
121}
122
123fn extract_service_name_from_url(url: &str) -> String {
125 if let Some(domain) = url.split("://").nth(1) {
127 if let Some(host) = domain.split('/').next() {
128 return host.split('.').next().unwrap_or("default").to_string();
129 }
130 }
131
132 if let Some(first_segment) = url.split('/').nth(1) {
134 return first_segment.to_string();
135 }
136
137 "default".to_string()
138}