ソースを参照

集成轻量级webapi接口

tags/v1.0.0
SmallChi 6年前
コミット
004e4b0fc6
8個のファイルの変更230行の追加61行の削除
  1. +7
    -0
      src/JT808.DotNetty/Configurations/JT808Configuration.cs
  2. +15
    -0
      src/JT808.DotNetty/Dtos/JT808DefaultResultDto.cs
  3. +119
    -0
      src/JT808.DotNetty/Handlers/JT808WebAPIServerHandler.cs
  4. +1
    -2
      src/JT808.DotNetty/JT808.DotNetty.csproj
  5. +2
    -14
      src/JT808.DotNetty/JT808DotnettyExtensions.cs
  6. +4
    -4
      src/JT808.DotNetty/JT808ServerHost.cs
  7. +82
    -0
      src/JT808.DotNetty/JT808WebAPIServerHost.cs
  8. +0
    -41
      src/JT808.DotNetty/JT808WebHostBuilderKestrelExtensions.cs

+ 7
- 0
src/JT808.DotNetty/Configurations/JT808Configuration.cs ファイルの表示

@@ -25,6 +25,13 @@ namespace JT808.DotNetty.Configurations
public int WriterIdleTimeSeconds { get; set; } = 3600;

public int AllIdleTimeSeconds { get; set; } = 3600;

/// <summary>
/// WebAPI服务
/// 默认828端口
/// </summary>
public int WebAPIPort { get; set; } = 828;

/// <summary>
/// 会话报时
/// 默认5分钟


+ 15
- 0
src/JT808.DotNetty/Dtos/JT808DefaultResultDto.cs ファイルの表示

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.Dtos
{
public class JT808DefaultResultDto: JT808ResultDto<string>
{
public JT808DefaultResultDto()
{
Data = "Hello,JT808 WebAPI";
Code = 200;
}
}
}

+ 119
- 0
src/JT808.DotNetty/Handlers/JT808WebAPIServerHandler.cs ファイルの表示

@@ -0,0 +1,119 @@
using DotNetty.Buffers;
using DotNetty.Codecs.Http;
using DotNetty.Common;
using DotNetty.Common.Utilities;
using DotNetty.Transport.Channels;
using JT808.DotNetty.Dtos;
using JT808.DotNetty.Interfaces;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.Handlers
{
/// <summary>
/// jt808 webapi服务
/// 请求量不大,只支持JSON格式
/// ref: dotnetty HttpServer
/// </summary>
internal class JT808WebAPIServerHandler : ChannelHandlerAdapter
{
private static readonly ThreadLocalCache Cache = new ThreadLocalCache();

sealed class ThreadLocalCache : FastThreadLocal<AsciiString>
{
protected override AsciiString GetInitialValue()
{
DateTime dateTime = DateTime.UtcNow;
return AsciiString.Cached($"{dateTime.DayOfWeek}, {dateTime:dd MMM yyyy HH:mm:ss z}");
}
}

private static readonly AsciiString TypeJson = AsciiString.Cached("application/json");
private static readonly AsciiString ServerName = AsciiString.Cached("JT808WebAPINetty");
private static readonly AsciiString ContentTypeEntity = HttpHeaderNames.ContentType;
private static readonly AsciiString DateEntity = HttpHeaderNames.Date;
private static readonly AsciiString ContentLengthEntity = HttpHeaderNames.ContentLength;
private static readonly AsciiString ServerEntity = HttpHeaderNames.Server;

volatile ICharSequence date = Cache.Value;

private readonly ILogger<JT808WebAPIServerHandler> logger;

private readonly IJT808SessionService jT808SessionService;

private readonly IJT808UnificationSendService jT808UnificationSendService;

public JT808WebAPIServerHandler(
IJT808SessionService jT808SessionService,
IJT808UnificationSendService jT808UnificationSendService,
ILoggerFactory loggerFactory)
{
this.jT808SessionService = jT808SessionService;
this.jT808UnificationSendService = jT808UnificationSendService;
logger = loggerFactory.CreateLogger<JT808WebAPIServerHandler>();
}

public override void ChannelRead(IChannelHandlerContext ctx, object message)
{
if (message is IHttpRequest request)
{
try
{
Process(ctx, request);
}
finally
{
ReferenceCountUtil.Release(message);
}
}
else
{
ctx.FireChannelRead(message);
}
}

private void Process(IChannelHandlerContext ctx, IHttpRequest request)
{
string uri = request.Uri;
//switch (uri)
//{
// //case "/json":
// // byte[] json = Encoding.UTF8.GetBytes(NewMessage().ToJsonFormat());
// // this.WriteResponse(ctx, Unpooled.WrappedBuffer(json), TypeJson, JsonClheaderValue);
// // break;
// default:
// var response = new DefaultFullHttpResponse(HttpVersion.Http11, HttpResponseStatus.NotFound, Unpooled.Empty, false);
// ctx.WriteAndFlushAsync(response);
// ctx.CloseAsync();
// break;
//}
byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT808DefaultResultDto()));
this.WriteResponse(ctx, Unpooled.WrappedBuffer(json), TypeJson, json.Length);
}

private void WriteResponse(IChannelHandlerContext ctx, IByteBuffer buf, ICharSequence contentType, int contentLength)
{
// Build the response object.
var response = new DefaultFullHttpResponse(HttpVersion.Http11, HttpResponseStatus.OK, buf, false);
HttpHeaders headers = response.Headers;
headers.Set(ContentTypeEntity, contentType);
headers.Set(ServerEntity, ServerName);
headers.Set(DateEntity, this.date);
headers.Set(ContentLengthEntity, contentLength);
// Close the non-keep-alive connection after the write operation is done.
ctx.WriteAsync(response);
}

public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
{
string channelId = context.Channel.Id.AsShortText();
logger.LogError(exception, $"{channelId} {exception.Message}");
context.CloseAsync();
}

public override void ChannelReadComplete(IChannelHandlerContext context) => context.Flush();
}
}

+ 1
- 2
src/JT808.DotNetty/JT808.DotNetty.csproj ファイルの表示

@@ -7,11 +7,10 @@

<ItemGroup>
<PackageReference Include="DotNetty.Codecs" Version="0.6.0" />
<PackageReference Include="DotNetty.Codecs.Http" Version="0.6.0" />
<PackageReference Include="DotNetty.Handlers" Version="0.6.0" />
<PackageReference Include="DotNetty.Transport.Libuv" Version="0.6.0" />
<PackageReference Include="JT808" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Core" Version="2.1.3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Options" Version="2.1.1" />


+ 2
- 14
src/JT808.DotNetty/JT808DotnettyExtensions.cs ファイルの表示

@@ -24,24 +24,12 @@ namespace JT808.DotNetty
services.TryAddScoped<JT808ConnectionHandler>();
services.TryAddScoped<JT808Decoder>();
services.TryAddScoped<JT808ServerHandler>();
services.TryAddScoped<JT808WebAPIServerHandler>();
services.TryAddSingleton<IJT808SessionService, JT808SessionServiceDefaultImpl>();
services.TryAddSingleton<IJT808UnificationSendService, JT808UnificationSendServiceDefaultImpl>();
services.AddHostedService<JT808ServerHost>();
services.AddHostedService<JT808WebAPIServerHost>();
});
}

public static void UseJT808Host(this IServiceCollection serviceDescriptors, HostBuilderContext hostContext)
{
serviceDescriptors.Configure<JT808Configuration>(hostContext.Configuration.GetSection("JT808Configuration"));
serviceDescriptors.TryAddSingleton<JT808SessionManager>();
serviceDescriptors.TryAddSingleton<JT808MsgIdHandlerBase, JT808MsgIdDefaultHandler>();
serviceDescriptors.TryAddSingleton<IJT808SourcePackageDispatcher, JT808SourcePackageDispatcherDefaultImpl>();
serviceDescriptors.TryAddScoped<JT808ConnectionHandler>();
serviceDescriptors.TryAddScoped<JT808Decoder>();
serviceDescriptors.TryAddScoped<JT808ServerHandler>();
serviceDescriptors.TryAddSingleton<IJT808SessionService, JT808SessionServiceDefaultImpl>();
serviceDescriptors.TryAddSingleton<IJT808UnificationSendService, JT808UnificationSendServiceDefaultImpl>();
serviceDescriptors.AddHostedService<JT808ServerHost>();
}
}
}

+ 4
- 4
src/JT808.DotNetty/JT808ServerHost.cs ファイルの表示

@@ -21,9 +21,9 @@ using System.Threading.Tasks;

namespace JT808.DotNetty
{
public class JT808ServerHost : IHostedService
internal class JT808ServerHost : IHostedService
{
public IServiceProvider Provider { get; }
private readonly IServiceProvider serviceProvider;
private readonly JT808Configuration configuration;
private readonly ILogger<JT808ServerHost> logger;
private DispatcherEventLoopGroup bossGroup;
@@ -35,7 +35,7 @@ namespace JT808.DotNetty
ILoggerFactory loggerFactory,
IOptions<JT808Configuration> jT808ConfigurationAccessor)
{
Provider = provider;
serviceProvider = provider;
configuration = jT808ConfigurationAccessor.Value;
logger=loggerFactory.CreateLogger<JT808ServerHost>();
}
@@ -59,7 +59,7 @@ namespace JT808.DotNetty
.ChildHandler(new ActionChannelInitializer<IChannel>(channel =>
{
IChannelPipeline pipeline = channel.Pipeline;
using(var scope= Provider.CreateScope())
using (var scope = serviceProvider.CreateScope())
{
channel.Pipeline.AddLast("systemIdleState", new IdleStateHandler(
configuration.ReaderIdleTimeSeconds,


+ 82
- 0
src/JT808.DotNetty/JT808WebAPIServerHost.cs ファイルの表示

@@ -0,0 +1,82 @@
using DotNetty.Codecs.Http;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Libuv;
using JT808.DotNetty.Configurations;
using JT808.DotNetty.Handlers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace JT808.DotNetty
{
/// <summary>
/// 集成一个webapi服务
/// </summary>
internal class JT808WebAPIServerHost : IHostedService
{
private readonly IServiceProvider serviceProvider;
private readonly JT808Configuration configuration;
private readonly ILogger<JT808WebAPIServerHost> logger;
private DispatcherEventLoopGroup bossGroup;
private WorkerEventLoopGroup workerGroup;
private IChannel bootstrapChannel;

public JT808WebAPIServerHost(
IServiceProvider provider,
ILoggerFactory loggerFactory,
IOptions<JT808Configuration> jT808ConfigurationAccessor)
{
serviceProvider = provider;
configuration = jT808ConfigurationAccessor.Value;
logger = loggerFactory.CreateLogger<JT808WebAPIServerHost>();
}

public Task StartAsync(CancellationToken cancellationToken)
{
bossGroup = new DispatcherEventLoopGroup();
workerGroup = new WorkerEventLoopGroup(bossGroup, 1);
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.Group(bossGroup, workerGroup);
bootstrap.Channel<TcpServerChannel>();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
|| RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
bootstrap
.Option(ChannelOption.SoReuseport, true)
.ChildOption(ChannelOption.SoReuseaddr, true);
}
bootstrap
.Option(ChannelOption.SoBacklog, 8192)
.ChildHandler(new ActionChannelInitializer<IChannel>(channel =>
{
IChannelPipeline pipeline = channel.Pipeline;
using (var scope = serviceProvider.CreateScope())
{
pipeline.AddLast("encoder", new HttpResponseEncoder());
pipeline.AddLast("decoder", new HttpRequestDecoder(4096, 8192, 8192, false));
pipeline.AddLast("jt808webapihandler", scope.ServiceProvider.GetRequiredService<JT808WebAPIServerHandler>());
}
}));
logger.LogInformation($"WebAPI Server start at {IPAddress.Any}:{configuration.WebAPIPort}.");
return bootstrap.BindAsync(configuration.WebAPIPort).ContinueWith(i => bootstrapChannel = i.Result);
}

public async Task StopAsync(CancellationToken cancellationToken)
{
await bootstrapChannel.CloseAsync();
var quietPeriod = configuration.QuietPeriodTimeSpan;
var shutdownTimeout = configuration.ShutdownTimeoutTimeSpan;
await workerGroup.ShutdownGracefullyAsync(quietPeriod, shutdownTimeout);
await bossGroup.ShutdownGracefullyAsync(quietPeriod, shutdownTimeout);
}
}
}

+ 0
- 41
src/JT808.DotNetty/JT808WebHostBuilderKestrelExtensions.cs ファイルの表示

@@ -1,41 +0,0 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection.Abstractions;
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting.Server;

namespace JT808.DotNetty
{
public static class JT808WebHostBuilderKestrelExtensions
{
/// <summary>
/// Specify Kestrel as the server to be used by the web host.
/// </summary>
/// <param name="hostBuilder">
/// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure.
/// </param>
/// <returns>
/// The Microsoft.AspNetCore.Hosting.IWebHostBuilder.
/// </returns>
public static IHostBuilder UseKestrel(this IHostBuilder hostBuilder, Action<KestrelServerOptions> options)
{
return hostBuilder.ConfigureServices((context,services) =>
{
services.Configure(options);
// Don't override an already-configured transport
services.TryAddSingleton<ITransportFactory, SocketTransportFactory>();
services.AddTransient<IConfigureOptions<KestrelServerOptions>, KestrelServerOptionsSetup>();
services.AddSingleton<IServer, KestrelServer>();
});
}
}
}

読み込み中…
キャンセル
保存