Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ csharp_preferred_modifier_order = public,private,protected,internal,static,exter
csharp_prefer_braces = true:silent
csharp_prefer_simple_default_expression = true:suggestion
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
csharp_space_after_cast = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_keywords_in_control_flow_statements = true
Expand Down
4 changes: 2 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<ItemGroup>
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="dotnetCampus.AsyncWorkerCollection.Source" Version="1.7.2" />
<PackageVersion Include="dotnetCampus.CommandLine" Version="3.3.1" />
<PackageVersion Include="dotnetCampus.LatestCSharpFeatures" Version="12.0.1" />
<PackageVersion Include="DotNetCampus.CommandLine" Version="4.0.1-alpha.1" />
<PackageVersion Include="DotNetCampus.LatestCSharpFeatures" Version="13.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<PackageVersion Include="Microsoft.CodeAnalysis" Version="4.10.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
Expand Down
4 changes: 2 additions & 2 deletions demo/IpcDirectRoutedAotDemo/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
var ipcProvider = new IpcProvider(pipeName, new IpcConfiguration()
{

}.UseSystemJsonIpcObjectSerializer(SourceGenerationContext.Default));
}.UseSystemTextJsonIpcObjectSerializer(SourceGenerationContext.Default));
var ipcDirectRoutedProvider = new JsonIpcDirectRoutedProvider(ipcProvider);
ipcDirectRoutedProvider.AddNotifyHandler(notifyPath, () =>
{
Expand Down Expand Up @@ -50,7 +50,7 @@
var peerName = args[0];
Console.WriteLine($"[{Environment.ProcessId}] 客户端进程启动");
var jsonIpcDirectRoutedProvider = new JsonIpcDirectRoutedProvider(ipcConfiguration: new IpcConfiguration()
.UseSystemJsonIpcObjectSerializer(SourceGenerationContext.Default));
.UseSystemTextJsonIpcObjectSerializer(SourceGenerationContext.Default));
JsonIpcDirectRoutedClientProxy jsonIpcDirectRoutedClientProxy = await jsonIpcDirectRoutedProvider.GetAndConnectClientAsync(peerName);

Console.WriteLine($"[{Environment.ProcessId}] 客户端发送通知");
Expand Down
4 changes: 2 additions & 2 deletions demo/dotnetCampus.Ipc.WpfDemo/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using DotNetCampus.Cli;
using dotnetCampus.Ipc.Context;
using dotnetCampus.Ipc.Pipes;
using dotnetCampus.Ipc.WpfDemo.View;
Expand All @@ -34,7 +34,7 @@ public MainWindow()
InitializeComponent();
DataContext = this;

var options = dotnetCampus.Cli.CommandLine.Parse(Environment.GetCommandLineArgs()).As<Options>();
var options = CommandLine.Parse(Environment.GetCommandLineArgs().Skip(1).ToArray()).As<Options>();
if (!string.IsNullOrEmpty(options.ServerName))
{
Debugger.Launch();
Expand Down
29 changes: 14 additions & 15 deletions demo/dotnetCampus.Ipc.WpfDemo/Options.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
using dotnetCampus.Cli;
using DotNetCampus.Cli.Compiler;

namespace dotnetCampus.Ipc.WpfDemo
namespace dotnetCampus.Ipc.WpfDemo;

public class Options
{
public class Options
{
/// <summary>
/// 本机的服务名
/// </summary>
[Option(longName: nameof(ServerName))]
public string? ServerName { get; set; }
/// <summary>
/// 本机的服务名
/// </summary>
[Option]
public string? ServerName { get; set; }

/// <summary>
/// 对方的服务名
/// </summary>
[Option(longName: nameof(PeerName))]
public string? PeerName { get; set; }
}
/// <summary>
/// 对方的服务名
/// </summary>
[Option]
public string? PeerName { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
using System.Threading.Tasks;

using dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Models;
using dotnetCampus.Ipc.Messages;
using dotnetCampus.Ipc.Serialization;

namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Contexts;

namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Contexts
internal class GeneratedIpcJointResponse : IIpcResponseMessage
{
internal class GeneratedIpcJointResponse : IIpcResponseMessage
{
internal static GeneratedIpcJointResponse Empty { get; } = new GeneratedIpcJointResponse();
internal static GeneratedIpcJointResponse Empty { get; } = new GeneratedIpcJointResponse();

private GeneratedIpcJointResponse()
{
}
private GeneratedIpcJointResponse()
{
}

private GeneratedIpcJointResponse(IpcMessage message)
{
ResponseMessage = message;
}
private GeneratedIpcJointResponse(IpcMessage message)
{
ResponseMessage = message;
}

public IpcMessage ResponseMessage { get; }
public IpcMessage ResponseMessage { get; }

internal static async Task<GeneratedIpcJointResponse> FromAsyncReturnModel(Task<GeneratedProxyMemberReturnModel?> asyncReturnModel)
{
var returnModel = await asyncReturnModel.ConfigureAwait(false);
var message = returnModel is null
? new IpcMessage()
: GeneratedProxyMemberReturnModel.Serialize(returnModel);
return new GeneratedIpcJointResponse(message);
}
internal static async Task<GeneratedIpcJointResponse> FromAsyncReturnModel(
Task<GeneratedProxyMemberReturnModel?> asyncReturnModel,
IIpcObjectSerializer serializer)
{
var returnModel = await asyncReturnModel.ConfigureAwait(false);
var message = returnModel is null
? new IpcMessage()
: serializer.SerializeToIpcMessage(returnModel, "Return");
return new GeneratedIpcJointResponse(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
using System;

using dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Models;

#if UseNewtonsoftJson
using Newtonsoft.Json.Linq;
#endif
using dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Models;
using dotnetCampus.Ipc.Serialization;

namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies;

Expand All @@ -15,19 +10,17 @@ namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies;
{
private readonly object? _value;

#if UseNewtonsoftJson
/// <summary>
/// 创建一个存储 IPC 中 <see cref="JToken"/> 的临时 GARM 模型。
/// 创建一个存储 IPC 中 <see cref="IpcJsonElement"/> 的临时 GARM 模型。
/// </summary>
/// <param name="value">模型的值。</param>
/// <param name="valueType">模型中值的类型。</param>
public Garm(JToken? value, Type valueType)
public Garm(IpcJsonElement value, Type valueType)
{
_value = value;
ValueType = valueType ?? throw new ArgumentNullException(nameof(valueType));
IpcType = null;
}
#endif

/// <summary>
/// 创建一个存储 IPC 中 IPC 代理对象的临时 GARM 模型。
Expand All @@ -49,7 +42,7 @@ public Garm(object? value, Type ipcType)
/// proxy -> IPC model in proxy side -> IPC model in joint side -> joint
/// 其中,proxy 和 joint 均由编译器在用户端生成了泛型代码,因此这些上下文中都可以获取到泛型类型。
/// 但中间的传输过程中没有泛型上下文,所以会用到此临时类型中转值。
/// 由于中转的值可能是 <see cref="JToken"/> 这种未确定类型的值,为避免代码中意外写出错误的代码,因此禁止在此类型中获取值。
/// 由于中转的值可能是 JsonElement 这种未确定类型的值,为避免代码中意外写出错误的代码,因此禁止在此类型中获取值。
/// </remarks>
object? IGarmObject.Value => throw new InvalidOperationException("当 GARM 未获得泛型类型时,不可获取其值。请等待泛型上下文中调用 ToGeneric<T> 转换为泛型类型后再获取值。");

Expand All @@ -68,10 +61,13 @@ public Garm(object? value, Type ipcType)
/// </summary>
/// <typeparam name="T">泛型类型。</typeparam>
/// <returns>泛型 GARM 模型。</returns>
public Garm<T> ToGeneric<T>()
public Garm<T> ToGeneric<T>(IIpcObjectSerializer serializer) => _value switch
{
return new Garm<T>(
KnownTypeConverter.ConvertBackFromJTokenOrObject<T>(_value),
IpcType);
}
// 是 null。
null => new Garm<T>(default, IpcType),
// 是一个普通的 IPC 对象。
IpcJsonElement jsonElement => new Garm<T>(IpcJsonElement.Deserialize<T>(jsonElement, serializer), IpcType),
// 是一个 IPC 代理对象。
_ => new Garm<T>((T?) _value, IpcType),
};
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System;

using dotnetCampus.Ipc.CompilerServices.Attributes;
using dotnetCampus.Ipc.CompilerServices.Attributes;

namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies;

/// <summary>
/// <para>IPC GARM 模型。</para>
/// <para>GARM = Generated Argument and Return Model 生成类的参数与返回值模型。</para>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Models;

namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies;

/// <summary>
/// 为 <see cref="Garm{T}"/> 提供非泛型访问的方法。
/// </summary>
Expand All @@ -9,6 +10,10 @@ public interface IGarmObject
/// <summary>
/// 获取 <see cref="Garm{T}"/> 的值。
/// </summary>
/// <remarks>
/// 对于发送方,值可能是:<see langword="null"/>、可 JSON 序列化的任意对象(即将被序列化)、IPC 代理对象。<br/>
/// 对于接收方,值可能是:<see langword="null"/>、<see cref="IpcJsonElement"/>(用于延迟反序列化)、IPC 代理对象。
/// </remarks>
object? Value { get; }

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,11 @@ public static TContract CreateIpcJoint<TContract>(this IIpcProvider ipcProvider,
var realType = realInstance.GetType();
if (IpcTypeToProxyJointCache[typeof(TContract)].jointType is { } jointType)
{
var context = GetContext(ipcProvider);
var joint = (GeneratedIpcJoint<TContract>) Activator.CreateInstance(jointType)!;
joint.Context = context;
joint.SetInstance(realInstance);
GetContext(ipcProvider).JointManager.AddPublicIpcObject(joint, ipcObjectId);
context.JointManager.AddPublicIpcObject(joint, ipcObjectId);
return realInstance;
}
else
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Models;
using dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Models;
using dotnetCampus.Ipc.Exceptions;

namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies;
/// <summary>
/// 为自动生成的 IPC 对接类提供基类。
/// </summary>
public abstract class GeneratedIpcJoint
{
private GeneratedProxyJointIpcContext? _context;

/// <summary>
/// 提供基于 .NET 类型的 IPC 传输上下文信息。
/// </summary>
internal GeneratedProxyJointIpcContext Context
{
get => _context ?? throw new IpcRemoteException($"基于 .NET 类型的 IPC 传输机制应使用 {typeof(GeneratedIpcFactory)} 工厂类型来构造。");
set => _context = value ?? throw new ArgumentNullException(nameof(value));
}

/// <summary>
/// 设置此对接对象的真实实例。
/// </summary>
Expand Down Expand Up @@ -233,7 +240,7 @@ internal sealed override IGarmObject SetProperty(ulong memberId, string property

internal sealed override IGarmObject CallMethod(ulong memberId, string methodName, IGarmObject[]? args)
{
var count = args is null ? 0 : args.Length;
var count = args?.Length ?? 0;
if (_methods.TryGetValue(memberId, out var tuple))
{
return tuple.method(args);
Expand All @@ -243,22 +250,19 @@ internal sealed override IGarmObject CallMethod(ulong memberId, string methodNam

internal sealed override async Task<IGarmObject> CallMethodAsync(ulong memberId, string methodName, IGarmObject[]? args)
{
var count = args is null ? 0 : args.Length;
if (_asyncMethods.TryGetValue(memberId, out var tuple))
{
return await tuple.asyncMethod(args).ConfigureAwait(false);
}
throw CreateMethodNotMatchException(memberId, methodName);
}

private T? CastArg<T>(IGarmObject argModel)
private T? CastArg<T>(IGarmObject argModel) => argModel switch
{
if (argModel is Garm go)
{
argModel = go.ToGeneric<T>();
}
return KnownTypeConverter.ConvertBackFromJTokenOrObject<T>(argModel.Value);
}
Garm go => go.ToGeneric<T>(Context.ObjectSerializer).Value,
Garm<T> go => go.Value,
_ => throw new InvalidOperationException("不可能进入此分支,因为所有参数都应该是 GARM 对象。"),
};

internal override Type[] GetParameterTypes(MemberInvokingType invokingType, ulong memberId)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;

using dotnetCampus.Ipc.CompilerServices.Attributes;
using dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Models;
using dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Utils;
using dotnetCampus.Ipc.Exceptions;

namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies;

/// <summary>
/// 提供给自动生成的代理对象使用,以便能够生成通过 IPC 方式访问目标成员的能力。
/// </summary>
Expand Down Expand Up @@ -119,7 +118,7 @@ protected GeneratedIpcProxy()
/// <returns>可异步等待的属性设置。</returns>
protected Task SetValueAsync<T>(ulong memberId, Garm<T> value, IpcProxyMemberNamedValues namedValues, [CallerMemberName] string propertyName = "")
{
return IpcInvokeAsync<object>(MemberInvokingType.SetProperty, memberId, propertyName, new IGarmObject[] { value }, namedValues);
return IpcInvokeAsync<object>(MemberInvokingType.SetProperty, memberId, propertyName, [value], namedValues);
}

/// <summary>
Expand Down Expand Up @@ -189,7 +188,7 @@ protected Task CallMethodAsync(ulong memberId, IGarmObject[]? args, IpcProxyMemb
var ignoresIpcException = namedValues.IgnoresIpcException ?? RuntimeConfigs?.IgnoresIpcException ?? false;
try
{
return (namedValues.Timeout ?? RuntimeConfigs?.Timeout) is int timeout && timeout > 0
return (namedValues.Timeout ?? RuntimeConfigs?.Timeout) is { } timeout and > 0
? await InvokeWithTimeoutAsync<T>(
callType,
memberId,
Expand Down Expand Up @@ -224,10 +223,6 @@ protected Task CallMethodAsync(ulong memberId, IGarmObject[]? args, IpcProxyMemb
throw;
}
}
catch (Exception)
{
throw;
}
}

private async Task<T?> InvokeWithTimeoutAsync<T>(MemberInvokingType callType, ulong memberId, string memberName, IGarmObject[]? args,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using dotnetCampus.Ipc.Context;
using dotnetCampus.Ipc.Serialization;

namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies
{
Expand All @@ -13,6 +14,7 @@ public class GeneratedProxyJointIpcContext
/// <param name="ipcContext"></param>
internal GeneratedProxyJointIpcContext(IpcContext ipcContext)
{
ObjectSerializer = ipcContext.IpcConfiguration.IpcObjectSerializer;
JointManager = new PublicIpcJointManager(this, ipcContext);
RequestHandler = new GeneratedProxyJointIpcRequestHandler(this, ipcContext);
}
Expand All @@ -26,5 +28,10 @@ internal GeneratedProxyJointIpcContext(IpcContext ipcContext)
/// 请将此属性赋值给 IpcConfiguration.DefaultIpcRequestHandler 以获得 .NET 类型的 IPC 传输访问能力。
/// </summary>
public IIpcRequestHandler RequestHandler { get; }

/// <summary>
/// 用于序列化和反序列化 IPC 对象的序列化器。
/// </summary>
public IIpcObjectSerializer ObjectSerializer { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Threading.Tasks;

using dotnetCampus.Ipc.Context;
using dotnetCampus.Ipc.Context;
using dotnetCampus.Ipc.Messages;

namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies
Expand Down
Loading
Loading