@@ -0,0 +1,15 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.DotNetty.Abstractions.Dtos | |||
{ | |||
public class JT809DefaultResultDto: JT809ResultDto<string> | |||
{ | |||
public JT809DefaultResultDto() | |||
{ | |||
Data = "Hello,JT809 Superior WebAPI"; | |||
Code = JT809ResultCode.Ok; | |||
} | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.DotNetty.Abstractions.Dtos | |||
{ | |||
/// <summary> | |||
/// 健康检查 | |||
/// </summary> | |||
public class JT809HealthCheckDto | |||
{ | |||
/// <summary> | |||
/// 主链路会话状态集合 | |||
/// </summary> | |||
public List<JT809SessionInfoDto> MainSessions { get; set; } | |||
/// <summary> | |||
/// 从链路会话状态集合 | |||
/// </summary> | |||
public List<JT809SessionInfoDto> SubordinateSessions { get; set; } | |||
/// <summary> | |||
/// 应用程序使用率 | |||
/// </summary> | |||
public JT809SystemCollectInfoDto SystemCollect { get; set; } | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.DotNetty.Abstractions.Dtos | |||
{ | |||
public class JT809ResultDto<T> | |||
{ | |||
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; | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
using System; | |||
namespace JT809.DotNetty.Abstractions.Dtos | |||
{ | |||
public class JT809SessionInfoDto | |||
{ | |||
/// <summary> | |||
/// 最后上线时间 | |||
/// </summary> | |||
public string LastActiveTime { get; set; } | |||
/// <summary> | |||
/// 上线时间 | |||
/// </summary> | |||
public string StartTime { get; set; } | |||
/// <summary> | |||
/// 通道是否打开 | |||
/// </summary> | |||
public bool Open { get; set; } | |||
/// <summary> | |||
/// 通道是否活跃 | |||
/// </summary> | |||
public bool Active { get; set; } | |||
/// <summary> | |||
/// 远程IP地址 | |||
/// </summary> | |||
public string RemoteIP { get; set; } | |||
} | |||
} |
@@ -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"; | |||
/// <summary> | |||
///获取当前系统进程使用率 | |||
/// </summary> | |||
public static string SystemCollectGet = $"{RouteTablePrefix}/{SystemCollectPrefix}/Get"; | |||
public static string SystemCollectGet = $"{RouteTablePrefix}/{Prefix}/{SystemCollectPrefix}"; | |||
/// <summary> | |||
///健康检查 | |||
/// </summary> | |||
public static string HealthCheckGet = $"{RouteTablePrefix}/{Prefix}/{HealthCheck}"; | |||
} | |||
} | |||
} |
@@ -30,7 +30,7 @@ namespace JT809.DotNetty.Core.Clients | |||
private MultithreadEventLoopGroup group; | |||
private IChannel channel; | |||
public IChannel Channel { get; private set; } | |||
private readonly ILogger<JT809SubordinateClient> 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)); | |||
} | |||
} | |||
@@ -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); | |||
@@ -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<JT809MainServerConnectionHandler> logger; | |||
private readonly JT809SuperiorMainSessionManager jT809SuperiorMainSessionManager; | |||
public JT809MainServerConnectionHandler( | |||
JT809SuperiorMainSessionManager jT809SuperiorMainSessionManager, | |||
ILoggerFactory loggerFactory) | |||
{ | |||
logger = loggerFactory.CreateLogger<JT809MainServerConnectionHandler>(); | |||
this.jT809SuperiorMainSessionManager = jT809SuperiorMainSessionManager; | |||
} | |||
/// <summary> | |||
@@ -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(); | |||
} | |||
} | |||
@@ -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, Func<JT809Request, JT809Response>> | |||
{ | |||
//{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 | |||
/// <returns>主链路注销应答消息</returns> | |||
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 | |||
} | |||
/// <summary> | |||
/// 主链路动态信息交换消息 | |||
/// 主链路断开通知消息 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public virtual JT809Response Msg0x1200(JT809Request request) | |||
/// <returns>本条消息无需被通知方应答</returns> | |||
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; | |||
} | |||
/// <summary> | |||
/// 下级平台主动关闭链路通知消息 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns>本条消息无需被通知方应答</returns> | |||
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; | |||
} | |||
/// <summary> | |||
/// 从链路连接应答消息 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns>本条消息无需被通知方应答</returns> | |||
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; | |||
} | |||
/// <summary> | |||
/// | |||
/// 从链路注销应答消息 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns>从链路注销应答消息</returns> | |||
/// <returns>本条消息无需被通知方应答</returns> | |||
public virtual JT809Response Msg0x9004(JT809Request request) | |||
{ | |||
Logger.LogInformation("从链路注销应答消息"); | |||
return null; | |||
} | |||
/// <summary> | |||
/// 从链路连接保持应答消息 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns>本条消息无需被通知方应答</returns> | |||
public virtual JT809Response Msg0x9006(JT809Request request) | |||
{ | |||
Logger.LogInformation("从链路连接保持应答消息"); | |||
return null; | |||
} | |||
/// <summary> | |||
/// 主链路动态信息交换消息 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public virtual JT809Response Msg0x1200(JT809Request request) | |||
{ | |||
return null; | |||
} | |||
} | |||
@@ -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 | |||
{ | |||
/// <summary> | |||
/// 上级平台 | |||
/// 基于webapi http模式抽象消息处理业务 | |||
/// 自定义消息处理业务 | |||
/// 注意: | |||
/// 1.ConfigureServices: | |||
/// services.Replace(new ServiceDescriptor(typeof(JT809SuperiorWebAPIHandlerBase),typeof(JT809SuperiorWebAPICustomHandler),ServiceLifetime.Singleton)); | |||
/// 2.解析具体的消息体,具体消息调用具体的JT809Serializer.Deserialize<T> | |||
/// </summary> | |||
public abstract class JT809SuperiorWebAPIHandlerBase | |||
{ | |||
/// <summary> | |||
/// 初始化消息处理业务 | |||
/// </summary> | |||
protected JT809SuperiorWebAPIHandlerBase() | |||
{ | |||
HandlerDict = new Dictionary<string, Func<JT809HttpRequest, JT809HttpResponse>>(); | |||
} | |||
protected void CreateRoute(string url, Func<JT809HttpRequest, JT809HttpResponse> func) | |||
{ | |||
if (!HandlerDict.ContainsKey(url)) | |||
{ | |||
HandlerDict.Add(url, func); | |||
} | |||
else | |||
{ | |||
// 替换 | |||
HandlerDict[url] = func; | |||
} | |||
} | |||
public Dictionary<string, Func<JT809HttpRequest, JT809HttpResponse>> 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<string>() | |||
{ | |||
Code = JT809ResultCode.Empty, | |||
Message = "内容为空", | |||
Data = "Content Empty" | |||
})); | |||
return new JT809HttpResponse(json); | |||
} | |||
public JT809HttpResponse NotFoundHttpResponse() | |||
{ | |||
byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT809ResultDto<string>() | |||
{ | |||
Code = JT809ResultCode.NotFound, | |||
Message = "没有该服务", | |||
Data = "没有该服务" | |||
})); | |||
return new JT809HttpResponse(json); | |||
} | |||
public JT809HttpResponse ErrorHttpResponse(Exception ex) | |||
{ | |||
byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT809ResultDto<string>() | |||
{ | |||
Code = JT809ResultCode.Error, | |||
Message = JsonConvert.SerializeObject(ex), | |||
Data = ex.Message | |||
})); | |||
return new JT809HttpResponse(json); | |||
} | |||
} | |||
} |
@@ -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 | |||
{ | |||
/// <summary> | |||
/// 上级平台 | |||
/// webapi处理 | |||
/// </summary> | |||
internal class JT809SuperiorWebAPIServerHandler : SimpleChannelInboundHandler<IFullHttpRequest> | |||
{ | |||
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<JT809SuperiorWebAPIServerHandler> logger; | |||
public JT809SuperiorWebAPIServerHandler( | |||
JT809SuperiorWebAPIHandlerBase jT809SuperiorWebAPIHandlerBase, | |||
ILoggerFactory loggerFactory) | |||
{ | |||
this.JT809SuperiorWebAPIHandler = jT809SuperiorWebAPIHandlerBase; | |||
logger = loggerFactory.CreateLogger<JT809SuperiorWebAPIServerHandler>(); | |||
} | |||
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(); | |||
} | |||
} |
@@ -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 | |||
{ | |||
/// <summary> | |||
/// 默认消息处理业务实现 | |||
/// </summary> | |||
public class JT809SuperiorWebAPIDefaultHandler : JT809SuperiorWebAPIHandlerBase | |||
{ | |||
private readonly JT809SimpleSystemCollectService jT809SimpleSystemCollectService; | |||
public JT809SuperiorWebAPIDefaultHandler(JT809SimpleSystemCollectService jT809SimpleSystemCollectService) | |||
{ | |||
this.jT809SimpleSystemCollectService = jT809SimpleSystemCollectService; | |||
InitRoute(); | |||
} | |||
/// <summary> | |||
/// 统一下发信息 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public JT809HttpResponse UnificationSend(JT809HttpRequest request) | |||
{ | |||
if (string.IsNullOrEmpty(request.Json)) | |||
{ | |||
return EmptyHttpResponse(); | |||
} | |||
//JT809UnificationSendRequestDto jT808UnificationSendRequestDto = JsonConvert.DeserializeObject<JT809UnificationSendRequestDto>(request.Json); | |||
//var result = jT808UnificationTcpSendService.Send(jT808UnificationSendRequestDto.TerminalPhoneNo, jT808UnificationSendRequestDto.Data); | |||
//return CreateJT808HttpResponse(result); | |||
return null; | |||
} | |||
/// <summary> | |||
/// 获取当前系统进程使用率 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public JT809HttpResponse SystemCollectGet(JT809HttpRequest request) | |||
{ | |||
JT809ResultDto<JT809SystemCollectInfoDto> jT809ResultDto = new JT809ResultDto<JT809SystemCollectInfoDto>(); | |||
jT809ResultDto.Data = jT809SimpleSystemCollectService.Get(); | |||
return CreateJT809HttpResponse(jT809ResultDto); | |||
} | |||
protected virtual void InitRoute() | |||
{ | |||
CreateRoute(JT809Constants.JT809SuperiorWebApiRouteTable.SystemCollectGet, SystemCollectGet); | |||
} | |||
} | |||
} |
@@ -7,13 +7,13 @@ | |||
<ItemGroup> | |||
<Compile Remove="Internal\JT809SessionPublishingEmptyImpl.cs" /> | |||
<Compile Remove="Session\JT809MainSessionManager.cs" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<PackageReference Include="DotNetty.Handlers" Version="0.6.0" /> | |||
<PackageReference Include="DotNetty.Transport.Libuv" Version="0.6.0" /> | |||
<PackageReference Include="DotNetty.Codecs" Version="0.6.0" /> | |||
<PackageReference Include="DotNetty.Codecs.Http" Version="0.6.0" /> | |||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.2.0" /> | |||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" /> | |||
@@ -24,9 +24,5 @@ | |||
<ProjectReference Include="..\JT809.DotNetty.Abstractions\JT809.DotNetty.Abstractions.csproj" /> | |||
<ProjectReference Include="..\JT809.Protocol\src\JT809.Protocol\JT809.Protocol.csproj" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Folder Include="Session\" /> | |||
</ItemGroup> | |||
</Project> |
@@ -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<JT809MainServerConnectionHandler>(); | |||
serviceDescriptors.TryAddScoped<JT809SubordinateClientConnectionHandler>(); | |||
//主链路服务端会话管理 | |||
//serviceDescriptors.TryAddSingleton<JT809MainSessionManager>(); | |||
serviceDescriptors.TryAddSingleton<JT809SuperiorMainSessionManager>(); | |||
//主从链路接收消息默认业务处理器 | |||
serviceDescriptors.TryAddSingleton<JT809SuperiorMsgIdReceiveHandlerBase, JT809SuperiorMsgIdReceiveDefaultHandler>(); | |||
//主从链路消息接收处理器 | |||
@@ -117,6 +117,10 @@ namespace JT809.DotNetty.Core | |||
serviceDescriptors.TryAddSingleton<JT809SubordinateClient>(); | |||
//主链路服务端 | |||
serviceDescriptors.AddHostedService<JT809MainServerHost>(); | |||
//上级平台webapi | |||
serviceDescriptors.TryAddSingleton<JT809SuperiorWebAPIHandlerBase, JT809SuperiorWebAPIDefaultHandler>(); | |||
serviceDescriptors.TryAddScoped<JT809SuperiorWebAPIServerHandler>(); | |||
serviceDescriptors.AddHostedService<JT809MainWebAPIServerHost>(); | |||
return serviceDescriptors; | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -19,7 +19,7 @@ namespace JT809.DotNetty.Core.Metadata | |||
/// </summary> | |||
public uint MsgGNSSCENTERID { get; set; } | |||
public IChannel Channel { get;} | |||
public IChannel Channel { get; set; } | |||
public DateTime LastActiveTime { get; set; } | |||
@@ -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 | |||
{ | |||
/// <summary> | |||
/// JT809 集成一个webapi服务 | |||
/// </summary> | |||
internal class JT809MainWebAPIServerHost : IHostedService | |||
{ | |||
private readonly IServiceProvider serviceProvider; | |||
private readonly ILogger<JT809MainWebAPIServerHost> logger; | |||
private DispatcherEventLoopGroup bossGroup; | |||
private WorkerEventLoopGroup workerGroup; | |||
private IChannel bootstrapChannel; | |||
private readonly JT809SuperiorPlatformOptions configuration; | |||
public JT809MainWebAPIServerHost( | |||
IServiceProvider provider, | |||
IOptions<JT809SuperiorPlatformOptions> jT809SuperiorPlatformOptionsAccessor, | |||
ILoggerFactory loggerFactory) | |||
{ | |||
serviceProvider = provider; | |||
configuration = jT809SuperiorPlatformOptionsAccessor.Value; | |||
logger = loggerFactory.CreateLogger<JT809MainWebAPIServerHost>(); | |||
} | |||
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("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<JT809SuperiorWebAPIServerHandler>()); | |||
} | |||
})); | |||
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); | |||
} | |||
} | |||
} |
@@ -9,7 +9,7 @@ namespace JT809.DotNetty.Core.Services | |||
/// <summary> | |||
/// 简单系统收集服务 | |||
/// </summary> | |||
internal class JT809SimpleSystemCollectService | |||
public class JT809SimpleSystemCollectService | |||
{ | |||
/// <summary> | |||
/// 获取系统当前进程使用情况 | |||
@@ -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 | |||
{ | |||
/// <summary> | |||
/// JT809 主链路会话管理 | |||
/// 上级平台 | |||
/// JT809主链路会话管理 | |||
/// </summary> | |||
public class JT809MainSessionManager | |||
public class JT809SuperiorMainSessionManager | |||
{ | |||
private readonly ILogger<JT809MainSessionManager> logger; | |||
private readonly ILogger<JT809SuperiorMainSessionManager> logger; | |||
//private readonly IJT809SessionPublishing jT809SessionPublishing; | |||
public JT809MainSessionManager( | |||
public JT809SuperiorMainSessionManager( | |||
//IJT809SessionPublishing jT809SessionPublishing, | |||
ILoggerFactory loggerFactory) | |||
{ | |||
//this.jT809SessionPublishing = jT809SessionPublishing; | |||
logger = loggerFactory.CreateLogger<JT809MainSessionManager>(); | |||
logger = loggerFactory.CreateLogger<JT809SuperiorMainSessionManager>(); | |||
} | |||
private ConcurrentDictionary<uint, JT809Session> SessionIdDict = new ConcurrentDictionary<uint, JT809Session>(); | |||
@@ -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()); | |||
} | |||
} |