Skip to content
This repository was archived by the owner on Jul 8, 2026. It is now read-only.

Commit 92c8236

Browse files
committed
feat(cli): add run_cmd_and_stream function for command execution with output streaming
1 parent a78b620 commit 92c8236

1 file changed

Lines changed: 35 additions & 4 deletions

File tree

core/cli_api.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,38 @@ def run_cmd(command: list[str]) -> str:
121121
raise CommandExecutionError(f"OS error while trying to run command '{' '.join(command)}': {e}")
122122

123123

124+
def run_cmd_and_stream(command: list[str]):
125+
'''
126+
Runs a command, streams its combined stdout/stderr, and raises an exception on failure.
127+
'''
128+
if DEBUG:
129+
print(f"Executing command: {' '.join(command)}")
130+
try:
131+
process = subprocess.Popen(
132+
command,
133+
stdout=subprocess.PIPE,
134+
stderr=subprocess.STDOUT,
135+
text=True,
136+
bufsize=1,
137+
universal_newlines=True
138+
)
139+
140+
if process.stdout:
141+
for line in iter(process.stdout.readline, ''):
142+
print(line, end='')
143+
process.stdout.close()
144+
145+
return_code = process.wait()
146+
147+
if return_code != 0:
148+
raise CommandExecutionError(f"Process failed with exit code {return_code}")
149+
150+
except FileNotFoundError as e:
151+
raise ScriptNotFoundError(f"Script or command not found: {command[0]}. Original error: {e}")
152+
except OSError as e:
153+
raise CommandExecutionError(f"OS error while trying to run command '{' '.join(command)}': {e}")
154+
155+
124156
def generate_password() -> str:
125157
'''
126158
Generates a secure, random alphanumeric password.
@@ -138,11 +170,11 @@ def generate_password() -> str:
138170
# region Hysteria
139171

140172

141-
def install_hysteria2(port: int, sni: str) -> str:
173+
def install_hysteria2(port: int, sni: str):
142174
'''
143-
Installs Hysteria2 on the given port and uses the provided or default SNI value.
175+
Installs Hysteria2 and streams the output of the installation script.
144176
'''
145-
return run_cmd(['bash', Command.INSTALL_HYSTERIA2.value, str(port), sni])
177+
run_cmd_and_stream(['bash', Command.INSTALL_HYSTERIA2.value, str(port), sni])
146178

147179

148180
def uninstall_hysteria2():
@@ -388,7 +420,6 @@ def kick_users_by_name(usernames: list[str]):
388420
except subprocess.CalledProcessError as e:
389421
raise CommandExecutionError(f"Failed to execute kick user script: {e}")
390422

391-
# TODO: it's better to return json
392423
def show_user_uri(username: str, qrcode: bool, ipv: int, all: bool, singbox: bool, normalsub: bool) -> str | None:
393424
'''
394425
Displays the URI for a user, with options for QR code and other formats.

0 commit comments

Comments
 (0)