DeviceCustomUIDController.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import time
  2. from MySQLdb import DatabaseError
  3. from django.db import transaction
  4. from django.http import QueryDict
  5. from django.views import View
  6. from Ansjer.config import LOGGER
  7. from AgentModel.models import DeviceCustomUID, CustomUIDPool
  8. from Object.ResponseObject import ResponseObject
  9. from Service.CommonService import CommonService
  10. from Object.RedisObject import RedisObject
  11. class DeviceCustomUIDView(View):
  12. def get(self, request, *args, **kwargs):
  13. request.encoding = 'utf-8'
  14. operation = kwargs.get('operation')
  15. return self.validation(request.GET, request, operation)
  16. def post(self, request, *args, **kwargs):
  17. request.encoding = 'utf-8'
  18. operation = kwargs.get('operation')
  19. return self.validation(request.POST, request, operation)
  20. def delete(self, request, *args, **kwargs):
  21. request.encoding = 'utf-8'
  22. operation = kwargs.get('operation')
  23. delete = QueryDict(request.body)
  24. if not delete:
  25. delete = request.GET
  26. return self.validation(delete, request, operation)
  27. def put(self, request, *args, **kwargs):
  28. request.encoding = 'utf-8'
  29. operation = kwargs.get('operation')
  30. put = QueryDict(request.body)
  31. return self.validation(put, request, operation)
  32. def validation(self, request_dict, request, operation):
  33. response = ResponseObject('en')
  34. if operation == 'getUID': # 获取电池电量列表
  35. return self.get_custom_uid(request, request_dict, response)
  36. @classmethod
  37. def get_custom_uid(cls, request, request_dict, response):
  38. ip = CommonService.get_ip_address(request)
  39. LOGGER.info('获取定制客户UID:{},ip:{}'.format(request_dict, ip))
  40. mac = request_dict.get('mac', None)
  41. token = request_dict.get('token', None)
  42. time_stamp = request_dict.get('time_stamp', None)
  43. if not all([mac, token, time_stamp]):
  44. LOGGER.error(f'{mac}请求绑定uid参数缺失')
  45. return response.json(444)
  46. # 时间戳token校验
  47. if not CommonService.check_time_stamp_token(token, time_stamp):
  48. LOGGER.error(f'{mac}时间戳校验失败time:{time_stamp},tk:{token}')
  49. return response.json(13)
  50. # 分布式锁配置
  51. redis = RedisObject()
  52. lock_key = f"uid_assign:{mac}"
  53. request_id = f"{mac}_{time_stamp}"
  54. try:
  55. # 第一次检查现有绑定
  56. existing_binding = DeviceCustomUID.objects.filter(
  57. device_mac=mac,
  58. status=1
  59. ).select_related('uid').first()
  60. if existing_binding:
  61. LOGGER.info(f'{mac}已存在有效绑定')
  62. return response.json(0, data={'uid': existing_binding.uid.uid})
  63. # 获取分布式锁(设置5秒过期时间)
  64. if not redis.try_lock(lock_key, request_id, expire=5, time_unit_second=1):
  65. LOGGER.error(f'{mac}获取锁失败')
  66. return response.json(5)
  67. # 二次检查(防止在等待锁期间被其他请求处理)
  68. existing_binding = DeviceCustomUID.objects.filter(
  69. device_mac=mac,
  70. status=1
  71. ).select_related('uid').first()
  72. if existing_binding:
  73. LOGGER.info(f'{mac}二次检查存在绑定')
  74. return response.json(0, data={'uid': existing_binding.uid.uid})
  75. # 核心分配逻辑
  76. with transaction.atomic():
  77. # 获取可用UID(使用SELECT FOR UPDATE锁定行)
  78. available_uid = CustomUIDPool.objects.select_for_update() \
  79. .filter(status=0) \
  80. .order_by('id') \
  81. .first()
  82. if not available_uid:
  83. LOGGER.error(f'{mac}UID池已耗尽')
  84. return response.json(173)
  85. # 更新UID状态
  86. n_time = int(time.time())
  87. available_uid.status = 1
  88. available_uid.updated_time = n_time
  89. available_uid.save(update_fields=['status', 'updated_time'])
  90. # 创建绑定记录
  91. DeviceCustomUID.objects.create(
  92. uid=available_uid,
  93. device_mac=mac,
  94. status=1,
  95. created_time=n_time,
  96. updated_time=n_time
  97. )
  98. LOGGER.info(f'{mac}成功分配UID: {available_uid.uid}')
  99. return response.json(0, data={'uid': available_uid.uid})
  100. except DatabaseError as e:
  101. LOGGER.error(f'{mac}数据库操作异常: {str(e)}')
  102. return response.json(18)
  103. except Exception as e:
  104. LOGGER.error(f'系统异常: {str(e)}')
  105. return response.json(500)
  106. finally:
  107. # 确保释放锁
  108. if redis.release_lock(lock_key, request_id):
  109. LOGGER.debug(f'{mac}锁释放成功')
  110. else:
  111. LOGGER.warning(f'{mac}锁释放异常')