123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- import time
- from MySQLdb import DatabaseError
- from django.db import transaction
- from django.http import QueryDict
- from django.views import View
- from Ansjer.config import LOGGER
- from AgentModel.models import DeviceCustomUID, CustomUIDPool
- from Object.ResponseObject import ResponseObject
- from Service.CommonService import CommonService
- from Object.RedisObject import RedisObject
- class DeviceCustomUIDView(View):
- def get(self, request, *args, **kwargs):
- request.encoding = 'utf-8'
- operation = kwargs.get('operation')
- return self.validation(request.GET, request, operation)
- def post(self, request, *args, **kwargs):
- request.encoding = 'utf-8'
- operation = kwargs.get('operation')
- return self.validation(request.POST, request, operation)
- def delete(self, request, *args, **kwargs):
- request.encoding = 'utf-8'
- operation = kwargs.get('operation')
- delete = QueryDict(request.body)
- if not delete:
- delete = request.GET
- return self.validation(delete, request, operation)
- def put(self, request, *args, **kwargs):
- request.encoding = 'utf-8'
- operation = kwargs.get('operation')
- put = QueryDict(request.body)
- return self.validation(put, request, operation)
- def validation(self, request_dict, request, operation):
- response = ResponseObject('en')
- if operation == 'getUID': # 获取电池电量列表
- return self.get_custom_uid(request, request_dict, response)
- @classmethod
- def get_custom_uid(cls, request, request_dict, response):
- ip = CommonService.get_ip_address(request)
- LOGGER.info('获取定制客户UID:{},ip:{}'.format(request_dict, ip))
- mac = request_dict.get('mac', None)
- token = request_dict.get('token', None)
- time_stamp = request_dict.get('time_stamp', None)
- if not all([mac, token, time_stamp]):
- LOGGER.error(f'{mac}请求绑定uid参数缺失')
- return response.json(444)
- # 时间戳token校验
- if not CommonService.check_time_stamp_token(token, time_stamp):
- LOGGER.error(f'{mac}时间戳校验失败time:{time_stamp},tk:{token}')
- return response.json(13)
- # 分布式锁配置
- redis = RedisObject()
- lock_key = f"uid_assign:{mac}"
- request_id = f"{mac}_{time_stamp}"
- try:
- # 第一次检查现有绑定
- existing_binding = DeviceCustomUID.objects.filter(
- device_mac=mac,
- status=1
- ).select_related('uid').first()
- if existing_binding:
- LOGGER.info(f'{mac}已存在有效绑定')
- return response.json(0, data={'uid': existing_binding.uid.uid})
- # 获取分布式锁(设置5秒过期时间)
- if not redis.try_lock(lock_key, request_id, expire=5, time_unit_second=1):
- LOGGER.error(f'{mac}获取锁失败')
- return response.json(5)
- # 二次检查(防止在等待锁期间被其他请求处理)
- existing_binding = DeviceCustomUID.objects.filter(
- device_mac=mac,
- status=1
- ).select_related('uid').first()
- if existing_binding:
- LOGGER.info(f'{mac}二次检查存在绑定')
- return response.json(0, data={'uid': existing_binding.uid.uid})
- # 核心分配逻辑
- with transaction.atomic():
- # 获取可用UID(使用SELECT FOR UPDATE锁定行)
- available_uid = CustomUIDPool.objects.select_for_update() \
- .filter(status=0) \
- .order_by('id') \
- .first()
- if not available_uid:
- LOGGER.error(f'{mac}UID池已耗尽')
- return response.json(173)
- # 更新UID状态
- n_time = int(time.time())
- available_uid.status = 1
- available_uid.updated_time = n_time
- available_uid.save(update_fields=['status', 'updated_time'])
- # 创建绑定记录
- DeviceCustomUID.objects.create(
- uid=available_uid,
- device_mac=mac,
- status=1,
- created_time=n_time,
- updated_time=n_time
- )
- LOGGER.info(f'{mac}成功分配UID: {available_uid.uid}')
- return response.json(0, data={'uid': available_uid.uid})
- except DatabaseError as e:
- LOGGER.error(f'{mac}数据库操作异常: {str(e)}')
- return response.json(18)
- except Exception as e:
- LOGGER.error(f'系统异常: {str(e)}')
- return response.json(500)
- finally:
- # 确保释放锁
- if redis.release_lock(lock_key, request_id):
- LOGGER.debug(f'{mac}锁释放成功')
- else:
- LOGGER.warning(f'{mac}锁释放异常')
|