@@ -4,14 +4,16 @@ use std::sync::Arc;
44
55use crate :: api:: NodeType ;
66use crate :: process:: { ProcessManager , NodeConfig } ;
7+ use crate :: setup:: { SetupManager , NodeEndpoint } ;
78
89pub struct DeploymentManager {
910 process : Arc < ProcessManager > ,
11+ setup : Arc < SetupManager > ,
1012}
1113
1214impl DeploymentManager {
13- pub fn new ( process : Arc < ProcessManager > ) -> Self {
14- Self { process }
15+ pub fn new ( process : Arc < ProcessManager > , setup : Arc < SetupManager > ) -> Self {
16+ Self { process, setup }
1517 }
1618
1719 pub async fn deploy_nodes ( & self , deployment_id : & str , node_type : NodeType , count : usize ) {
@@ -22,29 +24,91 @@ impl DeploymentManager {
2224 node_type
2325 ) ;
2426
25- let base_port = match node_type {
26- NodeType :: Validator => 9000 ,
27- NodeType :: Miner => 9100 ,
28- NodeType :: FullNode => 9200 ,
27+ // Find the highest used port to avoid conflicts
28+ // Using higher ports (19000+) to avoid conflicts with system services
29+ let mut base_port = match node_type {
30+ NodeType :: Validator => 19000 ,
31+ NodeType :: Miner => 19100 ,
32+ NodeType :: FullNode => 19200 ,
2933 } ;
34+
35+ // Check existing nodes in process manager
36+ let existing_nodes = self . process . list_nodes ( ) ;
37+ for node in & existing_nodes {
38+ if node. port >= base_port {
39+ // We use port (P2P) and port+1 (Metrics), so next available is port+2
40+ base_port = std:: cmp:: max ( base_port, node. port + 2 ) ;
41+ }
42+ }
43+
44+ // Check existing nodes in setup manager
45+ let setup_nodes = self . setup . get_nodes ( ) ;
46+ for node in & setup_nodes {
47+ // Parse port from metrics endpoint if possible, or just skip
48+ // This is a heuristic
49+ if let Some ( port_str) = node. metrics_endpoint . split ( ':' ) . last ( ) {
50+ if let Some ( port_part) = port_str. split ( '/' ) . next ( ) {
51+ if let Ok ( metrics_port) = port_part. parse :: < u16 > ( ) {
52+ // metrics_port is port + 1, so P2P port is metrics_port - 1
53+ let p2p_port = metrics_port. saturating_sub ( 1 ) ;
54+ if p2p_port >= base_port {
55+ base_port = std:: cmp:: max ( base_port, p2p_port + 2 ) ;
56+ }
57+ }
58+ }
59+ }
60+ }
3061
3162 let base_rpc_port = base_port + 1000 ;
3263
3364 for i in 0 ..count {
3465 let node_id = format ! ( "{:?}-{}-{}" , node_type, deployment_id, i) ;
66+ // Increment by 2 to allow space for metrics port (port + 1)
67+ let port = base_port + ( i * 2 ) as u16 ;
68+ let rpc_port = base_rpc_port + i as u16 ;
69+
3570 let config = NodeConfig {
3671 node_type,
3772 data_dir : format ! ( "/tmp/bitcell/{}" , node_id) ,
38- port : base_port + i as u16 ,
39- rpc_port : base_rpc_port + i as u16 ,
73+ port,
74+ rpc_port,
4075 log_level : "info" . to_string ( ) ,
4176 network : "testnet" . to_string ( ) ,
4277 } ;
4378
4479 // Register the node (but don't start it automatically)
80+ // Note: The UI calls start_node separately, or we could start it here.
81+ // But wait, the UI "Deploy" button calls deploy_node, which spawns this task.
82+ // The UI then refreshes the list. It doesn't automatically start them?
83+ // The screenshot shows them as "Running".
84+ // Let's check process.rs start_node again.
85+ // Ah, register_node returns NodeStatus::Stopped.
86+ // So the user must have clicked Start.
87+ // But wait, if I register them in SetupManager, they appear in the list.
88+
4589 self . process . register_node ( node_id. clone ( ) , config) ;
90+
91+ // Register in SetupManager so metrics can be fetched
92+ let endpoint = NodeEndpoint {
93+ id : node_id. clone ( ) ,
94+ node_type : format ! ( "{:?}" , node_type) . to_lowercase ( ) ,
95+ metrics_endpoint : format ! ( "http://127.0.0.1:{}/metrics" , port + 1 ) ,
96+ rpc_endpoint : format ! ( "http://127.0.0.1:{}" , rpc_port) ,
97+ } ;
98+ self . setup . add_node ( endpoint) ;
4699
47100 tracing:: info!( "Registered node '{}' in deployment {}" , node_id, deployment_id) ;
101+
102+ // Auto-start the node for convenience
103+ if let Err ( e) = self . process . start_node ( & node_id) {
104+ tracing:: error!( "Failed to auto-start node {}: {}" , node_id, e) ;
105+ }
106+ }
107+
108+ // Save setup state
109+ let setup_path = std:: path:: PathBuf :: from ( crate :: setup:: SETUP_FILE_PATH ) ;
110+ if let Err ( e) = self . setup . save_to_file ( & setup_path) {
111+ tracing:: error!( "Failed to save setup state: {}" , e) ;
48112 }
49113
50114 tracing:: info!(
0 commit comments