31 """Asynchronously reads lines from a stream and prints them immediately."""
34 line = await stream.readline()
37 decoded_line = line.decode().rstrip()
39 if "*** COMMAND HAS COMPLETED ***" in decoded_line:
40 completion_event.set()
44 print(f
"[{process_name}] {line.decode().rstrip()}", flush=
True)
45 last_msg_time = time.time()
50 command_completion_event = asyncio.Event()
57 print(f
"*** Starting \"{cmd[0]}\" with local process name \"{name}\"...")
59 proc = await asyncio.create_subprocess_exec(
61 stdin=asyncio.subprocess.PIPE,
62 stdout=asyncio.subprocess.PIPE,
63 stderr=asyncio.subprocess.STDOUT
65 processes[name] = proc
68 tasks.append(asyncio.create_task(
read_stream(proc.stdout, name, command_completion_event)))
73 print(f
"*** Started {len(processes)} processes. Type: '<process_name>:<input>' (e.g., shell:help)")
74 print(
"*** Type 'exit' to quit everything.")
78 loop = asyncio.get_running_loop()
79 reader = asyncio.StreamReader()
80 protocol = asyncio.StreamReaderProtocol(reader)
81 await loop.connect_read_pipe(
lambda: protocol, sys.stdin)
85 print(
"\nmprc_drvr> ", end=
"", flush=
True)
86 user_line = await reader.readline()
90 command_text = user_line.decode().strip()
91 if command_text.lower() ==
'exit':
95 if ":" in command_text:
96 target, msg = command_text.split(
":", 1)
97 target = target.strip()
99 if target
in processes:
100 proc = processes[target]
101 if proc.returncode
is None:
102 cmd_start_time = time.time()
103 proc.stdin.write((msg +
"\n").encode())
104 await proc.stdin.drain()
105 print(f
"[System] Sent to {target}: {msg}")
106 if "drunc" in target:
107 proc.stdin.write((
"echo '*** COMMAND HAS COMPLETED ***'\n").encode())
108 await proc.stdin.drain()
109 print(f
"[System] Sent to {target}: echo '*** COMMAND HAS COMPLETED ***'")
110 await command_completion_event.wait()
111 command_completion_event.clear()
115 if last_msg_time <= cmd_start_time:
116 if now - cmd_start_time > 5:
119 if now - last_msg_time >= 5:
121 await asyncio.sleep(0.25)
124 print(f
"[System] Error: {target} has already exited.")
126 print(f
"[System] Error: Process '{target}' not found.")
128 print(
"[System] Invalid format. Use: <process_name>:<command>")
130 except asyncio.CancelledError:
134 print(
"\n[System] Shutting down processes...")
135 for name, proc
in reversed(processes.items()):
136 if proc.returncode
is None: