IcloudService.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. # -*- coding: utf-8 -*-
  2. """
  3. @Author : peng
  4. @Time : 2023-6-7 18:26:35
  5. @File :IcloudMeal.py
  6. """
  7. import logging
  8. import time
  9. from django.db.models import Sum, Q
  10. from django.http import HttpResponse
  11. from django.views import View
  12. from Model.models import IcloudUseDetails, IcloudService, VodBucketModel, IcloudStorageRecord, Device_Info
  13. from Object.AWS.AmazonS3Util import AmazonS3Util
  14. from Object.RedisObject import RedisObject
  15. from Object.ResponseObject import ResponseObject
  16. from Object.TokenObject import TokenObject
  17. from Ansjer.config import ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME, SERVER_DOMAIN, AWS_ACCESS_KEY_ID, \
  18. AWS_SECRET_ACCESS_KEY
  19. from Service.VodHlsService import SplitVodHlsObject
  20. logger = logging.getLogger('info')
  21. class IcloudServiceView(View):
  22. def get(self, request, *args, **kwargs):
  23. request.encoding = 'utf-8'
  24. operation = kwargs.get('operation')
  25. return self.validation(request.GET, operation, request)
  26. def post(self, request, *args, **kwargs):
  27. request.encoding = 'utf-8'
  28. operation = kwargs.get('operation')
  29. return self.validation(request.POST, operation, request)
  30. def validation(self, request_dict, operation, request):
  31. response = ResponseObject()
  32. tko = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
  33. response.lang = tko.lang
  34. user_id = tko.userID
  35. if tko.code != 0:
  36. return response.json(tko.code)
  37. if operation == 'vodUpload': # 云存上传云盘
  38. return self.vod_upload(request_dict, response, user_id)
  39. elif operation == 'getUploadUrl': # 获取s3上传地址
  40. return self.get_upload_url(request_dict, response, user_id)
  41. elif operation == 'localUpload': # 本地上传云盘
  42. return self.local_upload(request_dict, response, user_id)
  43. else:
  44. return response.json(404)
  45. @staticmethod
  46. def vod_upload(request_dict, response, user_id):
  47. """
  48. 云存上传云盘
  49. @param request_dict: 请求参数
  50. @param user_id: 用户id
  51. @request_dict uid: 设备uid
  52. @request_dict channel: 设备通道
  53. @request_dict start_time: 播放时间戳
  54. @param response: 响应对象
  55. @return: response
  56. """
  57. logger.info('开始云存转移到云盘')
  58. uid = request_dict.get('uid', None)
  59. channel = request_dict.get('channel', None)
  60. time_stamp = request_dict.get('time_stamp', None)
  61. if not all([uid, channel, time_stamp]):
  62. return response.json(444, {'error param': 'uid,channel,start_time'})
  63. device_qs = Device_Info.objects.filter(UID=uid, userID=user_id).values('NickName')
  64. if not device_qs.exists():
  65. return response.json(173)
  66. # 查询是否开通云盘
  67. use_details_qs = IcloudUseDetails.objects.filter(user_id=user_id).values('id', 'bucket_id', 'use_size')
  68. if not use_details_qs.exists():
  69. return response.json(173)
  70. use_details_id = use_details_qs[0]['id']
  71. target_bucket_id = use_details_qs[0]['bucket_id']
  72. use_size = float(use_details_qs[0]['use_size'])
  73. now_time = int(time.time())
  74. nickname = device_qs[0]['NickName']
  75. # 判断云盘是否还有容量
  76. all_size = IcloudService.objects.filter(Q(use_details_id=use_details_id), Q(use_status=0),
  77. Q(end_time__gt=now_time) | Q(end_time=0)).values(
  78. 'size').aggregate(total_size=Sum('size'))['total_size']
  79. all_size = all_size * 1024 if all_size else 0
  80. if use_size > all_size:
  81. logger.info('{}用户套餐总容量为:{},已使用容量为:{}'.format(uid, all_size, use_size))
  82. return response.json(910)
  83. split_vod_hls_obj = SplitVodHlsObject()
  84. vod_hls = split_vod_hls_obj.get_vod_hls_data(uid=uid, channel=channel, start_time=time_stamp).values(
  85. 'bucket_id', 'fg', 'sec')
  86. if not vod_hls.exists():
  87. logger.info('{}用户查无此云存:{}'.format(uid, time_stamp))
  88. return response.json(173)
  89. source_bucket_id = vod_hls[0]['bucket_id']
  90. fg = int(vod_hls[0]['fg'])
  91. sec = vod_hls[0]['sec']
  92. target_bucket_qs = VodBucketModel.objects.filter(id=target_bucket_id).values('bucket')
  93. if not target_bucket_qs.exists():
  94. return response.json(173)
  95. target_bucket_name = target_bucket_qs[0]['bucket']
  96. source_bucket_qs = VodBucketModel.objects.filter(id=source_bucket_id).values('bucket', 'region', 'mold')
  97. if not source_bucket_qs.exists():
  98. return response.json(173)
  99. bucket_region = source_bucket_qs[0]['region']
  100. source_bucket_name = source_bucket_qs[0]['bucket']
  101. mold = source_bucket_qs[0]["mold"]
  102. ts_list = []
  103. ts_size = 0
  104. try:
  105. s3_obj = AmazonS3Util(
  106. AWS_ACCESS_KEY_ID[mold],
  107. AWS_SECRET_ACCESS_KEY[mold],
  108. bucket_region
  109. )
  110. # 获取s3对象,并计算总字节
  111. for i in range(15):
  112. shift = (i + 1) * 4
  113. duration = (fg >> shift) & 0xf
  114. if duration > 0:
  115. ts_file = '{uid}/vod{channel}/{time}/ts{i}.ts'.format(uid=uid, channel=channel, time=time_stamp,
  116. i=i)
  117. ts_list.append(ts_file)
  118. ts_size += s3_obj.get_object_size(source_bucket_name, ts_file) # 获取存储对象字节,单位B
  119. ts_size = round(ts_size / 1024 / 1024, 2) # 字节转换为MB单位
  120. temp_size = ts_size + use_size
  121. if temp_size > all_size:
  122. logger.info('{}用户无空间上传,套餐容量为:{},使用容量为:{}'.format(uid, all_size, temp_size))
  123. return response.json(910)
  124. time_stamp = int(time_stamp) * 1000 # 转换单位为毫秒
  125. icloud_record_qs = IcloudStorageRecord.objects.filter(user_id=user_id, uid=uid, channel=channel,
  126. time_stamp=time_stamp,
  127. size=ts_size, store_type=1)
  128. if not icloud_record_qs.exists(): # 转移云盘,并记录上传记录,更新使用容量
  129. for source_key in ts_list:
  130. ts_name = source_key.split('/')[-1]
  131. target_key = '{user_id}/ts_file/{uid}/vod{channel}/{time}/{ts_name}'.format(user_id=user_id,
  132. uid=uid,
  133. channel=channel,
  134. time=time_stamp,
  135. ts_name=ts_name)
  136. s3_obj.copy_single_obj(source_bucket_name, source_key, target_bucket_name, target_key)
  137. IcloudStorageRecord.objects.create(user_id=user_id, uid=uid, channel=channel, time_stamp=time_stamp,
  138. nickname=nickname,
  139. sec=sec, bucket_id=target_bucket_id, fg=fg, size=ts_size,
  140. store_type=1)
  141. use_details_qs.update(use_size=temp_size)
  142. return response.json(0)
  143. else:
  144. return response.json(174)
  145. except Exception as e:
  146. logger.info('云存转移云盘异常:{}'.format(repr(e)))
  147. return response.json(500)
  148. @staticmethod
  149. def local_upload(request_dict, response, user_id):
  150. """
  151. 本地上传云盘
  152. @param request_dict: 请求参数
  153. @param user_id: 用户id
  154. @request_dict serial_number: 序列号
  155. @param response: 响应对象
  156. @return: response
  157. """
  158. logger.info('开始云存转移到云盘')
  159. uid = request_dict.get('uid', None)
  160. channel = request_dict.get('channel', None)
  161. start_time = request_dict.get('start_time', None)
  162. if not all([uid, channel, start_time]):
  163. return response.json(444, {'error param': 'uid,channel,start_time'})
  164. device_qs = Device_Info.objects.filter(UID=uid, userID=user_id).values('NickName')
  165. if not device_qs.exists():
  166. return response.json(173)
  167. # 查询是否开通云盘
  168. use_details_qs = IcloudUseDetails.objects.filter(user_id=user_id).values('id', 'bucket_id', 'use_size')
  169. if not use_details_qs.exists():
  170. return response.json(173)
  171. use_details_id = use_details_qs[0]['id']
  172. target_bucket_id = use_details_qs[0]['bucket_id']
  173. use_size = float(use_details_qs[0]['use_size'])
  174. now_time = int(time.time())
  175. nickname = device_qs[0]['NickName']
  176. # 判断云盘是否还有容量
  177. all_size = IcloudService.objects.filter(Q(use_details_id=use_details_id), Q(use_status=0),
  178. Q(end_time__gt=now_time) | Q(end_time=0)).values(
  179. 'size').aggregate(total_size=Sum('size'))['total_size']
  180. all_size = all_size * 1024 if all_size else 0
  181. if use_size > all_size:
  182. logger.info('{}用户套餐总容量为:{},已使用容量为:{}'.format(uid, all_size, use_size))
  183. return response.json(910)
  184. split_vod_hls_obj = SplitVodHlsObject()
  185. vod_hls = split_vod_hls_obj.get_vod_hls_data(uid=uid, channel=channel, start_time=start_time).values(
  186. 'bucket_id', 'fg', 'sec')
  187. if not vod_hls.exists():
  188. logger.info('{}用户查无此云存:{}'.format(uid, start_time))
  189. return response.json(173)
  190. source_bucket_id = vod_hls[0]['bucket_id']
  191. fg = int(vod_hls[0]['fg'])
  192. sec = vod_hls[0]['sec']
  193. target_bucket_qs = VodBucketModel.objects.filter(id=target_bucket_id).values('bucket')
  194. if not target_bucket_qs.exists():
  195. return response.json(173)
  196. target_bucket_name = target_bucket_qs[0]['bucket']
  197. source_bucket_qs = VodBucketModel.objects.filter(id=source_bucket_id).values('bucket', 'region', 'mold')
  198. if not source_bucket_qs.exists():
  199. return response.json(173)
  200. bucket_region = source_bucket_qs[0]['region']
  201. source_bucket_name = source_bucket_qs[0]['bucket']
  202. mold = source_bucket_qs[0]["mold"]
  203. ts_list = []
  204. ts_size = 0
  205. try:
  206. s3_obj = AmazonS3Util(
  207. AWS_ACCESS_KEY_ID[mold],
  208. AWS_SECRET_ACCESS_KEY[mold],
  209. bucket_region
  210. )
  211. # 获取s3对象,并计算总字节
  212. for i in range(15):
  213. shift = (i + 1) * 4
  214. duration = (fg >> shift) & 0xf
  215. if duration > 0:
  216. ts_file = '{uid}/vod{channel}/{time}/ts{i}.ts'.format(uid=uid, channel=channel, time=start_time,
  217. i=i)
  218. ts_list.append(ts_file)
  219. ts_size += s3_obj.get_object_size(source_bucket_name, ts_file) # 获取存储对象字节,单位B
  220. ts_size = round(ts_size / 1024 / 1024, 2) # 字节转换为MB单位
  221. temp_size = ts_size + use_size
  222. if temp_size > all_size:
  223. logger.info('{}用户无空间上传,套餐容量为:{},使用容量为:{}'.format(uid, all_size, temp_size))
  224. return response.json(910)
  225. start_time = int(start_time) * 1000 # 转换单位为毫秒
  226. icloud_record_qs = IcloudStorageRecord.objects.filter(user_id=user_id, uid=uid, channel=channel,
  227. time_stamp=start_time,
  228. size=ts_size, store_type=1)
  229. if not icloud_record_qs.exists(): # 转移云盘,并记录上传记录,更新使用容量
  230. for source_key in ts_list:
  231. ts_name = source_key.split('/')[-1]
  232. target_key = '{user_id}/ts_file/{uid}/vod{channel}/{time}/{ts_name}'.format(user_id=user_id,
  233. uid=uid,
  234. channel=channel,
  235. time=start_time,
  236. ts_name=ts_name)
  237. s3_obj.copy_single_obj(source_bucket_name, source_key, target_bucket_name, target_key)
  238. IcloudStorageRecord.objects.create(user_id=user_id, uid=uid, channel=channel, time_stamp=start_time,
  239. nickname=nickname,
  240. sec=sec, bucket_id=target_bucket_id, fg=fg, size=ts_size,
  241. store_type=1)
  242. use_details_qs.update(use_size=temp_size)
  243. return response.json(0)
  244. else:
  245. return response.json(174)
  246. except Exception as e:
  247. logger.info('云存转移云盘异常:{}'.format(repr(e)))
  248. return response.json(500)
  249. @staticmethod
  250. def get_upload_url(request_dict, response, user_id):
  251. """
  252. 获取s3上传地址
  253. @param request_dict: 请求参数
  254. @param user_id: 用户id
  255. @request_dict serial_number: 序列号
  256. @param response: 响应对象
  257. @return: response
  258. """
  259. logger.info('获取s3上传地址')
  260. time_stamp = request_dict.get('time_stamp', None)
  261. file_type = request_dict.get('file_type', None)
  262. uid = request_dict.get('uid', None)
  263. channel = request_dict.get('channel', None)
  264. if not all([time_stamp, uid, channel]):
  265. return response.json(444, {'error param': 'time_stamp,channel,uid'})
  266. device_qs = Device_Info.objects.filter(UID=uid, userID=user_id)
  267. if not device_qs.exists():
  268. return response.json(173)
  269. # 查询是否开通云盘
  270. use_details_qs = IcloudUseDetails.objects.filter(user_id=user_id).values('id', 'use_size', 'bucket_id')
  271. if not use_details_qs.exists():
  272. return response.json(173)
  273. use_details_id = use_details_qs[0]['id']
  274. use_size = use_details_qs[0]['use_size']
  275. bucket_id = use_details_qs[0]['bucket_id']
  276. now_time = int(time.time())
  277. # 判断云盘是否还有容量
  278. all_size = IcloudService.objects.filter(Q(use_details_id=use_details_id), Q(use_status=0),
  279. Q(end_time__gt=now_time) | Q(end_time=0)).values(
  280. 'size').aggregate(total_size=Sum('size'))['total_size']
  281. all_size = all_size * 1024 if all_size else 0
  282. excess_size = all_size - use_size
  283. if excess_size < 0:
  284. logger.info('{}用户套餐总容量为:{},已使用容量为:{}'.format(user_id, all_size, use_size))
  285. return response.json(910)
  286. bucket_qs = VodBucketModel.objects.filter(id=bucket_id).values('bucket', 'region', 'mold')
  287. if not bucket_qs.exists():
  288. return response.json(173)
  289. bucket_name = bucket_qs[0]['bucket']
  290. bucket_region = bucket_qs[0]['region']
  291. mold = bucket_qs[0]['mold']
  292. try:
  293. s3_obj = AmazonS3Util(
  294. AWS_ACCESS_KEY_ID[mold],
  295. AWS_SECRET_ACCESS_KEY[mold],
  296. bucket_region
  297. )
  298. if file_type == '0': # 图片
  299. key_name = '{user_id}/image_file/{uid}/{channel}/{time}/{time}.jpg'.format(user_id=user_id, uid=uid,
  300. channel=channel,
  301. time=time_stamp)
  302. elif file_type == '2':
  303. key_name = '{user_id}/mp4_file/{uid}/{channel}/{time}/{time}.mp4'.format(user_id=user_id, uid=uid,
  304. channel=channel,
  305. time=time_stamp)
  306. else:
  307. return response.json(444, {'error param': 'file_type'})
  308. upload_url = s3_obj.generate_put_obj_url(bucket_name, key_name)
  309. return response.json(0, {'uploadUrl': upload_url, 'excessSize': excess_size})
  310. except Exception as e:
  311. logger.info('获取s3上传地址异常:{}'.format(repr(e)))
  312. return response.json(500)