浏览代码

ota新增城市升级过滤、自动升级

zhangdongming 1 年之前
父节点
当前提交
daffecce79
共有 2 个文件被更改,包括 174 次插入10 次删除
  1. 154 5
      AdminController/VersionManagementController.py
  2. 20 5
      Controller/OTAEquipment.py

+ 154 - 5
AdminController/VersionManagementController.py

@@ -1,21 +1,26 @@
 #!/usr/bin/env python3
 # -*- coding: utf-8 -*-
-import os
 import hashlib
+import json
+import os
+import threading
 import time
-import math
 
 import boto3
 import botocore
+from django.core.paginator import Paginator
 from django.db import transaction
 from django.views.generic.base import View
-from Ansjer.config import LOGGER
 
 from Ansjer.config import BASE_DIR, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
-from Object.TokenObject import TokenObject
+from Ansjer.config import LOGGER, CONFIG_TEST, SERVER_DOMAIN, CONFIG_CN, CONFIG_INFO
+from Model.models import Equipment_Version, App_Info, AppSetModel, App_Colophon, Pc_Info, CountryModel, CNRegion, \
+    Device_Info, UidSetModel, Device_User, IPAddr
+from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+from Object.UrlTokenObject import UrlTokenObject
 from Service.CommonService import CommonService
-from Model.models import Equipment_Version, App_Info, AppSetModel, App_Colophon, Pc_Info, CountryModel, CNRegion
 
 
 class VersionManagement(View):
@@ -34,6 +39,8 @@ class VersionManagement(View):
         response = ResponseObject(language, 'pc')
         if operation == 'upLoadFile':
             return self.upLoadFile(request, request_dict, response)
+        elif operation == 'deviceAutoUpdate':
+            return self.device_auto_update('124', request_dict, response)
         else:
             tko = TokenObject(
                 request.META.get('HTTP_AUTHORIZATION'),
@@ -76,6 +83,8 @@ class VersionManagement(View):
                 return self.getCountryList(request_dict, response)
             elif operation == 'getCityList':
                 return self.getCityList(request_dict, response)
+            elif operation == 'deviceAutoUpdate':
+                return self.device_auto_update(userID, request_dict, response)
             else:
                 return response.json(404)
 
@@ -670,3 +679,143 @@ class VersionManagement(View):
         except Exception as e:
             print(e)
             return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+
+    @classmethod
+    def device_auto_update(cls, user_id, request_dict, response):
+        verId = request_dict.get('verId', None)
+        if not verId:
+            return response.json(444)
+        LOGGER.info(f'版本ID:{verId},操作用户{user_id}')
+        version_qs = Equipment_Version.objects.filter(eid=verId, auto_update=True, status=1)
+        if not version_qs.exists():
+            return response.json(173)
+
+        agent_thread = threading.Thread(target=VersionManagement().device_async_update,
+                                        args=version_qs)
+        agent_thread.start()
+        return response.json(0)
+
+    @staticmethod
+    def device_async_update(version_qs):
+        code = version_qs.code
+        version = version_qs.softwareVersion
+        ver_data = version_qs.data_json
+        uid_set_qs = UidSetModel.objects.filter(ucode=code).exclude(version=version) \
+            .values('uid', 'ip', 'version')
+        LOGGER.info(f'通知设备自动升级查询符合数量{uid_set_qs.count()}')
+        if not uid_set_qs.exists():
+            return
+
+        # 创建分页器,每页100条数据
+        paginator = Paginator(uid_set_qs, 100)
+
+        # 遍历每一页数据
+        for page_num in range(1, paginator.num_pages + 1):
+            # 获取当前页的数据
+            page_data = paginator.page(page_num)
+
+            # 遍历当前页的每一条数据
+            for data in page_data:
+                uid = data['uid']
+
+                result = VersionManagement.check_version_auto_update(uid, '', ver_data)
+                if not result:
+                    continue
+                serial_number = CommonService.get_serial_number_by_uid(uid)
+                now_ver = data['version']
+                LOGGER.info(f'uid={uid},ucode={code},当前版本{now_ver},最新版本{version}')
+                VersionManagement.send_auto_update_url(version_qs, uid, serial_number, code, now_ver)
+
+    @classmethod
+    def check_version_auto_update(cls, uid, user_id, ver_data):
+        """
+
+        :param uid: 设备UID
+        :param user_id: 用户id
+        :param ver_data: 版本指定升级数据
+        :return: True | False
+        """
+        try:
+            if not ver_data:  # 过滤值默认当前版本所有设备自动升级
+                return True
+
+            if uid and ver_data['uid_list']:  # 当前版本指定UID
+                return uid in ver_data['uid_list']
+            if user_id and ver_data['country_list'] and CONFIG_INFO not in [CONFIG_CN, CONFIG_TEST]:  # 当前版本指定用户国家
+                user_qs = Device_User.objects.filter(userID=user_id).values('region_country')
+                if not user_qs.exists():  # 用户不存在不升级
+                    return False
+                if user_qs[0]['region_country'] == 0:  # 用户未选择国家 不进行升级提示
+                    return False
+                return user_qs[0]['region_country'] in ver_data['country_list']
+            if CONFIG_INFO in [CONFIG_CN, CONFIG_TEST] and ver_data['addr']:  # 中国区可指定城市
+                city_list = ver_data['addr']['city_list']
+                if not city_list:
+                    return True
+                uid_set_qs = UidSetModel.objects.filter(uid=uid).values('ip')
+                if not uid_set_qs:
+                    return False
+                ip_qs = IPAddr.objects.filter(ip=uid_set_qs[0]['ip']).values('city').order_by('-id')
+                if not ip_qs:
+                    return False
+                return ip_qs[0]['city'] in city_list
+            return False
+        except Exception as e:
+            LOGGER.error(f'检测是否符合自动升级{repr(e)}')
+            return False
+
+    @staticmethod
+    def send_auto_update_url(version_qs, uid, serial_number, code, now_ver):
+        """
+        发送自动升级URL
+        @param version_qs: 最新版本querySet
+        @param uid: 设备UID
+        @param serial_number: 设备序列号
+        @param code: 设备规格码
+        @param now_ver: 设备当前版本好
+        @return:
+        """
+        try:
+            file_path = version_qs.filePath
+            version = version_qs.version
+            mci = version_qs.mci
+            ver = version_qs.softwareVersion
+            max_ver = version_qs.max_ver
+
+            if ver <= max_ver:
+                user_qs = Device_Info.objects.filter(UID=uid, isShare=False).values('userID_id')
+                if not user_qs.exists():
+                    return False
+                user_id = user_qs[0]['userID_id']
+                # 创建url的token
+                param_url = "ansjer/" + CommonService.RandomStr(6) + "/" + file_path
+                data = {'Url': param_url, 'user_id': user_id,
+                        'uid': uid, 'serial_number': serial_number, 'old_version': "V" + now_ver + "." + code,
+                        'new_version': version, 'mci': mci}
+                device_info_value = json.dumps(data)
+                expire = 600
+
+                str_uuid = str(user_id)
+                if serial_number and serial_number != 'null':
+                    str_uuid += serial_number
+                elif uid and uid != 'null':
+                    str_uuid += uid
+                str_uuid += now_ver
+                device_info_key = 'ASJ:SERVER:VERSION:{}'.format(str_uuid)
+                LOGGER.info('缓存key={}'.format(device_info_key))
+                redisObject = RedisObject()
+                redisObject.set_data(device_info_key, device_info_value, expire)
+
+                url_tko = UrlTokenObject()
+                file_path = url_tko.generate(data={'uid': str_uuid})
+
+                url = SERVER_DOMAIN + 'dlotapack/' + file_path
+                # 主题名称
+                topic_name = f'ansjer/generic/{serial_number}'
+                # 发布消息内容
+                msg = {"commandCode": 1, "data": {"url": url}}
+
+                result = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
+                LOGGER.info(f'uid={uid}发送数据msg={msg},发送MQTT结果={result}')
+        except Exception as e:
+            LOGGER.error(f'自动升级异常{repr(e)}')

+ 20 - 5
Controller/OTAEquipment.py

@@ -12,9 +12,10 @@ from django.utils.decorators import method_decorator
 from django.views.decorators.csrf import csrf_exempt
 from django.views.generic import TemplateView
 
-from Ansjer.config import BASE_DIR
+from Ansjer.config import BASE_DIR, CONFIG_TEST
 from Ansjer.config import SERVER_DOMAIN
-from Model.models import Device_User, EquipmentVersionLimitModel, CountryIPModel, DeviceOTAUpgradeRecord
+from Model.models import Device_User, EquipmentVersionLimitModel, CountryIPModel, DeviceOTAUpgradeRecord, UidSetModel, \
+    IPAddr
 from Model.models import Equipment_Version
 from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
@@ -489,8 +490,8 @@ def getNewVerInterface(request):
     if tko.code != 0:
         return response.json(tko.code)
     if lang == 'zh-Hans' or lang == 'cn':
-        equipmentValid = Equipment_Version.objects.filter(code=code, auto_update=False, status=1, lang='zh-Hans').order_by(
-            '-data_joined')
+        equipmentValid = Equipment_Version.objects.filter(code=code, auto_update=False, status=1, lang='zh-Hans')\
+            .order_by('-data_joined')
     else:
         equipmentValid = Equipment_Version.objects.filter(code=code, auto_update=False, status=1, lang='en').order_by(
             '-data_joined')
@@ -599,13 +600,27 @@ def check_version(uid, user_id, ver_data):
 
         if uid and ver_data['uid_list']:  # 当前版本指定UID
             return uid in ver_data['uid_list']
-        if user_id and ver_data['country_list'] and CONFIG_INFO != CONFIG_CN:  # 当前版本指定用户国家
+        # 最新版本 过滤国家并且不是国内或者测试服
+        if user_id and ver_data['country_list'] and CONFIG_INFO not in [CONFIG_CN, CONFIG_TEST]:
             user_qs = Device_User.objects.filter(userID=user_id).values('region_country')
             if not user_qs.exists():  # 用户不存在不升级
                 return False
             if user_qs[0]['region_country'] == 0:  # 用户未选择国家 不进行升级提示
                 return False
             return user_qs[0]['region_country'] in ver_data['country_list']
+
+        # 中国区可指定城市进行升级
+        if ver_data['addr'] and CONFIG_INFO in [CONFIG_CN, CONFIG_TEST]:
+            city_list = ver_data['addr']['city_list']
+            if not city_list:
+                return True
+            uid_set_qs = UidSetModel.objects.filter(uid=uid).values('ip')
+            if not uid_set_qs:
+                return False
+            ip_qs = IPAddr.objects.filter(ip=uid_set_qs[0]['ip']).values('city').order_by('-id')
+            if not ip_qs:
+                return False
+            return ip_qs[0]['city'] in city_list
         return True
     except Exception as e:
         print(repr(e))