同步源代码

This commit is contained in:
若汝棋茗
2023-10-10 15:11:09 +08:00
parent 4033069ed8
commit f66479ee30
132 changed files with 4829 additions and 3041 deletions

View File

@@ -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.

Binary file not shown.

Binary file not shown.

View File

@@ -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>

Binary file not shown.

View File

@@ -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));
}
}
});
}
}
}

View File

@@ -16,8 +16,7 @@ using System.Runtime.CompilerServices;
namespace TouchSocket.Core
{
/// <summary>
/// 具有释放的对象。
/// 并未实现析构函数相关。
/// 具有释放的对象。内部实现了GC.SuppressFinalize但不包括析构函数相关。
/// </summary>
public class DisposableObject : IDisposable
{

View File

@@ -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不满足解析开始缓存然后保存对象
{

View File

@@ -16,7 +16,7 @@ using System.Collections.Generic;
namespace TouchSocket.Core
{
/// <summary>
/// 普通TCP数据处理器,该适配器不对数据做任何处理。
/// 普通Tcp数据处理器,该适配器不对数据做任何处理。
/// </summary>
public class NormalDataHandlingAdapter : SingleStreamDataHandlingAdapter
{

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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())
{

View File

@@ -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;
}
}
}

View File

@@ -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>

View File

@@ -18,7 +18,7 @@ namespace TouchSocket.Core
/// 忽略的Fast序列化
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class FastNonSerializedAttribute : Attribute
public sealed class FastNonSerializedAttribute : Attribute
{
}
}

View File

@@ -6,7 +6,7 @@ namespace TouchSocket.Core
/// 强制Fast序列化。一般当某个属性为只读时使用该特性。
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class FastSerializedAttribute : Attribute
public sealed class FastSerializedAttribute : Attribute
{
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;

View File

@@ -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) &&

View File

@@ -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序列化和反序列化

Binary file not shown.

View File

@@ -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);

View File

@@ -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;
}
}
}

View File

@@ -218,7 +218,8 @@ namespace TouchSocket.Dmtp
await Task.Delay(this.VerifyTimeout);
if (!this.IsHandshaked)
{
this.Close("Handshak验证超时");
this.TryShutdown();
base.Close("Handshak验证超时");
}
});
}

View File

@@ -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();

View File

@@ -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

View File

@@ -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();
}
}

Binary file not shown.

View File

@@ -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>

View File

@@ -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;
}

Binary file not shown.

View 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;
}
}
}

View File

@@ -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>

View File

@@ -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);
// }
// }
// }
//}

View File

@@ -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; }
}
}

View File

@@ -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));

View File

@@ -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)

View File

@@ -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);
});
}
}
}

View File

@@ -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);
}
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -42,7 +42,7 @@ namespace TouchSocket.JsonRpc
/// <summary>
/// JsonRpc上下文
/// </summary>
public JsonRpcContext JsonRpcContext { get; internal set; }
public JsonRpcRequestContext JsonRpcContext { get; internal set; }
/// <summary>
/// Json字符串

View 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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View 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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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;
}
}
}

View File

@@ -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 ; }
}
}

View File

@@ -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

View 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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View 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连接");
}
}
}
}

View 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);
}
}

View File

@@ -27,6 +27,6 @@ namespace TouchSocket.JsonRpc
/// <summary>
/// JsonRpc数据包
/// </summary>
public JsonRpcContext JsonRpcContext { get; }
public JsonRpcRequestContext JsonRpcContext { get; }
}
}

View File

@@ -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
{
}
}

View File

@@ -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
{
}
}

View File

@@ -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

View File

@@ -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();
}
}
}

View File

@@ -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解析器
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}
}
}

Binary file not shown.

View File

@@ -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)

Binary file not shown.

View File

@@ -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>

View File

@@ -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();
}
}

View File

@@ -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);
}
}
}
}
}

View File

@@ -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>
/// 获取指定类型属性标签

View File

@@ -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)
{

View File

@@ -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)}");
}

View File

@@ -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,
}
}

View File

@@ -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);
}
}

Binary file not shown.

View File

@@ -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;
}
}
}

View 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)
// {
// }
// }
//}

View File

@@ -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("}");
}
}
}

View File

@@ -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);
}
}
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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; }
}
}

View File

@@ -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);
// }
// }
// }
// }
// }
// }
//}

View File

@@ -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
// }
// }
//}

View File

@@ -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();
// }
// }
//}

View File

@@ -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());
// }
// }
// }
// }
//}

View File

@@ -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;
// }
// }
//}

View File

@@ -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));
// }
// }
//}

View File

@@ -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)
// {
// }
// }
//}

View File

@@ -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);
});
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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