文件内容 RedisClient.cs 48 KB 48498 字符
using Microsoft.Extensions.Options;
using PasteApeart.Handler.Extend;
using StackExchange.Redis;
using System.Text.Json;

namespace PasteApeart.Handler.redis
{
    /// <summary>
    /// 封装 Redis 相关操作的方法类。
    /// </summary>
    public class RedisClient : IAppCache
    {
        //private readonly RedisConfig _redisconfig;
        //private IDatabase _database { get { return _mainconnect.Value.GetDatabase(); } }
        //private Lazy<ConnectionMultiplexer> _mainconnect;
        //private string PrefixHead = String.Empty;
        //public RedisClient(IOptions<RedisConfig> options)
        //{
        //    _redisconfig = options.Value;
        //    var oaconfig = ConfigurationOptions.Parse(_redisconfig.MainConnection);
        //    PrefixHead = _redisconfig.Prefix;
        //    oaconfig.ClientName = _redisconfig.ClientName;
        //    _mainconnect = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(oaconfig));
        //}

        private readonly RedisConfig _redisconfig;
        private readonly Lazy<ConnectionMultiplexer>[] _connectionPool;
        private int _currentConnectionIndex = 0;
        private readonly object _lock = new object();

        /// <summary>
        /// Key的前缀
        /// </summary>
        private string PrefixHead = string.Empty;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="options"></param>
        public RedisClient(IOptions<RedisConfig> options)
        {
            _redisconfig = options.Value;
            PrefixHead = _redisconfig.Prefix;
            _connectionPool = new Lazy<ConnectionMultiplexer>[4];
            for (int i = 0; i < _connectionPool.Length; i++)
            {
                var config = ConfigurationOptions.Parse(_redisconfig.MainConnection);
                config.ClientName = $"{_redisconfig.ClientName}_{i}"; // 为每个连接添加序号
                _connectionPool[i] = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(config));
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private IDatabase GetDatabase()
        {
            lock (_lock)
            {
                var connection = _connectionPool[_currentConnectionIndex];
                _currentConnectionIndex = (_currentConnectionIndex + 1) % _connectionPool.Length;
                return connection.Value.GetDatabase();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private IDatabase _database { get { return GetDatabase(); } }


        private string setKey(string key)
        {
            return PrefixHead + key;
        }



        #region 同步方法...

        /// <summary>
        /// 添加一个字符串对象。
        /// </summary>
        /// <param name="key">键。</param>
        /// <param name="value">值。</param>
        /// <param name="expiry">过期时间(时间间隔)。</param>
        /// <returns>返回是否执行成功。</returns>
        public bool Set(string key, string value, TimeSpan? expiry = null)
        {
            if (expiry == null)
            {
                return _database.StringSet(setKey(key), value);
            }
            return _database.StringSet(setKey(key), value, expiry.Value);
        }

        /// <summary>
        /// 设置值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        public bool SetValue(string key, string val, int second)
        {
            return _database.StringSet(setKey(key), val, TimeSpan.FromSeconds(second));
        }

        /// <summary>
        /// 添加一个字符串对象。
        /// </summary>
        /// <param name="key">键。</param>
        /// <param name="value">值。</param>
        /// <param name="seconds">过期时间(秒)。</param>
        /// <returns>返回是否执行成功。</returns>
        public bool Set(string key, string value, int seconds)
        {
            TimeSpan expiry = TimeSpan.FromSeconds(seconds);
            return _database.StringSet(setKey(key), value, expiry);
        }

        /// <summary>
        /// 添加一个对象。
        /// </summary>
        /// <param name="key">键。</param>
        /// <typeparam name="T">对象的类型。</typeparam>
        /// <param name="value">值。</param>
        /// <param name="expiry">过期时间(时间间隔)。</param>
        /// <returns>返回是否执行成功。</returns>
        public bool SetObject<T>(string key, T value, TimeSpan? expiry = null)
        {
            var data = System.Text.Json.JsonSerializer.Serialize<T>(value, JsonConfig.Options);// JsonConvert.SerializeObject(value);
            if (expiry == null)
            {
                return _database.StringSet(setKey(key), data);
            }
            else
            {
                return _database.StringSet(setKey(key), data, expiry.Value);
            }
        }

        /// <summary>
        /// 添加一个对象。
        /// </summary>
        /// <param name="key">键。</param>
        /// <typeparam name="T">对象的类型。</typeparam>
        /// <param name="value">值。</param>
        /// <param name="seconds">过期时间(秒)。</param>
        /// <returns>返回是否执行成功。</returns>
        public bool SetObject<T>(string key, T value, int seconds)
        {
            TimeSpan expiry = TimeSpan.FromSeconds(seconds);
            var data = System.Text.Json.JsonSerializer.Serialize<T>(value, JsonConfig.Options); //JsonConvert.SerializeObject(value);
            return _database.StringSet(setKey(key), data, expiry);
        }

        /// <summary>
        /// 获取一个对象。
        /// </summary>
        /// <param name="key">值。</param>
        /// <returns>返回对象的值。</returns>
        public T GetObject<T>(string key)
        {
            string json = _database.StringGet(setKey(key));
            if (string.IsNullOrWhiteSpace(json))
            {
                return default(T);
            }
            T entity = JsonSerializer.Deserialize<T>(json, JsonConfig.Options);// JsonConvert.DeserializeObject<T>(json);
            return entity;
        }

        /// <summary>
        /// 获取一个字符串对象。
        /// </summary>
        /// <param name="key">值。</param>
        /// <returns>返回对象的值。</returns>
        public string Get(string key)
        {
            return _database.StringGet(setKey(key));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string GetStringValue(string key)
        {
            return _database.StringGet(setKey(key));
        }

        /// <summary>
        /// 删除一个对象。
        /// </summary>
        /// <param name="key">键。</param>
        /// <returns>返回是否执行成功。</returns>
        public bool Delete(string key)
        {
            return _database.KeyDelete(setKey(key));
        }

        /// <summary>
        /// 返回键是否存在。
        /// </summary>
        /// <param name="key">键。</param>
        /// <returns>返回键是否存在。</returns>
        public bool Exists(string key)
        {
            return _database.KeyExists(setKey(key));
        }

        /// <summary>
        /// 返回键是否存在。
        /// </summary>
        /// <param name="key">键。</param>
        /// <returns>返回键是否存在。</returns>
        public async Task<bool> ExistsAsync(string key)
        {
            return await _database.KeyExistsAsync(setKey(key));
        }

        /// <summary>
        /// 设置一个键的过期时间。
        /// </summary>
        /// <param name="key">键。</param>
        /// <param name="expiry">过期时间(时间间隔)。</param>
        /// <returns>返回是否执行成功。</returns>
        public bool SetExpire(string key, TimeSpan? expiry)
        {
            return _database.KeyExpire(setKey(key), expiry);
        }

        /// <summary>
        /// 设置一个键的过期时间。
        /// </summary>
        /// <param name="key">键。</param>
        /// <param name="seconds">过期时间(秒)。</param>
        /// <returns>返回是否执行成功。</returns>
        public bool SetExpire(string key, int seconds)
        {

            TimeSpan expiry = TimeSpan.FromSeconds(seconds);
            return _database.KeyExpire(setKey(key), expiry);
        }

        #endregion

        #region 异步方法...

        /// <summary>
        /// 异步添加一个字符串对象。
        /// </summary>
        /// <param name="key">键。</param>
        /// <param name="value">值。</param>
        /// <param name="expiry">过期时间(时间间隔)。</param>
        /// <returns>返回是否执行成功。</returns>
        public async Task<bool> SetAsync(string key, string value, TimeSpan? expiry = null)
        {
            if (expiry != null)
            {
                return await _database.StringSetAsync(setKey(key), value, expiry.Value);
            }
            return await _database.StringSetAsync(setKey(key), value);
        }

        /// <summary>
        /// 异步添加一个字符串对象。
        /// </summary>
        /// <param name="key">键。</param>
        /// <param name="value">值。</param>
        /// <param name="seconds">过期时间(秒)。</param>
        /// <returns>返回是否执行成功。</returns>
        public async Task<bool> SetAsync(string key, string value, int seconds)
        {
            TimeSpan expiry = TimeSpan.FromSeconds(seconds);
            return await _database.StringSetAsync(setKey(key), value, expiry);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        public async Task<bool> SetObjectAsync<T>(string key, T value, int second)
        {
            var data = JsonSerializer.Serialize<T>(value, JsonConfig.Options);// JsonConvert.SerializeObject(value);
            return await _database.StringSetAsync(setKey(key), data, TimeSpan.FromSeconds(second));
        }

        /// <summary>
        /// 异步获取一个对象。
        /// </summary>
        /// <typeparam name="T">对象的类型。</typeparam>
        /// <param name="key">值。</param>
        /// <returns>返回对象的值。</returns>
        public async Task<T> GetObjectAsync<T>(string key)
        {
            string json = await _database.StringGetAsync(setKey(key));
            if (string.IsNullOrWhiteSpace(json))
            {
                return default(T);
            }
            T entity = JsonSerializer.Deserialize<T>(json, JsonConfig.Options);// JsonConvert.DeserializeObject<T>(json);
            return entity;
        }

        /// <summary>
        /// 异步获取一个字符串对象。
        /// </summary>
        /// <param name="key">值。</param>
        /// <returns>返回对象的值。</returns>
        public async Task<string> GetAsync(string key)
        {
            return await _database.StringGetAsync(setKey(key));
        }

        /// <summary>
        /// 异步删除一个对象。
        /// </summary>
        /// <param name="key">键。</param>
        /// <returns>返回是否执行成功。</returns>
        public async Task<bool> DeleteAsync(string key)
        {
            return await _database.KeyDeleteAsync(setKey(key));
        }

        /// <summary>
        /// 异步设置一个键的过期时间。
        /// </summary>
        /// <param name="key">键。</param>
        /// <param name="seconds">过期时间(秒)。</param>
        /// <returns>返回是否执行成功。</returns>
        public async Task<bool> SetExpireAsync(string key, int seconds)
        {
            TimeSpan expiry = TimeSpan.FromSeconds(seconds);
            return await _database.KeyExpireAsync(setKey(key), expiry);
        }

        /// <summary>
        /// 异步设置一个键的过期时间。
        /// </summary>
        /// <param name="key">键。</param>
        /// <param name="expiry">过期时间(时间间隔)。</param>
        /// <returns>返回是否执行成功。</returns>
        public async Task<bool> SetExpireAsync(string key, TimeSpan? expiry)
        {
            return await _database.KeyExpireAsync(setKey(key), expiry);
        }

        #endregion

        #region 分布式锁...

        /// <summary>
        /// 分布式锁 Token。
        /// </summary>
        private static readonly RedisValue LockToken = Environment.MachineName;

        /// <summary>
        /// 是redis缓存
        /// </summary>
        public bool IsRedis => true;

        /// <summary>
        /// 获取锁。
        /// </summary>
        /// <param name="key">锁名称。</param>
        /// <param name="seconds">过期时间(秒)。</param>
        /// <returns>是否已锁。</returns>
        public bool Lock(string key, int seconds)
        {
            return _database.LockTake(setKey(key), LockToken, TimeSpan.FromSeconds(seconds));
        }

        /// <summary>
        /// 释放锁。
        /// </summary>
        /// <param name="key">锁名称。</param>
        /// <returns>是否成功。</returns>
        public bool UnLock(string key)
        {
            return _database.LockRelease(setKey(key), LockToken);
        }

        /// <summary>
        /// 异步获取锁。
        /// </summary>
        /// <param name="key">锁名称。</param>
        /// <param name="seconds">过期时间(秒)。</param>
        /// <returns>是否成功。</returns>
        public async Task<bool> LockAsync(string key, int seconds)
        {
            return await _database.LockTakeAsync(setKey(key), LockToken, TimeSpan.FromSeconds(seconds));
        }

        /// <summary>
        /// 异步释放锁。
        /// </summary>
        /// <param name="key">锁名称。</param>
        /// <returns>是否成功。</returns>
        public async Task<bool> UnLockAsync(string key)
        {
            return await _database.LockReleaseAsync(setKey(key), LockToken);
        }

        #endregion

        #region Hash
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public List<HashKeyValue> HashGetAll(string key)
        {

            //return  _database.HashGetAll(setKey(key));
            var hentry = _database.HashGetAll(setKey(key));
            var result = new List<HashKeyValue>();
            foreach (var h in hentry)
            {
                result.Add(new HashKeyValue()
                {
                    Key = h.Name,
                    Value = h.Value
                });
            }
            return result;

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public HashEntry[] HashGetAllEntry(string key)
        {
            return _database.HashGetAll(setKey(key));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<HashEntry[]> HashGetAllEntryAsync(string key)
        {
            return await _database.HashGetAllAsync(setKey(key));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<List<HashKeyValue>> HashGetAllAsync(string key)
        {
            var hentry = await _database.HashGetAllAsync(setKey(key));
            var result = new List<HashKeyValue>();
            foreach (var h in hentry)
            {
                result.Add(new HashKeyValue()
                {
                    Key = h.Name,
                    Value = h.Value
                });
            }
            return result;

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="vals"></param>
        public void HashSet(string key, HashEntry[] vals)
        {
            _database.HashSet(setKey(key), vals);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="vals"></param>
        /// <param name="isnum"></param>
        /// <returns></returns>
        public async Task HashSetAsync(string key, HashEntry[] vals, bool isnum = false)
        {
            await _database.HashSetAsync(setKey(key), vals);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="value"></param>
        /// <param name="isnum"></param>
        /// <returns></returns>
        public async Task HashSetAsync(string key, string field, RedisValue value, bool isnum = false)
        {
            await _database.HashSetAsync(setKey(key), field, value);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="sunkey"></param>
        /// <returns></returns>
        public string HashGet(string key, string sunkey)
        {
            return _database.HashGet(setKey(key), sunkey);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="sunkey"></param>
        /// <param name="isnum"></param>
        /// <returns></returns>
        public async Task<string> HashGetAsync(string key, string sunkey, bool isnum = false)
        {
            return await _database.HashGetAsync(setKey(key), sunkey);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="fields"></param>
        /// <param name="isinnum"></param>
        /// <returns></returns>
        public async Task<RedisValue[]> HashGetAsync(string key, RedisValue[] fields, bool isinnum = false)
        {
            return await _database.HashGetAsync(setKey(key), fields);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public async Task<bool> HashDeleteAsync(string key, string field)
        {
            return await _database.HashDeleteAsync(setKey(key), field);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="fields"></param>
        /// <returns></returns>
        public async Task<bool> HashDeleteAsync(string key, RedisValue[] fields)
        {
            await _database.HashDeleteAsync(setKey(key), fields);
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public bool HashDelete(string key, string field)
        {
            return _database.HashDelete(setKey(key), field);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="num"></param>
        /// <returns></returns>
        public async Task<long> HashIncrementAsync(string key, string field, long num = 1)
        {
            return await _database.HashIncrementAsync(setKey(key), field, num);
        }

        /// <summary>
        /// HashSet是否有数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public long HashLength(string key)
        {
            return _database.HashLength(setKey(key));
        }

        /// <summary>
        /// HashSet是否有数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<long> HashLengthAsync(string key)
        {
            return await _database.HashLengthAsync(setKey(key));
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="num"></param>
        /// <returns></returns>
        public long HashIncrement(string key, string field, long num = 1)
        {
            return _database.HashIncrement(setKey(key), field, num);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public async Task<long> HashDecrementAsync(string key, string field, long val = 1)
        {
            return await _database.HashDecrementAsync(setKey(key), field, val);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public async Task<long> HashDecrementAsync(string key, string field)
        {
            var val = 1;
            return await _database.HashDecrementAsync(setKey(key), field, val);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public long HashDecrement(string key, string field, long val = 1)
        {
            return _database.HashDecrement(setKey(key), field, val);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="pattern"></param>
        /// <param name="page"></param>
        /// <param name="size"></param>
        /// <param name="isincom"></param>
        /// <returns></returns>
        public async Task<List<HashEntry>> HashScanAsync(string key, string pattern, int page, int size, bool isincom = true)
        {
            var offset = (page - 1) * size;
            IAsyncEnumerable<HashEntry> result = _database.HashScanAsync(key: setKey(key), pattern: pattern, pageSize: size, pageOffset: offset, cursor: offset);
            var rmlist = new List<HashEntry>();
            var enumerator = result.GetAsyncEnumerator();
            var iindex = 0;
            while (await enumerator.MoveNextAsync())
            {
                iindex++;
                if (iindex <= size)
                {
                    var item = enumerator.Current;
                    rmlist.Add(item);
                }
                else
                {
                    break;
                }
            }
            return rmlist;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public async Task<T> HashGetObjectAsync<T>(string key, string field)
        {
            var redisValue = await _database.HashGetAsync(setKey(key), field);
            if (redisValue.HasValue)
            {
                T entity = JsonSerializer.Deserialize<T>(redisValue.ToString(), JsonConfig.Options);// JsonConvert.DeserializeObject<T>(redisValue.ToString());
                return entity;
            }
            return default(T);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="isNum"></param>
        /// <returns></returns>
        public async Task<int> HashGetIntFieldAsync(string key, string field, bool isNum = false)
        {
            var redisValue = await _database.HashGetAsync(setKey(key), field);
            if (redisValue.HasValue)
            {
                int.TryParse(redisValue.ToString(), out var ival);
                return ival;
            }
            return default(int);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="isNum"></param>
        /// <returns></returns>
        public async Task<long> HashGetLongFieldAsync(string key, string field, bool isNum = false)
        {
            var redisValue = await _database.HashGetAsync(setKey(key), field);
            if (redisValue.HasValue)
            {
                long.TryParse(redisValue.ToString(), out var ival);
                return ival;
            }
            return default(long);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<bool> HashSetObjectAsync<T>(string key, string field, T entity)
        {
            var jsonString = JsonSerializer.Serialize<T>(entity, JsonConfig.Options);// JsonConvert.SerializeObject(entity);
            return await _database.HashSetAsync(setKey(key), field, jsonString);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public bool HashExists(string key, string field)
        {
            return _database.HashExists(setKey(key), field);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public async Task<bool> HashExistsAsync(string key, string field)
        {
            return await _database.HashExistsAsync(setKey(key), field);
        }

        #endregion

        #region

        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="key"></param>
        ///// <param name="start"></param>
        ///// <param name="stop"></param>
        ///// <returns></returns>
        //public async Task<SortedSetEntry[]> SortedSetRangeByRankWithScoresAsync(string key, int start = 0, int stop = 1)
        //{
        //    return await _database.SortedSetRangeByRankWithScoresAsync(setKey(key), start, stop);
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        public async Task<RedisValue[]> SortedSetRangeByScoreAsync(string key, long start = 0, long stop = 1)
        {
            return await _database.SortedSetRangeByScoreAsync(setKey(key), start, stop, order: Order.Descending);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task<long> SortedSetIncrementAsync(string key, string field, long value)
        {
            var _read = await _database.SortedSetIncrementAsync(setKey(key), field, (long)value);
            return (long)_read;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task<long> SortedSetDecrementAsync(string key, string field, long value)
        {
            var _read = await _database.SortedSetDecrementAsync(setKey(key), field, (long)value);
            return (long)_read;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public async Task<bool> SortedSetRemoveAsync(string key, string field)
        {
            return await _database.SortedSetRemoveAsync(setKey(key), field);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task<bool> SortedSetAddAsync(string key, string field, long value)
        {
            return await _database.SortedSetAddAsync(setKey(key), field, value);
        }

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <param name="bit"></param>
        /// <returns></returns>
        public async Task<long> StringBitPositionAsync(string key, int start, int end, bool bit)
        {
            return await _database.StringBitPositionAsync(setKey(key), bit, start, end);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public async Task<long> StringBitCountAsync(string key, long start = 0, long end = -1)
        {
            return await _database.StringBitCountAsync(setKey(key), start, end);
        }

        /// <summary>
        /// 获取第一次出现的位置
        /// </summary>
        /// <param name="key"></param>
        /// <param name="offset"></param>
        /// <param name="bit"></param>
        /// <returns></returns>
        public async Task<bool> StringSetBitAsync(string key, long offset, bool bit)
        {
            return await _database.StringSetBitAsync(setKey(key), offset, bit);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="vals"></param>
        public void HashSet(string key, List<HashKeyValue> vals)
        {
            var list = new List<HashEntry>();
            foreach (var item in vals)
            {
                list.Add(new HashEntry(item.Key, item.Value) { });
            }

            _database.HashSet(setKey(key), list.ToArray());
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="vals"></param>
        /// <param name="isnum"></param>
        /// <returns></returns>
        public async Task HashSetAsync(string key, List<HashKeyValue> vals, bool isnum = false)
        {
            var list = new List<HashEntry>();
            foreach (var item in vals)
            {
                list.Add(new HashEntry(item.Key, item.Value) { });
            }

            await _database.HashSetAsync(setKey(key), list.ToArray());
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public bool SetValue(string key, string val)
        {
            return Set(key, val);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string Print()
        {
            return "is redis!";
        }



        //--------------------------------------------------------------------------------



        #region 同步方法...



        #endregion

        #region 异步方法...


        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="keys"></param>
        /// <returns></returns>
        public async Task BatchRemoveAsync(string[] keys)
        {
            var batchCommand = _database.CreateBatch();
            var redisKeys = keys.Select(x => new RedisKey(setKey(x))).ToArray();
            await batchCommand.KeyDeleteAsync(redisKeys);
        }



        #endregion

        #region 分布式锁...


        #endregion

        #region Hash

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<HashEntry[]> HashReadAllAsync(string key)
        {
            return await _database.HashGetAllAsync(setKey(key));
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="vals"></param>
        public async Task HashSetAsync(string key, HashEntry[] vals)
        {
            await _database.HashSetAsync(setKey(key), vals);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="num"></param>
        /// <returns></returns>
        public async Task<long> HashIncrementAsync(string key, RedisValue field, long num = 1)
        {
            return await _database.HashIncrementAsync(setKey(key), field, num);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="num"></param>
        /// <returns></returns>
        public async Task<long> HashDecrementAsync(string key, RedisValue field, long num = 1)
        {
            return await _database.HashDecrementAsync(setKey(key), field, num);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="sunkey"></param>
        /// <returns></returns>
        public async Task<string> HashGetAsync(string key, string sunkey)
        {
            return await _database.HashGetAsync(setKey(key), sunkey);
        }

        #endregion


        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="vals"></param>
        /// <returns></returns>
        public async Task HashSetAsync(string key, List<HashKeyValue> vals)
        {
            var list = new List<HashEntry>();
            foreach (var item in vals)
            {
                list.Add(new HashEntry(item.Key, item.Value) { });
            }

            await _database.HashSetAsync(setKey(key), list.ToArray());
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="num"></param>
        /// <returns></returns>
        public async Task HashIncrementAsync(string key, string field, int num)
        {
            await _database.HashIncrementAsync(setKey(key), field, num);
        }


        /// <summary>
        /// 写入有序排序
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="score"></param>
        public async Task SortedSetAddAsync(string key, RedisValue field, int score)
        {
            await _database.SortedSetAddAsync(setKey(key), field, score);
        }

        /// <summary>
        /// 批量写入有序排序
        /// </summary>
        /// <param name="key"></param>
        /// <param name="fields"></param>
        public async Task SortedSetAddAsync(string key, SortedSetEntry[] fields)
        {
            await _database.SortedSetAddAsync(setKey(key), fields);
        }


        /// <summary>
        /// 从hash中获取随机一个!!!
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<HashEntry> HashRandomFieldsWithValuesAsync(string key)
        {
            var reads = await _database.HashRandomFieldsWithValuesAsync(setKey(key), 1);
            if (reads?.Length > 0)
            {
                return reads.First();
            }
            return default;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="pattern"></param>
        /// <param name="size"></param>
        /// <param name="cursor"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        public async Task<HashEntry[]> HashScanAsync(string key, string pattern, int size = 1, int cursor = 0, int offset = 0)
        {
            var results = new List<HashEntry>();
            var reads = _database.HashScanAsync(setKey(key), pattern, size, cursor, offset);
            await foreach (var item in reads)
            {
                results.Add(item);
                if (results.Count >= size)
                {
                    break;
                }
            }
            return results.ToArray();
        }


        /// <summary>
        /// 按照分数升序,获取第一个分数 >= 指定分数的数据并删除
        /// </summary>
        /// <param name="key"></param>
        /// <param name="minScore">最低分数</param>
        /// <returns></returns>
        public async Task<SortedSetEntry?> SortedSetStartPopScoreAsync(string key, int minScore)
        {
            var luaScript = @"
                    local members = redis.call('ZRANGEBYSCORE', KEYS[1], ARGV[1], '+inf', 'WITHSCORES', 'LIMIT', 0, 1)
                    if #members == 0 then
                        return nil
                    end
                    redis.call('ZREM', KEYS[1], members[1])
                    return {members[1], members[2]}
                ";
            var result = await _database.ScriptEvaluateAsync(luaScript,
                new RedisKey[] { setKey(key) },
                new RedisValue[] { minScore });
            if (result.IsNull)
            {
                return null;
            }
            var resultArray = (RedisResult[])result;
            if (resultArray.Length >= 2)
            {
                string element = (string)resultArray[0];
                double redisScore = (double)resultArray[1];
                // 将double转换为int(根据您的需求)
                int scoreValue = (int)redisScore;
                return new SortedSetEntry(element, scoreValue);
            }
            return null;
        }

        /// <summary>
        /// 返回分数符合的第一个元素,返回并删除这个元素
        /// </summary>
        public async Task<SortedSetEntry?> SortedSetPopExactScoreAsync(string key, int targetScore)
        {
            var luaScript = @"
                    local members = redis.call('ZRANGEBYSCORE', KEYS[1], ARGV[1], ARGV[1], 'WITHSCORES', 'LIMIT', 0, 1)
                    if #members == 0 then
                        return nil
                    end
                    redis.call('ZREM', KEYS[1], members[1])
                    return {members[1], members[2]}
                ";

            var result = await _database.ScriptEvaluateAsync(luaScript,
                new RedisKey[] { setKey(key) },
                new RedisValue[] { targetScore });

            if (result.IsNull)
            {
                return null;
            }

            var resultArray = (RedisResult[])result;
            if (resultArray.Length >= 2)
            {
                string element = (string)resultArray[0];
                double redisScore = (double)resultArray[1];
                int scoreValue = (int)redisScore;

                return new SortedSetEntry(element, scoreValue);
            }

            return null;
        }


        #region -----------------blog--------------------------------


        #region Hash模块

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<string[]> HashKeysAsync(string key)
        {
            var keys = await _database.HashKeysAsync(setKey(key));
            var list = new List<string>();
            foreach (var item in keys)
            {
                list.Add(item.ToString());
            }
            return list.ToArray();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public Task<string> ReadStringAsync(string key)
        {
            return Task.Run<string>((Func<Task<string>>)(async () =>
            {
                return await this._database.StringGetAsync(setKey(key));
            }));

        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<T> ReadObjectAsync<T>(string key)
        {

            string str = await _database.StringGetAsync(setKey(key));
            if (!string.IsNullOrEmpty(str))
            {
                return JsonSerializer.Deserialize<T>(str, JsonConfig.Options);// Newtonsoft.Json.JsonConvert.DeserializeObject<T>(str);
            }
            return default(T);


        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="skey"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public async Task<bool> SetAddAsync(string skey, int val)
        {
            return await _database.SetAddAsync(setKey(skey), val);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="skey"></param>
        /// <param name="filed"></param>
        /// <returns></returns>
        public async Task<bool> SetContainsAsync(string skey, int filed)
        {
            return await _database.SetContainsAsync(setKey(skey), filed);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="skey"></param>
        /// <param name="filed"></param>
        /// <returns></returns>
        public async Task<bool> SetRemoveAsync(string skey, int filed)
        {
            return await _database.SetRemoveAsync(setKey(skey), filed);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="skey"></param>
        /// <returns></returns>
        public async Task<long> SetRandomMemberAsync(string skey)
        {
            (await _database.SetRandomMemberAsync(setKey(skey))).TryParse(out long val);
            return val;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="skey"></param>
        /// <returns></returns>
        public async Task<long> SetLengthAsync(string skey)
        {
            return (await _database.SetLengthAsync(setKey(skey)));
        }

        /// <summary>
        /// 获取排序中的第一个field并删除
        /// type.action.randcode.id
        /// </summary>
        /// <param name="skey"></param>
        /// <returns></returns>
        public async Task<string> SortedSetRangeByRankAsync(string skey)
        {
            var _read = await _database.SortedSetRangeByRankAsync(setKey(skey), 0, 1);
            if (_read != null && _read.Length > 0)
            {
                var _current = _read[0];
                await _database.SortedSetRemoveAsync(setKey(skey), _current);
                return _current.ToString();
            }
            return String.Empty;
        }

        /// <summary>
        /// 返回最近的一个!并删除
        /// </summary>
        /// <param name="skey"></param>
        /// <param name="_time"></param>
        /// <returns></returns>
        public async Task<string> SortedSetRangeByScoreWithScoresAsync(string skey, long _time)
        {
            var reads = await _database.SortedSetRangeByScoreWithScoresAsync(setKey(skey), 0, _time, take: 1);
            if (reads != null && reads.Length > 0)
            {
                var _field = reads[0].Element.ToString();
                await _database.SortedSetRemoveAsync(setKey(skey), _field);
                return _field;
            }
            return String.Empty;
        }

        /// <summary>
        /// 返回最近的一个!并删除
        /// </summary>
        /// <param name="skey"></param>
        /// <param name="_time">yyyyMMddHHmmss</param>
        /// <returns></returns>
        public async Task<string> SortedSetRangeByScoreAsync(string skey, long _time)
        {
            var reads = await _database.SortedSetRangeByScoreAsync(setKey(skey), 0, _time, take: 1);
            if (reads != null && reads.Length > 0)
            {
                var _field = reads[0].ToString();
                await _database.SortedSetRemoveAsync(setKey(skey), _field);
                return _field;
            }
            return String.Empty;
        }

        /// <summary>
        /// 获取当前排期最长的任务时间戳 如果没有则返回当前时间戳
        /// </summary>
        /// <param name="skey"></param>
        /// <returns>时间戳秒</returns>
        public async Task<long> SortedSetRangeByRankWithScoresAsync(string skey)
        {
            var _read = await _database.SortedSetRangeByRankWithScoresAsync(setKey(skey), 0, 1, Order.Descending);
            if (_read != null && _read.Length > 0)
            {
                var _current = _read[0];
                return (long)_current.Score;
            }
            return DateTime.Now.ToUnixTimeSeconds();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="skey"></param>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        public List<string> ListRange(string skey, int start = 0, int stop = 30)
        {
            var vals = _database.ListRange(setKey(skey), start, stop);
            if (vals != null && vals.Length > 0)
            {
                var strs = new List<string>();
                foreach (var item in vals)
                {
                    if (item.HasValue)
                    {
                        strs.Add(item.ToString());
                    }
                }
                return strs;
            }
            return new List<string>();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="skey"></param>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        public async Task<List<string>> ListRangeAsync(string skey, int start = 0, int stop = 30)
        {
            var vals = await _database.ListRangeAsync(setKey(skey), start, stop);
            if (vals != null && vals.Length > 0)
            {
                var strs = new List<string>();
                foreach (var item in vals)
                {
                    if (item.HasValue)
                    {
                        strs.Add(item.ToString());
                    }
                }
                return strs;
            }
            return new List<string>();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="skey"></param>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        public List<T> ListRange<T>(string skey, int start = 0, int stop = 30)
        {
            var vals = _database.ListRange(setKey(skey), start, stop);
            if (vals != null && vals.Length > 0)
            {
                var strs = new List<T>();
                foreach (var item in vals)
                {
                    if (item.HasValue)
                    {
                        strs.Add(JsonSerializer.Deserialize<T>(item.ToString(), JsonConfig.Options));// Newtonsoft.Json.JsonConvert.DeserializeObject<T>(item.ToString()));
                    }
                }
                return strs;
            }
            return new List<T>();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="skey"></param>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        public async Task<List<T>> ListRangeAsync<T>(string skey, int start = 0, int stop = 30)
        {
            var vals = await _database.ListRangeAsync(setKey(skey), start, stop);
            if (vals != null && vals.Length > 0)
            {
                var strs = new List<T>();
                foreach (var item in vals)
                {
                    if (item.HasValue)
                    {
                        strs.Add(JsonSerializer.Deserialize<T>(item.ToString(), JsonConfig.Options));
                    }
                }
                return strs;
            }
            return new List<T>();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="skey"></param>
        /// <param name="sval"></param>
        /// <returns></returns>
        public async Task<long> ListRightPushAsync(string skey, string sval)
        {
            return await _database.ListRightPushAsync(setKey(skey), sval);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="skey"></param>
        /// <returns></returns>
        public async Task<long> ListLengthAsync(string skey)
        {
            return await _database.ListLengthAsync(setKey(skey));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="skey"></param>
        /// <returns></returns>
        public async Task<string> ListLeftPopAsync(string skey)
        {
            return await _database.ListLeftPopAsync(setKey(skey));
        }




        #endregion



        #endregion



    }



}
​ ​