1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4# Copyright (c) 2020-2021 Huawei Device Co., Ltd. 5# 6# HDF is dual licensed: you can use it either under the terms of 7# the GPL, or the BSD license, at your option. 8# See the LICENSE file in the root of this repository for complete details. 9 10 11import sys 12import argparse 13 14from hdf_tool_exception import HdfToolException 15from .hdf_command_error_code import CommandErrorCode 16from .hdf_tool_commands import HdfToolCommands 17from .hdf_tool_argument_parser import HdfToolArgumentParser 18 19 20class Message(object): 21 TYPE_REQ = 'request' 22 TYPE_QUIT = 'quit' 23 TYPE_ERROR = 'error' 24 TYPE_SUCCESS = 'success' 25 26 def __init__(self, msg_type, content): 27 self.msg_type = msg_type 28 self.content = content 29 30 def is_quit(self): 31 return self.msg_type.lower() == Message.TYPE_ERROR 32 33 34def pack_message(msg_type, content, err_code=None): 35 body = bytearray(content, 'utf-8') 36 if not err_code: 37 header = bytearray('{},{}\n'.format(msg_type, len(body)), 'utf-8') 38 else: 39 header = bytearray('{},{},{}\n'.format(msg_type, len(body), err_code), 40 'utf-8') 41 bytes_packet = bytearray().join([header, body]) 42 return bytes_packet 43 44 45def decode_header(header): 46 header_parts = header.split(',') 47 if len(header_parts) < 2: 48 return -1, '', 0 49 msg_type = header_parts[0] 50 body_len = int(header_parts[1]) 51 return 0, msg_type, body_len 52 53 54def decode_body(body): 55 arg_parser = HdfToolArgumentParser() 56 arg_parser.add_argument('cmd') 57 arg_parser.add_argument('remainder_args', nargs=argparse.REMAINDER) 58 args = arg_parser.parse_args(body.strip().split(' ')) 59 remainder = [arg for arg in args.remainder_args if len(arg) != 0] 60 return args.cmd, remainder 61 62 63class HdfCommandLineServer(object): 64 def __init__(self, input_obj, output_obj): 65 self.input_obj = input_obj 66 self.output_obj = output_obj 67 self.commands = HdfToolCommands() 68 69 def _send_back(self, msg_type, content, error_code=None): 70 message_bytes = pack_message(msg_type, content, error_code) 71 self.output_obj.write(message_bytes) 72 self.output_obj.flush() 73 74 def _send_back_success(self, content): 75 self._send_back(Message.TYPE_SUCCESS, content) 76 77 def _send_back_error(self, error_code, content): 78 self._send_back(Message.TYPE_ERROR, content, error_code) 79 80 def _read_header(self): 81 head_bytes = self.input_obj.readline() 82 msg_header = str(head_bytes, encoding="utf-8") 83 return decode_header(msg_header) 84 85 def _read_body(self, body_len): 86 body_bytes = self.input_obj.read(body_len) 87 body = str(body_bytes, encoding='utf-8') 88 return decode_body(body) 89 90 def run(self): 91 while True: 92 try: 93 ret, msg_type, body_len = self._read_header() 94 if ret != 0: 95 err_code = CommandErrorCode.MESSAGE_FORMAT_WRONG 96 self._send_back_error(err_code, 'header wrong') 97 continue 98 if msg_type == Message.TYPE_QUIT: 99 self._send_back_success('Bye bye!') 100 break 101 if body_len < 0: 102 err_code = CommandErrorCode.MESSAGE_FORMAT_WRONG 103 self._send_back_error(err_code, 'body len wrong') 104 continue 105 cmd, args = self._read_body(body_len) 106 ret = self.commands.run(cmd, args) 107 if ret: 108 self._send_back_success(str(ret)) 109 else: 110 self._send_back_success('') 111 except HdfToolException as exc: 112 try: 113 self._send_back_error(exc.error_code, exc.exc_msg) 114 except OSError: 115 sys.exit(-1) 116 finally: 117 pass 118 119 except BaseException as exc: 120 try: 121 self._send_back_error(CommandErrorCode.UNKNOWN_ERROR, 122 str(exc)) 123 except OSError: 124 sys.exit(-1) 125 finally: 126 pass 127 finally: 128 pass 129