<?php

namespace traits;

use bw\Redis;


/**
 * 缓存
 */
trait CacheTrait
{


    private $cache_lock_error_msg = "获取锁失败！";

    private $cache_lock_thorws_excption = true;

    public function setCacheLockThorwsExcption($cache_lock_thorws_excption){
        $this->cache_lock_thorws_excption = $cache_lock_thorws_excption;
        return $this;
    }


    public function getCacheLockThorwsExcption(){
        return $this->cache_lock_thorws_excption;
    }




    public function hasRedis($is_interrupt = false) {
        $error_msg = '';
        try {
            $redis = $this->getRedis();

            // 检测连接是否正常
            $redis->ping();
        } catch (\BadFunctionCallException $e) {
            // 缺少扩展
            $error_msg = $e->getMessage() ? $e->getMessage() : "缺少 redis 扩展";
        } catch (\RedisException $e) {
            // 连接拒绝
            \think\Log::write('redis connection redisException fail: ' . $e->getMessage());
            $error_msg = $e->getMessage() ? $e->getMessage() : "redis 连接失败";
        } catch (\Exception $e) {
            // 异常
            \think\Log::write('redis connection fail: ' . $e->getMessage());
            $error_msg = $e->getMessage() ? $e->getMessage() : "redis 连接异常";
        }

        if ($error_msg) {
            if ($is_interrupt || $this->cache_lock_thorws_excption) {
                throw new \Exception($error_msg);
            } else {
                $this->setCacheLockErrorMsg($error_msg);
                return false;
            }
        }

        return true;
    }


    public function getRedis() {
        if (!isset($GLOBALS['SPREDIS'])) {
            $GLOBALS['SPREDIS'] = (new Redis())->getRedis();
        }

        return $GLOBALS['SPREDIS'];
    }



    public function getLock($key,$suffix = "-lock-suffix", $timeout = 120){
        $this->hasRedis(true);
        $redis = $this->getRedis();
        $hashKey = $key.$suffix;
//        $redis->del($hashKey);
//        var_dump($hashKey);die;
        //判断锁是否存在，如果存在，返回错误
//        if ($redis->exists($hashKey)){
////            var_dump(111111222);die;
//            if($this->cache_lock_thorws_excption){
//                throw new \Exception($this->cache_lock_error_msg);
//            }else{
//                return false;
//            }
//
//        }
        //如果不存在创建锁并返回
//        $redis->set($hashKey, 1,$timeout);//注释掉
        //替换成原子操作的命令
        $nxLock =  $redis->set($hashKey, 1,['nx', 'ex' => $timeout]);
        if ($nxLock == 1) {
            return true;
        } else {
            if($this->cache_lock_thorws_excption){
                throw new \Exception($this->cache_lock_error_msg);
            }else{
                return false;
            }
        }


    }


    public function setCacheLockErrorMsg($cache_lock_error_msg){
        $this->cache_lock_error_msg = $cache_lock_error_msg;
        return $this;
    }


    public function getCacheLockErrorMsg(){
        return $this->cache_lock_error_msg;
    }


    public function freeLock($key,$suffix = "-lock-suffix"){
        $this->hasRedis(true);
        $redis = $this->getRedis();
        if(!$key || !$suffix) return true;
        $hashKey = $key.$suffix;

        //执行lua脚本，确保删除锁是原子操作
        $lua = 'if redis.call("get",KEYS[1]) == ARGV[1]
        then
            return redis.call("del",KEYS[1])
        else
            return 0
        end';
        $result = $redis->eval($lua, [$hashKey, 1], 1);

        if ('1' == $result) {

            return true;
        }
        return false;

//        if (!$redis->EXISTS($hashKey)) return true;
//        $redis->del($hashKey);
//        return true;
    }







}
