package com.ningdatech.carapi.open.aop;

import com.ningdatech.cache.redis.RedisOps;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.UUID;

/**
 * @program:
 * @description: 定时任务锁切面
 * @author: PoffyZhang
 * @created: 2022/11/1 09:12
 */
@Aspect
@Component
@Slf4j
@AllArgsConstructor
@Order(10)
public class TaskLockAspect {

    private RedisOps redisOps;
 
    @Pointcut("@annotation(com.ningdatech.carapi.open.aop.TaskLock)")
    public void taskLockAspect() {
 
    }

    @Around("taskLockAspect() && @annotation(taskLock)")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint, TaskLock taskLock) throws Throwable {
        String value = UUID.randomUUID().toString();
        try {
            if (lock(taskLock.key(), value, taskLock.expired())) {
                return proceedingJoinPoint.proceed();
            }
        } catch (Exception e) {
            log.error("定时任务执行失败,{}", taskLock.key(), e);
        } finally {
            // 执行完毕解除锁
            if (taskLock.unLock()) {
                String lockValue = getLockValue(taskLock.key());
                if (StringUtils.isNotEmpty(lockValue) && lockValue.equals(value)) {
                    // 解锁设置为延时1S
                    unLock(taskLock.key());
                }
            }
        }
        return null;
    }
 
 
 
    /**
     * 加锁
     * @param key
     * @param value
     * @param time
     * @return
     */
    public boolean lock(String key , String value , int time){
        return redisOps.setXx(key,value,time,false);
    }
 
 
    /**
     * 解锁
     * @param key
     */
    public void unLock(String key){
        redisOps.expire(key,Duration.ofSeconds(1));
    }
 
    /**
     * 获取锁值
     * @param key
     * @return
     */
    public String getLockValue(String key){
        return redisOps.get(key);
    }
}