<?php

/**
 * 应用信息
 * @author solu
 */
class AppInfo extends Model {
    protected $tableName = 'app_info';
    protected $dbKey = 'dw_chat';

    const REDIS_KEY_ACCESS_TOKEN = 'globals:app_access_token:%s:%s';

    const VERIFY_TIMEOUT = 20;
    const ACCESS_TOKEN_TTL = 86400;

    const STATE_CLOSE = 0; //不可用
    const STATE_OPEN = 1; // 可用

    /**
     * 校验app参数
     * @author solu
     * @param $appId
     * @param $ts
     * @param $sign
     * @return bool
     * @throws Exception
     */
    public function verify($appId, $ts, $sign) {
        $info = $this->objTable->getRow(['app_id' => $appId]);
        if (!$info || $info['state'] == self::STATE_CLOSE) {
            throw new Exception('app id not available', CODE_PARAM_ERROR);
        }

        if ($sign != self::doSign($appId, $info['app_secret'], $ts)) {
            throw new Exception('sign error!', CODE_SIGN_ERROR);
        }

        if (time() - self::VERIFY_TIMEOUT > $ts) {
            throw new Exception('request params timeout', CODE_PARAM_ERROR);
        }

        return true;
    }

    public static function doSign($appId, $appSecret, $ts) {
        return md5(sprintf('%s_%s_%s', $appId, $appSecret, $ts));
    }

    private static function _accessTokenKey($appId, $accessToken) {
        return sprintf(self::REDIS_KEY_ACCESS_TOKEN, $appId, $accessToken);
    }

    public static function genAccessToken($appId, $userId) {
        $accessToken = uuid16();
        if (!$accessToken) {
            return false;
        }

        $key = self::_accessTokenKey($appId, $accessToken);
        $objRedis = dwRedis::init(Eos::REDIS_SERV);

        $objRedis->setex($key, self::ACCESS_TOKEN_TTL, $userId);

        return $accessToken;
    }

    public static function checkAccessToken($appId, $userId, $accessToken) {
        $key = self::_accessTokenKey($appId, $accessToken);
        $objRedis = dwRedis::init(Eos::REDIS_SERV);

        $in = $objRedis->get($key);
        if (intval($in) === intval($userId)) {
            return true;
        }

        return false;
    }
}