feat(cli): add run_cmd_and_stream function for command execution with output streaming
This commit is contained in:
@ -121,6 +121,38 @@ def run_cmd(command: list[str]) -> str:
|
|||||||
raise CommandExecutionError(f"OS error while trying to run command '{' '.join(command)}': {e}")
|
raise CommandExecutionError(f"OS error while trying to run command '{' '.join(command)}': {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def run_cmd_and_stream(command: list[str]):
|
||||||
|
'''
|
||||||
|
Runs a command, streams its combined stdout/stderr, and raises an exception on failure.
|
||||||
|
'''
|
||||||
|
if DEBUG:
|
||||||
|
print(f"Executing command: {' '.join(command)}")
|
||||||
|
try:
|
||||||
|
process = subprocess.Popen(
|
||||||
|
command,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
text=True,
|
||||||
|
bufsize=1,
|
||||||
|
universal_newlines=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if process.stdout:
|
||||||
|
for line in iter(process.stdout.readline, ''):
|
||||||
|
print(line, end='')
|
||||||
|
process.stdout.close()
|
||||||
|
|
||||||
|
return_code = process.wait()
|
||||||
|
|
||||||
|
if return_code != 0:
|
||||||
|
raise CommandExecutionError(f"Process failed with exit code {return_code}")
|
||||||
|
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
raise ScriptNotFoundError(f"Script or command not found: {command[0]}. Original error: {e}")
|
||||||
|
except OSError as e:
|
||||||
|
raise CommandExecutionError(f"OS error while trying to run command '{' '.join(command)}': {e}")
|
||||||
|
|
||||||
|
|
||||||
def generate_password() -> str:
|
def generate_password() -> str:
|
||||||
'''
|
'''
|
||||||
Generates a secure, random alphanumeric password.
|
Generates a secure, random alphanumeric password.
|
||||||
@ -138,11 +170,11 @@ def generate_password() -> str:
|
|||||||
# region Hysteria
|
# region Hysteria
|
||||||
|
|
||||||
|
|
||||||
def install_hysteria2(port: int, sni: str) -> str:
|
def install_hysteria2(port: int, sni: str):
|
||||||
'''
|
'''
|
||||||
Installs Hysteria2 on the given port and uses the provided or default SNI value.
|
Installs Hysteria2 and streams the output of the installation script.
|
||||||
'''
|
'''
|
||||||
return run_cmd(['bash', Command.INSTALL_HYSTERIA2.value, str(port), sni])
|
run_cmd_and_stream(['bash', Command.INSTALL_HYSTERIA2.value, str(port), sni])
|
||||||
|
|
||||||
|
|
||||||
def uninstall_hysteria2():
|
def uninstall_hysteria2():
|
||||||
@ -388,7 +420,6 @@ def kick_users_by_name(usernames: list[str]):
|
|||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
raise CommandExecutionError(f"Failed to execute kick user script: {e}")
|
raise CommandExecutionError(f"Failed to execute kick user script: {e}")
|
||||||
|
|
||||||
# TODO: it's better to return json
|
|
||||||
def show_user_uri(username: str, qrcode: bool, ipv: int, all: bool, singbox: bool, normalsub: bool) -> str | None:
|
def show_user_uri(username: str, qrcode: bool, ipv: int, all: bool, singbox: bool, normalsub: bool) -> str | None:
|
||||||
'''
|
'''
|
||||||
Displays the URI for a user, with options for QR code and other formats.
|
Displays the URI for a user, with options for QR code and other formats.
|
||||||
|
|||||||
Reference in New Issue
Block a user