服务端代码

# !/usr/bin/env python3
# -*- coding:utf-8 -*-

import re
import json
from shuncom_params_init import *
from socketserver import StreamRequestHandler, ThreadingTCPServer
from vbox_cloud import vbox_cloud
import socket
import sz_log
import time
import os
from sz_tftp import sz_tftp_server
import threading
from sz_encrypt_mac import sz_encrypt
from shuncom_fun import get_local_ip
import paramiko



ip = get_local_ip()
host = ip  # 监听ip,串口服务器的指向 #host = '0.0.0.0'
tftp_ip = ip  # tftp服务器IP

local_firmware_name = "shuncom-juhe4-mt7621-sysupgrade.bin"  # 固件文件
uboot_firmware_name = 'u-boot-mt7621-212.bin'  # uboot文件
cmd_text = ''  # 下发串口服务器命令
client_ip_list = []
mutex = threading.Lock()



class vbox_handle_t():
    def __init__(self, product, id, ip, port):
        self.id = id
        self.vbox_handle = vbox_cloud(product, id, ip, port, self.message_handle)
        self.vbox_handle.connect()

    def register_mssage_cb(self, process_message_function):
        self.process_message_function = process_message_function

    def message_handle(self, client, userdata, msg):
        print("message handle " + msg.topic + " " + str(msg.payload))
        mqtt_msg = json.loads(msg.payload)
        if msg.topic[-6:] == "invoke":
            print(" invoke ")
            firmware_url_para = mqtt_msg["inputs"][0]["value"]
            firmware_url_para["ip"] = "122.144.131.26"
            firmware_url_para["port"] = 6001
            # # linux命令
            # os.system("rm /tmp/tftp/" + local_firmware_name)
            # update_cmd = "lftp -p " + str(firmware_url_para["port"]) + " -u " \
            #              + firmware_url_para["username"] + "," \
            #              + firmware_url_para["password"] + " sftp://" \
            #              + firmware_url_para["ip"] + ":" + str(firmware_url_para["port"]) \
            #              + "  -e \"  set net:max-retries 3; && get  download/firmware/" + firmware_url_para["path"] \
            #              + "/firmware.bin -o %s" % tftp_path + local_firmware_name + "  && quit \" &"
            # sz_log.info("从平台下载的网关固件命令", update_cmd)
            # os.system(update_cmd)

            try:
                if os.path.isfile(tftp_path + local_firmware_name):
                    os.remove(tftp_path + local_firmware_name)
                    sz_log.info('网关固件存在删除文件成功!')
                sz_log.info("从平台下载网关新固件中...")
                pt = paramiko.Transport(('122.144.131.26', 6001))
                pt.connect(username='shuncom', password='shuncomgw')
                sftp = paramiko.SFTPClient.from_transport(pt)  # sftp = t.open_sftp_client()
                sftp.get('download/firmware/%s/firmware.bin' % firmware_url_para["path"],
                         (tftp_path + local_firmware_name))
                sz_log.info("从平台下载网关新固件完成!")
                self.vbox_handle.report_properties({"notice": ''})   # 清除下载固件错误提示
                pt.close()
            except Exception as e:
                sz_log.info("*************从平台下载网关新固件失败!!!*********** %s" % e)
                self.vbox_handle.report_properties({"notice": '*从平台下载网关新固件失败*【请重新选择固件】%s'% e})
            self.vbox_handle.invoke_rsp(mqtt_msg, True)
        else:
            self.vbox_handle.write_properties_rsp(mqtt_msg, self.process_message_function(mqtt_msg["properties"]))


class productor_t():
    global client_ip

    def __init__(self, product, id, ip, port):
        self.id = id
        self.vbox_obj = vbox_handle_t(product, id, ip, port)
        self.vbox_obj.register_mssage_cb(self.cloud_msg_cb)
        self.refresh_vars()
        config_ip_250 = config_init.get('CONFIG_SHUNCOM', 'config_ip_250')
        args = "".join(client_ip[0])  # client_ip = ('192.168.31.103', 41358)
        ip_ = '.'.join(args.split('.')[:-1])
        self.config = {}
        self.config["ip_addr"] = ip_ + config_ip_250  # "192.168.31.222" # 网关静态IP地址
        sz_log.info('设置的静态ip:',self.config["ip_addr"])
        self.config["gatewayip"] = ip_ + '.1'  # '192.168.31.1'   # 上级路由ip地址
        self.config["gwmac"] = "无"
        self.config["firmware_version"] = "请选择固件版本"
        self.config["bdinfo"] = "请选择bdinfo"
        self.bdinfo_value = {}
        self.config["running"] = False
        # os.system("mkdir -p /tmp/tftp")
        self.uboot_v = '2.01.02'  # uboot版本

    def refresh_vars(self):
        self.step = 0  # 生产状态
        self.device_status = ""  # 设备状态
        self.device_uboot_ver = ""  # 设备uboot版本
        self.firmware_login_step_last_cmd_time = None
        self.last_send_time = time.time()  # 上次发送时间
        self.status = "wait"  # WEB状态
        self.mac_exist_in_gw = ""  # 网关MAC
        self.mac_exist_in_gw_cal_passwd = ""  # 网关登录密码
        self.Request_bdinfo_mac = 0  # 向平台请求bdinfo的Mac地址标志位
        try:
            self.vbox_obj.vbox_handle.report_properties({"notice": ''})  # 告警提示停止
            self.vbox_obj.vbox_handle.report_properties({"info": ''})    # 提示停止
            mutex.release()
            sz_log.info('重置线程锁解锁完成')
        except:
            pass

    def get_status(self):
        return self.status

    def get_config(self):
        return self.config

    def get_step(self):
        return self.step

    def next_step_test(self):
        """没有使用的功能"""
        if self.status == "wait":
            self.status = "error"
        elif self.status == "error":
            self.status = "process"
        elif self.status == "process":
            self.status = "finish"
        elif self.status == "finish":
            self.status = "wait"
            self.step += 1
            if self.step >= 4:
                self.step = 0

    def get_mac_exist_in_gw(self, splited_str):
        try:
            for tmp_line in splited_str:   # splited_str = ['Login incorrect2c:6a:6f:40:00:05\r', '']
                if "2c:6a:6f" in tmp_line or "2C:6A:6F" in tmp_line:
                    p = re.compile(r'(?:[0-9a-fA-F]:?){12}')
                    tmp_line = re.findall(p, tmp_line)  # 匹配Mac地址
                    sz_log.info('匹配Mac地址:', tmp_line)
                    if tmp_line:
                        tmp_mac_split = tmp_line[0].split(':')
                        self.mac_exist_in_gw = ""
                        for tmp_mac_char in tmp_mac_split:
                            self.mac_exist_in_gw = self.mac_exist_in_gw + tmp_mac_char
                        self.mac_exist_in_gw_cal_passwd = sz_encrypt(self.mac_exist_in_gw).decode(encoding="utf-8",errors="strict")
                        sz_log.info("mac_exist_in_gw  " + self.mac_exist_in_gw)
                        sz_log.info("mac_exist_in_gw_password  " + self.mac_exist_in_gw_cal_passwd)
                        self.config["gwmac"] = self.mac_exist_in_gw  # 回显原mac地址
                        return True
                    else:
                        sz_log.info('mac地址异常', tmp_line)
                        return False

                elif "00:c0:02:12:35:88" in tmp_line:
                    sz_log.info('上报Mac:00:c0:02:12:35:88,使用密码 回车')
                    # self.mac_exist_in_gw_cal_passwd = "5afc1d286cdcb137fcb234a962c19288" # 老板子密码
                    self.mac_exist_in_gw_cal_passwd = "\r"   # 新板子密码是回车
                    return True

                elif "无" in tmp_line:
                    sz_log.info('上报Mac无,使用默认密码:5554f3ba30a3727c05d66e047c6acbe8')
                    self.mac_exist_in_gw_cal_passwd = "5554f3ba30a3727c05d66e047c6acbe8"
                    return True

            sz_log.info('获取串口中的mac地址:false')
            return False
        except Exception as e:
            sz_log.info('get_mac_exist_in_gw异常:',e)
            return False


    def cloud_msg_cb(self, properties):
        """web页面的用户设置"""
        global cmd_text
        try:
            sz_log.info("接收web页面【生产工具-配置参数】")
            sz_log.info('接收web页面【properties】 ', properties)
            # sz_log.info(self.config.keys())
            for obj_name in properties:
                sz_log.info('接收web页面【obj_name】 ', obj_name)
                sz_log.info('接收web页面【self.config】 ', self.config)
                if obj_name in self.config:
                    if obj_name == "bdinfo":
                        sz_log.info('接收web页面【进入bdinfo】')
                        bdinfo_json = json.loads(properties[obj_name])
                        self.config["bdinfo"] = bdinfo_json["BOARD"] + "_" + bdinfo_json["VARIANT"]
                        self.bdinfo_value = properties[obj_name]
                        sz_log.info(" bdinfo " + self.config["bdinfo"])
                        sz_log.info(self.bdinfo_value)
                    else:
                        try:
                            self.config[obj_name] = properties[obj_name]
                        except:
                            sz_log.info('接收web页面【properties[obj_name] 处理错误】')
                        if obj_name == "running":
                            self.refresh_vars()
                else:
                    if obj_name == "log":
                        sz_log.info('读取日志:不支持')
                        self.vbox_obj.vbox_handle.report_properties({"log": {"日志": '读取日志:不支持'}})
                    elif obj_name == "cmd":
                        cmd_text = properties['cmd']
                        sz_log.info('执行cmd命令:', cmd_text)
                        self.vbox_obj.vbox_handle.report_properties({"log": {"日志": '执行cmd命令:%s' % cmd_text}})
                    elif obj_name == "step":
                        sz_log.info('读取步骤:不支持')
                        self.vbox_obj.vbox_handle.report_properties({"log": {"日志": '读取步骤:不支持'}})
                    elif obj_name == "status":
                        sz_log.info('读取当前状态:不支持')
                        self.vbox_obj.vbox_handle.report_properties({"log": {"日志": '读取当前状态:不支持'}})
                    else:
                        sz_log.info("obj not exist,不存在")
            sz_log.info('接收web页面 self.config 修改后 ', self.config)
            return True
        except Exception as e:
            sz_log.info('接收web页面异常%s' % e)
            return False

    def bdinfo_save(self, mac_str):
        """平台下载bdinfo文件"""
        bdinfo_value_split = self.bdinfo_value.split('\n')
        last_split_str = ""
        tmp_line_num = 0
        for tmp_split_str in bdinfo_value_split:
            if "\"type\": \"wan\"," in last_split_str and "macaddr" in tmp_split_str:
                tmp_i = 0
                dst_split_str = "                        \"macaddr\":\""
                sz_log.info('下载bdinfo,遍历出macaddr', tmp_split_str)  # 遍历出"macaddr": "2C:6A:6F:00:d4:12"
                sz_log.info('下载bdinfo,传入的Mac地址', mac_str)
                for tmp_char in mac_str:
                    tmp_i += 1
                    print('tmp_i', tmp_i)
                    if tmp_i < 13:
                        dst_split_str = dst_split_str + tmp_char
                        print('dst_split_str数据:', dst_split_str)
                        print("tmp i : " + str(tmp_i))
                        print("tmp i / 2: " + str(tmp_i % 2))
                        if (tmp_i % 2) == 0 and (tmp_i < 12):
                            dst_split_str += ":"
                            sz_log.info('下载bdinfo遍历12次,获取出Mac地址: ', dst_split_str)
                dst_split_str += "\""  # "macaddr":"无"
                bdinfo_value_split[tmp_line_num] = dst_split_str
            last_split_str = tmp_split_str  # "macaddr": "2C:6A:6F:00:d4:12"
            tmp_line_num += 1
        self.bdinfo_value = ""
        for tmp_split_str in bdinfo_value_split:
            self.bdinfo_value = self.bdinfo_value + tmp_split_str + "\n"
        sz_log.info('bdinfo_value值:', self.bdinfo_value)
        #os.system("mkdir -p /tmp/tftp/" + self.id)  # linux 命令
        print('判断bdinfo文件夹是否存在',os.path.exists(tftp_path + self.id))
        if not os.path.exists(tftp_path + self.id):
            sz_log.info('创建bdinfo文件夹')
            os.mkdir( tftp_path + self.id)
        with open(tftp_path + self.id + '/bdinfo.json', 'w+') as f:
            f.write(self.bdinfo_value)

    def firmware_login(self):
        if self.firmware_login_step == "username":
            if self.firmware_login_step_last_cmd_time is None:
                self.firmware_login_step_last_cmd_time = time.time()
                sz_log.info('发送登录root ')
                return "root\r"
            else:
                if time.time() - self.firmware_login_step_last_cmd_time > 2:
                    self.firmware_login_step_last_cmd_time = None
                    self.firmware_login_step = "passwd"

        if self.firmware_login_step == "passwd":
            if self.firmware_login_step_last_cmd_time is None:
                self.firmware_login_step_last_cmd_time = time.time()
                sz_log.info('发送ssh登录密码:' + self.mac_exist_in_gw_cal_passwd)
                return self.mac_exist_in_gw_cal_passwd + '\r'
            else:
                if time.time() - self.firmware_login_step_last_cmd_time > 2:
                    self.firmware_login_step_last_cmd_time = None
                    self.firmware_login_step = "finish"

    def do_step(self):
        """下发数据给串口服务器到网关"""
        if self.config["running"] == False:
            return None
        if self.step == 0:
            print('生产状态:检查并更新uboot')
        elif self.step == 1:
            print('生产状态:固件烧录中')
        elif self.step == 2:
            print('生产状态:bdinfo写入中')
        elif self.step == 3:
            print('生产状态:完成中')
        else:
            print('生产状态:未知%s' % self.step)
        if (time.time() - self.last_send_time) < 1:
            sz_log.info(" 时间间隔小于1秒不发送串口数据 last send too close")
            return None
        self.last_send_time = time.time()

        # 刷写网关uboot
        if self.step == 0:
            if self.status == "wait":
                if self.device_status == "have_firmware_login":
                    if self.firmware_login_step is None:
                        self.firmware_login_step = "username"
                    elif self.firmware_login_step == "finish":
                        sz_log.info(" login cmd send finish")
                    else:
                        return self.firmware_login()
                elif self.device_status == "have_firmware_shell":
                    return "reboot\n"
                else:
                    return "\n"
            elif self.status == "process":
                if self.device_status == "break_uboot":
                    return "0\n"
                elif self.device_status == "check_uboot_version":
                    return "version\n"
                elif self.device_status == 'updata_uboot':
                    sz_log.info('执行设置uboot参数,mtkupgrade')
                    self.updata_uboot_reset_num = 0
                    return "setenv gatewayip " + self.config["gatewayip"] + "\n" \
                           + "setenv ipaddr " + self.config["ip_addr"] + "\n" \
                           + "setenv serverip " + tftp_ip + "\n" \
                           + 'setenv bootfile.bootloader ' + uboot_firmware_name + '\n' \
                           + 'saveenv\n'
                elif self.device_status == 'updata_uboot_2_1' and self.updata_uboot_reset_num ==0:
                    self.updata_uboot_reset_num = 1
                    sz_log.info('uboot 设置重启 reset ')
                    return 'reset\n'
                elif self.device_status == 'updata_uboot_2':
                    return '4\n'
                elif self.device_status == 'updata_uboot_3':
                    return '\n' * 4
                elif self.device_status == 'updata_uboot_4':
                    return 'y\r'
                elif self.device_status == 'updata_uboot_5':
                    sz_log.info('等待网关断电重启网关')
                    return 'reset\n'


        # 刷写网关固件
        elif self.step == 1:
            if self.status == "wait":
                if self.device_status == "firmware_set_ip":
                    return " setenv gatewayip " + self.config["gatewayip"] + "\n" \
                           + "setenv ipaddr " + self.config["ip_addr"] + "\n" \
                           + "setenv serverip " + tftp_ip + "\n" \
                           + "setenv netmask " + "255.255.255.0\n" \
                           + "saveenv\n"
                elif self.device_status == "firmware_tftp":
                    return "szupgradefw\n"

        # 刷写网关bdinfo
        elif self.step == 2:
            if self.status == "process":
                if self.device_status == "bdinfo_init_login":
                    return "\n"
                elif self.device_status == "bdinfo_login":
                    if self.firmware_login_step is None:
                        self.firmware_login_step = "username"

                    elif self.firmware_login_step == "finish":
                        sz_log.info(" login cmd send finish")
                        sz_log.info(" 登录命令发送完成")
                    else:
                        return self.firmware_login()
                elif self.device_status == "bdinfo_shell":
                    return " tftp -g -r " + self.id + "/bdinfo.json " + tftp_ip + " && mv bdinfo.json /bdinfo/ && jffs2reset -y && reboot -f\n"
            elif self.status == "finish":
                return " tftp -g -r " + self.id + "/bdinfo.json " + tftp_ip + " && mv bdinfo.json /bdinfo/ && rm -f /etc/config/datacenter.db &&  jffs2reset -y && reboot -f\n"


        # 完成中
        elif self.step == 3:
            if self.device_status == "uboot_error_tftp":
                return "szboardboot\n"

            if self.device_status == "tty_usb_r":
                return "\r"

            if self.device_status == 'tty_usb_root':
                if self.firmware_login_step == "finish":
                    sz_log.info("查询usb登录命令发送成功")
                else:
                    return self.firmware_login()

            if self.device_status == "tty_usb_shell":
                sz_log.info('发送查询USB命令')
                #return "uci show shuncom && lspci\r"
                return "lspci\r"

            if self.device_status =='finish_reboot':
                pass
                # sz_log.info('发送换行命令')
                # return '\n' # 可以修改为恢复出厂设置


    def process_uart_data(self, data):
        """根据接收的数据判断网关的状态"""
        global mutex
        if self.config["running"] == False:
            return None

        sz_log.info("device status 前:" + self.device_status)
        sz_log.info(data.split('\n'))
        splited_str = data.split('\n')

        # 计算登录密码
        gw_mac_key = self.get_mac_exist_in_gw(splited_str)

        # 网关检查更新uboot
        if self.step == 0:
            if self.status == "wait":
                print("#########################################################splited_str#############",splited_str)
                if "Shuncom login:" in splited_str[-1]:
                    sz_log.info(" shuncom登录存在 ")
                    self.device_status = "have_firmware_login"
                    self.firmware_login_step = None
                # elif "-ash: root: not found" in splited_str[-1]:
                # if "root@Shuncom:~#" in splited_str[-1]:
                if "[\x1b[35;1mroot\x1b[0m@\x1b[31;1mshuncom\x1b[0m:\x1b[32;1m/root\x1b[0m]#" or "root@Shuncom:~#" in splited_str[-1]:
                    self.device_status = "have_firmware_shell"
                    self.firmware_login_step = None
                    self.firmware_login_step_last_cmd_time = None

                if "Hit any key to stop autoboot" in data:  # 重启网关进入
                    self.status = "process"
                    self.device_status = "break_uboot"
                    self.vbox_obj.vbox_handle.report_properties({"notice": ''})
                if "=>" in data:
                    self.status = "process"
                    self.device_status = "check_uboot_version"
                    self.vbox_obj.vbox_handle.report_properties({"notice": ''})

            elif self.status == "process":
                if self.device_status == 'updata_uboot_5':
                    self.status = "wait"
                    self.device_status = ''

                if self.device_status == "break_uboot":
                    if "=>" in data:
                        self.device_status = "check_uboot_version"

                if self.device_status == "check_uboot_version":
                    for tmp_str in splited_str:
                        local_idx = tmp_str.find("SHUNCOM-U-BOOT-VERSION")
                        if local_idx >= 0:
                            self.device_uboot_ver = tmp_str[local_idx + len("SHUNCOM-U-BOOT-VERSION") + 1:]
                            sz_log.info("found uboot version:" + self.device_uboot_ver)
                            if self.device_uboot_ver >= self.uboot_v:  # 对比uboot版本 2.01.02
                                sz_log.info('当前uboot版本不需要升级')
                                self.status = "wait"
                                self.step = 1
                                self.device_status = "firmware_set_ip"

                            else:
                                sz_log.info('需要升级uboot版本')
                                self.device_status = 'updata_uboot'
                                # self.uboot_v = '2.01.02'# 测试时候使用

                if self.device_status == 'updata_uboot':
                    if "Saving Environment to SPI Flash" in data: # 保存成功
                        self.device_status = 'updata_uboot_2_1'

                if self.device_status == 'updata_uboot_2_1':
                    if "Upgrade bootloader (advanced mode)" in data:
                        self.device_status = 'updata_uboot_2'  # 选择4 Upgrade bootloader (advanced mode)

                if self.device_status == 'updata_uboot_2':
                    if "Select (enter for default)" in data:
                        self.device_status = 'updata_uboot_3'  # 回车4if self.device_status == 'updata_uboot_3':
                    if "Upgrade Bootblock? (N/y)" in data:     # 回复 y
                        self.device_status = 'updata_uboot_4'
                if self.device_status == 'updata_uboot_4':     # 表示uboot更新完成。
                    if "Bootloader upgrade completed!" in data:
                        sz_log.info('++++ uboot 升级完成 +++++')
                        self.device_status = 'updata_uboot_5'
                        self.vbox_obj.vbox_handle.report_properties({"notice": 'uboot升级完成,请把网关断电重启,继续生产!'})
                    """
                    mUpgrade Bootblock? (N/y):[0m  y
                    Whole bootloader will be upgraded
                    Erasing from 0x0 to 0x2ffff, size 0x30000 ... OK
                    Writting from 0x80010000 to 0x0, size 0x2fca2 ... OK
                    [0;33m*** Bootloader upgrade completed! ***[0m
                    Hit any key to stop reboot:  3 
                    """

        # 刷写网关固件
        if self.step == 1:
            if self.status == "wait":
                if self.device_status == "firmware_set_ip":
                    if "setenv serverip" in data:
                        self.device_status = "firmware_tftp"
                        mutex.acquire()
                        sz_log.info('线程锁生效')
                elif self.device_status == "firmware_tftp":
                    if "Loading:" in data:
                        self.device_status = "firmware_tftping"
                        self.status = "process"
                        self.start_time = int(time.time())

            elif self.status == "process":
                if self.device_status == "firmware_tftping":
                    now_time = int(time.time())
                    if now_time - self.start_time > 300:
                        self.vbox_obj.vbox_handle.report_properties({"notice": '固件下载下载超时,请把【控制台-生产状态】重新开始,网关断电重启'})
                        self.start_time = now_time
                    sz_log.info(" tftping 固件下载中")

                if "Bytes transferred" in data:
                    sz_log.info("tftp finished ")
                    mutex.release()
                    sz_log.info('线程锁解锁')
                if "init: Console is alive" in data:
                    self.device_status = "bdinfo_waiting"
                    self.status = "wait"
                    self.step = 2

        # 更新刷写bdinfo文件
        if self.step == 2:
            if self.status == "wait":
                if gw_mac_key:
                    sz_log.info('根据Mac计算出的密码:', self.mac_exist_in_gw_cal_passwd)
                    self.status = "process"
                    self.device_status = "bdinfo_init_login"
                    self.firmware_login_step = None
                    self.Logintimedout = 0


            elif self.status == "process":
                if "Login timed" in data or "Login timed out" in data or "timed out" in data:
                    self.device_status = "bdinfo_init_login"
                    sz_log.info('****刷写bdinfo文件登录失败超时,尝试重新登录****', data)
                    self.Logintimedout = 1

                if ('Shuncom login:'in data and self.Logintimedout ==1)or('huncom login'in data and self.Logintimedout ==1):
                    # 发送root重新登录
                    self.device_status = "bdinfo_login"
                    self.firmware_login_step_last_cmd_time = None
                    self.firmware_login_step = "username"
                    self.Logintimedout = 0
                    sz_log.info('\n**** 登录超时,重新发送登录 root ****\n')

                if self.device_status == "bdinfo_init_login":
                    if "IPv6: ADDRCONF(NETDEV_UP): br-lan:" in data:
                        self.device_status = "bdinfo_login"
                        self.bdinfo_save(self.config["gwmac"])

                # if "root@Shuncom:~#" in data:
                if "[\x1b[35;1mroot\x1b[0m@\x1b[31;1mshuncom\x1b[0m:\x1b[32;1m/root\x1b[0m]#" or "root@Shuncom:~#" in splited_str[-1]:
                    self.device_status = "bdinfo_shell"
                    self.firmware_login_step = None
                    self.firmware_login_step_last_cmd_time = None
                    sz_log.info(" bdinfo " + self.config["bdinfo"])
                    self.status = "finish"
                    self.step = 2

            elif self.status == "finish":
                sz_log.info(" finishing")
                if "SHUNCOM-U-BOOT" in data:
                    self.status = "wait"
                    self.step = 3


        # 完成中等待网关重启
        if self.step == 3:
            if self.status == "wait":
                if "=>" in data:
                    sz_log.info(" 在uboot中错误输入了tftp ")
                    self.device_status = "uboot_error_tftp"
                elif "Linux version" in data:
                    self.status = "process"
                    self.tty_usb = False

            elif self.status == "process":
                if "first boot" in data:
                    # self.status = "finish"

                    self.device_status = 'tty_usb_r'  # 回车换行登录
                    self.tty_usb_num = 0
                    self.tty_usb = True

                # 后加的代码++++++++++++++++++++++++++++++++++++++++++++++
                if self.tty_usb:
                    if 'shuncom login:' in data:  # 输入root
                        self.device_status = 'tty_usb_root'
                        self.firmware_login_step = "username"
                        self.firmware_login_step_last_cmd_time = None

                    if "Login timed out" in data or "ogin timed ou" in data:
                        self.device_status = 'tty_usb_r'  # 回车换行登录
                        self.firmware_login_step = "username"
                        self.firmware_login_step_last_cmd_time = None
                        sz_log.info('****查询usb登录失败超时,尝试重新登录****', data)

                    # if "root@Shuncom:~#" in data:
                    if "[\x1b[35;1mroot\x1b[0m@\x1b[31;1mshuncom\x1b[0m:\x1b[32;1m/root\x1b[0m]#" or "root@Shuncom:~#" in splited_str[-1]:
                        self.device_status = "tty_usb_shell"
                        self.firmware_login_step = None
                        self.firmware_login_step_last_cmd_time = None
                        self.tty_usb = 'tty_usb_shell'

                    if self.tty_usb == 'tty_usb_shell':
                        """
                        root@Shuncom:~# lspci
                        00:00.0 Class 0604: 0e8d:0801
                        01:00.0 Class 0c03: 1912:0015
                        """
                        if '1912:0015' in data:
                            self.status = "finish"
                            sz_log.info('网关ttyUSB正常')
                        self.tty_usb_num += 1
                        print('检查ttyUSB运行次数',self.tty_usb_num)
                        time.sleep(1)
                        if self.tty_usb_num > 10:
                            self.vbox_obj.vbox_handle.report_properties({"notice": 'ttyUSB异常(pcie转usb3.0),请检查硬件问题!'})

            elif self.status == "finish":
                self.device_status = 'finish_reboot'
                sz_log.info('生产完成Mac地址:',self.config["gwmac"])
                self.vbox_obj.vbox_handle.report_properties({"info": 'MAC:%s 生产完成,请更换下一台网关!!!'% self.config["gwmac"]})
                if "SHUNCOM-U-BOOT" in data: # uboot
                    self.refresh_vars()
                    self.status = "process"
                    self.device_status = "break_uboot"

        sz_log.info("device status 后:" + self.device_status)



class rev_tcp(StreamRequestHandler):
    """ https://zhuanlan.zhihu.com/p/50214470  tcp接收数据
        创建一个继承自 SocketServer.BaseRequestHandler 的类,类中必须定义一个名称为 handle 的方法
    """
    def handle(self):
        global client_ip
        global cmd_text
        global gwproductor_id
        try:
            client_ip = self.client_address
            sz_log.info('客户端地址', self.client_address)
            config_web_url = config_init.get('CONFIG_SHUNCOM', 'config_web_url')
            sz_log.info('生产平台是:',config_web_url)
            self.productor = productor_t("PRODUCTOR_GW_1", gwproductor_id, config_web_url, 8027)
            self.request.settimeout(1.0)
            #client_ip_list.append([self.client_address,self.request,self.wfile,self.rfile,self.productor,time.time()])
            client_ip_list.append([self.client_address])
            report_seqs = 0
            while True:
                try:
                    data = self.request.recv(1024)
                except socket.timeout:
                    pass
                else:
                    if (len(data) == 0):
                        sz_log.info("客户端自动断开关闭,socket shut down")
                        self.productor.vbox_obj.vbox_handle.report_properties({"notice": '[串口服务器]自动断开了,【控制台-生产状态】重新开始'})
                        self.finish()
                        break
                    try:
                        splited_str = data.decode('utf-8').split('\n')
                        print('接收数据 splited_str: %s' % splited_str)
                        sz_log.info(splited_str)
                        print("#########################################################串口接收到的数据splited_str#############",splited_str)
                    except Exception as e:
                        splited_str = ''
                        sz_log.info("data.decode('utf-8')data异常,请检查串口线是否接触不良", e)
                        # self.productor.vbox_obj.vbox_handle.report_properties({"notice": '串口服务器异常,请检查串口线是否接触不良,【控制台-生产状态】重新开始'})

                    try:
                        if len(splited_str) > 0:
                            if 'gwproductor' in splited_str:
                                # self.deviceId = splited_str[0]
                                print('串口服务器的心跳包:', splited_str[0])

                            for tmp_log_line in splited_str:
                                if 'MMC init failed' in tmp_log_line:
                                    self.productor.vbox_obj.vbox_handle.report_properties({"notice": 'EMMC初始化失败,【控制台-生产状态】网关重启,重新生产'})
                                if 'ARP Retry count exceeded; starting again' in tmp_log_line:
                                    sz_log.info('tftp网络不通')
                                    # self.productor.vbox_obj.vbox_handle.report_properties({"notice": 'tftp网络不通,ARP Retry count exceeded; starting again'})
                                if self.productor.config["running"] == True:
                                    self.productor.vbox_obj.vbox_handle.report_properties({"log": tmp_log_line})
                        else:
                            if self.productor.config["running"] == True:
                                self.productor.vbox_obj.vbox_handle.report_properties({"log": data.decode('utf-8')})
                        if self.productor.config["running"] == True:
                            self.productor.process_uart_data(data.decode('utf-8'))
                    except:
                        sz_log.info('data数据无法解析')

                if len(client_ip_list) > 1:
                    try:
                        sz_log.info('删除前客户端列表:', client_ip_list)
                        for x in range(len(client_ip_list) - 1):
                            self.finish()
                            client_ip_list.pop(x)
                    except:
                        pass
                    sz_log.info('删除后客户端列表:', client_ip_list)
                    break

                if (report_seqs > 3):
                    self.productor.vbox_obj.vbox_handle.report_properties(
                        {"status": self.productor.get_status(), "step": self.productor.get_step()})
                    if self.productor.get_status() == "process" and self.productor.get_step() == 2:
                        if self.productor.Request_bdinfo_mac == 0:
                            if len(self.productor.mac_exist_in_gw) > 0:
                                if self.productor.config["gwmac"] == "无":
                                    sz_log.info('检测到mac无 刷写过固件')
                                    self.productor.config["gwmac"] = self.productor.mac_exist_in_gw
                            else:
                                if self.productor.config["gwmac"] == "无":
                                    sz_log.info('检测到mac无 没有刷写过固件')
                                    self.productor.vbox_obj.vbox_handle.report_properties(
                                        {"gwmac": "无", "bdinfo": self.productor.config["bdinfo"]})
                            self.productor.Request_bdinfo_mac = 1  # 请求平台分配bdinfo Mac一次

                    self.productor.vbox_obj.vbox_handle.report_properties(self.productor.get_config())
                    print("【主线程线程数量】:", len(threading.enumerate()))
                    sz_log.info("【主线程线程数量】:", len(threading.enumerate()))
                    report_seqs = 0
                report_seqs += 1

                data = self.productor.do_step()
                if data:
                    sz_log.info(" 下发串口数据 write port:\n" + data)
                    self.request.sendall(data.encode('utf-8'))
                if cmd_text:
                    sz_log.info(" 下发执行cmd命令: " + cmd_text)
                    if cmd_text == '回车':
                        self.request.sendall('\r'.encode('utf-8'))
                    elif cmd_text == '程序重启':
                        cmd_text = ''
                        client_ip_list.clear()
                        self.finish()
                        break
                    else:
                        self.request.sendall(cmd_text.encode('utf-8'))
                    cmd_text = ''

        except Exception as e:
            sz_log.info('rev_tcp程序异常', e)
            self.finish()
            client_ip_list.pop(0)

    def finish(self):
        """ wfile close,rfile close,mqtt close """
        try:
            self.request.close()
            if not self.wfile.closed:
                try:
                    self.wfile.flush()
                except socket.error:
                    pass
            self.wfile.close()
            self.rfile.close()
            self.productor.vbox_obj.vbox_handle.stop()
        except Exception as e:
            sz_log.info('finish异常', e)


class ThreadingTCPServerA(ThreadingTCPServer):
    """ThreadingTCPServer从ThreadingMixIn和TCPServer继承
        继承SocketServer.ThreadingTCPServer,在init之前设置allow_reuse_address = True(默认为False)
    """
    allow_reuse_address = True
    sz_log.info('电脑ip地址:', host)




class run_class():
    """运行和停止"""

    def run_(self,gw_id):
        global gwproductor_id
        gwproductor_id = gw_id # 聚盒基地生产ID

        self.tftp_server = sz_tftp_server(tftp_path, tftp_ip, 69)
        threading.Thread(target=self.tftp_server.sz_tftp_server, args=()).start()
        self.rev_tcp = rev_tcp
        config_ep = config_init.get('CONFIG_SHUNCOM', 'config_ep')
        addr = (host, int(config_ep))
        sz_log.info(('ip地址和端口:',addr, self.rev_tcp))
        self.TCP_server = ThreadingTCPServerA(addr, self.rev_tcp)
        self.TCP_server.serve_forever()  # 启动线程 #永久循环执行,可以接受多个客户端连接


    def run_stop(self):
        sz_log.info('+'*30 + '关闭程序' + '+'*30 + '\n\n')
        self.rev_tcp.finish()
        self.tftp_server.tftpy_close()
        self.TCP_server.server_close()



if __name__ == '__main__':
    pass

    # t_path = os.path.split(os.path.realpath(__file__))[0]
    # if not os.path.exists(t_path + r'\tmp\tftp/'):
    #     os.mkdir(t_path + r'\tmp\tftp/')
    # tftp_path = os.path.split(os.path.realpath(__file__))[0]+ r'\tmp\tftp/'
    # tftp_server = sz_tftp_server(tftp_path, tftp_ip, 69)
    # threading.Thread(target=tftp_server.sz_tftp_server, args=()).start()
    # TCP_server = ThreadingTCPServerA(addr, rev_tcp)
    # TCP_server.serve_forever()  # 启动线程 #永久循环执行,可以接受多个客户端连接



你可能感兴趣的:(python,服务器,开发语言)