import hashlib import os import simplejson as json import time import traceback from wsgiref.util import FileWrapper from zlib import crc32 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 Ansjer.config import SERVER_TYPE from Model.models import Device_User, EquipmentVersionLimitModel, CountryIPModel 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/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', None) 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') 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 ver = equipment.softwareVersion max_ver = equipment.max_ver print(now_ver <= max_ver) if now_ver <= max_ver: # 创建url的token tko = UrlTokenObject() file_path = tko.generate(data={'Url': "ansjer/" + CommonService.RandomStr(6) + "/" + file_path}) url = SERVER_DOMAIN + 'dlotapack/' + file_path print(url) # if SERVER_TYPE == 'Ansjer.formal_settings': # url = SERVER_DOMAIN + 'dlotapack/' + file_path # else: # 这里调用国内服务器进行下载,防止下载bug # if code == '18E201200CA' or code == '18E201200CZ': # url = 'http://www.zositech.xyz/dlotapack/' + file_path # else: # url = SERVER_DOMAIN + 'dlotapack/' + file_path return response.json(0, { 'ver': ver, 'url': url, "Description": equipment.Description, }) else: return response.json(902) else: return response.json(902) # ota包上传 class uploadOTAInterfaceView(TemplateView): @method_decorator(csrf_exempt) def dispatch(self, *args, **kwargs): return super(uploadOTAInterfaceView, self).dispatch(*args, **kwargs) def post(self, request, *args, **kwargs): request.encoding = 'utf-8' token = request.POST.get('token', None) fileName = request.FILES.get('fileName', None) fileType = request.POST.get('fileType', None) language = request.POST.get('language', None) return self.validate(token, fileName, fileType, language) def get(self, request, *args, **kwargs): request.encoding = 'gb2312' token = request.GET.get('token', None) fileName = request.FILES.get('fileName', None) fileType = request.GET.get('fileType', None) language = request.GET.get('language', None) return self.validate(token, fileName, fileType, language) def validate(self, token, fileName, fileType, language): response = ResponseObject() 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_permission = ModelService.check_perm(userID=userID, permID=210) if own_permission is not True: return response.json(404) return self.upload_ota_file(fileName, response, fileType, language) def upload_ota_file(self, fileName, response, fileType, language): try: if not language: language = 0 path = '/'.join((BASE_DIR, 'static/otapack', fileType, str(language))).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}) # ota包下载 @csrf_exempt def downloadOTAInterface(request, fullPath, *callback_args, **callback_kwargs): res = ResponseObject() print('fullPath:') print(fullPath) if fullPath: if os.path.isfile(fullPath): try: 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'] = res.formal(0) return response except Exception as e: return res.json(906, repr(e)) else: return res.json(907) else: return res.json(444, 'fullPath') # ota包下载 @csrf_exempt def downloadOTAInterfaceV2(request, fullPath, *callback_args, **callback_kwargs): res = ResponseObject() print('fullPath:') print(fullPath) # 解密url的token url_token = UrlTokenObject(fullPath) if ('' == url_token.Url): print('过期了') return res.json(907) else: print(url_token.Url) fp = url_token.Url fullPath = fp[14:] if fullPath: if os.path.isfile(fullPath): try: 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'] = res.formal(0) return response except Exception as e: return res.json(906, repr(e)) else: return res.json(907) else: return res.json(444, 'fullPath') @csrf_exempt def getDownLoadOTApackUrl(request): # QT获取升级文件的下载链接 response = ResponseObject() if request.method == "POST": request_dict = request.POST elif request.method == "GET": request_dict = request.GET else: return response.json(444) deviceType = request_dict.get('deviceType', None) version = request_dict.get('version', None) if not deviceType or not version: return response.json(444, 'deviceType or version') equipmentVersion = Equipment_Version.objects.filter(mci=deviceType, version=version) # 判断是否有该版本存在 if not equipmentVersion.exists(): return response.json(907) file_path = equipmentVersion[0].filePath if file_path: if file_path.find('static/otapack') != -1: # 只下载otapack路径下的文件 url = SERVER_DOMAIN + 'OTA/downloadsPack/' + file_path # 复用app下载ota包的方式 # SERVER_DOMAIN = 'https://test.dvema.com/' # url = SERVER_DOMAIN + 'OTA/downloadsPack/' + file_path res = { "url": url, } return response.json(0, res) else: return response.json(901) else: return response.json(901) @csrf_exempt def checkMaxVersion(request): # QT检查ota设备软件版本是否需要更新 response = ResponseObject() if request.method == "POST": request_dict = request.POST elif request.method == "GET": request_dict = request.GET else: return response.json(444) deviceType = request_dict.get('deviceType', None) version = request_dict.get('version', None) # 设备版本:当前版本+设备规格代码 lang = request_dict.get('lang', None) # 'zh-Hans','en' if not deviceType or not version: return response.json(444, 'deviceType or version') now_version = version[1:version.rindex('.')] # 去掉V code = version[version.rindex('.')+1:] equipmentVersion = Equipment_Version.objects.filter(mci=deviceType, code=code, lang=lang, status=1) # order by data_joined # 判断是否有该版本存在 if not equipmentVersion.exists(): return response.json(907) filePath = equipmentVersion[0].filePath softwareVersion = equipmentVersion[0].softwareVersion # 可用最新版本的版本号 maxVersion = equipmentVersion[0].max_ver if now_version >= softwareVersion: # 当前版本大于等于最新版本,不需要更新 return response.json(902) url = SERVER_DOMAIN + 'OTA/downloadsPack/' + filePath # 复用app下载ota包的方式 res = { 'url': url, } return response.json(0, res)