package com.tuoheng.admin.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * redis分布式锁
 * @author ：小肖
 * @date ：Created in 2022/2/10 13:28
 */
@Component
@Slf4j
public class RedisLock {

    @Autowired
    private StringRedisTemplate redisTemplate;

//    /**
//     * 加锁
//     * @param key
//     * @param value
//     * @return
//     */
//    public boolean lock(String key,String value){
//        if(redisTemplate.opsForValue().setIfAbsent(key,value)){
//            // 加锁成功
//            return true;
//        }
//
//        // 如果锁过期
//        String currentValue = redisTemplate.opsForValue().get(key);
//        if(!StringUtils.isEmpty(currentValue) &&
//                Long.parseLong(currentValue) < System.currentTimeMillis()){
//
//            String oldValue = redisTemplate.opsForValue().getAndSet(key,value);
//            if(!StringUtils.isEmpty(oldValue) &&
//                    oldValue.equals(oldValue)){
//                return true;
//            }
//        }
//
//        // 锁已经被其它线程获取
//        return false;
//    }

    /**
     * redis 分布式锁
     *
     * @param key
     * @param value
     * @param timeout
     * @param unit
     * @return
     */
    public boolean setLock(String key, String value, Long timeout, TimeUnit unit) {
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value) || timeout == null || unit == null || timeout <= 0) {
            return false;
        }
        SessionCallback<Boolean> sessionCallback = new SessionCallback<Boolean>() {
            List<Object> exec = null;

            @Override
            public Boolean execute(RedisOperations operations) throws DataAccessException {
                operations.multi();
                redisTemplate.opsForValue().setIfAbsent(key, value);
                redisTemplate.expire(key, timeout, unit);
                exec = operations.exec();
                if (exec.size() > 0) {
                    return (Boolean) exec.get(0);
                }
                return false;
            }
        };
        return redisTemplate.execute(sessionCallback);
    }

    /**
     * 解锁
     * @param key
     * @param value
     */
    public void unlock(String key,String value){
        try{
            String currentValue = redisTemplate.opsForValue().get(key);
            if(!StringUtils.isEmpty(currentValue) &&
                    currentValue.equals(value)){
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        }catch (Exception e){
            log.error("【redis 分布式锁】 解锁异常,{}",e);
        }
    }
}

