IcloudService.py 18 KB

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