diff --git a/src/JT808.DotNetty/Configurations/JT808Configuration.cs b/src/JT808.DotNetty/Configurations/JT808Configuration.cs
index adbb104..4c73388 100644
--- a/src/JT808.DotNetty/Configurations/JT808Configuration.cs
+++ b/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;
+
+ ///
+ /// WebAPI服务
+ /// 默认828端口
+ ///
+ public int WebAPIPort { get; set; } = 828;
+
///
/// 会话报时
/// 默认5分钟
diff --git a/src/JT808.DotNetty/Dtos/JT808DefaultResultDto.cs b/src/JT808.DotNetty/Dtos/JT808DefaultResultDto.cs
new file mode 100644
index 0000000..58b18dc
--- /dev/null
+++ b/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
+ {
+ public JT808DefaultResultDto()
+ {
+ Data = "Hello,JT808 WebAPI";
+ Code = 200;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty/Handlers/JT808WebAPIServerHandler.cs b/src/JT808.DotNetty/Handlers/JT808WebAPIServerHandler.cs
new file mode 100644
index 0000000..f30e557
--- /dev/null
+++ b/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
+{
+ ///
+ /// jt808 webapi服务
+ /// 请求量不大,只支持JSON格式
+ /// ref: dotnetty HttpServer
+ ///
+ internal class JT808WebAPIServerHandler : ChannelHandlerAdapter
+ {
+ private static readonly ThreadLocalCache Cache = new ThreadLocalCache();
+
+ sealed class ThreadLocalCache : FastThreadLocal
+ {
+ 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 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();
+ }
+
+ 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();
+ }
+}
diff --git a/src/JT808.DotNetty/JT808.DotNetty.csproj b/src/JT808.DotNetty/JT808.DotNetty.csproj
index 608982c..11c8ee7 100644
--- a/src/JT808.DotNetty/JT808.DotNetty.csproj
+++ b/src/JT808.DotNetty/JT808.DotNetty.csproj
@@ -7,11 +7,10 @@
+
-
-
diff --git a/src/JT808.DotNetty/JT808DotnettyExtensions.cs b/src/JT808.DotNetty/JT808DotnettyExtensions.cs
index bbefa67..4951a61 100644
--- a/src/JT808.DotNetty/JT808DotnettyExtensions.cs
+++ b/src/JT808.DotNetty/JT808DotnettyExtensions.cs
@@ -24,24 +24,12 @@ namespace JT808.DotNetty
services.TryAddScoped();
services.TryAddScoped();
services.TryAddScoped();
+ services.TryAddScoped();
services.TryAddSingleton();
services.TryAddSingleton();
services.AddHostedService();
+ services.AddHostedService();
});
}
-
- public static void UseJT808Host(this IServiceCollection serviceDescriptors, HostBuilderContext hostContext)
- {
- serviceDescriptors.Configure(hostContext.Configuration.GetSection("JT808Configuration"));
- serviceDescriptors.TryAddSingleton();
- serviceDescriptors.TryAddSingleton();
- serviceDescriptors.TryAddSingleton();
- serviceDescriptors.TryAddScoped();
- serviceDescriptors.TryAddScoped();
- serviceDescriptors.TryAddScoped();
- serviceDescriptors.TryAddSingleton();
- serviceDescriptors.TryAddSingleton();
- serviceDescriptors.AddHostedService();
- }
}
}
\ No newline at end of file
diff --git a/src/JT808.DotNetty/JT808ServerHost.cs b/src/JT808.DotNetty/JT808ServerHost.cs
index 4ae3e94..1674583 100644
--- a/src/JT808.DotNetty/JT808ServerHost.cs
+++ b/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 logger;
private DispatcherEventLoopGroup bossGroup;
@@ -35,7 +35,7 @@ namespace JT808.DotNetty
ILoggerFactory loggerFactory,
IOptions jT808ConfigurationAccessor)
{
- Provider = provider;
+ serviceProvider = provider;
configuration = jT808ConfigurationAccessor.Value;
logger=loggerFactory.CreateLogger();
}
@@ -59,7 +59,7 @@ namespace JT808.DotNetty
.ChildHandler(new ActionChannelInitializer(channel =>
{
IChannelPipeline pipeline = channel.Pipeline;
- using(var scope= Provider.CreateScope())
+ using (var scope = serviceProvider.CreateScope())
{
channel.Pipeline.AddLast("systemIdleState", new IdleStateHandler(
configuration.ReaderIdleTimeSeconds,
diff --git a/src/JT808.DotNetty/JT808WebAPIServerHost.cs b/src/JT808.DotNetty/JT808WebAPIServerHost.cs
new file mode 100644
index 0000000..6e0c39c
--- /dev/null
+++ b/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
+{
+ ///
+ /// 集成一个webapi服务
+ ///
+ internal class JT808WebAPIServerHost : IHostedService
+ {
+ private readonly IServiceProvider serviceProvider;
+ private readonly JT808Configuration configuration;
+ private readonly ILogger logger;
+ private DispatcherEventLoopGroup bossGroup;
+ private WorkerEventLoopGroup workerGroup;
+ private IChannel bootstrapChannel;
+
+ public JT808WebAPIServerHost(
+ IServiceProvider provider,
+ ILoggerFactory loggerFactory,
+ IOptions jT808ConfigurationAccessor)
+ {
+ serviceProvider = provider;
+ configuration = jT808ConfigurationAccessor.Value;
+ logger = loggerFactory.CreateLogger();
+ }
+
+ public Task StartAsync(CancellationToken cancellationToken)
+ {
+ bossGroup = new DispatcherEventLoopGroup();
+ workerGroup = new WorkerEventLoopGroup(bossGroup, 1);
+ ServerBootstrap bootstrap = new ServerBootstrap();
+ bootstrap.Group(bossGroup, workerGroup);
+ bootstrap.Channel();
+ 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(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());
+ }
+ }));
+ 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);
+ }
+ }
+}
diff --git a/src/JT808.DotNetty/JT808WebHostBuilderKestrelExtensions.cs b/src/JT808.DotNetty/JT808WebHostBuilderKestrelExtensions.cs
deleted file mode 100644
index dbcfc73..0000000
--- a/src/JT808.DotNetty/JT808WebHostBuilderKestrelExtensions.cs
+++ /dev/null
@@ -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
- {
- ///
- /// Specify Kestrel as the server to be used by the web host.
- ///
- ///
- /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure.
- ///
- ///
- /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder.
- ///
- public static IHostBuilder UseKestrel(this IHostBuilder hostBuilder, Action options)
- {
- return hostBuilder.ConfigureServices((context,services) =>
- {
- services.Configure(options);
- // Don't override an already-configured transport
- services.TryAddSingleton();
- services.AddTransient, KestrelServerOptionsSetup>();
- services.AddSingleton();
- });
- }
- }
-}