You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
576 lines
21 KiB
576 lines
21 KiB
|
3 months ago
|
//------------------------------------------------------------------------------
|
||
|
|
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||
|
|
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||
|
|
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||
|
|
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||
|
|
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||
|
|
// Github源代码仓库:https://github.com/RRQM
|
||
|
|
// API首页:https://www.yuque.com/rrqm/touchsocket/index
|
||
|
|
// 交流QQ群:234762506
|
||
|
|
// 感谢您的下载和使用
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
using System;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
using TouchSocket.Core;
|
||
|
|
using TouchSocket.Resources;
|
||
|
|
|
||
|
|
namespace TouchSocket.Rpc.TouchRpc
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 具有远程键值存贮的操作端。
|
||
|
|
/// </summary>
|
||
|
|
public abstract class RedisClient : ICache<string, byte[]>
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 序列化转换器。
|
||
|
|
/// </summary>
|
||
|
|
public BytesConverter Converter { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 超时设定。默认30000ms
|
||
|
|
/// </summary>
|
||
|
|
public int Timeout { get; set; } = 30 * 1000;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc cref="ICache{TKey, TValue}.AddCache(ICacheEntry{TKey, TValue})"/>
|
||
|
|
/// </summary>
|
||
|
|
/// <typeparam name="TValue"></typeparam>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="duration"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public bool Add<TValue>(string key, TValue value, int duration = 60000)
|
||
|
|
{
|
||
|
|
var cache = new CacheEntry<string, byte[]>(key)
|
||
|
|
{
|
||
|
|
Duration = TimeSpan.FromSeconds(duration)
|
||
|
|
};
|
||
|
|
if (!(value is byte[]))
|
||
|
|
{
|
||
|
|
cache.Value = Converter.ConvertTo(value);
|
||
|
|
}
|
||
|
|
return AddCache(cache);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="entity"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public bool AddCache(ICacheEntry<string, byte[]> entity)
|
||
|
|
{
|
||
|
|
if (ContainsCache(entity.Key))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return SetCache(entity);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="entity"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public Task<bool> AddCacheAsync(ICacheEntry<string, byte[]> entity)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return AddCache(entity);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public abstract void ClearCache();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public Task ClearCacheAsync()
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
ClearCache();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public abstract bool ContainsCache(string key);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public Task<bool> ContainsCacheAsync(string key)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return ContainsCache(key);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取缓存的键值对。
|
||
|
|
/// </summary>
|
||
|
|
/// <typeparam name="TValue"></typeparam>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public TValue Get<TValue>(string key)
|
||
|
|
{
|
||
|
|
if (TryGet<TValue>(key, out var cache))
|
||
|
|
{
|
||
|
|
return cache;
|
||
|
|
}
|
||
|
|
return default;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public abstract ICacheEntry<string, byte[]> GetCache(string key);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public Task<ICacheEntry<string, byte[]>> GetCacheAsync(string key)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return GetCache(key);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public abstract bool RemoveCache(string key);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public Task<bool> RemoveCacheAsync(string key)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return RemoveCache(key);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc cref="ICache{TKey, TValue}.SetCache(ICacheEntry{TKey, TValue})"/>
|
||
|
|
/// </summary>
|
||
|
|
/// <typeparam name="TValue"></typeparam>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="duration"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public bool Set<TValue>(string key, TValue value, int duration = 60000)
|
||
|
|
{
|
||
|
|
var cache = new CacheEntry<string, byte[]>(key)
|
||
|
|
{
|
||
|
|
Duration = TimeSpan.FromSeconds(duration)
|
||
|
|
};
|
||
|
|
if (value is byte[] bytes)
|
||
|
|
{
|
||
|
|
cache.Value = bytes;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
cache.Value = Converter.ConvertTo(value);
|
||
|
|
}
|
||
|
|
return SetCache(cache);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="entity"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public abstract bool SetCache(ICacheEntry<string, byte[]> entity);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="entity"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public Task<bool> SetCacheAsync(ICacheEntry<string, byte[]> entity)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return SetCache(entity);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取指定键的值。
|
||
|
|
/// </summary>
|
||
|
|
/// <typeparam name="TValue"></typeparam>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ArgumentNullException">参数为空</exception>
|
||
|
|
/// <exception cref="TimeoutException">操作超时</exception>
|
||
|
|
/// <exception cref="Exception">其他异常</exception>
|
||
|
|
public bool TryGet<TValue>(string key, out TValue value)
|
||
|
|
{
|
||
|
|
var cache = GetCache(key);
|
||
|
|
|
||
|
|
if (cache != null)
|
||
|
|
{
|
||
|
|
if (cache.Value is null)
|
||
|
|
{
|
||
|
|
value = default;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
if (cache.Value is TValue value1)
|
||
|
|
{
|
||
|
|
value = value1;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
value = (TValue)Converter.ConvertFrom(cache.Value, typeof(TValue));
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
value = default;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// RedisClient
|
||
|
|
/// </summary>
|
||
|
|
internal class InternalRedisClient : RedisClient
|
||
|
|
{
|
||
|
|
private readonly RpcActor m_rpcActor;
|
||
|
|
|
||
|
|
public InternalRedisClient(RpcActor rpcActor, BytesConverter converter)
|
||
|
|
{
|
||
|
|
m_rpcActor = rpcActor;
|
||
|
|
Converter = converter;
|
||
|
|
}
|
||
|
|
|
||
|
|
public override void ClearCache()
|
||
|
|
{
|
||
|
|
var package = new RedisRequestWaitPackage
|
||
|
|
{
|
||
|
|
packageType = RedisPackageType.Clear
|
||
|
|
};
|
||
|
|
|
||
|
|
var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
using (ByteBlock byteBlock = new ByteBlock())
|
||
|
|
{
|
||
|
|
package.Package(byteBlock);
|
||
|
|
m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||
|
|
}
|
||
|
|
switch (waitData.Wait(Timeout))
|
||
|
|
{
|
||
|
|
case WaitDataStatus.SetRunning:
|
||
|
|
{
|
||
|
|
if (waitData.WaitResult.Status == 1)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
throw new Exception(waitData.WaitResult.Message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Overtime: throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription());
|
||
|
|
case WaitDataStatus.Canceled:
|
||
|
|
case WaitDataStatus.Default:
|
||
|
|
case WaitDataStatus.Disposed:
|
||
|
|
default:
|
||
|
|
throw new Exception(TouchSocketStatus.UnknownError.GetDescription());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
m_rpcActor.WaitHandlePool.Destroy(waitData);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public override bool ContainsCache(string key)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrEmpty(key))
|
||
|
|
{
|
||
|
|
throw new ArgumentException($"“{nameof(key)}”不能为 null 或空。", nameof(key));
|
||
|
|
}
|
||
|
|
|
||
|
|
var package = new RedisRequestWaitPackage
|
||
|
|
{
|
||
|
|
key = key,
|
||
|
|
packageType = RedisPackageType.Contains
|
||
|
|
};
|
||
|
|
|
||
|
|
var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
using (ByteBlock byteBlock = new ByteBlock())
|
||
|
|
{
|
||
|
|
package.Package(byteBlock);
|
||
|
|
m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||
|
|
}
|
||
|
|
switch (waitData.Wait(Timeout))
|
||
|
|
{
|
||
|
|
case WaitDataStatus.SetRunning:
|
||
|
|
{
|
||
|
|
if (waitData.WaitResult.Status == 1)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
else if (waitData.WaitResult.Status == byte.MaxValue)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
throw new Exception(waitData.WaitResult.Message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Overtime: throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription());
|
||
|
|
case WaitDataStatus.Canceled:
|
||
|
|
case WaitDataStatus.Default:
|
||
|
|
case WaitDataStatus.Disposed:
|
||
|
|
default:
|
||
|
|
throw new Exception(TouchSocketStatus.UnknownError.GetDescription());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
m_rpcActor.WaitHandlePool.Destroy(waitData);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public override ICacheEntry<string, byte[]> GetCache(string key)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrEmpty(key))
|
||
|
|
{
|
||
|
|
throw new ArgumentException($"“{nameof(key)}”不能为 null 或空。", nameof(key));
|
||
|
|
}
|
||
|
|
|
||
|
|
RedisRequestWaitPackage package = new RedisRequestWaitPackage()
|
||
|
|
{
|
||
|
|
key = key,
|
||
|
|
packageType = RedisPackageType.Get
|
||
|
|
};
|
||
|
|
|
||
|
|
var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
using (ByteBlock byteBlock = new ByteBlock((package.value == null ? 0 : package.value.Length) + 1024))
|
||
|
|
{
|
||
|
|
package.Package(byteBlock);
|
||
|
|
m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||
|
|
}
|
||
|
|
switch (waitData.Wait(Timeout))
|
||
|
|
{
|
||
|
|
case WaitDataStatus.SetRunning:
|
||
|
|
{
|
||
|
|
RedisResponseWaitPackage responsePackage = (RedisResponseWaitPackage)waitData.WaitResult;
|
||
|
|
if (responsePackage.Status == 1)
|
||
|
|
{
|
||
|
|
return new CacheEntry<string, byte[]>(key)
|
||
|
|
{
|
||
|
|
Value = responsePackage.value
|
||
|
|
};
|
||
|
|
}
|
||
|
|
else if (responsePackage.Status == byte.MaxValue)
|
||
|
|
{
|
||
|
|
return new CacheEntry<string, byte[]>(key);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return default;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Overtime: throw new TimeoutException(TouchSocketStatus.Overtime.GetDescription());
|
||
|
|
case WaitDataStatus.Canceled:
|
||
|
|
case WaitDataStatus.Default:
|
||
|
|
case WaitDataStatus.Disposed:
|
||
|
|
default:
|
||
|
|
throw new TimeoutException(TouchSocketStatus.UnknownError.GetDescription());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
m_rpcActor.WaitHandlePool.Destroy(waitData);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public override bool RemoveCache(string key)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrEmpty(key))
|
||
|
|
{
|
||
|
|
throw new ArgumentException($"“{nameof(key)}”不能为 null 或空。", nameof(key));
|
||
|
|
}
|
||
|
|
|
||
|
|
var package = new RedisRequestWaitPackage
|
||
|
|
{
|
||
|
|
key = key,
|
||
|
|
packageType = RedisPackageType.Remove
|
||
|
|
};
|
||
|
|
|
||
|
|
var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
using (ByteBlock byteBlock = new ByteBlock((package.value == null ? 0 : package.value.Length) + 1024))
|
||
|
|
{
|
||
|
|
package.Package(byteBlock);
|
||
|
|
m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||
|
|
}
|
||
|
|
switch (waitData.Wait(Timeout))
|
||
|
|
{
|
||
|
|
case WaitDataStatus.SetRunning:
|
||
|
|
{
|
||
|
|
if (waitData.WaitResult.Status == 1)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
else if (waitData.WaitResult.Status == byte.MaxValue)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
throw new Exception(waitData.WaitResult.Message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Overtime: throw new TimeoutException(Resources.TouchSocketStatus.Overtime.GetDescription());
|
||
|
|
case WaitDataStatus.Canceled: return false;
|
||
|
|
case WaitDataStatus.Default:
|
||
|
|
case WaitDataStatus.Disposed:
|
||
|
|
default:
|
||
|
|
throw new TimeoutException(Resources.TouchSocketStatus.UnknownError.GetDescription());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
m_rpcActor.WaitHandlePool.Destroy(waitData);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public override bool SetCache(ICacheEntry<string, byte[]> cache)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrEmpty(cache.Key))
|
||
|
|
{
|
||
|
|
throw new ArgumentException($"“{nameof(cache.Key)}”不能为 null 或空。", nameof(cache.Key));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (cache is null)
|
||
|
|
{
|
||
|
|
throw new ArgumentNullException(nameof(cache));
|
||
|
|
}
|
||
|
|
|
||
|
|
var package = new RedisRequestWaitPackage
|
||
|
|
{
|
||
|
|
key = cache.Key,
|
||
|
|
timeSpan = cache.Duration,
|
||
|
|
value = cache.Value,
|
||
|
|
packageType = RedisPackageType.Set
|
||
|
|
};
|
||
|
|
|
||
|
|
var waitData = m_rpcActor.WaitHandlePool.GetWaitData(package);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
using (ByteBlock byteBlock = new ByteBlock((package.value == null ? 0 : package.value.Length) + 1024))
|
||
|
|
{
|
||
|
|
package.Package(byteBlock);
|
||
|
|
m_rpcActor.Send(TouchRpcUtility.P_600_Redis_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||
|
|
}
|
||
|
|
switch (waitData.Wait(Timeout))
|
||
|
|
{
|
||
|
|
case WaitDataStatus.SetRunning:
|
||
|
|
{
|
||
|
|
if (waitData.WaitResult.Status == 1)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
else if (waitData.WaitResult.Status == byte.MaxValue)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
throw new Exception(waitData.WaitResult.Message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Overtime: throw new TimeoutException(Resources.TouchSocketStatus.Overtime.GetDescription());
|
||
|
|
case WaitDataStatus.Canceled: return false;
|
||
|
|
case WaitDataStatus.Default:
|
||
|
|
case WaitDataStatus.Disposed:
|
||
|
|
default:
|
||
|
|
throw new TimeoutException(Resources.TouchSocketStatus.UnknownError.GetDescription());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
m_rpcActor.WaitHandlePool.Destroy(waitData);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|