66 $ discos-simulator start -s if_distributor
77 $ discos-simulator stop -s if_distributor
88"""
9- from __future__ import print_function
109import importlib
1110import subprocess
1211import sys
13- import time
14- import socket
12+ import re
13+ import os
1514from argparse import ArgumentParser , ArgumentTypeError
15+ from concurrent .futures import ThreadPoolExecutor
1616
1717from simulators .server import Simulator
1818from simulators .utils import list_simulators
1919
2020AVAILABLE_SIMULATORS = list_simulators ()
21+ PATTERN = re .compile (
22+ r"discos-simulator\s+(?:-s\s+(\S+)\s+start|start\s+-s\s+(\S+))"
23+ )
24+
25+
26+ def running_simulators ():
27+ current_pid = os .getpid ()
28+ out = subprocess .check_output (["ps" , "aux" ], text = True )
29+ result = set ()
30+ for line in out .splitlines ():
31+ parts = line .split (None , 2 )
32+ if len (parts ) < 3 :
33+ continue
34+ try :
35+ pid = int (parts [1 ])
36+ except ValueError :
37+ continue
38+ if pid == current_pid :
39+ continue
40+ m = PATTERN .search (line )
41+ if m :
42+ n = m .group (1 ) or m .group (2 )
43+ result .add (n )
44+ return sorted (result )
45+
46+
47+ def wait_until_started (process ):
48+ for line in process .stdout :
49+ sys .stdout .write (line )
50+ sys .stdout .flush ()
51+ if "running" in line :
52+ return
2153
2254
2355def system_from_arg (system_name ):
@@ -35,7 +67,7 @@ def system_from_arg(system_name):
3567parser = ArgumentParser ()
3668parser .add_argument (
3769 "action" ,
38- choices = ["start" , "stop" , "list" ]
70+ choices = ["start" , "stop" , "status" , " list" ]
3971)
4072parser .add_argument (
4173 "-s" , "--system" ,
@@ -49,62 +81,106 @@ parser.add_argument(
4981 required = False ,
5082 help = "System configuration type: IFD_14_channels for if_distributor, ..." ,
5183)
52- args = parser .parse_args ()
5384
54- if args .action == "list" :
55- print (
56- "Available simulators: '"
57- + "', '" .join (AVAILABLE_SIMULATORS )
58- + "'."
59- )
85+ if __name__ == "__main__" :
86+ kwargs = {}
6087
61- kwargs = {}
62-
63- if args .type :
64- name = args .system .__name__ .rsplit ("." , 1 )[1 ]
65- if not args .system :
66- parser .error (
67- "The '--type' argument only has to be used "
68- + "in conjunction with the '--system' argument."
69- )
70- try :
71- systems = getattr (args .system , "systems" )
72- except AttributeError :
73- parser .error (
74- f"System '{ name } ' has no configurations other than the default one"
75- + ". Omit the '--type' argument to start the simulator properly."
76- )
77- if args .type not in systems :
78- err_string = (
79- f"Configuration '{ args .type } ' for system '{ name } ' not found.\n "
80- )
81- err_string += "Available configurations for desired simulator:\n "
82- err_string += "'" + "', " .join (systems ) + "'."
83- parser .error (err_string )
84- kwargs ["system_type" ] = args .type
88+ args = parser .parse_args ()
8589
86- if args .action == "start" :
87- if args .system :
90+ if args .type :
91+ sim = args .system .__name__ .rsplit ("." , 1 )[1 ]
92+ if not args .system :
93+ parser .error (
94+ "The '--type' argument only has to be used "
95+ + "in conjunction with the '--system' argument."
96+ )
8897 try :
89- simulator = Simulator (args .system , ** kwargs )
90- simulator .start ()
91- except socket .error :
92- name = args .system .__name__ .rsplit ("." , 1 )[1 ]
98+ systems = getattr (args .system , "systems" )
99+ except AttributeError :
100+ parser .error (
101+ f"System '{ sim } ' has no configurations other than the default "
102+ + "one. Omit the '--type' argument to start the simulator "
103+ + "properly."
104+ )
105+ if args .type not in systems :
106+ err_string = (
107+ f"Configuration '{ args .type } ' for system '{ sim } ' not found.\n "
108+ )
109+ err_string += "Available configurations for desired simulator:\n "
110+ err_string += "'" + "', " .join (systems ) + "'."
111+ parser .error (err_string )
112+ kwargs ["system_type" ] = args .type
113+
114+ if args .action == "list" :
115+ print (
116+ "Available simulators: '"
117+ + "', '" .join (AVAILABLE_SIMULATORS )
118+ + "'."
119+ )
120+ running = running_simulators ()
121+ if running :
93122 print (
94- f"Cannot start simulator '{ name } ', address already in use."
123+ "Running simulators: '"
124+ + "', '" .join (running )
125+ + "'."
95126 )
96- sys .exit (1 )
97- else :
98- for sim in AVAILABLE_SIMULATORS :
99- # pylint: disable=consider-using-with
100- subprocess .Popen ([sys .argv [0 ], "start" , "-s" , sim ])
101- time .sleep (3 )
102- elif args .action == "stop" :
103- if args .system :
104- simulator = Simulator (args .system , ** kwargs )
105- simulator .stop ()
106- else :
107- for sim in AVAILABLE_SIMULATORS :
108- sim = importlib .import_module (f"simulators.{ sim } " )
109- simulator = Simulator (sim , ** kwargs )
110- simulator .stop ()
127+ if args .action == "status" :
128+ running = running_simulators ()
129+ if running :
130+ print (
131+ "Running simulators: '"
132+ + "', '" .join (running )
133+ + "'."
134+ )
135+ else :
136+ print ("No simulator is running." )
137+ elif args .action == "start" :
138+ running = running_simulators ()
139+ if args .system :
140+ sim = args .system .__name__ .split ('.' )[- 1 ]
141+ if sim not in running :
142+ simulator = Simulator (args .system , ** kwargs )
143+ simulator .start ()
144+ else :
145+ print (f"Simulator '{ sim } ' already running." )
146+ else :
147+ processes = []
148+ for sim in AVAILABLE_SIMULATORS :
149+ if sim in running :
150+ print (f"Simulator '{ sim } ' already running." )
151+ continue
152+ command = \
153+ [sys .executable , "-u" , sys .argv [0 ], "-s" , sim , "start" ]
154+ # pylint: disable=consider-using-with
155+ p = subprocess .Popen (
156+ command ,
157+ stdout = subprocess .PIPE ,
158+ stderr = subprocess .PIPE ,
159+ text = True ,
160+ bufsize = 1
161+ )
162+ processes .append (p )
163+ if processes :
164+ futures = []
165+ executor = ThreadPoolExecutor (max_workers = len (processes ))
166+ for proc in processes :
167+ fut = executor .submit (wait_until_started , proc )
168+ futures .append (fut )
169+ executor .shutdown (wait = True )
170+ elif args .action == "stop" :
171+ running = running_simulators ()
172+ if args .system :
173+ name = args .system .__name__ .split ('.' )[- 1 ]
174+ if name not in running :
175+ print (f"Simulator '{ name } ' is not running." )
176+ else :
177+ simulator = Simulator (args .system , ** kwargs )
178+ simulator .stop ()
179+ else :
180+ for name in AVAILABLE_SIMULATORS :
181+ if name not in running :
182+ print (f"Simulator '{ name } ' is not running." )
183+ else :
184+ sim = importlib .import_module (f"simulators.{ name } " )
185+ simulator = Simulator (sim , ** kwargs )
186+ simulator .stop ()
0 commit comments