diff --git a/src/JT809.DotNetty.Abstractions/Dtos/JT809DefaultResultDto.cs b/src/JT809.DotNetty.Abstractions/Dtos/JT809DefaultResultDto.cs new file mode 100644 index 0000000..67c57b4 --- /dev/null +++ b/src/JT809.DotNetty.Abstractions/Dtos/JT809DefaultResultDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT809.DotNetty.Abstractions.Dtos +{ + public class JT809DefaultResultDto: JT809ResultDto + { + public JT809DefaultResultDto() + { + Data = "Hello,JT809 Superior WebAPI"; + Code = JT809ResultCode.Ok; + } + } +} diff --git a/src/JT809.DotNetty.Abstractions/Dtos/JT809HealthCheckDto.cs b/src/JT809.DotNetty.Abstractions/Dtos/JT809HealthCheckDto.cs new file mode 100644 index 0000000..a1bdfa1 --- /dev/null +++ b/src/JT809.DotNetty.Abstractions/Dtos/JT809HealthCheckDto.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT809.DotNetty.Abstractions.Dtos +{ + /// + /// 健康检查 + /// + public class JT809HealthCheckDto + { + /// + /// 主链路会话状态集合 + /// + public List MainSessions { get; set; } + /// + /// 从链路会话状态集合 + /// + public List SubordinateSessions { get; set; } + /// + /// 应用程序使用率 + /// + public JT809SystemCollectInfoDto SystemCollect { get; set; } + } +} diff --git a/src/JT809.DotNetty.Abstractions/Dtos/JT809ResultDto.cs b/src/JT809.DotNetty.Abstractions/Dtos/JT809ResultDto.cs new file mode 100644 index 0000000..2ea889e --- /dev/null +++ b/src/JT809.DotNetty.Abstractions/Dtos/JT809ResultDto.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT809.DotNetty.Abstractions.Dtos +{ + public class JT809ResultDto + { + public JT809ResultDto() + { + Code = JT809ResultCode.Ok; + } + + public string Message { get; set; } + + public int Code { get; set; } + + public T Data { get; set; } + } + + public class JT809ResultCode + { + public const int Ok = 200; + public const int Empty = 201; + public const int NotFound = 404; + public const int Fail = 400; + public const int Error = 500; + } +} diff --git a/src/JT809.DotNetty.Abstractions/Dtos/JT809SessionInfoDto.cs b/src/JT809.DotNetty.Abstractions/Dtos/JT809SessionInfoDto.cs new file mode 100644 index 0000000..3b8c24f --- /dev/null +++ b/src/JT809.DotNetty.Abstractions/Dtos/JT809SessionInfoDto.cs @@ -0,0 +1,28 @@ +using System; + +namespace JT809.DotNetty.Abstractions.Dtos +{ + public class JT809SessionInfoDto + { + /// + /// 最后上线时间 + /// + public string LastActiveTime { get; set; } + /// + /// 上线时间 + /// + public string StartTime { get; set; } + /// + /// 通道是否打开 + /// + public bool Open { get; set; } + /// + /// 通道是否活跃 + /// + public bool Active { get; set; } + /// + /// 远程IP地址 + /// + public string RemoteIP { get; set; } + } +} diff --git a/src/JT809.DotNetty.Abstractions/JT809Constants.cs b/src/JT809.DotNetty.Abstractions/JT809Constants.cs index f28f5b6..66586a4 100644 --- a/src/JT809.DotNetty.Abstractions/JT809Constants.cs +++ b/src/JT809.DotNetty.Abstractions/JT809Constants.cs @@ -6,7 +6,7 @@ public const string SessionOffline = "JT809SessionOffline"; - public static class JT809WebApiRouteTable + public static class JT809SuperiorWebApiRouteTable { public const string RouteTablePrefix = "/jt809api"; @@ -14,12 +14,19 @@ public const string SystemCollectPrefix = "SystemCollect"; - public const string TcpPrefix = "Tcp"; + public const string HealthCheck = "HealthCheck"; + + public const string Prefix = "Main"; /// ///获取当前系统进程使用率 /// - public static string SystemCollectGet = $"{RouteTablePrefix}/{SystemCollectPrefix}/Get"; + public static string SystemCollectGet = $"{RouteTablePrefix}/{Prefix}/{SystemCollectPrefix}"; + + /// + ///健康检查 + /// + public static string HealthCheckGet = $"{RouteTablePrefix}/{Prefix}/{HealthCheck}"; } } } diff --git a/src/JT809.DotNetty.Core/Clients/JT809SubordinateClient.cs b/src/JT809.DotNetty.Core/Clients/JT809SubordinateClient.cs index ae4d324..a6cacd9 100644 --- a/src/JT809.DotNetty.Core/Clients/JT809SubordinateClient.cs +++ b/src/JT809.DotNetty.Core/Clients/JT809SubordinateClient.cs @@ -30,7 +30,7 @@ namespace JT809.DotNetty.Core.Clients private MultithreadEventLoopGroup group; - private IChannel channel; + public IChannel Channel { get; private set; } private readonly ILogger logger; @@ -81,14 +81,14 @@ namespace JT809.DotNetty.Core.Clients await Task.Delay(delay); try { - if (channel == null) + if (Channel == null) { - channel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip), port)); + Channel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip), port)); } else { - await channel.CloseAsync(); - channel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip), port)); + await Channel.CloseAsync(); + Channel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip), port)); } } catch (AggregateException ex) @@ -103,11 +103,11 @@ namespace JT809.DotNetty.Core.Clients public async void SendAsync(JT809Response jT809Response) { - if (channel == null) throw new NullReferenceException("Channel Not Open"); + if (Channel == null) throw new NullReferenceException("Channel Not Open"); if (jT809Response == null) throw new ArgumentNullException("Data is null"); - if (channel.Open && channel.Active) + if (Channel.Open && Channel.Active) { - await channel.WriteAndFlushAsync(jT809Response); + await Channel.WriteAndFlushAsync(jT809Response); } } @@ -115,8 +115,8 @@ namespace JT809.DotNetty.Core.Clients { get { - if (channel == null) return false; - return channel.Open && channel.Active; + if (Channel == null) return false; + return Channel.Open && Channel.Active; } } @@ -136,7 +136,7 @@ namespace JT809.DotNetty.Core.Clients VerifyCode = verifyCodeGenerator.Get() }); JT809Response jT809Response = new JT809Response(package, 100); - channel.WriteAndFlushAsync(jT809Response); + Channel.WriteAndFlushAsync(jT809Response); logger.LogInformation($"发送从链路注销请求>>>{JT809Serializer.Serialize(package, 100).ToHexString()}"); } catch (Exception ex) @@ -146,7 +146,7 @@ namespace JT809.DotNetty.Core.Clients finally { //清理托管资源 - channel.CloseAsync(); + Channel.CloseAsync(); group.ShutdownGracefullyAsync(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(3)); } } diff --git a/src/JT809.DotNetty.Core/Configurations/JT809SuperiorPlatformOptions.cs b/src/JT809.DotNetty.Core/Configurations/JT809SuperiorPlatformOptions.cs index 37ca856..243628f 100644 --- a/src/JT809.DotNetty.Core/Configurations/JT809SuperiorPlatformOptions.cs +++ b/src/JT809.DotNetty.Core/Configurations/JT809SuperiorPlatformOptions.cs @@ -14,6 +14,8 @@ namespace JT809.DotNetty.Core.Configurations public int TcpPort { get; set; } = 819; + public int WebApiPort { get; set; } = 829; + public int QuietPeriodSeconds { get; set; } = 1; public TimeSpan QuietPeriodTimeSpan => TimeSpan.FromSeconds(QuietPeriodSeconds); diff --git a/src/JT809.DotNetty.Core/Handlers/JT809MainServerConnectionHandler.cs b/src/JT809.DotNetty.Core/Handlers/JT809MainServerConnectionHandler.cs index da4d1d6..2c0e147 100644 --- a/src/JT809.DotNetty.Core/Handlers/JT809MainServerConnectionHandler.cs +++ b/src/JT809.DotNetty.Core/Handlers/JT809MainServerConnectionHandler.cs @@ -1,5 +1,6 @@ using DotNetty.Handlers.Timeout; using DotNetty.Transport.Channels; +using JT809.DotNetty.Core.Session; using Microsoft.Extensions.Logging; using System; using System.Threading.Tasks; @@ -14,10 +15,14 @@ namespace JT809.DotNetty.Core.Handlers private readonly ILogger logger; + private readonly JT809SuperiorMainSessionManager jT809SuperiorMainSessionManager; + public JT809MainServerConnectionHandler( + JT809SuperiorMainSessionManager jT809SuperiorMainSessionManager, ILoggerFactory loggerFactory) { logger = loggerFactory.CreateLogger(); + this.jT809SuperiorMainSessionManager = jT809SuperiorMainSessionManager; } /// @@ -41,6 +46,7 @@ namespace JT809.DotNetty.Core.Handlers string channelId = context.Channel.Id.AsShortText(); if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug($">>>{ channelId } The client disconnects from the server."); + jT809SuperiorMainSessionManager.RemoveSessionByChannel(context.Channel); base.ChannelInactive(context); } @@ -54,6 +60,7 @@ namespace JT809.DotNetty.Core.Handlers string channelId = context.Channel.Id.AsShortText(); if (logger.IsEnabled(LogLevel.Debug)) logger.LogDebug($"<<<{ channelId } The server disconnects from the client."); + jT809SuperiorMainSessionManager.RemoveSessionByChannel(context.Channel); return base.CloseAsync(context); } @@ -81,6 +88,7 @@ namespace JT809.DotNetty.Core.Handlers { string channelId = context.Channel.Id.AsShortText(); logger.LogError(exception, $"{channelId} {exception.Message}"); + jT809SuperiorMainSessionManager.RemoveSessionByChannel(context.Channel); context.CloseAsync(); } } diff --git a/src/JT809.DotNetty.Core/Handlers/JT809SuperiorMsgIdReceiveHandlerBase.cs b/src/JT809.DotNetty.Core/Handlers/JT809SuperiorMsgIdReceiveHandlerBase.cs index 3ecd6bc..b07c561 100644 --- a/src/JT809.DotNetty.Core/Handlers/JT809SuperiorMsgIdReceiveHandlerBase.cs +++ b/src/JT809.DotNetty.Core/Handlers/JT809SuperiorMsgIdReceiveHandlerBase.cs @@ -9,6 +9,7 @@ using JT809.Protocol.Extensions; using JT809.Protocol.MessageBody; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Newtonsoft.Json; namespace JT809.DotNetty.Core.Handlers { @@ -39,11 +40,16 @@ namespace JT809.DotNetty.Core.Handlers {JT809BusinessType.主链路登录请求消息, Msg0x1001}, {JT809BusinessType.主链路注销请求消息, Msg0x1003}, {JT809BusinessType.主链路连接保持请求消息, Msg0x1005}, + {JT809BusinessType.主链路断开通知消息,Msg0x1007 }, {JT809BusinessType.主链路动态信息交换消息, Msg0x1200}, + {JT809BusinessType.下级平台主动关闭链路通知消息, Msg0x1008}, + {JT809BusinessType.从链路连接应答消息, Msg0x9002}, {JT809BusinessType.从链路注销应答消息, Msg0x9004}, - }; + {JT809BusinessType.从链路连接保持应答消息, Msg0x9006}, + + }; SubHandlerDict = new Dictionary> { //{JT809SubBusinessType.实时上传车辆定位信息, Msg0x1200_0x1202}, @@ -62,7 +68,7 @@ namespace JT809.DotNetty.Core.Handlers public virtual JT809Response Msg0x1001(JT809Request request) { var verifyCode = VerifyCodeGenerator.Create(); - Logger.LogInformation($"VerifyCode-{verifyCode}"); + Logger.LogInformation($"主链路登录请求消息:VerifyCode-{verifyCode}"); var package = JT809BusinessType.主链路登录应答消息.Create(new JT809_0x1002() { Result = JT809_0x1002_Result.成功, @@ -83,6 +89,8 @@ namespace JT809.DotNetty.Core.Handlers /// 主链路注销应答消息 public virtual JT809Response Msg0x1003(JT809Request request) { + var jT809_0x1003 = request.Package.Bodies as JT809_0x1003; + Logger.LogInformation(JsonConvert.SerializeObject(jT809_0x1003)); var package = JT809BusinessType.主链路注销应答消息.Create(); return new JT809Response(package, 100); } @@ -99,23 +107,73 @@ namespace JT809.DotNetty.Core.Handlers } /// - /// 主链路动态信息交换消息 + /// 主链路断开通知消息 /// /// - /// - public virtual JT809Response Msg0x1200(JT809Request request) + /// 本条消息无需被通知方应答 + public virtual JT809Response Msg0x1007(JT809Request request) + { + var jT809_0x1007 = request.Package.Bodies as JT809_0x1007; + Logger.LogInformation($"主链路断开通知消息:{jT809_0x1007.ErrorCode.ToString()}-{jT809_0x1007.ErrorCode}"); + return null; + } + + /// + /// 下级平台主动关闭链路通知消息 + /// + /// + /// 本条消息无需被通知方应答 + public virtual JT809Response Msg0x1008(JT809Request request) { + var jT809_0x1008 = request.Package.Bodies as JT809_0x1008; + Logger.LogInformation($"下级平台主动关闭链路通知消息:{jT809_0x1008.ReasonCode.ToString()}-{jT809_0x1008.ReasonCode}"); + return null; + } + /// + /// 从链路连接应答消息 + /// + /// + /// 本条消息无需被通知方应答 + public virtual JT809Response Msg0x9002(JT809Request request) + { + var jT809_0x9002 = request.Package.Bodies as JT809_0x9002; + Logger.LogInformation($"从链路连接应答消息:{jT809_0x9002.Result.ToString()}-{jT809_0x9002.Result}"); return null; } /// - /// + /// 从链路注销应答消息 /// /// - /// 从链路注销应答消息 + /// 本条消息无需被通知方应答 public virtual JT809Response Msg0x9004(JT809Request request) { + Logger.LogInformation("从链路注销应答消息"); + return null; + } + + /// + /// 从链路连接保持应答消息 + /// + /// + /// 本条消息无需被通知方应答 + public virtual JT809Response Msg0x9006(JT809Request request) + { + Logger.LogInformation("从链路连接保持应答消息"); + return null; + } + + + + /// + /// 主链路动态信息交换消息 + /// + /// + /// + public virtual JT809Response Msg0x1200(JT809Request request) + { + return null; } } diff --git a/src/JT809.DotNetty.Core/Handlers/JT809SuperiorWebAPIHandlerBase.cs b/src/JT809.DotNetty.Core/Handlers/JT809SuperiorWebAPIHandlerBase.cs new file mode 100644 index 0000000..5dc62aa --- /dev/null +++ b/src/JT809.DotNetty.Core/Handlers/JT809SuperiorWebAPIHandlerBase.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Text; +using JT809.DotNetty.Abstractions.Dtos; +using JT809.DotNetty.Core.Metadata; +using Newtonsoft.Json; + +namespace JT809.DotNetty.Core.Handlers +{ + /// + /// 上级平台 + /// 基于webapi http模式抽象消息处理业务 + /// 自定义消息处理业务 + /// 注意: + /// 1.ConfigureServices: + /// services.Replace(new ServiceDescriptor(typeof(JT809SuperiorWebAPIHandlerBase),typeof(JT809SuperiorWebAPICustomHandler),ServiceLifetime.Singleton)); + /// 2.解析具体的消息体,具体消息调用具体的JT809Serializer.Deserialize + /// + public abstract class JT809SuperiorWebAPIHandlerBase + { + /// + /// 初始化消息处理业务 + /// + protected JT809SuperiorWebAPIHandlerBase() + { + HandlerDict = new Dictionary>(); + } + + protected void CreateRoute(string url, Func func) + { + if (!HandlerDict.ContainsKey(url)) + { + HandlerDict.Add(url, func); + } + else + { + // 替换 + HandlerDict[url] = func; + } + } + + public Dictionary> HandlerDict { get; } + + protected JT809HttpResponse CreateJT809HttpResponse(dynamic dynamicObject) + { + byte[] data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(dynamicObject)); + return new JT809HttpResponse() + { + Data = data + }; + } + + public JT809HttpResponse DefaultHttpResponse() + { + byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT809DefaultResultDto())); + return new JT809HttpResponse(json); + } + + public JT809HttpResponse EmptyHttpResponse() + { + byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT809ResultDto() + { + Code = JT809ResultCode.Empty, + Message = "内容为空", + Data = "Content Empty" + })); + return new JT809HttpResponse(json); + } + + public JT809HttpResponse NotFoundHttpResponse() + { + byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT809ResultDto() + { + Code = JT809ResultCode.NotFound, + Message = "没有该服务", + Data = "没有该服务" + })); + return new JT809HttpResponse(json); + } + + public JT809HttpResponse ErrorHttpResponse(Exception ex) + { + byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT809ResultDto() + { + Code = JT809ResultCode.Error, + Message = JsonConvert.SerializeObject(ex), + Data = ex.Message + })); + return new JT809HttpResponse(json); + } + } +} diff --git a/src/JT809.DotNetty.Core/Handlers/JT809SuperiorWebAPIServerHandler.cs b/src/JT809.DotNetty.Core/Handlers/JT809SuperiorWebAPIServerHandler.cs new file mode 100644 index 0000000..6586d24 --- /dev/null +++ b/src/JT809.DotNetty.Core/Handlers/JT809SuperiorWebAPIServerHandler.cs @@ -0,0 +1,81 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.Http; +using DotNetty.Common.Utilities; +using DotNetty.Transport.Channels; +using JT809.DotNetty.Core.Metadata; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT809.DotNetty.Core.Handlers +{ + /// + /// 上级平台 + /// webapi处理 + /// + internal class JT809SuperiorWebAPIServerHandler : SimpleChannelInboundHandler + { + private static readonly AsciiString TypeJson = AsciiString.Cached("application/json"); + private static readonly AsciiString ServerName = AsciiString.Cached("JT809SuperiorWebAPINetty"); + 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; + private readonly JT809SuperiorWebAPIHandlerBase JT809SuperiorWebAPIHandler; + private readonly ILogger logger; + + public JT809SuperiorWebAPIServerHandler( + JT809SuperiorWebAPIHandlerBase jT809SuperiorWebAPIHandlerBase, + ILoggerFactory loggerFactory) + { + this.JT809SuperiorWebAPIHandler = jT809SuperiorWebAPIHandlerBase; + logger = loggerFactory.CreateLogger(); + } + + protected override void ChannelRead0(IChannelHandlerContext ctx, IFullHttpRequest msg) + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.LogDebug($"Uri:{msg.Uri}"); + logger.LogDebug($"Content:{msg.Content.ToString(Encoding.UTF8)}"); + } + JT809HttpResponse jT808HttpResponse = null; + if (JT809SuperiorWebAPIHandler.HandlerDict.TryGetValue(msg.Uri, out var funcHandler)) + { + jT808HttpResponse = funcHandler(new JT809HttpRequest() { Json = msg.Content.ToString(Encoding.UTF8) }); + } + else + { + jT808HttpResponse = JT809SuperiorWebAPIHandler.NotFoundHttpResponse(); + } + if (jT808HttpResponse != null) + { + WriteResponse(ctx, Unpooled.WrappedBuffer(jT808HttpResponse.Data), TypeJson, jT808HttpResponse.Data.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, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")); + headers.Set(ContentLengthEntity, contentLength); + // Close the non-keep-alive connection after the write operation is done. + ctx.WriteAndFlushAsync(response); + ctx.CloseAsync(); + } + + public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) + { + WriteResponse(context, Unpooled.WrappedBuffer(JT809SuperiorWebAPIHandler.ErrorHttpResponse(exception).Data), TypeJson, JT809SuperiorWebAPIHandler.ErrorHttpResponse(exception).Data.Length); + logger.LogError(exception, exception.Message); + context.CloseAsync(); + } + + public override void ChannelReadComplete(IChannelHandlerContext context) => context.Flush(); + } +} diff --git a/src/JT809.DotNetty.Core/Internal/JT809SuperiorWebAPIDefaultHandler.cs b/src/JT809.DotNetty.Core/Internal/JT809SuperiorWebAPIDefaultHandler.cs new file mode 100644 index 0000000..93fa313 --- /dev/null +++ b/src/JT809.DotNetty.Core/Internal/JT809SuperiorWebAPIDefaultHandler.cs @@ -0,0 +1,57 @@ +using JT809.DotNetty.Abstractions; +using JT809.DotNetty.Abstractions.Dtos; +using JT809.DotNetty.Core.Handlers; +using JT809.DotNetty.Core.Metadata; +using JT809.DotNetty.Core.Services; +using Newtonsoft.Json; + +namespace JT809.DotNetty.Core.Internal +{ + /// + /// 默认消息处理业务实现 + /// + public class JT809SuperiorWebAPIDefaultHandler : JT809SuperiorWebAPIHandlerBase + { + private readonly JT809SimpleSystemCollectService jT809SimpleSystemCollectService; + + public JT809SuperiorWebAPIDefaultHandler(JT809SimpleSystemCollectService jT809SimpleSystemCollectService) + { + this.jT809SimpleSystemCollectService = jT809SimpleSystemCollectService; + InitRoute(); + } + + /// + /// 统一下发信息 + /// + /// + /// + public JT809HttpResponse UnificationSend(JT809HttpRequest request) + { + if (string.IsNullOrEmpty(request.Json)) + { + return EmptyHttpResponse(); + } + //JT809UnificationSendRequestDto jT808UnificationSendRequestDto = JsonConvert.DeserializeObject(request.Json); + //var result = jT808UnificationTcpSendService.Send(jT808UnificationSendRequestDto.TerminalPhoneNo, jT808UnificationSendRequestDto.Data); + //return CreateJT808HttpResponse(result); + return null; + } + + /// + /// 获取当前系统进程使用率 + /// + /// + /// + public JT809HttpResponse SystemCollectGet(JT809HttpRequest request) + { + JT809ResultDto jT809ResultDto = new JT809ResultDto(); + jT809ResultDto.Data = jT809SimpleSystemCollectService.Get(); + return CreateJT809HttpResponse(jT809ResultDto); + } + + protected virtual void InitRoute() + { + CreateRoute(JT809Constants.JT809SuperiorWebApiRouteTable.SystemCollectGet, SystemCollectGet); + } + } +} diff --git a/src/JT809.DotNetty.Core/JT809.DotNetty.Core.csproj b/src/JT809.DotNetty.Core/JT809.DotNetty.Core.csproj index a5639ce..1b28832 100644 --- a/src/JT809.DotNetty.Core/JT809.DotNetty.Core.csproj +++ b/src/JT809.DotNetty.Core/JT809.DotNetty.Core.csproj @@ -7,13 +7,13 @@ - + @@ -24,9 +24,5 @@ - - - - diff --git a/src/JT809.DotNetty.Core/JT809CoreDotnettyExtensions.cs b/src/JT809.DotNetty.Core/JT809CoreDotnettyExtensions.cs index ed99112..b045fcb 100644 --- a/src/JT809.DotNetty.Core/JT809CoreDotnettyExtensions.cs +++ b/src/JT809.DotNetty.Core/JT809CoreDotnettyExtensions.cs @@ -17,10 +17,10 @@ using Newtonsoft.Json; using System; using System.Runtime.CompilerServices; using Microsoft.Extensions.Options; - +using JT808.DotNetty.WebApi; +using JT809.DotNetty.Core.Session; [assembly: InternalsVisibleTo("JT809.DotNetty.Core.Test")] -[assembly: InternalsVisibleTo("JT809.DotNetty.WebApi.Test")] namespace JT809.DotNetty.Core { @@ -107,7 +107,7 @@ namespace JT809.DotNetty.Core serviceDescriptors.TryAddScoped(); serviceDescriptors.TryAddScoped(); //主链路服务端会话管理 - //serviceDescriptors.TryAddSingleton(); + serviceDescriptors.TryAddSingleton(); //主从链路接收消息默认业务处理器 serviceDescriptors.TryAddSingleton(); //主从链路消息接收处理器 @@ -117,6 +117,10 @@ namespace JT809.DotNetty.Core serviceDescriptors.TryAddSingleton(); //主链路服务端 serviceDescriptors.AddHostedService(); + //上级平台webapi + serviceDescriptors.TryAddSingleton(); + serviceDescriptors.TryAddScoped(); + serviceDescriptors.AddHostedService(); return serviceDescriptors; } } diff --git a/src/JT809.DotNetty.Core/Metadata/JT809HttpRequest.cs b/src/JT809.DotNetty.Core/Metadata/JT809HttpRequest.cs new file mode 100644 index 0000000..5599d54 --- /dev/null +++ b/src/JT809.DotNetty.Core/Metadata/JT809HttpRequest.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace JT809.DotNetty.Core.Metadata +{ + public class JT809HttpRequest + { + public string Json { get; set; } + + public JT809HttpRequest() + { + + } + + public JT809HttpRequest(string json) + { + Json = json; + } + } +} \ No newline at end of file diff --git a/src/JT809.DotNetty.Core/Metadata/JT809HttpResponse.cs b/src/JT809.DotNetty.Core/Metadata/JT809HttpResponse.cs new file mode 100644 index 0000000..17c2cbc --- /dev/null +++ b/src/JT809.DotNetty.Core/Metadata/JT809HttpResponse.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace JT809.DotNetty.Core.Metadata +{ + public class JT809HttpResponse + { + public byte[] Data { get; set; } + + public JT809HttpResponse() + { + + } + + public JT809HttpResponse(byte[] data) + { + this.Data = data; + } + } +} \ No newline at end of file diff --git a/src/JT809.DotNetty.Core/Metadata/JT809Session.cs b/src/JT809.DotNetty.Core/Metadata/JT809Session.cs index e8a86a8..26b3370 100644 --- a/src/JT809.DotNetty.Core/Metadata/JT809Session.cs +++ b/src/JT809.DotNetty.Core/Metadata/JT809Session.cs @@ -19,7 +19,7 @@ namespace JT809.DotNetty.Core.Metadata /// public uint MsgGNSSCENTERID { get; set; } - public IChannel Channel { get;} + public IChannel Channel { get; set; } public DateTime LastActiveTime { get; set; } diff --git a/src/JT809.DotNetty.Core/Servers/JT809MainWebAPIServerHost.cs b/src/JT809.DotNetty.Core/Servers/JT809MainWebAPIServerHost.cs new file mode 100644 index 0000000..dd40223 --- /dev/null +++ b/src/JT809.DotNetty.Core/Servers/JT809MainWebAPIServerHost.cs @@ -0,0 +1,82 @@ +using DotNetty.Codecs.Http; +using DotNetty.Transport.Bootstrapping; +using DotNetty.Transport.Channels; +using DotNetty.Transport.Libuv; +using JT809.DotNetty.Core.Configurations; +using JT809.DotNetty.Core.Handlers; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Net; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +namespace JT808.DotNetty.WebApi +{ + /// + /// JT809 集成一个webapi服务 + /// + internal class JT809MainWebAPIServerHost : IHostedService + { + private readonly IServiceProvider serviceProvider; + private readonly ILogger logger; + private DispatcherEventLoopGroup bossGroup; + private WorkerEventLoopGroup workerGroup; + private IChannel bootstrapChannel; + private readonly JT809SuperiorPlatformOptions configuration; + + public JT809MainWebAPIServerHost( + IServiceProvider provider, + IOptions jT809SuperiorPlatformOptionsAccessor, + ILoggerFactory loggerFactory) + { + serviceProvider = provider; + configuration = jT809SuperiorPlatformOptionsAccessor.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("http_encoder", new HttpResponseEncoder()); + pipeline.AddLast("http_decoder", new HttpRequestDecoder(4096, 8192, 8192, false)); + //将多个消息转换为单一的request或者response对象 =>IFullHttpRequest + pipeline.AddLast("http_aggregator", new HttpObjectAggregator(65536)); + pipeline.AddLast("http_jt809webapihandler", scope.ServiceProvider.GetRequiredService()); + } + })); + logger.LogInformation($"JT809 Superior 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/JT809.DotNetty.Core/Services/JT809SimpleSystemCollectService.cs b/src/JT809.DotNetty.Core/Services/JT809SimpleSystemCollectService.cs index 143e7c5..3507a5b 100644 --- a/src/JT809.DotNetty.Core/Services/JT809SimpleSystemCollectService.cs +++ b/src/JT809.DotNetty.Core/Services/JT809SimpleSystemCollectService.cs @@ -9,7 +9,7 @@ namespace JT809.DotNetty.Core.Services /// /// 简单系统收集服务 /// - internal class JT809SimpleSystemCollectService + public class JT809SimpleSystemCollectService { /// /// 获取系统当前进程使用情况 diff --git a/src/JT809.DotNetty.Core/Session/JT809MainSessionManager.cs b/src/JT809.DotNetty.Core/Session/JT809SuperiorMainSessionManager.cs similarity index 78% rename from src/JT809.DotNetty.Core/Session/JT809MainSessionManager.cs rename to src/JT809.DotNetty.Core/Session/JT809SuperiorMainSessionManager.cs index 7611479..4b22aa1 100644 --- a/src/JT809.DotNetty.Core/Session/JT809MainSessionManager.cs +++ b/src/JT809.DotNetty.Core/Session/JT809SuperiorMainSessionManager.cs @@ -4,26 +4,26 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using DotNetty.Transport.Channels; -using JT809.DotNetty.Abstractions; using JT809.DotNetty.Core.Metadata; namespace JT809.DotNetty.Core.Session { /// - /// JT809 主链路会话管理 + /// 上级平台 + /// JT809主链路会话管理 /// - public class JT809MainSessionManager + public class JT809SuperiorMainSessionManager { - private readonly ILogger logger; + private readonly ILogger logger; //private readonly IJT809SessionPublishing jT809SessionPublishing; - public JT809MainSessionManager( + public JT809SuperiorMainSessionManager( //IJT809SessionPublishing jT809SessionPublishing, ILoggerFactory loggerFactory) { //this.jT809SessionPublishing = jT809SessionPublishing; - logger = loggerFactory.CreateLogger(); + logger = loggerFactory.CreateLogger(); } private ConcurrentDictionary SessionIdDict = new ConcurrentDictionary(); @@ -48,20 +48,17 @@ namespace JT809.DotNetty.Core.Session } } - public void Heartbeat(uint msgGNSSCENTERID) + public void TryAdd(IChannel channel, uint msgGNSSCENTERID) { - if (SessionIdDict.TryGetValue(msgGNSSCENTERID, out JT809Session oldjT808Session)) + if(SessionIdDict.TryGetValue(msgGNSSCENTERID,out JT809Session jT809Session)) { - oldjT808Session.LastActiveTime = DateTime.Now; - SessionIdDict.TryUpdate(msgGNSSCENTERID, oldjT808Session, oldjT808Session); + jT809Session.LastActiveTime = DateTime.Now; + jT809Session.Channel = channel; + SessionIdDict.TryUpdate(msgGNSSCENTERID, jT809Session, jT809Session); } - } - - public void TryAdd(IChannel channel, uint msgGNSSCENTERID) - { - if (SessionIdDict.ContainsKey(msgGNSSCENTERID)) return; - if (SessionIdDict.TryAdd(msgGNSSCENTERID, new JT809Session(channel, msgGNSSCENTERID))) + else { + SessionIdDict.TryAdd(msgGNSSCENTERID, new JT809Session(channel, msgGNSSCENTERID)); //jT809SessionPublishing.PublishAsync(JT809Constants.SessionOnline, msgGNSSCENTERID.ToString()); } }