The 'cmd' module is introduced to make the CLI easy to use. (#10542)

…pdate comand

### What problem does this PR solve?

To make the CLI easy to use.

### Type of change

- [x] New Feature (non-breaking change which adds functionality)

---------

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
This commit is contained in:
Jin Hai
2025-10-14 14:53:00 +08:00
committed by GitHub
parent f92a45dcc4
commit 5b387b68ba
2 changed files with 51 additions and 20 deletions

View File

@ -16,14 +16,14 @@
import argparse import argparse
import base64 import base64
from cmd import Cmd
from Cryptodome.PublicKey import RSA from Cryptodome.PublicKey import RSA
from Cryptodome.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5 from Cryptodome.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from typing import Dict, List, Any from typing import Dict, List, Any
from lark import Lark, Transformer, Tree from lark import Lark, Transformer, Tree, Token
import requests import requests
from requests.auth import HTTPBasicAuth from requests.auth import HTTPBasicAuth
from api.common.base64 import encode_to_base64
GRAMMAR = r""" GRAMMAR = r"""
start: command start: command
@ -100,7 +100,6 @@ NUMBER: /[0-9]+/
%ignore WS %ignore WS
""" """
class AdminTransformer(Transformer): class AdminTransformer(Transformer):
def start(self, items): def start(self, items):
@ -183,7 +182,6 @@ class AdminTransformer(Transformer):
def meta_args(self, items): def meta_args(self, items):
return items return items
def encrypt(input_string): def encrypt(input_string):
pub = '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB\n-----END PUBLIC KEY-----' pub = '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB\n-----END PUBLIC KEY-----'
pub_key = RSA.importKey(pub) pub_key = RSA.importKey(pub)
@ -191,13 +189,50 @@ def encrypt(input_string):
cipher_text = cipher.encrypt(base64.b64encode(input_string.encode('utf-8'))) cipher_text = cipher.encrypt(base64.b64encode(input_string.encode('utf-8')))
return base64.b64encode(cipher_text).decode("utf-8") return base64.b64encode(cipher_text).decode("utf-8")
def encode_to_base64(input_string):
base64_encoded = base64.b64encode(input_string.encode('utf-8'))
return base64_encoded.decode('utf-8')
class AdminCommandParser: class AdminCLI(Cmd):
def __init__(self): def __init__(self):
super().__init__()
self.parser = Lark(GRAMMAR, start='start', parser='lalr', transformer=AdminTransformer()) self.parser = Lark(GRAMMAR, start='start', parser='lalr', transformer=AdminTransformer())
self.command_history = [] self.command_history = []
self.is_interactive = False
self.admin_account = "admin@ragflow.io"
self.admin_password: str = "admin"
self.host: str = ""
self.port: int = 0
def parse_command(self, command_str: str) -> Dict[str, Any]: intro = r"""Type "\h" for help."""
prompt = "admin> "
def onecmd(self, command: str) -> bool:
try:
print(f"command: {command}")
result = self.parse_command(command)
self.execute_command(result)
if isinstance(result, Tree):
return False
if result.get('type') == 'meta' and result.get('command') in ['q', 'quit', 'exit']:
return True
except KeyboardInterrupt:
print("\nUse '\\q' to quit")
except EOFError:
print("\nGoodbye!")
return True
return False
def emptyline(self) -> bool:
return False
def default(self, line: str) -> bool:
return self.onecmd(line)
def parse_command(self, command_str: str) -> dict[str, str] | Tree[Token]:
if not command_str.strip(): if not command_str.strip():
return {'type': 'empty'} return {'type': 'empty'}
@ -209,16 +244,6 @@ class AdminCommandParser:
except Exception as e: except Exception as e:
return {'type': 'error', 'message': f'Parse error: {str(e)}'} return {'type': 'error', 'message': f'Parse error: {str(e)}'}
class AdminCLI:
def __init__(self):
self.parser = AdminCommandParser()
self.is_interactive = False
self.admin_account = "admin@ragflow.io"
self.admin_password: str = "admin"
self.host: str = ""
self.port: int = 0
def verify_admin(self, args): def verify_admin(self, args):
conn_info = self._parse_connection_args(args) conn_info = self._parse_connection_args(args)
@ -323,7 +348,7 @@ class AdminCLI:
continue continue
print(f"command: {command}") print(f"command: {command}")
result = self.parser.parse_command(command) result = self.parse_command(command)
self.execute_command(result) self.execute_command(result)
if isinstance(result, Tree): if isinstance(result, Tree):
@ -610,10 +635,17 @@ def main():
/_/ |_/_/ |_\____/_/ /_/\____/|__/|__/ /_/ |_\__,_/_/ /_/ /_/_/_/ /_/ /_/ |_/_/ |_\____/_/ /_/\____/|__/|__/ /_/ |_\__,_/_/ /_/ /_/_/_/ /_/
""") """)
if cli.verify_admin(sys.argv): if cli.verify_admin(sys.argv):
cli.run_interactive() cli.cmdloop()
else: else:
print(r"""
____ ___ ______________ ___ __ _
/ __ \/ | / ____/ ____/ /___ _ __ / | ____/ /___ ___ (_)___
/ /_/ / /| |/ / __/ /_ / / __ \ | /| / / / /| |/ __ / __ `__ \/ / __ \
/ _, _/ ___ / /_/ / __/ / / /_/ / |/ |/ / / ___ / /_/ / / / / / / / / / /
/_/ |_/_/ |_\____/_/ /_/\____/|__/|__/ /_/ |_\__,_/_/ /_/ /_/_/_/ /_/
""")
if cli.verify_admin(sys.argv): if cli.verify_admin(sys.argv):
cli.run_interactive() cli.cmdloop()
# cli.run_single_command(sys.argv[1:]) # cli.run_single_command(sys.argv[1:])

View File

@ -179,7 +179,6 @@ class ServiceMgr:
configs = SERVICE_CONFIGS.configs configs = SERVICE_CONFIGS.configs
for service_id, config in enumerate(configs): for service_id, config in enumerate(configs):
config_dict = config.to_dict() config_dict = config.to_dict()
service_detail = None
try: try:
service_detail = ServiceMgr.get_service_details(service_id) service_detail = ServiceMgr.get_service_details(service_id)
if service_detail['alive']: if service_detail['alive']: