84 lines
3.3 KiB
Python
84 lines
3.3 KiB
Python
import subprocess
|
|
import os
|
|
import time
|
|
|
|
|
|
class Server():
|
|
def __init__(self, first_server_p, first_monitor_p, n_servers, no_render=True, no_realtime=True) -> None:
|
|
try:
|
|
import psutil
|
|
self.check_running_servers(psutil, first_server_p, first_monitor_p, n_servers)
|
|
except ModuleNotFoundError:
|
|
print("Info: Cannot check if the server is already running, because the psutil module was not found")
|
|
|
|
self.first_server_p = first_server_p
|
|
self.n_servers = n_servers
|
|
self.rcss_processes = []
|
|
first_monitor_p = first_monitor_p + 100
|
|
|
|
# makes it easier to kill test servers without affecting train servers
|
|
cmd = "rcssservermj"
|
|
render_arg = "--no-render" if no_render else ""
|
|
realtime_arg = "--no-realtime" if no_realtime else ""
|
|
for i in range(n_servers):
|
|
port = first_server_p + i
|
|
mport = first_monitor_p + i
|
|
|
|
server_cmd = f"{cmd} -c {port} -m {mport} {render_arg} {realtime_arg}".strip()
|
|
|
|
proc = subprocess.Popen(
|
|
server_cmd.split(),
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.STDOUT,
|
|
start_new_session=True
|
|
)
|
|
|
|
# Avoid startup storm when launching many servers at once.
|
|
time.sleep(0.03)
|
|
|
|
rc = proc.poll()
|
|
if rc is not None:
|
|
raise RuntimeError(
|
|
f"rcssservermj exited early (code={rc}) on server port {port}, monitor port {mport}"
|
|
)
|
|
|
|
self.rcss_processes.append(proc)
|
|
|
|
def check_running_servers(self, psutil, first_server_p, first_monitor_p, n_servers):
|
|
''' Check if any server is running on chosen ports '''
|
|
found = False
|
|
p_list = [p for p in psutil.process_iter() if p.cmdline() and "rcssservermj" in " ".join(p.cmdline())]
|
|
range1 = (first_server_p, first_server_p + n_servers)
|
|
range2 = (first_monitor_p, first_monitor_p + n_servers)
|
|
bad_processes = []
|
|
|
|
for p in p_list:
|
|
# currently ignoring remaining default port when only one of the ports is specified (uncommon scenario)
|
|
ports = [int(arg) for arg in p.cmdline()[1:] if arg.isdigit()]
|
|
if len(ports) == 0:
|
|
ports = [60000, 60100] # default server ports (changing this is unlikely)
|
|
|
|
conflicts = [str(port) for port in ports if (
|
|
(range1[0] <= port < range1[1]) or (range2[0] <= port < range2[1]))]
|
|
|
|
if len(conflicts) > 0:
|
|
if not found:
|
|
print("\nThere are already servers running on the same port(s)!")
|
|
found = True
|
|
bad_processes.append(p)
|
|
print(f"Port(s) {','.join(conflicts)} already in use by \"{' '.join(p.cmdline())}\" (PID:{p.pid})")
|
|
|
|
if found:
|
|
print()
|
|
while True:
|
|
inp = input("Enter 'kill' to kill these processes or ctrl+c to abort. ")
|
|
if inp == "kill":
|
|
for p in bad_processes:
|
|
p.kill()
|
|
return
|
|
|
|
def kill(self):
|
|
for p in self.rcss_processes:
|
|
p.kill()
|
|
print(f"Killed {self.n_servers} rcssservermj processes starting at {self.first_server_p}")
|