Unity Udexreal开发插件包
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

//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在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);
}
}
}
}