47async def interactive_manager(commands):
48 processes = {}
49 tasks = []
50 command_completion_event = asyncio.Event()
51 global last_msg_time
52
53
54 for cmd in commands:
55 name = cmd.pop(0)
56 print()
57 print(f"*** Starting \"{cmd[0]}\" with local process name \"{name}\"...")
58 print()
59 proc = await asyncio.create_subprocess_exec(
60 *cmd,
61 stdin=asyncio.subprocess.PIPE,
62 stdout=asyncio.subprocess.PIPE,
63 stderr=asyncio.subprocess.STDOUT
64 )
65 processes[name] = proc
66
67
68 tasks.append(asyncio.create_task(read_stream(proc.stdout, name, command_completion_event)))
69
70 time.sleep(2)
71
72 print()
73 print(f"*** Started {len(processes)} processes. Type: '<process_name>:<input>' (e.g., shell:help)")
74 print("*** Type 'exit' to quit everything.")
75 print()
76
77
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)
82
83 try:
84 while True:
85 print("\nmprc_drvr> ", end="", flush=True)
86 user_line = await reader.readline()
87 if not user_line:
88 break
89
90 command_text = user_line.decode().strip()
91 if command_text.lower() == 'exit':
92 break
93
94
95 if ":" in command_text:
96 target, msg = command_text.split(":", 1)
97 target = target.strip()
98
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()
112 else:
113 now = time.time()
114 while True:
115 if last_msg_time <= cmd_start_time:
116 if now - cmd_start_time > 5:
117 break
118 else:
119 if now - last_msg_time >= 5:
120 break
121 await asyncio.sleep(0.25)
122 now = time.time()
123 else:
124 print(f"[System] Error: {target} has already exited.")
125 else:
126 print(f"[System] Error: Process '{target}' not found.")
127 else:
128 print("[System] Invalid format. Use: <process_name>:<command>")
129
130 except asyncio.CancelledError:
131 pass
132 finally:
133
134 print("\n[System] Shutting down processes...")
135 for name, proc in reversed(processes.items()):
136 if proc.returncode is None:
137 proc.terminate()
138 await proc.wait()
139
140
141 for task in tasks:
142 task.cancel()
143