-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: 舰队的偶像-岛风酱! <[email protected]>
- Loading branch information
Showing
7 changed files
with
210 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
namespace Shimakaze.Sdk.JsonRPC.Server; | ||
|
||
/// <summary> | ||
/// 表示这是一个JsonRpc Handler | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Class)] | ||
public sealed class HandlerAttribute : Attribute | ||
{ | ||
/// <summary> | ||
/// 这个Handler中的方法/事件的路径 | ||
/// </summary> | ||
public string? Route { get; set; } | ||
|
||
/// <summary> | ||
/// 表示这是一个JsonRpc Handler | ||
/// </summary> | ||
/// <param name="route">这个Handler中的方法/事件的路径</param> | ||
public HandlerAttribute(string? route = null) | ||
{ | ||
Route = route; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
using System.Reflection; | ||
|
||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
|
||
using StreamJsonRpc; | ||
|
||
namespace Shimakaze.Sdk.JsonRPC.Server; | ||
|
||
internal sealed class JsonRPCHostedService : IHostedService | ||
{ | ||
private readonly IServiceCollection _services; | ||
private readonly IServiceProvider _serviceProvider; | ||
private readonly ILogger<JsonRPCHostedService> _logger; | ||
private readonly JsonRPCHostedServiceOptions _options; | ||
|
||
public JsonRPCHostedService( | ||
IServiceCollection services, | ||
IServiceProvider serviceProvider) | ||
{ | ||
_services = services; | ||
_serviceProvider = serviceProvider; | ||
_logger = serviceProvider.GetRequiredService<ILogger<JsonRPCHostedService>>(); | ||
_options = serviceProvider.GetRequiredService<JsonRPCHostedServiceOptions>(); | ||
} | ||
|
||
public Task StartAsync(CancellationToken cancellationToken) | ||
{ | ||
JsonRpc jsonRpc = new( | ||
new NewLineDelimitedMessageHandler( | ||
_options.Output ?? throw new ArgumentNullException(nameof(_options.Output)), | ||
_options.Input ?? throw new ArgumentNullException(nameof(_options.Input)), | ||
_options.JsonRpcMessageTextFormatter ?? throw new ArgumentNullException(nameof(_options.JsonRpcMessageTextFormatter)) | ||
) | ||
); | ||
int count = 0; | ||
foreach (var target in _services | ||
.Select(i => ( | ||
Metadata: i.ImplementationType?.GetCustomAttribute<HandlerAttribute>(), | ||
i.ImplementationType)) | ||
.Where(i => i is | ||
{ | ||
Metadata: not null, | ||
ImplementationType: | ||
{ | ||
IsInterface: false, | ||
IsAbstract: false | ||
} | ||
}) | ||
.SelectMany(i => i.ImplementationType!.GetTargets(i.Metadata?.Route, _serviceProvider.GetRequiredService(i.ImplementationType!)))) | ||
{ | ||
var isEvent = target.Method.ReturnType == typeof(void); | ||
_logger.LogDebug("Find {type}: {path}", isEvent ? "Event" : "Method", target.Path); | ||
jsonRpc.AddLocalRpcMethod(target.Path, target.Method, target.Object); | ||
count++; | ||
} | ||
_logger.LogInformation("Loaded {count} JsonRPC Methods/Events.", count); | ||
return Task.CompletedTask; | ||
} | ||
|
||
public Task StopAsync(CancellationToken cancellationToken) | ||
{ | ||
return Task.CompletedTask; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/Shimakaze.Sdk.JsonRPC.Server/JsonRPCHostedServiceOptions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using StreamJsonRpc; | ||
|
||
namespace Shimakaze.Sdk.JsonRPC.Server; | ||
|
||
/// <summary> | ||
/// Options for JsonRPCHostedService | ||
/// </summary> | ||
public sealed class JsonRPCHostedServiceOptions | ||
{ | ||
/// <summary> | ||
/// Input Stream | ||
/// </summary> | ||
public Stream? Input { get; set; } | ||
/// <summary> | ||
/// Output Stream | ||
/// </summary> | ||
public Stream? Output { get; set; } | ||
/// <summary> | ||
/// JsonRpcMessageTextFormatter | ||
/// </summary> | ||
public IJsonRpcMessageTextFormatter? JsonRpcMessageTextFormatter { get; set; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
namespace Shimakaze.Sdk.JsonRPC.Server; | ||
|
||
/// <summary> | ||
/// 表示这是一个JsonRpc 方法/事件 | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Method)] | ||
public sealed class MethodAttribute : Attribute | ||
{ | ||
/// <summary> | ||
/// 这个方法/事件的路径 | ||
/// </summary> | ||
public string? Route { get; set; } | ||
/// <summary> | ||
/// 表示这是一个JsonRpc 方法/事件 | ||
/// </summary> | ||
/// <param name="route">这个方法/事件的路径</param> | ||
public MethodAttribute(string? route = null) | ||
{ | ||
Route = route; | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
src/Shimakaze.Sdk.JsonRPC.Server/Shimakaze.Sdk.JsonRPC.Server.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<ItemGroup> | ||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" /> | ||
<PackageReference Include="StreamJsonRpc" Version="2.14.24" /> | ||
</ItemGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
using System.Reflection; | ||
|
||
namespace Shimakaze.Sdk.JsonRPC.Server; | ||
|
||
internal sealed record Target(string Path, MethodInfo Method, object? Object); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using System.Reflection; | ||
using System.Text; | ||
using System.Text.RegularExpressions; | ||
|
||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Shimakaze.Sdk.JsonRPC.Server; | ||
|
||
/// <summary> | ||
/// JsonRpc Server Helper | ||
/// </summary> | ||
public static class TargetExtensions | ||
{ | ||
/// <summary> | ||
/// 添加所有的Handler | ||
/// </summary> | ||
/// <param name="services"></param> | ||
/// <param name="optionsBuilder"></param> | ||
/// <returns></returns> | ||
public static IServiceCollection AddJsonRpcHandlers(this IServiceCollection services, Action<JsonRPCHostedServiceOptions> optionsBuilder) | ||
{ | ||
foreach (var t in AppDomain | ||
.CurrentDomain | ||
.GetAssemblies() | ||
.SelectMany(asm => asm.GetTypes()) | ||
.Where(t => t.GetCustomAttribute<HandlerAttribute>() is not null)) | ||
services.AddTransient(t, t); | ||
|
||
return services | ||
.AddSingleton<JsonRPCHostedServiceOptions>(provider => | ||
{ | ||
JsonRPCHostedServiceOptions options; | ||
optionsBuilder(options = new()); | ||
return options; | ||
}) | ||
.AddHostedService<JsonRPCHostedService>(provider => new(services, provider)); | ||
} | ||
|
||
internal static IEnumerable<Target> GetTargets(this Type type, string? route, object? o) | ||
{ | ||
return type | ||
.GetMethods() | ||
.Select(m => (metadata: m.GetCustomAttribute<MethodAttribute>(), m)) | ||
.Where(i => i.metadata is not null) | ||
.Select(i => new Target(type.GetFullPath(route, i.metadata?.Route, i.m), i.m, o)); | ||
} | ||
|
||
private static string GetFullPath(this Type type, string? route, string? method, MethodInfo m) | ||
{ | ||
route ??= Regex.Replace(type.Name, "Handlers?|Controllers?", string.Empty); | ||
method ??= m.Name; | ||
if (method.StartsWith('/')) | ||
return method; | ||
|
||
StringBuilder sb = new(); | ||
if (!route.StartsWith('/')) | ||
sb.Append('/'); | ||
sb.Append(route); | ||
if (!route.EndsWith('/')) | ||
sb.Append('/'); | ||
|
||
sb.Append(method); | ||
return sb.ToString(); | ||
} | ||
} |