import os
import re
import sys

sys.path.append(os.path.dirname(sys.path[0]))

import paramiko
from paramiko import SSHClient


class SSHUtil(object):
    """
    ssh工具类
    """

    __sqoop_home__ = "hadoop5"
    __python_home__ = "hadoop5"

    __ssh_h5_host__ = "hadoop5"
    __ssh_h5_port__ = 22
    __ssh_h5_user__ = "root"
    __ssh_h5_pwd__ = "Tq3@Nz8%vRb1&"

    @staticmethod
    def get_ssh_client():
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(hostname=SSHUtil.__ssh_h5_host__, port=SSHUtil.__ssh_h5_port__, username=SSHUtil.__ssh_h5_user__,
                       password=SSHUtil.__ssh_h5_pwd__)
        return client

    @staticmethod
    def exec_command_async(client: SSHClient, cmd: str, ignore_err: bool = False):
        """
        :param client:
        :param cmd:
        :return: 成功返回shout 失败返回 sherr
        """
        print("============================执行脚本中=================================")
        print(cmd)
        channel = client.invoke_shell()
        channel.keep_this = client
        stdin = channel.makefile('wb')
        stdout = channel.makefile('r')

        cmd = cmd.strip('\n')
        stdin.write(cmd + '\n')
        finish = 'end of stdOUT buffer. finished with exit status'
        special_symbol = '\x1b'
        echo_cmd = 'echo {} $?'.format(finish)
        stdin.write(echo_cmd + '\n')
        # shin = self.stdin
        stdin.flush()

        shout = []
        sherr = []
        exit_status = 0
        for line in stdout:
            print(line.replace("\n", ""))
            if str(line).startswith(cmd) or str(line).startswith(echo_cmd):
                # up for now filled with shell junk from stdin
                shout = []
            elif str(line).startswith(special_symbol):
                continue
            elif str(line).startswith(finish):
                # our finish command ends with the exit status
                exit_status = int(str(line).rsplit(maxsplit=1)[1])
                if exit_status:
                    # stderr is combined with stdout.
                    # thus, swap sherr with shout in a case of failure.
                    sherr = shout
                    shout = []
                break
            else:
                # get rid of 'coloring and formatting' special characters
                shout.append(re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]').sub('', line).
                             replace('\b', '').replace('\r', ''))

        # first and last lines of shout/sherr contain a prompt
        if shout and echo_cmd in shout[-1]:
            shout.pop()
        if shout and cmd in shout[0]:
            shout.pop(0)
        if sherr and echo_cmd in sherr[-1]:
            sherr.pop()
        if sherr and cmd in sherr[0]:
            sherr.pop(0)

        err_msg = ''.join(sherr)
        success_msg = ''.join(shout)
        success_flag = success_msg is not None and success_msg != ''
        msg = success_msg or err_msg
        if ignore_err == False and success_flag == False:
            print(msg)
            raise Exception("脚本执行出错！出错原因详情如上！")
        channel.close()
        return {
            "success": success_flag,
            "msg": msg,
            "exit_status": exit_status
        }


if __name__ == '__main__':
    pass
