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 from Model.models import Device_User, EquipmentVersionLimitModel, CountryIPModel, DeviceOTAUpgradeRecord 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 import uuid 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/downloads/' + path + '?time=' + str(time.time()) urls.append(url) if file_path.find('static/otapack') != -1: url = SERVER_DOMAIN + '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 = 3600 * 24 * 2 + 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/downloadsPack/' + filePath # 复用app下载ota包的方式 res = { 'url': url, } return response.json(0, res)