OTAEquipment.py 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. import hashlib
  2. import logging
  3. import os
  4. import time
  5. import traceback
  6. from wsgiref.util import FileWrapper
  7. from zlib import crc32
  8. import simplejson as json
  9. from django.http import HttpResponse
  10. from django.utils.decorators import method_decorator
  11. from django.views.decorators.csrf import csrf_exempt
  12. from django.views.generic import TemplateView
  13. from Ansjer.config import BASE_DIR, CONFIG_TEST
  14. from Ansjer.config import SERVER_DOMAIN
  15. from Model.models import Device_User, EquipmentVersionLimitModel, CountryIPModel, DeviceOTAUpgradeRecord, UidSetModel, \
  16. IPAddr
  17. from Model.models import Equipment_Version
  18. from Object.RedisObject import RedisObject
  19. from Object.ResponseObject import ResponseObject
  20. from Object.TokenObject import TokenObject
  21. from Object.UrlTokenObject import UrlTokenObject
  22. from Service.CommonService import CommonService
  23. from Service.ModelService import ModelService
  24. from Ansjer.config import CONFIG_INFO, CONFIG_CN
  25. def downloadUrl(fileType, fileCode, fileVersion, fileName):
  26. fullPath = os.path.join(BASE_DIR, "static/Upgrade").replace('\\', '/')
  27. if fileType == 'IPC':
  28. Path = '/'.join((fullPath, 'IPC', fileCode, fileVersion, fileName)).replace('\\', '/')
  29. elif fileType == 'DVR':
  30. Path = '/'.join((fullPath, 'DVR', fileCode, fileVersion, fileName)).replace('\\', '/')
  31. elif fileType == 'NVR':
  32. Path = '/'.join((fullPath, 'NVR', fileCode, fileVersion, fileName)).replace('\\', '/')
  33. elif fileType == 'XVR':
  34. Path = '/'.join((fullPath, 'IPC', fileCode, fileVersion, fileName)).replace('\\', '/')
  35. else:
  36. if fileType == 'CHM':
  37. Path = fileName
  38. else:
  39. Path = '/'.join((fullPath, 'Other', fileName)).replace('\\', '/')
  40. if os.path.isfile(Path):
  41. try:
  42. JSON = json.dumps(
  43. {
  44. "result_code": 0,
  45. "reason": 'Success',
  46. "result": {},
  47. "error_code": 0,
  48. }, ensure_ascii=False
  49. )
  50. wrapper = FileWrapper(open(Path, 'rb'))
  51. response = HttpResponse(wrapper, content_type="application/octet-stream")
  52. response['Content-Length'] = os.path.getsize(Path)
  53. response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(Path)
  54. response['Content-MD5'] = getMD5orSHA265(Path)
  55. response['Content-SHA265'] = getMD5orSHA265(Path, 'SHA265')
  56. response['Content-CRC32'] = getMD5orSHA265(Path, 'CRC32')
  57. response['Content-Error'] = JSON
  58. return response
  59. except Exception as e:
  60. res = ResponseObject()
  61. errorJSON = res.formal(906, {'details': repr(e)})
  62. response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8')
  63. response['Content-Error'] = errorJSON
  64. return response
  65. else:
  66. res = ResponseObject()
  67. errorJSON = res.formal(907)
  68. response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8')
  69. response['Content-Error'] = errorJSON
  70. return response
  71. def getMD5orSHA265(fileName, encryptionType='MD5'):
  72. """
  73. :param filePath:
  74. :param encryptionType:
  75. :return:
  76. """
  77. if not os.path.isfile(fileName):
  78. return ''
  79. else:
  80. if encryptionType == 'MD5':
  81. encryption = hashlib.md5()
  82. elif encryptionType == 'SHA265':
  83. encryption = hashlib.sha256()
  84. elif encryptionType == 'CRC32':
  85. f = open(fileName, 'rb')
  86. chunk = f.read()
  87. return crc32(chunk)
  88. f = open(fileName, 'rb')
  89. block_size = 8192 # why is 8192 | 8192 is fast than 2048
  90. while True:
  91. chunk = f.read(block_size)
  92. if not chunk:
  93. break
  94. encryption.update(chunk)
  95. f.close()
  96. return encryption.hexdigest()
  97. @csrf_exempt
  98. def downloadUpdataFileUrl(request):
  99. response = ResponseObject()
  100. if request.method == 'GET':
  101. request_dict = request.GET
  102. elif request.method == 'POST':
  103. request_dict = request.POST
  104. else:
  105. errorJSON = response.formal(444)
  106. response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8')
  107. response['Content-Error'] = errorJSON
  108. return response
  109. fileType = request_dict.get('fileType', None)
  110. fileCode = request_dict.get('fileCode', None)
  111. fileVersion = request_dict.get('fileVersion', None)
  112. fileName = request_dict.get('fileName', None)
  113. if fileType != None and fileCode != None and fileVersion != \
  114. None and fileName != None:
  115. return downloadUrl(fileType, fileCode, fileVersion, fileName, response)
  116. else:
  117. errorJSON = response.formal(444)
  118. response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8')
  119. response['Content-Error'] = errorJSON
  120. return response
  121. @csrf_exempt
  122. def getEquipmentVersionInterface(request):
  123. response = ResponseObject()
  124. if request.method == "POST":
  125. request.encoding = 'utf-8'
  126. request_dict = request.POST
  127. elif request.method == "GET":
  128. request.encoding = 'gb2312'
  129. request_dict = request.GET
  130. else:
  131. return response.json(444)
  132. code = request_dict.get('code', None)
  133. ov = request_dict.get('ov', None)
  134. if not code:
  135. return response.json(444, 'code')
  136. eqs = Equipment_Version.objects.filter(code=code, status=1, lang='en').order_by('-data_joined')
  137. if not eqs.exists():
  138. return response.json(900)
  139. if ov is not None:
  140. # 判断大小
  141. nv = eqs[0].softwareVersion
  142. if ov > nv:
  143. return response.json(0, {'softwareVersion': ov})
  144. equipment = eqs[0]
  145. return response.json(0, {'softwareVersion': equipment.softwareVersion})
  146. @csrf_exempt
  147. def getUpdataFileUrlInterface(request):
  148. response = ResponseObject()
  149. request.encoding = 'utf-8'
  150. if request.method == "POST":
  151. code = request.POST.get('code', None)
  152. elif request.method == "GET":
  153. code = request.GET.get('code', None)
  154. else:
  155. return response.json(444)
  156. if not code:
  157. return response.json(444, 'code')
  158. eq = Equipment_Version.objects.filter(code=code, status=1, lang='en').order_by('-data_joined')
  159. # 判断是否有版本存在
  160. if not eq.exists():
  161. return response.json(902)
  162. file_path = eq[0].filePath
  163. urls = []
  164. if file_path:
  165. if file_path.find('static/Upgrade/') != -1:
  166. path = file_path.replace('static/Upgrade/', '').replace('\\', '/')
  167. url = SERVER_DOMAIN + 'OTA/downloads/' + path + '?time=' + str(time.time())
  168. urls.append(url)
  169. if file_path.find('static/otapack') != -1:
  170. url = SERVER_DOMAIN + 'OTA/downloadsPack/' + file_path + '?time=' + str(time.time())
  171. urls.append(url)
  172. if len(urls) > 0:
  173. res = {
  174. "urlCount": len(urls),
  175. "url": urls,
  176. "fileSize": eq[0].fileSize,
  177. "Description": eq[0].Description,
  178. }
  179. return response.json(0, res)
  180. else:
  181. return response.json(901)
  182. @csrf_exempt
  183. def downloadUpdataFileUrlInterface(request, fileType, fileName,
  184. *callback_args, **callback_kwargs):
  185. res = ResponseObject()
  186. if fileType is not None and fileName is not None:
  187. fullPath = os.path.join(BASE_DIR, "static/Upgrade/").replace('\\', '/')
  188. if fileType == 'IPC':
  189. fullPath += 'IPC/' + fileName
  190. elif fileType == 'DVR':
  191. fullPath += 'DVR/' + fileName
  192. elif fileType == 'NVR':
  193. fullPath += 'NVR/' + fileName
  194. elif fileType == 'XVR':
  195. fullPath += 'XVR/' + fileName
  196. elif fileType == 'User':
  197. fullPath = os.path.join(BASE_DIR, "static/").replace('\\', '/')
  198. fullPath += 'User/' + fileName
  199. elif fileType == 'ADCloud':
  200. fullPath = os.path.join(BASE_DIR, "static/APK/").replace('\\', '/')
  201. fullPath += 'ADCloud/' + fileName
  202. elif fileType == 'ACCloud':
  203. fullPath = os.path.join(BASE_DIR, "static/APK/").replace('\\', '/')
  204. fullPath += 'ACCloud/' + fileName
  205. else:
  206. fullPath += 'Other/' + fileName
  207. print(fullPath)
  208. if os.path.isfile(fullPath):
  209. try:
  210. JSON = res.formal(0)
  211. if fileType != 'User':
  212. wrapper = FileWrapper(open(fullPath, 'rb'))
  213. response = HttpResponse(wrapper, content_type="application/octet-stream")
  214. response['Content-Length'] = os.path.getsize(fullPath)
  215. response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(fullPath)
  216. response['Content-MD5'] = getMD5orSHA265(fullPath)
  217. # 校验文件md5值
  218. response['Content-SHA265'] = getMD5orSHA265(fullPath, 'SHA265')
  219. response['Content-CRC32'] = getMD5orSHA265(fullPath, 'CRC32')
  220. response['Content-Error'] = JSON
  221. return response
  222. else:
  223. Imagedata = open(fullPath, 'rb').read()
  224. response = HttpResponse(Imagedata, content_type="image/jpeg")
  225. return response
  226. except Exception as e:
  227. errorJSON = res.formal(906)
  228. response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8')
  229. response['Content-Error'] = errorJSON
  230. return response
  231. else:
  232. errorJSON = res.formal(907)
  233. response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8')
  234. response['Content-Error'] = errorJSON
  235. return response
  236. else:
  237. errorJSON = res.formal(444)
  238. response = HttpResponse(errorJSON, content_type='text/plain', charset='utf-8')
  239. response['Content-Error'] = errorJSON
  240. return response
  241. class getUploadFiletoDirView(TemplateView):
  242. @method_decorator(csrf_exempt)
  243. def dispatch(self, *args, **kwargs):
  244. return super(getUploadFiletoDirView, self).dispatch(*args, **kwargs)
  245. def post(self, request, *args, **kwargs):
  246. request.encoding = 'utf-8'
  247. request_dict = request.POST
  248. fileName = request.FILES.get('fileName', None)
  249. return self.ValidationError(request_dict, fileName)
  250. def get(self, request, *args, **kwargs):
  251. request.encoding = 'gb2312'
  252. request_dict = request.GET
  253. fileName = request.FILES.get('fileName', None)
  254. return self.ValidationError(request_dict, fileName)
  255. def ValidationError(self, request_dict, fileName):
  256. response = ResponseObject()
  257. token = request_dict.get('token', None)
  258. fileType = request_dict.get('fileType', None)
  259. fileCode = request_dict.get('fileCode', None)
  260. fileVersion = request_dict.get('fileVersion', None)
  261. if not fileName or not fileType:
  262. return response.json(444, 'fileName,fileType')
  263. tko = TokenObject(token)
  264. response.lang = tko.lang
  265. if tko.code != 0:
  266. return response.json(tko.code)
  267. userID = tko.userID
  268. if not userID:
  269. return response.json(104)
  270. own_perm = ModelService.check_perm(userID=userID, permID=210)
  271. if not own_perm:
  272. return response.json(404)
  273. if fileVersion != None and fileCode != None:
  274. return self.getUploadFiletoDir(userID, fileType, fileName, response, fileCode,
  275. fileVersion=fileVersion)
  276. else:
  277. return self.getUploadFiletoDir(userID, fileType, fileName, response)
  278. def getUploadFiletoDir(self, userID, fileType, fileName, response, *args, **kwargs):
  279. """
  280. 将上传的文件写入服务器对应目录下
  281. :param Type: equipment type
  282. :param fileName: File name of upgrade file.
  283. :return: filePath
  284. """
  285. User = Device_User.objects.filter(userID=userID)
  286. if not User:
  287. return response.json(104)
  288. own_perm = ModelService.check_perm(userID, permID=210)
  289. if own_perm is not True:
  290. return response.json(404)
  291. updataFile = fileName.name
  292. updataFile = updataFile.replace(' ', '+')
  293. versionIndex = updataFile.find('.', updataFile.find('.', updataFile.find('.') + 1) + 1)
  294. codeIndex = versionIndex + 12
  295. if codeIndex != -1 and versionIndex != -1:
  296. fileVersion = len(updataFile[1: versionIndex]) > 0 and updataFile[1: versionIndex] or None
  297. fileCode = len(updataFile[versionIndex + 1: codeIndex]) > 0 and \
  298. updataFile[versionIndex + 1: codeIndex] or None
  299. if fileCode is not None and fileVersion is not None:
  300. return self.getDir(fileType, fileName, fileCode, fileVersion, response)
  301. else:
  302. fileCode = kwargs.get('fileCode', None)
  303. fileVersion = kwargs.get('fileVersion', None)
  304. print(fileCode, fileVersion)
  305. if fileCode != None and fileVersion != None:
  306. return self.getDir(fileType, fileName, fileCode, fileVersion)
  307. else:
  308. return response.json(903)
  309. else:
  310. fileCode = kwargs.get('fileCode', None)
  311. fileVersion = kwargs.get('fileVersion', None)
  312. if fileCode != None and fileVersion != None:
  313. return self.getDir(fileType, fileName, fileCode, fileVersion, response)
  314. else:
  315. return response.json(903)
  316. def getDir(self, fileType, fileName, fileCode, fileVersion, response):
  317. try:
  318. if fileCode != None and fileVersion != None:
  319. path = '/'.join((BASE_DIR, 'static/Upgrade', fileType, fileCode, fileVersion)).replace('\\', '/') + '/'
  320. else:
  321. if fileType != 'IPC' and fileType != 'DVR' and fileType != 'NVR' and fileType != 'XVR':
  322. path = '/'.join((BASE_DIR, "static/Upgrade", 'Other')).replace('\\', '/') + '/'
  323. if not os.path.exists(path):
  324. os.makedirs(path)
  325. file_name = path + str(fileName)
  326. if os.path.exists(file_name):
  327. os.remove(file_name)
  328. destination = open(file_name, 'wb+')
  329. for chunk in fileName.chunks():
  330. destination.write(chunk)
  331. destination.close()
  332. else:
  333. file_name = path + str(fileName)
  334. if os.path.exists(file_name):
  335. os.remove(file_name)
  336. destination = open(file_name, 'wb+')
  337. for chunk in fileName.chunks():
  338. destination.write(chunk)
  339. destination.close()
  340. except Exception as e:
  341. errorInfo = traceback.format_exc()
  342. print('上传文件错误: %s' % errorInfo)
  343. return response.json(700, {'details': repr(e)})
  344. else:
  345. index = file_name.find('static/')
  346. filePath = file_name[index:]
  347. return response.json(0, {'filePath': filePath})
  348. @csrf_exempt
  349. def addNewEquipmentVersionInterface(request):
  350. request.encoding = 'utf-8'
  351. response = ResponseObject()
  352. if request.method == "POST":
  353. request_dict = request.POST
  354. elif request.method == "GET":
  355. request_dict = request.GET
  356. else:
  357. return response.json(444)
  358. deviceContent = request_dict.get('content', None).encode('utf-8')
  359. token = request_dict.get('token', None)
  360. file_s = request.FILES.get('file', None)
  361. deviceContent = str(deviceContent, encoding='utf-8')
  362. deviceContent = deviceContent.replace(' ', ' ').replace('\'', '\"')
  363. if deviceContent is None:
  364. return response.json(444, 'content')
  365. tko = TokenObject(token)
  366. response.lang = tko.lang
  367. if tko.code != 0:
  368. return response.json(tko.code)
  369. userID = tko.userID
  370. own_perm = ModelService.check_perm(userID=userID, permID=220)
  371. if own_perm is False:
  372. return response.json(404)
  373. try:
  374. deviceData = json.loads(deviceContent)
  375. version = deviceData.get('version', None)
  376. filePath = deviceData.get('filePath', None)
  377. code = deviceData.get('code', None)
  378. lang = deviceData.get('lang', None)
  379. if code and lang:
  380. try:
  381. Equipment_Version.objects.filter(code=code, lang=lang).delete()
  382. except Exception as e:
  383. pass
  384. if version is None or filePath is None:
  385. return response.json(444, 'content')
  386. deviceData['filePath'] = ','.join(filePath)
  387. paths = 'static/versions/image'
  388. if not os.path.exists(paths):
  389. os.makedirs(paths) # makedirs 创建文件时如果路径不存在会创建这个路径
  390. # print ('该文件不存在')
  391. else:
  392. print('该文件存在')
  393. print(file_s)
  394. if file_s is None:
  395. deviceData['img'] = ''
  396. else:
  397. rv_path = 'static/versions/image/' + code + '.png'
  398. try:
  399. as_path = os.path.join(BASE_DIR, rv_path)
  400. if os.path.exists(as_path):
  401. os.remove(as_path)
  402. with open(as_path, 'wb+') as destination:
  403. for chunk in file_s.chunks():
  404. destination.write(chunk)
  405. except Exception as e:
  406. pass
  407. else:
  408. deviceData['img'] = SERVER_DOMAIN + 'sysfile/' + rv_path
  409. ev_qs = Equipment_Version(
  410. eid=CommonService.getUserID(getUser=False, setOTAID=True),
  411. **deviceData)
  412. ev_qs.save()
  413. except Exception as e:
  414. return response.json(444, repr(e))
  415. else:
  416. res = CommonService.qs_to_dict([ev_qs])
  417. return response.json(0, res)
  418. def showAllEquipmentVersion(userID, response):
  419. userValid = Device_User.objects.filter(userID=userID).order_by('-data_joined')
  420. if not userValid.exists():
  421. return response.json(104)
  422. own_perm = ModelService.check_perm(userID=userID, permID=240)
  423. if not own_perm:
  424. return response.json(404)
  425. qs = Equipment_Version.objects.all()
  426. res = CommonService.qs_to_dict(qs)
  427. return response.json(0, res)
  428. # 检测ota更新包
  429. @csrf_exempt
  430. def getNewVerInterface(request):
  431. response = ResponseObject()
  432. if request.method == "POST":
  433. request_dict = request.POST
  434. elif request.method == "GET":
  435. request_dict = request.GET
  436. else:
  437. return response.json(404)
  438. code = request_dict.get('code', None)
  439. token = request_dict.get('token', None)
  440. lang = request_dict.get('lang', None)
  441. now_ver = request_dict.get('ver', None)
  442. uid = request_dict.get('uid', 'null')
  443. serial_number = request_dict.get('serial_number', 'null')
  444. if not code or not now_ver:
  445. return response.json(902, {'param': 'code,ver'})
  446. # return response.json(444, 'code,ver')
  447. tko = TokenObject(token)
  448. response.lang = tko.lang
  449. if tko.code != 0:
  450. return response.json(tko.code)
  451. if lang == 'zh-Hans' or lang == 'cn':
  452. equipmentValid = Equipment_Version.objects.filter(code=code, auto_update=False, status=1, lang='zh-Hans')\
  453. .order_by('-data_joined')
  454. else:
  455. equipmentValid = Equipment_Version.objects.filter(code=code, auto_update=False, status=1, lang='en').order_by(
  456. '-data_joined')
  457. logger = logging.getLogger('info')
  458. if equipmentValid.exists():
  459. equipment = equipmentValid[0]
  460. redisObject = RedisObject()
  461. key = 'limit_{eid}'.format(eid=equipment.eid)
  462. evl_qs = redisObject.get_data(key=key)
  463. if evl_qs:
  464. evl_qs = json.loads(evl_qs)
  465. else:
  466. evl_qs = EquipmentVersionLimitModel.objects.filter(equipment_version_id=equipment.eid, status=1).values()
  467. if evl_qs.exists():
  468. redisObject.set_data(key=key, val=json.dumps(list(evl_qs.values())), expire=600)
  469. if evl_qs and len(evl_qs) > 0:
  470. evl = evl_qs[0]
  471. if evl['type'] == 1: # uid限制
  472. uids = json.loads(evl['content'])
  473. if not uids.__contains__(uid):
  474. return response.json(902)
  475. elif evl['type'] == 2: # user限制
  476. users = json.loads(evl['content'])
  477. if not users.__contains__(tko.userID):
  478. return response.json(902)
  479. elif evl['type'] == 3: # 国家地区限制
  480. countries = json.loads(evl['content'])
  481. country_ip_qs = CountryIPModel.objects.filter(user_ex__userID=tko.userID)
  482. if country_ip_qs.exists():
  483. country = country_ip_qs[0].country
  484. else:
  485. country = CommonService.getAddr(CommonService.get_ip_address(request))
  486. if not countries.__contains__(country):
  487. return response.json(902)
  488. file_path = equipment.filePath
  489. version = equipment.version
  490. mci = equipment.mci
  491. ver = equipment.softwareVersion
  492. max_ver = equipment.max_ver
  493. print(now_ver <= max_ver)
  494. now_stamp = int(time.time())
  495. if now_ver <= max_ver:
  496. ver_result = check_version(uid, tko.userID, equipment.data_json)
  497. if not ver_result: # 当前设备对应版本号不显示最新版本
  498. return response.json(902)
  499. # 创建url的token
  500. param_url = "ansjer/" + CommonService.RandomStr(6) + "/" + file_path
  501. data = {'Url': param_url, 'user_id': tko.userID,
  502. 'uid': uid, 'serial_number': serial_number, 'old_version': "V" + now_ver + "." + code,
  503. 'new_version': version, 'mci': mci}
  504. device_info_value = json.dumps(data)
  505. expire = 600
  506. str_uuid = str(tko.userID)
  507. if serial_number and serial_number != 'null':
  508. str_uuid += serial_number
  509. elif uid and uid != 'null':
  510. str_uuid += uid
  511. str_uuid += now_ver
  512. device_info_key = 'ASJ:SERVER:VERSION:{}'.format(str_uuid)
  513. logger.info('缓存key={}'.format(device_info_key))
  514. redisObject.set_data(device_info_key, device_info_value, expire)
  515. url_tko = UrlTokenObject()
  516. file_path = url_tko.generate(data={'uid': str_uuid})
  517. url = SERVER_DOMAIN + 'dlotapack/' + file_path
  518. logger.info('<<<<<<<URL={}'.format(url))
  519. # if SERVER_TYPE == 'Ansjer.formal_settings':
  520. # url = SERVER_DOMAIN + 'dlotapack/' + file_path
  521. # else:
  522. # 这里调用国内服务器进行下载,防止下载bug
  523. # if code == '18E201200CA' or code == '18E201200CZ':
  524. # url = 'http://www.zositech.xyz/dlotapack/' + file_path
  525. # else:
  526. # url = SERVER_DOMAIN + 'dlotapack/' + file_path
  527. result = {
  528. 'ver': ver,
  529. 'url': url,
  530. 'Description': equipment.Description,
  531. 'isPopup': equipment.is_popup
  532. }
  533. logger.info('<<<<<响应结果{}'.format(result))
  534. return response.json(0, result)
  535. else:
  536. return response.json(902)
  537. else:
  538. return response.json(902)
  539. def check_version(uid, user_id, ver_data):
  540. """
  541. :param uid: 设备UID
  542. :param user_id: 用户id
  543. :param ver_data: 版本指定升级数据
  544. :return: True | False
  545. """
  546. try:
  547. if not ver_data: # 默认当前版本所有设备
  548. return True
  549. if uid and ver_data['uid_list']: # 当前版本指定UID
  550. return uid in ver_data['uid_list']
  551. # 最新版本 过滤国家并且不是国内或者测试服
  552. if user_id and ver_data['country_list'] and CONFIG_INFO not in [CONFIG_CN, CONFIG_TEST]:
  553. user_qs = Device_User.objects.filter(userID=user_id).values('region_country')
  554. if not user_qs.exists(): # 用户不存在不升级
  555. return False
  556. if user_qs[0]['region_country'] == 0: # 用户未选择国家 不进行升级提示
  557. return False
  558. return user_qs[0]['region_country'] in ver_data['country_list']
  559. # 中国区可指定城市进行升级
  560. if ver_data['addr'] and CONFIG_INFO in [CONFIG_CN, CONFIG_TEST]:
  561. city_list = ver_data['addr']['city_list']
  562. if not city_list:
  563. return True
  564. uid_set_qs = UidSetModel.objects.filter(uid=uid).values('ip')
  565. if not uid_set_qs:
  566. return False
  567. ip_qs = IPAddr.objects.filter(ip=uid_set_qs[0]['ip']).values('city').order_by('-id')
  568. if not ip_qs:
  569. return False
  570. return ip_qs[0]['city'] in city_list
  571. return True
  572. except Exception as e:
  573. print(repr(e))
  574. return True
  575. # ota包上传
  576. class uploadOTAInterfaceView(TemplateView):
  577. @method_decorator(csrf_exempt)
  578. def dispatch(self, *args, **kwargs):
  579. return super(uploadOTAInterfaceView, self).dispatch(*args, **kwargs)
  580. def post(self, request, *args, **kwargs):
  581. request.encoding = 'utf-8'
  582. token = request.POST.get('token', None)
  583. fileName = request.FILES.get('fileName', None)
  584. fileType = request.POST.get('fileType', None)
  585. language = request.POST.get('language', None)
  586. return self.validate(token, fileName, fileType, language)
  587. def get(self, request, *args, **kwargs):
  588. request.encoding = 'gb2312'
  589. token = request.GET.get('token', None)
  590. fileName = request.FILES.get('fileName', None)
  591. fileType = request.GET.get('fileType', None)
  592. language = request.GET.get('language', None)
  593. return self.validate(token, fileName, fileType, language)
  594. def validate(self, token, fileName, fileType, language):
  595. response = ResponseObject()
  596. if not fileName or not fileType:
  597. return response.json(444, 'fileName,fileType')
  598. tko = TokenObject(token)
  599. response.lang = tko.lang
  600. if tko.code != 0:
  601. return response.json(tko.code)
  602. userID = tko.userID
  603. if not userID:
  604. return response.json(104)
  605. own_permission = ModelService.check_perm(userID=userID, permID=210)
  606. if own_permission is not True:
  607. return response.json(404)
  608. return self.upload_ota_file(fileName, response, fileType, language)
  609. def upload_ota_file(self, fileName, response, fileType, language):
  610. try:
  611. if not language:
  612. language = 0
  613. path = '/'.join((BASE_DIR, 'static/otapack', fileType, str(language))).replace('\\', '/') + '/'
  614. if not os.path.exists(path):
  615. os.makedirs(path)
  616. file_name = path + str(fileName)
  617. if os.path.exists(file_name):
  618. os.remove(file_name)
  619. destination = open(file_name, 'wb+')
  620. for chunk in fileName.chunks():
  621. destination.write(chunk)
  622. destination.close()
  623. else:
  624. file_name = path + str(fileName)
  625. if os.path.exists(file_name):
  626. os.remove(file_name)
  627. destination = open(file_name, 'wb+')
  628. for chunk in fileName.chunks():
  629. destination.write(chunk)
  630. destination.close()
  631. except Exception as e:
  632. errorInfo = traceback.format_exc()
  633. print('上传文件错误: %s' % errorInfo)
  634. return response.json(700, {'details': repr(e)})
  635. else:
  636. index = file_name.find('static/')
  637. filePath = file_name[index:]
  638. return response.json(0, {'filePath': filePath})
  639. # ota包下载
  640. @csrf_exempt
  641. def downloadOTAInterface(request, fullPath, *callback_args, **callback_kwargs):
  642. res = ResponseObject()
  643. print('fullPath:')
  644. print(fullPath)
  645. if fullPath:
  646. if os.path.isfile(fullPath):
  647. try:
  648. wrapper = FileWrapper(open(fullPath, 'rb'))
  649. response = HttpResponse(wrapper, content_type="application/octet-stream")
  650. response['Content-Length'] = os.path.getsize(fullPath)
  651. response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(fullPath)
  652. response['Content-MD5'] = getMD5orSHA265(fullPath)
  653. # 校验文件md5值
  654. response['Content-SHA265'] = getMD5orSHA265(fullPath, 'SHA265')
  655. response['Content-CRC32'] = getMD5orSHA265(fullPath, 'CRC32')
  656. response['Content-Error'] = res.formal(0)
  657. return response
  658. except Exception as e:
  659. return res.json(906, repr(e))
  660. else:
  661. return res.json(907)
  662. else:
  663. return res.json(444, 'fullPath')
  664. # ota包下载
  665. @csrf_exempt
  666. def downloadOTAInterfaceV2(request, fullPath, *callback_args, **callback_kwargs):
  667. res = ResponseObject()
  668. # print('fullPath:%s' % fullPath)
  669. # 解密url的token
  670. url_token = UrlTokenObject(fullPath)
  671. # fp = url_token.Url
  672. # serial_number = url_token.serial_number
  673. # uid = url_token.uid
  674. # user_id = url_token.user_id
  675. # mci = url_token.mci
  676. # old_version = url_token.old_version
  677. # new_version = url_token.new_version
  678. str_uuid = url_token.uid
  679. logger = logging.getLogger('info')
  680. logger.info('<<<<<进入OTA下载')
  681. redis_object = RedisObject()
  682. logger.info(str_uuid)
  683. device_key = 'ASJ:SERVER:VERSION:{}'.format(str_uuid)
  684. device_value = redis_object.get_data(device_key)
  685. logger.info(device_value)
  686. if not device_value:
  687. return res.json(907)
  688. device_dist = json.loads(device_value)
  689. logger.info('<<<<<解析={}'.format(device_dist))
  690. fp = device_dist['Url']
  691. serial_number = device_dist['serial_number']
  692. uid = device_dist['uid']
  693. user_id = device_dist['user_id']
  694. mci = device_dist['mci']
  695. old_version = device_dist['old_version']
  696. new_version = device_dist['new_version']
  697. if '' == fp:
  698. return res.json(907)
  699. fullPath = fp[14:]
  700. if fullPath:
  701. if os.path.isfile(fullPath):
  702. try:
  703. wrapper = FileWrapper(open(fullPath, 'rb'))
  704. response = HttpResponse(wrapper, content_type="application/octet-stream")
  705. response['Content-Length'] = os.path.getsize(fullPath)
  706. response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(fullPath)
  707. response['Content-MD5'] = getMD5orSHA265(fullPath)
  708. # 校验文件md5值
  709. response['Content-SHA265'] = getMD5orSHA265(fullPath, 'SHA265')
  710. response['Content-CRC32'] = getMD5orSHA265(fullPath, 'CRC32')
  711. response['Content-Error'] = res.formal(0)
  712. # 设备下载OTA包,记录数据库
  713. # 记录设备OTA升级
  714. createdTime = int(time.time())
  715. DeviceOTAUpgradeRecord.objects.create(
  716. created_time=createdTime,
  717. old_version=old_version,
  718. new_version=new_version,
  719. user_id=user_id,
  720. serial_number=serial_number,
  721. uid=uid,
  722. mci=mci,
  723. )
  724. return response
  725. except Exception as e:
  726. return res.json(906, repr(e))
  727. else:
  728. return res.json(907)
  729. else:
  730. return res.json(444, 'fullPath')
  731. @csrf_exempt
  732. def getDownLoadOTApackUrl(request):
  733. # QT获取升级文件的下载链接
  734. response = ResponseObject()
  735. if request.method == "POST":
  736. request_dict = request.POST
  737. elif request.method == "GET":
  738. request_dict = request.GET
  739. else:
  740. return response.json(444)
  741. deviceType = request_dict.get('deviceType', None)
  742. version = request_dict.get('version', None)
  743. if not deviceType or not version:
  744. return response.json(444, 'deviceType or version')
  745. equipmentVersion = Equipment_Version.objects.filter(mci=deviceType, version=version)
  746. # 判断是否有该版本存在
  747. if not equipmentVersion.exists():
  748. return response.json(907)
  749. file_path = equipmentVersion[0].filePath
  750. if file_path:
  751. if file_path.find('static/otapack') != -1: # 只下载otapack路径下的文件
  752. url = SERVER_DOMAIN + 'OTA/downloadsPack/' + file_path # 复用app下载ota包的方式
  753. # SERVER_DOMAIN = 'https://test.dvema.com/'
  754. # url = SERVER_DOMAIN + 'OTA/downloadsPack/' + file_path
  755. res = {
  756. "url": url,
  757. }
  758. return response.json(0, res)
  759. else:
  760. return response.json(901)
  761. else:
  762. return response.json(901)
  763. @csrf_exempt
  764. def checkMaxVersion(request):
  765. # QT检查ota设备软件版本是否需要更新
  766. response = ResponseObject()
  767. if request.method == "POST":
  768. request_dict = request.POST
  769. elif request.method == "GET":
  770. request_dict = request.GET
  771. else:
  772. return response.json(444)
  773. deviceType = request_dict.get('deviceType', None)
  774. version = request_dict.get('version', None) # 设备版本:当前版本+设备规格代码
  775. lang = request_dict.get('lang', None) # 'zh-Hans','en'
  776. if not deviceType or not version:
  777. return response.json(444, 'deviceType or version')
  778. now_version = version[1:version.rindex('.')] # 去掉V
  779. code = version[version.rindex('.') + 1:]
  780. equipmentVersion = Equipment_Version.objects.filter(mci=deviceType, code=code, lang=lang,
  781. status=1) # order by data_joined
  782. # 判断是否有该版本存在
  783. if not equipmentVersion.exists():
  784. return response.json(907)
  785. filePath = equipmentVersion[0].filePath
  786. softwareVersion = equipmentVersion[0].softwareVersion # 可用最新版本的版本号
  787. maxVersion = equipmentVersion[0].max_ver
  788. if now_version >= softwareVersion:
  789. # 当前版本大于等于最新版本,不需要更新
  790. return response.json(902)
  791. url = SERVER_DOMAIN + 'OTA/downloadsPack/' + filePath # 复用app下载ota包的方式
  792. res = {
  793. 'url': url,
  794. }
  795. return response.json(0, res)