44import sys
55from pathlib import Path
66
7+ from rich import print
8+ from rich .console import Console
9+ from rich .table import Table
10+
711import click
812import inquirer
913import yaml
@@ -24,9 +28,7 @@ def graph():
2428
2529
2630def custom_graph (
27- num_nodes : int ,
28- num_connections : int ,
29- version : str ,
31+ tanks : list ,
3032 datadir : Path ,
3133 fork_observer : bool ,
3234 fork_obs_query_interval : int ,
@@ -43,30 +45,39 @@ def custom_graph(
4345 # Generate network.yaml
4446 nodes = []
4547 connections = set ()
48+ total_count = sum (int (entry ["count" ]) for entry in tanks )
49+ index = 0
4650
47- for i in range (num_nodes ):
48- node = {"name" : f"tank-{ i :04d} " , "addnode" : []}
49-
50- # Add round-robin connection
51- next_node = (i + 1 ) % num_nodes
52- node ["addnode" ].append (f"tank-{ next_node :04d} " )
53- connections .add ((i , next_node ))
54-
55- # Add random connections
56- available_nodes = list (range (num_nodes ))
57- available_nodes .remove (i )
58- if next_node in available_nodes :
59- available_nodes .remove (next_node )
60-
61- for _ in range (min (num_connections - 1 , len (available_nodes ))):
62- random_node = random .choice (available_nodes )
63- # Avoid circular loops of A -> B -> A
64- if (random_node , i ) not in connections :
65- node ["addnode" ].append (f"tank-{ random_node :04d} " )
66- connections .add ((i , random_node ))
67- available_nodes .remove (random_node )
68-
69- nodes .append (node )
51+ for entry in tanks :
52+ for i in range (int (entry ["count" ])):
53+ if ":" in entry ["version" ] and "/" in entry ["version" ]:
54+ repo , tag = entry ["version" ].split (":" )
55+ image = {"repository" : repo , "tag" : tag }
56+ else :
57+ image = {"tag" : entry ["version" ]}
58+ node = {"name" : f"tank-{ index :04d} " , "addnode" : [], "image" : image }
59+
60+ # Add round-robin connection
61+ next_node = (index + 1 ) % total_count
62+ node ["addnode" ].append (f"tank-{ next_node :04d} " )
63+ connections .add ((index , next_node ))
64+
65+ # Add random connections
66+ available_nodes = list (range (total_count ))
67+ available_nodes .remove (index )
68+ if next_node in available_nodes :
69+ available_nodes .remove (next_node )
70+
71+ for _ in range (min (int (entry ["connections" ]) - 1 , len (available_nodes ))):
72+ random_node = random .choice (available_nodes )
73+ # Avoid circular loops of A -> B -> A
74+ if (random_node , index ) not in connections :
75+ node ["addnode" ].append (f"tank-{ random_node :04d} " )
76+ connections .add ((index , random_node ))
77+ available_nodes .remove (random_node )
78+
79+ nodes .append (node )
80+ index += 1
7081
7182 network_yaml_data = {"nodes" : nodes }
7283 network_yaml_data ["fork_observer" ] = {
@@ -86,7 +97,6 @@ def custom_graph(
8697 "image" : {
8798 "repository" : DEFAULT_IMAGE_REPO ,
8899 "pullPolicy" : "IfNotPresent" ,
89- "tag" : version
90100 },
91101 "defaultConfig" :
92102 f"rpcauth={ FORK_OBSERVER_RPCAUTH } \n " +
@@ -108,73 +118,104 @@ def custom_graph(
108118
109119
110120def inquirer_create_network (project_path : Path ):
111- # Custom network configuration
112- questions = [
121+ network_name_prompt = inquirer .prompt ([
113122 inquirer .Text (
114123 "network_name" ,
115124 message = click .style ("Enter your network name" , fg = "blue" , bold = True ),
116125 validate = lambda _ , x : len (x ) > 0 ,
117- ),
118- inquirer .List (
119- "nodes" ,
120- message = click .style ("How many nodes would you like?" , fg = "blue" , bold = True ),
121- choices = ["8" , "12" , "20" , "50" , "other" ],
122- default = "12" ,
123- ),
124- inquirer .List (
125- "connections" ,
126- message = click .style (
127- "How many connections would you like each node to have?" ,
128- fg = "blue" ,
129- bold = True ,
130- ),
131- choices = ["0" , "1" , "2" , "8" , "12" , "other" ],
132- default = "8" ,
133- ),
134- inquirer .List (
135- "version" ,
136- message = click .style (
137- "Which version would you like nodes to run by default?" , fg = "blue" , bold = True
138- ),
139- choices = SUPPORTED_TAGS ,
140- default = DEFAULT_TAG ,
141- ),
142- ]
143-
144- net_answers = inquirer .prompt (questions )
145- if net_answers is None :
126+ )])
127+ if not network_name_prompt :
146128 click .secho ("Setup cancelled by user." , fg = "yellow" )
147129 return False
148130
149- if net_answers ["nodes" ] == "other" :
150- custom_nodes = inquirer .prompt (
151- [
152- inquirer .Text (
153- "nodes" ,
154- message = click .style ("Enter the number of nodes" , fg = "blue" , bold = True ),
155- validate = lambda _ , x : int (x ) > 0 ,
156- )
157- ]
158- )
159- if custom_nodes is None :
131+ tanks = []
132+ while True :
133+ table = Table (title = "Current Network Population" , show_header = True , header_style = "magenta" )
134+ table .add_column ("Version" , style = "cyan" )
135+ table .add_column ("Count" , style = "green" )
136+ table .add_column ("Connections" , style = "green" )
137+
138+ for entry in tanks :
139+ table .add_row (entry ["version" ], entry ["count" ], entry ["connections" ])
140+
141+ Console ().print (table )
142+
143+ add_more_prompt = inquirer .prompt ([
144+ inquirer .List (
145+ "add_more" ,
146+ message = click .style (f"How many nodes to add? (0 = done)" , fg = "blue" , bold = True ),
147+ choices = ["0" , "4" , "8" , "12" , "20" , "50" , "other" ],
148+ default = "12" )])
149+ if not add_more_prompt :
160150 click .secho ("Setup cancelled by user." , fg = "yellow" )
161151 return False
162- net_answers ["nodes" ] = custom_nodes ["nodes" ]
152+ if add_more_prompt ["add_more" ].startswith ("0" ):
153+ break
163154
164- if net_answers ["connections" ] == "other" :
165- custom_connections = inquirer .prompt (
166- [
155+ if add_more_prompt ["add_more" ] == "other" :
156+ how_many_prompt = inquirer .prompt ([
167157 inquirer .Text (
168- "connections" ,
169- message = click .style ("Enter the number of connections" , fg = "blue" , bold = True ),
170- validate = lambda _ , x : int (x ) >= 0 ,
171- )
172- ]
173- )
174- if custom_connections is None :
158+ "how_many" ,
159+ message = click .style ("Enter the number of nodes" , fg = "blue" , bold = True ),
160+ validate = lambda _ , x : int (x ) > 0 )])
161+ if not how_many_prompt :
162+ click .secho ("Setup cancelled by user." , fg = "yellow" )
163+ return False
164+ how_many = how_many_prompt ["how_many" ]
165+ else :
166+ how_many = add_more_prompt ["add_more" ]
167+
168+ tank_details_prompt = inquirer .prompt ([
169+ inquirer .List (
170+ "version" ,
171+ message = click .style ("Which version would you like to add to network?" , fg = "blue" , bold = True ),
172+ choices = ["other" ] + SUPPORTED_TAGS ,
173+ default = DEFAULT_TAG ,
174+ ),
175+ inquirer .List (
176+ "connections" ,
177+ message = click .style (
178+ "How many connections would you like each of these nodes to have?" ,
179+ fg = "blue" ,
180+ bold = True ,
181+ ),
182+ choices = ["0" , "1" , "2" , "8" , "12" , "other" ],
183+ default = "8" ,
184+ )])
185+ if not tank_details_prompt :
175186 click .secho ("Setup cancelled by user." , fg = "yellow" )
176187 return False
177- net_answers ["connections" ] = custom_connections ["connections" ]
188+ break
189+ if tank_details_prompt ["version" ] == "other" :
190+ custom_version_prompt = inquirer .prompt ([
191+ inquirer .Text (
192+ "version" ,
193+ message = click .style ("Provide dockerhub repository/image:tag" , fg = "blue" , bold = True ),
194+ validate = lambda _ , x : "/" in x and ":" in x )])
195+ if not custom_version_prompt :
196+ click .secho ("Setup cancelled by user." , fg = "yellow" )
197+ return False
198+ tank_details_prompt ["version" ] = custom_version_prompt ["version" ]
199+
200+ if tank_details_prompt ["connections" ] == "other" :
201+ how_many_conn_prompt = inquirer .prompt ([
202+ inquirer .Text (
203+ "how_many_conn" ,
204+ message = click .style ("Enter the number of connections" , fg = "blue" , bold = True ),
205+ validate = lambda _ , x : int (x ) > 0 )])
206+ if not how_many_conn_prompt :
207+ click .secho ("Setup cancelled by user." , fg = "yellow" )
208+ return False
209+ how_many_conn = how_many_conn_prompt ["how_many_conn" ]
210+ else :
211+ how_many_conn = tank_details_prompt ["connections" ]
212+
213+ tanks .append ({
214+ "version" : tank_details_prompt ["version" ],
215+ "count" : how_many ,
216+ "connections" : how_many_conn
217+ })
218+
178219 fork_observer = click .prompt (
179220 click .style (
180221 "\n Would you like to enable fork-observer on the network?" , fg = "blue" , bold = True
@@ -202,12 +243,10 @@ def inquirer_create_network(project_path: Path):
202243 default = False ,
203244 )
204245 caddy = fork_observer | logging
205- custom_network_path = project_path / "networks" / net_answers ["network_name" ]
246+ custom_network_path = project_path / "networks" / network_name_prompt ["network_name" ]
206247 click .secho ("\n Generating custom network..." , fg = "yellow" , bold = True )
207248 custom_graph (
208- int (net_answers ["nodes" ]),
209- int (net_answers ["connections" ]),
210- net_answers ["version" ],
249+ tanks ,
211250 custom_network_path ,
212251 fork_observer ,
213252 fork_observer_query_interval ,
0 commit comments