mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-19 09:56:44 +08:00
同步源代码
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>logo.ico</ApplicationIcon>
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>..\Keys\TouchSocket.snk</AssemblyOriginatorKeyFile>
|
||||
<Version>2.0.0-beta.186</Version>
|
||||
<AssemblyOriginatorKeyFile>Sign.snk</AssemblyOriginatorKeyFile>
|
||||
<Version>2.0.0-beta.196</Version>
|
||||
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||
<Company>若汝棋茗</Company>
|
||||
<Copyright>Copyright © 2023 若汝棋茗</Copyright>
|
||||
|
||||
Binary file not shown.
BIN
src/TouchSocket.AspNetCore/Sign.snk
Normal file
BIN
src/TouchSocket.AspNetCore/Sign.snk
Normal file
Binary file not shown.
BIN
src/TouchSocket.CodeAnalyzer/Sign.snk
Normal file
BIN
src/TouchSocket.CodeAnalyzer/Sign.snk
Normal file
Binary file not shown.
@@ -2,7 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net45;netstandard2.0;</TargetFrameworks>
|
||||
<PackageTags>rpc,analyzer</PackageTags>
|
||||
<Description>这是一个为TouchSocket全系提供语法分析、源代码生成的库。目前包含Rpc源代理代码生成。 </Description>
|
||||
<Description>这是一个为TouchSocket全系提供语法分析、源生成的库。目前包含Rpc源生成、插件源生成、IOC容器源生成。 </Description>
|
||||
<Title>TouchSocket.CodeAnalyzer</Title>
|
||||
<PackageOutputPath>..\..\Build\NugetPackages\TouchSocket.CodeAnalyzer</PackageOutputPath>
|
||||
<DevelopmentDependency>true</DevelopmentDependency>
|
||||
|
||||
BIN
src/TouchSocket.Core.DependencyInjection/Sign.snk
Normal file
BIN
src/TouchSocket.Core.DependencyInjection/Sign.snk
Normal file
Binary file not shown.
@@ -11,6 +11,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
@@ -25,8 +26,7 @@ namespace TouchSocket.Core
|
||||
public class AppMessenger
|
||||
{
|
||||
private static AppMessenger m_instance;
|
||||
private readonly ReaderWriterLockSlim m_lockSlim = new ReaderWriterLockSlim();
|
||||
private readonly Dictionary<string, List<MessageInstance>> m_tokenAndInstance = new Dictionary<string, List<MessageInstance>>();
|
||||
private readonly ConcurrentDictionary<string, List<MessageInstance>> m_tokenAndInstance = new ConcurrentDictionary<string, List<MessageInstance>>();
|
||||
|
||||
/// <summary>
|
||||
/// 默认单例实例
|
||||
@@ -64,25 +64,24 @@ namespace TouchSocket.Core
|
||||
/// <exception cref="MessageRegisteredException"></exception>
|
||||
public void Add(string token, MessageInstance messageInstance)
|
||||
{
|
||||
using (var writeLock = new WriteLock(this.m_lockSlim))
|
||||
{
|
||||
if (this.m_tokenAndInstance.ContainsKey(token))
|
||||
|
||||
if (this.m_tokenAndInstance.TryGetValue(token, out var value))
|
||||
{
|
||||
if (!this.AllowMultiple)
|
||||
{
|
||||
throw new MessageRegisteredException(TouchSocketCoreResource.TokenExisted.GetDescription(token));
|
||||
}
|
||||
this.m_tokenAndInstance[token].Add(messageInstance);
|
||||
|
||||
value.Add(messageInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_tokenAndInstance.Add(token, new List<MessageInstance>()
|
||||
this.m_tokenAndInstance.TryAdd(token, new List<MessageInstance>()
|
||||
{
|
||||
messageInstance
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断能否触发该消息,意味着该消息是否已经注册。
|
||||
@@ -90,34 +89,25 @@ namespace TouchSocket.Core
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public bool CanSendMessage(string token)
|
||||
{
|
||||
using (var readLock = new ReadLock(this.m_lockSlim))
|
||||
{
|
||||
return this.m_tokenAndInstance.ContainsKey(token);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除所有消息
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
using (var writeLock = new WriteLock(this.m_lockSlim))
|
||||
{
|
||||
this.m_tokenAndInstance.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有消息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string[] GetAllMessage()
|
||||
public IEnumerable<string> GetAllMessage()
|
||||
{
|
||||
using (var readLock = new ReadLock(this.m_lockSlim))
|
||||
{
|
||||
return this.m_tokenAndInstance.Keys.ToArray();
|
||||
}
|
||||
return this.m_tokenAndInstance.Keys;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -126,10 +116,7 @@ namespace TouchSocket.Core
|
||||
/// <param name="token"></param>
|
||||
public void Remove(string token)
|
||||
{
|
||||
using (var writeLock = new WriteLock(this.m_lockSlim))
|
||||
{
|
||||
this.m_tokenAndInstance.Remove(token);
|
||||
}
|
||||
this.m_tokenAndInstance.TryRemove(token,out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -137,8 +124,6 @@ namespace TouchSocket.Core
|
||||
/// </summary>
|
||||
/// <param name="messageObject"></param>
|
||||
public void Remove(IMessageObject messageObject)
|
||||
{
|
||||
using (var writeLock = new WriteLock(this.m_lockSlim))
|
||||
{
|
||||
var key = new List<string>();
|
||||
|
||||
@@ -159,8 +144,7 @@ namespace TouchSocket.Core
|
||||
|
||||
foreach (var item in key)
|
||||
{
|
||||
this.m_tokenAndInstance.Remove(item);
|
||||
}
|
||||
this.m_tokenAndInstance.TryRemove(item,out _);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,11 +154,7 @@ namespace TouchSocket.Core
|
||||
/// <param name="token"></param>
|
||||
/// <param name="parameters"></param>
|
||||
/// <exception cref="MessageNotFoundException"></exception>
|
||||
public Task SendAsync(string token, params object[] parameters)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
using (var readLock = new ReadLock(this.m_lockSlim))
|
||||
public async Task SendAsync(string token, params object[] parameters)
|
||||
{
|
||||
if (this.m_tokenAndInstance.TryGetValue(token, out var list))
|
||||
{
|
||||
@@ -187,13 +167,7 @@ namespace TouchSocket.Core
|
||||
clear.Add(item);
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
item.Invoke(item.MessageObject, parameters);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
await item.InvokeAsync(item.MessageObject, parameters);
|
||||
}
|
||||
|
||||
foreach (var item in clear)
|
||||
@@ -206,8 +180,6 @@ namespace TouchSocket.Core
|
||||
throw new MessageNotFoundException(TouchSocketCoreResource.MessageNotFound.GetDescription(token));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息,当多播时,只返回最后一个返回值
|
||||
@@ -217,11 +189,7 @@ namespace TouchSocket.Core
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="MessageNotFoundException"></exception>
|
||||
public Task<T> SendAsync<T>(string token, params object[] parameters)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
using (var readLock = new ReadLock(this.m_lockSlim))
|
||||
public async Task<T> SendAsync<T>(string token, params object[] parameters)
|
||||
{
|
||||
if (this.m_tokenAndInstance.TryGetValue(token, out var list))
|
||||
{
|
||||
@@ -236,19 +204,13 @@ namespace TouchSocket.Core
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (i == list.Count - 1)
|
||||
{
|
||||
result = (T)item.Invoke(item.MessageObject, parameters);
|
||||
result = await item.InvokeAsync<T>(item.MessageObject, parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Invoke(item.MessageObject, parameters);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await item.InvokeAsync<T>(item.MessageObject, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +225,5 @@ namespace TouchSocket.Core
|
||||
throw new MessageNotFoundException(TouchSocketCoreResource.MessageNotFound.GetDescription(token));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,7 @@ using System.Runtime.CompilerServices;
|
||||
namespace TouchSocket.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 具有释放的对象。
|
||||
/// 并未实现析构函数相关。
|
||||
/// 具有释放的对象。内部实现了GC.SuppressFinalize,但不包括析构函数相关。
|
||||
/// </summary>
|
||||
public class DisposableObject : IDisposable
|
||||
{
|
||||
|
||||
@@ -67,6 +67,11 @@ namespace TouchSocket.Core
|
||||
byteBlock.Read(out var header, this.HeaderLength);
|
||||
if (requestInfo.OnParsingHeader(header))
|
||||
{
|
||||
if (requestInfo.BodyLength>this.MaxPackageSize)
|
||||
{
|
||||
this.OnError($"接收的BodyLength={requestInfo.BodyLength},大于设定的MaxPackageSize={this.MaxPackageSize}");
|
||||
return FilterResult.GoOn;
|
||||
}
|
||||
request = requestInfo;
|
||||
if (requestInfo.BodyLength > byteBlock.CanReadLen)//body不满足解析,开始缓存,然后保存对象
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ using System.Collections.Generic;
|
||||
namespace TouchSocket.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 普通TCP数据处理器,该适配器不对数据做任何处理。
|
||||
/// 普通Tcp数据处理器,该适配器不对数据做任何处理。
|
||||
/// </summary>
|
||||
public class NormalDataHandlingAdapter : SingleStreamDataHandlingAdapter
|
||||
{
|
||||
|
||||
@@ -83,6 +83,7 @@ namespace TouchSocket.Core
|
||||
{
|
||||
return descriptor.ImplementationFactory.Invoke(this);
|
||||
}
|
||||
|
||||
if (descriptor.Lifetime == Lifetime.Singleton)
|
||||
{
|
||||
if (descriptor.ToInstance != null)
|
||||
@@ -99,22 +100,23 @@ namespace TouchSocket.Core
|
||||
{
|
||||
if (descriptor.ToType.IsGenericType)
|
||||
{
|
||||
return (descriptor.ToInstance = this.Create(descriptor.ToType.MakeGenericType(fromType.GetGenericArguments()), ps));
|
||||
return (descriptor.ToInstance = this.Create(descriptor,descriptor.ToType.MakeGenericType(fromType.GetGenericArguments()), ps));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (descriptor.ToInstance = this.Create(descriptor.ToType, ps));
|
||||
return (descriptor.ToInstance = this.Create(descriptor,descriptor.ToType, ps));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptor.ToType.IsGenericType)
|
||||
{
|
||||
return this.Create(descriptor.ToType.MakeGenericType(fromType.GetGenericArguments()), ps);
|
||||
return this.Create(descriptor,descriptor.ToType.MakeGenericType(fromType.GetGenericArguments()), ps);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.Create(descriptor.ToType, ps);
|
||||
return this.Create(descriptor,descriptor.ToType, ps);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,10 +135,10 @@ namespace TouchSocket.Core
|
||||
}
|
||||
lock (descriptor)
|
||||
{
|
||||
return descriptor.ToInstance ??= this.Create(descriptor.ToType, ps);
|
||||
return descriptor.ToInstance ??= this.Create(descriptor,descriptor.ToType, ps);
|
||||
}
|
||||
}
|
||||
return this.Create(descriptor.ToType, ps);
|
||||
return this.Create(descriptor,descriptor.ToType, ps);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -162,13 +164,7 @@ namespace TouchSocket.Core
|
||||
this.m_registrations.TryRemove(k, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="toType"></param>
|
||||
/// <param name="ops"></param>
|
||||
/// <returns></returns>
|
||||
private object Create(Type toType, object[] ops)
|
||||
private object Create(DependencyDescriptor descriptor,Type toType, object[] ops)
|
||||
{
|
||||
var ctor = toType.GetConstructors().FirstOrDefault(x => x.IsDefined(typeof(DependencyInjectAttribute), true));
|
||||
if (ctor is null)
|
||||
@@ -283,6 +279,7 @@ namespace TouchSocket.Core
|
||||
item.Invoke(instance, ps);
|
||||
}
|
||||
}
|
||||
descriptor.OnResolved?.Invoke(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,14 @@ namespace TouchSocket.Core
|
||||
/// </summary>
|
||||
public Func<IContainer, object> ImplementationFactory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 在获取到注册时触发委托。
|
||||
/// <para>
|
||||
/// 在单例实例注册时,不会触发。在单例注册时,只会触发一次,在瞬态注册时,会每次都触发。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public Action<object> OnResolved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实例类型
|
||||
/// </summary>
|
||||
|
||||
@@ -205,7 +205,7 @@ namespace TouchSocket.Core
|
||||
public static string GetDeterminantName(this MethodInfo methodInfo)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
stringBuilder.Append($"{methodInfo.DeclaringType?.Namespace}.{methodInfo.DeclaringType?.Name}.{methodInfo.Name}(");
|
||||
stringBuilder.Append($"{methodInfo.DeclaringType?.Namespace}.{methodInfo.DeclaringType?.Name}.{methodInfo.GetName()}(");
|
||||
|
||||
foreach (var item in methodInfo.GetParameters())
|
||||
{
|
||||
|
||||
@@ -18,11 +18,6 @@ namespace TouchSocket.Core
|
||||
/// </summary>
|
||||
protected DateTime m_lastIncrement;
|
||||
|
||||
/// <summary>
|
||||
/// 当达到一个周期时触发。
|
||||
/// </summary>
|
||||
public Action<long> OnPeriod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 周期内的累计计数值。
|
||||
/// </summary>
|
||||
@@ -33,6 +28,11 @@ namespace TouchSocket.Core
|
||||
/// </summary>
|
||||
public DateTime LastIncrement { get => this.m_lastIncrement; }
|
||||
|
||||
/// <summary>
|
||||
/// 当达到一个周期时触发。
|
||||
/// </summary>
|
||||
public Action<long> OnPeriod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 计数周期。默认1秒。
|
||||
/// </summary>
|
||||
@@ -60,5 +60,14 @@ namespace TouchSocket.Core
|
||||
Interlocked.Add(ref this.m_count, value);
|
||||
return isPeriod;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置<see cref="Count"/>和<see cref="LastIncrement"/>
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
this.m_count = 0;
|
||||
this.m_lastIncrement = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,15 @@ namespace TouchSocket.Core
|
||||
/// </summary>
|
||||
public TimeSpan Period { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重置<see cref="Count"/>和<see cref="LastIncrement"/>
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
this.m_count = 0;
|
||||
this.m_lastIncrement = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 累计增加计数
|
||||
/// </summary>
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace TouchSocket.Core
|
||||
/// 忽略的Fast序列化
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class FastNonSerializedAttribute : Attribute
|
||||
public sealed class FastNonSerializedAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace TouchSocket.Core
|
||||
/// 强制Fast序列化。一般当某个属性为只读时,使用该特性。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class FastSerializedAttribute : Attribute
|
||||
public sealed class FastSerializedAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Core
|
||||
{
|
||||
internal class StringFastBinaryConverter : FastBinaryConverter<string>
|
||||
{
|
||||
protected override string Read(byte[] buffer, int offset, int len)
|
||||
{
|
||||
var byteBlock = new ValueByteBlock(buffer)
|
||||
{
|
||||
Pos = offset
|
||||
};
|
||||
return byteBlock.ReadString();
|
||||
}
|
||||
|
||||
protected override int Write(ByteBlock byteBlock, string obj)
|
||||
{
|
||||
var pos = byteBlock.Pos;
|
||||
byteBlock.Write(obj);
|
||||
return byteBlock.Pos - pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,23 +15,35 @@ using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Runtime;
|
||||
using System.Text;
|
||||
#if NET6_0_OR_GREATER
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
#endif
|
||||
|
||||
|
||||
namespace TouchSocket.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 快速二进制序列化。
|
||||
/// </summary>
|
||||
public static class FastBinaryFormatter
|
||||
public static partial class FastBinaryFormatter
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
/// <summary>
|
||||
/// DynamicallyAccessed
|
||||
/// </summary>
|
||||
public const DynamicallyAccessedMemberTypes DynamicallyAccessed = DynamicallyAccessedMemberTypes.All;
|
||||
#endif
|
||||
static FastBinaryFormatter()
|
||||
{
|
||||
AddFastBinaryConverter<Version, VersionFastBinaryConverter>();
|
||||
AddFastBinaryConverter<ByteBlock, ByteBlockFastBinaryConverter>();
|
||||
AddFastBinaryConverter<MemoryStream, MemoryStreamFastBinaryConverter>();
|
||||
AddFastBinaryConverter<Guid, GuidFastBinaryConverter>();
|
||||
AddFastBinaryConverter<DataTable, DataTableFastBinaryConverter>();
|
||||
AddFastBinaryConverter<DataSet, DataSetFastBinaryConverter>();
|
||||
AddFastBinaryConverter(typeof(string), new StringFastBinaryConverter());
|
||||
AddFastBinaryConverter(typeof(Version), new VersionFastBinaryConverter());
|
||||
AddFastBinaryConverter(typeof(ByteBlock), new ByteBlockFastBinaryConverter());
|
||||
AddFastBinaryConverter(typeof(MemoryStream), new MemoryStreamFastBinaryConverter());
|
||||
AddFastBinaryConverter(typeof(Guid), new GuidFastBinaryConverter());
|
||||
AddFastBinaryConverter(typeof(DataTable), new DataTableFastBinaryConverter());
|
||||
AddFastBinaryConverter(typeof(DataSet), new DataSetFastBinaryConverter());
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<Type, SerializObject> m_instanceCache = new ConcurrentDictionary<Type, SerializObject>();
|
||||
@@ -39,7 +51,12 @@ namespace TouchSocket.Core
|
||||
/// <summary>
|
||||
/// 添加转换器。
|
||||
/// </summary>
|
||||
#if NET6_0_OR_GREATER
|
||||
public static void AddFastBinaryConverter<[DynamicallyAccessedMembers(DynamicallyAccessed)] TType, [DynamicallyAccessedMembers(DynamicallyAccessed)] TConverter>() where TConverter : IFastBinaryConverter, new()
|
||||
#else
|
||||
public static void AddFastBinaryConverter<TType, TConverter>() where TConverter : IFastBinaryConverter, new()
|
||||
#endif
|
||||
|
||||
{
|
||||
AddFastBinaryConverter(typeof(TType), (IFastBinaryConverter)Activator.CreateInstance(typeof(TConverter)));
|
||||
}
|
||||
@@ -49,7 +66,11 @@ namespace TouchSocket.Core
|
||||
/// </summary>
|
||||
/// <typeparam name="TType"></typeparam>
|
||||
/// <param name="converter"></param>
|
||||
#if NET6_0_OR_GREATER
|
||||
public static void AddFastBinaryConverter<[DynamicallyAccessedMembers(DynamicallyAccessed)] TType>(IFastBinaryConverter converter)
|
||||
#else
|
||||
public static void AddFastBinaryConverter<TType>(IFastBinaryConverter converter)
|
||||
#endif
|
||||
{
|
||||
AddFastBinaryConverter(typeof(TType), converter);
|
||||
}
|
||||
@@ -59,9 +80,14 @@ namespace TouchSocket.Core
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="converter"></param>
|
||||
#if NET6_0_OR_GREATER
|
||||
public static void AddFastBinaryConverter([DynamicallyAccessedMembers(DynamicallyAccessed)] Type type, IFastBinaryConverter converter)
|
||||
#else
|
||||
public static void AddFastBinaryConverter(Type type, IFastBinaryConverter converter)
|
||||
#endif
|
||||
{
|
||||
m_instanceCache.AddOrUpdate(type, new SerializObject(type) { Converter = converter }, (k, v) => v);
|
||||
var serializObject = new SerializObject(type, converter);
|
||||
m_instanceCache.AddOrUpdate(type, serializObject, (k, v) => serializObject);
|
||||
}
|
||||
|
||||
#region Serialize
|
||||
@@ -71,12 +97,16 @@ namespace TouchSocket.Core
|
||||
/// </summary>
|
||||
/// <param name="byteBlock">流</param>
|
||||
/// <param name="graph">对象</param>
|
||||
#if NET6_0_OR_GREATER
|
||||
public static void Serialize<[DynamicallyAccessedMembers(DynamicallyAccessed)] T>(ByteBlock byteBlock, [DynamicallyAccessedMembers(DynamicallyAccessed)] in T graph)
|
||||
#else
|
||||
public static void Serialize<T>(ByteBlock byteBlock,in T graph)
|
||||
#endif
|
||||
{
|
||||
byteBlock.Pos = 1;
|
||||
byteBlock.Position = 1;
|
||||
SerializeObject(byteBlock, graph);
|
||||
byteBlock.Buffer[0] = 1;
|
||||
byteBlock.SetLength(byteBlock.Pos);
|
||||
byteBlock.SetLength(byteBlock.Position);
|
||||
}
|
||||
|
||||
private static int SerializeClass<T>(ByteBlock stream, T obj, Type type)
|
||||
@@ -126,8 +156,8 @@ namespace TouchSocket.Core
|
||||
var len = 0;
|
||||
if (param != null)
|
||||
{
|
||||
var oldPosition = stream.Pos;
|
||||
stream.Pos += 4;
|
||||
var oldPosition = stream.Position;
|
||||
stream.Position += 4;
|
||||
len += 4;
|
||||
uint paramLen = 0;
|
||||
|
||||
@@ -137,10 +167,10 @@ namespace TouchSocket.Core
|
||||
len += SerializeObject(stream, DynamicMethodMemberAccessor.Default.GetValue(item, "Value"));
|
||||
paramLen++;
|
||||
}
|
||||
var newPosition = stream.Pos;
|
||||
stream.Pos = oldPosition;
|
||||
var newPosition = stream.Position;
|
||||
stream.Position = oldPosition;
|
||||
stream.Write(TouchSocketBitConverter.Default.GetBytes(paramLen));
|
||||
stream.Pos = newPosition;
|
||||
stream.Position = newPosition;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@@ -150,8 +180,8 @@ namespace TouchSocket.Core
|
||||
var len = 0;
|
||||
if (param != null)
|
||||
{
|
||||
var oldPosition = stream.Pos;
|
||||
stream.Pos += 4;
|
||||
var oldPosition = stream.Position;
|
||||
stream.Position += 4;
|
||||
len += 4;
|
||||
uint paramLen = 0;
|
||||
|
||||
@@ -160,10 +190,10 @@ namespace TouchSocket.Core
|
||||
paramLen++;
|
||||
len += SerializeObject(stream, item);
|
||||
}
|
||||
var newPosition = stream.Pos;
|
||||
stream.Pos = oldPosition;
|
||||
var newPosition = stream.Position;
|
||||
stream.Position = oldPosition;
|
||||
stream.Write(TouchSocketBitConverter.Default.GetBytes(paramLen));
|
||||
stream.Pos = newPosition;
|
||||
stream.Position = newPosition;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@@ -173,8 +203,8 @@ namespace TouchSocket.Core
|
||||
var len = 0;
|
||||
byte[] data = null;
|
||||
|
||||
var startPosition = byteBlock.Pos;
|
||||
int endPosition;
|
||||
var startPosition = byteBlock.Position;
|
||||
long endPosition;
|
||||
if (graph != null)
|
||||
{
|
||||
var type = graph.GetType();
|
||||
@@ -252,11 +282,11 @@ namespace TouchSocket.Core
|
||||
{
|
||||
switch (graph)
|
||||
{
|
||||
case string value:
|
||||
{
|
||||
data = Encoding.UTF8.GetBytes(value);
|
||||
break;
|
||||
}
|
||||
//case string value:
|
||||
// {
|
||||
// data = Encoding.UTF8.GetBytes(value);
|
||||
// break;
|
||||
// }
|
||||
case decimal value:
|
||||
{
|
||||
data = TouchSocketBitConverter.Default.GetBytes(value);
|
||||
@@ -302,7 +332,7 @@ namespace TouchSocket.Core
|
||||
}
|
||||
default:
|
||||
{
|
||||
byteBlock.Pos += 4;
|
||||
byteBlock.Position += 4;
|
||||
var serializeObj = GetOrAddInstance(type);
|
||||
if (serializeObj.Converter != null)
|
||||
{
|
||||
@@ -342,7 +372,7 @@ namespace TouchSocket.Core
|
||||
}
|
||||
else
|
||||
{
|
||||
endPosition = byteBlock.Pos;
|
||||
endPosition = byteBlock.Position;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -351,14 +381,14 @@ namespace TouchSocket.Core
|
||||
}
|
||||
|
||||
var lenBuffer = TouchSocketBitConverter.Default.GetBytes(len);
|
||||
byteBlock.Pos = startPosition;
|
||||
byteBlock.Position = startPosition;
|
||||
byteBlock.Write(lenBuffer, 0, lenBuffer.Length);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
byteBlock.Write(data, 0, data.Length);
|
||||
}
|
||||
byteBlock.Pos = endPosition;
|
||||
byteBlock.Position = endPosition;
|
||||
return len + 4;
|
||||
}
|
||||
|
||||
@@ -373,7 +403,11 @@ namespace TouchSocket.Core
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
#if NET6_0_OR_GREATER
|
||||
public static object Deserialize(byte[] data, int offset, [DynamicallyAccessedMembers(DynamicallyAccessed)] Type type)
|
||||
#else
|
||||
public static object Deserialize(byte[] data, int offset, Type type)
|
||||
#endif
|
||||
{
|
||||
if (data[offset] != 1)
|
||||
{
|
||||
@@ -390,16 +424,17 @@ namespace TouchSocket.Core
|
||||
{
|
||||
type = type.GenericTypeArguments[0];
|
||||
}
|
||||
dynamic obj;
|
||||
object obj;
|
||||
var len = TouchSocketBitConverter.Default.ToInt32(datas, offset);
|
||||
offset += 4;
|
||||
if (len > 0)
|
||||
{
|
||||
if (type == TouchSocketCoreUtility.stringType)
|
||||
{
|
||||
obj = Encoding.UTF8.GetString(datas, offset, len);
|
||||
}
|
||||
else if (type == TouchSocketCoreUtility.byteType)
|
||||
//if (type == TouchSocketCoreUtility.stringType)
|
||||
//{
|
||||
// obj = Encoding.UTF8.GetString(datas, offset, len);
|
||||
//}
|
||||
//else
|
||||
if (type == TouchSocketCoreUtility.byteType)
|
||||
{
|
||||
obj = datas[offset];
|
||||
}
|
||||
@@ -485,13 +520,20 @@ namespace TouchSocket.Core
|
||||
else if (type == TouchSocketCoreUtility.bytesType)
|
||||
{
|
||||
var data = new byte[len];
|
||||
Buffer.BlockCopy(datas, offset, data, 0, len);
|
||||
Array.Copy(datas, offset, data, 0, len);
|
||||
obj = data;
|
||||
}
|
||||
else if (type.IsClass || type.IsStruct())
|
||||
{
|
||||
var serializeObj = GetOrAddInstance(type);
|
||||
obj = serializeObj.Converter != null ? serializeObj.Converter.Read(datas, offset, len) : (dynamic)DeserializeClass(type, datas, offset, len);
|
||||
if (serializeObj.Converter != null)
|
||||
{
|
||||
obj = serializeObj.Converter.Read(datas, offset, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = DeserializeClass(type, datas, offset, len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -500,7 +542,14 @@ namespace TouchSocket.Core
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = nullable ? null : (dynamic)type.GetDefault();
|
||||
if (nullable)
|
||||
{
|
||||
obj = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = type.GetDefault();
|
||||
}
|
||||
}
|
||||
offset += len;
|
||||
return obj;
|
||||
@@ -655,24 +704,19 @@ namespace TouchSocket.Core
|
||||
#endregion Deserialize
|
||||
|
||||
private static SerializObject GetOrAddInstance(Type type)
|
||||
{
|
||||
if (m_instanceCache.TryGetValue(type, out var instance))
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
if (type.IsArray)//数组
|
||||
{
|
||||
var instanceObject = new SerializObject(type);
|
||||
m_instanceCache.TryAdd(type, instanceObject);
|
||||
return instanceObject;
|
||||
}
|
||||
else if (type.IsClass || type.IsStruct())
|
||||
{
|
||||
if (type.IsNullableType())
|
||||
{
|
||||
type = type.GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
if (m_instanceCache.TryGetValue(type, out var instance))
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
if (type.IsArray || type.IsClass || type.IsStruct())
|
||||
{
|
||||
var instanceObject = new SerializObject(type);
|
||||
m_instanceCache.TryAdd(type, instanceObject);
|
||||
return instanceObject;
|
||||
|
||||
@@ -17,12 +17,17 @@ using System.Reflection;
|
||||
|
||||
namespace TouchSocket.Core
|
||||
{
|
||||
internal class SerializObject
|
||||
internal sealed class SerializObject
|
||||
{
|
||||
private MemberInfo[] m_MemberInfos;
|
||||
private FieldInfo[] m_fieldInfos;
|
||||
private MemberInfo[] m_memberInfos;
|
||||
private PropertyInfo[] m_properties;
|
||||
public IFastBinaryConverter Converter { get; set; }
|
||||
|
||||
public SerializObject(Type type, IFastBinaryConverter converter)
|
||||
{
|
||||
this.Type = type;
|
||||
this.Converter = converter;
|
||||
}
|
||||
|
||||
public SerializObject(Type type)
|
||||
{
|
||||
@@ -101,13 +106,10 @@ namespace TouchSocket.Core
|
||||
this.IsStruct = type.IsStruct();
|
||||
}
|
||||
|
||||
public bool IsStruct { get; private set; }
|
||||
|
||||
public Method AddMethod { get; private set; }
|
||||
|
||||
public Type[] ArgTypes { get; private set; }
|
||||
|
||||
public Type ArrayType { get; private set; }
|
||||
public IFastBinaryConverter Converter { get; private set; }
|
||||
|
||||
public FieldInfo[] FieldInfos
|
||||
{
|
||||
@@ -118,27 +120,26 @@ namespace TouchSocket.Core
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, FieldInfo> FieldInfosDic { get; private set; }
|
||||
public InstanceType InstanceType { get; private set; }
|
||||
public bool IsStruct { get; private set; }
|
||||
public MemberAccessor MemberAccessor { get; private set; }
|
||||
|
||||
public MemberInfo[] MemberInfos
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.m_MemberInfos == null)
|
||||
if (this.m_memberInfos == null)
|
||||
{
|
||||
var infos = new List<MemberInfo>();
|
||||
infos.AddRange(this.FieldInfosDic.Values);
|
||||
infos.AddRange(this.PropertiesDic.Values);
|
||||
this.m_MemberInfos = infos.ToArray();
|
||||
this.m_memberInfos = infos.ToArray();
|
||||
}
|
||||
return this.m_MemberInfos;
|
||||
return this.m_memberInfos;
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, FieldInfo> FieldInfosDic { get; private set; }
|
||||
|
||||
public InstanceType InstanceType { get; private set; }
|
||||
|
||||
public MemberAccessor MemberAccessor { get; private set; }
|
||||
|
||||
public PropertyInfo[] Properties
|
||||
{
|
||||
get
|
||||
@@ -172,9 +173,7 @@ namespace TouchSocket.Core
|
||||
return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Default)
|
||||
.Where(p =>
|
||||
{
|
||||
return p.IsDefined(typeof(FastSerializedAttribute), true)
|
||||
? true
|
||||
: p.CanWrite &&
|
||||
return p.IsDefined(typeof(FastSerializedAttribute), true) || p.CanWrite &&
|
||||
p.CanRead &&
|
||||
(!p.IsDefined(typeof(FastNonSerializedAttribute), true) &&
|
||||
(p.SetMethod.GetParameters().Length == 1) &&
|
||||
|
||||
@@ -16,6 +16,10 @@ using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
#if NET6_0_OR_GREATER
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
#endif
|
||||
|
||||
|
||||
namespace TouchSocket.Core
|
||||
{
|
||||
@@ -186,7 +190,11 @@ namespace TouchSocket.Core
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
#if NET6_0_OR_GREATER
|
||||
public static void FastBinarySerialize<[DynamicallyAccessedMembers(FastBinaryFormatter.DynamicallyAccessed)] T>(ByteBlock stream, [DynamicallyAccessedMembers(FastBinaryFormatter.DynamicallyAccessed)] in T obj)
|
||||
#else
|
||||
public static void FastBinarySerialize<T>(ByteBlock stream, in T obj)
|
||||
#endif
|
||||
{
|
||||
FastBinaryFormatter.Serialize(stream, obj);
|
||||
}
|
||||
@@ -196,7 +204,11 @@ namespace TouchSocket.Core
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
#if NET6_0_OR_GREATER
|
||||
public static byte[] FastBinarySerialize<[DynamicallyAccessedMembers(FastBinaryFormatter.DynamicallyAccessed)] T>([DynamicallyAccessedMembers(FastBinaryFormatter.DynamicallyAccessed)] in T obj)
|
||||
#else
|
||||
public static byte[] FastBinarySerialize<T>(in T obj)
|
||||
#endif
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
@@ -216,7 +228,11 @@ namespace TouchSocket.Core
|
||||
/// <param name="data"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
#if NET6_0_OR_GREATER
|
||||
public static T FastBinaryDeserialize<[DynamicallyAccessedMembers(FastBinaryFormatter.DynamicallyAccessed)] T>(byte[] data, int offset)
|
||||
#else
|
||||
public static T FastBinaryDeserialize<T>(byte[] data, int offset)
|
||||
#endif
|
||||
{
|
||||
return (T)FastBinaryFormatter.Deserialize(data, offset, typeof(T));
|
||||
}
|
||||
@@ -228,7 +244,11 @@ namespace TouchSocket.Core
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
#if NET6_0_OR_GREATER
|
||||
public static object FastBinaryDeserialize(byte[] data, int offset, [DynamicallyAccessedMembers(FastBinaryFormatter.DynamicallyAccessed)] Type type)
|
||||
#else
|
||||
public static object FastBinaryDeserialize(byte[] data, int offset, Type type)
|
||||
#endif
|
||||
{
|
||||
return FastBinaryFormatter.Deserialize(data, offset, type);
|
||||
}
|
||||
@@ -239,11 +259,22 @@ namespace TouchSocket.Core
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
#if NET6_0_OR_GREATER
|
||||
public static T FastBinaryDeserialize<[DynamicallyAccessedMembers(FastBinaryFormatter.DynamicallyAccessed)] T>(byte[] data)
|
||||
#else
|
||||
public static T FastBinaryDeserialize<T>(byte[] data)
|
||||
#endif
|
||||
{
|
||||
return FastBinaryDeserialize<T>(data, 0);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
public static void AddFastBinary<[DynamicallyAccessedMembers(FastBinaryFormatter.DynamicallyAccessed)] T>()
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion Fast二进制反序列化
|
||||
|
||||
#region Xml序列化和反序列化
|
||||
|
||||
BIN
src/TouchSocket.Core/Sign.snk
Normal file
BIN
src/TouchSocket.Core/Sign.snk
Normal file
Binary file not shown.
@@ -40,6 +40,10 @@ namespace TouchSocket.Dmtp
|
||||
{
|
||||
throw new Exception($"无法将{nameof(requestInfo)}转换为{nameof(DmtpMessage)}");
|
||||
}
|
||||
if (message.BodyByteBlock!=null&&message.BodyByteBlock.Length>this.MaxPackageSize)
|
||||
{
|
||||
throw new Exception("发送的BodyLength={requestInfo.BodyLength},大于设定的MaxPackageSize={this.MaxPackageSize}");
|
||||
}
|
||||
using (var byteBlock = new ByteBlock(message.GetLength()))
|
||||
{
|
||||
message.Build(byteBlock);
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace TouchSocket.Dmtp
|
||||
/// <summary>
|
||||
/// DmtpUtility
|
||||
/// </summary>
|
||||
public partial class DmtpUtility
|
||||
public static partial class DmtpUtility
|
||||
{
|
||||
/// <summary>
|
||||
/// Dmtp字符串
|
||||
@@ -28,5 +28,15 @@ namespace TouchSocket.Dmtp
|
||||
/// Dmtp协议
|
||||
/// </summary>
|
||||
public static Protocol DmtpProtocol { get; private set; } = new Protocol(Dmtp);
|
||||
|
||||
/// <summary>
|
||||
/// 是否为Dmtp协议
|
||||
/// </summary>
|
||||
/// <param name="protocol"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsDmtp(this Protocol protocol)
|
||||
{
|
||||
return protocol == DmtpProtocol;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,7 +218,8 @@ namespace TouchSocket.Dmtp
|
||||
await Task.Delay(this.VerifyTimeout);
|
||||
if (!this.IsHandshaked)
|
||||
{
|
||||
this.Close("Handshak验证超时");
|
||||
this.TryShutdown();
|
||||
base.Close("Handshak验证超时");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,10 +73,10 @@ namespace TouchSocket.Dmtp
|
||||
public IDmtpActor DmtpActor { get => this.m_dmtpActor; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Id => this.m_dmtpActor.Id;
|
||||
public string Id => this.m_dmtpActor?.Id;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsHandshaked => this.m_dmtpActor.IsHandshaked;
|
||||
public bool IsHandshaked { get;private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastReceivedTime => this.m_receiveCounter.LastIncrement;
|
||||
@@ -154,6 +154,7 @@ namespace TouchSocket.Dmtp
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty),
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), CancellationToken.None);
|
||||
this.IsHandshaked = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -201,6 +202,7 @@ namespace TouchSocket.Dmtp
|
||||
this.m_dmtpActor.Handshake(this.Config.GetValue(DmtpConfigExtension.VerifyTokenProperty),
|
||||
this.Config.GetValue(DmtpConfigExtension.DefaultIdProperty),
|
||||
timeout, this.Config.GetValue(DmtpConfigExtension.MetadataProperty), token);
|
||||
this.IsHandshaked = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -339,6 +341,7 @@ namespace TouchSocket.Dmtp
|
||||
{
|
||||
if (this.IsHandshaked)
|
||||
{
|
||||
this.IsHandshaked = false;
|
||||
this.m_client.CloseAsync(WebSocketCloseStatus.NormalClosure, msg, CancellationToken.None);
|
||||
this.m_client.SafeDispose();
|
||||
this.DmtpActor.SafeDispose();
|
||||
|
||||
@@ -22,12 +22,11 @@ namespace TouchSocket.Dmtp.Redis
|
||||
/// <inheritdoc/>
|
||||
public BytesConverter Converter { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ICache<string, byte[]> ICache { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IDmtpActor DmtpActor { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ICache<string, byte[]> ICache { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public int Timeout { get; set; } = 30 * 1000;
|
||||
|
||||
@@ -414,16 +413,14 @@ namespace TouchSocket.Dmtp.Redis
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
return waitData.WaitResult.Status == 1
|
||||
? true
|
||||
: waitData.WaitResult.Status == byte.MaxValue ? false : throw new Exception(waitData.WaitResult.Message);
|
||||
return waitData.WaitResult.Status == 1 || (waitData.WaitResult.Status == byte.MaxValue ? false : throw new Exception(waitData.WaitResult.Message));
|
||||
}
|
||||
case WaitDataStatus.Overtime: throw new TimeoutException(Resources.TouchSocketDmtpStatus.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled: return false;
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new TimeoutException(Resources.TouchSocketDmtpStatus.UnknownError.GetDescription());
|
||||
throw new TimeoutException(TouchSocketDmtpStatus.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -190,7 +190,7 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
}
|
||||
|
||||
private void InvokeThis(object o)
|
||||
private async Task InvokeThis(object o)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -275,7 +275,7 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
{
|
||||
transientRpcServer.CallContext = callContext;
|
||||
}
|
||||
invokeResult = RpcStore.Execute(rpcServer, ps, callContext);
|
||||
invokeResult = await RpcStore.ExecuteAsync(rpcServer, ps, callContext);
|
||||
}
|
||||
|
||||
if (rpcPackage.Feedback == FeedbackType.OnlySend)
|
||||
@@ -392,7 +392,11 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
SourceId = this.DmtpActor.Id
|
||||
};
|
||||
var waitData = this.DmtpActor.WaitHandlePool.GetWaitData(rpcPackage);
|
||||
var byteBlock = new ByteBlock();
|
||||
|
||||
try
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = DmtpInvokeOption.WaitInvoke;
|
||||
@@ -403,9 +407,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
waitData.SetCancellationToken(invokeOption.Token);
|
||||
invokeOption.Token.Register(this.CanceledInvoke, new CanceledPackage() { SourceId = this.DmtpActor.Id, Sign = rpcPackage.Sign });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
rpcPackage.LoadInvokeOption(invokeOption);
|
||||
var datas = new List<byte[]>();
|
||||
foreach (var parameter in parameters)
|
||||
@@ -415,16 +416,17 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
rpcPackage.ParametersBytes = datas;
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -440,7 +442,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -481,7 +482,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
finally
|
||||
{
|
||||
this.DmtpActor.WaitHandlePool.Destroy(waitData);
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,7 +495,13 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
};
|
||||
|
||||
var waitData = this.DmtpActor.WaitHandlePool.GetWaitData(rpcPackage);
|
||||
var byteBlock = new ByteBlock();
|
||||
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = DmtpInvokeOption.WaitInvoke;
|
||||
@@ -507,8 +513,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
invokeOption.Token.Register(this.CanceledInvoke, new CanceledPackage() { SourceId = this.DmtpActor.Id, Sign = rpcPackage.Sign });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
rpcPackage.LoadInvokeOption(invokeOption);
|
||||
var datas = new List<byte[]>();
|
||||
foreach (var parameter in parameters)
|
||||
@@ -517,18 +521,17 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
rpcPackage.ParametersBytes = datas;
|
||||
rpcPackage.Package(byteBlock);
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
break;
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -544,7 +547,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -578,7 +580,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
finally
|
||||
{
|
||||
this.DmtpActor.WaitHandlePool.Destroy(waitData);
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,7 +593,11 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
};
|
||||
|
||||
var waitData = this.DmtpActor.WaitHandlePool.GetWaitData(rpcPackage);
|
||||
var byteBlock = new ByteBlock();
|
||||
|
||||
try
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = DmtpInvokeOption.WaitInvoke;
|
||||
@@ -604,8 +609,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
invokeOption.Token.Register(this.CanceledInvoke, new CanceledPackage() { SourceId = this.DmtpActor.Id, Sign = rpcPackage.Sign });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
rpcPackage.LoadInvokeOption(invokeOption);
|
||||
if (parameters != null)
|
||||
{
|
||||
@@ -618,18 +621,16 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
break;
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -644,7 +645,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -667,7 +667,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
finally
|
||||
{
|
||||
this.DmtpActor.WaitHandlePool.Destroy(waitData);
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,7 +680,13 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
};
|
||||
|
||||
var waitData = this.DmtpActor.WaitHandlePool.GetWaitData(rpcPackage);
|
||||
var byteBlock = new ByteBlock();
|
||||
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = DmtpInvokeOption.WaitInvoke;
|
||||
@@ -693,8 +698,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
invokeOption.Token.Register(this.CanceledInvoke, new CanceledPackage() { SourceId = this.DmtpActor.Id, Sign = rpcPackage.Sign });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
rpcPackage.LoadInvokeOption(invokeOption);
|
||||
if (parameters != null)
|
||||
{
|
||||
@@ -708,16 +711,18 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
@@ -729,7 +734,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -753,7 +757,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
finally
|
||||
{
|
||||
this.DmtpActor.WaitHandlePool.Destroy(waitData);
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -767,7 +770,13 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
};
|
||||
|
||||
var waitData = this.DmtpActor.WaitHandlePool.GetWaitDataAsync(rpcPackage);
|
||||
var byteBlock = new ByteBlock();
|
||||
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = DmtpInvokeOption.WaitInvoke;
|
||||
@@ -779,8 +788,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
invokeOption.Token.Register(this.CanceledInvoke, new CanceledPackage() { SourceId = this.DmtpActor.Id, Sign = rpcPackage.Sign });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
rpcPackage.LoadInvokeOption(invokeOption);
|
||||
if (parameters != null)
|
||||
{
|
||||
@@ -793,18 +800,16 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
break;
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -819,7 +824,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -842,7 +846,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
finally
|
||||
{
|
||||
this.DmtpActor.WaitHandlePool.Destroy(waitData);
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -856,7 +859,11 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
};
|
||||
|
||||
var waitData = this.DmtpActor.WaitHandlePool.GetWaitDataAsync(rpcPackage);
|
||||
var byteBlock = new ByteBlock();
|
||||
|
||||
try
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = DmtpInvokeOption.WaitInvoke;
|
||||
@@ -867,9 +874,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
waitData.SetCancellationToken(invokeOption.Token);
|
||||
invokeOption.Token.Register(this.CanceledInvoke, new CanceledPackage() { SourceId = this.DmtpActor.Id, Sign = rpcPackage.Sign });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
rpcPackage.LoadInvokeOption(invokeOption);
|
||||
if (parameters != null)
|
||||
{
|
||||
@@ -883,16 +887,18 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
@@ -904,7 +910,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -928,7 +933,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
finally
|
||||
{
|
||||
this.DmtpActor.WaitHandlePool.Destroy(waitData);
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -964,7 +968,12 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
};
|
||||
|
||||
var waitData = this.DmtpActor.WaitHandlePool.GetReverseWaitData(rpcPackage);
|
||||
var byteBlock = new ByteBlock();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = DmtpInvokeOption.WaitInvoke;
|
||||
@@ -976,8 +985,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
invokeOption.Token.Register(this.CanceledInvoke, new CanceledPackage() { SourceId = this.DmtpActor.Id, TargetId = targetId, Sign = rpcPackage.Sign, Route = true });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
rpcPackage.LoadInvokeOption(invokeOption);
|
||||
if (parameters != null)
|
||||
{
|
||||
@@ -991,17 +998,17 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
break;
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -1016,7 +1023,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -1039,7 +1045,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
finally
|
||||
{
|
||||
this.DmtpActor.WaitHandlePool.Destroy(waitData);
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1070,7 +1075,13 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
};
|
||||
|
||||
var waitData = this.DmtpActor.WaitHandlePool.GetReverseWaitData(rpcPackage);
|
||||
var byteBlock = new ByteBlock();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = DmtpInvokeOption.WaitInvoke;
|
||||
@@ -1082,8 +1093,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
invokeOption.Token.Register(this.CanceledInvoke, new CanceledPackage() { SourceId = this.DmtpActor.Id, TargetId = targetId, Sign = rpcPackage.Sign, Route = true });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
rpcPackage.LoadInvokeOption(invokeOption);
|
||||
if (parameters != null)
|
||||
{
|
||||
@@ -1096,17 +1105,18 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
@@ -1118,7 +1128,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -1142,7 +1151,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
finally
|
||||
{
|
||||
this.DmtpActor.WaitHandlePool.Destroy(waitData);
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1174,7 +1182,12 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
};
|
||||
|
||||
var waitData = this.DmtpActor.WaitHandlePool.GetReverseWaitData(rpcPackage);
|
||||
var byteBlock = new ByteBlock();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = DmtpInvokeOption.WaitInvoke;
|
||||
@@ -1186,8 +1199,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
invokeOption.Token.Register(this.CanceledInvoke, new CanceledPackage() { SourceId = this.DmtpActor.Id, TargetId = targetId, Sign = rpcPackage.Sign, Route = true });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
rpcPackage.LoadInvokeOption(invokeOption);
|
||||
var datas = new List<byte[]>();
|
||||
foreach (var parameter in parameters)
|
||||
@@ -1197,16 +1208,18 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
rpcPackage.ParametersBytes = datas;
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
return;
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
@@ -1218,7 +1231,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -1253,7 +1265,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
finally
|
||||
{
|
||||
this.DmtpActor.WaitHandlePool.Destroy(waitData);
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1284,7 +1295,12 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
};
|
||||
|
||||
var waitData = this.DmtpActor.WaitHandlePool.GetReverseWaitData(rpcPackage);
|
||||
var byteBlock = new ByteBlock();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = DmtpInvokeOption.WaitInvoke;
|
||||
@@ -1295,9 +1311,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
waitData.SetCancellationToken(invokeOption.Token);
|
||||
invokeOption.Token.Register(this.CanceledInvoke, new CanceledPackage() { SourceId = this.DmtpActor.Id, TargetId = targetId, Sign = rpcPackage.Sign, Route = true });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
rpcPackage.LoadInvokeOption(invokeOption);
|
||||
var datas = new List<byte[]>();
|
||||
foreach (var parameter in parameters)
|
||||
@@ -1306,17 +1319,18 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
rpcPackage.ParametersBytes = datas;
|
||||
rpcPackage.Package(byteBlock);
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
@@ -1328,7 +1342,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -1363,7 +1376,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
finally
|
||||
{
|
||||
this.DmtpActor.WaitHandlePool.Destroy(waitData);
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1395,7 +1407,12 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
};
|
||||
|
||||
var waitData = this.DmtpActor.WaitHandlePool.GetReverseWaitDataAsync(rpcPackage);
|
||||
var byteBlock = new ByteBlock();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = DmtpInvokeOption.WaitInvoke;
|
||||
@@ -1407,8 +1424,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
invokeOption.Token.Register(this.CanceledInvoke, new CanceledPackage() { SourceId = this.DmtpActor.Id, TargetId = targetId, Sign = rpcPackage.Sign, Route = true });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
rpcPackage.LoadInvokeOption(invokeOption);
|
||||
if (parameters != null)
|
||||
{
|
||||
@@ -1422,17 +1437,17 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
break;
|
||||
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -1447,7 +1462,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -1470,7 +1484,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
finally
|
||||
{
|
||||
this.DmtpActor.WaitHandlePool.Destroy(waitData);
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1501,7 +1514,11 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
};
|
||||
|
||||
var waitData = this.DmtpActor.WaitHandlePool.GetReverseWaitDataAsync(rpcPackage);
|
||||
var byteBlock = new ByteBlock();
|
||||
|
||||
try
|
||||
{
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = DmtpInvokeOption.WaitInvoke;
|
||||
@@ -1512,9 +1529,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
waitData.SetCancellationToken(invokeOption.Token);
|
||||
invokeOption.Token.Register(this.CanceledInvoke, new CanceledPackage() { SourceId = this.DmtpActor.Id, TargetId = targetId, Sign = rpcPackage.Sign, Route = true });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
rpcPackage.LoadInvokeOption(invokeOption);
|
||||
if (parameters != null)
|
||||
{
|
||||
@@ -1528,16 +1542,19 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
|
||||
rpcPackage.Package(byteBlock);
|
||||
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
return returnType.GetDefault();
|
||||
}
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.Overtime:
|
||||
@@ -1549,7 +1566,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
{
|
||||
this.DmtpActor.Send(this.m_invoke_Request, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
@@ -1573,7 +1589,6 @@ namespace TouchSocket.Dmtp.Rpc
|
||||
finally
|
||||
{
|
||||
this.DmtpActor.WaitHandlePool.Destroy(waitData);
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
src/TouchSocket.Dmtp/Sign.snk
Normal file
BIN
src/TouchSocket.Dmtp/Sign.snk
Normal file
Binary file not shown.
@@ -14,6 +14,7 @@ using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
@@ -149,6 +150,27 @@ namespace TouchSocket.Http
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建数据并回应。
|
||||
/// <para>该方法仅在具有Client实例时有效。</para>
|
||||
/// </summary>
|
||||
public async Task AnswerAsync()
|
||||
{
|
||||
if (this.Responsed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
this.Build(byteBlock);
|
||||
if (this.m_client.CanSend)
|
||||
{
|
||||
await this.m_client.DefaultSendAsync(byteBlock);
|
||||
}
|
||||
this.Responsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建响应数据。
|
||||
/// <para>当数据较大时,不建议这样操作,可直接<see cref="WriteContent(byte[], int, int)"/></para>
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace TouchSocket.Http
|
||||
/// <returns></returns>
|
||||
public static string GetContentTypeFromExtension(string extension)
|
||||
{
|
||||
if (m_provider.TryGetContentType(extension, out string result))
|
||||
if (m_provider.TryGetContentType(extension, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
BIN
src/TouchSocket.Http/Sign.snk
Normal file
BIN
src/TouchSocket.Http/Sign.snk
Normal file
Binary file not shown.
155
src/TouchSocket.Http/WebSockets/Common/InternalWebSocket.cs
Normal file
155
src/TouchSocket.Http/WebSockets/Common/InternalWebSocket.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
internal class InternalWebSocket : DisposableObject, IWebSocket
|
||||
{
|
||||
private readonly IHttpClientBase m_client;
|
||||
private bool m_receive;
|
||||
private readonly AsyncAutoResetEvent m_resetEventForComplateRead = new AsyncAutoResetEvent(false);
|
||||
private readonly AsyncAutoResetEvent m_resetEventForRead = new AsyncAutoResetEvent(false);
|
||||
private WSDataFrame m_dataFrame;
|
||||
|
||||
public InternalWebSocket(IHttpClientBase client, bool receive)
|
||||
{
|
||||
this.m_client = client;
|
||||
this.m_receive = receive;
|
||||
}
|
||||
|
||||
public bool IsHandshaked => this.m_client.GetHandshaked();
|
||||
|
||||
public string Version => this.m_client.GetWebSocketVersion();
|
||||
|
||||
public void Close(string msg)
|
||||
{
|
||||
this.m_client.CloseWithWS(msg);
|
||||
this.m_client.TryShutdown();
|
||||
this.m_client.SafeClose(msg);
|
||||
this.m_receive = false;
|
||||
}
|
||||
|
||||
public async Task CloseAsync(string msg)
|
||||
{
|
||||
await this.m_client.CloseWithWSAsync(msg);
|
||||
this.m_client.TryShutdown();
|
||||
this.m_client.SafeClose(msg);
|
||||
this.m_receive = false;
|
||||
}
|
||||
|
||||
public void Ping()
|
||||
{
|
||||
this.m_client.PingWS();
|
||||
}
|
||||
|
||||
public Task PingAsync()
|
||||
{
|
||||
return this.m_client.PingWSAsync();
|
||||
}
|
||||
|
||||
public void Pong()
|
||||
{
|
||||
this.m_client.PongWS();
|
||||
}
|
||||
|
||||
public Task PongAsync()
|
||||
{
|
||||
return this.m_client.PongWSAsync();
|
||||
}
|
||||
|
||||
public async Task<WebSocketReceiveResult> ReadAsync(CancellationToken token)
|
||||
{
|
||||
if (!this.m_receive)
|
||||
{
|
||||
return new WebSocketReceiveResult(this.ComplateRead, null);
|
||||
}
|
||||
await this.m_resetEventForRead.WaitOneAsync(token);
|
||||
return new WebSocketReceiveResult(this.ComplateRead, this.m_dataFrame);
|
||||
}
|
||||
|
||||
#region 发送
|
||||
public void Send(WSDataFrame dataFrame, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.SendWithWS(dataFrame, endOfMessage);
|
||||
}
|
||||
|
||||
public void Send(string text, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.SendWithWS(text, endOfMessage);
|
||||
}
|
||||
|
||||
public Task SendAsync(string text, bool endOfMessage = true)
|
||||
{
|
||||
return this.m_client.SendWithWSAsync(text, endOfMessage);
|
||||
}
|
||||
|
||||
public void Send(byte[] buffer, int offset, int length, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.SendWithWS(buffer, offset, length, endOfMessage);
|
||||
}
|
||||
|
||||
public void Send(ByteBlock byteBlock, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.SendWithWS(byteBlock, endOfMessage);
|
||||
}
|
||||
|
||||
public Task SendAsync(byte[] buffer, bool endOfMessage = true)
|
||||
{
|
||||
return this.m_client.SendWithWSAsync(buffer, endOfMessage);
|
||||
}
|
||||
|
||||
public void Send(byte[] buffer, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.SendWithWS(buffer, endOfMessage);
|
||||
}
|
||||
|
||||
public Task SendAsync(byte[] buffer, int offset, int length, bool endOfMessage = true)
|
||||
{
|
||||
return this.m_client.SendWithWSAsync(buffer, offset, length, endOfMessage);
|
||||
}
|
||||
|
||||
public Task SendAsync(WSDataFrame dataFrame, bool endOfMessage = true)
|
||||
{
|
||||
return this.m_client.SendWithWSAsync(dataFrame, endOfMessage);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public async Task<bool> TryInputReceiveAsync(WSDataFrame dataFrame)
|
||||
{
|
||||
if (!this.m_receive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
this.m_dataFrame = dataFrame;
|
||||
this.m_resetEventForRead.Set();
|
||||
if (dataFrame == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (await this.m_resetEventForComplateRead.WaitOneAsync(TimeSpan.FromSeconds(10)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
this.m_client.RemoveValue(WebSocketClientExtensions.WebSocketProperty);
|
||||
this.m_resetEventForComplateRead.SafeDispose();
|
||||
this.m_resetEventForRead.SafeDispose();
|
||||
this.m_dataFrame = null;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void ComplateRead()
|
||||
{
|
||||
this.m_resetEventForComplateRead.Set();
|
||||
this.m_dataFrame = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,31 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
public bool FIN { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否是二进制数据类型
|
||||
/// </summary>
|
||||
public bool IsBinary => this.Opcode == WSDataType.Binary;
|
||||
|
||||
/// <summary>
|
||||
/// 是否是关闭请求
|
||||
/// </summary>
|
||||
public bool IsClose => this.Opcode == WSDataType.Close;
|
||||
|
||||
/// <summary>
|
||||
/// 是否是Ping
|
||||
/// </summary>
|
||||
public bool IsPing => this.Opcode == WSDataType.Ping;
|
||||
|
||||
/// <summary>
|
||||
/// 是否是Pong
|
||||
/// </summary>
|
||||
public bool IsPong => this.Opcode == WSDataType.Pong;
|
||||
|
||||
/// <summary>
|
||||
/// 是否是文本类型
|
||||
/// </summary>
|
||||
public bool IsText => this.Opcode == WSDataType.Text;
|
||||
|
||||
/// <summary>
|
||||
/// 计算掩码
|
||||
/// </summary>
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
//using System.Threading.Tasks;
|
||||
//using TouchSocket.Core;
|
||||
|
||||
//namespace TouchSocket.Http.WebSockets
|
||||
//{
|
||||
// public class WebSocket : IWebSocket
|
||||
// {
|
||||
// private readonly IHttpClientBase m_client;
|
||||
// private readonly bool m_isServer;
|
||||
|
||||
// public WebSocket(IHttpClientBase client, bool isServer)
|
||||
// {
|
||||
// this.m_client = client;
|
||||
// this.m_isServer = isServer;
|
||||
// }
|
||||
|
||||
// public bool IsHandshaked => this.m_client.GetHandshaked();
|
||||
|
||||
// public void Close(string msg)
|
||||
// {
|
||||
// using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Close }.AppendText(msg))
|
||||
// {
|
||||
// this.Send(frame);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public void Ping()
|
||||
// {
|
||||
// using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Ping })
|
||||
// {
|
||||
// this.Send(frame);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public void Pong()
|
||||
// {
|
||||
// using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Pong })
|
||||
// {
|
||||
// this.Send(frame);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public void Send(WSDataFrame dataFrame)
|
||||
// {
|
||||
// using (var byteBlock = new ByteBlock(dataFrame.PayloadLength + 1024))
|
||||
// {
|
||||
// if (this.m_isServer)
|
||||
// {
|
||||
// dataFrame.BuildResponse(byteBlock);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// dataFrame.BuildRequest(byteBlock);
|
||||
// }
|
||||
|
||||
// this.m_client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len);
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 采用WebSocket协议,发送WS数据。
|
||||
// /// </summary>
|
||||
// /// <param name="dataFrame"></param>
|
||||
// public Task SendAsync(WSDataFrame dataFrame)
|
||||
// {
|
||||
// using (var byteBlock = new ByteBlock(dataFrame.PayloadLength + 1024))
|
||||
// {
|
||||
// if (this.m_isServer)
|
||||
// {
|
||||
// dataFrame.BuildResponse(byteBlock);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// dataFrame.BuildRequest(byteBlock);
|
||||
// }
|
||||
|
||||
// return this.m_client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
/// <summary>
|
||||
/// WebSocketReceiveResult
|
||||
/// </summary>
|
||||
public struct WebSocketReceiveResult : IDisposable
|
||||
{
|
||||
private Action m_disAction;
|
||||
|
||||
/// <summary>
|
||||
/// WebSocketReceiveResult
|
||||
/// </summary>
|
||||
/// <param name="disAction"></param>
|
||||
/// <param name="dataFrame"></param>
|
||||
public WebSocketReceiveResult(Action disAction, WSDataFrame dataFrame)
|
||||
{
|
||||
this.m_disAction = disAction;
|
||||
this.DataFrame = dataFrame;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
m_disAction?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket数据帧
|
||||
/// </summary>
|
||||
public WSDataFrame DataFrame { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -150,7 +150,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_semaphoreSlim.Release();
|
||||
this.m_semaphoreSlim.Release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,10 +182,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
this.Handshaked?.Invoke(this, e);
|
||||
|
||||
if (this.PluginsManager.Raise(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), this, e))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_ = this.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -238,6 +235,10 @@ namespace TouchSocket.Http.WebSockets
|
||||
protected override void OnDisconnected(DisconnectEventArgs e)
|
||||
{
|
||||
this.SetValue(WebSocketFeature.HandshakedProperty, false);
|
||||
if (this.TryGetValue(WebSocketClientExtensions.WebSocketProperty, out var internalWebSocket))
|
||||
{
|
||||
_=internalWebSocket.TryInputReceiveAsync(null);
|
||||
}
|
||||
base.OnDisconnected(e);
|
||||
}
|
||||
|
||||
@@ -247,6 +248,14 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="dataFrame"></param>
|
||||
protected virtual void OnHandleWSDataFrame(WSDataFrame dataFrame)
|
||||
{
|
||||
if (this.TryGetValue(WebSocketClientExtensions.WebSocketProperty, out var internalWebSocket))
|
||||
{
|
||||
if (internalWebSocket.TryInputReceiveAsync(dataFrame).ConfigureAwait(false).GetAwaiter().GetResult())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.PluginsManager.Enable)
|
||||
{
|
||||
this.PluginsManager.Raise(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this, new WSDataFrameEventArgs(dataFrame));
|
||||
|
||||
@@ -21,6 +21,53 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
public static class WebSocketClientExtensions
|
||||
{
|
||||
#region DependencyProperty
|
||||
|
||||
private static readonly DependencyProperty<bool> IsContProperty =
|
||||
DependencyProperty<bool>.Register("IsCont", false);
|
||||
|
||||
private static void SetIsCont(this IHttpClientBase client, bool value)
|
||||
{
|
||||
client.SetValue(IsContProperty, value);
|
||||
}
|
||||
|
||||
private static bool GetIsCont(this IHttpClientBase client)
|
||||
{
|
||||
return client.GetValue(IsContProperty);
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty<InternalWebSocket> WebSocketProperty =
|
||||
DependencyProperty<InternalWebSocket>.Register("WebSocket", null);
|
||||
|
||||
/// <summary>
|
||||
/// 获取显式WebSocket终端。
|
||||
/// <para>
|
||||
///
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="allowReceive"></param>
|
||||
/// <returns></returns>
|
||||
public static IWebSocket GetWebSocket(this IHttpClientBase client,bool allowReceive=true)
|
||||
{
|
||||
var websocket = client.GetValue(WebSocketProperty);
|
||||
if (websocket == null)
|
||||
{
|
||||
websocket = new InternalWebSocket(client, allowReceive);
|
||||
client.SetValue(WebSocketProperty, websocket);
|
||||
}
|
||||
return websocket;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除显式WebSocket终端。
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
public static void ClearWebSocket(this IHttpClientBase client)
|
||||
{
|
||||
client.RemoveValue(WebSocketProperty);
|
||||
}
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// 发送Close报文。
|
||||
/// </summary>
|
||||
@@ -119,28 +166,6 @@ namespace TouchSocket.Http.WebSockets
|
||||
|
||||
#region 同步发送
|
||||
|
||||
/// <summary>
|
||||
/// 采用WebSocket协议,发送二进制流数据。
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
public static void SendWithWS(this IHttpClientBase client, byte[] buffer, int offset, int length)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Binary })
|
||||
{
|
||||
if (offset == 0)
|
||||
{
|
||||
frame.PayloadData = new ByteBlock(buffer, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.AppendBinary(buffer, offset, length);
|
||||
}
|
||||
SendWithWS(client, frame);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 采用WebSocket协议,发送二进制流数据。
|
||||
@@ -150,9 +175,9 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
public static void SendWithWS(this IHttpClientBase client, bool endOfMessage, byte[] buffer, int offset, int length)
|
||||
public static void SendWithWS(this IHttpClientBase client, byte[] buffer, int offset, int length, bool endOfMessage = true)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = endOfMessage ? WSDataType.Binary : WSDataType.Cont })
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = WSDataType.Binary })
|
||||
{
|
||||
if (offset == 0)
|
||||
{
|
||||
@@ -162,7 +187,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
frame.AppendBinary(buffer, offset, length);
|
||||
}
|
||||
SendWithWS(client, frame);
|
||||
SendWithWS(client, frame,endOfMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,9 +196,14 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="byteBlock"></param>
|
||||
public static void SendWithWS(this IHttpClientBase client, ByteBlock byteBlock)
|
||||
/// <param name="endOfMessage"></param>
|
||||
public static void SendWithWS(this IHttpClientBase client, ByteBlock byteBlock, bool endOfMessage = true)
|
||||
{
|
||||
SendWithWS(client, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = WSDataType.Binary })
|
||||
{
|
||||
frame.PayloadData = byteBlock;
|
||||
SendWithWS(client, frame,endOfMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -181,9 +211,10 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer"></param>
|
||||
public static void SendWithWS(this IHttpClientBase client, byte[] buffer)
|
||||
/// <param name="endOfMessage"></param>
|
||||
public static void SendWithWS(this IHttpClientBase client, byte[] buffer, bool endOfMessage = true)
|
||||
{
|
||||
SendWithWS(client, buffer, 0, buffer.Length);
|
||||
SendWithWS(client, buffer, 0, buffer.Length, endOfMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -191,11 +222,12 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="text"></param>
|
||||
public static void SendWithWS(this IHttpClientBase client, string text)
|
||||
/// <param name="endOfMessage"></param>
|
||||
public static void SendWithWS(this IHttpClientBase client, string text, bool endOfMessage = true)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Text }.AppendText(text))
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = WSDataType.Text }.AppendText(text))
|
||||
{
|
||||
SendWithWS(client, frame);
|
||||
SendWithWS(client, frame,endOfMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,8 +236,29 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="dataFrame"></param>
|
||||
public static void SendWithWS(this IHttpClientBase client, WSDataFrame dataFrame)
|
||||
/// <param name="endOfMessage"></param>
|
||||
public static void SendWithWS(this IHttpClientBase client, WSDataFrame dataFrame,bool endOfMessage=true)
|
||||
{
|
||||
var isCont = client.GetIsCont();
|
||||
|
||||
WSDataType dataType;
|
||||
if (isCont)
|
||||
{
|
||||
dataType = WSDataType.Cont;
|
||||
if (endOfMessage)
|
||||
{
|
||||
client.SetIsCont(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataType = dataFrame.Opcode;
|
||||
if (!endOfMessage)
|
||||
{
|
||||
client.SetIsCont(true);
|
||||
}
|
||||
}
|
||||
dataFrame.Opcode = dataType;
|
||||
using (var byteBlock = new ByteBlock(dataFrame.GetTotalSize()))
|
||||
{
|
||||
if (client.IsClient)
|
||||
@@ -232,9 +285,9 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, bool endOfMessage, byte[] buffer, int offset, int length)
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, byte[] buffer, int offset, int length, bool endOfMessage = true)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = endOfMessage ? WSDataType.Binary : WSDataType.Cont })
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = WSDataType.Binary })
|
||||
{
|
||||
if (offset == 0)
|
||||
{
|
||||
@@ -244,7 +297,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
frame.AppendBinary(buffer, offset, length);
|
||||
}
|
||||
return SendWithWSAsync(client, frame);
|
||||
return SendWithWSAsync(client, frame,endOfMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,42 +306,10 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, byte[] buffer, int offset, int length)
|
||||
/// <param name="endOfMessage"></param>
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, byte[] buffer, bool endOfMessage = true)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Binary })
|
||||
{
|
||||
if (offset == 0)
|
||||
{
|
||||
frame.PayloadData = new ByteBlock(buffer, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.AppendBinary(buffer, offset, length);
|
||||
}
|
||||
return SendWithWSAsync(client, frame);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 采用WebSocket协议,发送二进制流数据。
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="byteBlock"></param>
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, ByteBlock byteBlock)
|
||||
{
|
||||
return SendWithWSAsync(client, byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 采用WebSocket协议,发送二进制流数据。
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer"></param>
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, byte[] buffer)
|
||||
{
|
||||
return SendWithWSAsync(client, buffer, 0, buffer.Length);
|
||||
return SendWithWSAsync(client, buffer, 0, buffer.Length, endOfMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -296,11 +317,12 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="text"></param>
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, string text)
|
||||
/// <param name="endOfMessage"></param>
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, string text, bool endOfMessage = true)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Text }.AppendText(text))
|
||||
{
|
||||
return SendWithWSAsync(client, frame);
|
||||
return SendWithWSAsync(client, frame, endOfMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,8 +331,29 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="dataFrame"></param>
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, WSDataFrame dataFrame)
|
||||
/// <param name="endOfMessage"></param>
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, WSDataFrame dataFrame,bool endOfMessage=true)
|
||||
{
|
||||
var isCont = client.GetIsCont();
|
||||
|
||||
WSDataType dataType;
|
||||
if (isCont)
|
||||
{
|
||||
dataType = WSDataType.Cont;
|
||||
if (endOfMessage)
|
||||
{
|
||||
client.SetIsCont(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataType = dataFrame.Opcode;
|
||||
if (!endOfMessage)
|
||||
{
|
||||
client.SetIsCont(true);
|
||||
}
|
||||
}
|
||||
dataFrame.Opcode = dataType;
|
||||
using (var byteBlock = new ByteBlock(dataFrame.GetTotalSize()))
|
||||
{
|
||||
if (client.IsClient)
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="httpContext">Http上下文</param>
|
||||
public static bool SwitchProtocolToWebSocket<TClient>(this TClient client, HttpContext httpContext) where TClient : IHttpSocketClient
|
||||
public static async Task<bool> SwitchProtocolToWebSocket<TClient>(this TClient client, HttpContext httpContext) where TClient : IHttpSocketClient
|
||||
{
|
||||
if (client.Protocol == Protocol.WebSocket)
|
||||
{
|
||||
@@ -40,7 +40,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
IsPermitOperation = true
|
||||
};
|
||||
client.PluginsManager.Raise(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), client, args);
|
||||
await client.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), client, args);
|
||||
if (args.Context.Response.Responsed)
|
||||
{
|
||||
return false;
|
||||
@@ -54,9 +54,9 @@ namespace TouchSocket.Http.WebSockets
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
args.Context.Response.Build(byteBlock);
|
||||
client.DefaultSend(byteBlock);
|
||||
await client.DefaultSendAsync(byteBlock);
|
||||
}
|
||||
client.PluginsManager.Raise(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), client, new HttpContextEventArgs(httpContext));
|
||||
await client.PluginsManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), client, new HttpContextEventArgs(httpContext));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -65,7 +65,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
args.Context.Response.Build(byteBlock);
|
||||
client.DefaultSend(byteBlock);
|
||||
await client.DefaultSendAsync(byteBlock);
|
||||
}
|
||||
|
||||
client.Close("主动拒绝WebSocket连接");
|
||||
@@ -78,18 +78,5 @@ namespace TouchSocket.Http.WebSockets
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转化Protocol协议标识为<see cref="Protocol.WebSocket"/>
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="httpContext">Http上下文</param>
|
||||
public static Task<bool> SwitchProtocolToWebSocketAsync<TClient>(this TClient client, HttpContext httpContext) where TClient : HttpSocketClient
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
return SwitchProtocolToWebSocket(client, httpContext);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,136 @@
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Net.WebSockets;
|
||||
//using System.Text;
|
||||
//using System.Threading.Tasks;
|
||||
//using TouchSocket.Core;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
|
||||
//namespace TouchSocket.Http.WebSockets
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// IWebSocket
|
||||
// /// </summary>
|
||||
// public interface IWebSocket
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// 表示当前WebSocket是否已经完成连接。
|
||||
// /// </summary>
|
||||
// bool IsHandshaked { get; }
|
||||
namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
/// <summary>
|
||||
/// IWebSocket
|
||||
/// </summary>
|
||||
public interface IWebSocket : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示当前WebSocket是否已经完成连接。
|
||||
/// </summary>
|
||||
bool IsHandshaked { get; }
|
||||
|
||||
// /// <summary>
|
||||
// /// 发送Close报文。
|
||||
// /// </summary>
|
||||
// /// <param name="msg"></param>
|
||||
// void Close(string msg);
|
||||
/// <summary>
|
||||
/// WebSocket版本
|
||||
/// </summary>
|
||||
string Version { get; }
|
||||
|
||||
// /// <summary>
|
||||
// /// 发送Ping报文。
|
||||
// /// </summary>
|
||||
// void Ping();
|
||||
/// <summary>
|
||||
/// 发送Close报文。
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
void Close(string msg);
|
||||
|
||||
// /// <summary>
|
||||
// /// 发送Pong报文。
|
||||
// /// </summary>
|
||||
// void Pong();
|
||||
/// <summary>
|
||||
/// 发送Close报文
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
Task CloseAsync(string msg);
|
||||
|
||||
// /// <summary>
|
||||
// /// 采用WebSocket协议,发送WS数据。发送结束后,请及时释放<see cref="WSDataFrame"/>
|
||||
// /// </summary>
|
||||
// /// <param name="dataFrame"></param>
|
||||
// void Send(WSDataFrame dataFrame);
|
||||
/// <summary>
|
||||
/// 发送Ping报文。
|
||||
/// </summary>
|
||||
void Ping();
|
||||
|
||||
// /// <summary>
|
||||
// /// 采用WebSocket协议,发送WS数据。发送结束后,请及时释放<see cref="WSDataFrame"/>
|
||||
// /// </summary>
|
||||
// /// <param name="dataFrame"></param>
|
||||
// /// <returns></returns>
|
||||
// Task SendAsync(WSDataFrame dataFrame);
|
||||
// }
|
||||
//}
|
||||
/// <summary>
|
||||
/// 发送Ping报文
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task PingAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 发送Pong报文。
|
||||
/// </summary>
|
||||
void Pong();
|
||||
|
||||
/// <summary>
|
||||
/// 发送Pong报文
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task PongAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 异步等待读取数据
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<WebSocketReceiveResult> ReadAsync(CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// 采用WebSocket协议,发送WS数据。发送结束后,请及时释放<see cref="WSDataFrame"/>
|
||||
/// </summary>
|
||||
/// <param name="dataFrame"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
void Send(WSDataFrame dataFrame, bool endOfMessage = true);
|
||||
|
||||
/// <summary>
|
||||
/// 发送文本消息
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
void Send(string text, bool endOfMessage = true);
|
||||
|
||||
/// <summary>
|
||||
/// 发送二进制消息
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
void Send(byte[] buffer, int offset, int length, bool endOfMessage = true);
|
||||
|
||||
/// <summary>
|
||||
/// 发送二进制消息
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
void Send(ByteBlock byteBlock, bool endOfMessage = true);
|
||||
|
||||
/// <summary>
|
||||
/// 发送二进制消息
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
void Send(byte[] buffer, bool endOfMessage = true);
|
||||
|
||||
/// <summary>
|
||||
/// 采用WebSocket协议,发送WS数据。发送结束后,请及时释放<see cref="WSDataFrame"/>
|
||||
/// </summary>
|
||||
/// <param name="dataFrame"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
/// <returns></returns>
|
||||
Task SendAsync(WSDataFrame dataFrame, bool endOfMessage = true);
|
||||
|
||||
/// <summary>
|
||||
/// 发送文本消息
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
/// <returns></returns>
|
||||
Task SendAsync(string text, bool endOfMessage = true);
|
||||
|
||||
/// <summary>
|
||||
/// 发送二进制消息
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
/// <returns></returns>
|
||||
Task SendAsync(byte[] buffer, bool endOfMessage = true);
|
||||
|
||||
/// <summary>
|
||||
/// 发送二进制消息
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
/// <returns></returns>
|
||||
Task SendAsync(byte[] buffer, int offset, int length, bool endOfMessage = true);
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,22 @@ namespace TouchSocket.Http.WebSockets
|
||||
|
||||
try
|
||||
{
|
||||
var result = method.Invoke(this, os);
|
||||
object result;
|
||||
switch (method.TaskType)
|
||||
{
|
||||
case TaskReturnType.Task:
|
||||
await method.InvokeAsync(this, os);
|
||||
result = default;
|
||||
break;
|
||||
case TaskReturnType.TaskObject:
|
||||
result = await method.InvokeObjectAsync(this, os);
|
||||
break;
|
||||
case TaskReturnType.None:
|
||||
default:
|
||||
result = method.Invoke(this, os);
|
||||
break;
|
||||
}
|
||||
|
||||
if (method.HasReturn)
|
||||
{
|
||||
if (client is HttpClient httpClient)
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <para>此组件只能挂载在<see cref="HttpService"/>中</para>
|
||||
/// </summary>
|
||||
[PluginOption(Singleton = true, NotRegister = false)]
|
||||
public class WebSocketFeature : PluginBase, ITcpReceivedPlugin, IHttpPlugin
|
||||
public sealed class WebSocketFeature : PluginBase, ITcpReceivedPlugin, IHttpPlugin,ITcpDisconnectedPlugin
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示是否完成WS握手
|
||||
@@ -93,26 +93,42 @@ namespace TouchSocket.Http.WebSockets
|
||||
if (this.VerifyConnection.Invoke(client, e.Context))
|
||||
{
|
||||
e.Handled = true;
|
||||
client.SwitchProtocolToWebSocket(e.Context);
|
||||
_ = client.SwitchProtocolToWebSocket(e.Context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
await e.InvokeNext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
public Task OnTcpReceived(ITcpClientBase client, ReceivedDataEventArgs e)
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
/// <returns></returns>
|
||||
public async Task OnTcpDisconnected(ITcpClientBase client, DisconnectEventArgs e)
|
||||
{
|
||||
client.SetValue(HandshakedProperty, false);
|
||||
if (client.TryGetValue(WebSocketClientExtensions.WebSocketProperty, out var internalWebSocket))
|
||||
{
|
||||
_=internalWebSocket.TryInputReceiveAsync(null);
|
||||
}
|
||||
await e.InvokeNext();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task OnTcpReceived(ITcpClientBase client, ReceivedDataEventArgs e)
|
||||
{
|
||||
if (client.Protocol == Protocol.WebSocket)
|
||||
{
|
||||
if (e.RequestInfo is WSDataFrame dataFrame)
|
||||
{
|
||||
e.Handled = true;
|
||||
this.OnHandleWSDataFrame(client, new WSDataFrameEventArgs(dataFrame));
|
||||
return EasyTask.CompletedTask;
|
||||
await this.OnHandleWSDataFrame(client, dataFrame);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return e.InvokeNext();
|
||||
await e.InvokeNext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -148,27 +164,28 @@ namespace TouchSocket.Http.WebSockets
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理WS数据帧。覆盖父类方法将不会触发插件。
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="e"></param>
|
||||
protected virtual void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e)
|
||||
private async Task OnHandleWSDataFrame(ITcpClientBase client, WSDataFrame dataFrame)
|
||||
{
|
||||
if (this.AutoClose && e.DataFrame.Opcode == WSDataType.Close)
|
||||
if (this.AutoClose && dataFrame.IsClose)
|
||||
{
|
||||
var msg = e.DataFrame.PayloadData?.ToString();
|
||||
this.m_pluginsManager.Raise(nameof(IWebSocketClosingPlugin.OnWebSocketClosing), client, new MsgPermitEventArgs() { Message = msg });
|
||||
var msg = dataFrame.PayloadData?.ToString();
|
||||
await this.m_pluginsManager.RaiseAsync(nameof(IWebSocketClosingPlugin.OnWebSocketClosing), client, new MsgPermitEventArgs() { Message = msg });
|
||||
client.Close(msg);
|
||||
return;
|
||||
}
|
||||
if (this.AutoPong && e.DataFrame.Opcode == WSDataType.Ping)
|
||||
if (this.AutoPong && dataFrame.IsPing)
|
||||
{
|
||||
((HttpSocketClient)client).PongWS();
|
||||
return;
|
||||
}
|
||||
|
||||
this.m_pluginsManager.Raise(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), client, e);
|
||||
if (client.TryGetValue(WebSocketClientExtensions.WebSocketProperty, out var internalWebSocket))
|
||||
{
|
||||
if (await internalWebSocket.TryInputReceiveAsync(dataFrame))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.m_pluginsManager.RaiseAsync(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), client, new WSDataFrameEventArgs(dataFrame));
|
||||
}
|
||||
|
||||
private bool ThisVerifyConnection(IHttpSocketClient client, HttpContext context)
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace TouchSocket.JsonRpc
|
||||
/// <summary>
|
||||
/// JsonRpc上下文
|
||||
/// </summary>
|
||||
public JsonRpcContext JsonRpcContext { get; internal set; }
|
||||
public JsonRpcRequestContext JsonRpcContext { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Json字符串
|
||||
|
||||
32
src/TouchSocket.JsonRpc/Common/JsonRpcErrorResponse.cs
Normal file
32
src/TouchSocket.JsonRpc/Common/JsonRpcErrorResponse.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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首页:http://rrqm_home.gitee.io/touchsocket/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpcErrorResponse
|
||||
/// </summary>
|
||||
public class JsonRpcErrorResponse: JsonRpcResponseBase
|
||||
{
|
||||
/// <summary>
|
||||
/// error
|
||||
/// </summary>
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonPropertyName("error")]
|
||||
#endif
|
||||
[JsonProperty("error")]
|
||||
public JsonRpcError Error { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -24,24 +24,36 @@ namespace TouchSocket.JsonRpc
|
||||
/// jsonrpc
|
||||
/// </summary>
|
||||
[JsonProperty("jsonrpc")]
|
||||
public string Jsonrpc = "2.0";
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonPropertyName("jsonrpc")]
|
||||
#endif
|
||||
public string Jsonrpc { get; set; } = "2.0";
|
||||
|
||||
/// <summary>
|
||||
/// method
|
||||
/// </summary>
|
||||
[JsonProperty("method")]
|
||||
public string Method;
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonPropertyName("method")]
|
||||
#endif
|
||||
public string Method { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// @params
|
||||
/// </summary>
|
||||
[JsonProperty("params")]
|
||||
public object Params;
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonPropertyName("params")]
|
||||
#endif
|
||||
public object Params { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
[JsonProperty("id")]
|
||||
public string Id;
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonPropertyName("id")]
|
||||
#endif
|
||||
public long? Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -11,25 +11,21 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpcPackage
|
||||
/// JsonRpcRequestContext
|
||||
/// </summary>
|
||||
public class JsonRpcContext : JsonRpcRequest
|
||||
public class JsonRpcRequestContext : JsonRpcRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// parameters
|
||||
/// </summary>
|
||||
[JsonProperty("parameters")]
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
#endif
|
||||
public object[] Parameters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// needResponse
|
||||
/// </summary>
|
||||
[JsonProperty("needResponse")]
|
||||
public bool NeedResponse { get; set; }
|
||||
}
|
||||
}
|
||||
34
src/TouchSocket.JsonRpc/Common/JsonRpcResponseBase.cs
Normal file
34
src/TouchSocket.JsonRpc/Common/JsonRpcResponseBase.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpcResponseBase
|
||||
/// </summary>
|
||||
public class JsonRpcResponseBase
|
||||
{
|
||||
/// <summary>
|
||||
/// jsonrpc
|
||||
/// </summary>
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonPropertyName("jsonrpc")]
|
||||
#endif
|
||||
[JsonProperty("jsonrpc")]
|
||||
public string Jsonrpc { get; set; } = "2.0";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonPropertyName("id")]
|
||||
#endif
|
||||
[JsonProperty("id")]
|
||||
public long? Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -12,36 +12,31 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpc响应器
|
||||
/// </summary>
|
||||
public class JsonResponseContext
|
||||
public class JsonRpcResponseContext:JsonRpcResponseBase
|
||||
{
|
||||
/// <summary>
|
||||
/// jsonrpc
|
||||
/// </summary>
|
||||
[JsonProperty("jsonrpc")]
|
||||
public string Jsonrpc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// result
|
||||
/// </summary>
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonPropertyName("result")]
|
||||
#endif
|
||||
[JsonProperty("result")]
|
||||
public object Result { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// error
|
||||
/// </summary>
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonPropertyName("error")]
|
||||
#endif
|
||||
[JsonProperty("error")]
|
||||
public JsonRpcError Error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
[JsonProperty("id")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -11,47 +11,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpcSuccessResponse
|
||||
/// </summary>
|
||||
public class JsonRpcSuccessResponse
|
||||
public class JsonRpcSuccessResponse: JsonRpcResponseBase
|
||||
{
|
||||
/// <summary>
|
||||
/// jsonrpc
|
||||
/// </summary>
|
||||
public string jsonrpc = "2.0";
|
||||
|
||||
/// <summary>
|
||||
/// result
|
||||
/// </summary>
|
||||
public object result;
|
||||
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
public string id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// JsonRpcErrorResponse
|
||||
/// </summary>
|
||||
public class JsonRpcErrorResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// jsonrpc
|
||||
/// </summary>
|
||||
public string jsonrpc = "2.0";
|
||||
|
||||
/// <summary>
|
||||
/// error
|
||||
/// </summary>
|
||||
public JsonRpcError error;
|
||||
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
public string id;
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonPropertyName("result")]
|
||||
#endif
|
||||
[JsonProperty("result")]
|
||||
public object Result { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,9 @@
|
||||
using TouchSocket.Sockets;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Rpc;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
@@ -8,8 +13,236 @@ namespace TouchSocket.JsonRpc
|
||||
public static class JsonRpcUtility
|
||||
{
|
||||
/// <summary>
|
||||
/// TcpJsonRpc
|
||||
/// 是否属于JsonRpc请求
|
||||
/// </summary>
|
||||
public static Protocol TcpJsonRpc { get; private set; } = new Protocol("TcpJsonRpc");
|
||||
/// <param name="jsonString"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsJsonRpcRequest(string jsonString)
|
||||
{
|
||||
if (jsonString.Contains("error") || jsonString.Contains("result"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ToJsonRpcWaitResult
|
||||
/// </summary>
|
||||
/// <param name="jsonString"></param>
|
||||
/// <returns></returns>
|
||||
public static JsonRpcWaitResult ToJsonRpcWaitResult(string jsonString)
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
return jsonString.FromJsonString<JsonRpcWaitResult>();
|
||||
return (JsonRpcWaitResult)System.Text.Json.JsonSerializer.Deserialize(jsonString, typeof(JsonRpcWaitResult), TouchSokcetJsonRpcSourceGenerationContext.Default);
|
||||
#else
|
||||
return jsonString.FromJsonString<JsonRpcWaitResult>();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ToJsonRpcRequestContext
|
||||
/// </summary>
|
||||
/// <param name="jsonString"></param>
|
||||
/// <returns></returns>
|
||||
public static JsonRpcRequestContext ToJsonRpcRequestContext(string jsonString)
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
return jsonString.FromJsonString<JsonRpcRequestContext>();
|
||||
//return (JsonRpcRequestContext)System.Text.Json.JsonSerializer.Deserialize(jsonString, typeof(JsonRpcRequestContext), TouchSokcetJsonRpcSourceGenerationContext.Default);
|
||||
#else
|
||||
return jsonString.FromJsonString<JsonRpcRequestContext>();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ToJsonRpcResponseString
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToJsonRpcResponseString(JsonRpcResponseBase response)
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
return JsonConvert.SerializeObject(response);
|
||||
return System.Text.Json.JsonSerializer.Serialize(response);
|
||||
#else
|
||||
return JsonConvert.SerializeObject(response);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ResultParseToType
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
/// <param name="returnType"></param>
|
||||
/// <returns></returns>
|
||||
public static object ResultParseToType(object result,Type returnType)
|
||||
{
|
||||
if (returnType.IsPrimitive || returnType == typeof(string))
|
||||
{
|
||||
return result.ToString().ParseToType(returnType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return result.ToJsonString().FromJsonString(returnType);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BuildRequestContext
|
||||
/// </summary>
|
||||
/// <param name="actionMap"></param>
|
||||
/// <param name="callContext"></param>
|
||||
/// <exception cref="RpcException"></exception>
|
||||
public static void BuildRequestContext(ActionMap actionMap, ref JsonRpcCallContextBase callContext)
|
||||
{
|
||||
var requestContext = JsonRpcUtility.ToJsonRpcRequestContext(callContext.JsonString);
|
||||
|
||||
callContext.JsonRpcContext = requestContext;
|
||||
|
||||
if (actionMap.TryGetMethodInstance(requestContext.Method, out var methodInstance))
|
||||
{
|
||||
callContext.MethodInstance = methodInstance;
|
||||
if (requestContext.Params == null)
|
||||
{
|
||||
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
|
||||
{
|
||||
requestContext.Parameters = methodInstance.ParameterNames.Length > 1 ? throw new RpcException("调用参数计数不匹配") : (new object[] { callContext });
|
||||
}
|
||||
else
|
||||
{
|
||||
if (methodInstance.ParameterNames.Length != 0)
|
||||
{
|
||||
throw new RpcException("调用参数计数不匹配");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (requestContext.Params is JObject obj)
|
||||
{
|
||||
requestContext.Parameters = new object[methodInstance.ParameterNames.Length];
|
||||
//内联
|
||||
var i = 0;
|
||||
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
|
||||
{
|
||||
requestContext.Parameters[0] = callContext;
|
||||
i = 1;
|
||||
}
|
||||
for (; i < methodInstance.ParameterNames.Length; i++)
|
||||
{
|
||||
if (obj.TryGetValue(methodInstance.ParameterNames[i], out var jToken))
|
||||
{
|
||||
var type = methodInstance.ParameterTypes[i];
|
||||
requestContext.Parameters[i] = jToken.ToJsonString().FromJsonString(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (methodInstance.Parameters[i].HasDefaultValue)
|
||||
{
|
||||
requestContext.Parameters[i] = methodInstance.Parameters[i].DefaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RpcException("调用参数计数不匹配");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (requestContext.Params is JArray array)
|
||||
{
|
||||
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
|
||||
{
|
||||
if (array.Count != methodInstance.ParameterNames.Length - 1)
|
||||
{
|
||||
throw new RpcException("调用参数计数不匹配");
|
||||
}
|
||||
requestContext.Parameters = new object[methodInstance.ParameterNames.Length];
|
||||
|
||||
requestContext.Parameters[0] = callContext;
|
||||
for (var i = 0; i < array.Count; i++)
|
||||
{
|
||||
requestContext.Parameters[i + 1] = array[i].ToJsonString().FromJsonString(methodInstance.ParameterTypes[i + 1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (array.Count != methodInstance.ParameterNames.Length)
|
||||
{
|
||||
throw new RpcException("调用参数计数不匹配");
|
||||
}
|
||||
requestContext.Parameters = new object[methodInstance.ParameterNames.Length];
|
||||
|
||||
for (var i = 0; i < array.Count; i++)
|
||||
{
|
||||
requestContext.Parameters[i] = array[i].ToJsonString().FromJsonString(methodInstance.ParameterTypes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RpcException("未知参数类型");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetJsonRpcError
|
||||
/// </summary>
|
||||
/// <param name="invokeResult"></param>
|
||||
/// <returns></returns>
|
||||
public static JsonRpcError GetJsonRpcError(InvokeResult invokeResult)
|
||||
{
|
||||
JsonRpcError error = null;
|
||||
switch (invokeResult.Status)
|
||||
{
|
||||
case InvokeStatus.Success:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.UnFound:
|
||||
{
|
||||
error = new JsonRpcError
|
||||
{
|
||||
Code = -32601,
|
||||
Message = "函数未找到"
|
||||
};
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.UnEnable:
|
||||
{
|
||||
error = new JsonRpcError
|
||||
{
|
||||
Code = -32601,
|
||||
Message = "函数已被禁用"
|
||||
};
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.InvocationException:
|
||||
{
|
||||
error = new JsonRpcError
|
||||
{
|
||||
Code = -32603,
|
||||
Message = "函数内部异常"
|
||||
};
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.Exception:
|
||||
{
|
||||
error = new JsonRpcError
|
||||
{
|
||||
Code = -32602,
|
||||
Message = invokeResult.Message
|
||||
};
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,54 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using Newtonsoft.Json;
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
internal class JsonRpcWaitResult : WaitResult
|
||||
/// <summary>
|
||||
/// JsonRpcWaitResult
|
||||
/// </summary>
|
||||
public class JsonRpcWaitResult : JsonRpcResponseBase,IWaitResult
|
||||
{
|
||||
public object Return;
|
||||
/// <summary>
|
||||
/// Result
|
||||
/// </summary>
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonPropertyName("result")]
|
||||
#endif
|
||||
[JsonProperty("result")]
|
||||
public object Result { get; set; }
|
||||
|
||||
public JsonRpcError Error;
|
||||
/// <summary>
|
||||
/// Error
|
||||
/// </summary>
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonPropertyName("error")]
|
||||
#endif
|
||||
[JsonProperty("error")]
|
||||
public JsonRpcError Error { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
#endif
|
||||
[JsonIgnore]
|
||||
public string Message { get ; set ; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
#endif
|
||||
[JsonIgnore]
|
||||
public long Sign { get=> (long)this.Id ; set=>this.Id=value ; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
#if NET6_0_OR_GREATER
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
#endif
|
||||
[JsonIgnore]
|
||||
public byte Status { get ; set ; }
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign.ToString() : null
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
var request = new HttpRequest();
|
||||
request.Method = HttpMethod.Post;
|
||||
@@ -69,7 +69,7 @@ namespace TouchSocket.JsonRpc
|
||||
throw new RpcException(resultContext.Error.Message);
|
||||
}
|
||||
|
||||
if (resultContext.Return == null)
|
||||
if (resultContext.Result == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@@ -77,11 +77,11 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
if (returnType.IsPrimitive || returnType == typeof(string))
|
||||
{
|
||||
return resultContext.Return.ToString().ParseToType(returnType);
|
||||
return resultContext.Result.ToString().ParseToType(returnType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return resultContext.Return.ToJsonString().FromJsonString(returnType);
|
||||
return resultContext.Result.ToJsonString().FromJsonString(returnType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,7 @@ namespace TouchSocket.JsonRpc
|
||||
Params = parameters
|
||||
};
|
||||
|
||||
jsonRpcRequest.Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign.ToString() : null;
|
||||
jsonRpcRequest.Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0;
|
||||
var request = new HttpRequest();
|
||||
request.Method = HttpMethod.Post;
|
||||
request.SetUrl(this.RemoteIPHost.PathAndQuery);
|
||||
@@ -182,7 +182,7 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign.ToString() : null
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
var request = new HttpRequest
|
||||
{
|
||||
@@ -245,7 +245,7 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign.ToString() : null
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
var request = new HttpRequest();
|
||||
request.Method = HttpMethod.Post;
|
||||
@@ -282,7 +282,7 @@ namespace TouchSocket.JsonRpc
|
||||
throw new RpcException(resultContext.Error.Message);
|
||||
}
|
||||
|
||||
if (resultContext.Return == null)
|
||||
if (resultContext.Result == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@@ -290,11 +290,11 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
if (returnType.IsPrimitive || returnType == typeof(string))
|
||||
{
|
||||
return resultContext.Return.ToString().ParseToType(returnType);
|
||||
return resultContext.Result.ToString().ParseToType(returnType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return resultContext.Return.ToJsonString().FromJsonString(returnType);
|
||||
return resultContext.Result.ToJsonString().FromJsonString(returnType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -317,20 +317,11 @@ namespace TouchSocket.JsonRpc
|
||||
|
||||
try
|
||||
{
|
||||
if (jsonString.Contains("error") || jsonString.Contains("result"))
|
||||
var waitResult = JsonRpcUtility.ToJsonRpcWaitResult(jsonString);
|
||||
if (waitResult != null)
|
||||
{
|
||||
var responseContext = jsonString.FromJsonString<JsonResponseContext>();
|
||||
if (responseContext != null && !responseContext.Id.IsNullOrEmpty())
|
||||
{
|
||||
var waitContext = new JsonRpcWaitResult
|
||||
{
|
||||
Status = 1,
|
||||
Sign = long.Parse(responseContext.Id),
|
||||
Error = responseContext.Error,
|
||||
Return = responseContext.Result
|
||||
};
|
||||
this.m_waitHandle.SetRun(waitContext);
|
||||
}
|
||||
waitResult.Status = 1;
|
||||
this.m_waitHandle.SetRun(waitResult);
|
||||
}
|
||||
}
|
||||
catch
|
||||
|
||||
333
src/TouchSocket.JsonRpc/Components/JsonRpcActionClientBase.cs
Normal file
333
src/TouchSocket.JsonRpc/Components/JsonRpcActionClientBase.cs
Normal file
@@ -0,0 +1,333 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Resources;
|
||||
using TouchSocket.Rpc;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpcActionClientBase
|
||||
/// </summary>
|
||||
public abstract class JsonRpcActionClientBase : IJsonRpcActionClient
|
||||
{
|
||||
private readonly WaitHandlePool<JsonRpcWaitResult> m_waitHandle = new WaitHandlePool<JsonRpcWaitResult>();
|
||||
|
||||
/// <summary>
|
||||
/// WaitHandle
|
||||
/// </summary>
|
||||
public WaitHandlePool<JsonRpcWaitResult> WaitHandle => this.m_waitHandle;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Invoke(Type returnType, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types)
|
||||
{
|
||||
var context = new JsonRpcWaitResult();
|
||||
var waitData = this.m_waitHandle.GetWaitData(context);
|
||||
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = InvokeOption.WaitInvoke;
|
||||
}
|
||||
|
||||
parameters ??= new object[0];
|
||||
var jsonRpcRequest = new JsonRpcRequest
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
try
|
||||
{
|
||||
this.SendJsonString(jsonRpcRequest.ToJsonString());
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
return default;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
default:
|
||||
{
|
||||
if (invokeOption.Token.CanBeCanceled)
|
||||
{
|
||||
waitData.SetCancellationToken(invokeOption.Token);
|
||||
}
|
||||
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (JsonRpcWaitResult)waitData.WaitResult;
|
||||
if (resultContext.Error != null)
|
||||
{
|
||||
throw new RpcException(resultContext.Error.Message);
|
||||
}
|
||||
|
||||
if (resultContext.Result == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
return JsonRpcUtility.ResultParseToType(resultContext.Result, returnType);
|
||||
}
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException("等待结果超时");
|
||||
case WaitDataStatus.Canceled:
|
||||
return default;
|
||||
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketCoreResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Invoke(string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types)
|
||||
{
|
||||
var context = new JsonRpcWaitResult();
|
||||
var waitData = this.m_waitHandle.GetWaitData(context);
|
||||
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = InvokeOption.WaitInvoke;
|
||||
}
|
||||
|
||||
parameters ??= new object[0];
|
||||
var jsonRpcRequest = new JsonRpcRequest
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
try
|
||||
{
|
||||
this.SendJsonString(jsonRpcRequest.ToJsonString());
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
return;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
default:
|
||||
{
|
||||
if (invokeOption.Token.CanBeCanceled)
|
||||
{
|
||||
waitData.SetCancellationToken(invokeOption.Token);
|
||||
}
|
||||
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (JsonRpcWaitResult)waitData.WaitResult;
|
||||
if (resultContext.Error != null)
|
||||
{
|
||||
throw new RpcException(resultContext.Error.Message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException("等待结果超时");
|
||||
case WaitDataStatus.Canceled:
|
||||
return;
|
||||
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketCoreResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Invoke(string method, IInvokeOption invokeOption, params object[] parameters)
|
||||
{
|
||||
this.Invoke(method, invokeOption, ref parameters, null);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Invoke(Type returnType, string method, IInvokeOption invokeOption, params object[] parameters)
|
||||
{
|
||||
return this.Invoke(returnType, method, invokeOption, ref parameters, null);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task InvokeAsync(string method, IInvokeOption invokeOption, params object[] parameters)
|
||||
{
|
||||
var context = new JsonRpcWaitResult();
|
||||
var waitData = this.m_waitHandle.GetWaitDataAsync(context);
|
||||
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = InvokeOption.WaitInvoke;
|
||||
}
|
||||
|
||||
parameters ??= new object[0];
|
||||
var jsonRpcRequest = new JsonRpcRequest
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
try
|
||||
{
|
||||
await this.SendJsonStringAsync(jsonRpcRequest.ToJsonString());
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
return;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
default:
|
||||
{
|
||||
if (invokeOption.Token.CanBeCanceled)
|
||||
{
|
||||
waitData.SetCancellationToken(invokeOption.Token);
|
||||
}
|
||||
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (JsonRpcWaitResult)waitData.WaitResult;
|
||||
if (resultContext.Error != null)
|
||||
{
|
||||
throw new RpcException(resultContext.Error.Message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException("等待结果超时");
|
||||
case WaitDataStatus.Canceled:
|
||||
return;
|
||||
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketCoreResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<object> InvokeAsync(Type returnType, string method, IInvokeOption invokeOption, params object[] parameters)
|
||||
{
|
||||
var context = new JsonRpcWaitResult();
|
||||
var waitData = this.m_waitHandle.GetWaitDataAsync(context);
|
||||
|
||||
if (invokeOption == default)
|
||||
{
|
||||
invokeOption = InvokeOption.WaitInvoke;
|
||||
}
|
||||
|
||||
parameters ??= new object[0];
|
||||
var jsonRpcRequest = new JsonRpcRequest
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
try
|
||||
{
|
||||
await this.SendJsonStringAsync(jsonRpcRequest.ToJsonString());
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
return default;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
default:
|
||||
{
|
||||
if (invokeOption.Token.CanBeCanceled)
|
||||
{
|
||||
waitData.SetCancellationToken(invokeOption.Token);
|
||||
}
|
||||
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (JsonRpcWaitResult)waitData.WaitResult;
|
||||
if (resultContext.Error != null)
|
||||
{
|
||||
throw new RpcException(resultContext.Error.Message);
|
||||
}
|
||||
|
||||
if (resultContext.Result == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
return JsonRpcUtility.ResultParseToType(resultContext.Result, returnType);
|
||||
}
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException("等待结果超时");
|
||||
case WaitDataStatus.Canceled:
|
||||
return default;
|
||||
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketCoreResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送Json字符串
|
||||
/// </summary>
|
||||
/// <param name="jsonString"></param>
|
||||
protected abstract void SendJsonString(string jsonString);
|
||||
|
||||
/// <summary>
|
||||
/// 发送Json字符串
|
||||
/// </summary>
|
||||
/// <param name="jsonString"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract Task SendJsonStringAsync(string jsonString);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void InputResponseString(string jsonString)
|
||||
{
|
||||
var waitResult = JsonRpcUtility.ToJsonRpcWaitResult(jsonString);
|
||||
this.m_waitHandle.SetRun(waitResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
internal class TcpServerJsonRpcClient : JsonRpcActionClientBase
|
||||
{
|
||||
private ISocketClient m_client;
|
||||
|
||||
public TcpServerJsonRpcClient(ISocketClient socketClient)
|
||||
{
|
||||
this.m_client = socketClient;
|
||||
}
|
||||
|
||||
protected override void SendJsonString(string jsonString)
|
||||
{
|
||||
m_client.Send(jsonString);
|
||||
}
|
||||
|
||||
protected override Task SendJsonStringAsync(string jsonString)
|
||||
{
|
||||
return m_client.SendAsync(jsonString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Http;
|
||||
using TouchSocket.Http.WebSockets;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
internal sealed class WebSocketServerJsonRpcClient : JsonRpcActionClientBase
|
||||
{
|
||||
private readonly IHttpSocketClient m_client;
|
||||
|
||||
public WebSocketServerJsonRpcClient(IHttpSocketClient client)
|
||||
{
|
||||
if (client.Protocol != Sockets.Protocol.WebSocket)
|
||||
{
|
||||
throw new Exception("必须完成WebSocket连接");
|
||||
}
|
||||
this.m_client = client;
|
||||
}
|
||||
protected override void SendJsonString(string jsonString)
|
||||
{
|
||||
m_client.SendWithWS(jsonString);
|
||||
}
|
||||
|
||||
protected override Task SendJsonStringAsync(string jsonString)
|
||||
{
|
||||
return m_client.SendWithWSAsync(jsonString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,9 @@ namespace TouchSocket.JsonRpc
|
||||
/// </summary>
|
||||
public class TcpJsonRpcClient : TcpClientBase, ITcpJsonRpcClient
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public RpcStore RpcStore { get; private set; }
|
||||
|
||||
private readonly WaitHandlePool<IWaitResult> m_waitHandle = new WaitHandlePool<IWaitResult>();
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -29,7 +32,7 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign.ToString() : null
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
@@ -61,7 +64,7 @@ namespace TouchSocket.JsonRpc
|
||||
throw new RpcException(resultContext.Error.Message);
|
||||
}
|
||||
|
||||
if (resultContext.Return == null)
|
||||
if (resultContext.Result == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@@ -69,11 +72,11 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
if (returnType.IsPrimitive || returnType == typeof(string))
|
||||
{
|
||||
return resultContext.Return.ToString().ParseToType(returnType);
|
||||
return resultContext.Result.ToString().ParseToType(returnType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return resultContext.Return.ToJsonString().FromJsonString(returnType);
|
||||
return resultContext.Result.ToJsonString().FromJsonString(returnType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,7 +102,7 @@ namespace TouchSocket.JsonRpc
|
||||
Params = parameters
|
||||
};
|
||||
|
||||
jsonRpcRequest.Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign.ToString() : null;
|
||||
jsonRpcRequest.Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0;
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
@@ -166,7 +169,7 @@ namespace TouchSocket.JsonRpc
|
||||
Params = parameters
|
||||
};
|
||||
|
||||
jsonRpcRequest.Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign.ToString() : null;
|
||||
jsonRpcRequest.Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0;
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
@@ -219,7 +222,7 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign.ToString() : null
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
|
||||
switch (invokeOption.FeedbackType)
|
||||
@@ -252,7 +255,7 @@ namespace TouchSocket.JsonRpc
|
||||
throw new RpcException(resultContext.Error.Message);
|
||||
}
|
||||
|
||||
if (resultContext.Return == null)
|
||||
if (resultContext.Result == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@@ -260,11 +263,11 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
if (returnType.IsPrimitive || returnType == typeof(string))
|
||||
{
|
||||
return resultContext.Return.ToString().ParseToType(returnType);
|
||||
return resultContext.Result.ToString().ParseToType(returnType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return resultContext.Return.ToJsonString().FromJsonString(returnType);
|
||||
return resultContext.Result.ToJsonString().FromJsonString(returnType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -273,6 +276,127 @@ namespace TouchSocket.JsonRpc
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
base.LoadConfig(config);
|
||||
if (this.Container.IsRegistered(typeof(RpcStore)))
|
||||
{
|
||||
this.RpcStore = this.Container.Resolve<RpcStore>();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RpcStore = new RpcStore(this.Container);
|
||||
}
|
||||
this.RpcStore.AddRpcParser(this);
|
||||
}
|
||||
|
||||
#region Rpc解析器
|
||||
|
||||
/// <summary>
|
||||
/// JsonRpc的调用键。
|
||||
/// </summary>
|
||||
public ActionMap ActionMap { get; private set; } = new ActionMap(true);
|
||||
|
||||
void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances)
|
||||
{
|
||||
foreach (var methodInstance in methodInstances)
|
||||
{
|
||||
if (methodInstance.GetAttribute<JsonRpcAttribute>() is JsonRpcAttribute attribute)
|
||||
{
|
||||
this.ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances)
|
||||
{
|
||||
foreach (var methodInstance in methodInstances)
|
||||
{
|
||||
if (methodInstance.GetAttribute<JsonRpcAttribute>() is JsonRpcAttribute attribute)
|
||||
{
|
||||
this.ActionMap.Remove(attribute.GetInvokenKey(methodInstance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Rpc解析器
|
||||
|
||||
private void ThisInvoke(object obj)
|
||||
{
|
||||
var callContext = (JsonRpcCallContextBase)obj;
|
||||
var invokeResult = new InvokeResult();
|
||||
|
||||
try
|
||||
{
|
||||
JsonRpcUtility.BuildRequestContext(this.ActionMap, ref callContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
invokeResult.Status = InvokeStatus.Exception;
|
||||
invokeResult.Message = ex.Message;
|
||||
}
|
||||
|
||||
if (callContext.MethodInstance != null)
|
||||
{
|
||||
if (!callContext.MethodInstance.IsEnable)
|
||||
{
|
||||
invokeResult.Status = InvokeStatus.UnEnable;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
invokeResult.Status = InvokeStatus.UnFound;
|
||||
}
|
||||
|
||||
if (invokeResult.Status == InvokeStatus.Ready)
|
||||
{
|
||||
var rpcServer = callContext.MethodInstance.ServerFactory.Create(callContext, callContext.JsonRpcContext.Parameters);
|
||||
if (rpcServer is ITransientRpcServer transientRpcServer)
|
||||
{
|
||||
transientRpcServer.CallContext = callContext;
|
||||
}
|
||||
|
||||
invokeResult = RpcStore.Execute(rpcServer, callContext.JsonRpcContext.Parameters, callContext);
|
||||
}
|
||||
|
||||
if (!callContext.JsonRpcContext.Id.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var error = JsonRpcUtility.GetJsonRpcError(invokeResult);
|
||||
this.Response(callContext, invokeResult.Result, error);
|
||||
}
|
||||
|
||||
private void Response(JsonRpcCallContextBase callContext, object result, JsonRpcError error)
|
||||
{
|
||||
try
|
||||
{
|
||||
JsonRpcResponseBase response;
|
||||
if (error == null)
|
||||
{
|
||||
response = new JsonRpcSuccessResponse
|
||||
{
|
||||
Result = result,
|
||||
Id = callContext.JsonRpcContext.Id
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
response = new JsonRpcErrorResponse
|
||||
{
|
||||
Error = error,
|
||||
Id = callContext.JsonRpcContext.Id
|
||||
};
|
||||
}
|
||||
var str = JsonRpcUtility.ToJsonRpcResponseString(response);
|
||||
this.Send(str);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
|
||||
{
|
||||
@@ -296,19 +420,17 @@ namespace TouchSocket.JsonRpc
|
||||
|
||||
try
|
||||
{
|
||||
if (jsonString.Contains("error") || jsonString.Contains("result"))
|
||||
if (this.ActionMap.Count > 0 && JsonRpcUtility.IsJsonRpcRequest(jsonString))
|
||||
{
|
||||
var responseContext = jsonString.FromJsonString<JsonResponseContext>();
|
||||
if (responseContext != null && !responseContext.Id.IsNullOrEmpty())
|
||||
Task.Factory.StartNew(this.ThisInvoke, new WebSocketJsonRpcCallContext(this, jsonString));
|
||||
}
|
||||
else
|
||||
{
|
||||
var waitContext = new JsonRpcWaitResult
|
||||
var waitResult = JsonRpcUtility.ToJsonRpcWaitResult(jsonString);
|
||||
if (waitResult != null)
|
||||
{
|
||||
Status = 1,
|
||||
Sign = long.Parse(responseContext.Id),
|
||||
Error = responseContext.Error,
|
||||
Return = responseContext.Result
|
||||
};
|
||||
this.m_waitHandle.SetRun(waitContext);
|
||||
waitResult.Status = 1;
|
||||
this.m_waitHandle.SetRun(waitResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Http.WebSockets;
|
||||
using TouchSocket.Resources;
|
||||
using TouchSocket.Rpc;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
@@ -11,7 +13,15 @@ namespace TouchSocket.JsonRpc
|
||||
/// </summary>
|
||||
public class WebSocketJsonRpcClient : WebSocketClientBase, IWebSocketJsonRpcClient
|
||||
{
|
||||
private readonly WaitHandlePool<IWaitResult> m_waitHandle = new WaitHandlePool<IWaitResult>();
|
||||
private readonly WaitHandlePool<JsonRpcWaitResult> m_waitHandle = new WaitHandlePool<JsonRpcWaitResult>();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public RpcStore RpcStore { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// WaitHandle
|
||||
/// </summary>
|
||||
public WaitHandlePool<JsonRpcWaitResult> WaitHandle => this.m_waitHandle;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Invoke(Type returnType, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types)
|
||||
@@ -29,50 +39,60 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign.ToString() : null
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
try
|
||||
{
|
||||
this.SendWithWS(jsonRpcRequest.ToJsonString());
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
return default;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
default:
|
||||
{
|
||||
waitData.Wait(invokeOption.Timeout);
|
||||
var resultContext = (JsonRpcWaitResult)waitData.WaitResult;
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
|
||||
if (resultContext.Status == 0)
|
||||
if (invokeOption.Token.CanBeCanceled)
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
waitData.SetCancellationToken(invokeOption.Token);
|
||||
}
|
||||
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (JsonRpcWaitResult)waitData.WaitResult;
|
||||
if (resultContext.Error != null)
|
||||
{
|
||||
throw new RpcException(resultContext.Error.Message);
|
||||
}
|
||||
|
||||
if (resultContext.Return == null)
|
||||
if (resultContext.Result == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (returnType.IsPrimitive || returnType == typeof(string))
|
||||
{
|
||||
return resultContext.Return.ToString().ParseToType(returnType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return resultContext.Return.ToJsonString().FromJsonString(returnType);
|
||||
}
|
||||
return JsonRpcUtility.ResultParseToType(resultContext.Result, returnType);
|
||||
}
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException("等待结果超时");
|
||||
case WaitDataStatus.Canceled:
|
||||
return default;
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
return default;
|
||||
throw new Exception(TouchSocketCoreResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,42 +106,59 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
invokeOption = InvokeOption.WaitInvoke;
|
||||
}
|
||||
|
||||
parameters ??= new object[0];
|
||||
var jsonRpcRequest = new JsonRpcRequest()
|
||||
var jsonRpcRequest = new JsonRpcRequest
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
|
||||
jsonRpcRequest.Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign.ToString() : null;
|
||||
try
|
||||
{
|
||||
this.SendWithWS(jsonRpcRequest.ToJsonString());
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
return;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
default:
|
||||
{
|
||||
waitData.Wait(invokeOption.Timeout);
|
||||
var resultContext = (JsonRpcWaitResult)waitData.WaitResult;
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
|
||||
if (resultContext.Status == 0)
|
||||
if (invokeOption.Token.CanBeCanceled)
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
waitData.SetCancellationToken(invokeOption.Token);
|
||||
}
|
||||
|
||||
switch (waitData.Wait(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (JsonRpcWaitResult)waitData.WaitResult;
|
||||
if (resultContext.Error != null)
|
||||
{
|
||||
throw new RpcException(resultContext.Error.Message);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException("等待结果超时");
|
||||
case WaitDataStatus.Canceled:
|
||||
return;
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketCoreResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -146,42 +183,59 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
invokeOption = InvokeOption.WaitInvoke;
|
||||
}
|
||||
|
||||
parameters ??= new object[0];
|
||||
var jsonRpcRequest = new JsonRpcRequest()
|
||||
var jsonRpcRequest = new JsonRpcRequest
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
|
||||
jsonRpcRequest.Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign.ToString() : null;
|
||||
this.SendWithWS(jsonRpcRequest.ToJsonString());
|
||||
try
|
||||
{
|
||||
await this.SendWithWSAsync(jsonRpcRequest.ToJsonString());
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
return;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
default:
|
||||
{
|
||||
await waitData.WaitAsync(invokeOption.Timeout);
|
||||
var resultContext = (JsonRpcWaitResult)waitData.WaitResult;
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
|
||||
if (resultContext.Status == 0)
|
||||
if (invokeOption.Token.CanBeCanceled)
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
waitData.SetCancellationToken(invokeOption.Token);
|
||||
}
|
||||
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (JsonRpcWaitResult)waitData.WaitResult;
|
||||
if (resultContext.Error != null)
|
||||
{
|
||||
throw new RpcException(resultContext.Error.Message);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException("等待结果超时");
|
||||
case WaitDataStatus.Canceled:
|
||||
return;
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketCoreResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -194,94 +248,221 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
invokeOption = InvokeOption.WaitInvoke;
|
||||
}
|
||||
|
||||
parameters ??= new object[0];
|
||||
var jsonRpcRequest = new JsonRpcRequest
|
||||
{
|
||||
Method = method,
|
||||
Params = parameters,
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign.ToString() : null
|
||||
Id = invokeOption.FeedbackType == FeedbackType.WaitInvoke ? context.Sign : 0
|
||||
};
|
||||
this.SendWithWS(jsonRpcRequest.ToJsonString());
|
||||
try
|
||||
{
|
||||
await this.SendWithWSAsync(jsonRpcRequest.ToJsonString());
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
case FeedbackType.WaitSend:
|
||||
{
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
return default;
|
||||
}
|
||||
case FeedbackType.WaitInvoke:
|
||||
default:
|
||||
{
|
||||
await waitData.WaitAsync(invokeOption.Timeout);
|
||||
var resultContext = (JsonRpcWaitResult)waitData.WaitResult;
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
|
||||
if (resultContext.Status == 0)
|
||||
if (invokeOption.Token.CanBeCanceled)
|
||||
{
|
||||
throw new TimeoutException("等待结果超时");
|
||||
waitData.SetCancellationToken(invokeOption.Token);
|
||||
}
|
||||
|
||||
switch (await waitData.WaitAsync(invokeOption.Timeout))
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
{
|
||||
var resultContext = (JsonRpcWaitResult)waitData.WaitResult;
|
||||
if (resultContext.Error != null)
|
||||
{
|
||||
throw new RpcException(resultContext.Error.Message);
|
||||
}
|
||||
|
||||
if (resultContext.Return == null)
|
||||
if (resultContext.Result == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (returnType.IsPrimitive || returnType == typeof(string))
|
||||
{
|
||||
return resultContext.Return.ToString().ParseToType(returnType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return resultContext.Return.ToJsonString().FromJsonString(returnType);
|
||||
}
|
||||
return JsonRpcUtility.ResultParseToType(resultContext.Result, returnType);
|
||||
}
|
||||
}
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException("等待结果超时");
|
||||
case WaitDataStatus.Canceled:
|
||||
return default;
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
return default;
|
||||
throw new Exception(TouchSocketCoreResource.UnknownError.GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_waitHandle.Destroy(waitData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool HandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
base.LoadConfig(config);
|
||||
if (this.Container.IsRegistered(typeof(RpcStore)))
|
||||
{
|
||||
this.RpcStore = this.Container.Resolve<RpcStore>();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RpcStore = new RpcStore(this.Container);
|
||||
}
|
||||
this.RpcStore.AddRpcParser(this);
|
||||
}
|
||||
|
||||
#region Rpc解析器
|
||||
|
||||
/// <summary>
|
||||
/// JsonRpc的调用键。
|
||||
/// </summary>
|
||||
public ActionMap ActionMap { get; private set; } = new ActionMap(true);
|
||||
|
||||
|
||||
void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances)
|
||||
{
|
||||
foreach (var methodInstance in methodInstances)
|
||||
{
|
||||
if (methodInstance.GetAttribute<JsonRpcAttribute>() is JsonRpcAttribute attribute)
|
||||
{
|
||||
this.ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances)
|
||||
{
|
||||
foreach (var methodInstance in methodInstances)
|
||||
{
|
||||
if (methodInstance.GetAttribute<JsonRpcAttribute>() is JsonRpcAttribute attribute)
|
||||
{
|
||||
this.ActionMap.Remove(attribute.GetInvokenKey(methodInstance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Rpc解析器
|
||||
|
||||
private void ThisInvoke(object obj)
|
||||
{
|
||||
var callContext = (JsonRpcCallContextBase)obj;
|
||||
var invokeResult = new InvokeResult();
|
||||
|
||||
try
|
||||
{
|
||||
JsonRpcUtility.BuildRequestContext(this.ActionMap, ref callContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
invokeResult.Status = InvokeStatus.Exception;
|
||||
invokeResult.Message = ex.Message;
|
||||
}
|
||||
|
||||
if (callContext.MethodInstance != null)
|
||||
{
|
||||
if (!callContext.MethodInstance.IsEnable)
|
||||
{
|
||||
invokeResult.Status = InvokeStatus.UnEnable;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
invokeResult.Status = InvokeStatus.UnFound;
|
||||
}
|
||||
|
||||
if (invokeResult.Status == InvokeStatus.Ready)
|
||||
{
|
||||
var rpcServer = callContext.MethodInstance.ServerFactory.Create(callContext, callContext.JsonRpcContext.Parameters);
|
||||
if (rpcServer is ITransientRpcServer transientRpcServer)
|
||||
{
|
||||
transientRpcServer.CallContext = callContext;
|
||||
}
|
||||
|
||||
invokeResult = RpcStore.Execute(rpcServer, callContext.JsonRpcContext.Parameters, callContext);
|
||||
}
|
||||
|
||||
if (!callContext.JsonRpcContext.Id.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var error = JsonRpcUtility.GetJsonRpcError(invokeResult);
|
||||
this.Response(callContext, invokeResult.Result, error);
|
||||
}
|
||||
|
||||
private void Response(JsonRpcCallContextBase callContext, object result, JsonRpcError error)
|
||||
{
|
||||
try
|
||||
{
|
||||
JsonRpcResponseBase response;
|
||||
if (error == null)
|
||||
{
|
||||
response = new JsonRpcSuccessResponse
|
||||
{
|
||||
Result = result,
|
||||
Id = callContext.JsonRpcContext.Id
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
response = new JsonRpcErrorResponse
|
||||
{
|
||||
Error = error,
|
||||
Id = callContext.JsonRpcContext.Id
|
||||
};
|
||||
}
|
||||
var str = JsonRpcUtility.ToJsonRpcResponseString(response);
|
||||
this.SendWithWS(str);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnHandleWSDataFrame(WSDataFrame dataFrame)
|
||||
{
|
||||
string jsonString = null;
|
||||
if (requestInfo is WSDataFrame dataFrame && dataFrame.Opcode == WSDataType.Text)
|
||||
if (dataFrame.Opcode == WSDataType.Text)
|
||||
{
|
||||
jsonString = dataFrame.ToText();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(jsonString))
|
||||
{
|
||||
return base.HandleReceivedData(byteBlock, requestInfo);
|
||||
base.OnHandleWSDataFrame(dataFrame);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
if (this.ActionMap.Count > 0 && JsonRpcUtility.IsJsonRpcRequest(jsonString))
|
||||
{
|
||||
if (jsonString.Contains("error") || jsonString.Contains("result"))
|
||||
Task.Factory.StartNew(this.ThisInvoke,new WebSocketJsonRpcCallContext(this, jsonString));
|
||||
}
|
||||
else
|
||||
{
|
||||
var responseContext = jsonString.FromJsonString<JsonResponseContext>();
|
||||
if (responseContext != null && !responseContext.Id.IsNullOrEmpty())
|
||||
var waitResult = JsonRpcUtility.ToJsonRpcWaitResult(jsonString);
|
||||
if (waitResult != null)
|
||||
{
|
||||
var waitContext = new JsonRpcWaitResult
|
||||
{
|
||||
Status = 1,
|
||||
Sign = long.Parse(responseContext.Id),
|
||||
Error = responseContext.Error,
|
||||
Return = responseContext.Result
|
||||
};
|
||||
this.m_waitHandle.SetRun(waitContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return base.HandleReceivedData(byteBlock, requestInfo);
|
||||
waitResult.Status = 1;
|
||||
this.m_waitHandle.SetRun(waitResult);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnHandleWSDataFrame(dataFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Http;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// HttpSocketClientExtension
|
||||
/// </summary>
|
||||
public static class HttpSocketClientExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 标识是否为JsonRpc
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<bool> JsonRpcProperty =
|
||||
DependencyProperty<bool>.Register("JsonRpc", false);
|
||||
|
||||
/// <summary>
|
||||
/// 获取<see cref="JsonRpcProperty"/>
|
||||
/// </summary>
|
||||
/// <param name="socketClient"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetJsonRpc(this IHttpSocketClient socketClient, bool value = true)
|
||||
{
|
||||
return socketClient.GetValue(JsonRpcProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置<see cref="JsonRpcProperty"/>
|
||||
/// </summary>
|
||||
/// <param name="socketClient"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void SetJsonRpc(this IHttpSocketClient socketClient, bool value = true)
|
||||
{
|
||||
socketClient.SetValue(JsonRpcProperty, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/TouchSocket.JsonRpc/Extensions/JsonRpcClientExtension.cs
Normal file
76
src/TouchSocket.JsonRpc/Extensions/JsonRpcClientExtension.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Http;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// JsonRpcClientExtension
|
||||
/// </summary>
|
||||
public static class JsonRpcClientExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 标识是否为JsonRpc
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<bool> IsJsonRpcProperty =
|
||||
DependencyProperty<bool>.Register("IsJsonRpc", false);
|
||||
|
||||
/// <summary>
|
||||
/// IJsonRpcActionClient
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<IJsonRpcActionClient> JsonRpcActionClientProperty =
|
||||
DependencyProperty<IJsonRpcActionClient>.Register("JsonRpcActionClient", default);
|
||||
|
||||
/// <summary>
|
||||
/// 获取<see cref="IsJsonRpcProperty"/>
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetIsJsonRpc(this ITcpClientBase client)
|
||||
{
|
||||
return client.GetValue(IsJsonRpcProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置<see cref="IsJsonRpcProperty"/>
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void SetIsJsonRpc(this ITcpClientBase client, bool value = true)
|
||||
{
|
||||
client.SetValue(IsJsonRpcProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取基于Tcp协议或者WebSocket协议的双工JsonRpc端
|
||||
/// </summary>
|
||||
/// <param name="socketClient"></param>
|
||||
/// <returns></returns>
|
||||
public static IJsonRpcActionClient GetJsonRpcActionClient(this ISocketClient socketClient)
|
||||
{
|
||||
if (socketClient.TryGetValue(JsonRpcActionClientProperty, out var actionClient))
|
||||
{
|
||||
return actionClient;
|
||||
}
|
||||
|
||||
if (socketClient.Protocol== Sockets.Protocol.Tcp)
|
||||
{
|
||||
actionClient = new TcpServerJsonRpcClient(socketClient);
|
||||
socketClient.SetValue(JsonRpcActionClientProperty, actionClient);
|
||||
return actionClient;
|
||||
}
|
||||
else if (socketClient.Protocol == Sockets.Protocol.WebSocket)
|
||||
{
|
||||
actionClient = new WebSocketServerJsonRpcClient((IHttpSocketClient)socketClient);
|
||||
socketClient.SetValue(JsonRpcActionClientProperty, actionClient);
|
||||
return actionClient;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new System.Exception("SocketClient必须是Tcp协议,或者完成WebSocket连接");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/TouchSocket.JsonRpc/Interface/IJsonRpcActionClient.cs
Normal file
26
src/TouchSocket.JsonRpc/Interface/IJsonRpcActionClient.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// IJsonRpcClientBase
|
||||
/// </summary>
|
||||
public interface IJsonRpcActionClient : IJsonRpcClient
|
||||
{
|
||||
/// <summary>
|
||||
/// WaitHandle
|
||||
/// </summary>
|
||||
WaitHandlePool<JsonRpcWaitResult> WaitHandle { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 收到JsonRpc的响应数据
|
||||
/// </summary>
|
||||
/// <param name="jsonString"></param>
|
||||
void InputResponseString(string jsonString);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,6 @@ namespace TouchSocket.JsonRpc
|
||||
/// <summary>
|
||||
/// JsonRpc数据包
|
||||
/// </summary>
|
||||
public JsonRpcContext JsonRpcContext { get; }
|
||||
public JsonRpcRequestContext JsonRpcContext { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
using TouchSocket.Sockets;
|
||||
using TouchSocket.Rpc;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// 基于Tcp协议的JsonRpc客户端。
|
||||
/// </summary>
|
||||
public interface ITcpJsonRpcClient : IJsonRpcClient, ITcpClient
|
||||
public interface ITcpJsonRpcClient : IJsonRpcClient, ITcpClient,IRpcParser
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
using TouchSocket.Http.WebSockets;
|
||||
using TouchSocket.Rpc;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// IWebSocketJsonRpcClient
|
||||
/// </summary>
|
||||
public interface IWebSocketJsonRpcClient : IWebSocketClient, IJsonRpcClient
|
||||
public interface IWebSocketJsonRpcClient : IWebSocketClient, IJsonRpcClient, IRpcParser
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#if NET6_0_OR_GREATER
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// TouchSokcetJsonRpcSourceGenerationContext
|
||||
/// </summary>
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(JsonRpcResponseContext))]
|
||||
[JsonSerializable(typeof(JsonRpcError))]
|
||||
[JsonSerializable(typeof(JsonRpcRequestContext))]
|
||||
[JsonSerializable(typeof(JsonRpcSuccessResponse))]
|
||||
[JsonSerializable(typeof(JsonRpcErrorResponse))]
|
||||
[JsonSerializable(typeof(JsonRpcWaitResult))]
|
||||
[JsonSerializable(typeof(object))]
|
||||
internal partial class TouchSokcetJsonRpcSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Http;
|
||||
|
||||
@@ -8,7 +9,7 @@ namespace TouchSocket.JsonRpc
|
||||
/// HttpJsonRpcParserPlugin
|
||||
/// </summary>
|
||||
[PluginOption(Singleton = true, NotRegister = false)]
|
||||
public sealed class HttpJsonRpcParserPlugin : JsonRpcParserPluginBase, IHttpPlugin
|
||||
public sealed class HttpJsonRpcParserPlugin : JsonRpcParserPluginBase
|
||||
{
|
||||
private string m_jsonRpcUrl = "/jsonrpc";
|
||||
|
||||
@@ -16,8 +17,10 @@ namespace TouchSocket.JsonRpc
|
||||
/// HttpJsonRpcParserPlugin
|
||||
/// </summary>
|
||||
/// <param name="container"></param>
|
||||
public HttpJsonRpcParserPlugin(IContainer container) : base(container)
|
||||
/// <param name="pluginsManager"></param>
|
||||
public HttpJsonRpcParserPlugin(IContainer container, IPluginsManager pluginsManager) : base(container)
|
||||
{
|
||||
pluginsManager.Add<IHttpSocketClient, HttpContextEventArgs>(nameof(IHttpPlugin.OnHttpRequest), OnHttpRequest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -29,21 +32,6 @@ namespace TouchSocket.JsonRpc
|
||||
set => this.m_jsonRpcUrl = string.IsNullOrEmpty(value) ? "/" : value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e)
|
||||
{
|
||||
if (e.Context.Request.Method == HttpMethod.Post)
|
||||
{
|
||||
if (this.m_jsonRpcUrl == "/" || e.Context.Request.UrlEquals(this.m_jsonRpcUrl))
|
||||
{
|
||||
e.Handled = true;
|
||||
this.ThisInvoke(new HttpJsonRpcCallContext(client, e.Context.Request.GetBody(), e.Context));
|
||||
return;
|
||||
}
|
||||
}
|
||||
await e.InvokeNext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当挂载在<see cref="HttpService"/>时,匹配Url然后响应。当设置为null或空时,会全部响应。
|
||||
/// </summary>
|
||||
@@ -60,34 +48,46 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var responseByteBlock = new ByteBlock())
|
||||
{
|
||||
object jobject;
|
||||
JsonRpcResponseBase response;
|
||||
if (error == null)
|
||||
{
|
||||
jobject = new JsonRpcSuccessResponse
|
||||
response = new JsonRpcSuccessResponse
|
||||
{
|
||||
result = result,
|
||||
id = callContext.JsonRpcContext.Id
|
||||
Result = result,
|
||||
Id = callContext.JsonRpcContext.Id
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
jobject = new JsonRpcErrorResponse
|
||||
response = new JsonRpcErrorResponse
|
||||
{
|
||||
error = error,
|
||||
id = callContext.JsonRpcContext.Id
|
||||
Error = error,
|
||||
Id = callContext.JsonRpcContext.Id
|
||||
};
|
||||
}
|
||||
var str = JsonRpcUtility.ToJsonRpcResponseString(response);
|
||||
|
||||
var httpResponse = ((HttpJsonRpcCallContext)callContext).HttpContext.Response;
|
||||
httpResponse.FromJson(jobject.ToJsonString());
|
||||
httpResponse.FromJson(str);
|
||||
httpResponse.Answer();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e)
|
||||
{
|
||||
if (e.Context.Request.Method == HttpMethod.Post)
|
||||
{
|
||||
if (this.m_jsonRpcUrl == "/" || e.Context.Request.UrlEquals(this.m_jsonRpcUrl))
|
||||
{
|
||||
e.Handled = true;
|
||||
await this.ThisInvoke(new HttpJsonRpcCallContext(client, e.Context.Request.GetBody(), e.Context));
|
||||
return;
|
||||
}
|
||||
}
|
||||
await e.InvokeNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,12 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Rpc;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
@@ -38,6 +39,7 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
this.RpcStore = new RpcStore(container);
|
||||
}
|
||||
|
||||
this.ActionMap = new ActionMap(true);
|
||||
this.RpcStore.AddRpcParser(this);
|
||||
}
|
||||
@@ -47,37 +49,12 @@ namespace TouchSocket.JsonRpc
|
||||
/// </summary>
|
||||
public ActionMap ActionMap { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public RpcStore RpcStore { get; private set; }
|
||||
|
||||
#region RPC解析器
|
||||
|
||||
void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances)
|
||||
{
|
||||
foreach (var methodInstance in methodInstances)
|
||||
{
|
||||
if (methodInstance.GetAttribute<JsonRpcAttribute>() is JsonRpcAttribute attribute)
|
||||
{
|
||||
this.ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances)
|
||||
{
|
||||
foreach (var methodInstance in methodInstances)
|
||||
{
|
||||
if (methodInstance.GetAttribute<JsonRpcAttribute>() is JsonRpcAttribute attribute)
|
||||
{
|
||||
this.ActionMap.Remove(attribute.GetInvokenKey(methodInstance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion RPC解析器
|
||||
|
||||
/// <summary>
|
||||
/// 处理响应结果。
|
||||
/// </summary>
|
||||
@@ -89,14 +66,14 @@ namespace TouchSocket.JsonRpc
|
||||
/// <summary>
|
||||
/// 调用JsonRpc
|
||||
/// </summary>
|
||||
/// <param name="callContext"></param>
|
||||
protected void ThisInvoke(JsonRpcCallContextBase callContext)
|
||||
protected async Task ThisInvoke(object obj)
|
||||
{
|
||||
var callContext = (JsonRpcCallContextBase)obj;
|
||||
var invokeResult = new InvokeResult();
|
||||
|
||||
try
|
||||
{
|
||||
this.BuildRequestContext(ref callContext);
|
||||
JsonRpcUtility.BuildRequestContext(this.ActionMap,ref callContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -124,151 +101,40 @@ namespace TouchSocket.JsonRpc
|
||||
transientRpcServer.CallContext = callContext;
|
||||
}
|
||||
|
||||
invokeResult = RpcStore.Execute(rpcServer, callContext.JsonRpcContext.Parameters, callContext);
|
||||
invokeResult = await RpcStore.ExecuteAsync(rpcServer, callContext.JsonRpcContext.Parameters, callContext);
|
||||
}
|
||||
|
||||
if (!callContext.JsonRpcContext.NeedResponse)
|
||||
if (!callContext.JsonRpcContext.Id.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
JsonRpcError error = null;
|
||||
switch (invokeResult.Status)
|
||||
{
|
||||
case InvokeStatus.Success:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.UnFound:
|
||||
{
|
||||
error = new JsonRpcError
|
||||
{
|
||||
Code = -32601,
|
||||
Message = "函数未找到"
|
||||
};
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.UnEnable:
|
||||
{
|
||||
error = new JsonRpcError
|
||||
{
|
||||
Code = -32601,
|
||||
Message = "函数已被禁用"
|
||||
};
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.InvocationException:
|
||||
{
|
||||
error = new JsonRpcError
|
||||
{
|
||||
Code = -32603,
|
||||
Message = "函数内部异常"
|
||||
};
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.Exception:
|
||||
{
|
||||
error = new JsonRpcError
|
||||
{
|
||||
Code = -32602,
|
||||
Message = invokeResult.Message
|
||||
};
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
var error = JsonRpcUtility.GetJsonRpcError(invokeResult);
|
||||
this.Response(callContext, invokeResult.Result, error);
|
||||
}
|
||||
#region Rpc解析器
|
||||
|
||||
private void BuildRequestContext(ref JsonRpcCallContextBase callContext)
|
||||
void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances)
|
||||
{
|
||||
var jsonRpcContext = SerializeConvert.JsonDeserializeFromString<JsonRpcContext>(callContext.JsonString);
|
||||
callContext.JsonRpcContext = jsonRpcContext;
|
||||
if (jsonRpcContext.Id != null)
|
||||
foreach (var methodInstance in methodInstances)
|
||||
{
|
||||
jsonRpcContext.NeedResponse = true;
|
||||
if (methodInstance.GetAttribute<JsonRpcAttribute>() is JsonRpcAttribute attribute)
|
||||
{
|
||||
this.ActionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.ActionMap.TryGetMethodInstance(jsonRpcContext.Method, out var methodInstance))
|
||||
void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances)
|
||||
{
|
||||
callContext.MethodInstance = methodInstance;
|
||||
if (jsonRpcContext.Params == null)
|
||||
foreach (var methodInstance in methodInstances)
|
||||
{
|
||||
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
|
||||
if (methodInstance.GetAttribute<JsonRpcAttribute>() is JsonRpcAttribute attribute)
|
||||
{
|
||||
jsonRpcContext.Parameters = methodInstance.ParameterNames.Length > 1 ? throw new RpcException("调用参数计数不匹配") : (new object[] { callContext });
|
||||
}
|
||||
else
|
||||
{
|
||||
if (methodInstance.ParameterNames.Length != 0)
|
||||
{
|
||||
throw new RpcException("调用参数计数不匹配");
|
||||
this.ActionMap.Remove(attribute.GetInvokenKey(methodInstance));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (jsonRpcContext.Params is Dictionary<string, object> obj)
|
||||
{
|
||||
jsonRpcContext.Parameters = new object[methodInstance.ParameterNames.Length];
|
||||
//内联
|
||||
var i = 0;
|
||||
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
|
||||
{
|
||||
jsonRpcContext.Parameters[0] = callContext;
|
||||
i = 1;
|
||||
}
|
||||
for (; i < methodInstance.ParameterNames.Length; i++)
|
||||
{
|
||||
if (obj.TryGetValue(methodInstance.ParameterNames[i], out var jToken))
|
||||
{
|
||||
var type = methodInstance.ParameterTypes[i];
|
||||
jsonRpcContext.Parameters[i] = jToken.ToJsonString().FromJsonString(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (methodInstance.Parameters[i].HasDefaultValue)
|
||||
{
|
||||
jsonRpcContext.Parameters[i] = methodInstance.Parameters[i].DefaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RpcException("调用参数计数不匹配");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var array = (IList)jsonRpcContext.Params;
|
||||
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
|
||||
{
|
||||
if (array.Count != methodInstance.ParameterNames.Length - 1)
|
||||
{
|
||||
throw new RpcException("调用参数计数不匹配");
|
||||
}
|
||||
jsonRpcContext.Parameters = new object[methodInstance.ParameterNames.Length];
|
||||
|
||||
jsonRpcContext.Parameters[0] = callContext;
|
||||
for (var i = 0; i < array.Count; i++)
|
||||
{
|
||||
jsonRpcContext.Parameters[i + 1] = array[i].ToJsonString().FromJsonString(methodInstance.ParameterTypes[i + 1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (array.Count != methodInstance.ParameterNames.Length)
|
||||
{
|
||||
throw new RpcException("调用参数计数不匹配");
|
||||
}
|
||||
jsonRpcContext.Parameters = new object[methodInstance.ParameterNames.Length];
|
||||
|
||||
for (var i = 0; i < array.Count; i++)
|
||||
{
|
||||
jsonRpcContext.Parameters[i] = array[i].ToJsonString().FromJsonString(methodInstance.ParameterTypes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion Rpc解析器
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,17 @@ namespace TouchSocket.JsonRpc
|
||||
/// 基于Tcp协议的JsonRpc功能插件
|
||||
/// </summary>
|
||||
[PluginOption(Singleton = true, NotRegister = false)]
|
||||
public sealed class TcpJsonRpcParserPlugin : JsonRpcParserPluginBase, ITcpConnectingPlugin, ITcpReceivedPlugin
|
||||
public sealed class TcpJsonRpcParserPlugin : JsonRpcParserPluginBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 基于Tcp协议的JsonRpc功能插件
|
||||
/// </summary>
|
||||
/// <param name="container"></param>
|
||||
public TcpJsonRpcParserPlugin(IContainer container) : base(container)
|
||||
/// <param name="pluginsManager"></param>
|
||||
public TcpJsonRpcParserPlugin(IContainer container, IPluginsManager pluginsManager) : base(container)
|
||||
{
|
||||
pluginsManager.Add<ITcpClientBase, ConnectedEventArgs>(nameof(ITcpConnectedPlugin.OnTcpConnected), OnTcpConnected);
|
||||
pluginsManager.Add<ITcpClientBase, ReceivedDataEventArgs>(nameof(ITcpReceivedPlugin.OnTcpReceived), OnTcpReceived);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -25,7 +28,7 @@ namespace TouchSocket.JsonRpc
|
||||
|
||||
/// <summary>
|
||||
/// 不需要自动转化协议。
|
||||
/// <para>仅当服务器是TCP时生效。此时如果携带协议为TcpJsonRpc时才会解释为jsonRpc。</para>
|
||||
/// <para>仅当服务器是Tcp时生效。才会解释为jsonRpc。</para>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public TcpJsonRpcParserPlugin NoSwitchProtocol()
|
||||
@@ -35,20 +38,49 @@ namespace TouchSocket.JsonRpc
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task OnTcpConnecting(ITcpClientBase client, ConnectingEventArgs e)
|
||||
protected override sealed void Response(JsonRpcCallContextBase callContext, object result, JsonRpcError error)
|
||||
{
|
||||
try
|
||||
{
|
||||
JsonRpcResponseBase response;
|
||||
if (error == null)
|
||||
{
|
||||
response = new JsonRpcSuccessResponse
|
||||
{
|
||||
Result = result,
|
||||
Id = callContext.JsonRpcContext.Id
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
response = new JsonRpcErrorResponse
|
||||
{
|
||||
Error = error,
|
||||
Id = callContext.JsonRpcContext.Id
|
||||
};
|
||||
}
|
||||
var str = JsonRpcUtility.ToJsonRpcResponseString(response);
|
||||
var client = (ITcpClientBase)callContext.Caller;
|
||||
client.Send(str.ToUTF8Bytes());
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private Task OnTcpConnected(ITcpClientBase client, ConnectedEventArgs e)
|
||||
{
|
||||
if (this.AutoSwitch && client.Protocol == Protocol.Tcp)
|
||||
{
|
||||
client.Protocol = JsonRpcUtility.TcpJsonRpc;
|
||||
client.SetIsJsonRpc();
|
||||
}
|
||||
|
||||
return e.InvokeNext();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task OnTcpReceived(ITcpClientBase client, ReceivedDataEventArgs e)
|
||||
private Task OnTcpReceived(ITcpClientBase client, ReceivedDataEventArgs e)
|
||||
{
|
||||
if (client.Protocol == JsonRpcUtility.TcpJsonRpc)
|
||||
if (client.GetIsJsonRpc())
|
||||
{
|
||||
var jsonRpcStr = string.Empty;
|
||||
if (e.RequestInfo is IJsonRpcRequestInfo requestInfo)
|
||||
@@ -63,43 +95,22 @@ namespace TouchSocket.JsonRpc
|
||||
if (jsonRpcStr.HasValue())
|
||||
{
|
||||
e.Handled = true;
|
||||
this.ThisInvoke(new TcpJsonRpcCallContext(client, jsonRpcStr));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await e.InvokeNext();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override sealed void Response(JsonRpcCallContextBase callContext, object result, JsonRpcError error)
|
||||
if (client.TryGetValue(JsonRpcClientExtension.JsonRpcActionClientProperty, out var actionClient)
|
||||
&& !JsonRpcUtility.IsJsonRpcRequest(jsonRpcStr))
|
||||
{
|
||||
try
|
||||
{
|
||||
object jobject;
|
||||
if (error == null)
|
||||
{
|
||||
jobject = new JsonRpcSuccessResponse
|
||||
{
|
||||
result = result,
|
||||
id = callContext.JsonRpcContext.Id
|
||||
};
|
||||
actionClient.InputResponseString(jsonRpcStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
jobject = new JsonRpcErrorResponse
|
||||
{
|
||||
error = error,
|
||||
id = callContext.JsonRpcContext.Id
|
||||
};
|
||||
Task.Factory.StartNew(this.ThisInvoke, new WebSocketJsonRpcCallContext(client, jsonRpcStr));
|
||||
}
|
||||
|
||||
var client = (ITcpClientBase)callContext.Caller;
|
||||
client.Send(jobject.ToJsonString().ToUTF8Bytes());
|
||||
}
|
||||
catch
|
||||
{
|
||||
return EasyTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
return e.InvokeNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,18 @@ namespace TouchSocket.JsonRpc
|
||||
/// WebSocketJsonRpcParserPlugin
|
||||
/// </summary>
|
||||
[PluginOption(Singleton = true, NotRegister = false)]
|
||||
public sealed class WebSocketJsonRpcParserPlugin : JsonRpcParserPluginBase, IWebSocketReceivedPlugin<IHttpSocketClient>, IWebSocketHandshakedPlugin<IHttpSocketClient>
|
||||
public sealed class WebSocketJsonRpcParserPlugin : JsonRpcParserPluginBase
|
||||
{
|
||||
/// <summary>
|
||||
/// WebSocketJsonRpcParserPlugin
|
||||
/// </summary>
|
||||
/// <param name="container"></param>
|
||||
public WebSocketJsonRpcParserPlugin(IContainer container) : base(container)
|
||||
/// <param name="pluginsManager"></param>
|
||||
public WebSocketJsonRpcParserPlugin(IContainer container, IPluginsManager pluginsManager) : base(container)
|
||||
{
|
||||
pluginsManager.Add<IHttpSocketClient, HttpContextEventArgs>(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), this.OnWebSocketHandshaked);
|
||||
|
||||
pluginsManager.Add<IHttpSocketClient, WSDataFrameEventArgs>(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this.OnWebSocketReceived);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -25,33 +29,6 @@ namespace TouchSocket.JsonRpc
|
||||
/// </summary>
|
||||
public Func<IHttpSocketClient, HttpContext, Task<bool>> AllowJsonRpc { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task OnWebSocketHandshaked(IHttpSocketClient client, HttpContextEventArgs e)
|
||||
{
|
||||
if (this.AllowJsonRpc != null)
|
||||
{
|
||||
if (await this.AllowJsonRpc.Invoke(client, e.Context))
|
||||
{
|
||||
client.SetJsonRpc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task OnWebSocketReceived(IHttpSocketClient client, WSDataFrameEventArgs e)
|
||||
{
|
||||
if (e.DataFrame.Opcode == WSDataType.Text && client.GetJsonRpc())
|
||||
{
|
||||
var jsonRpcStr = e.DataFrame.ToText();
|
||||
e.Handled = true;
|
||||
this.ThisInvoke(new WebSocketJsonRpcCallContext(client, jsonRpcStr));
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.InvokeNext();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 经过判断是否标识当前的客户端为JsonRpc
|
||||
/// </summary>
|
||||
@@ -82,32 +59,72 @@ namespace TouchSocket.JsonRpc
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var responseByteBlock = new ByteBlock())
|
||||
{
|
||||
object jobject;
|
||||
JsonRpcResponseBase response;
|
||||
if (error == null)
|
||||
{
|
||||
jobject = new JsonRpcSuccessResponse
|
||||
response = new JsonRpcSuccessResponse
|
||||
{
|
||||
result = result,
|
||||
id = callContext.JsonRpcContext.Id
|
||||
Result = result,
|
||||
Id = callContext.JsonRpcContext.Id
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
jobject = new JsonRpcErrorResponse
|
||||
response = new JsonRpcErrorResponse
|
||||
{
|
||||
error = error,
|
||||
id = callContext.JsonRpcContext.Id
|
||||
Error = error,
|
||||
Id = callContext.JsonRpcContext.Id
|
||||
};
|
||||
}
|
||||
|
||||
((IHttpSocketClient)callContext.Caller).SendWithWS(jobject.ToJsonString());
|
||||
}
|
||||
var str = JsonRpcUtility.ToJsonRpcResponseString(response);
|
||||
((IHttpSocketClient)callContext.Caller).SendWithWS(str);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnWebSocketHandshaked(IHttpSocketClient client, HttpContextEventArgs e)
|
||||
{
|
||||
if (this.AllowJsonRpc != null)
|
||||
{
|
||||
if (await this.AllowJsonRpc.Invoke(client, e.Context))
|
||||
{
|
||||
client.SetIsJsonRpc();
|
||||
}
|
||||
}
|
||||
|
||||
await e.InvokeNext();
|
||||
}
|
||||
|
||||
private Task OnWebSocketReceived(IHttpSocketClient client, WSDataFrameEventArgs e)
|
||||
{
|
||||
if (e.DataFrame.Opcode == WSDataType.Text && client.GetIsJsonRpc())
|
||||
{
|
||||
var jsonRpcStr = e.DataFrame.ToText();
|
||||
if (jsonRpcStr.IsNullOrEmpty())
|
||||
{
|
||||
return e.InvokeNext();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
|
||||
if (client.TryGetValue(JsonRpcClientExtension.JsonRpcActionClientProperty, out var actionClient)
|
||||
&& !JsonRpcUtility.IsJsonRpcRequest(jsonRpcStr))
|
||||
{
|
||||
actionClient.InputResponseString(jsonRpcStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.Factory.StartNew(this.ThisInvoke, new WebSocketJsonRpcCallContext(client, jsonRpcStr));
|
||||
}
|
||||
|
||||
return EasyTask.CompletedTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
return e.InvokeNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
src/TouchSocket.JsonRpc/Sign.snk
Normal file
BIN
src/TouchSocket.JsonRpc/Sign.snk
Normal file
Binary file not shown.
@@ -167,7 +167,7 @@ namespace TouchSocket.NamedPipe
|
||||
public Func<ByteBlock, IRequestInfo, bool> OnHandleReceivedData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当客户端完整建立TCP连接。
|
||||
/// 当客户端完整建立Tcp连接。
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected virtual void OnConnected(ConnectedEventArgs e)
|
||||
|
||||
BIN
src/TouchSocket.NamedPipe/Sign.snk
Normal file
BIN
src/TouchSocket.NamedPipe/Sign.snk
Normal file
Binary file not shown.
@@ -16,13 +16,13 @@ using System.Threading.Tasks;
|
||||
namespace TouchSocket.Rpc
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC行为过滤器。
|
||||
/// Rpc行为过滤器。
|
||||
/// </summary>
|
||||
public interface IRpcActionFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// 成功执行Rpc后。
|
||||
/// <para>如果修改<paramref name="invokeResult"/>的InvokeStatus,或Result。则会影响RPC最终结果</para>
|
||||
/// <para>如果修改<paramref name="invokeResult"/>的InvokeStatus,或Result。则会影响Rpc最终结果</para>
|
||||
/// </summary>
|
||||
/// <param name="callContext"></param>
|
||||
/// <param name="parameters"></param>
|
||||
@@ -31,7 +31,7 @@ namespace TouchSocket.Rpc
|
||||
|
||||
/// <summary>
|
||||
/// 执行Rpc遇见异常。
|
||||
/// <para>如果修改<paramref name="invokeResult"/>的InvokeStatus,或Result。则会影响RPC最终结果</para>
|
||||
/// <para>如果修改<paramref name="invokeResult"/>的InvokeStatus,或Result。则会影响Rpc最终结果</para>
|
||||
/// </summary>
|
||||
/// <param name="callContext"></param>
|
||||
/// <param name="parameters"></param>
|
||||
@@ -41,7 +41,7 @@ namespace TouchSocket.Rpc
|
||||
|
||||
/// <summary>
|
||||
/// 在执行Rpc之前。
|
||||
/// <para>当<paramref name="invokeResult"/>的InvokeStatus不为<see cref="InvokeStatus.Ready"/>。则不会执行RPC</para>
|
||||
/// <para>当<paramref name="invokeResult"/>的InvokeStatus不为<see cref="InvokeStatus.Ready"/>。则不会执行Rpc</para>
|
||||
/// <para>同时,当<paramref name="invokeResult"/>的InvokeStatus为<see cref="InvokeStatus.Success"/>。会直接返回结果</para>
|
||||
/// </summary>
|
||||
/// <param name="callContext"></param>
|
||||
|
||||
@@ -726,7 +726,7 @@ namespace TouchSocket.Rpc
|
||||
}
|
||||
else
|
||||
{
|
||||
return !this.InvokeKey.IsNullOrEmpty() ? this.InvokeKey : $"{methodInstance.ServerType.FullName}.{methodInstance.Name}".ToLower();
|
||||
return !this.InvokeKey.IsNullOrEmpty() ? this.InvokeKey : $"{methodInstance.ServerFromType.FullName}.{methodInstance.Name}".ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace TouchSocket.Rpc
|
||||
internal static readonly List<Assembly> m_ignoreAssemblies = new List<Assembly>();
|
||||
internal static readonly List<Type> m_ignoreTypes = new List<Type>();
|
||||
internal static readonly Dictionary<Type, string> m_proxyType = new Dictionary<Type, string>();
|
||||
|
||||
private const BindingFlags m_methodFlags = BindingFlags.Default | BindingFlags.Instance | BindingFlags.Public;
|
||||
|
||||
/// <summary>
|
||||
@@ -381,6 +382,53 @@ namespace TouchSocket.Rpc
|
||||
return serverCellCode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取函数唯一Id
|
||||
/// </summary>
|
||||
/// <param name="method"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetMethodId(MethodInfo method)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
stringBuilder.Append(method.GetName());
|
||||
foreach (var item in method.GetParameters())
|
||||
{
|
||||
stringBuilder.Append(item.ParameterType.FullName);
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取Method
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="methods"></param>
|
||||
public static void GetMethodInfos(Type type, ref Dictionary<string, MethodInfo> methods)
|
||||
{
|
||||
foreach (var item in type.GetInterfaces())
|
||||
{
|
||||
GetMethodInfos(item, ref methods);
|
||||
}
|
||||
foreach (var method in type.GetMethods(m_methodFlags))
|
||||
{
|
||||
if (method.IsGenericMethod)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (methods.ContainsKey(GetMethodId(method)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var attributes = method.GetCustomAttributes<RpcAttribute>(true);
|
||||
if (attributes.Any())
|
||||
{
|
||||
methods.Add(GetMethodId(method), method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从类型获取函数实例
|
||||
/// </summary>
|
||||
@@ -412,10 +460,7 @@ namespace TouchSocket.Rpc
|
||||
var instances = new List<MethodInstance>();
|
||||
|
||||
var fromMethodInfos = new Dictionary<string, MethodInfo>();
|
||||
GetMethodInfos(serverFromType, ref fromMethodInfos);
|
||||
|
||||
var toMethodInfos = new Dictionary<string, MethodInfo>();
|
||||
GetMethodInfos(serverToType, ref toMethodInfos);
|
||||
GetMethodInfos(serverToType, ref fromMethodInfos);
|
||||
|
||||
foreach (var method in fromMethodInfos.Values)
|
||||
{
|
||||
@@ -424,84 +469,9 @@ namespace TouchSocket.Rpc
|
||||
continue;
|
||||
}
|
||||
var attributes = method.GetCustomAttributes<RpcAttribute>(true);
|
||||
if (attributes.Count() > 0)
|
||||
if (attributes.Any())
|
||||
{
|
||||
var methodInstance = new MethodInstance(method, serverToType)
|
||||
{
|
||||
ServerType = serverFromType,
|
||||
IsEnable = true,
|
||||
Parameters = method.GetParameters()
|
||||
};
|
||||
if (!toMethodInfos.TryGetValue(GetMethodId(method), out var toMethod))
|
||||
{
|
||||
throw new InvalidOperationException($"没有找到方法{method.Name}的实现");
|
||||
}
|
||||
|
||||
var actionFilters = new List<IRpcActionFilter>();
|
||||
|
||||
foreach (var item in method.GetCustomAttributes(true))
|
||||
{
|
||||
if (item is IRpcActionFilter filter)
|
||||
{
|
||||
actionFilters.Add(filter);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in serverFromType.GetCustomAttributes(true))
|
||||
{
|
||||
if (item is IRpcActionFilter filter)
|
||||
{
|
||||
actionFilters.Add(filter);
|
||||
}
|
||||
}
|
||||
|
||||
if (serverFromType != serverToType)
|
||||
{
|
||||
foreach (var item in toMethod.GetCustomAttributes(true))
|
||||
{
|
||||
if (item is IRpcActionFilter filter)
|
||||
{
|
||||
actionFilters.Add(filter);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in serverToType.GetCustomAttributes(true))
|
||||
{
|
||||
if (item is IRpcActionFilter filter)
|
||||
{
|
||||
actionFilters.Add(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (actionFilters.Count > 0)
|
||||
{
|
||||
methodInstance.Filters = actionFilters.ToArray();
|
||||
}
|
||||
foreach (var item in attributes)
|
||||
{
|
||||
methodInstance.MethodFlags |= item.MethodFlags;
|
||||
}
|
||||
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
|
||||
{
|
||||
if (methodInstance.Parameters.Length == 0 || !typeof(ICallContext).IsAssignableFrom(methodInstance.Parameters[0].ParameterType))
|
||||
{
|
||||
throw new RpcException($"函数:{method},标识包含{MethodFlags.IncludeCallContext}时,必须包含{nameof(ICallContext)}或其派生类参数,且为第一参数。");
|
||||
}
|
||||
}
|
||||
var names = new List<string>();
|
||||
foreach (var parameterInfo in methodInstance.Parameters)
|
||||
{
|
||||
names.Add(parameterInfo.Name);
|
||||
}
|
||||
methodInstance.ParameterNames = names.ToArray();
|
||||
var parameters = method.GetParameters();
|
||||
var types = new List<Type>();
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
types.Add(parameter.ParameterType.GetRefOutType());
|
||||
}
|
||||
methodInstance.ParameterTypes = types.ToArray();
|
||||
instances.Add(methodInstance);
|
||||
instances.Add(new MethodInstance(method,serverFromType,serverToType));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,35 +508,5 @@ namespace TouchSocket.Rpc
|
||||
{
|
||||
return m_proxyType.TryGetValue(type, out className);
|
||||
}
|
||||
|
||||
private static string GetMethodId(MethodInfo method)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
stringBuilder.Append(method.Name);
|
||||
foreach (var item in method.GetParameters())
|
||||
{
|
||||
stringBuilder.Append(item.ParameterType.FullName);
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
private static void GetMethodInfos(Type type, ref Dictionary<string, MethodInfo> infos)
|
||||
{
|
||||
if (type.IsInterface)
|
||||
{
|
||||
foreach (var item in type.GetInterfaces())
|
||||
{
|
||||
GetMethodInfos(item, ref infos);
|
||||
}
|
||||
}
|
||||
foreach (var item in type.GetMethods(m_methodFlags))
|
||||
{
|
||||
if (!infos.ContainsKey(GetMethodId(item)))
|
||||
{
|
||||
infos.Add(GetMethodId(item), item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -30,70 +31,151 @@ namespace TouchSocket.Rpc
|
||||
/// 实例化一个Rpc调用函数,并在方法声明的类上操作
|
||||
/// </summary>
|
||||
/// <param name="methodInfo"></param>
|
||||
public MethodInstance(MethodInfo methodInfo) : this(methodInfo, methodInfo.DeclaringType)
|
||||
public MethodInstance(MethodInfo methodInfo) : this(methodInfo, methodInfo.DeclaringType, methodInfo.DeclaringType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实例化一个Rpc调用函数,并在指定类上操作
|
||||
/// </summary>
|
||||
/// <param name="methodInfo"></param>
|
||||
/// <param name="serverType"></param>
|
||||
public MethodInstance(MethodInfo methodInfo, Type serverType) : base(methodInfo, false)
|
||||
/// <param name="method"></param>
|
||||
/// <param name="serverFromType"></param>
|
||||
/// <param name="serverToType"></param>
|
||||
public MethodInstance(MethodInfo method,Type serverFromType, Type serverToType) : base(method, false)
|
||||
{
|
||||
var name = $"{serverType.Name}{methodInfo.Name}Func";
|
||||
var property = serverType.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Static);
|
||||
this.ServerFromType = serverFromType;
|
||||
this.ServerToType = serverToType;
|
||||
|
||||
this.Parameters = method.GetParameters();
|
||||
|
||||
var name = $"{serverToType.Name}{method.Name}Func";
|
||||
var property = serverToType.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Static);
|
||||
if (property == null)
|
||||
{
|
||||
if (GlobalEnvironment.DynamicBuilderType == DynamicBuilderType.IL)
|
||||
{
|
||||
this.m_invoker = this.CreateILInvoker(methodInfo);
|
||||
this.m_invoker = this.CreateILInvoker(method);
|
||||
}
|
||||
else if (GlobalEnvironment.DynamicBuilderType == DynamicBuilderType.Expression)
|
||||
{
|
||||
this.m_invoker = this.CreateExpressionInvoker(methodInfo);
|
||||
this.m_invoker = this.CreateExpressionInvoker(method);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_invoker = (Func<object, object[], object>)property.GetValue(null);
|
||||
}
|
||||
|
||||
var fromMethodInfos = new Dictionary<string, MethodInfo>();
|
||||
CodeGenerator.GetMethodInfos(ServerFromType, ref fromMethodInfos);
|
||||
|
||||
var toMethodInfos = new Dictionary<string, MethodInfo>();
|
||||
CodeGenerator.GetMethodInfos(ServerToType, ref toMethodInfos);
|
||||
|
||||
var attributes = method.GetCustomAttributes<RpcAttribute>(true);
|
||||
if (attributes.Any())
|
||||
{
|
||||
if (!toMethodInfos.TryGetValue(CodeGenerator.GetMethodId(method), out var toMethod))
|
||||
{
|
||||
throw new InvalidOperationException($"没有找到方法{method.Name}的实现");
|
||||
}
|
||||
|
||||
var actionFilters = new List<IRpcActionFilter>();
|
||||
|
||||
foreach (var item in method.GetCustomAttributes(true))
|
||||
{
|
||||
if (item is IRpcActionFilter filter)
|
||||
{
|
||||
actionFilters.Add(filter);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in ServerFromType.GetCustomAttributes(true))
|
||||
{
|
||||
if (item is IRpcActionFilter filter)
|
||||
{
|
||||
actionFilters.Add(filter);
|
||||
}
|
||||
}
|
||||
|
||||
if (ServerFromType != ServerToType)
|
||||
{
|
||||
foreach (var item in toMethod.GetCustomAttributes(true))
|
||||
{
|
||||
if (item is IRpcActionFilter filter)
|
||||
{
|
||||
actionFilters.Add(filter);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in ServerToType.GetCustomAttributes(true))
|
||||
{
|
||||
if (item is IRpcActionFilter filter)
|
||||
{
|
||||
actionFilters.Add(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (actionFilters.Count > 0)
|
||||
{
|
||||
this.Filters = actionFilters.ToArray();
|
||||
}
|
||||
foreach (var item in attributes)
|
||||
{
|
||||
this.MethodFlags |= item.MethodFlags;
|
||||
}
|
||||
if (this.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
|
||||
{
|
||||
if (this.Parameters.Length == 0 || !typeof(ICallContext).IsAssignableFrom(this.Parameters[0].ParameterType))
|
||||
{
|
||||
throw new RpcException($"函数:{method},标识包含{MethodFlags.IncludeCallContext}时,必须包含{nameof(ICallContext)}或其派生类参数,且为第一参数。");
|
||||
}
|
||||
}
|
||||
var names = new List<string>();
|
||||
foreach (var parameterInfo in this.Parameters)
|
||||
{
|
||||
names.Add(parameterInfo.Name);
|
||||
}
|
||||
this.ParameterNames = names.ToArray();
|
||||
var parameters = method.GetParameters();
|
||||
var types = new List<Type>();
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
types.Add(parameter.ParameterType.GetRefOutType());
|
||||
}
|
||||
this.ParameterTypes = types.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 筛选器
|
||||
/// </summary>
|
||||
public IRpcActionFilter[] Filters { get; set; }
|
||||
public IRpcActionFilter[] Filters { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否可用
|
||||
/// </summary>
|
||||
public bool IsEnable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为单例
|
||||
/// </summary>
|
||||
public bool IsSingleton { get; internal set; }
|
||||
public bool IsEnable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 函数标识
|
||||
/// </summary>
|
||||
public MethodFlags MethodFlags { get; internal set; }
|
||||
public MethodFlags MethodFlags { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数名集合
|
||||
/// </summary>
|
||||
public string[] ParameterNames { get; internal set; }
|
||||
public string[] ParameterNames { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数集合
|
||||
/// </summary>
|
||||
public ParameterInfo[] Parameters { get; internal set; }
|
||||
public ParameterInfo[] Parameters { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数类型集合,已处理out及ref,无参数时为空集合,
|
||||
/// </summary>
|
||||
public Type[] ParameterTypes { get; internal set; }
|
||||
public Type[] ParameterTypes { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Rpc属性集合
|
||||
@@ -112,6 +194,11 @@ namespace TouchSocket.Rpc
|
||||
/// </summary>
|
||||
public IRpcServerFactory ServerFactory { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 注册类型
|
||||
/// </summary>
|
||||
public Type ServerFromType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Rpc服务属性集合
|
||||
/// </summary>
|
||||
@@ -119,7 +206,7 @@ namespace TouchSocket.Rpc
|
||||
{
|
||||
get
|
||||
{
|
||||
this.m_serverRpcAttributes ??= this.ServerType.GetCustomAttributes<RpcAttribute>(true).ToArray();
|
||||
this.m_serverRpcAttributes ??= this.ServerFromType.GetCustomAttributes<RpcAttribute>(true).ToArray();
|
||||
return this.m_serverRpcAttributes;
|
||||
}
|
||||
}
|
||||
@@ -127,7 +214,7 @@ namespace TouchSocket.Rpc
|
||||
/// <summary>
|
||||
/// 实例类型
|
||||
/// </summary>
|
||||
public Type ServerType { get; internal set; }
|
||||
public Type ServerToType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型属性标签
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace TouchSocket.Rpc
|
||||
{
|
||||
try
|
||||
{
|
||||
return (IRpcServer)this.m_container.Resolve(callContext.MethodInstance.ServerType);
|
||||
return (IRpcServer)this.m_container.Resolve(callContext.MethodInstance.ServerFromType);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
|
||||
@@ -464,8 +464,6 @@ namespace TouchSocket.Rpc
|
||||
var methodInstances = CodeGenerator.GetMethodInstances(serverFromType, rpcServer.GetType());
|
||||
foreach (var item in methodInstances)
|
||||
{
|
||||
item.IsSingleton = true;
|
||||
//item.ServerFactory = new RpcServerFactory(this.Container);
|
||||
item.ServerFactory = this.Container.Resolve<IRpcServerFactory>() ?? throw new ArgumentNullException($"{nameof(IRpcServerFactory)}");
|
||||
}
|
||||
this.m_serverTypes.TryAdd(serverFromType, new List<MethodInstance>(methodInstances));
|
||||
@@ -503,21 +501,18 @@ namespace TouchSocket.Rpc
|
||||
}
|
||||
}
|
||||
|
||||
bool singleton;
|
||||
|
||||
if (typeof(ITransientRpcServer).IsAssignableFrom(serverFromType))
|
||||
{
|
||||
singleton = false;
|
||||
this.Container.RegisterTransient(serverFromType, serverToType);
|
||||
}
|
||||
else
|
||||
{
|
||||
singleton = true;
|
||||
this.Container.RegisterSingleton(serverFromType, serverToType);
|
||||
}
|
||||
var methodInstances = CodeGenerator.GetMethodInstances(serverFromType, serverToType);
|
||||
foreach (var item in methodInstances)
|
||||
{
|
||||
item.IsSingleton = singleton;
|
||||
item.ServerFactory = this.Container.Resolve<IRpcServerFactory>() ?? throw new ArgumentNullException($"{nameof(IRpcServerFactory)}");
|
||||
}
|
||||
|
||||
|
||||
@@ -20,64 +20,40 @@ namespace TouchSocket.Rpc
|
||||
[Flags]
|
||||
public enum CodeGeneratorFlag
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成同步代码(源代码生成无效)
|
||||
/// </summary>
|
||||
[Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)]
|
||||
Sync = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 生成异步代码(源代码生成无效)
|
||||
/// </summary>
|
||||
[Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)]
|
||||
Async = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 生成扩展同步代码
|
||||
/// </summary>
|
||||
ExtensionSync = 4,
|
||||
ExtensionSync =1,
|
||||
|
||||
/// <summary>
|
||||
/// 生成扩展异步代码
|
||||
/// </summary>
|
||||
ExtensionAsync = 8,
|
||||
|
||||
/// <summary>
|
||||
/// 包含接口(源代码生成无效)
|
||||
/// </summary>
|
||||
[Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)]
|
||||
IncludeInterface = 16,
|
||||
|
||||
/// <summary>
|
||||
/// 包含实例(源代码生成无效)
|
||||
/// </summary>
|
||||
[Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)]
|
||||
IncludeInstance = 32,
|
||||
ExtensionAsync = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 包含扩展(源代码生成无效)
|
||||
/// </summary>
|
||||
[Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)]
|
||||
IncludeExtension = 64,
|
||||
IncludeExtension = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 生成实例类同步代码(源代码生成无效)
|
||||
/// </summary>
|
||||
InstanceSync = 128,
|
||||
InstanceSync = 8,
|
||||
|
||||
/// <summary>
|
||||
/// 生成实例类异步代码(源代码生成无效)
|
||||
/// </summary>
|
||||
InstanceAsync = 256,
|
||||
InstanceAsync = 16,
|
||||
|
||||
/// <summary>
|
||||
/// 生成接口同步代码
|
||||
/// </summary>
|
||||
InterfaceSync = 512,
|
||||
InterfaceSync = 32,
|
||||
|
||||
/// <summary>
|
||||
/// 生成接口异步代码
|
||||
/// </summary>
|
||||
InterfaceAsync = 1024,
|
||||
InterfaceAsync = 64,
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,6 @@ namespace TouchSocket.Rpc
|
||||
/// <param name="callContext"></param>
|
||||
/// <param name="ps"></param>
|
||||
/// <returns></returns>
|
||||
public IRpcServer Create(ICallContext callContext, object[] ps);
|
||||
IRpcServer Create(ICallContext callContext, object[] ps);
|
||||
}
|
||||
}
|
||||
BIN
src/TouchSocket.Rpc/Sign.snk
Normal file
BIN
src/TouchSocket.Rpc/Sign.snk
Normal file
Binary file not shown.
@@ -1,7 +1,5 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace TouchSocket
|
||||
{
|
||||
@@ -21,5 +19,54 @@ namespace TouchSocket
|
||||
|
||||
return IsInheritFrom(typeSymbol.BaseType, baseType);
|
||||
}
|
||||
|
||||
public static string RenameCamelCase(this string str)
|
||||
{
|
||||
var firstChar = str[0];
|
||||
|
||||
if (firstChar == char.ToLowerInvariant(firstChar))
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
var name = str.ToCharArray();
|
||||
name[0] = char.ToLowerInvariant(firstChar);
|
||||
|
||||
return new string(name);
|
||||
}
|
||||
|
||||
|
||||
public static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol attribute)
|
||||
{
|
||||
foreach (var attr in symbol.GetAttributes())
|
||||
{
|
||||
var attrClass = attr.AttributeClass;
|
||||
if (attrClass != null && attrClass.ToDisplayString()==attribute.ToDisplayString())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool HasAttribute(this ISymbol symbol, string attribute,out AttributeData attributeData)
|
||||
{
|
||||
foreach (var attr in symbol.GetAttributes())
|
||||
{
|
||||
var attrClass = attr.AttributeClass;
|
||||
if (attrClass != null && attrClass.ToDisplayString()==attribute)
|
||||
{
|
||||
attributeData = attr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
attributeData = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool HasFlags(int value, int flag)
|
||||
{
|
||||
return (value & flag) == flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
151
src/TouchSocket.SourceGenerator/Container/ContainerAttribute.cs
Normal file
151
src/TouchSocket.SourceGenerator/Container/ContainerAttribute.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Text;
|
||||
|
||||
//namespace TouchSocket.Core
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// 源生成容器特性
|
||||
// /// </summary>
|
||||
// internal class GeneratorContainerAttribute : Attribute
|
||||
// {
|
||||
// }
|
||||
|
||||
// internal class BaseInjectAttribute : Attribute
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// 注册类型
|
||||
// /// </summary>
|
||||
// public Type FromType { get; set; }
|
||||
|
||||
// /// <summary>
|
||||
// /// 实例类型
|
||||
// /// </summary>
|
||||
// public Type ToType { get; set; }
|
||||
|
||||
// /// <summary>
|
||||
// /// 注册额外键
|
||||
// /// </summary>
|
||||
// public string Key { get; set; }
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 自动注入为单例。
|
||||
// /// </summary>
|
||||
// [AttributeUsage(AttributeTargets.Class| AttributeTargets.Interface, AllowMultiple = true)]
|
||||
// internal class AutoInjectForSingletonAttribute : BaseInjectAttribute
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 自动注入为瞬时。
|
||||
// /// </summary>
|
||||
// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true)]
|
||||
// internal class AutoInjectForTransientAttribute : BaseInjectAttribute
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 添加单例注入。
|
||||
// /// <para>
|
||||
// /// 该标签仅添加在继承<see cref="ManualContainer"/>的容器上时有用。
|
||||
// /// </para>
|
||||
// /// </summary>
|
||||
// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
||||
// internal class AddSingletonInjectAttribute : BaseInjectAttribute
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// 添加单例注入。
|
||||
// /// <para>
|
||||
// /// 该标签仅添加在继承<see cref="ManualContainer"/>的容器上时有用。
|
||||
// /// </para>
|
||||
// /// </summary>
|
||||
// /// <param name="fromType">注册类型</param>
|
||||
// /// <param name="toType">实例类型</param>
|
||||
// /// <param name="key">注册额外键</param>
|
||||
// public AddSingletonInjectAttribute(Type fromType, Type toType, string key)
|
||||
// {
|
||||
// this.FromType = fromType;
|
||||
// this.ToType = toType;
|
||||
// this.Key = key;
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 添加单例注入。
|
||||
// /// <para>
|
||||
// /// 该标签仅添加在继承<see cref="ManualContainer"/>的容器上时有用。
|
||||
// /// </para>
|
||||
// /// </summary>
|
||||
// /// <param name="type">注册类型与实例类型一致</param>
|
||||
// public AddSingletonInjectAttribute(Type type) : this(type, type, null)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 添加单例注入。
|
||||
// /// <para>
|
||||
// /// 该标签仅添加在继承<see cref="ManualContainer"/>的容器上时有用。
|
||||
// /// </para>
|
||||
// /// </summary>
|
||||
// /// <param name="fromType">注册类型</param>
|
||||
// /// <param name="toType">实例类型</param>
|
||||
// public AddSingletonInjectAttribute(Type fromType, Type toType) : this(fromType, toType, null)
|
||||
// {
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 添加瞬态注入。
|
||||
// /// <para>
|
||||
// /// 该标签仅添加在继承<see cref="ManualContainer"/>的容器上时有用。
|
||||
// /// </para>
|
||||
// /// </summary>
|
||||
// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
||||
// internal class AddTransientInjectAttribute : BaseInjectAttribute
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// 添加瞬态注入。
|
||||
// /// <para>
|
||||
// /// 该标签仅添加在继承<see cref="ManualContainer"/>的容器上时有用。
|
||||
// /// </para>
|
||||
// /// </summary>
|
||||
// /// <param name="fromType">注册类型</param>
|
||||
// /// <param name="toType">实例类型</param>
|
||||
// /// <param name="key">注册额外键</param>
|
||||
// public AddTransientInjectAttribute(Type fromType, Type toType, string key)
|
||||
// {
|
||||
// this.FromType = fromType;
|
||||
// this.ToType = toType;
|
||||
// this.Key = key;
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 添加瞬态注入。
|
||||
// /// <para>
|
||||
// /// 该标签仅添加在继承<see cref="ManualContainer"/>的容器上时有用。
|
||||
// /// </para>
|
||||
// /// </summary>
|
||||
// /// <param name="type">注册类型与实例类型一致</param>
|
||||
// public AddTransientInjectAttribute(Type type) : this(type, type, null)
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 添加瞬态注入。
|
||||
// /// <para>
|
||||
// /// 该标签仅添加在继承<see cref="ManualContainer"/>的容器上时有用。
|
||||
// /// </para>
|
||||
// /// </summary>
|
||||
// /// <param name="fromType">注册类型</param>
|
||||
// /// <param name="toType">实例类型</param>
|
||||
// public AddTransientInjectAttribute(Type fromType, Type toType) : this(fromType, toType, null)
|
||||
// {
|
||||
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,539 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace TouchSocket
|
||||
{
|
||||
internal sealed class ContainerCodeBuilder
|
||||
{
|
||||
private const string AddSingletonInjectAttributeString = "TouchSocket.Core.AddSingletonInjectAttribute";
|
||||
private const string AddTransientInjectAttributeString = "TouchSocket.Core.AddTransientInjectAttribute";
|
||||
private const string DependencyInjectAttributeString = "TouchSocket.Core.DependencyInjectAttribute";
|
||||
private const string DependencyTypeAttributeString = "TouchSocket.Core.DependencyTypeAttribute";
|
||||
private readonly IEnumerable<InjectDescription> m_autoInjectForSingletonClassTypes;
|
||||
private readonly IEnumerable<InjectDescription> m_autoInjectForTransientClassTypes;
|
||||
private readonly INamedTypeSymbol m_containerClass;
|
||||
|
||||
public ContainerCodeBuilder(INamedTypeSymbol containerClass, IEnumerable<InjectDescription> autoInjectForSingletonClassTypes, IEnumerable<InjectDescription> autoInjectForTransientClassTypes)
|
||||
{
|
||||
this.m_containerClass = containerClass;
|
||||
this.m_autoInjectForSingletonClassTypes = autoInjectForSingletonClassTypes;
|
||||
this.m_autoInjectForTransientClassTypes = autoInjectForTransientClassTypes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 依赖注入类型。
|
||||
/// </summary>
|
||||
[Flags]
|
||||
private enum DependencyType
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
|
||||
Constructor = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 属性
|
||||
/// </summary>
|
||||
Property = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 方法
|
||||
/// </summary>
|
||||
Method = 2
|
||||
}
|
||||
|
||||
public string Prefix { get; set; }
|
||||
|
||||
public IEnumerable<string> Usings
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "using System;";
|
||||
yield return "using System.Diagnostics;";
|
||||
yield return "using TouchSocket.Core;";
|
||||
yield return "using System.Threading.Tasks;";
|
||||
}
|
||||
}
|
||||
|
||||
public string GetFileName()
|
||||
{
|
||||
return this.m_containerClass.ToDisplayString() + "Generator";
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var codeString = new StringBuilder();
|
||||
codeString.AppendLine("/*");
|
||||
codeString.AppendLine("此代码由SourceGenerator工具直接生成,非必要请不要修改此处代码");
|
||||
codeString.AppendLine("*/");
|
||||
codeString.AppendLine("#pragma warning disable");
|
||||
|
||||
foreach (var item in this.Usings)
|
||||
{
|
||||
codeString.AppendLine(item);
|
||||
}
|
||||
|
||||
//Debugger.Launch();
|
||||
|
||||
codeString.AppendLine($"namespace {this.m_containerClass.ContainingNamespace}");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine($"[global::System.CodeDom.Compiler.GeneratedCode(\"TouchSocket.SourceGenerator\",\"{Assembly.GetExecutingAssembly().GetName().Version.ToString()}\")]");
|
||||
codeString.AppendLine($"partial class {this.m_containerClass.Name}");
|
||||
codeString.AppendLine("{");
|
||||
var singletonInjectDescriptions = this.FindSingletonInjects().ToList();
|
||||
singletonInjectDescriptions.AddRange(this.m_autoInjectForSingletonClassTypes);
|
||||
|
||||
var transientInjectDescriptions = this.FindTransientInjects().ToList();
|
||||
transientInjectDescriptions.AddRange(this.m_autoInjectForTransientClassTypes);
|
||||
|
||||
this.BuildConstructor(codeString);
|
||||
this.BuildContainerInit(codeString, singletonInjectDescriptions);
|
||||
foreach (var item in singletonInjectDescriptions)
|
||||
{
|
||||
this.BuildSingletonInjectField(codeString, item);
|
||||
this.BuildInject(codeString, item);
|
||||
}
|
||||
|
||||
foreach (var item in transientInjectDescriptions)
|
||||
{
|
||||
this.BuildInject(codeString, item);
|
||||
}
|
||||
|
||||
this.BuildPrivateTryResolve(codeString, singletonInjectDescriptions, transientInjectDescriptions);
|
||||
this.TryBuildInvokeTryResolve(codeString);
|
||||
codeString.AppendLine("}");
|
||||
codeString.AppendLine("}");
|
||||
|
||||
// System.Diagnostics.Debugger.Launch();
|
||||
return codeString.ToString();
|
||||
}
|
||||
|
||||
public bool TryToSourceText(out SourceText sourceText)
|
||||
{
|
||||
var code = this.ToString();
|
||||
if (string.IsNullOrEmpty(code))
|
||||
{
|
||||
sourceText = null;
|
||||
return false;
|
||||
}
|
||||
sourceText = SourceText.From(code, Encoding.UTF8);
|
||||
return true;
|
||||
}
|
||||
|
||||
#region TryResolve
|
||||
|
||||
private void BuildPrivateTryResolve(StringBuilder codeString, List<InjectDescription> singletonDescriptions, List<InjectDescription> transientInjectDescriptions)
|
||||
{
|
||||
codeString.AppendLine($"private bool PrivateTryResolve(Type fromType, out object instance, object[] ps = null, string key = \"\")");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine("string typeKey;");
|
||||
codeString.AppendLine("if(key.IsNullOrEmpty())");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine("typeKey = fromType.FullName;");
|
||||
codeString.AppendLine("}");
|
||||
codeString.AppendLine("else");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine("typeKey = $\"{fromType.FullName}{key}\";");
|
||||
codeString.AppendLine("}");
|
||||
codeString.AppendLine("switch (typeKey)");
|
||||
codeString.AppendLine("{");
|
||||
foreach (var item in singletonDescriptions)
|
||||
{
|
||||
codeString.AppendLine($"case \"{item.From.ToDisplayString()}{item.Key}\":");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine($"instance = this.{this.GetFieldName(item)}.Value;");
|
||||
codeString.AppendLine("return true;");
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
|
||||
foreach (var item in transientInjectDescriptions)
|
||||
{
|
||||
codeString.AppendLine($"case \"{item.From.ToDisplayString()}{item.Key}\":");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine($"instance = this.{this.GetMethodName(item)}();");
|
||||
codeString.AppendLine("return true;");
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
|
||||
codeString.AppendLine("default:");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine("instance = default;");
|
||||
codeString.AppendLine("return false;");
|
||||
codeString.AppendLine("}");
|
||||
codeString.AppendLine("}");
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
|
||||
#endregion TryResolve
|
||||
|
||||
private void BuildConstructor(StringBuilder codeString)
|
||||
{
|
||||
codeString.AppendLine($"public {this.m_containerClass.Name}()");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine("this.ContainerInit();");
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
|
||||
private void BuildContainerInit(StringBuilder codeString, List<InjectDescription> descriptions)
|
||||
{
|
||||
if (descriptions.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
codeString.AppendLine($"private void ContainerInit()");
|
||||
codeString.AppendLine("{");
|
||||
foreach (var item in descriptions)
|
||||
{
|
||||
codeString.AppendLine($"this.{this.GetFieldName(item)} = new Lazy<{item.From.ToDisplayString()}>(this.{GetMethodName(item)});");
|
||||
}
|
||||
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
|
||||
#region SingletonInject
|
||||
|
||||
private void BuildSingletonInjectField(StringBuilder codeString, InjectDescription description)
|
||||
{
|
||||
codeString.AppendLine($"private Lazy<{description.From.ToDisplayString()}> {GetFieldName(description)};");
|
||||
}
|
||||
|
||||
private IMethodSymbol GetConstructor(INamedTypeSymbol namedTypeSymbol)
|
||||
{
|
||||
var methodSymbol = namedTypeSymbol.Constructors.FirstOrDefault();
|
||||
foreach (var item in namedTypeSymbol.Constructors)
|
||||
{
|
||||
if (item.HasAttribute(DependencyInjectAttributeString, out _))
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
if (item.Parameters.Length > methodSymbol.Parameters.Length)
|
||||
{
|
||||
methodSymbol = item;
|
||||
}
|
||||
}
|
||||
|
||||
return methodSymbol;
|
||||
}
|
||||
|
||||
private string GetFieldName(InjectDescription description)
|
||||
{
|
||||
if (string.IsNullOrEmpty(description.Key))
|
||||
{
|
||||
return $"m_{description.From.Name.RenameCamelCase()}";
|
||||
}
|
||||
return $"m_{description.From.Name.RenameCamelCase()}_{description.Key}";
|
||||
}
|
||||
|
||||
private string GetMethodName(InjectDescription description)
|
||||
{
|
||||
if (string.IsNullOrEmpty(description.Key))
|
||||
{
|
||||
return $"Create{description.From.Name}";
|
||||
}
|
||||
return $"Create{description.From.Name}_{description.Key}";
|
||||
}
|
||||
|
||||
#endregion SingletonInject
|
||||
|
||||
private void BuildInject(StringBuilder codeString, InjectDescription description)
|
||||
{
|
||||
codeString.AppendLine($"private {description.From.ToDisplayString()} {this.GetMethodName(description)}()");
|
||||
codeString.Append('{');
|
||||
|
||||
var constructor = this.GetConstructor(description.To);
|
||||
if (constructor == default || constructor.Parameters.Length == 0)
|
||||
{
|
||||
codeString.Append($"var obj= new {description.To.ToDisplayString()}();");
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.Append($"var obj= new {description.To.ToDisplayString()}(");
|
||||
var ps = new List<string>();
|
||||
foreach (var item in constructor.Parameters)
|
||||
{
|
||||
ps.Add($"({item.Type.ToDisplayString()})this.Resolve(typeof({item.Type.ToDisplayString()}))");
|
||||
}
|
||||
codeString.Append(string.Join(",", ps));
|
||||
codeString.Append($");");
|
||||
}
|
||||
var dependencyType = this.GetDependencyType(description.To);
|
||||
if (dependencyType.HasFlag(DependencyType.Property))
|
||||
{
|
||||
var properties = this.GetInjectProperties(description.To);
|
||||
foreach (var item in properties)
|
||||
{
|
||||
if (string.IsNullOrEmpty(item.Key))
|
||||
{
|
||||
codeString.Append($"obj.{item.Name}=({item.Type.ToDisplayString()})this.Resolve(typeof({item.Type.ToDisplayString()}));");
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.Append($"obj.{item.Name}=({item.Type.ToDisplayString()})this.Resolve(typeof({item.Type.ToDisplayString()}),key:{item.Key});");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dependencyType.HasFlag(DependencyType.Method))
|
||||
{
|
||||
foreach (var item in this.GetInjectMethods(description.To))
|
||||
{
|
||||
codeString.Append($"obj.{item.Name}(");
|
||||
var parameters = new List<string>();
|
||||
foreach (var item2 in item.Types)
|
||||
{
|
||||
if (string.IsNullOrEmpty(item2.Key))
|
||||
{
|
||||
parameters.Add($"({item2.Type.ToDisplayString()})this.Resolve(typeof({item2.Type.ToDisplayString()}))");
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters.Add($"({item2.Type.ToDisplayString()})this.Resolve(typeof({item2.Type.ToDisplayString()}),key:{item2.Key})");
|
||||
}
|
||||
}
|
||||
codeString.Append(string.Join(",", parameters));
|
||||
codeString.Append($");");
|
||||
}
|
||||
}
|
||||
|
||||
codeString.Append("return obj;");
|
||||
codeString.Append('}');
|
||||
}
|
||||
|
||||
private IEnumerable<InjectDescription> FindSingletonInjects()
|
||||
{
|
||||
return this.m_containerClass.GetAttributes()
|
||||
.Where(a => a.AttributeClass?.ToDisplayString() == AddSingletonInjectAttributeString)
|
||||
.Select(a =>
|
||||
{
|
||||
var list = a.ConstructorArguments;
|
||||
|
||||
INamedTypeSymbol fromTypedConstant = null;
|
||||
INamedTypeSymbol toTypedConstant = null;
|
||||
string key = string.Empty;
|
||||
if (list.Length == 1)
|
||||
{
|
||||
fromTypedConstant = (INamedTypeSymbol)list[0].Value;
|
||||
toTypedConstant = (INamedTypeSymbol)list[0].Value;
|
||||
}
|
||||
else if (list.Length == 2)
|
||||
{
|
||||
fromTypedConstant = (INamedTypeSymbol)list[0].Value;
|
||||
toTypedConstant = (INamedTypeSymbol)list[1].Value;
|
||||
}
|
||||
else if (list.Length == 3)
|
||||
{
|
||||
fromTypedConstant = (INamedTypeSymbol)list[0].Value;
|
||||
toTypedConstant = (INamedTypeSymbol)list[1].Value;
|
||||
key = list[2].Value.ToString();
|
||||
}
|
||||
|
||||
return new InjectDescription()
|
||||
{
|
||||
From = fromTypedConstant,
|
||||
To = toTypedConstant,
|
||||
Key = key
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private IEnumerable<InjectDescription> FindTransientInjects()
|
||||
{
|
||||
return this.m_containerClass.GetAttributes()
|
||||
.Where(a => a.AttributeClass?.ToDisplayString() == AddTransientInjectAttributeString)
|
||||
.Select(a =>
|
||||
{
|
||||
var list = a.ConstructorArguments;
|
||||
|
||||
INamedTypeSymbol fromTypedConstant = null;
|
||||
INamedTypeSymbol toTypedConstant = null;
|
||||
string key = string.Empty;
|
||||
if (list.Length == 1)
|
||||
{
|
||||
fromTypedConstant = (INamedTypeSymbol)list[0].Value;
|
||||
toTypedConstant = (INamedTypeSymbol)list[0].Value;
|
||||
}
|
||||
else if (list.Length == 2)
|
||||
{
|
||||
fromTypedConstant = (INamedTypeSymbol)list[0].Value;
|
||||
toTypedConstant = (INamedTypeSymbol)list[1].Value;
|
||||
}
|
||||
else if (list.Length == 3)
|
||||
{
|
||||
fromTypedConstant = (INamedTypeSymbol)list[0].Value;
|
||||
toTypedConstant = (INamedTypeSymbol)list[1].Value;
|
||||
key = list[2].Value.ToString();
|
||||
}
|
||||
|
||||
return new InjectDescription()
|
||||
{
|
||||
From = fromTypedConstant,
|
||||
To = toTypedConstant,
|
||||
Key = key
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private DependencyType GetDependencyType(INamedTypeSymbol namedType)
|
||||
{
|
||||
if (namedType.HasAttribute(DependencyTypeAttributeString, out var attributeData))
|
||||
{
|
||||
return (DependencyType)attributeData.ConstructorArguments[0].Value;
|
||||
}
|
||||
return DependencyType.Constructor | DependencyType.Property | DependencyType.Method;
|
||||
}
|
||||
|
||||
private IEnumerable<InjectMethodDescription> GetInjectMethods(INamedTypeSymbol namedType)
|
||||
{
|
||||
//Debugger.Launch();
|
||||
var members = namedType.GetMembers();
|
||||
|
||||
var descriptions = new List<InjectMethodDescription>();
|
||||
foreach (var item in members)
|
||||
{
|
||||
if (item is not IMethodSymbol method)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.DeclaredAccessibility != Accessibility.Public)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (method.MethodKind != MethodKind.Ordinary)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (method.HasAttribute(DependencyInjectAttributeString, out var attributeData))
|
||||
{
|
||||
var description = new InjectMethodDescription()
|
||||
{
|
||||
Name = method.Name
|
||||
};
|
||||
|
||||
description.Types = method.Parameters
|
||||
.Select(a =>
|
||||
{
|
||||
var des = new InjectPropertyDescription();
|
||||
|
||||
if (a.HasAttribute(DependencyInjectAttributeString, out var attributeData))
|
||||
{
|
||||
if (attributeData.ConstructorArguments.Length == 0)
|
||||
{
|
||||
des.Type = a.Type;
|
||||
}
|
||||
else if (attributeData.ConstructorArguments.Length == 1 && attributeData.ConstructorArguments[0].Kind == TypedConstantKind.Primitive)
|
||||
{
|
||||
des.Type = a.Type;
|
||||
des.Key = attributeData.ConstructorArguments[0].Value.ToString();
|
||||
}
|
||||
else if (attributeData.ConstructorArguments.Length == 1 && attributeData.ConstructorArguments[0].Kind == TypedConstantKind.Type)
|
||||
{
|
||||
des.Type = (ITypeSymbol)attributeData.ConstructorArguments[0].Value;
|
||||
}
|
||||
else if (attributeData.ConstructorArguments.Length == 2)
|
||||
{
|
||||
des.Type = (ITypeSymbol)attributeData.ConstructorArguments[0].Value;
|
||||
des.Key = attributeData.ConstructorArguments[1].Value.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
des.Type = a.Type;
|
||||
}
|
||||
return des;
|
||||
});
|
||||
descriptions.Add(description);
|
||||
}
|
||||
}
|
||||
return descriptions;
|
||||
}
|
||||
|
||||
private IEnumerable<InjectPropertyDescription> GetInjectProperties(INamedTypeSymbol namedType)
|
||||
{
|
||||
// Debugger.Launch();
|
||||
var members = namedType.GetMembers();
|
||||
|
||||
var descriptions = new List<InjectPropertyDescription>();
|
||||
foreach (var item in members)
|
||||
{
|
||||
if (item is not IPropertySymbol property)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (property.IsWriteOnly)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (property.HasAttribute(DependencyInjectAttributeString, out var attributeData))
|
||||
{
|
||||
var description = new InjectPropertyDescription()
|
||||
{
|
||||
Name = property.Name
|
||||
};
|
||||
|
||||
if (attributeData.ConstructorArguments.Length == 0)
|
||||
{
|
||||
description.Type = property.Type;
|
||||
}
|
||||
else if (attributeData.ConstructorArguments.Length == 1 && attributeData.ConstructorArguments[0].Kind == TypedConstantKind.Primitive)
|
||||
{
|
||||
description.Type = property.Type;
|
||||
description.Key = attributeData.ConstructorArguments[0].Value.ToString();
|
||||
}
|
||||
else if (attributeData.ConstructorArguments.Length == 1 && attributeData.ConstructorArguments[0].Kind == TypedConstantKind.Type)
|
||||
{
|
||||
description.Type = (ITypeSymbol)attributeData.ConstructorArguments[0].Value;
|
||||
}
|
||||
else if (attributeData.ConstructorArguments.Length == 2)
|
||||
{
|
||||
description.Type = (ITypeSymbol)attributeData.ConstructorArguments[0].Value;
|
||||
description.Key = attributeData.ConstructorArguments[1].Value.ToString();
|
||||
}
|
||||
descriptions.Add(description);
|
||||
}
|
||||
}
|
||||
return descriptions;
|
||||
}
|
||||
|
||||
private bool HasOverrideMethod()
|
||||
{
|
||||
return this.m_containerClass
|
||||
.GetMembers()
|
||||
.OfType<IMethodSymbol>()
|
||||
.Any(m =>
|
||||
{
|
||||
if (m.Name == "TryResolve" && m.IsOverride && m.Parameters.Length == 4)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private void TryBuildInvokeTryResolve(StringBuilder stringBuilder)
|
||||
{
|
||||
if (this.HasOverrideMethod())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
stringBuilder.AppendLine("protected override bool TryResolve(Type fromType, out object instance, object[] ps = null, string key = \"\")");
|
||||
stringBuilder.AppendLine("{");
|
||||
stringBuilder.AppendLine("if (base.TryResolve(fromType, out instance, ps, key))");
|
||||
stringBuilder.AppendLine("{");
|
||||
stringBuilder.AppendLine("return true;");
|
||||
stringBuilder.AppendLine("}");
|
||||
stringBuilder.AppendLine("return this.PrivateTryResolve(fromType, out instance, ps, key);");
|
||||
stringBuilder.AppendLine("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace TouchSocket
|
||||
{
|
||||
|
||||
[Generator]
|
||||
public class ContainerSourceGenerator : ISourceGenerator
|
||||
{
|
||||
private string m_generatorAttribute = @"
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace TouchSocket.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 源生成容器特性
|
||||
/// </summary>
|
||||
internal class GeneratorContainerAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
internal class BaseInjectAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册类型
|
||||
/// </summary>
|
||||
public Type FromType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实例类型
|
||||
/// </summary>
|
||||
public Type ToType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 注册额外键
|
||||
/// </summary>
|
||||
public string Key { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动注入为单例。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class| AttributeTargets.Interface, AllowMultiple = true)]
|
||||
internal class AutoInjectForSingletonAttribute : BaseInjectAttribute
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动注入为瞬时。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true)]
|
||||
internal class AutoInjectForTransientAttribute : BaseInjectAttribute
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加单例注入。
|
||||
/// <para>
|
||||
/// 该标签仅添加在继承<see cref=""ManualContainer""/>的容器上时有用。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
||||
internal class AddSingletonInjectAttribute : BaseInjectAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加单例注入。
|
||||
/// <para>
|
||||
/// 该标签仅添加在继承<see cref=""ManualContainer""/>的容器上时有用。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name=""fromType"">注册类型</param>
|
||||
/// <param name=""toType"">实例类型</param>
|
||||
/// <param name=""key"">注册额外键</param>
|
||||
public AddSingletonInjectAttribute(Type fromType, Type toType, string key)
|
||||
{
|
||||
this.FromType = fromType;
|
||||
this.ToType = toType;
|
||||
this.Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加单例注入。
|
||||
/// <para>
|
||||
/// 该标签仅添加在继承<see cref=""ManualContainer""/>的容器上时有用。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name=""type"">注册类型与实例类型一致</param>
|
||||
public AddSingletonInjectAttribute(Type type) : this(type, type, null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加单例注入。
|
||||
/// <para>
|
||||
/// 该标签仅添加在继承<see cref=""ManualContainer""/>的容器上时有用。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name=""fromType"">注册类型</param>
|
||||
/// <param name=""toType"">实例类型</param>
|
||||
public AddSingletonInjectAttribute(Type fromType, Type toType) : this(fromType, toType, null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加瞬态注入。
|
||||
/// <para>
|
||||
/// 该标签仅添加在继承<see cref=""ManualContainer""/>的容器上时有用。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
||||
internal class AddTransientInjectAttribute : BaseInjectAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加瞬态注入。
|
||||
/// <para>
|
||||
/// 该标签仅添加在继承<see cref=""ManualContainer""/>的容器上时有用。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name=""fromType"">注册类型</param>
|
||||
/// <param name=""toType"">实例类型</param>
|
||||
/// <param name=""key"">注册额外键</param>
|
||||
public AddTransientInjectAttribute(Type fromType, Type toType, string key)
|
||||
{
|
||||
this.FromType = fromType;
|
||||
this.ToType = toType;
|
||||
this.Key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加瞬态注入。
|
||||
/// <para>
|
||||
/// 该标签仅添加在继承<see cref=""ManualContainer""/>的容器上时有用。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name=""type"">注册类型与实例类型一致</param>
|
||||
public AddTransientInjectAttribute(Type type) : this(type, type, null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加瞬态注入。
|
||||
/// <para>
|
||||
/// 该标签仅添加在继承<see cref=""ManualContainer""/>的容器上时有用。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name=""fromType"">注册类型</param>
|
||||
/// <param name=""toType"">实例类型</param>
|
||||
public AddTransientInjectAttribute(Type fromType, Type toType) : this(fromType, toType, null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
";
|
||||
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterForPostInitialization(a =>
|
||||
{
|
||||
a.AddSource(nameof(this.m_generatorAttribute), this.m_generatorAttribute);
|
||||
});
|
||||
context.RegisterForSyntaxNotifications(() => new ContainerSyntaxReceiver());
|
||||
}
|
||||
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
var s = context.Compilation.GetMetadataReference(context.Compilation.Assembly);
|
||||
|
||||
if (context.SyntaxReceiver is ContainerSyntaxReceiver receiver)
|
||||
{
|
||||
var types1 = receiver.GetAutoInjectForSingletonClassTypes(context.Compilation);
|
||||
var types2 = receiver.GetAutoInjectForTransientClassTypes(context.Compilation);
|
||||
|
||||
var builders = receiver
|
||||
.GetContainerClassTypes(context.Compilation)
|
||||
.Select(i => new ContainerCodeBuilder(i,types1, types2))
|
||||
.Distinct();
|
||||
//Debugger.Launch();
|
||||
|
||||
foreach (var builder in builders)
|
||||
{
|
||||
if (builder.TryToSourceText(out var sourceText))
|
||||
{
|
||||
var tree = CSharpSyntaxTree.ParseText(sourceText);
|
||||
var root = tree.GetRoot().NormalizeWhitespace();
|
||||
var ret = root.ToFullString();
|
||||
context.AddSource($"{builder.GetFileName()}.g.cs", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace TouchSocket
|
||||
{
|
||||
|
||||
internal sealed class ContainerSyntaxReceiver : ISyntaxReceiver
|
||||
{
|
||||
public const string GeneratorContainerAttributeTypeName = "TouchSocket.Core.GeneratorContainerAttribute";
|
||||
public const string AutoInjectForSingletonAttributeTypeName = "TouchSocket.Core.AutoInjectForSingletonAttribute";
|
||||
public const string AutoInjectForTransientAttributeTypeName = "TouchSocket.Core.AutoInjectForTransientAttribute";
|
||||
public const string ManualContainerTypeName = "TouchSocket.Core.ManualContainer";
|
||||
|
||||
public static INamedTypeSymbol GeneratorContainerAttribute { get; private set; }
|
||||
public static INamedTypeSymbol AutoInjectForSingletonAttribute { get; private set; }
|
||||
public static INamedTypeSymbol AutoInjectForTransientAttribute { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 接口列表
|
||||
/// </summary>
|
||||
private readonly List<TypeDeclarationSyntax> m_classSyntaxList = new List<TypeDeclarationSyntax>();
|
||||
|
||||
/// <summary>
|
||||
/// 访问语法树
|
||||
/// </summary>
|
||||
/// <param name="syntaxNode"></param>
|
||||
void ISyntaxReceiver.OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||
{
|
||||
if (syntaxNode is ClassDeclarationSyntax syntax)
|
||||
{
|
||||
this.m_classSyntaxList.Add(syntax);
|
||||
}
|
||||
else if (syntaxNode is InterfaceDeclarationSyntax @interface)
|
||||
{
|
||||
this.m_classSyntaxList.Add(@interface);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有Container符号
|
||||
/// </summary>
|
||||
/// <param name="compilation"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<INamedTypeSymbol> GetContainerClassTypes(Compilation compilation)
|
||||
{
|
||||
// Debugger.Launch();
|
||||
GeneratorContainerAttribute = compilation.GetTypeByMetadataName(GeneratorContainerAttributeTypeName);
|
||||
if (GeneratorContainerAttribute == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (var classSyntax in this.m_classSyntaxList)
|
||||
{
|
||||
var @class = compilation.GetSemanticModel(classSyntax.SyntaxTree).GetDeclaredSymbol(classSyntax);
|
||||
if (@class != null && IsContainerClass(@class))
|
||||
{
|
||||
yield return @class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<InjectDescription> GetAutoInjectForSingletonClassTypes(Compilation compilation)
|
||||
{
|
||||
// Debugger.Launch();
|
||||
AutoInjectForSingletonAttribute = compilation.GetTypeByMetadataName(AutoInjectForSingletonAttributeTypeName);
|
||||
if (AutoInjectForSingletonAttribute == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (var classSyntax in this.m_classSyntaxList)
|
||||
{
|
||||
var @class = compilation.GetSemanticModel(classSyntax.SyntaxTree).GetDeclaredSymbol(classSyntax);
|
||||
if (@class != null && IsAutoInjectForSingletonClass(@class, out var attributeData))
|
||||
{
|
||||
yield return this.Create(@class, attributeData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<InjectDescription> GetAutoInjectForTransientClassTypes(Compilation compilation)
|
||||
{
|
||||
// Debugger.Launch();
|
||||
AutoInjectForTransientAttribute = compilation.GetTypeByMetadataName(AutoInjectForTransientAttributeTypeName);
|
||||
if (AutoInjectForTransientAttribute == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (var classSyntax in this.m_classSyntaxList)
|
||||
{
|
||||
var @class = compilation.GetSemanticModel(classSyntax.SyntaxTree).GetDeclaredSymbol(classSyntax);
|
||||
if (@class != null && IsAutoInjectForTransientClass(@class, out var attributeData))
|
||||
{
|
||||
yield return this.Create(@class, attributeData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private InjectDescription Create(INamedTypeSymbol typeSymbol, AttributeData attributeData)
|
||||
{
|
||||
var dic = attributeData.NamedArguments.ToImmutableDictionary();
|
||||
var description = new InjectDescription();
|
||||
if (dic.TryGetValue("FromType", out var typedConstant))
|
||||
{
|
||||
description.From = (INamedTypeSymbol)typedConstant.Value;
|
||||
}
|
||||
if (dic.TryGetValue("ToType", out typedConstant))
|
||||
{
|
||||
description.To = (INamedTypeSymbol)typedConstant.Value;
|
||||
}
|
||||
if (dic.TryGetValue("Key", out typedConstant))
|
||||
{
|
||||
description.Key = typedConstant.Value.ToString();
|
||||
}
|
||||
description.From ??= typeSymbol;
|
||||
description.To ??= typeSymbol;
|
||||
return description;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否为容器生成
|
||||
/// </summary>
|
||||
/// <param name="class"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsContainerClass(INamedTypeSymbol @class)
|
||||
{
|
||||
if (GeneratorContainerAttribute is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//Debugger.Launch();
|
||||
|
||||
if (!@class.HasAttribute(GeneratorContainerAttributeTypeName, out _))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (@class.IsInheritFrom(ManualContainerTypeName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsAutoInjectForSingletonClass(INamedTypeSymbol @class, out AttributeData attributeData)
|
||||
{
|
||||
if (AutoInjectForSingletonAttribute is null)
|
||||
{
|
||||
attributeData = null;
|
||||
return false;
|
||||
}
|
||||
//Debugger.Launch();
|
||||
|
||||
if (@class.HasAttribute(AutoInjectForSingletonAttributeTypeName, out attributeData))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static bool IsAutoInjectForTransientClass(INamedTypeSymbol @class, out AttributeData attributeData)
|
||||
{
|
||||
if (AutoInjectForTransientAttribute is null)
|
||||
{
|
||||
attributeData = null;
|
||||
return false;
|
||||
}
|
||||
//Debugger.Launch();
|
||||
|
||||
if (@class.HasAttribute(AutoInjectForTransientAttributeTypeName, out attributeData))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace TouchSocket
|
||||
{
|
||||
class InjectDescription
|
||||
{
|
||||
public INamedTypeSymbol From { get; set; }
|
||||
public INamedTypeSymbol To { get; set; }
|
||||
public string Key { get; set; }
|
||||
}
|
||||
class InjectPropertyDescription
|
||||
{
|
||||
public ITypeSymbol Type { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Key { get; set; }
|
||||
}
|
||||
|
||||
class InjectMethodDescription
|
||||
{
|
||||
public IEnumerable<InjectPropertyDescription> Types { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
//using Microsoft.CodeAnalysis;
|
||||
//using Microsoft.CodeAnalysis.CSharp;
|
||||
//using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
//using Microsoft.CodeAnalysis.Text;
|
||||
|
||||
//namespace TouchSocket.SourceGenerator.Rpc
|
||||
//{
|
||||
// [Generator]
|
||||
// public class AutoNotifyGenerator : ISourceGenerator
|
||||
// {
|
||||
// private const string attributeText = @"
|
||||
//using System;
|
||||
//namespace AutoNotify
|
||||
//{
|
||||
// [AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
|
||||
// [System.Diagnostics.Conditional(""AutoNotifyGenerator_DEBUG"")]
|
||||
// public sealed class AutoNotifyAttribute : Attribute
|
||||
// {
|
||||
// public AutoNotifyAttribute()
|
||||
// {
|
||||
// }
|
||||
// public string PropertyName { get; set; }
|
||||
// }
|
||||
//}
|
||||
//";
|
||||
|
||||
|
||||
// public void Initialize(GeneratorInitializationContext context)
|
||||
// {
|
||||
// // Register the attribute source
|
||||
// context.RegisterForPostInitialization((i) => i.AddSource("AutoNotifyAttribute.g.cs", attributeText));
|
||||
|
||||
// // Register a syntax receiver that will be created for each generation pass
|
||||
// context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
|
||||
// }
|
||||
|
||||
// public void Execute(GeneratorExecutionContext context)
|
||||
// {
|
||||
// // retrieve the populated receiver
|
||||
// if (!(context.SyntaxContextReceiver is SyntaxReceiver receiver))
|
||||
// return;
|
||||
|
||||
// // get the added attribute, and INotifyPropertyChanged
|
||||
// INamedTypeSymbol attributeSymbol = context.Compilation.GetTypeByMetadataName("AutoNotify.AutoNotifyAttribute");
|
||||
// INamedTypeSymbol notifySymbol = context.Compilation.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanged");
|
||||
|
||||
// // group the fields by class, and generate the source
|
||||
// foreach (IGrouping<INamedTypeSymbol, IFieldSymbol> group in receiver.Fields.GroupBy<IFieldSymbol, INamedTypeSymbol>(f => f.ContainingType, SymbolEqualityComparer.Default))
|
||||
// {
|
||||
// string classSource = ProcessClass(group.Key, group.ToList(), attributeSymbol, notifySymbol, context);
|
||||
// context.AddSource($"{group.Key.Name}_autoNotify.g.cs", SourceText.From(classSource, Encoding.UTF8));
|
||||
// }
|
||||
// }
|
||||
|
||||
// private string ProcessClass(INamedTypeSymbol classSymbol, List<IFieldSymbol> fields, ISymbol attributeSymbol, ISymbol notifySymbol, GeneratorExecutionContext context)
|
||||
// {
|
||||
// if (!classSymbol.ContainingSymbol.Equals(classSymbol.ContainingNamespace, SymbolEqualityComparer.Default))
|
||||
// {
|
||||
// return null; //TODO: issue a diagnostic that it must be top level
|
||||
// }
|
||||
|
||||
// string namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
|
||||
|
||||
// // begin building the generated source
|
||||
// StringBuilder source = new StringBuilder($@"
|
||||
//namespace {namespaceName}
|
||||
//{{
|
||||
// public partial class {classSymbol.Name} : {notifySymbol.ToDisplayString()}
|
||||
// {{
|
||||
//");
|
||||
|
||||
// // if the class doesn't implement INotifyPropertyChanged already, add it
|
||||
// if (!classSymbol.Interfaces.Contains(notifySymbol, SymbolEqualityComparer.Default))
|
||||
// {
|
||||
// source.Append("public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;");
|
||||
// }
|
||||
|
||||
// // create properties for each field
|
||||
// foreach (IFieldSymbol fieldSymbol in fields)
|
||||
// {
|
||||
// ProcessField(source, fieldSymbol, attributeSymbol);
|
||||
// }
|
||||
|
||||
// source.Append("} }");
|
||||
// return source.ToString();
|
||||
// }
|
||||
|
||||
// private void ProcessField(StringBuilder source, IFieldSymbol fieldSymbol, ISymbol attributeSymbol)
|
||||
// {
|
||||
// // get the name and type of the field
|
||||
// string fieldName = fieldSymbol.Name;
|
||||
// ITypeSymbol fieldType = fieldSymbol.Type;
|
||||
|
||||
// // get the AutoNotify attribute from the field, and any associated data
|
||||
// AttributeData attributeData = fieldSymbol.GetAttributes().Single(ad => ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.Default));
|
||||
// TypedConstant overridenNameOpt = attributeData.NamedArguments.SingleOrDefault(kvp => kvp.Key == "PropertyName").Value;
|
||||
|
||||
// string propertyName = chooseName(fieldName, overridenNameOpt);
|
||||
// if (propertyName.Length == 0 || propertyName == fieldName)
|
||||
// {
|
||||
// //TODO: issue a diagnostic that we can't process this field
|
||||
// return;
|
||||
// }
|
||||
|
||||
// source.Append($@"
|
||||
//public {fieldType} {propertyName}
|
||||
//{{
|
||||
// get
|
||||
// {{
|
||||
// return this.{fieldName};
|
||||
// }}
|
||||
|
||||
// set
|
||||
// {{
|
||||
// this.{fieldName} = value;
|
||||
// this.PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(nameof({propertyName})));
|
||||
// }}
|
||||
//}}
|
||||
|
||||
//");
|
||||
|
||||
// string chooseName(string fieldName, TypedConstant overridenNameOpt)
|
||||
// {
|
||||
// if (!overridenNameOpt.IsNull)
|
||||
// {
|
||||
// return overridenNameOpt.Value.ToString();
|
||||
// }
|
||||
|
||||
// fieldName = fieldName.TrimStart('_');
|
||||
// if (fieldName.Length == 0)
|
||||
// return string.Empty;
|
||||
|
||||
// if (fieldName.Length == 1)
|
||||
// return fieldName.ToUpper();
|
||||
|
||||
// return fieldName.Substring(0, 1).ToUpper() + fieldName.Substring(1);
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// Created on demand before each generation pass
|
||||
// /// </summary>
|
||||
// class SyntaxReceiver : ISyntaxContextReceiver
|
||||
// {
|
||||
// public List<IFieldSymbol> Fields { get; } = new List<IFieldSymbol>();
|
||||
|
||||
// /// <summary>
|
||||
// /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation
|
||||
// /// </summary>
|
||||
// public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
|
||||
// {
|
||||
// // any field with at least one attribute is a candidate for property generation
|
||||
// if (context.Node is FieldDeclarationSyntax fieldDeclarationSyntax
|
||||
// && fieldDeclarationSyntax.AttributeLists.Count > 0)
|
||||
// {
|
||||
// foreach (VariableDeclaratorSyntax variable in fieldDeclarationSyntax.Declaration.Variables)
|
||||
// {
|
||||
// // Get the symbol being declared by the field, and keep it if its annotated
|
||||
// IFieldSymbol fieldSymbol = context.SemanticModel.GetDeclaredSymbol(variable) as IFieldSymbol;
|
||||
// if (fieldSymbol.GetAttributes().Any(ad => ad.AttributeClass.ToDisplayString() == "AutoNotify.AutoNotifyAttribute"))
|
||||
// {
|
||||
// Fields.Add(fieldSymbol);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,51 +0,0 @@
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Text;
|
||||
//using Microsoft.CodeAnalysis;
|
||||
//using Microsoft.CodeAnalysis.Text;
|
||||
|
||||
//namespace SourceGeneratorSamples
|
||||
//{
|
||||
// [Generator]
|
||||
// public class HelloWorldGenerator : ISourceGenerator
|
||||
// {
|
||||
// public void Execute(GeneratorExecutionContext context)
|
||||
// {
|
||||
// // begin creating the source we'll inject into the users compilation
|
||||
// StringBuilder sourceBuilder = new StringBuilder(@"
|
||||
//using System;
|
||||
//namespace HelloWorldGenerated
|
||||
//{
|
||||
// public static class HelloWorld
|
||||
// {
|
||||
// public static void SayHello()
|
||||
// {
|
||||
// Console.WriteLine(""Hello from generated code!"");
|
||||
// Console.WriteLine(""The following syntax trees existed in the compilation that created this program:"");
|
||||
//");
|
||||
|
||||
// // using the context, get a list of syntax trees in the users compilation
|
||||
// IEnumerable<SyntaxTree> syntaxTrees = context.Compilation.SyntaxTrees;
|
||||
|
||||
// // add the filepath of each tree to the class we're building
|
||||
// foreach (SyntaxTree tree in syntaxTrees)
|
||||
// {
|
||||
// sourceBuilder.AppendLine($@"Console.WriteLine(@"" - {tree.FilePath}"");");
|
||||
// }
|
||||
|
||||
// // finish creating the source to inject
|
||||
// sourceBuilder.Append(@"
|
||||
// }
|
||||
// }
|
||||
//}");
|
||||
|
||||
// // inject the created source into the users compilation
|
||||
// context.AddSource("helloWorldGenerated.g.cs", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
|
||||
// }
|
||||
|
||||
// public void Initialize(GeneratorInitializationContext context)
|
||||
// {
|
||||
// // No initialization required
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,225 +0,0 @@
|
||||
//using Microsoft.CodeAnalysis;
|
||||
//using Microsoft.CodeAnalysis.Text;
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
|
||||
//namespace TouchSocket.SourceGenerator.Rpc.Http
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// HttpApi代码构建器
|
||||
// /// </summary>
|
||||
// sealed class HttpApiCodeBuilder : IEquatable<HttpApiCodeBuilder>
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// 接口符号
|
||||
// /// </summary>
|
||||
// private readonly INamedTypeSymbol httpApi;
|
||||
|
||||
// /// <summary>
|
||||
// /// 拦截器变量名
|
||||
// /// </summary>
|
||||
// private readonly string apiInterceptorFieldName = $"apiInterceptor_{(uint)Environment.TickCount}";
|
||||
|
||||
// /// <summary>
|
||||
// /// action执行器变量名
|
||||
// /// </summary>
|
||||
// private readonly string actionInvokersFieldName = $"actionInvokers_{(uint)Environment.TickCount}";
|
||||
|
||||
// /// <summary>
|
||||
// /// using
|
||||
// /// </summary>
|
||||
// public IEnumerable<string> Usings
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// yield return "using System;";
|
||||
// yield return "using System.Diagnostics;";
|
||||
// yield return "using WebApiClientCore;";
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 命名空间
|
||||
// /// </summary>
|
||||
// public string Namespace => $"{this.httpApi.ContainingNamespace}.SourceGenerators";
|
||||
|
||||
// /// <summary>
|
||||
// /// 基础接口名
|
||||
// /// </summary>
|
||||
// public string BaseInterfaceName => this.httpApi.ToDisplayString();
|
||||
|
||||
// /// <summary>
|
||||
// /// 代理的接口类型名称
|
||||
// /// </summary>
|
||||
// public string HttpApiTypeName => this.httpApi.IsGenericType ? this.httpApi.ConstructUnboundGenericType().ToDisplayString() : this.httpApi.ToDisplayString();
|
||||
|
||||
// /// <summary>
|
||||
// /// 类名
|
||||
// /// </summary>
|
||||
// public string ClassName => "_" + this.httpApi.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
|
||||
|
||||
// /// <summary>
|
||||
// /// 构造器名
|
||||
// /// </summary>
|
||||
// public string CtorName => "_" + this.httpApi.Name;
|
||||
|
||||
// /// <summary>
|
||||
// /// HttpApi代码构建器
|
||||
// /// </summary>
|
||||
// /// <param name="httpApi"></param>
|
||||
// public HttpApiCodeBuilder(INamedTypeSymbol httpApi)
|
||||
// {
|
||||
// this.httpApi = httpApi;
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 转换为SourceText
|
||||
// /// </summary>
|
||||
// /// <returns></returns>
|
||||
// public SourceText ToSourceText()
|
||||
// {
|
||||
// var code = this.ToString();
|
||||
// return SourceText.From(code, Encoding.UTF8);
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 转换为字符串
|
||||
// /// </summary>
|
||||
// /// <returns></returns>
|
||||
// public override string ToString()
|
||||
// {
|
||||
// var builder = new StringBuilder();
|
||||
// foreach (var item in this.Usings)
|
||||
// {
|
||||
// builder.AppendLine(item);
|
||||
// }
|
||||
// builder.AppendLine($"namespace {this.Namespace}");
|
||||
// builder.AppendLine("{");
|
||||
// builder.AppendLine($"\t[HttpApiProxyClass(typeof({this.HttpApiTypeName}))]");
|
||||
// builder.AppendLine($"\tclass {this.ClassName}:{this.BaseInterfaceName}");
|
||||
// builder.AppendLine("\t{");
|
||||
|
||||
// builder.AppendLine("\t\t[DebuggerBrowsable(DebuggerBrowsableState.Never)]");
|
||||
// builder.AppendLine($"\t\tprivate readonly IHttpApiInterceptor {this.apiInterceptorFieldName};");
|
||||
|
||||
// builder.AppendLine("\t\t[DebuggerBrowsable(DebuggerBrowsableState.Never)]");
|
||||
// builder.AppendLine($"\t\tprivate readonly ApiActionInvoker[] {this.actionInvokersFieldName};");
|
||||
|
||||
// builder.AppendLine($"\t\tpublic {this.CtorName}(IHttpApiInterceptor apiInterceptor,ApiActionInvoker[] actionInvokers)");
|
||||
// builder.AppendLine("\t\t{");
|
||||
// builder.AppendLine($"\t\t\tthis.{this.apiInterceptorFieldName} = apiInterceptor;");
|
||||
// builder.AppendLine($"\t\t\tthis.{this.actionInvokersFieldName} = actionInvokers;");
|
||||
// builder.AppendLine("\t\t}");
|
||||
|
||||
// var index = 0;
|
||||
// foreach (var method in FindApiMethods(this.httpApi))
|
||||
// {
|
||||
// var methodCode = this.BuildMethod(method, index);
|
||||
// builder.AppendLine(methodCode);
|
||||
// index += 1;
|
||||
// }
|
||||
|
||||
// builder.AppendLine("\t}");
|
||||
// builder.AppendLine("}");
|
||||
|
||||
// // System.Diagnostics.Debugger.Launch();
|
||||
// return builder.ToString();
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 查找接口类型及其继承的接口的所有方法
|
||||
// /// </summary>
|
||||
// /// <param name="httpApi">接口</param>
|
||||
// /// <returns></returns>
|
||||
// private static IEnumerable<IMethodSymbol> FindApiMethods(INamedTypeSymbol httpApi)
|
||||
// {
|
||||
// return httpApi
|
||||
// .AllInterfaces
|
||||
// .Append(httpApi)
|
||||
// .OrderBy(item => item.Name)
|
||||
// .SelectMany(item => item.GetMembers())
|
||||
// .OfType<IMethodSymbol>();
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 构建方法
|
||||
// /// </summary>
|
||||
// /// <param name="method"></param>
|
||||
// /// <param name="index"></param>
|
||||
// /// <returns></returns>
|
||||
// private string BuildMethod(IMethodSymbol method, int index)
|
||||
// {
|
||||
// if (method.GetAttributes().Length == 0)
|
||||
// {
|
||||
// return string.Empty;
|
||||
// }
|
||||
|
||||
// //method.Parameters[0].
|
||||
|
||||
// var attributeData = method.GetAttributes()[0];
|
||||
// //string ss = attributeData.ConstructorArguments[0].Kind.ToDisplayString();
|
||||
|
||||
// //Type type = Type.GetType(ss);
|
||||
|
||||
// var builder = new StringBuilder();
|
||||
// var parametersString = string.Join(",", method.Parameters.Select(item => $"{item.Type} {item.Name}"));
|
||||
// var parameterNamesString = string.Join(",", method.Parameters.Select(item => item.Name));
|
||||
|
||||
// //method.
|
||||
// builder.AppendLine($"\t\tpublic {method.ReturnType} {method.Name}( {parametersString} )");
|
||||
// builder.AppendLine("\t\t{");
|
||||
// builder.AppendLine($"\t\t\treturn ({method.ReturnType})this.{this.apiInterceptorFieldName}.Intercept(this.{this.actionInvokersFieldName}[{index}], new object[] {{ {parameterNamesString} }});");
|
||||
// builder.AppendLine("\t\t}");
|
||||
// return builder.ToString();
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 获取扩展函数代码
|
||||
// /// </summary>
|
||||
// /// <param name="method"></param>
|
||||
// /// <param name="attribute"></param>
|
||||
// /// <returns></returns>
|
||||
// public string GetExtensionsMethodProxy(IMethodSymbol method)
|
||||
// {
|
||||
// StringBuilder codeString = new StringBuilder();
|
||||
|
||||
|
||||
// return codeString.ToString();
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 是否与目标相等
|
||||
// /// </summary>
|
||||
// /// <param name="other"></param>
|
||||
// /// <returns></returns>
|
||||
// public bool Equals(HttpApiCodeBuilder other)
|
||||
// {
|
||||
// return this.HttpApiTypeName == other.HttpApiTypeName;
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 是否与目标相等
|
||||
// /// </summary>
|
||||
// /// <param name="obj"></param>
|
||||
// /// <returns></returns>
|
||||
// public override bool Equals(object obj)
|
||||
// {
|
||||
// if (obj is HttpApiCodeBuilder builder)
|
||||
// {
|
||||
// return this.Equals(builder);
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 获取哈希
|
||||
// /// </summary>
|
||||
// /// <returns></returns>
|
||||
// public override int GetHashCode()
|
||||
// {
|
||||
// return this.HttpApiTypeName.GetHashCode();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,46 +0,0 @@
|
||||
//using Microsoft.CodeAnalysis;
|
||||
//using System.Diagnostics;
|
||||
//using System.IO;
|
||||
//using System.Linq;
|
||||
|
||||
//namespace TouchSocket.SourceGenerator.Rpc.Http
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// HttpApi代码生成器
|
||||
// /// </summary>
|
||||
// [Generator]
|
||||
// public class HttpApiSourceGenerator : ISourceGenerator
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// 初始化
|
||||
// /// </summary>
|
||||
// /// <param name="context"></param>
|
||||
// public void Initialize(GeneratorInitializationContext context)
|
||||
// {
|
||||
// context.RegisterForSyntaxNotifications(() => new HttpApiSyntaxReceiver());
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 执行
|
||||
// /// </summary>
|
||||
// /// <param name="context"></param>
|
||||
// public void Execute(GeneratorExecutionContext context)
|
||||
// {
|
||||
// //Debugger.Launch();
|
||||
// var s = context.Compilation.GetMetadataReference(context.Compilation.Assembly);
|
||||
|
||||
// if (context.SyntaxReceiver is HttpApiSyntaxReceiver receiver)
|
||||
// {
|
||||
// var builders = receiver
|
||||
// .GetHttpApiTypes(context.Compilation)
|
||||
// .Select(i => new HttpApiCodeBuilder(i))
|
||||
// .Distinct();
|
||||
|
||||
// foreach (var builder in builders)
|
||||
// {
|
||||
// context.AddSource(builder.HttpApiTypeName, builder.ToSourceText());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,106 +0,0 @@
|
||||
//using Microsoft.CodeAnalysis;
|
||||
//using Microsoft.CodeAnalysis.CSharp;
|
||||
//using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
|
||||
//namespace TouchSocket.SourceGenerator.Rpc.Http
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// httpApi语法接收器
|
||||
// /// </summary>
|
||||
// sealed class HttpApiSyntaxReceiver : ISyntaxReceiver
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// 接口标记名称
|
||||
// /// </summary>
|
||||
// private const string IHttpApiTypeName = "RRQMSocket.RPC.IServerProvider";
|
||||
// private const string IApiAttributeTypeName = "RRQMSocket.RPC.TouchRpc.TouchRpcAttribute";
|
||||
|
||||
// /// <summary>
|
||||
// /// 接口列表
|
||||
// /// </summary>
|
||||
// private readonly List<InterfaceDeclarationSyntax> interfaceSyntaxList = new List<InterfaceDeclarationSyntax>();
|
||||
|
||||
// /// <summary>
|
||||
// /// 访问语法树
|
||||
// /// </summary>
|
||||
// /// <param name="syntaxNode"></param>
|
||||
// void ISyntaxReceiver.OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||
// {
|
||||
// if (syntaxNode is InterfaceDeclarationSyntax syntax)
|
||||
// {
|
||||
// this.interfaceSyntaxList.Add(syntax);
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 获取所有HttpApi符号
|
||||
// /// </summary>
|
||||
// /// <param name="compilation"></param>
|
||||
// /// <returns></returns>
|
||||
// public IEnumerable<INamedTypeSymbol> GetHttpApiTypes(Compilation compilation)
|
||||
// {
|
||||
// var ihttpApi = compilation.GetTypeByMetadataName(IHttpApiTypeName);
|
||||
// if (ihttpApi == null)
|
||||
// {
|
||||
// yield break;
|
||||
// }
|
||||
|
||||
// var iapiAttribute = compilation.GetTypeByMetadataName(IApiAttributeTypeName);
|
||||
// foreach (var interfaceSyntax in this.interfaceSyntaxList)
|
||||
// {
|
||||
// var @interface = compilation.GetSemanticModel(interfaceSyntax.SyntaxTree).GetDeclaredSymbol(interfaceSyntax);
|
||||
// if (@interface != null && IsHttpApiInterface(@interface, ihttpApi, iapiAttribute))
|
||||
// {
|
||||
// yield return @interface;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// /// <summary>
|
||||
// /// 是否为http接口
|
||||
// /// </summary>
|
||||
// /// <param name="interface"></param>
|
||||
// /// <param name="ihttpApi"></param>
|
||||
// /// <param name="iapiAttribute"></param>
|
||||
// /// <returns></returns>
|
||||
// private static bool IsHttpApiInterface(INamedTypeSymbol @interface, INamedTypeSymbol ihttpApi, INamedTypeSymbol iapiAttribute)
|
||||
// {
|
||||
// if (@interface.AllInterfaces.Contains(ihttpApi))
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// if (iapiAttribute == null)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// return @interface.AllInterfaces.Append(@interface).Any(i =>
|
||||
// HasAttribute(i, iapiAttribute) || i.GetMembers().OfType<IMethodSymbol>().Any(m =>
|
||||
// HasAttribute(m, iapiAttribute) || m.Parameters.Any(p => HasAttribute(p, iapiAttribute))));
|
||||
// }
|
||||
|
||||
|
||||
// /// <summary>
|
||||
// /// 返回是否声明指定的特性
|
||||
// /// </summary>
|
||||
// /// <param name="symbol"></param>
|
||||
// /// <param name="attribute"></param>
|
||||
// /// <returns></returns>
|
||||
// private static bool HasAttribute(ISymbol symbol, INamedTypeSymbol attribute)
|
||||
// {
|
||||
// foreach (var attr in symbol.GetAttributes())
|
||||
// {
|
||||
// var attrClass = attr.AttributeClass;
|
||||
// if (attrClass != null && attrClass.AllInterfaces.Contains(attribute))
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,528 +0,0 @@
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Text;
|
||||
//using System.Text.RegularExpressions;
|
||||
//using static System.Console;
|
||||
//using Tokens = System.Collections.Generic.IEnumerable<MathsGenerator.Token>;
|
||||
//using SymTable = System.Collections.Generic.HashSet<string>;
|
||||
//using System.Linq;
|
||||
//using Microsoft.CodeAnalysis;
|
||||
//using System.IO;
|
||||
//using Microsoft.CodeAnalysis.Text;
|
||||
//using System.Diagnostics;
|
||||
|
||||
//#pragma warning disable IdE0008 // Use explicit type
|
||||
|
||||
//namespace MathsGenerator
|
||||
//{
|
||||
// public enum TokenType
|
||||
// {
|
||||
// Number,
|
||||
// Identifier,
|
||||
// Operation,
|
||||
// OpenParens,
|
||||
// CloseParens,
|
||||
// Equal,
|
||||
// EOL,
|
||||
// EOF,
|
||||
// Spaces,
|
||||
// Comma,
|
||||
// Sum,
|
||||
// None
|
||||
// }
|
||||
|
||||
// public struct Token
|
||||
// {
|
||||
// public TokenType Type;
|
||||
// public string Value;
|
||||
// public int Line;
|
||||
// public int Column;
|
||||
// }
|
||||
|
||||
// public static class Lexer
|
||||
// {
|
||||
|
||||
// public static void PrintTokens(IEnumerable<Token> tokens)
|
||||
// {
|
||||
// foreach (var token in tokens)
|
||||
// {
|
||||
// WriteLine($"{token.Line}, {token.Column}, {token.Type}, {token.Value}");
|
||||
// }
|
||||
// }
|
||||
|
||||
// static (TokenType, string)[] tokenStrings = {
|
||||
// (TokenType.EOL, @"(\r\n|\r|\n)"),
|
||||
// (TokenType.Spaces, @"\s+"),
|
||||
// (TokenType.Number, @"[+-]?((\d+\.?\d*)|(\.\d+))"),
|
||||
// (TokenType.Identifier, @"[_a-zA-Z][`'""_a-zA-Z0-9]*"),
|
||||
// (TokenType.Operation, @"[\+\-/\*]"),
|
||||
// (TokenType.OpenParens, @"[([{]"),
|
||||
// (TokenType.CloseParens, @"[)\]}]"),
|
||||
// (TokenType.Equal, @"="),
|
||||
// (TokenType.Comma, @","),
|
||||
// (TokenType.Sum, @"∑")
|
||||
// };
|
||||
|
||||
// static IEnumerable<(TokenType, Regex)> tokenExpressions =
|
||||
// tokenStrings.Select(
|
||||
// t => (t.Item1, new Regex($"^{t.Item2}", RegexOptions.Compiled | RegexOptions.Singleline)));
|
||||
|
||||
// // Can be optimized with spans to avoid so many allocations ...
|
||||
// static public Tokens Tokenize(string source)
|
||||
// {
|
||||
// var currentLine = 1;
|
||||
// var currentColumn = 1;
|
||||
|
||||
// while (source.Length > 0)
|
||||
// {
|
||||
|
||||
// var matchLength = 0;
|
||||
// var tokenType = TokenType.None;
|
||||
// var value = "";
|
||||
|
||||
// foreach (var (type, rule) in tokenExpressions)
|
||||
// {
|
||||
// var match = rule.Match(source);
|
||||
// if (match.Success)
|
||||
// {
|
||||
// matchLength = match.Length;
|
||||
// tokenType = type;
|
||||
// value = match.Value;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (matchLength == 0)
|
||||
// {
|
||||
|
||||
// throw new Exception($"Unrecognized symbol '{source[currentLine - 1]}' at index {currentLine - 1} (line {currentLine}, column {currentColumn}).");
|
||||
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
|
||||
// if (tokenType != TokenType.Spaces)
|
||||
// yield return new Token
|
||||
// {
|
||||
// Type = tokenType,
|
||||
// Value = value,
|
||||
// Line = currentLine,
|
||||
// Column = currentColumn
|
||||
// };
|
||||
|
||||
// currentColumn += matchLength;
|
||||
// if (tokenType == TokenType.EOL)
|
||||
// {
|
||||
// currentLine += 1;
|
||||
// currentColumn = 0;
|
||||
// }
|
||||
|
||||
// source = source.Substring(matchLength);
|
||||
// }
|
||||
// }
|
||||
|
||||
// yield return new Token
|
||||
// {
|
||||
// Type = TokenType.EOF,
|
||||
// Line = currentLine,
|
||||
// Column = currentColumn
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
||||
// /* EBNF for the language
|
||||
// lines = {line} EOF
|
||||
// line = {EOL} identifier [lround args rround] equal expr EOL {EOL}
|
||||
// args = identifier {comma identifier}
|
||||
// expr = [plus|minus] term { (plus|minus) term }
|
||||
// term = factor { (times|divide) factor };
|
||||
// factor = number | var | func | sum | matrix | lround expr rround;
|
||||
// var = identifier;
|
||||
// func = identifier lround expr {comma expr} rround;
|
||||
// sum = ∑ lround identifier comma expr comma expr comma expr rround;
|
||||
// */
|
||||
// public static class Parser
|
||||
// {
|
||||
|
||||
|
||||
// public static string Parse(Tokens tokens)
|
||||
// {
|
||||
// var globalSymbolTable = new SymTable();
|
||||
// var symbolTable = new SymTable();
|
||||
// var buffer = new StringBuilder();
|
||||
|
||||
// var en = tokens.GetEnumerator();
|
||||
// en.MoveNext();
|
||||
|
||||
// buffer = Lines(new Context
|
||||
// {
|
||||
// tokens = en,
|
||||
// globalSymbolTable = globalSymbolTable,
|
||||
// symbolTable = symbolTable,
|
||||
// buffer = buffer
|
||||
// });
|
||||
// return buffer.ToString();
|
||||
|
||||
// }
|
||||
|
||||
// private readonly static string Preamble = @"
|
||||
//using static System.Math;
|
||||
//using static Maths.FormulaHelpers;
|
||||
|
||||
//namespace Maths {
|
||||
|
||||
// public static partial class Formulas {
|
||||
//";
|
||||
// private readonly static string Ending = @"
|
||||
// }
|
||||
//}";
|
||||
|
||||
// private struct Context
|
||||
// {
|
||||
// public IEnumerator<Token> tokens;
|
||||
// public SymTable globalSymbolTable;
|
||||
// public SymTable symbolTable;
|
||||
// public StringBuilder buffer;
|
||||
// }
|
||||
|
||||
// private static StringBuilder Error(Token token, TokenType type, string value = "") =>
|
||||
// throw new Exception($"Expected {type} {(value == "" ? "" : $" with {token.Value}")} at {token.Line},{token.Column} Instead found {token.Type} with value {token.Value}");
|
||||
|
||||
// static HashSet<string> validFunctions =
|
||||
// new HashSet<string>(typeof(System.Math).GetMethods().Select(m => m.Name.ToLower()));
|
||||
|
||||
// static Dictionary<string, string> replacementStrings = new Dictionary<string, string> {
|
||||
// {"'''", "Third" }, {"''", "Second" }, {"'", "Prime"}
|
||||
// };
|
||||
|
||||
// private static StringBuilder EmitIdentifier(Context ctx, Token token)
|
||||
// {
|
||||
// var val = token.Value;
|
||||
|
||||
// if (val == "pi")
|
||||
// {
|
||||
// ctx.buffer.Append("PI"); // Doesn't follow pattern
|
||||
// return ctx.buffer;
|
||||
// }
|
||||
|
||||
// if (validFunctions.Contains(val))
|
||||
// {
|
||||
// ctx.buffer.Append(char.ToUpper(val[0]) + val.Substring(1));
|
||||
// return ctx.buffer;
|
||||
// }
|
||||
|
||||
// string id = token.Value;
|
||||
// if (ctx.globalSymbolTable.Contains(token.Value) ||
|
||||
// ctx.symbolTable.Contains(token.Value))
|
||||
// {
|
||||
// foreach (var r in replacementStrings)
|
||||
// {
|
||||
// id = id.Replace(r.Key, r.Value);
|
||||
// }
|
||||
// return ctx.buffer.Append(id);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// throw new Exception($"{token.Value} not a known identifier or function.");
|
||||
// }
|
||||
// }
|
||||
|
||||
// private static StringBuilder Emit(Context ctx, Token token) => token.Type switch
|
||||
// {
|
||||
// TokenType.EOL => ctx.buffer.Append("\n"),
|
||||
// TokenType.CloseParens => ctx.buffer.Append(')'), // All parens become rounded
|
||||
// TokenType.OpenParens => ctx.buffer.Append('('),
|
||||
// TokenType.Equal => ctx.buffer.Append("=>"),
|
||||
// TokenType.Comma => ctx.buffer.Append(token.Value),
|
||||
|
||||
// // Identifiers are normalized and checked for injection attacks
|
||||
// TokenType.Identifier => EmitIdentifier(ctx, token),
|
||||
// TokenType.Number => ctx.buffer.Append(token.Value),
|
||||
// TokenType.Operation => ctx.buffer.Append(token.Value),
|
||||
// TokenType.Sum => ctx.buffer.Append("MySum"),
|
||||
// _ => Error(token, TokenType.None)
|
||||
// };
|
||||
|
||||
// private static bool Peek(Context ctx, TokenType type, string value = "")
|
||||
// {
|
||||
// var token = ctx.tokens.Current;
|
||||
|
||||
// return (token.Type == type && value == "") ||
|
||||
// (token.Type == type && value == token.Value);
|
||||
// }
|
||||
// private static Token NextToken(Context ctx)
|
||||
// {
|
||||
|
||||
// var token = ctx.tokens.Current;
|
||||
// ctx.tokens.MoveNext();
|
||||
// return token;
|
||||
// }
|
||||
// private static void Consume(Context ctx, TokenType type, string value = "")
|
||||
// {
|
||||
|
||||
// var token = NextToken(ctx);
|
||||
|
||||
// if ((token.Type == type && value == "") ||
|
||||
// (token.Type == type && value == token.Value))
|
||||
// {
|
||||
|
||||
// ctx.buffer.Append(" ");
|
||||
// Emit(ctx, token);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Error(token, type, value);
|
||||
// }
|
||||
// }
|
||||
|
||||
// private static StringBuilder Lines(Context ctx)
|
||||
// {
|
||||
// // lines = {line} EOF
|
||||
|
||||
// ctx.buffer.Append(Preamble);
|
||||
|
||||
// while (!Peek(ctx, TokenType.EOF))
|
||||
// Line(ctx);
|
||||
|
||||
// ctx.buffer.Append(Ending);
|
||||
|
||||
// return ctx.buffer;
|
||||
// }
|
||||
|
||||
// private static void AddGlobalSymbol(Context ctx)
|
||||
// {
|
||||
// var token = ctx.tokens.Current;
|
||||
// if (Peek(ctx, TokenType.Identifier))
|
||||
// {
|
||||
// ctx.globalSymbolTable.Add(token.Value);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Error(token, TokenType.Identifier);
|
||||
// }
|
||||
// }
|
||||
// private static void AddSymbol(Context ctx)
|
||||
// {
|
||||
// var token = ctx.tokens.Current;
|
||||
// if (Peek(ctx, TokenType.Identifier))
|
||||
// {
|
||||
// ctx.symbolTable.Add(token.Value);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Error(token, TokenType.Identifier);
|
||||
// }
|
||||
// }
|
||||
// private static void Line(Context ctx)
|
||||
// {
|
||||
// // line = {EOL} identifier [lround args rround] equal expr EOL {EOL}
|
||||
|
||||
// ctx.symbolTable.Clear();
|
||||
|
||||
// while (Peek(ctx, TokenType.EOL))
|
||||
// Consume(ctx, TokenType.EOL);
|
||||
|
||||
// ctx.buffer.Append("\tpublic static double ");
|
||||
|
||||
// AddGlobalSymbol(ctx);
|
||||
// Consume(ctx, TokenType.Identifier);
|
||||
|
||||
// if (Peek(ctx, TokenType.OpenParens, "("))
|
||||
// {
|
||||
// Consume(ctx, TokenType.OpenParens, "("); // Just round parens
|
||||
// Args(ctx);
|
||||
// Consume(ctx, TokenType.CloseParens, ")");
|
||||
// }
|
||||
|
||||
// Consume(ctx, TokenType.Equal);
|
||||
// Expr(ctx);
|
||||
// ctx.buffer.Append(" ;");
|
||||
|
||||
// Consume(ctx, TokenType.EOL);
|
||||
|
||||
// while (Peek(ctx, TokenType.EOL))
|
||||
// Consume(ctx, TokenType.EOL);
|
||||
// }
|
||||
// private static void Args(Context ctx)
|
||||
// {
|
||||
// // args = identifier {comma identifier}
|
||||
// // It doesn't make sense for a math function to have zero args (I think)
|
||||
|
||||
// ctx.buffer.Append("double ");
|
||||
// AddSymbol(ctx);
|
||||
// Consume(ctx, TokenType.Identifier);
|
||||
|
||||
// while (Peek(ctx, TokenType.Comma))
|
||||
// {
|
||||
// Consume(ctx, TokenType.Comma);
|
||||
// ctx.buffer.Append("double ");
|
||||
// AddSymbol(ctx);
|
||||
// Consume(ctx, TokenType.Identifier);
|
||||
// }
|
||||
// }
|
||||
// private static Func<Context, string, bool> IsOp = (ctx, op)
|
||||
// => Peek(ctx, TokenType.Operation, op);
|
||||
// private static Action<Context, string> ConsOp = (ctx, op)
|
||||
// => Consume(ctx, TokenType.Operation, op);
|
||||
|
||||
// private static void Expr(Context ctx)
|
||||
// {
|
||||
// // expr = [plus|minus] term { (plus|minus) term }
|
||||
|
||||
// if (IsOp(ctx, "+")) ConsOp(ctx, "+");
|
||||
// if (IsOp(ctx, "-")) ConsOp(ctx, "-");
|
||||
|
||||
// Term(ctx);
|
||||
|
||||
// while (IsOp(ctx, "+") || IsOp(ctx, "-"))
|
||||
// {
|
||||
|
||||
// if (IsOp(ctx, "+")) ConsOp(ctx, "+");
|
||||
// if (IsOp(ctx, "-")) ConsOp(ctx, "-");
|
||||
|
||||
// Term(ctx);
|
||||
// }
|
||||
// }
|
||||
// private static void Term(Context ctx)
|
||||
// {
|
||||
// // term = factor { (times|divide) factor };
|
||||
// Factor(ctx);
|
||||
|
||||
// while (IsOp(ctx, "*") || IsOp(ctx, "/"))
|
||||
// {
|
||||
// if (IsOp(ctx, "*")) ConsOp(ctx, "*");
|
||||
// if (IsOp(ctx, "/")) ConsOp(ctx, "/");
|
||||
|
||||
// Term(ctx);
|
||||
// }
|
||||
// }
|
||||
// private static void Factor(Context ctx)
|
||||
// {
|
||||
// // factor = number | var | func | lround expr rround;
|
||||
// if (Peek(ctx, TokenType.Number))
|
||||
// {
|
||||
// Consume(ctx, TokenType.Number);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (Peek(ctx, TokenType.Identifier))
|
||||
// {
|
||||
// Consume(ctx, TokenType.Identifier); // Is either var or func
|
||||
// if (Peek(ctx, TokenType.OpenParens, "("))
|
||||
// { // Is Func, but we already consumed its name
|
||||
// Funct(ctx);
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// if (Peek(ctx, TokenType.Sum))
|
||||
// {
|
||||
// Sum(ctx);
|
||||
// return;
|
||||
// }
|
||||
// // Must be a parenthesized expression
|
||||
// Consume(ctx, TokenType.OpenParens);
|
||||
// Expr(ctx);
|
||||
// Consume(ctx, TokenType.CloseParens);
|
||||
// }
|
||||
// private static void Sum(Context ctx)
|
||||
// {
|
||||
// // sum = ∑ lround identifier comma expr1 comma expr2 comma expr3 rround;
|
||||
// // TODO: differentiate in the language between integer and double, but complicated for a sample.
|
||||
// Consume(ctx, TokenType.Sum);
|
||||
// Consume(ctx, TokenType.OpenParens, "(");
|
||||
|
||||
// AddSymbol(ctx);
|
||||
// var varName = NextToken(ctx).Value;
|
||||
// NextToken(ctx); // consume the first comma without emitting it
|
||||
|
||||
// ctx.buffer.Append("(int)");
|
||||
// Expr(ctx); // Start index
|
||||
// Consume(ctx, TokenType.Comma);
|
||||
|
||||
// ctx.buffer.Append("(int)");
|
||||
// Expr(ctx); // End index
|
||||
// Consume(ctx, TokenType.Comma);
|
||||
|
||||
// ctx.buffer.Append($"{varName} => "); // It needs to be a lambda
|
||||
|
||||
// Expr(ctx); // expr to evaluate at each iteration
|
||||
|
||||
// Consume(ctx, TokenType.CloseParens, ")");
|
||||
// }
|
||||
// private static void Funct(Context ctx)
|
||||
// {
|
||||
// // func = identifier lround expr {comma expr} rround;
|
||||
// Consume(ctx, TokenType.OpenParens, "(");
|
||||
// Expr(ctx);
|
||||
// while (Peek(ctx, TokenType.Comma))
|
||||
// {
|
||||
// Consume(ctx, TokenType.Comma);
|
||||
// Expr(ctx);
|
||||
// }
|
||||
// Consume(ctx, TokenType.CloseParens, ")");
|
||||
// }
|
||||
// }
|
||||
|
||||
// [Generator]
|
||||
// public class MathsGenerator : ISourceGenerator
|
||||
// {
|
||||
// private const string libraryCode = @"
|
||||
//using System.Linq;
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
|
||||
//namespace Maths {
|
||||
// public static class FormulaHelpers {
|
||||
|
||||
// public static IEnumerable<double> ConvertToDouble(IEnumerable<int> col)
|
||||
// {
|
||||
// foreach (var s in col)
|
||||
// yield return (double) s;
|
||||
// }
|
||||
|
||||
// public static double MySum(int start, int end, Func<double, double> f) =>
|
||||
// Enumerable.Sum<double>(ConvertToDouble(Enumerable.Range(start, end - start)), f);
|
||||
// }
|
||||
//}
|
||||
//";
|
||||
|
||||
// public void Execute(GeneratorExecutionContext context)
|
||||
// {
|
||||
// foreach (AdditionalText file in context.AdditionalFiles)
|
||||
// {
|
||||
// if (Path.GetExtension(file.Path).Equals(".math", StringComparison.OrdinalIgnoreCase))
|
||||
// {
|
||||
// // Load formulas from .math files
|
||||
// var mathText = file.GetText();
|
||||
// var mathString = "";
|
||||
|
||||
// if (mathText != null)
|
||||
// {
|
||||
// mathString = mathText.ToString();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// throw new Exception($"Cannot load file {file.Path}");
|
||||
// }
|
||||
|
||||
// // Get name of generated namespace from file name
|
||||
// string fileName = Path.GetFileNameWithoutExtension(file.Path);
|
||||
|
||||
// // Parse and gen the formulas functions
|
||||
// var tokens = Lexer.Tokenize(mathString);
|
||||
// var code = Parser.Parse(tokens);
|
||||
|
||||
// var codeFileName = $@"{fileName}.g.cs";
|
||||
|
||||
// context.AddSource(codeFileName, SourceText.From(code, Encoding.UTF8));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// public void Initialize(GeneratorInitializationContext context)
|
||||
// {
|
||||
// context.RegisterForPostInitialization((pi) => pi.AddSource("__MathLibrary__.g.cs", libraryCode));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
//using Microsoft.CodeAnalysis;
|
||||
//using Microsoft.CodeAnalysis.Text;
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Diagnostics;
|
||||
//using System.IO;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
//using System.Xml;
|
||||
|
||||
//namespace Analyzer1
|
||||
//{
|
||||
// [Generator]
|
||||
// public class SettingsXmlGenerator : ISourceGenerator
|
||||
// {
|
||||
// public void Execute(GeneratorExecutionContext context)
|
||||
// {
|
||||
// // Debugger.Launch();
|
||||
// // Using the context, get any additional files that end in .xmlsettings
|
||||
// IEnumerable<AdditionalText> settingsFiles = context.AdditionalFiles.Where(at => at.Path.EndsWith(".xmlsettings"));
|
||||
// foreach (AdditionalText settingsFile in settingsFiles)
|
||||
// {
|
||||
// ProcessSettingsFile(settingsFile, context);
|
||||
// }
|
||||
// }
|
||||
|
||||
// private void ProcessSettingsFile(AdditionalText xmlFile, GeneratorExecutionContext context)
|
||||
// {
|
||||
// // try and load the settings file
|
||||
// XmlDocument xmlDoc = new XmlDocument();
|
||||
// string text = xmlFile.GetText(context.CancellationToken).ToString();
|
||||
// try
|
||||
// {
|
||||
// xmlDoc.LoadXml(text);
|
||||
// }
|
||||
// catch
|
||||
// {
|
||||
// //TODO: issue a diagnostic that says we couldn't parse it
|
||||
// return;
|
||||
// }
|
||||
|
||||
|
||||
// // create a class in the XmlSetting class that represnts this entry, and a static field that contains a singleton instance.
|
||||
// string fileName = Path.GetFileName(xmlFile.Path);
|
||||
// string name = xmlDoc.DocumentElement.GetAttribute("name");
|
||||
|
||||
// StringBuilder sb = new StringBuilder($@"
|
||||
//namespace AutoSettings
|
||||
//{{
|
||||
// using System;
|
||||
// using System.Xml;
|
||||
|
||||
// public partial class XmlSettings
|
||||
// {{
|
||||
|
||||
// public static {name}Settings {name} {{ get; }} = new {name}Settings(""{fileName}"");
|
||||
|
||||
// public class {name}Settings
|
||||
// {{
|
||||
|
||||
// XmlDocument xmlDoc = new XmlDocument();
|
||||
|
||||
// private string fileName;
|
||||
|
||||
// public string GetLocation() => fileName;
|
||||
|
||||
// internal {name}Settings(string fileName)
|
||||
// {{
|
||||
// this.fileName = fileName;
|
||||
// xmlDoc.Load(fileName);
|
||||
// }}
|
||||
//");
|
||||
|
||||
// for (int i = 0; i < xmlDoc.DocumentElement.ChildNodes.Count; i++)
|
||||
// {
|
||||
// XmlElement setting = (XmlElement)xmlDoc.DocumentElement.ChildNodes[i];
|
||||
// string settingName = setting.GetAttribute("name");
|
||||
// string settingType = setting.GetAttribute("type");
|
||||
|
||||
// sb.Append($@"
|
||||
|
||||
//public {settingType} {settingName}
|
||||
//{{
|
||||
// get
|
||||
// {{
|
||||
// return ({settingType}) Convert.ChangeType(((XmlElement)xmlDoc.DocumentElement.ChildNodes[{i}]).InnerText, typeof({settingType}));
|
||||
// }}
|
||||
//}}
|
||||
//");
|
||||
// }
|
||||
|
||||
// sb.Append("} } }");
|
||||
|
||||
// context.AddSource($"Settings_{name}.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
|
||||
// }
|
||||
|
||||
// public void Initialize(GeneratorInitializationContext context)
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,33 +1,24 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket
|
||||
{
|
||||
/// <summary>
|
||||
/// RpcApi代码构建器
|
||||
/// </summary>
|
||||
|
||||
internal sealed class PluginCodeBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// 接口符号
|
||||
/// </summary>
|
||||
|
||||
private readonly INamedTypeSymbol m_pluginClass;
|
||||
|
||||
const string PluginEventArgsString = "TouchSocket.Core.PluginEventArgs";
|
||||
const string PluginBaseString = "TouchSocket.Core.PluginBase";
|
||||
const string IPluginsManagerString = "TouchSocket.Core.IPluginsManager";
|
||||
private const string PluginEventArgsString = "TouchSocket.Core.PluginEventArgs";
|
||||
private const string PluginBaseString = "TouchSocket.Core.PluginBase";
|
||||
private const string IPluginsManagerString = "TouchSocket.Core.IPluginsManager";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// RpcApi代码构建器
|
||||
/// </summary>
|
||||
/// <param name="pluginClass"></param>
|
||||
public PluginCodeBuilder(INamedTypeSymbol pluginClass)
|
||||
{
|
||||
this.m_pluginClass = pluginClass;
|
||||
@@ -35,9 +26,7 @@ namespace TouchSocket
|
||||
|
||||
public string Prefix { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// using
|
||||
/// </summary>
|
||||
|
||||
public IEnumerable<string> Usings
|
||||
{
|
||||
get
|
||||
@@ -54,10 +43,7 @@ namespace TouchSocket
|
||||
return this.m_pluginClass.ToDisplayString() + "Generator";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为SourceText
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
|
||||
public bool TryToSourceText(out SourceText sourceText)
|
||||
{
|
||||
var code = this.ToString();
|
||||
@@ -70,10 +56,7 @@ namespace TouchSocket
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为字符串
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var methods = this.FindMethods().ToList();
|
||||
@@ -96,6 +79,7 @@ namespace TouchSocket
|
||||
|
||||
codeString.AppendLine($"namespace {this.m_pluginClass.ContainingNamespace}");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine($"[global::System.CodeDom.Compiler.GeneratedCode(\"TouchSocket.SourceGenerator\",\"{Assembly.GetExecutingAssembly().GetName().Version.ToString()}\")]");
|
||||
codeString.AppendLine($"partial class {this.m_pluginClass.Name}");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine("private int RegisterPlugins(IPluginsManager pluginsManager)");
|
||||
@@ -110,7 +94,6 @@ namespace TouchSocket
|
||||
codeString.AppendLine("}");
|
||||
codeString.AppendLine("}");
|
||||
|
||||
|
||||
// System.Diagnostics.Debugger.Launch();
|
||||
return codeString.ToString();
|
||||
}
|
||||
@@ -184,7 +167,5 @@ namespace TouchSocket
|
||||
return m.GetAttributes().Any(a => a.AttributeClass.ToDisplayString() == PluginSyntaxReceiver.GeneratorPluginAttributeTypeName);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using System.Linq;
|
||||
|
||||
namespace TouchSocket
|
||||
{
|
||||
/// <summary>
|
||||
/// HttpApi代码生成器
|
||||
/// </summary>
|
||||
|
||||
[Generator]
|
||||
public class PluginSourceGenerator : ISourceGenerator
|
||||
{
|
||||
string m_generatorPluginAttribute = @"
|
||||
private string m_generatorPluginAttribute = @"
|
||||
using System;
|
||||
|
||||
namespace TouchSocket.Core
|
||||
@@ -33,10 +32,8 @@ namespace TouchSocket.Core
|
||||
}
|
||||
|
||||
";
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterForPostInitialization(a =>
|
||||
@@ -46,10 +43,7 @@ namespace TouchSocket.Core
|
||||
context.RegisterForSyntaxNotifications(() => new PluginSyntaxReceiver());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
var s = context.Compilation.GetMetadataReference(context.Compilation.Assembly);
|
||||
@@ -65,7 +59,10 @@ namespace TouchSocket.Core
|
||||
{
|
||||
if (builder.TryToSourceText(out var sourceText))
|
||||
{
|
||||
context.AddSource($"{builder.GetFileName()}.g.cs", sourceText);
|
||||
var tree = CSharpSyntaxTree.ParseText(sourceText);
|
||||
var root = tree.GetRoot().NormalizeWhitespace();
|
||||
var ret = root.ToFullString();
|
||||
context.AddSource($"{builder.GetFileName()}.g.cs", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace TouchSocket
|
||||
@@ -10,7 +9,7 @@ namespace TouchSocket
|
||||
/// <summary>
|
||||
/// RpcApi语法接收器
|
||||
/// </summary>
|
||||
sealed class PluginSyntaxReceiver : ISyntaxReceiver
|
||||
internal sealed class PluginSyntaxReceiver : ISyntaxReceiver
|
||||
{
|
||||
public const string GeneratorPluginAttributeTypeName = "TouchSocket.Core.GeneratorPluginAttribute";
|
||||
|
||||
@@ -56,7 +55,6 @@ namespace TouchSocket
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否为插件
|
||||
/// </summary>
|
||||
@@ -84,7 +82,6 @@ namespace TouchSocket
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 返回是否声明指定的特性
|
||||
/// </summary>
|
||||
|
||||
@@ -1,34 +1,27 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket
|
||||
{
|
||||
/// <summary>
|
||||
/// RpcApi代码构建器
|
||||
/// </summary>
|
||||
internal sealed class RpcCodeBuilder
|
||||
|
||||
internal sealed class RpcClientCodeBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// 接口符号
|
||||
/// </summary>
|
||||
private readonly INamedTypeSymbol m_rpcApi;
|
||||
|
||||
private readonly Dictionary<string, TypedConstant> m_rpcApiNamedArguments;
|
||||
|
||||
/// <summary>
|
||||
/// RpcApi代码构建器
|
||||
/// </summary>
|
||||
/// <param name="rpcApi"></param>
|
||||
public RpcCodeBuilder(INamedTypeSymbol rpcApi)
|
||||
public RpcClientCodeBuilder(INamedTypeSymbol rpcApi)
|
||||
{
|
||||
this.m_rpcApi = rpcApi;
|
||||
var attributeData = rpcApi.GetAttributes().FirstOrDefault(a => a.AttributeClass.ToDisplayString() == RpcSyntaxReceiver.GeneratorRpcProxyAttributeTypeName);
|
||||
var attributeData = rpcApi.GetAttributes().FirstOrDefault(a => a.AttributeClass.ToDisplayString() == RpcClientSyntaxReceiver.GeneratorRpcProxyAttributeTypeName);
|
||||
|
||||
this.m_rpcApiNamedArguments = attributeData.NamedArguments.ToDictionary(a => a.Key, a => a.Value);
|
||||
|
||||
@@ -46,76 +39,49 @@ namespace TouchSocket
|
||||
/// 代码生成标识
|
||||
/// </summary>
|
||||
[Flags]
|
||||
private enum CodeGeneratorFlag
|
||||
public enum CodeGeneratorFlag
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成同步代码(源代码生成无效)
|
||||
/// </summary>
|
||||
[Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)]
|
||||
Sync = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 生成异步代码(源代码生成无效)
|
||||
/// </summary>
|
||||
[Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)]
|
||||
Async = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 生成扩展同步代码
|
||||
/// </summary>
|
||||
ExtensionSync = 4,
|
||||
ExtensionSync = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 生成扩展异步代码
|
||||
/// </summary>
|
||||
ExtensionAsync = 8,
|
||||
|
||||
/// <summary>
|
||||
/// 包含接口(源代码生成无效)
|
||||
/// </summary>
|
||||
[Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)]
|
||||
IncludeInterface = 16,
|
||||
|
||||
/// <summary>
|
||||
/// 包含实例(源代码生成无效)
|
||||
/// </summary>
|
||||
[Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)]
|
||||
IncludeInstance = 32,
|
||||
ExtensionAsync = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 包含扩展(源代码生成无效)
|
||||
/// </summary>
|
||||
[Obsolete("该值已被弃用,请使用颗粒度更小的配置", true)]
|
||||
IncludeExtension = 64,
|
||||
IncludeExtension = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 生成实例类同步代码(源代码生成无效)
|
||||
/// </summary>
|
||||
InstanceSync = 128,
|
||||
InstanceSync = 8,
|
||||
|
||||
/// <summary>
|
||||
/// 生成实例类异步代码(源代码生成无效)
|
||||
/// </summary>
|
||||
InstanceAsync = 256,
|
||||
InstanceAsync = 16,
|
||||
|
||||
/// <summary>
|
||||
/// 生成接口同步代码
|
||||
/// </summary>
|
||||
InterfaceSync = 512,
|
||||
InterfaceSync = 32,
|
||||
|
||||
/// <summary>
|
||||
/// 生成接口异步代码
|
||||
/// </summary>
|
||||
InterfaceAsync = 1024,
|
||||
InterfaceAsync = 64,
|
||||
}
|
||||
|
||||
public string Prefix { get; set; }
|
||||
|
||||
public string ServerName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// using
|
||||
/// </summary>
|
||||
public IEnumerable<string> Usings
|
||||
{
|
||||
get
|
||||
@@ -134,20 +100,12 @@ namespace TouchSocket
|
||||
return this.m_rpcApi.ToDisplayString() + "Generator";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为SourceText
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public SourceText ToSourceText()
|
||||
{
|
||||
var code = this.ToString();
|
||||
return SourceText.From(code, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为字符串
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
var codeString = new StringBuilder();
|
||||
@@ -212,17 +170,17 @@ namespace TouchSocket
|
||||
return true;
|
||||
}
|
||||
|
||||
private void BuildIntereface(StringBuilder builder)
|
||||
private void BuildIntereface(StringBuilder codeString)
|
||||
{
|
||||
var interfaceNames = new List<string>();
|
||||
if (this.IsInheritedInterface())
|
||||
{
|
||||
var interfaceNames1 = this.m_rpcApi.Interfaces
|
||||
.Where(a => RpcSyntaxReceiver.IsRpcApiInterface(a))
|
||||
.Select(a => $"I{new RpcCodeBuilder(a).GetClassName()}");
|
||||
.Where(a => RpcClientSyntaxReceiver.IsRpcApiInterface(a))
|
||||
.Select(a => $"I{new RpcClientCodeBuilder(a).GetClassName()}");
|
||||
|
||||
var interfaceNames2 = this.m_rpcApi.Interfaces
|
||||
.Where(a => !RpcSyntaxReceiver.IsRpcApiInterface(a))
|
||||
.Where(a => !RpcClientSyntaxReceiver.IsRpcApiInterface(a))
|
||||
.Select(a => a.ToDisplayString());
|
||||
|
||||
interfaceNames.AddRange(interfaceNames1);
|
||||
@@ -231,44 +189,47 @@ namespace TouchSocket
|
||||
|
||||
if (interfaceNames.Count == 0)
|
||||
{
|
||||
builder.AppendLine($"public interface I{this.GetClassName()}");
|
||||
codeString.AppendLine($"[global::System.CodeDom.Compiler.GeneratedCode(\"TouchSocket.SourceGenerator\",\"{Assembly.GetExecutingAssembly().GetName().Version.ToString()}\")]");
|
||||
codeString.AppendLine($"public interface I{this.GetClassName()}");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine($"public interface I{this.GetClassName()} :{string.Join(",", interfaceNames)}");
|
||||
codeString.AppendLine($"[global::System.CodeDom.Compiler.GeneratedCode(\"TouchSocket.SourceGenerator\",\"{Assembly.GetExecutingAssembly().GetName().Version.ToString()}\")]");
|
||||
codeString.AppendLine($"public interface I{this.GetClassName()} :{string.Join(",", interfaceNames)}");
|
||||
}
|
||||
|
||||
builder.AppendLine("{");
|
||||
codeString.AppendLine("{");
|
||||
//Debugger.Launch();
|
||||
|
||||
foreach (var method in this.FindApiMethods())
|
||||
{
|
||||
var methodCode = this.BuildMethodInterface(method);
|
||||
builder.AppendLine(methodCode);
|
||||
codeString.AppendLine(methodCode);
|
||||
}
|
||||
|
||||
builder.AppendLine("}");
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
|
||||
private void BuildMethod(StringBuilder builder)
|
||||
private void BuildMethod(StringBuilder codeString)
|
||||
{
|
||||
builder.AppendLine($"public static class {this.GetClassName()}Extensions");
|
||||
builder.AppendLine("{");
|
||||
codeString.AppendLine($"[global::System.CodeDom.Compiler.GeneratedCode(\"TouchSocket.SourceGenerator\",\"{Assembly.GetExecutingAssembly().GetName().Version.ToString()}\")]");
|
||||
codeString.AppendLine($"public static class {this.GetClassName()}Extensions");
|
||||
codeString.AppendLine("{");
|
||||
//Debugger.Launch();
|
||||
|
||||
foreach (var method in this.FindApiMethods())
|
||||
{
|
||||
var methodCode = this.BuildMethod(method);
|
||||
builder.AppendLine(methodCode);
|
||||
codeString.AppendLine(methodCode);
|
||||
}
|
||||
|
||||
builder.AppendLine("}");
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
|
||||
private string BuildMethod(IMethodSymbol method)
|
||||
{
|
||||
//Debugger.Launch();
|
||||
var attributeData = method.GetAttributes().FirstOrDefault(a => a.AttributeClass.ToDisplayString() == RpcSyntaxReceiver.RpcMethodAttributeTypeName);
|
||||
var attributeData = method.GetAttributes().FirstOrDefault(a => a.AttributeClass.ToDisplayString() == RpcClientSyntaxReceiver.RpcMethodAttributeTypeName);
|
||||
if (attributeData is null)
|
||||
{
|
||||
return string.Empty;
|
||||
@@ -548,7 +509,7 @@ namespace TouchSocket
|
||||
private string BuildMethodInterface(IMethodSymbol method)
|
||||
{
|
||||
//Debugger.Launch();
|
||||
var attributeData = method.GetAttributes().FirstOrDefault(a => a.AttributeClass.ToDisplayString() == RpcSyntaxReceiver.RpcMethodAttributeTypeName);
|
||||
var attributeData = method.GetAttributes().FirstOrDefault(a => a.AttributeClass.ToDisplayString() == RpcClientSyntaxReceiver.RpcMethodAttributeTypeName);
|
||||
if (attributeData is null)
|
||||
{
|
||||
return string.Empty;
|
||||
@@ -641,7 +602,6 @@ namespace TouchSocket
|
||||
return codeString.ToString();
|
||||
}
|
||||
|
||||
|
||||
private IEnumerable<IMethodSymbol> FindApiMethods()
|
||||
{
|
||||
return this.m_rpcApi
|
||||
@@ -1,41 +1,38 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using System.Linq;
|
||||
|
||||
namespace TouchSocket
|
||||
{
|
||||
/// <summary>
|
||||
/// HttpApi代码生成器
|
||||
/// </summary>
|
||||
|
||||
[Generator]
|
||||
public class RpcSourceGenerator : ISourceGenerator
|
||||
public class RpcClientSourceGenerator : ISourceGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterForSyntaxNotifications(() => new RpcSyntaxReceiver());
|
||||
context.RegisterForSyntaxNotifications(() => new RpcClientSyntaxReceiver());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
var s = context.Compilation.GetMetadataReference(context.Compilation.Assembly);
|
||||
|
||||
if (context.SyntaxReceiver is RpcSyntaxReceiver receiver)
|
||||
if (context.SyntaxReceiver is RpcClientSyntaxReceiver receiver)
|
||||
{
|
||||
var builders = receiver
|
||||
.GetRpcApiTypes(context.Compilation)
|
||||
.Select(i => new RpcCodeBuilder(i))
|
||||
.Select(i => new RpcClientCodeBuilder(i))
|
||||
.Distinct();
|
||||
//Debugger.Launch();
|
||||
foreach (var builder in builders)
|
||||
{
|
||||
context.AddSource($"{builder.GetFileName()}.g.cs", builder.ToSourceText());
|
||||
var tree = CSharpSyntaxTree.ParseText(builder.ToSourceText());
|
||||
var root = tree.GetRoot().NormalizeWhitespace();
|
||||
var ret = root.ToFullString();
|
||||
context.AddSource($"{builder.GetFileName()}.g.cs", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,23 +6,16 @@ using System.Linq;
|
||||
|
||||
namespace TouchSocket
|
||||
{
|
||||
/// <summary>
|
||||
/// RpcApi语法接收器
|
||||
/// </summary>
|
||||
sealed class RpcSyntaxReceiver : ISyntaxReceiver
|
||||
|
||||
internal sealed class RpcClientSyntaxReceiver : ISyntaxReceiver
|
||||
{
|
||||
public const string GeneratorRpcProxyAttributeTypeName = "TouchSocket.Rpc.GeneratorRpcProxyAttribute";
|
||||
public const string RpcMethodAttributeTypeName = "TouchSocket.Rpc.GeneratorRpcMethodAttribute";
|
||||
|
||||
/// <summary>
|
||||
/// 接口列表
|
||||
/// </summary>
|
||||
|
||||
private readonly List<InterfaceDeclarationSyntax> interfaceSyntaxList = new List<InterfaceDeclarationSyntax>();
|
||||
|
||||
/// <summary>
|
||||
/// 访问语法树
|
||||
/// </summary>
|
||||
/// <param name="syntaxNode"></param>
|
||||
|
||||
void ISyntaxReceiver.OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||
{
|
||||
if (syntaxNode is InterfaceDeclarationSyntax syntax)
|
||||
@@ -33,11 +26,7 @@ namespace TouchSocket
|
||||
|
||||
public static INamedTypeSymbol GeneratorRpcProxyAttribute { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有RpcApi符号
|
||||
/// </summary>
|
||||
/// <param name="compilation"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public IEnumerable<INamedTypeSymbol> GetRpcApiTypes(Compilation compilation)
|
||||
{
|
||||
//Debugger.Launch();
|
||||
@@ -56,7 +45,6 @@ namespace TouchSocket
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否为Rpc接口
|
||||
/// </summary>
|
||||
@@ -90,25 +78,5 @@ namespace TouchSocket
|
||||
return true;
|
||||
}) is not null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 返回是否声明指定的特性
|
||||
/// </summary>
|
||||
/// <param name="symbol"></param>
|
||||
/// <param name="attribute"></param>
|
||||
/// <returns></returns>
|
||||
public static bool HasAttribute(ISymbol symbol, INamedTypeSymbol attribute)
|
||||
{
|
||||
foreach (var attr in symbol.GetAttributes())
|
||||
{
|
||||
var attrClass = attr.AttributeClass;
|
||||
if (attrClass != null && attrClass.AllInterfaces.Contains(attribute))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace TouchSocket.Rpc
|
||||
{
|
||||
/// <summary>
|
||||
/// 标识将通过源生成器生成Rpc服务的调用委托。
|
||||
/// </summary>
|
||||
[AttributeUsage( AttributeTargets.Class)]
|
||||
internal class GeneratorRpcServerAttribute:Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user