123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- import json
- import time
- from django.db import transaction
- from django.http import QueryDict
- from django.views import View
- from AgentModel.models import DeviceCustomUID, CustomUIDPool
- from Ansjer.config import LOGGER
- from Model.models import LogModel
- from Object.RedisObject import RedisObject
- from Object.ResponseObject import ResponseObject
- from Service.CommonService import CommonService
- 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)
- @staticmethod
- def get_custom_uid(request, request_dict, response):
- ip = CommonService.get_ip_address(request)
- LOGGER.info(f'获取定制客户UID:{request_dict},ip:{ip}')
- mac = request_dict.get('mac')
- token = request_dict.get('token')
- time_stamp = request_dict.get('time_stamp')
- # 参数校验
- 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(db=3)
- lock_key = f"MAC:ASSIGN:{mac}"
- request_id = f"{mac}_{int(time.time())}"
- try:
- # 预检查绑定状态(缓存优化)
- cached_uid = redis.get_data(f"DEVICE:MAC:{mac}")
- if cached_uid:
- return response.json(0, data={'uid': cached_uid})
- # 分布式锁配置(增加锁持有检测)
- acquired = False
- for _ in range(3):
- if redis.try_lock(lock_key, request_id, expire=5, time_unit_second=1):
- acquired = True
- break
- time.sleep(0.3)
- if not acquired:
- LOGGER.warning(f'{mac}系统繁忙请稍后重试')
- return response.json(5)
- with transaction.atomic():
- # 二次检查(带数据库查询)
- existing = DeviceCustomUID.objects.filter(
- device_mac=mac,
- status=1
- ).only('uid').first()
- if existing:
- # 更新缓存
- redis.set_ex_data(f"DEVICE:MAC:{mac}", existing.uid, 10)
- return response.json(0, {'uid': existing.uid})
- count = 0
- while count < 5:
- available_uid = (
- CustomUIDPool.objects
- .filter(status=0)
- .order_by('updated_time')
- .first()
- )
- if not available_uid:
- LOGGER.error(f'{mac}UID池资源耗尽')
- return response.json(173)
- # 查询到未被绑定的UID进行redis加锁
- uid_lock = redis.try_lock(f"DEVICE:UID:{available_uid.uid}",
- request_id, expire=3, time_unit_second=1)
- if not uid_lock:
- count += 1
- continue
- # 原子操作更新
- rows_updated = CustomUIDPool.objects.filter(
- id=available_uid.id,
- status=0 # 乐观锁校验
- ).update(
- status=1,
- updated_time=int(time.time())
- )
- if int(rows_updated) <= 0: # 更新失败
- count += 1
- continue
- if not rows_updated:
- LOGGER.warning(f'{mac}UID并发竞争更新失败')
- return response.json(14)
- # 创建设备关联记录
- DeviceCustomUID.objects.create(
- device_mac=mac,
- uid=available_uid.uid,
- status=1,
- updated_time=int(time.time()),
- created_time=int(time.time())
- )
- content = json.loads(json.dumps(request_dict))
- log = {
- 'ip': ip,
- 'user_id': 1,
- 'status': 200,
- 'time': int(time.time()),
- 'content': json.dumps(content),
- 'url': 'api/device/custom/getUID',
- 'operation': '定制设备mac{}绑定uid: {}'.format(mac, available_uid.uid),
- }
- LogModel.objects.create(**log)
- # 设置缓存
- redis.set_ex_data(f"MAC_UID_CACHE:{mac}", available_uid.uid, 10)
- return response.json(0, {'uid': available_uid.uid})
- except Exception as e:
- LOGGER.error(f'mac:{mac}系统异常: {str(e)}', exc_info=True)
- return response.json(500)
- finally:
- redis.release_lock(lock_key, request_id)
|