import hashlib import logging import os import time import traceback from wsgiref.util import FileWrapper from zlib import crc32 import simplejson as json from django.http import HttpResponse 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 SERVER_DOMAIN, SERVER_DOMAIN_OTA from Model.models import Device_User, EquipmentVersionLimitModel, CountryIPModel, DeviceOTAUpgradeRecord, LogModel from Model.models import Equipment_Version 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 Service.ModelService import ModelService def downloadUrl(fileType, fileCode, fileVersion, fileName): fullPath = os.path.join(BASE_DIR, "static/Upgrade").replace('\\', '/') if fileType == 'IPC': Path = '/'.join((fullPath, 'IPC', fileCode, fileVersion, fileName)).replace('\\', '/') elif fileType == 'DVR': Path = '/'.join((fullPath, 'DVR', fileCode, fileVersion, fileName)).replace('\\', '/') elif fileType == 'NVR': Path = '/'.join((fullPath, 'NVR', fileCode, fileVersion, fileName)).replace('\\', '/') elif fileType == 'XVR': Path = '/'.join((fullPath, 'IPC', fileCode, fileVersion, fileName)).replace('\\', '/') else: if fileType == 'CHM': Path = fileName else: Path = '/'.join((fullPath, 'Other', fileName)).replace('\\', '/') if os.path.isfile(Path): try: JSON = json.dumps( { "result_code": 0, "reason": 'Success', "result": {}, "error_code": 0, }, ensure_ascii=False ) wrapper = FileWrapper(open(Path, 'rb')) response = HttpResponse(wrapper, content_type="application/octet-stream") response['Content-Length'] = os.path.getsize(Path) response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(Path) response['Content-MD5'] = getMD5orSHA265(Path) response['Content-SHA265'] = getMD5orSHA265(Path, 'SHA265') response['Content-CRC32'] = getMD5orSHA265(Path, 'CRC32') response['Content-Error'] = JSON return response except Exception as e: res = ResponseObject() errorJSON = res.formal(906, {'details': repr(e)}) response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8') response['Content-Error'] = errorJSON return response else: res = ResponseObject() errorJSON = res.formal(907) response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8') response['Content-Error'] = errorJSON return response def getMD5orSHA265(fileName, encryptionType='MD5'): """ :param filePath: :param encryptionType: :return: """ if not os.path.isfile(fileName): return '' else: if encryptionType == 'MD5': encryption = hashlib.md5() elif encryptionType == 'SHA265': encryption = hashlib.sha256() elif encryptionType == 'CRC32': f = open(fileName, 'rb') chunk = f.read() return crc32(chunk) f = open(fileName, 'rb') block_size = 8192 # why is 8192 | 8192 is fast than 2048 while True: chunk = f.read(block_size) if not chunk: break encryption.update(chunk) f.close() return encryption.hexdigest() @csrf_exempt def downloadUpdataFileUrl(request): response = ResponseObject() if request.method == 'GET': request_dict = request.GET elif request.method == 'POST': request_dict = request.POST else: errorJSON = response.formal(444) response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8') response['Content-Error'] = errorJSON return response fileType = request_dict.get('fileType', None) fileCode = request_dict.get('fileCode', None) fileVersion = request_dict.get('fileVersion', None) fileName = request_dict.get('fileName', None) if fileType != None and fileCode != None and fileVersion != \ None and fileName != None: return downloadUrl(fileType, fileCode, fileVersion, fileName, response) else: errorJSON = response.formal(444) response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8') response['Content-Error'] = errorJSON return response @csrf_exempt def getEquipmentVersionInterface(request): response = ResponseObject() if request.method == "POST": request.encoding = 'utf-8' request_dict = request.POST elif request.method == "GET": request.encoding = 'gb2312' request_dict = request.GET else: return response.json(444) code = request_dict.get('code', None) ov = request_dict.get('ov', None) if not code: return response.json(444, 'code') eqs = Equipment_Version.objects.filter(code=code, status=1, lang='en').order_by('-data_joined') if not eqs.exists(): return response.json(900) if ov is not None: # 判断大小 nv = eqs[0].softwareVersion if ov > nv: return response.json(0, {'softwareVersion': ov}) equipment = eqs[0] return response.json(0, {'softwareVersion': equipment.softwareVersion}) @csrf_exempt def getUpdataFileUrlInterface(request): response = ResponseObject() request.encoding = 'utf-8' if request.method == "POST": code = request.POST.get('code', None) elif request.method == "GET": code = request.GET.get('code', None) else: return response.json(444) if not code: return response.json(444, 'code') eq = Equipment_Version.objects.filter(code=code, status=1, lang='en').order_by('-data_joined') # 判断是否有版本存在 if not eq.exists(): return response.json(902) file_path = eq[0].filePath urls = [] if file_path: if file_path.find('static/Upgrade/') != -1: path = file_path.replace('static/Upgrade/', '').replace('\\', '/') url = SERVER_DOMAIN_OTA + 'OTA/downloads/' + path + '?time=' + str(time.time()) urls.append(url) if file_path.find('static/otapack') != -1: url = SERVER_DOMAIN_OTA + 'OTA/downloadsPack/' + file_path + '?time=' + str(time.time()) urls.append(url) if len(urls) > 0: res = { "urlCount": len(urls), "url": urls, "fileSize": eq[0].fileSize, "Description": eq[0].Description, } return response.json(0, res) else: return response.json(901) @csrf_exempt def downloadUpdataFileUrlInterface(request, fileType, fileName, *callback_args, **callback_kwargs): res = ResponseObject() if fileType is not None and fileName is not None: fullPath = os.path.join(BASE_DIR, "static/Upgrade/").replace('\\', '/') if fileType == 'IPC': fullPath += 'IPC/' + fileName elif fileType == 'DVR': fullPath += 'DVR/' + fileName elif fileType == 'NVR': fullPath += 'NVR/' + fileName elif fileType == 'XVR': fullPath += 'XVR/' + fileName elif fileType == 'User': fullPath = os.path.join(BASE_DIR, "static/").replace('\\', '/') fullPath += 'User/' + fileName elif fileType == 'ADCloud': fullPath = os.path.join(BASE_DIR, "static/APK/").replace('\\', '/') fullPath += 'ADCloud/' + fileName elif fileType == 'ACCloud': fullPath = os.path.join(BASE_DIR, "static/APK/").replace('\\', '/') fullPath += 'ACCloud/' + fileName else: fullPath += 'Other/' + fileName print(fullPath) if os.path.isfile(fullPath): try: JSON = res.formal(0) if fileType != 'User': wrapper = FileWrapper(open(fullPath, 'rb')) response = HttpResponse(wrapper, content_type="application/octet-stream") response['Content-Length'] = os.path.getsize(fullPath) response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(fullPath) response['Content-MD5'] = getMD5orSHA265(fullPath) # 校验文件md5值 response['Content-SHA265'] = getMD5orSHA265(fullPath, 'SHA265') response['Content-CRC32'] = getMD5orSHA265(fullPath, 'CRC32') response['Content-Error'] = JSON return response else: Imagedata = open(fullPath, 'rb').read() response = HttpResponse(Imagedata, content_type="image/jpeg") return response except Exception as e: errorJSON = res.formal(906) response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8') response['Content-Error'] = errorJSON return response else: errorJSON = res.formal(907) response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8') response['Content-Error'] = errorJSON return response else: errorJSON = res.formal(444) response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8') response['Content-Error'] = errorJSON return response class getUploadFiletoDirView(TemplateView): @method_decorator(csrf_exempt) def dispatch(self, *args, **kwargs): return super(getUploadFiletoDirView, self).dispatch(*args, **kwargs) def post(self, request, *args, **kwargs): request.encoding = 'utf-8' request_dict = request.POST fileName = request.FILES.get('fileName', None) return self.ValidationError(request_dict, fileName) def get(self, request, *args, **kwargs): request.encoding = 'gb2312' request_dict = request.GET fileName = request.FILES.get('fileName', None) return self.ValidationError(request_dict, fileName) def ValidationError(self, request_dict, fileName): response = ResponseObject() token = request_dict.get('token', None) fileType = request_dict.get('fileType', None) fileCode = request_dict.get('fileCode', None) fileVersion = request_dict.get('fileVersion', None) if not fileName or not fileType: return response.json(444, 'fileName,fileType') tko = TokenObject(token) response.lang = tko.lang if tko.code != 0: return response.json(tko.code) userID = tko.userID if not userID: return response.json(104) own_perm = ModelService.check_perm(userID=userID, permID=210) if not own_perm: return response.json(404) if fileVersion != None and fileCode != None: return self.getUploadFiletoDir(userID, fileType, fileName, response, fileCode, fileVersion=fileVersion) else: return self.getUploadFiletoDir(userID, fileType, fileName, response) def getUploadFiletoDir(self, userID, fileType, fileName, response, *args, **kwargs): """ 将上传的文件写入服务器对应目录下 :param Type: equipment type :param fileName: File name of upgrade file. :return: filePath """ User = Device_User.objects.filter(userID=userID) if not User: return response.json(104) own_perm = ModelService.check_perm(userID, permID=210) if own_perm is not True: return response.json(404) updataFile = fileName.name updataFile = updataFile.replace(' ', '+') versionIndex = updataFile.find('.', updataFile.find('.', updataFile.find('.') + 1) + 1) codeIndex = versionIndex + 12 if codeIndex != -1 and versionIndex != -1: fileVersion = len(updataFile[1: versionIndex]) > 0 and updataFile[1: versionIndex] or None fileCode = len(updataFile[versionIndex + 1: codeIndex]) > 0 and \ updataFile[versionIndex + 1: codeIndex] or None if fileCode is not None and fileVersion is not None: return self.getDir(fileType, fileName, fileCode, fileVersion, response) else: fileCode = kwargs.get('fileCode', None) fileVersion = kwargs.get('fileVersion', None) print(fileCode, fileVersion) if fileCode != None and fileVersion != None: return self.getDir(fileType, fileName, fileCode, fileVersion) else: return response.json(903) else: fileCode = kwargs.get('fileCode', None) fileVersion = kwargs.get('fileVersion', None) if fileCode != None and fileVersion != None: return self.getDir(fileType, fileName, fileCode, fileVersion, response) else: return response.json(903) def getDir(self, fileType, fileName, fileCode, fileVersion, response): try: if fileCode != None and fileVersion != None: path = '/'.join((BASE_DIR, 'static/Upgrade', fileType, fileCode, fileVersion)).replace('\\', '/') + '/' else: if fileType != 'IPC' and fileType != 'DVR' and fileType != 'NVR' and fileType != 'XVR': path = '/'.join((BASE_DIR, "static/Upgrade", 'Other')).replace('\\', '/') + '/' if not os.path.exists(path): os.makedirs(path) file_name = path + str(fileName) if os.path.exists(file_name): os.remove(file_name) destination = open(file_name, 'wb+') for chunk in fileName.chunks(): destination.write(chunk) destination.close() else: file_name = path + str(fileName) if os.path.exists(file_name): os.remove(file_name) destination = open(file_name, 'wb+') for chunk in fileName.chunks(): destination.write(chunk) destination.close() except Exception as e: errorInfo = traceback.format_exc() print('上传文件错误: %s' % errorInfo) return response.json(700, {'details': repr(e)}) else: index = file_name.find('static/') filePath = file_name[index:] return response.json(0, {'filePath': filePath}) @csrf_exempt def addNewEquipmentVersionInterface(request): request.encoding = 'utf-8' response = ResponseObject() if request.method == "POST": request_dict = request.POST elif request.method == "GET": request_dict = request.GET else: return response.json(444) deviceContent = request_dict.get('content', None).encode('utf-8') token = request_dict.get('token', None) file_s = request.FILES.get('file', None) deviceContent = str(deviceContent, encoding='utf-8') deviceContent = deviceContent.replace(' ', ' ').replace('\'', '\"') if deviceContent is None: return response.json(444, 'content') tko = TokenObject(token) response.lang = tko.lang if tko.code != 0: return response.json(tko.code) userID = tko.userID own_perm = ModelService.check_perm(userID=userID, permID=220) if own_perm is False: return response.json(404) try: deviceData = json.loads(deviceContent) version = deviceData.get('version', None) filePath = deviceData.get('filePath', None) code = deviceData.get('code', None) lang = deviceData.get('lang', None) if code and lang: try: Equipment_Version.objects.filter(code=code, lang=lang).delete() except Exception as e: pass if version is None or filePath is None: return response.json(444, 'content') deviceData['filePath'] = ','.join(filePath) paths = 'static/versions/image' if not os.path.exists(paths): os.makedirs(paths) # makedirs 创建文件时如果路径不存在会创建这个路径 # print ('该文件不存在') else: print('该文件存在') print(file_s) if file_s is None: deviceData['img'] = '' else: rv_path = 'static/versions/image/' + code + '.png' try: as_path = os.path.join(BASE_DIR, rv_path) if os.path.exists(as_path): os.remove(as_path) with open(as_path, 'wb+') as destination: for chunk in file_s.chunks(): destination.write(chunk) except Exception as e: pass else: deviceData['img'] = SERVER_DOMAIN + 'sysfile/' + rv_path ev_qs = Equipment_Version( eid=CommonService.getUserID(getUser=False, setOTAID=True), **deviceData) ev_qs.save() except Exception as e: return response.json(444, repr(e)) else: res = CommonService.qs_to_dict([ev_qs]) return response.json(0, res) def showAllEquipmentVersion(userID, response): userValid = Device_User.objects.filter(userID=userID).order_by('-data_joined') if not userValid.exists(): return response.json(104) own_perm = ModelService.check_perm(userID=userID, permID=240) if not own_perm: return response.json(404) qs = Equipment_Version.objects.all() res = CommonService.qs_to_dict(qs) return response.json(0, res) # 检测ota更新包 @csrf_exempt def getNewVerInterface(request): response = ResponseObject() if request.method == "POST": request_dict = request.POST elif request.method == "GET": request_dict = request.GET else: return response.json(404) code = request_dict.get('code', None) token = request_dict.get('token', None) lang = request_dict.get('lang', None) now_ver = request_dict.get('ver', None) uid = request_dict.get('uid', 'null') serial_number = request_dict.get('serial_number', 'null') if not code or not now_ver: return response.json(902, {'param': 'code,ver'}) # return response.json(444, 'code,ver') tko = TokenObject(token) response.lang = tko.lang if tko.code != 0: return response.json(tko.code) if lang == 'zh-Hans' or lang == 'cn': equipmentValid = Equipment_Version.objects.filter(code=code, status=1, lang='zh-Hans').order_by( '-data_joined') else: equipmentValid = Equipment_Version.objects.filter(code=code, status=1, lang='en').order_by( '-data_joined') logger = logging.getLogger('info') if equipmentValid.exists(): equipment = equipmentValid[0] redisObject = RedisObject() key = 'limit_{eid}'.format(eid=equipment.eid) evl_qs = redisObject.get_data(key=key) if evl_qs: evl_qs = json.loads(evl_qs) else: evl_qs = EquipmentVersionLimitModel.objects.filter(equipment_version_id=equipment.eid, status=1).values() if evl_qs.exists(): redisObject.set_data(key=key, val=json.dumps(list(evl_qs.values())), expire=600) if evl_qs and len(evl_qs) > 0: evl = evl_qs[0] if evl['type'] == 1: # uid限制 uids = json.loads(evl['content']) if not uids.__contains__(uid): return response.json(902) elif evl['type'] == 2: # user限制 users = json.loads(evl['content']) if not users.__contains__(tko.userID): return response.json(902) elif evl['type'] == 3: # 国家地区限制 countries = json.loads(evl['content']) country_ip_qs = CountryIPModel.objects.filter(user_ex__userID=tko.userID) if country_ip_qs.exists(): country = country_ip_qs[0].country else: country = CommonService.getAddr(CommonService.get_ip_address(request)) if not countries.__contains__(country): return response.json(902) file_path = equipment.filePath version = equipment.version mci = equipment.mci ver = equipment.softwareVersion max_ver = equipment.max_ver print(now_ver <= max_ver) now_stamp = int(time.time()) if now_ver <= max_ver: # 创建url的token param_url = "ansjer/" + CommonService.RandomStr(6) + "/" + file_path data = {'Url': param_url, 'user_id': tko.userID, '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(tko.userID) 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.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 logger.info('<<<<<<= softwareVersion: # 当前版本大于等于最新版本,不需要更新 return response.json(902) url = SERVER_DOMAIN_OTA + 'OTA/downloadsPack/' + filePath # 复用app下载ota包的方式 res = { 'url': url, } return response.json(0, res)