From 1a7c6c879426e9bfad21104ae61b780dcd310e90 Mon Sep 17 00:00:00 2001 From: "SmallChi(Koike)" <564952747@qq.com> Date: Wed, 18 Dec 2019 17:28:15 +0800 Subject: [PATCH] =?UTF-8?q?1.=E4=BF=AE=E6=94=B9=E6=96=87=E6=A1=A3=E5=8F=8A?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE=202.=E5=A2=9E=E5=8A=A0pipeline=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=203.=E7=A7=BB=E9=99=A4gateway=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 2 +- README.md | 17 +- README_V1.0.0.md | 120 - doc/README.md | 27 +- doc/{img => dotnetty}/demo1.png | Bin doc/{img => dotnetty}/demo2.png | Bin doc/{img => dotnetty}/design_model.png | Bin doc/{img => dotnetty}/performance_1000.png | Bin doc/{img => dotnetty}/performance_10000.png | Bin doc/{img => dotnetty}/performance_2000.png | Bin doc/{img => dotnetty}/performance_5000.png | Bin doc/pipeline/client_10k.png | Bin 0 -> 22003 bytes doc/pipeline/server_network_10k.png | Bin 0 -> 63584 bytes doc/pipeline/server_proccess_10k.png | Bin 0 -> 60562 bytes .../Configs/ClientBenchmarkOptions.cs | 19 - .../Configs/NLog.xsd | 3106 ----------------- .../Configs/nlog.unix.config | 36 - .../Configs/nlog.win.config | 35 - .../JT808.Gateway.CleintBenchmark.csproj | 33 - src/JT808.Gateway.CleintBenchmark/Program.cs | 51 - .../Services/CleintBenchmarkHostedService.cs | 82 - .../CleintBenchmarkReportHostedService.cs | 53 - .../Configs/JT808ConsumerConfig.cs | 15 - .../Configs/JT808MsgConsumerConfig.cs | 13 - .../Configs/JT808MsgProducerConfig.cs | 13 - .../Configs/JT808MsgReplyConsumerConfig.cs | 13 - .../Configs/JT808MsgReplyProducerConfig.cs | 13 - .../Configs/JT808ProducerConfig.cs | 15 - .../Configs/JT808SessionConsumerConfig.cs | 13 - .../Configs/JT808SessionProducerConfig.cs | 13 - .../JT808.Gateway.Kafka.csproj | 39 - .../JT808ClientBuilderDefault.cs | 24 - .../JT808ClientKafkaExtensions.cs | 66 - src/JT808.Gateway.Kafka/JT808MsgConsumer.cs | 82 - src/JT808.Gateway.Kafka/JT808MsgProducer.cs | 38 - .../JT808MsgReplyConsumer.cs | 82 - .../JT808MsgReplyProducer.cs | 38 - .../JT808ServerKafkaExtensions.cs | 48 - .../JT808SessionConsumer.cs | 82 - .../JT808SessionProducer.cs | 38 - .../JT808.Gateway.SimpleClient.csproj | 18 - src/JT808.Gateway.SimpleClient/Program.cs | 52 - .../Services/GrpcClientService.cs | 68 - .../Services/UpService.cs | 68 - .../Configs/NLog.xsd | 3106 ----------------- .../Configs/nlog.Unix.config | 36 - .../Configs/nlog.Win32NT.config | 36 - .../Configs/test.cer | Bin 784 -> 0 bytes .../JT808.Gateway.SimpleServer.csproj | 39 - src/JT808.Gateway.SimpleServer/Program.cs | 71 - src/JT808.Gateway.sln | 102 - .../MsgIdHandler/IJT808MsgIdHandler.cs | 14 - .../JT808MsgIdHandlerExtensions.cs | 18 - .../JT808MsgIdHandlerHostedService.cs | 34 - .../MsgLogging/IJT808MsgLogging.cs | 15 - .../JT808MsgDownLoggingHostedService.cs | 36 - .../MsgLogging/JT808MsgLoggingExtensions.cs | 19 - .../MsgLogging/JT808MsgLoggingType.cs | 18 - .../JT808MsgUpLoggingHostedService.cs | 36 - .../JT808ReplyMessageExtensions.cs | 57 - .../JT808ReplyMessageHostedService.cs | 34 - .../ReplyMessage/JT808ReplyMessageService.cs | 165 - .../JT808SessionNoticeExtensions.cs | 60 - .../JT808SessionNoticeHostedService.cs | 35 - .../JT808SessionNoticeService.cs | 24 - .../Traffic/JT808TrafficService.cs | 32 - .../Traffic/JT808TrafficServiceExtensions.cs | 33 - .../JT808TrafficServiceHostedService.cs | 38 - .../Traffic/TrafficRedisClient.cs | 9 - .../Transmit/Configs/DataTransferOptions.cs | 13 - .../Transmit/Configs/RemoteServerOptions.cs | 11 - .../Handlers/ClientConnectionHandler.cs | 76 - .../JT808DotNettyTransmitExtensions.cs | 39 - .../JT808DotNettyTransmitHostedService.cs | 33 - .../Transmit/JT808DotNettyTransmitService.cs | 236 -- src/JT808.Gateway/Client/DeviceConfig.cs | 28 - .../Client/JT808ClientDotnettyExtensions.cs | 23 - .../Client/JT808ClientMsgSNDistributedImpl.cs | 16 - src/JT808.Gateway/Client/JT808TcpClient.cs | 112 - .../Client/JT808TcpClientExtensions.cs | 103 - .../Client/JT808TcpClientFactory.cs | 62 - .../Codecs/JT808ClientTcpDecoder.cs | 20 - .../Codecs/JT808ClientTcpEncoder.cs | 52 - src/JT808.Gateway/Codecs/JT808TcpDecoder.cs | 32 - src/JT808.Gateway/Codecs/JT808TcpEncoder.cs | 52 - src/JT808.Gateway/Codecs/JT808UdpDecoder.cs | 33 - .../Configurations/JT808Configuration.cs | 41 - src/JT808.Gateway/Dtos/JT808ResultDto.cs | 29 - .../Dtos/JT808TcpSessionInfoDto.cs | 24 - .../Dtos/JT808UdpSessionInfoDto.cs | 24 - .../Enums/JT808TransportProtocolType.cs | 15 - .../JT808TcpClientConnectionHandler.cs | 96 - .../Handlers/JT808TcpClientHandler.cs | 31 - .../Handlers/JT808TcpConnectionHandler.cs | 104 - .../Handlers/JT808TcpServerHandler.cs | 77 - .../Handlers/JT808UdpServerHandler.cs | 79 - src/JT808.Gateway/IJT808ClientBuilder.cs | 14 - src/JT808.Gateway/IJT808GatewayBuilder.cs | 14 - .../Impls/JT808DatagramPacketImpl.cs | 18 - .../Impls/JT808GatewayBuilderDefault.cs | 25 - .../Impls/JT808MsgProducerDefaultImpl.cs | 30 - .../Impls/JT808MsgReplyConsumerDefaultImpl.cs | 193 - .../Impls/JT808SessionProducerDefaultImpl.cs | 32 - .../Interfaces/IJT808DatagramPacket.cs | 13 - src/JT808.Gateway/Interfaces/IJT808Reply.cs | 17 - src/JT808.Gateway/Interfaces/IJT808Session.cs | 20 - .../Interfaces/IJT808SessionService.cs | 30 - .../IJT808UnificationSendService.cs | 12 - src/JT808.Gateway/JT808.Gateway.csproj | 45 - src/JT808.Gateway/JT808GatewayConstants.cs | 48 - src/JT808.Gateway/JT808GatewayExtensions.cs | 54 - .../Metadata/JT808AtomicCounter.cs | 49 - .../Metadata/JT808ClientReport.cs | 16 - .../Metadata/JT808ClientRequest.cs | 30 - .../Metadata/JT808HttpRequest.cs | 22 - .../Metadata/JT808HttpResponse.cs | 22 - src/JT808.Gateway/Metadata/JT808Request.cs | 23 - src/JT808.Gateway/Metadata/JT808Response.cs | 31 - src/JT808.Gateway/Metadata/JT808TcpSession.cs | 32 - src/JT808.Gateway/Metadata/JT808UdpPackage.cs | 20 - src/JT808.Gateway/Metadata/JT808UdpSession.cs | 38 - src/JT808.Gateway/Protos/JT808Gateway.proto | 63 - src/JT808.Gateway/PubSub/IJT808MsgConsumer.cs | 15 - src/JT808.Gateway/PubSub/IJT808MsgProducer.cs | 17 - .../PubSub/IJT808MsgReplyConsumer.cs | 15 - .../PubSub/IJT808MsgReplyProducer.cs | 17 - src/JT808.Gateway/PubSub/IJT808PubSub.cs | 11 - .../PubSub/IJT808SessionConsumer.cs | 18 - .../PubSub/IJT808SessionProducer.cs | 13 - .../Services/JT808AtomicCounterService.cs | 52 - .../JT808AtomicCounterServiceFactory.cs | 30 - .../JT808ClientReceiveAtomicCounterService.cs | 35 - .../JT808ClientReportHostedService.cs | 37 - .../Services/JT808ClientReportService.cs | 43 - .../JT808ClientSendAtomicCounterService.cs | 35 - .../Services/JT808GatewayService.cs | 102 - .../Services/JT808MsgReplyHostedService.cs | 42 - src/JT808.Gateway/Services/JT808MsgService.cs | 11 - .../Services/JT808SessionService.cs | 98 - .../Services/JT808UnificationSendService.cs | 45 - .../Session/JT808SessionManager.cs | 304 -- .../Simples/JT808SimpleTcpClient.cs | 50 - .../Simples/JT808SimpleUdpClient.cs | 48 - .../Tcp/JT808TcpDotnettyExtensions.cs | 21 - src/JT808.Gateway/Tcp/JT808TcpServerHost.cs | 95 - .../Udp/JT808UdpDotnettyExtensions.cs | 22 - src/JT808.Gateway/Udp/JT808UdpServerHost.cs | 76 - 147 files changed, 36 insertions(+), 12087 deletions(-) delete mode 100644 README_V1.0.0.md rename doc/{img => dotnetty}/demo1.png (100%) rename doc/{img => dotnetty}/demo2.png (100%) rename doc/{img => dotnetty}/design_model.png (100%) rename doc/{img => dotnetty}/performance_1000.png (100%) rename doc/{img => dotnetty}/performance_10000.png (100%) rename doc/{img => dotnetty}/performance_2000.png (100%) rename doc/{img => dotnetty}/performance_5000.png (100%) create mode 100644 doc/pipeline/client_10k.png create mode 100644 doc/pipeline/server_network_10k.png create mode 100644 doc/pipeline/server_proccess_10k.png delete mode 100644 src/JT808.Gateway.CleintBenchmark/Configs/ClientBenchmarkOptions.cs delete mode 100644 src/JT808.Gateway.CleintBenchmark/Configs/NLog.xsd delete mode 100644 src/JT808.Gateway.CleintBenchmark/Configs/nlog.unix.config delete mode 100644 src/JT808.Gateway.CleintBenchmark/Configs/nlog.win.config delete mode 100644 src/JT808.Gateway.CleintBenchmark/JT808.Gateway.CleintBenchmark.csproj delete mode 100644 src/JT808.Gateway.CleintBenchmark/Program.cs delete mode 100644 src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkHostedService.cs delete mode 100644 src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkReportHostedService.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808ConsumerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808MsgConsumerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808MsgProducerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808MsgReplyConsumerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808MsgReplyProducerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808ProducerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808SessionConsumerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808SessionProducerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808.Gateway.Kafka.csproj delete mode 100644 src/JT808.Gateway.Kafka/JT808ClientBuilderDefault.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808ClientKafkaExtensions.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808MsgConsumer.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808MsgProducer.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808MsgReplyConsumer.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808MsgReplyProducer.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808ServerKafkaExtensions.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808SessionConsumer.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808SessionProducer.cs delete mode 100644 src/JT808.Gateway.SimpleClient/JT808.Gateway.SimpleClient.csproj delete mode 100644 src/JT808.Gateway.SimpleClient/Program.cs delete mode 100644 src/JT808.Gateway.SimpleClient/Services/GrpcClientService.cs delete mode 100644 src/JT808.Gateway.SimpleClient/Services/UpService.cs delete mode 100644 src/JT808.Gateway.SimpleServer/Configs/NLog.xsd delete mode 100644 src/JT808.Gateway.SimpleServer/Configs/nlog.Unix.config delete mode 100644 src/JT808.Gateway.SimpleServer/Configs/nlog.Win32NT.config delete mode 100644 src/JT808.Gateway.SimpleServer/Configs/test.cer delete mode 100644 src/JT808.Gateway.SimpleServer/JT808.Gateway.SimpleServer.csproj delete mode 100644 src/JT808.Gateway.SimpleServer/Program.cs delete mode 100644 src/JT808.Gateway.sln delete mode 100644 src/JT808.Gateway/BusinessServices/MsgIdHandler/IJT808MsgIdHandler.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerExtensions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgLogging/IJT808MsgLogging.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgDownLoggingHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingExtensions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingType.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgUpLoggingHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageExtensions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeExtensions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceExtensions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Traffic/TrafficRedisClient.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Transmit/Configs/DataTransferOptions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Transmit/Configs/RemoteServerOptions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Transmit/Handlers/ClientConnectionHandler.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitExtensions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitService.cs delete mode 100644 src/JT808.Gateway/Client/DeviceConfig.cs delete mode 100644 src/JT808.Gateway/Client/JT808ClientDotnettyExtensions.cs delete mode 100644 src/JT808.Gateway/Client/JT808ClientMsgSNDistributedImpl.cs delete mode 100644 src/JT808.Gateway/Client/JT808TcpClient.cs delete mode 100644 src/JT808.Gateway/Client/JT808TcpClientExtensions.cs delete mode 100644 src/JT808.Gateway/Client/JT808TcpClientFactory.cs delete mode 100644 src/JT808.Gateway/Codecs/JT808ClientTcpDecoder.cs delete mode 100644 src/JT808.Gateway/Codecs/JT808ClientTcpEncoder.cs delete mode 100644 src/JT808.Gateway/Codecs/JT808TcpDecoder.cs delete mode 100644 src/JT808.Gateway/Codecs/JT808TcpEncoder.cs delete mode 100644 src/JT808.Gateway/Codecs/JT808UdpDecoder.cs delete mode 100644 src/JT808.Gateway/Configurations/JT808Configuration.cs delete mode 100644 src/JT808.Gateway/Dtos/JT808ResultDto.cs delete mode 100644 src/JT808.Gateway/Dtos/JT808TcpSessionInfoDto.cs delete mode 100644 src/JT808.Gateway/Dtos/JT808UdpSessionInfoDto.cs delete mode 100644 src/JT808.Gateway/Enums/JT808TransportProtocolType.cs delete mode 100644 src/JT808.Gateway/Handlers/JT808TcpClientConnectionHandler.cs delete mode 100644 src/JT808.Gateway/Handlers/JT808TcpClientHandler.cs delete mode 100644 src/JT808.Gateway/Handlers/JT808TcpConnectionHandler.cs delete mode 100644 src/JT808.Gateway/Handlers/JT808TcpServerHandler.cs delete mode 100644 src/JT808.Gateway/Handlers/JT808UdpServerHandler.cs delete mode 100644 src/JT808.Gateway/IJT808ClientBuilder.cs delete mode 100644 src/JT808.Gateway/IJT808GatewayBuilder.cs delete mode 100644 src/JT808.Gateway/Impls/JT808DatagramPacketImpl.cs delete mode 100644 src/JT808.Gateway/Impls/JT808GatewayBuilderDefault.cs delete mode 100644 src/JT808.Gateway/Impls/JT808MsgProducerDefaultImpl.cs delete mode 100644 src/JT808.Gateway/Impls/JT808MsgReplyConsumerDefaultImpl.cs delete mode 100644 src/JT808.Gateway/Impls/JT808SessionProducerDefaultImpl.cs delete mode 100644 src/JT808.Gateway/Interfaces/IJT808DatagramPacket.cs delete mode 100644 src/JT808.Gateway/Interfaces/IJT808Reply.cs delete mode 100644 src/JT808.Gateway/Interfaces/IJT808Session.cs delete mode 100644 src/JT808.Gateway/Interfaces/IJT808SessionService.cs delete mode 100644 src/JT808.Gateway/Interfaces/IJT808UnificationSendService.cs delete mode 100644 src/JT808.Gateway/JT808.Gateway.csproj delete mode 100644 src/JT808.Gateway/JT808GatewayConstants.cs delete mode 100644 src/JT808.Gateway/JT808GatewayExtensions.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808AtomicCounter.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808ClientReport.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808ClientRequest.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808HttpRequest.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808HttpResponse.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808Request.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808Response.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808TcpSession.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808UdpPackage.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808UdpSession.cs delete mode 100644 src/JT808.Gateway/Protos/JT808Gateway.proto delete mode 100644 src/JT808.Gateway/PubSub/IJT808MsgConsumer.cs delete mode 100644 src/JT808.Gateway/PubSub/IJT808MsgProducer.cs delete mode 100644 src/JT808.Gateway/PubSub/IJT808MsgReplyConsumer.cs delete mode 100644 src/JT808.Gateway/PubSub/IJT808MsgReplyProducer.cs delete mode 100644 src/JT808.Gateway/PubSub/IJT808PubSub.cs delete mode 100644 src/JT808.Gateway/PubSub/IJT808SessionConsumer.cs delete mode 100644 src/JT808.Gateway/PubSub/IJT808SessionProducer.cs delete mode 100644 src/JT808.Gateway/Services/JT808AtomicCounterService.cs delete mode 100644 src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs delete mode 100644 src/JT808.Gateway/Services/JT808ClientReceiveAtomicCounterService.cs delete mode 100644 src/JT808.Gateway/Services/JT808ClientReportHostedService.cs delete mode 100644 src/JT808.Gateway/Services/JT808ClientReportService.cs delete mode 100644 src/JT808.Gateway/Services/JT808ClientSendAtomicCounterService.cs delete mode 100644 src/JT808.Gateway/Services/JT808GatewayService.cs delete mode 100644 src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs delete mode 100644 src/JT808.Gateway/Services/JT808MsgService.cs delete mode 100644 src/JT808.Gateway/Services/JT808SessionService.cs delete mode 100644 src/JT808.Gateway/Services/JT808UnificationSendService.cs delete mode 100644 src/JT808.Gateway/Session/JT808SessionManager.cs delete mode 100644 src/JT808.Gateway/Simples/JT808SimpleTcpClient.cs delete mode 100644 src/JT808.Gateway/Simples/JT808SimpleUdpClient.cs delete mode 100644 src/JT808.Gateway/Tcp/JT808TcpDotnettyExtensions.cs delete mode 100644 src/JT808.Gateway/Tcp/JT808TcpServerHost.cs delete mode 100644 src/JT808.Gateway/Udp/JT808UdpDotnettyExtensions.cs delete mode 100644 src/JT808.Gateway/Udp/JT808UdpServerHost.cs diff --git a/LICENSE b/LICENSE index 67b52f7..79a535b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 SmallChi(Koike) +Copyright (c) 2019 SmallChi(Koike) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index e7bcda4..62abed7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# JT808DotNetty +# JT808Gateway -基于DotNetty封装的JT808DotNetty支持TCP/UDP通用消息业务处理 +基于DotNetty封装的JT808DotNetty支持TCP/UDP通用消息业务处理 + +基于Pipeline封装的JT808DotNetty支持TCP/UDP通用消息业务处理 [了解JT808协议进这边](https://github.com/SmallChi/JT808) @@ -14,7 +16,7 @@ [![MIT Licence](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE)[![Build Status](https://travis-ci.org/SmallChi/JT808DotNetty.svg?branch=master)](https://travis-ci.org/SmallChi/JT808DotNetty) -## 新网关的优势: +## 新网关的优势 1. 跨平台 2. 借助 .NET Core模块化的思想 @@ -55,7 +57,7 @@ |Traffic|流量统计服务 |由于运营商sim卡查询流量滞后,通过流量统计服务可以实时准确的统计设备流量,可以最优配置设备的流量大小,以节省成本 |Transmit| 原包转发服务|该服务可以将设备上报原始数据转发到第三方,支持全部转发,指定终端号转发| -## NuGet安装 +## 基于DotNetty的NuGet安装 | Package Name | Version | Downloads | | --------------------- | -------------------------------------------------- | --------------------------------------------------- | @@ -75,6 +77,13 @@ | Install-Package JT808.DotNetty.Kafka | ![JT808](https://img.shields.io/nuget/v/JT808.DotNetty.Kafka.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.DotNetty.Kafka.svg) | | Install-Package JT808.DotNetty.RabbitMQ | ![JT808](https://img.shields.io/nuget/v/JT808.DotNetty.RabbitMQ.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.DotNetty.RabbitMQ.svg) | +## 基于Pipeline的NuGet安装 + +| Package Name | Version | Downloads | +| --------------------- | -------------------------------------------------- | --------------------------------------------------- | +| Install-Package JT808.Gateway | ![JT808.Gateway](https://img.shields.io/nuget/v/JT808.Gateway.svg) | ![JT808.Gateway](https://img.shields.io/nuget/dt/JT808.Gateway.svg) | +| Install-Package JT808.Gateway.Kafka| ![JT808.Gateway.Kafka](https://img.shields.io/nuget/v/JT808.Gateway.Kafka.svg) | ![JT808.Gateway.Kafka](https://img.shields.io/nuget/dt/JT808.Gateway.Kafka.svg) | + ## 举个栗子1 ``` demo1 diff --git a/README_V1.0.0.md b/README_V1.0.0.md deleted file mode 100644 index 1277e7e..0000000 --- a/README_V1.0.0.md +++ /dev/null @@ -1,120 +0,0 @@ -# JT808DotNetty - -基于DotNetty封装的JT808DotNetty支持TCP/UDP通用消息业务处理 - -[了解JT808协议进这边](https://github.com/SmallChi/JT808) - -[了解JT809协议进这边](https://github.com/SmallChi/JT809) - -[了解JT1078协议进这边](https://github.com/SmallChi/JT1078) - -[了解JTNE协议进这边](https://github.com/SmallChi/JTNewEnergy) - -[玩一玩压力测试](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/README.md) - -[V2.2.1老版本](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/README_V2.2.1.md) - -[![MIT Licence](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE) - -## 新网关的优势 - -1. 跨平台 -2. 借助 .NET Core模块化的思想 -3. 单机同时一万辆车在线不是梦(真有一万辆车那都很吃香了<( ̄3 ̄)> <( ̄3 ̄)> <( ̄3 ̄)> ) -4. 简单易上手 - -## 设计模型 - -![design_model](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/design_model.png) - -## 基于Grpc的消息业务处理程序(JT808.Gateway.GrpcService) - -``` 1 -services.AddGrpcClient(o => -{ - o.Address = new Uri("https://localhost:5001"); -}); -``` - -## 集成接口功能(JT808.Gateway.PubSub) - -|接口名称|接口说明|使用场景| -|:------:|:------|:------| -| IJT808SessionProducer| 会话通知(在线/离线)数据生产接口| 有些超长待机的设备,不会实时保持连接,那么通过平台下发的命令是无法到达的,这时候就需要设备一上线,就即时通知服务去处理,然后在即时的下发消息到设备。| -| IJT808SessionConsumer| 会话通知(在线/离线)数据消费接口| -| -| IJT808MsgProducer| 数据生产接口| 网关将接收到的数据发送到队列| -| IJT808MsgConsumer| 数据消费接口| 将数据进行对应的消息业务处理(例:设备流量统计、第三方平台数据转发、消息日志等) | -| IJT808MsgReplyProducer| 应答数据生产接口|将生产的数据解析为对应的消息Id应答发送到队列 | -| IJT808MsgReplyConsumer| 应答数据消费接口| 将接收到的应答数据下发给设备| - -> 使用物联网卡通过udp下发指令时,存储的那个socket地址端口,有效期非常短,不速度快点下发,那个socket地址端口就可能映射到别的对应卡去了,所以此处采用跟随设备消息下发指令。 - -## 基于网关的相关服务(JT808.Gateway.BusinessServices) - -|服务名称|服务说明|使用场景| -|:------:|:------|:------| -|MsgIdHandler| 消息处理服务|从队列中消费设备上报数据,再结合自身的业务场景,将数据进行处理并入库 | -|MsgLogging | 消息日志服务|从队列中消费设备上报和平台应答数据,再将数据存入influxdb等数据库中,便于技术和技术支持排查设备与平台交互的原始数据| -|ReplyMessage| 消息响应服务| 用于响应设备上报消息,以及下发指令信息到设备| -|SessionNotice| 会话管理服务| 通知设备上线下线,对于udp设备来说,可以在设备上线时,将指令跟随消息下发到设备| -|Traffic|流量统计服务 |由于运营商sim卡查询流量滞后,通过流量统计服务可以实时准确的统计设备流量,可以最优配置设备的流量大小,以节省成本 -|Transmit| 原包转发服务|该服务可以将设备上报原始数据转发到第三方,支持全部转发,指定终端号转发| - -## NuGet安装 - -| Package Name | Version | Downloads | -| --------------------- | -------------------------------------------------- | --------------------------------------------------- | -| Install-Package JT808.Gateway | ![JT808.Gateway](https://img.shields.io/nuget/v/JT808.Gateway.svg) | ![JT808.Gateway](https://img.shields.io/nuget/dt/JT808.Gateway.svg) | -| Install-Package JT808.Gateway.Kafka| ![JT808.Gateway.Kafka](https://img.shields.io/nuget/v/JT808.Gateway.Kafka.svg) | ![JT808.Gateway.Kafka](https://img.shields.io/nuget/dt/JT808.Gateway.Kafka.svg) | - -## 举个栗子1 - -1.进入JT808.Gateway.SimpleServer项目下的Debug目录运行服务端 - -2.进入JT808.Gateway.SimpleClient项目下的Debug目录运行客户端 - -``` 1 -static void Main(string[] args) -{ - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - //配置Grpc服务端 - webBuilder - .ConfigureKestrel(options => - { - options.Listen(IPAddress.Any, 5001, listenOptions => - { - listenOptions.Protocols = HttpProtocols.Http2; - listenOptions.UseHttps($"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Configs", "test.cer")}", ""); - }); - }) - .Configure(app => - { - app.UseRouting(); - app.UseEndpoints(endpoints => - { - //配置Grpc服务节点 - endpoints.MapGrpcService(); - }); - }); - }) - .ConfigureServices((hostContext,services) => - { - //services.Configure(hostContext.Configuration.GetSection("Kestrel")); - //添加Grpc服务 - services.AddGrpc(); - //添加JT808协议 - services.AddJT808Configure() - //添加JT808网关配置 - .AddJT808Gateway(hostContext.Configuration) - //添加基于Tcp的808网关 - .AddJT808GatewayTcpHost() - //添加基于Udp的808网关 - .AddJT808GatewayUdpHost() - .Builder(); - }) - .Build() - .Run(); -} -``` diff --git a/doc/README.md b/doc/README.md index ae791e0..9aaebe3 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,4 +1,6 @@ -## 压力测试 +# 压力测试 + +## 基于DotNetty [感谢泥水佬提供的压力测试工具](https://www.cnblogs.com/smark/p/4496660.html?utm_source=tuicool) @@ -7,10 +9,25 @@ | win server 2016 | 4c8g | 压力测试客户端 | | centos7 | 4c8g | JT808服务端 | -![performance_1000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_1000.png) +![performance_1000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/dotnetty/performance_1000.png) + +![performance_2000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/dotnetty/performance_2000.png) + +![performance_5000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/dotnetty/performance_5000.png) + +![performance_10000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/dotnetty/performance_10000.png) + +## 基于pipeline + +| 操作系统 | 配置 | 使用 | +|:-------:|:-------:|:-------:| +| centos7 | 4c8g | JT808服务端 | +| centos7 | 4c8g | JT808客户端 | + +> 计算网络增强型 sn1ne ecs.sn1ne.xlarge 4 vCPU 8 GiB Intel Xeon E5-2682v4 / Intel Xeon(Skylake) Platinum 8163 2.5 GHz 1.5 Gbps 50 万 PPS -![performance_2000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_2000.png) +![server_proccess_10k](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/pipeline/server_proccess_10k.png) -![performance_5000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_5000.png) +![server_network_10k](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/pipeline/server_network_10k.png) -![performance_10000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_10000.png) +![client_10k](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/pipeline/client_10k.png) diff --git a/doc/img/demo1.png b/doc/dotnetty/demo1.png similarity index 100% rename from doc/img/demo1.png rename to doc/dotnetty/demo1.png diff --git a/doc/img/demo2.png b/doc/dotnetty/demo2.png similarity index 100% rename from doc/img/demo2.png rename to doc/dotnetty/demo2.png diff --git a/doc/img/design_model.png b/doc/dotnetty/design_model.png similarity index 100% rename from doc/img/design_model.png rename to doc/dotnetty/design_model.png diff --git a/doc/img/performance_1000.png b/doc/dotnetty/performance_1000.png similarity index 100% rename from doc/img/performance_1000.png rename to doc/dotnetty/performance_1000.png diff --git a/doc/img/performance_10000.png b/doc/dotnetty/performance_10000.png similarity index 100% rename from doc/img/performance_10000.png rename to doc/dotnetty/performance_10000.png diff --git a/doc/img/performance_2000.png b/doc/dotnetty/performance_2000.png similarity index 100% rename from doc/img/performance_2000.png rename to doc/dotnetty/performance_2000.png diff --git a/doc/img/performance_5000.png b/doc/dotnetty/performance_5000.png similarity index 100% rename from doc/img/performance_5000.png rename to doc/dotnetty/performance_5000.png diff --git a/doc/pipeline/client_10k.png b/doc/pipeline/client_10k.png new file mode 100644 index 0000000000000000000000000000000000000000..85875d6c56f46263760cf301c65382a2bf586820 GIT binary patch literal 22003 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%0DS+N!*{!T$0&1T#y!Q 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 literal 0 HcmV?d00001 diff --git a/doc/pipeline/server_network_10k.png b/doc/pipeline/server_network_10k.png new file mode 100644 index 0000000000000000000000000000000000000000..4a469900ebfbf316cbaae7a2a8e4b41247e5ceee GIT binary patch literal 63584 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

L#8nWwuko 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≫⃒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 literal 0 HcmV?d00001 diff --git a/doc/pipeline/server_proccess_10k.png b/doc/pipeline/server_proccess_10k.png new file mode 100644 index 0000000000000000000000000000000000000000..c41d69d679d03c616f80ee0c1911a6139e7f2ec2 GIT binary patch literal 60562 zcmeFZ2UL^W)-H^quu%{N3muUrp!6<91(A-l7(hUJC-f#ED2SjGrT2hz5_<0-CDNsY z76BD$2}MeRBqZFpb)U2M{?7T%9pnGUy<`0UmoXf&-n?bbx#pVdna`YWq8{kpr#r)P zhJu2EPD5SQfP#VwPC;?f_cto?5xC%(G5Nm}-Uj#YQk0Ldt&<0*9Pa4cp`fUWJ9}hx znmnfQP&e_Wpg7n4t|NdwouK@mlyc)|@mB3>gIv);b; zR8^QF3Ja+`Xb~jK`HxR1<2Wk`WwRxH73BXD{uU_SAHE991^7HtUUSq*`WrVmGY}Es|FJD znP9))eYS=C&?gV0jrkn9*10rjDNaUQ`g!BTlMzTc@)w0XzqI)0`EqA<={2k=&Wn=g z_s1va;(sfHIs;{B=va3U z%3a^j&kEl7QmeB&6Qmj{<{!>akGvlBBVG|~ID19_wz?i9|LDmk{_b;v?VWfgityzK zBmxEnPmfL=_eBpwBU~>0E-3}ut0fiy6ptzm+U!M7!|iJDL^R~dW(*oaD6YGqBL;}~ z^Cf<+FiIh9f&dWfn;FPe*y8twZCJ>XiHk`(*;x0HP0AcHFw172l4eO*H|l~-l3a$P z%1iQBsP*rgw^$oW2g~kwW2)^IB5xQD>d?lNnWezahBO6FVS9uVtbjCyv-z)yt-&q> zq7po)WN^o}X`69e9ry{<`iG@ny90^tSP@cxOR0aG(4FJ2mXie&pGuLMeRsYOUD5X?G?agcU) z!UlCk8qjMxV;zWU2E%e<_y!|Oqv*;C13&>y^0iz>dj5S0uwyTCX?R`&yl6-ivngo# z&<5BP$KDSDB2i6tlbc8;D+e)ncB$~`{#7k3TZ{#V2%~M2*l~$g>By5(nE%{i9uPaU znQ?D`)Cy~sG<#z_nuSIy20;qZnl~^wmvVEwtTuaI;*vz)$Es{ptZ%FHh#gz)TJu(u z=|N*J>C4sm%6OUL;4E)V$i$iMA0deRiS13JBTt@zS=X5eB+T+VvHhdWaXsGDY%i2@ zar|Xfe64_2)UH5+rb}PWI>V5`Rtm)Ks4R+dQIotv^4C_3J4E!ykM=su6?e@bV>+W8 z8G9iLw43ACtMG1bZxW=Rm?GWq&uLMjtXk#fdsX#%-K7u}r|;4UZa}$bGH{k4Z>R6| z#*V;VDYcacw!qW9#^z70c(GI<9UYHOR>0_^5|r;w5Y|9qRxF*T-Mg+i|55m@huix7 z2Yj;&ywkiT<>H%q=DYpq>vt@s1LMT`A7wFW?3V=f9k{8ZNwkIBYM7`v1P_hfdtY$eE%`QcmItI|jGR^~7&u1@ zYiqZXItJ*xmffOd3B0vtfYpK&laHr+e^Yy7#c~m>;H-E!m?AC302hBHWrO?rfl4eS zdJF3K)O5J2evwcbjjQ7-PA!WJx_Ua7#6-#Fp7&w?0Ww#6BJh*u(D%F#(>* zy!{GkYXg|irg>e-{OqUJE!f993jU%H)WQQ?VQzo=CI0ZvI|VK$(4<7?$B=0KIG%4| zfiJd3_k%`0F-ZhcsS~Y}X&V@)7;jpBRHnYmRtqFZw8cG%3-jrIDf257T?I)?!%6vg zQ)~m0^KgBnvQ!ze--|{Dq^Z#gxmj=aR>oJX;GbK%E(SPW&8rSou(jgws zF2WaBMGUdBVQLxD%q)`KGVlR;4r`WEZmHv)ueA)LjqOWnXA|sLuXW$-kOrV!IaYWS@)DO7)p@%#&e-ANe5tS*NZ8k2@4Gaz^D%?ZytPH$X?Js6#D`j|ORSnz zR=md;us`NLfo)^@abPX@g%n8LIbJrvn@2YoI#%51uwi@|QJI}u+h7V0O5gOyy!7-; z4l;UcAu}N^xKTaV!{p9i>`+P{k6#syq>R&#GuzI_Gwp+6sM-VBe}?**$;vYeTd0wAd$Ja*WZk2;v;42?n7Nnd4)sXY zGIm}P@OL&`f`oubTj&A7UhnwU1H;W3e^ym*(8J9Rx^CbZl;jl`RKvEmYJ~AIE?yj- zIlCXQyjZ;3mtZFt*mR9MB1t0l<7!QZ74LGh8&iZaC>GhcoPzP2CESoFfPhXsPUQ^f zu%3n+aUFNvcyc+1%({ysac&n|virWS=|retXgoIAjy0Poi~-S+B;b(iPo2-_b9~9+ zDlji07}bQy0_}lO7n1N0mVa)D^%C%}bfw=L3a@pS22#R^&Yc&!2aroj+v{|&Z!+o4 zJ=LvZ`9n-a?{l0MWSu+CfO>K~v5lj0%#txCmr|+jamE2Q+m#Oo(K^)QOXlO~( zcpyC#oRvGVMc|4pSlKM?LK$pfPGEz|Vn4J?T*%PO`pn1zcq(vFR)dZ*Od}G*aZ$F# z>e44Vp~JGEKH=Lef=~F6x}O-?JV3e0K)jFXUhduD|$ViK%7-%wTUjfzU928-5hoM$+w+LvW&wMsIG zbAYqkY~oZ0N6%9a(!xq)O1~UW{KLI%s&+uYd*ZaP$7%Kz5ymbfJ~Unjeu(#G^w+v` zXp+|(_^Txy)0Zw}80X0!kk!IT;a}D_gS+;hl7st@M*A7jHHq%X`6sNI_KW2MIdr;) zRXi+aA+0#}XoS4Cbd?4$@0t* z$Tuke>uo!Ei-jy>%VxfZE8Y%w1qx{knH8#EimI^l^3er+{$mDPlwSkJYWyrhn-eO7(|Vv%N}M zs7yE5yJeg`lBk(T7`Q!}I-69?B&5+2o4#nbOS4u0x+U4a;ztzo=GP}9@lE5Aoq*jG zLtK?22X%-qS@o40Z|R)KUf^0_SW6%KJCYqI1BEhDuksGxOf;##qgbn`tM0d-`(|wK z1zH&KdY|TawhS2wYZ{Pkw@to!!~7S_PpJ8{|C)!2f@{8Vj;j3L&#OHCdszOz4T+yk zsF308sXsRH>!)d9-aj%5jXz89d!pfWIg=y4hvMqvUtV)t;4v`E`@fa=#2-jW^F%i~ zlf2>$<9}rX|I{$^bkVAi<)J1v0eY05bu!eT>mRwq+V4`$&@Ym34X_l;5ax+9IUaw` z3CO1Kd#?w<8#$`y*m+3gyP>^26e+O)$AWzi!JF{vlcv{`>bIs_c08$JTAJ`Zrt@6NP`> zHvD}0g@{YPOCw(o4_A`Uf-AkWD|<2i{MT*I-<9}7T10Zv2feXT@KRQ3&>j-KYKyO_ z04%yAk|=|ji?)qMPfsx7zhoF=2mB{nK}IqQ!8Q2Xw{D^!TdzXW;^7bXK3>7NHR)aG z!xfZ+AWN*nwY7GxoS5boFK3HJs6ztseia-WTSniytLwW|gA-q*-rFYzYX2Ke5_tPm zZMROXjNXp0k`k2(;{Hlm5xMhqP?r^8Fg1n*xeAHq;g^G;{0EET@Q)$uM1_psHS>2J zW(E*F8J0c>3hjygG|li6qgsAOT$*|VgPm4x>gxkO*K1m$-|Rvmbczt?#EyB+H%w2##ql{^vaNYZy| zB4&x|A09I`HjhFUK~}k+>R&>0Be#R`e!kPD{;I#kTbrq7z&ni>8p|r;>w@~p04P2j z8%MU8g4MVW`XVy`G=-@rd|se3Buth_z~`Kt^jw-7edQ%KJbo(N7~ifQ*j)<6?f=QX zr{~L*j%`5z@J1ihSfmY43?gBW4aevj!H=<@Gt!U-D2SU0BGF}?b-?w7|$Z!-3KMKfcwz|pKw0tF#qmgUR-H5(+B8G43 zQrkBV-|aT~ha$y+G8~N!LEoSIHJ2YRys%swe9|A}OFU2t&I|f((bm?pdF}UQ8IH@X zP&79`02vThAf*;Zq(vhLj+zsuwEG5wG_(w^3p(`fK&6?)SwNcc>BcW|gK1$`&<-qE zTAnl6VQ2^VT3X2)_(NsF4G#)@Ds(9-kA-`#9xt>Txg*c*W6mhbl}Zn;;7EQ-i*L{6;_Y-pno%`pov zIAgPyj5BQNM!)E|@~YQ6^=&5}Rk`h+?MMAs^?p}{a-oH|n;D?Us0mj3u7_Xb!uZqO zhhO=0mzv82!T28mFf|oZgmD&Y?CNS_+Bk%6KG&I+r7J@+Ylnd`19;Z%M?h(_(VQbw zK*9V0OE+JWq2A7RTvpyKrF(5wykR}~6KFLFQDoT6=i85zzez$lvx5ViIT-dI2MkoA zIj;mc+&R*|#EF86Uaf* z&`~zP@IAAxwRPJr`jg8NOJ1H#@MUIze$!(Ua)2|~eialp*nySGUvwz3N%uHb;qG%; z!R%Zf_&xmJPqO;!wQvc*g0cJF-DK!Mw8f^zT>x-THj zv)Mbn9%W0bq)Wp(7WNu{9AV^80bum z>VA=??w%uL|0cVFDk(3*xOhhf9zhQZ=DqrJvkk<&g3{6n6hV$>(IAU9L-30Kk{xG> z(&4?9Y+w^J;OVo~oCT&gPJ~O{x;>JP*$#Mm54CFHpgx=)v;+c@ z6Uw%+x}%#7mBaG&bM;!R#;sD2^MWYx?5ehYJH^$(>YQv|aeS`vfY>EN!&oiHRu;tm z1bs=f&qq3&#;A!GrN^R&$+`P>9XE;{;2~sNuIm1<>zYE%_v6b&bhu)CaqlaCF=mQ`pW*ul$J?-j~l1mIFTbN{8>w5UW(w zHSXIP6rScmb4a=BY?$|r66HGAG?qR4?*yGTw2c90QD-GOTZIt9{G=NVk4Rd$LXZVF z2OUv#YfcM!PBUeH_HJ}hxsrkP9LG5N4!#9yAB7p4kx5gd;GP|Rgl=0_5nWm5$CoyZ z?ocO=W;>bstliimiecD{{E@_G^NHGLa~D4H*rH@-#d z+W8}u=_ad5G7cEpfMsl7V#)eY15HFBp!s(U(U4`TqKSP|GL`S;CKJ;Jyw_?a#T$4# zJwR5Rs))p;G3xEi*=N7_$$2`dt2Vf!UO_f;sJf0y?aEI_bc6(9MPPa)ds}Vd7NjKm zSfqn>1cuFk9u1<6Vdqq4nE<+Fho9-5>DP@u-X**{u<+=(zigXahMZc5#;|m2k}9AD za}96~kHMflUS0Gp9o`um!`uAmCA**?=hP@gurlsv3W!>AUGCZXNaG*ve7>Run^?v>z({sK-4=iV@I zn>KFQ>fkmXc9KxQaVnle`jG<~CQ{L+-y3K&H5g*y48`u_$iYd>(C%@LBq&{0#c3ch-PF&gTQgQ=KN@FBINz$grKvQX&+=J!m=I279;|LnU4iG*Ebh!ZD;kUZ(4Xti`m--qqN$c` zDwbi?*WG~YCn})j7#3Q2EamN^(1H}CGl`)RT@FX?1r0*=ODCtV`V4w#O2Lyk@4vag>X}&=0cUF= z1?cWStqXYwa1#-}k|`kojy`{Pt@Zt%6O{YpKzG8f*{Xmum7_72voTu!h%%IwiJrP- zzOyO$i1+i^uoqEkHju8L$;tTv)d~m<4;xi9Cys3s3Fs((5*YggvhRa!>c9iA&BlIe zfh>UC*8HKc$0oPHOI8O%wtS@JG|d!WXY{^Z)}4ar(3M#oN&5WfTp0Vh5TU(l| zkO|bLE_`!6cGVtFB6QmbVf;Vb;<>X?Us6YH zUX=#iV#2B=aa0bpetN1!^)2MvT)NRgEUl^AJ^E8+zcRG*cP$Q?0K?wN3XC@cvo**i zkwb?%wOs{dx}Jj^cA?1aet5V<5X|D(aGejHx$T4q_QLs7eFo<_Mu3p`vQy(oRL z&uZQbLLYw4c)^Y34nHsNPtF?Fe5&!+lj}G%r}gQCWNvSe@VXrN@H@eZYixnn&rCmb zrrsf1>g%LhS(q!5tgP*`-hh8b#NVDGCns z1U6R{PFYh(_E7emXM7+ikGsj}9Ho2u7yXq;5n+5HaY4DD7P@yn^2CSp^ygKyZbozHvR-KTtCvz`9DRnmJ5;LHo!uVj`zpQy) z_e_KE;zRR233v1IEezkq>V@ZLvDIcjx(|%5pht6sA2!UrRV3H-uNci6)?x`k?&j?e z%sBw5QU(0Q1}G7*a&(2dKJ9_}kV#d5!ib9UV!NNE4|}6I^Z@6XRBg|Bnq`}DdU18b zR@sF1y|3gtP!qyuVH5KtV!x@$-JcygwdRK*j2gke4u~yT1#HD~O>4G5s94rT{kKM` z^xLw!uyf72(_(>50@J+@uZ$LTlvfN3igB%Kc^qLq)7KWq2>hM6|Kb7&3Apo@@To+r zWd;M`{?7?l0bk}c`E+=+oDbb-F%_N~qmAuH8fa)r`NJz=HogTxh2}zLt5Eh?@t}e-DptottAtKYOIVK~pn<6Os zk>St8yJ+v0wemfHdGc;MCz}Mv{-LZp={~~SBPPkj3F3MU6**1!!Pg&JCZ?jp+99k~ zUII*iiP27rqmlFXfie@hR`)+OMzfiXequW<{Jvem=wemI+O}A2pNi9L`0t-l}N~$3S7)#{2F`5D=>I|W$w*! z6T3H@N&O|5J5bR@+-IgA%i#Tr6XudW&e1TTrZnXfR>ehT<6lYUC@_)FEU@mCz4W*cP-@$c#EMW<&PSHX$xP+Q)yPDR&BlMD&w;) zh)r3^@7+h&J8360Tn;xduJJWpb=(rMjFf5{{AtgJJv*ewKZVei z8n)4E2g?f4r^63ZKM>ShmaYT2j_dsE%>2Y)~WDg?@_zow6EuxKdM zsm8nLb0;|(_pd*a)1;m3sZw5h^?hcVb}%3v;Rs;& z3L=SPVqltI%zE3!f=!4ce1}9wxI3_JqjVFjdyX(^70sUR-73Jk^$@kanTXglWM|Wf zmYjx~O$*2cH}O)Pcam5c%R9x=88EZqp@ zp4bIw3qGI$nzwX;3D6Y?L%*wh#+XM&EN=~-|3V^_H;W|TU%uW;gu9d8neeB4^@av) zAbB)fXFV3dOZLeNY6+PPhMLoh!CQOvKf`^fMe^ZemFbV6LD)o;zKnqH2-FpiOO zc&9bkB>Kz}n+M{XsfYIR3_V_pX+P~gwgsIq=I#CgRH|q8QE8CYcl%8s$>NJmg%CeM z)Y|>)yQ(jD)<&yRtt@F#%pvlJ^U4L2@nQXB`mbMdl+Iu6Uk&FXGbVtHZ$R_s&B>Ou9`Qly{8gKZbmt zJ}_sGPwiLekDpW~$Bvv7gx&nUQpdRm>aRv+#{i7Iw!psY5bOBS?(~{q;Co~dNW zujo-{l3R@+NPHyiE1?e3Kg#`xmIn)O_CCZ=M(m|90hU&`XPQ9Rnnb$o<6LG&7GRSE zC*$x=Ge2CR%1O?6pmx!)*!+w872jyoN~p=-jbk_@Kb@e zw0d=p>JlQXe4zx>56!NbYl-1b3ZTi#myDGX1F|JSaHiMa_+i2h?h_GyEUOgV^#Ec?WCHD zX`L^GWSNv_G3$goV2*U++Ni#{-+%{`jJVgz^_`p%nR&XWV#PLHNu1lSW-8HWG0O4+ z6t&_=C4ORURr+$bY@*i=xnWSJ_W=i+5{F}K)V3kmRZXYw(-G^f=@YSG8#Vlz_&%QQk=$-A{C`$w_~^i3|{;i;e!ky{>2fUH0%lC;i{F)1dRO zn)Th^HuX9FGQn_rU{{Dh8${Ddd6nxtWeyj|)rizk12X7g)-UcJ{$xhA%$#WE?{#PF0&$}u)B!d7C7muxdvCDqD+HjMHO8MAP z31rgQE2U?%$|t=gg92+e(uADbULmn5bB7#lM_;gl7OheUoeynB<{ge~VceDQtZ}F( z=X5k~`BCtGs}J$5;3{%bs!ls#Wxyl*(^QLi{k?B&e&wURn4YF>PfteSJQ2N7!Rhc> z5~o>(-Fa56CHg7by`4}S9=?^nGnDY472NPOJBYB+UP{56pi}14YqIzIsEN2%DwI@t z5!a4bWL$wowpZ}LZF2UmTJT4A^a)OO4Y@C^(Haq zM*Z=9uh$rPtQ3nr=X_U4C9(qA-kj&HF2s9@E7^NsV|j-6#eXCMOc*p&o#Ae0*D8K( zCrkD~v7A0H;H`*%S6T&)1W~!&Vo=>RAHfM9E?jz=9=0VyWr)4ebfsWx^s&6P;M6KE zmtWrRvb*xerVkL2BLwvr7QRTPBrYTg{=&eaZgS;TynM)l)l&aJr*1*uiVm+>s!?Ev zu8W^JcxW_E=X%?Mwt4x{Azu?jQrPJW<5m55lbhaA@mHDOCh!u}b&L4cc)CL7c?;&i zTMYN#UVmdJ>@v47Fb-Mrz=2j{o;JWh=Id;A}(bf(SI8f{4EVg-y2Lf*SmMUq=RYYa zMUWeoLBW|e%z*aHVr8C*)uBYIOPMMfL_@y6LotQ!fi!LZ(xSQk&dM`GLZ97z1p*`n zMBzS%k4>kHQE4z3MKXUekI7pGfw1rwH$Xbf8dIkRjToFOZWz}!kde4(b3in5B~K1DtY$qRr+aPhE8$gNY*x18qFNQkX{da`RlYd8CffUB zv(vQU**!K*G*tX=Av&2%IgOb;c-ntaKe2o=0k;+&PWS6zO#^`$h{Mvsz-ewdWMCGDslL3G3$IIc}vsCZ3UthJ*5W zaAM?AlgVYun_Bpi40k+NY*N=l2fq&~MW2SI!^cR|J(!!(F(u!_kh4JwA0GD@ z49^gGQP2>A zw003ItsyvzfjU0ebs!v3E2D7L-h?*5=crFrOf+aq55WiyWElz3QC~k^Z`U&mNq4c2 zVslUsonC!sG7!CqV(JdcY`SDD3b7Q&t!gi2R{2HOJ)srY9?f-}A9L{w{2SgG+@Xba zhL@J!lCg{qF>}Vtlr-DD%eT5jj4&QHjKfk*<&>XP$3UxkqCOp;Y0OGI6=PB)lM~uUcxnxgMo%CCp`iuncU;AMUbD)8p-rXK?&X z!XhN)apzw%P{tS2#abqM&=JNXefK`;^^$cG{Haq(`;~Xg-aFJNugsm!N7|CULmBb_ zMMHvgg#PGbg?NMQ@1*D$?`Ie%A9$uy;dTal_vTtq;b`vUzfkQ09gIcn?Oerr%WBmv zm5CC|eZ-NYh_cju(wxtQ2`(jTpBJ{BufXC)Irhr}Zx@B7e?p{%zUhe@^;KitzuQ zoi-4aL5F5Y#qDE&Z&6k__PXL7V@-mF>R;|IgcJE zgDo;788qAa80^`&#gI>GUho&_MahD0V4!5u{7U)cv9s;MbM)P!fWTpihxp|mq`Q>F z>h!IXzp!pVRr3N{XkPq+?z{*M*cw+hg!2vG1h3KCyfa%)S3CNV$bK77v+&Fx?-V{NUJ=pa#{R~A(0`tpb04+G;yT@!9npih zs+1fQIItr?`S-ZfZnaEXas~E8xD99yZpz{Zf`Ez;e#xTDS)Zby(kz9@#@MOO=GB#F z(za^O$NMxZ*SmJcvFMir5sl$Bn(uoi*d;LRukP&x+T+}TQZzNfcle^JqHfF^En4jF z6~vYgsotfRc6i0a)FvFjbNS114?TumQ_C3*#ffr!gVqyT(PGNmAA?12fWcn7} z`)nxXdt5RjXUpT+x(?pR7b@1LaYLTg)&XrEg_@5uc~WK66e;7a$BXZm>vy%P95@7V zW{n|ZC|Byae3_>w(krun8=2+#JKlI7krd4S*kw1GS!F6%ETM0J40dbH?t_ug5W~Ug z)yn~2G1LyYK?n!TA8|wLfeycA_@{~}-gWOCYh;GZ6*b23uAuuoB}CzpJVuQ^OMy7v zEULl2W6dX8(vFiAdy$Lj}%Tl{aCC+b@s}cm>h;{2oNViQgvZxAF<<-ZL9% zOFcc`9&t**3+XlvUDW0pt&i}?GS-g>geW?#S#Js$ktD)jjbQ8E)Mf@$-)JPaP0Kml z`nxKP5yp?H1okw)4O({>_YvKbq+fz7cq%g8bR}MwnHkX4et&4cOe+UDL86n;U~A4#L#efFTx7Qp z{h>u7O~u(e@jkY4JD#S==7i_p*pzPo9*?r|^F>UDeJ0w{bqmfl=x+qE)WBpi&Xw{9 z(%OESa*Lh+h@E`5*@5ymPWJZuFR4_i)p87fS=YlO6Ta6&uXG9p_8i@3O~~EbX7x77 zyv2nKygJwT)I~Mk@#0~NqC3}^Fzj#gaa!^B8*DxZW2Z+A2S2V(@Vtme$)$ZX;K7y^ z#jy%ZaK7s4VTZp%i+#9Yc_qEwExy3irb;h3^V#w=Y3)eq`cJ99VD71aD)-~}$nVO1 z^d`$4L8vdz?jn|zfbc=X?K!oc=m2| zYmU~Sz0Nv+vGX)1ze&b!KsI}JPIWvhcR!oPl4+~FVKD*nl zqjQ?p?ai4=FG48}ESM&RYEX>7?z-|~b9*Uq!q~3wkIyM1&s{ag0 z+LrVzBL?=ai+xN}OG9PF&jR!MXP~DK`nha2nOqK-3>GXO=KU*w35ZB?+F}Apn=IRA zI{~p&Glp@BS4g@^CbAy-0F2tCYhaLisnAxC{rQ z;tbzhrXLP;Kj`*>-wq)=%u4wc9rnG#SmV*j_86;4iAHF_#_acmANH4pz zWRO9Ieep2ZvF6=|a*`W7Jq$fB=0sB}&E=K*FeTKp|FuV2@#s@YnvAZaS!}F|0fCx) zrIx}Wu|D3MW^l-MQaT^!J!83~Q5Er~-T1xyoiF+gP}N!e*=tm46=zR$pMt&kF3Ya5 zQ@MtBKM?!cJtZa<(&iX_Q5mu|$yw&`xzTzTf9c12X%o|3JA{0*QA@or&oIZ0U=|C# z6lAxYOYYxlB=;rYpM3shC&vG9ssA^*)c;6vC-!c-92g&%x6JFFpy(7MH}U*x+R9ZN zu=z!*e)w2kKJTB~91P1!*W6faeq`S0VfAzi_Q<$8d-1j}tU36z7ZIf1IBySa_I0;} zZAoB27dJqaWr1+qLi5M1hO4M{^6xs_SFtspB`uq6lGF&u8!l&WZPedF6FE2zqIS2K zN{DRt(CPyI6khNpnh=jzJxC}eHzg`n|ak$xsRD>ldV2QQw*MG)!EOrq>kj`%Q5*{wggaZszV)jLbGj>gf}Jf3|J)IdRj`?oz*zgDi~_ft)J$(V3| z&{au3^$ypbi|c2YG@cBqzFfg-fMxXOr+G1q+Dr{!BAGv>IC=NYarS=Akcvq2T&y$8 zBh0w<0YTcs@+uPr>v;kbDzV0nr(zizT)50z)mxf_(!m+BwRtlU#uv40h|;Ob3Vva@ zW+v8jt#q9)ontsFk0VT=v%C`LDqctyLVkntKa-6KI!u z?WxskN8ml$1_?>!{AdZO!uW$AGwf>LDVpKX@@R>h5fSh9A9hK--$`?sxG_&+on?)x3sKn_A5NNBc_5UM(f~ z2}FMOYGe_yKCC?v_ujePT(piSaZT20l#YEnu70Mf7auc2OS-BUz03bFA7&hF=pc^Cg*w41= zkFmkdVwEhDpBY%%viOK=$HuxJ_pQYhNT@x^!q$>sL+D10Pl|bGGOiu)MyK52ypJ$p z!ZcJJK9hOp({TzcJrgT4SgV2DPZPPE?n0M=cq##%lW)PN?`b6;tW+&R?oIZ6571#( zrU)gs>HVATykEs*#rU-;OJ05r0$+c5JT|PS!ves_Gw~#$pj%Y2H#0N5X5wp>)s(x^B#*7y zB;>BE$ap6fS|Z|hyxbo)fLoTpG5H5>LqO(?#ZPh2x#N*?8hOn^rd6N2 zV4DYAU&hciY|VIqC?cPVxd7`JrMhaR)l5HT$W&Vzs3*S=(yOm4lCt6(#38B!QAJKK zTB8^_k4M%bS4IV#9#X4{eTvhY#?^19r#)qsv)7IpKIkFd@B!VXi)})K>V}Y9&={pl z(s7gmd9lP#-|G-)uUgL7;`Z+W!@t}A-*!j-vVZoJ_FDXo_-0H*@|`c{85b_M^^fOb z920QnN#+d7r8TG`DlvKDn4&hu}jPxpo2n6S$ut`){e z(?v&`+VI_-;b_sG$i@MiH>d1c*t0Oyy*c!w>ZpY~Nm#%1`si&G@Ckoh7-}K%4R_CG z!fwbMdqe&4T>GW&(YY!8FIP)t+#9s1QCL;C+9_7W5OPpF`5%HJOEZuE>*$AtdKoN{vun|rw+AcS!{Kkz5H7O4INdno7^esNu5R9DRRB3# zx}8w(HtZ^;TsSMza09&nQ+{u;2{(Ll9|sJ%Zzgq#X)A7cNme|EB8RgO+81QM~+Ga;u=mPo@7ujA(mJ* zHa^Wo$dAXHTX&eR?k+dSPU7lrND8u*>E|AdO{6mHDAf{fZu)GNp%%)N?OU0&Hxr6( z#X1Er_BQll9UAD`K%YbKSk<7E=8%}*Fm3~M=?t|Z(#6+?fXeP{jnW!~3Mr~2mxjax zM7~tH8o)oAU4$Z3@jtC;F`ah{tTb%~bkUB)673clE57){6cC+Gg;-vm3Ik~*@&n-u zrWiB9_gsdthv{2V9p9a4D#L-HHQJ~un`zAMlG{AD+t!Y69cpLgC8~iG5YWwSswA@V&F|^+!Yh|Axnk6N^}}Z=2arG>A|q&f*SgQkNK5~Y3>te|KMAYQpob} zOg#t#5j{C2yPUsaX>zyn>q%u1^9te8{1;lf&;(UP;f~zn?Fi!pQ4E7^JQM5SI8w~> zo>Wh7xL%J&>-SNE`zbjY>T6vqnQ~NX)86DC^E&lDdvd39t&ZGU8`OQP+2RJ9jW$xE z9i(D#;2_E_W~w**U)U4qe_>C^HJYlOeDZs64>_Nd2Tk*iy+R^W%u5{GT9CXZq?!43 z-%}=AEB6PpJ0{?ZyNPg4oki~&_t8g0<~QTY!k;hjNHH)7rM*tiNl+#FrX)HuDw}^% zzsOrXWH&74@{2+-xP?hR-52J9P_@?18;nh5W4M0>As$jG=MZ}Wk9|~iD0QNm`zGJD zXQ}E@DY;$X873RxXlQV%oxe2Or<1&?Yx^bMb7ZDds80sz%5Fxef3y zbT7^ZXdYDFyx(dzo~jv?MmYMx)0L%tU5zW7NX{zPd+jAMH9@YfP1Z^j@?l0_C6bu6 z__AK`_!u+>7GXaF6*DR}u&mAMA|;6~R}P{WqbyAG>hBj6X#-eq4TPB-0~; z!;)RVu&ise7-W-%{98V-Y3o3&}UoYUme-?{n78*u;MJ`|%TI zQ*H@+fq&;3X5*}+nl^NOH8PCf#p6F_n2_j7-X{iaxcjcIyebppT{hiwE+q}Aqd7I2 zPie#?+8S{1@VohnU(fcV$^V@si8WJ;Fs|G-RF}(ol<;~-qro0bW=R4(QI096X*6fj zrL03k6qQ|{=!CLqyo?H6n}c2y5!Xv8k#mf;nq)k`iMsBm7&D8^(4j_3I6g!xAsc-& zY_6p0PWjP(B(;Da+Q~uh|GmhkKr3{R6#V(&flj$Z0IOi|l4d(jPsv{`De=HkVy!{U z7-FB#SB(F9zhduoimvXQGvfdeSu0&IX{oGt(;KRnz^3WGYU?%lR-?0k?=tVs6z8kG z3o1>OA>@T8S2Hhl!i(3JT)%rnNcd9F;qKVi$JBMy#Tgde`^97NGE$;3P6n%EIcqC2UNd4M-$iA9(dOzf4!2E?&V)VeaeLq}`~+@G#hEnI1nla)pl1UUM|B|6cXr3*%5=Ouxu__E$kF0C4Y{XSr_GnbGd{&# z28{tfyd^|fX!u|3y?0bo+uAO!8wF8{g3^mf6G3{FwiQJ}5do!1FCrkFAUy&KBE3tu zPy_-2lwJZ-LPu$#_nJs2l!U-tLHF6}Is5GIj^8)F-?;alzcNO$*2-LSzVm(G`Ml+^ zaW1E7pKSzcO>4`ai71ichC zLPZnBJds{-Rima}R_vN~m*|;h=Cmm{SJ`5t!gNgsowQ94vOlqI$tz}Di4Ipi9uvKn zNUZ)O%nIk~EiT}vR)JC5E!=Ie`PvEX5>&Z7a(eUhvB`aBnTA}&TL10|1OBml#GhlO z&R?}fxffMpn}We75?AaWV(oa}2z~UQXmox!*urRXLnif{N_6}|-lHxpU-le4QA2Js zXWG6{(LeB-v>-L%j`5xA&iTAZ-f(g~ZY3GicFbkzE4GbKgM2&F#b%Cok${ARyq41| zg5HC%wk^d%&5vY*cR0Iu5BhF`)s}lLWb4;Yp`FlsUN(aEXTwr$H76QtJW5%*tj_%T zo`b*bTzESEF;U2-I!aVD^OI%G8<9=z-dRTN_#8|eYQ`KVX|3COXpR#a?dmoP89$-* zY?%mH-)5ldOOpIwmgIbQItwp!J?(MO3XbZlwG%xkc{)rN-L1AK)X+w6?pJg#W{Xi< z>tRgO=R)jI!T3OmaOY)AVBGB*OL1SOW5*_C{?7eyWMa_DmarmYN4yDR+miv>3Qoi5 zRfV9VjQ5S9$QbN{22c%oW`DBg8&k2to$agnjt?~SbQEDD_Fl7{K-)h_*1wAkJ&t%K z-dzGemr2I7(|mtFK1Mun)8nfeBR9aa=8RI)%#?W!RmoZHK z_I%{48>vHm$vR7c_svgR2V4<{CM^|GBudzFND&qIFy)p7v~PDm$q zy!e+zSl_e4l3!1FqJSQK)f&C8RLoXfx#H+<3^!_kU+|o--RnzIUcM&(0D10!rl0BP zc`|=(roZHB)sPaIwN@=qr?vdq+|uK|2gGQ~&cVuztT(0O(u?A*R5kJH0`kunDw9-PaY zBsgDKANyh@zY*;AZ#2Ski)9O9g9TFYJ%1e}CdgC9fya_3_?D%Nf#wjmA=J`|Duds} zDU!)LTEtLTF0UPH;(*y|V86dyVsLQC!H2#toQqsko`q6*h`M`v)8;!&-pkn$ zU01DGC{+!qZ9Lx%Gq7*%G*?I_=URDB1ZEs1I(|$`s_x%UEG0cF?82ia*#0T2MR6SLw3Zm+-XD3tYa7gnh7HQ#!Xv^IQOVLL^ZOS6DfBay)>_e3+u-^09565dc!eE6MII@1hM#+=wRJZc}qg2?2j3;fXm1)t7GU{n+WJaOjax}GU;yjgofpc zwhn+-ph(-FHnEZB=D_LV8$s!=1EjAKZ?*WVK~G zx2wPbxLrC$S^Jt0jL@S)rObHy7)#wHd7Gl|0p5D4s>vinhF=pF4H}dgRl3|OwPgG6 zY**_U`oMu+KDrnaUA1DF>zu7rK+2V4Fk6DfQVgr9vxssr85L*o{_ev&nm9{i!pUU- zCkJHAr3wo}qj5Leo(oM;J>q9c!f?tN@Ri$rY@fd9ucjwU9NkXE>SfVdGErIEus72& z&JftYR%vdI?0sceGvs<#Hoz@&MJwz*j1gFWUJN*wN+>Rx@Q=bsBIRppAReAcoCd(K$W8YSr@ ztdzkNl(F4jYfWvlh8#e_(zD|$y0bwPoMkRf=^TyEczgTUgUb$dIk;9#E@(&iWfV6e zj0mB0P$k#z1%yfWR-?)m_-k_C z5*csec3@mJs6SB$Mb3L`=Yl_-b_huQZYIa$6FgR&n$s3{M19^if`Iv*aP6@!gynW> zwHy3qg9wZpL2~+Bnp-fxLG@hCpZ_t$;SLZAk|&;T1Ll?sKMaeKlkF5ED_!_H;}?s* zeXn_z&$4;jF4R=EYxL!nR}x8~cqa$Y^G%?0|PId3GeT&_yqrkV#`({F!>^iat(Obg@Z#@IPCmJ?W$bL&S9Ev^Qq5jiz zJ~9YE{&c_3oN<1gMKp|LYjgEp!WNL{gZ}7X0!YX|vI=9{UCK{{rm=EAmYHcyS;CZZ z9=ZHnkDh#7&G{Ce<-GKKU5=guS?OFeJ(>We=3oKiK(Wkm{pNK-n(@1XvaLwDen!e#%>Ht#=P#{aaVrT4Gmw*eO2Yx zQSmlHD~n&Ui!YWyus6Z6mkA!B24{l7^fj@>Vj}Ud?&Dq(&?F1(gz9Ju5XxS* zpR``oh;0#05JO}pBCqfSmrz*anJ_S0gy3=7XcO&4Pern`!S6!Mhkn<6E`m7b^Q2&K zCFxj2@nf0KRE;;4tI1aBgTmNp#=R7Ue#NkJ>~3OiE}ur9%cu^OonBrLlav0n45XN~ z0oCII6!45iH{a_4638U-@>U%>IpiUaQ%k?P`uN9s6{Xc`$!2Dy3W@1KjDQqC@)!a0 z;4A~GLBKO?WlNn6j+ToaWl*_B9v^lXw;i8R<|4!MP$V^ynj>+bDWGpD;`Wor^XR7^ zT;}OsuXbG+F{Hkz6CXyxFiKZvOdCCIneWuNU&1|Drtz&IKTsyyr*aPY7VUA9mxn}R(gcB_a`}FI=;OVqu+E?x+eAMIQ%jvF3oSTSzshWdW(SBlI zJIDZZ<`;uyp}IpYNpqu~g+`r~dJ-6SN4u$ar5rf3_X$6F3^;}UKCBHdf@u=?TtP*S z6)FW4dun5vT}>e)zEz=o!>AvGyRCTr>BV(HQ|PO8vr!QWhTC+Q6E|_=?&!-y5 z@2iX_ykh*W|BxT;AhG_kHj0T<~#0 zFWQ|1s7PcW*+9zf*nt}F;lsG(iBd}-dZ3&3nnC5Phi2Q?pzo;jt)BT<__O%g&*9{} zWiXqG+c9QIeXj~fu7Vo5JZM>x$B+4y=t={-wR(sk~k>!P5n*bo&_9`W_W3V<% z2#QF2pmB0jF{Vg){&ks#_^+o1i-uf@u-U8JxF?x5TOSYj z9B%Ag%Nj_;lJnNb#Z45T7FrKlbST}j1}yL%QE9KK=A&6VjnP@0=G)hSyilq0`*E&Y zI<57_8iWEBAiJ{Xj|9JU;}E0^i4a?B?dvebo&q+5GI{YYzI9gsL6O}uT!AuDI4k%-Hua`6xAJumNz@jr$>a}Cq#k{6N=csSx;72*izxqVPn7tD^ z_tE$~_d0_G{vuBfvi)kLut^x*+UF;GA0Eoo?Oo*IYTR0!exm~!?jBX>yA~7J%`>FgHDS6C%5lkH=6o! z!~Jct9pE_pPZyp4rVjf^$%sV3@aSpRDNDMas;Ck1mK$L)?D$j zE}5wli^}EG8j|008+HeogSOo6U^1V_rlVXm2Is8`1~-i>eTym`UtYZY%+AaN$|qF# z1ZX`?g0z;T2nr*~DmWa#D8w^v21u$@sOx{Hr^;x=E6Ms7prF0n3$@ zS;H4t19o*$b3BM_vR{s%CxNsdfT|}G-G3o&-4Qg$|K$sZUS-Bh4z0@IU`uc+E%*{= znjBRtXypE2m8n>Nf`Vr+o3f``Q^?i_^+6EcaKrx65J?^o0ai_)XsoLR)oia$T_ZkTEQow=Ez$+Y4-mPF|0x)Jo^A35BfsU+>5P>QvjKiZ$gd6cI(iO4=&SV@pZccoRrwH%CcUgt(Yj}qHU@Mp*yrFdF zc=uY`lxp0?_nOm>r)sRuze@|49v@C$@^Mwvk)U`r64=K%6KtAlDtj&jN2o>(S#qWM zp~n$By|zCFi1JtfxM8aIL04VNMmtb=RAfvXBFO=uZc+S2Ox!YCTYbgiQoWpd9M?tT z9fu+_wyW?1!5No}&VR*?{s9<K^~z3>A+SDJ3ZDV^&9BaS~TzAGeFYcYl&N+Jm*1M#j_;97yNp@-mwe738~ts zh;W>kVR#T)lqraF#*bKP;l3(|p?s)UAf0r5wHR66QT?(W%MQ=7@>n)QnZ3)`-+Ehz z!~Hy#4V`@i2(e<)lAGDTedpp(p8OaX=libh&3O5zLjABg(p-krtryf6bJ~d^Mb#Ih zK3pPH91P&D4Li<9S27@7kUYqkYNBx31>aCklJrP$!AIQ!cQymJf(C6Ftxhk zERW3C1mmI$NVjF*N$7flQciA?6iI^BNO$ZsWJ#KQfYM~!t{0oTwkDg9vei^71l2$4 zlYj1d)yts0Vtcr9PrW22#zB|7?Z%aMs(UP;j$I2-Yz8US#hG@4jmvEZ8QjhTKw!Ff z;@Xm^(#HE4AwspX+hg4dpAwvH$|GiKAF>-96iITF5o!(wb^3s}s?ttHd3)2goD)Nx#VWEK)p^R#Hfg+k~Y^I&i zLgB{MFMqaFlzeM?|Gv6xmM^SLXp>R9tLLLO__}?9@^Q3HK8j4W`|s>AAJJj%&C`2 zpr5cpf=2OlgYvD&T4sanDai~&_AE0KEcT0Fwbirl705x2*&5x~o#cOl1;xuJP7`23 z3RYNL*guKyJ%C+Hg`hev*{SY%V99e$YOhcN;H!R{&S&=_P-0WN!KEgF2T2zCL9^S4 z;CGX+ZZ0buKID2=3dFKg7Ga;EkFu+Zoiy(VgqXj*K0p~A?I|1mDDT59ve0-=VmEbX znXi+8nq%YPdh1Tt+|+?l$nQRx?y&fcGD_pg=+K^#k`RU~EEx%ppes9G&G zN1p3`?Z4F0HB&8@=Y#SOO%?xInNnM|qbY<>0wA`yrO?LI7oS9%y{)A%(2yu{d@RT;P&37BC@?Df7A_$U z*%I_sOZ+)zyj7&-`c?GI$ebgNX|=ae{PgXAQi*8*C8fG&CEgoT1T@Goq#_hN55>J4 zsCr-+Jr^;SYIHkt&ffRq*FEV@>{azv?3XQB3G{YHfBHFVQ2S*b{xnScT`ydVxc02;d%wpcC>zLeIr&G!zi(gshc4{zX8@oJ zdm@WvA{5Jg)&O6r-H3x-B+M}LKj!+)Rq!dGAHcu^2STdOWeuRvCLVpSrLGmFMY!-y zzU!muhvalP!flJMzOh1uLkGRDw}Y=J4Ih0w`0d-fJpcdyDith;v%xIu)S3%;Z87$T zNsKV!$tDh(B|NdFrS^`n6)S%{h)FG3Yo{?(?0)QHk-KEAOBk zh;Jo^!`k0Csjl2Q`urSqAz6T1Bi9sj3wNJa2xwUdJP}~rq5akjPWc;=nX5(9eEU3u zP^#*rtuBFp=#?Nz) zNTS2isEid3FPM3Q>TNFe07y^Xj|bsc;dXoqr3D1GO5o|EH20GU+x z3d1{OV#RohYVo0`{DU#v8o*o=;DN~xW*I+hC?CIM1TE$0Z&I^QeCd{a)W=rHz zdark$Yv2KhvxLe#({N_;tPM7P&I~(B)!eDw!hs+efsC%jlt|mC3VW~GC70fwMYl02 zc{w>Mp@Zx1FNTE@5pN)CCO!M*^T?ak*?0D0Y`-#K>l#*)n7bIO29Pr~o_mYsm*Yp~ zx4=&>Lmnr4fi_A{-zyF5PeaJnZ+6Be?UHpR3xyd{bETc}#2}L#$7}i<1QtCu$Ohu` z&~{ynhu#kpZl8+FnrE>$%KmN7_Ky4VV%ittncx~DKmxvC3#b95voDFv%gX)5kG4k z%`)cW^Cs zuLJTt>QJ9PscAEbYb1nFWpaLz@c7F&`Fbfnlq}O7c$D$-T|@sjRWLPQ`Io zLMD5dch_J+e^7DLueU0Ky!8#Zp(0p%A z#hGgtZ8FB4?yHn~Y~WTF(p{K@?c?n|+mI^y+e9a$s_Yk!t2r*CSf9;ijmy4HL`ppH zF_Ww<5S5q^Bg@qdD8>3EFj|OiLeZ8V(imQq%mt8WSy#cHXj77PB$z9AqxhIcjCck^_E%^NqF75XZgXAI#I&8kChLW8pOiw#9u*%$O89qGfLC?fOcSR}cq z#6to4CRN{1VK;cZC02^JoEU>-typnIR@Z}V^l!7`$c9m{H=QD8$dxDz7M-`QIu!o= z6Bgm>fcdPzvqJ}a-U_6g)WUt|jnK6f>OgkL7ga;W{pOkAR(Z3KuH<@mi!UzM;dXd~ zexx<$i+(BSed7rGK6KOOOesKK5eeC5s4yzG#O__G9&kkhB6Atf;4wrdZ z$b#)y~KG&Y-Fi4plK08*8wpG^Q@?EoW7{`af?|YFu z2T*Tfb1e-evPcB*udViUoSxeiz(VTl^6aZV3em;xqCX0~U#G0pe#=eQHv}l=nfLhR zoEBGSfM0SYZ3T{k0a@KpJwfQh+2-Ruqbn|>@2J`HiAm{a7`}vy1sZ?&+>Tso7BNSX zXRa_|76wC;u$Wies=F;###Rt=ll_3ZPN&mi7{cJD{k{|h5}jhrhV5J4VEDw?Aon8| zck(B8a5lR>B$$VNBse@oOPWg$AIh!YiE^F@b8XMcXfHl`{pL0qb`mcB5nE+%_(bc5Zg?sp0o9 zq_2UMA#bvkHqPjEx&*E5XUZD7ovmxdrWcs&w(AxHkXIR*2H)2&|Bm3FaCLrSvVeLy zhhhQAHMVbkEJ;hEO*`eeMrF)_r8X06p(Bgjsw^44uJej)1G9Af?$sd)a0l^b6Az197loW#DzB&%yBT2ZoVeS{np1NP^LsKNWDkC2>)tdwqGtY==X zQ{Fh)HZ~D9;h^bk?DY=zp!vgaAK2!JdHSN~Vl(e@^~&(l$Y;ZB{9v1@QQlnq9@?kZ%IDH;Yzdq;bRvdQM=tQb%VTFc+@e*2 z?sWr-u1xEt^;r4|=h|B%akeT?>`&q@%m-Zq(MzqO4wE?^yZFjqG_HX*%Xu1~y}_B| zA)bV7`1H_VHXZiKR&6ImjE)jxIlublEua~Pt?p)$*x&5VG-RBG@XR2@OIPySD-ZF5 zu>QV5OYN0P=79wp*;yxqL9K|TZajK&nu_1NN1_Mo;+Sd!<1`Pvp9HN};i$N?hu)!g@HS0Gqu;_= z-0Y+qUMuj*X)F8UzWJwo%EOH_za?%9LFJ`W9Y?iznH=5=DGQeC%!G+o(1&VN?tQ7a zmrlK6dfiZB+NB{+`ZjI&lN5l^M?AA&{&p)q0Q4XnSiw0S%h0zlwq>ybxSSX=-GqyW~08uJJ{dL)EnN5(4U~?UP%n_`VgNx zF-F_GQbmn)K0yL?laKIf*r?RV@vPHSHxFkoiJyf@f6M5)wg?8 zlA=C1e=rOkrZJ45>|N8vpvoNNHwW6oa7xAgxQjC^Aq`}Cl51Oj^d~Zz=+ckrO1e9d z2veMf9~AO~lw9XBD4rCDrrdQJTbFAD6!`wr8wvCV9N05YQ%uH66)zZ?j5cL>Twarp z<(-?oX@{~!C%7>LC*1X!#E{aDNz^C}UW|>H)&Fb|l4N_!UCkPH4(oYA=5aqdlrxQX z%zcJ2Idj+OvxDsyjN*5)Gj+~^TT=}W-yIAFZekj&AJ@K~yLKTYTD&6E3*|BPv{p?9 zt83RxF5LA3aitTx5_ZBkfk!@T3C8Fv?~V6-FjmpK5@cuvbCgfEtJo}+gC!IC=cnhT z6IL#V5wV4Y)tB7lK0E6Y`P#YwG6rsHFE3C-E19R~*e*88Q4Z6#GE6)(Z#1eGlTBKM zjotCAuDDx|hu%L#!ckc0YK0bI|2^OxReWIYNU77B*y^=01+Xr)nSR}b9Kf{?0}dZI z7Ch=J6rT1u+Z(kd@>CizZ8xxhZooKuB|GCm6A1;?-g67nXzCk_`|l+jI=rf?+_q+t zclCP>k${^Rh5qtBJZ>`zkHqDO6?JRPa7KABFGtu3%F{_JZU)$v;0;nPHOp=?9R&8z zK2;zovf1ycZ=WSK?GuX}cgv{v?cxhr$T{vI??_LnEnDuyaKaPf7j;Hit4vM7NfBSRm1h51P-U(sXFs5(-Lh6S;?%sB63+9>&cQV@TlTW)7uO+ z@AUrO0HFpRgsh!R)x>o{v+>js6fgU*ZG%bZC5BL~>OS4uhP*x0H*A=Cuee9rpyNFb z80NZ{>oNRt@qu)Q7hSvhjLQ6-?o>gm0BxruEw|V#ojOZ?3OuHTOtY8%aBXEUyNat4 zZ7rg>1j`p@W(hg)w052hNU)!!- zZZW&(By!pIUKwQ%ziimqD|hi9kdu}DhPeIB{#`Iamemb;l}BRZt9Wj#*V|Y&brQ{Pn6k5s8oTXd8Ii$eHiSlFIrnoSNQ1J(WePc|vsZp+ z-?5Lp_=>4obWS0mNZ!4{qT#Ongg=qdYE_@W2>tSl_v9r8vRIh=J3n8SjlqEZgXuT( ziGD0`Uy|saHQ`MK%ECtqQy-kXeB%)#hSJn-$KzDgr8O7l*WERSQ+;C{?)Lx)*U zA^CE_0>)+X0d+L4aT&pig6U{f=#>!B@?PI?^kOb0W>z83`%2FDmNxu%zO=_@y_4xWO-Oy~P`MfIYMD@t`pAfv)H$*Q_Gu4 zm02y7_!{|YmR7Kv{7l+>C7rSP*sB{p>@Aa(lGv|TY$9&Ubm!g{byF8AJ;$U|GCnI5 zwi;E#vg3-V?*xc;E6__OqdMImR+&3L20`KY0TBNjemadd6YLXebyu-ArP8=^2bPNj=mvRi??lRda|9jI0$s!%NVxeEqw zei90M6l}`LkfzeYh-l1i4J;+S&oz*`#3YTsbYcLM^gmd^1KAVdvxl+xt>^$0Q zgiFF;lGi);>zx)0TG@NLVYMq!xWFo|2kmd|L~);2BUX5uWoyD6bmIy<@4BuwNF@2) z91E^Lc7w!;c{V2aqM^8?-z7D&Pbs6%rz1n2YR^n=hx6Zfgmgx-+16dMVRaqFWHN`o zLPlYU(J)z*r)c@ZD0g{GWER@qp+Av>eo~&NSkQK1&znq7-?rr$9+ssdc(_zn|-eufM0YX86fy?)aX&@D-m zEe<6>+u^M_pV?M%)sxjy zmpq`g)<}J^Rk}~9A(ivyd?%n(VCbmZEcARal>j}W32Vyj2IXeffx%l5x3|h~ztX1> zx$kB};Ji#p+kB*}XP(~Y-CS*iv6>}ca=soVPc1~CiE9+ZT_ z^LKVje6joIscfxKF5?0Ak&4t@?w?43pSBwc$nxmu@9tg?dQC#(pI%DECwz5tA+kQ00D8>T+qC^tC7_ec@A?X`GKg7V#1Gu zv{m9zi?wNzv%V&8zGTIEZ?|JSwRFL4p2FR{OnxIsiJ|9jM7{`D8ElPymb;=P)PSVMM~bLnyv zP|-fX+&=ZW`%e$#35-*W&zv=fR(I+8wk#yxEcPJ`jQRItmak^gC^X1wUiQLowLpI z21#_Or_W!cbhFmotG}r#b9SAGd=H(t%X@5LJT2(~FpC$jGjNWbAIEm|_EXBOTS%Yu z{mj2Xw5hc*v+9e)L^Zu}!Va*GV6J<#R0tHUn0*Zm?0;2s+LBKD(_lFQGO%bVWZO@) zv?fR<^?S;1vqXV$or5Fy&G*>oXLgIi4`s?IRg{FFH#a&ib~nT1v1ogShSQUhXS0ua z6!JE-QPMRNa|kc41(4!(L^kwbv`BXJ((w>u7WO%e@nFl-W(T6K<^hT4tOv;MlJq;> zjOyNf`2O>vEw8ctlty48Cl8zj8GRvquMgr3u`J~@<7f%+YhrV{;?Scs(s)YxOmVFj z??Q^uLy9z=+0g{|NOYYZ8E^3O)x(w5k6LH7UYd%Dubi8YUvlbxgQ=VP<1G|O1N#l+ zxL77s=fKSy3I`wd1zNT-TY4ZNs1anVVFf~uZa>_Brr79KScRs3l0E7CRPtm?fFZrM zZ{b-LO0z9*+4nDy{pdy_M*6Kr$aD7H`VbmuL%hUE2fCK0t9=e@E!$(SKMZ(?vQk_R zfBuR_xQ<2SWg|4IzAQFQ_`&wOL*CNe3E|B81iZ{n0%(I+{i+aqR`g6x@TLOw*Krx@PW;0d zj!koy-@}(Yge&)-IIARQ^}%(LEJL_7-in^r6TkmOM@IfFbroH0Ix>&W9%4>Jvi zQzo3fv%`xf!{ojg3~5S5IOx{z`3IS{90x?670@!^G>{l{mR>gvKf8AfkUMvR+yUm5 zgpIVHv$;(hSdZV8`~fz*W~ypAQa<9RbmUq%0WgzUQj4)tt2l>-z)0e!gfH{29`}|l z+=E&t?H#X@Flda8cJuQ7&6tc~iM1Z~;knZS*?FtSzJpCq5sbV7WyXwA{$JCf>^R0U z7oJ-Fy$K(Ca$ScPAUsPjZK8m2z}`Drcpr0_*cxQXDp9jXTrb|H!@9T0^B4{R-(xI0 ze9(mLvF&3hcfled`JU*+Zf%&)WI`V6!3abfzvgoY^~6gY=t!*MAZxfWp)U(Qp%L7B zr_~PSpPA^^k58G>9SLI)U=>qdAb}g> z@%^_eE8)0o$TYFjgztLO^`TY#7uHJ4;x2jb-9xk-WTE@u@!dNEah7UBhmyK-nefAw zcl~3Y7kMz1*u&{F52c1CAm!UHcsD6o55y#{BJO2n%4(sTu`3G)eXaW9+(XSfa+vfn z?8IIO+;KV1E@W0$AI%rVbViEHSKkZ(FK`_8c~JJvRindKy$rZZ(dPX4RkPOze4Dd_ zIPvyq}taK}u zAUnsc%zRd3(j9$dOB|flB4@bLSLN2fygqd4A118C(502*1A)MV25nmCF2PPPi9j2F zkDk*Cj5{2bKO^)e%a`~QqqgQ@3Qy@XDJ@X^lDy)1fFLiN#OZV-37xj%*^T&HZLizd zL53d5k2)nz?lUrZ)-6o@7EIzNY+MSPScwvEsoo{Oa7Yslsba&Z@xtx&x*;sMd1}Bc83FJfjzAuUQPP^hTHNn>t?a@=VzMU{|wGm;k=0M)+AXaf0 zX3jAZEf5TZx&FZx(|+GjtV#|@Wey`26K1(aGYKnX6V&;)hj=3Cx9C=!JJU!vx#U&RIMDE zvpdvhrtI`==hrs7kO3v6(lTTU6u@@gb4(-Sjd-OQZ#p+oog@-t;p1W3cB!c_dQQ_` zZC_-LZlHWz-n>&t=T8-OJn#aaVswn~U1fScQ1J(m`*QC6c=?25agEtfY85hyFbTQo z#tORAm%_+SXF|o<4W#uyD9unW`%8#GEuc_=)+Y`uyT!FW#gORP1bmFM=b_Jr@fy0- zcek|VQ1~j2id8_5%b0{4-Ez>5EePM<#o|HrW%oI?0xfD zOCRR^M%zxOE%T0wnioF24 zbr|;{SG*GAJ-7aipKe}gAW~Xo=l5#sBrydIA*r{p8_Mk{2CXhvTh(?4N*--o|ilX(4=$6_?F}H?i zBQn)Lwj)2bibKU)w=*G#($$D;jN>$}S_$F-gv zB`(SpiZ9HFh*{;G5QjXLDUKNbN?i>y$G}VEd+c+11vU{Q?Cs6rRg*X|dmLTys%G|M z+Ya3rJCEK6@T;75{W!LfSf3d2&?&PSon%Z64`+H)q2~y_Hs1TogF|?CWo;;~0|Bb; zJ}3_>;Z$rxEGspoFHpUs>Md43&~3({BhvQ;qGvL2mrLLj#{qU13d)8^qDG$I5cC^GcDmC)w)RV4vv;b$$5a=y<}UZVQGP(HMF; zj>cWX*S5=nr1az!+pwN^p*W99ScY$++uYm1;3%-M&#umx&ViH`3e~W(NqM*|4|dS4 z;d0PvtsW@E*0YkqX+Ez$Vd7?iR9nj5bWWKGGQ2*3@qwbF!L#mdo|mM=oszxf8-@6G z={C{jXeZg_i1dzx84gUF_#8x!-!8V>Ho)|xSI{5Mjj{dnhiv@l9d3S!=Y4F5n*$d_%nFv}qQ2hSiIPimHn1>0 zxs+XgsQGy$L2eVWG{*^U6UWQJf<-z;#jz6o8R?kqj8G;b>%0l>)bgF(*=jjrs%*_5 zm^vzcJ6LmgI%do4)Qk1$4#va+WEoa%zEyZ=LaJKBgbmYjpbWu@tJL%;4ms@cwa-GL zV&m*ya*WUEHZAvpgQ3gqMcYLJ&GCI~=`*_nLQ)TnT52otkK30vG}9lepmuPK2{G>R zK9T19?I+>#nq|#9S~A9tPH%?!msOV1S^I>RAaG?4^ub!qVIN2iw|B{-p^cR~X95v? zA)5u_6Dxecz{_Bp91>Jo%_I*Gk2r4qPX3{9vb{WNZ$NH$8Mk>WR0fhFTg=QeQ^x7T zIcMp0w2oFG*QM)*3FZtqi(U``I?{=!$*2HzvmQ3A@zd#6vqMcc;#(yRXAsLSM<+Xf zuhX-~zBvkor_v+06rXb_$X>h7z^#F>KOId64&Iu;GbfC0fzvM-CrqRlaTF@HF<1Ib zQ1BjSVYk%WUf@&0WkRM)cTd!==EdIhKCKCRgmxqKow%hHnEW+_i3Btmv7E4#C`W8d zW;845uFxdxU)sFWq~B7M{L)sBA3up}6z0wdHI^%L=wa<~a4F(x=cKv0F(l7~vU88Q z#rQ~5d%o4vyv0)!p*yNuy*Woqq^0cJt~_4oiK{vMcxafXt*O1XkOPnJvg>BG3br1) z9V{ReZc&rPdZ6{$7tl4g)-k`gdAX>}PDm!BSm8bp*1|SrX{cA-k$3fnpG!iP*Bsg7 z@SxQSZosHvrn-dLTD`yI?0-;MC$`qj0k{R}YSTg=A+@OrZ5grB7kA8kxCh*i5(N7nI%F-@wv&6D)n(Ui6#NX8 za*ra3>Kl}%ba%1%Dii6V5%1ukI$JL&eiLmdOuBHy4s0xZkufvV!)OfC{Kh`BJ4s#!W19002ck2_3s?2w-ZQ)(q!>x*W z+RmMq@0Td}L~D(xN=%J4=L1K>#S4dSjRwx1-OzrRlPsB0SMxpii>Tswwwe>Hs~a@g z65vwd1jv5Psy6Jf`S6;JZmTfQ2d;zTI$aCquWlV&%`39S7Xfy=rU8HA`$5A(H`NMo zT(`-;$z!CdOkMQsN7eRYDu?!=O`~epsq&>5FH22fmjiT2jBgzyGb+6~zLDtJYsFjr zg`YCQtn_gWr96I$GLLn1{~d6M-Lx2@d2Csy*RmdK?qMScHCc6(_hY(v=lI6)hAWgm z{#7VM>pJ`v8&}+6uE61Z+^se>Q`9nwo@fIdY)i!buWb({B2MIFxf07y4Qt;cd43MR&_h;)s6#G z|NMS^;qZ|wJgR*S;njh00hHQbkKisr=*7e$ zKb_M*%B&O%Kekgd zu@R4>)>A+PP45dr#owK1XcLaG7-rO7AGxdLa9b_TP?Iv_j}1XswzaJ2I0*s}2yXY? z9|Hhh2EGPVez(l>Y<=Nxx+DZd4j3ZoA$z(!w&%=pisjEwS3Vn{OvZ72+&{YP%?Y8{ zeeVeI528n-Y@hsj>4c#cX?!6?WO+xh--e0qaVXLEZTL*=h5m0pEP^tSuR316M8+wA z@ArxSGMiwV)yAJg5?}v=Os{280TL?rhlCaqYp6_q-w1#-E0PAry#krBSXWzvze+%7 zhhGq~twrsQABhnuAa?2B#SWw!@SgLRcN#C)Fh0KMF&)f3>dht&l%SDa4#_E2LHW6s zryp&hy{D#eB;)r0{_H{S?*c{T>xk(so3LNt3rPNrpb+!?O-txA0mo)O3Nq3PC!fo1 z>gX{(_kN-|+H&}760dYA8AT9|^qcOa)ApED%lyEgEsP%yDk#-@V~W{!fsA*J(f(is zIGTxda()@=S$2@>6#)l6k1b)m_B}w)np-~qXKBkf)m?A7-Y>6QIm%k(19>Mxjg0yUqz=oz$q4S`Jdx+%hX z6+Qs!Vo#Odo?n{KJG;lqO1rgRF=6uRigXF|-VZPHi)zBZBj@FPBK%O7wCLO%di@`g zS0zFav!TRW@ur;ZS3lNsat#Df$}P%0Pz830Itb8Xq~A9;5bpB&VXbf^4KKY;e`P&_ ztF3fB8ZYac={7kisMRow-FE}Ya;{_F!R>1Y(oX*%)IVz$n?n;_Cv`tOL6co~3yh;v zGCDvXYq}e49R`KL`9A|O6Oe4C(}3T(|Joz831NWX3J$IqI_3B;7Wwl3oA;Ln#$B|G zuca?(X4H1}<5d$D{D!9il^6`DF!W)T=S(ofj-OZUyAxPWqRU8tE(M|6-6?<_gzou^ zzjc+}&;!iCH?7h2+?2CXF-A4yxTVn1VAcpQJ$dN(9!h6Ks(tGFW?lOyMc;o=UpSri z8;&4)0guUeg|gDzr-R*ca|t@3&3$$!-`j(SQGnWGzAgMJ?*)02jetyrANKw)mTZ}o zjCX~n5JJ$9gQ=#Rim}!GvvcI^hhQIlAL0g1>Y7~OxioXhFvblO1tV2Th(sqpX$_|yLt3}IzTJ^7awuKz$P5J0dI z|3I(-6W8JYZ~o{ic^<3xbSo;1Tka)b+Z4YW0U#0h_4$8orSY4DZAqubT3tCO>i0jkFr-7a@ygB-v27^%fq4k{{E$;L@G-{w1^5>3du5Q zMV7LRLG~2Gm}FmOCP{rNOC^-Gl68g|%TTrvp$Lhw%*2F{8B3O-nK9;fk5WF*_j#V{ zdj9_X<0{wf+~>UCulMV{o%@`3Elcx{%gZf3^x>EtNshVY^fyPx!!nrdqv5v~aG-|+J#wd>XXx*ZAdgptjhYZ3gee}W^xFUvi88Lug6RBHIS zLB#yO8TKm&a^A~ZN$&mAv&|4l%aSg`snOPr;B=s;DT~V}H{OVFP*qE^`b%EK#pUn9 z{Bvi6GJfX9hcD1r74tV7d`!n-+^@eb;JM4YS0#BQGD#M-SUH(m-@7lETcutJCZl%< zDrQ`Kbmjh%%6$~d;OJGKmB>aZa@C<`Nq{B2Qg@Vmn>_rs=Mab0?gzh~rM`G4!RhJ? zO6rLPDKIExQlnh?13Q&(4f5sOA`8~~Hz0m8HrbzXaeKJM*-@6eq*^lOc8gWt0eY?a zsxff;o=)}{A%$n+AxpjQUA>=WOgGsq#~cA6#KWhqDBXQ2lq&%{!=ML*z`%?fUT@2( zCyjmwAMsU;t^z9kJm`zr?yYNx-dG)TOyAe-fJ@^*bn@X8ySU3z+ktPpo@6Tne)@6w z%PZdd?sIO+1L*sxz7R<4RR=9}Y)qhJrw46%BMF`j8!1+1uxCqf))VV7n|}pasvqpu z?^{DXKw-^xvltvm%uJ3Zcsx5?`AWv{kBbAOr(KfeLT?n2EkORbr;zq-E;)K~+G0%x z5nsh^<=SV2RHU7d{`a_>T`w|Z*T)Gd*^Y8%Ap`$BCde(kLq+J?1bXk1UX#!)#AzWL z1^2*CHhAoB#&W3qtjp0(L71tMTG>OV|A@#$C_iycj2{iO`wRr-)bh{F*w7ga()%5* z^~Ms4iYCgD^?xHy;_}SZ&rkD?CD?b+g6E8-jFA0B745fBVKmHj^Ir)Xkk_1>0o5?L zgxIG2uO(c87^MG=v7wycqn;nFW?PizPYmRqNOaM_J6-ttyU7Spbo7vrB7=kZU!tNo zt*4E%2Q3>vDAHb}uJ+%VO!%J7TflA*MVT><~9hxmm7%;o0G$Od)HKsXgl z2ZGG0(GWLJ)B5HV4>)LXY%;ZE)j>w~OM>HcXAS8SCGBOFdPzqdsQ%n+)Th3y_-S6T zWs9-FMrHNjM_L8lH-G!-8vxf0L~kz{Oz5d`s=hvEPjnhsmb(2|Zf3S065*a<9(u9Pl>1Fu2)t3pbSJ^(B= z1yT;D6v~AEFj%w&wgv(FY{s5x@Sj@E{zf(dmo=xQRPEhAS|0~UEpT(K?hch5T9mMn z!lMOpv2y9EnC^&Gl9vFpt|`|WFZYZ-aSUqJjS1I#(bcfZ9l*w==Kbd`c>{sD?)Z2f zck_o|I^(TEx<9D)jri|$J3&YYJvEt+S~|ao_nB=JthJEysiBvnY}jlHC-TAmdkO=^ zc5Bt2Q6d2*=|1Mfxj+hRlU7l@5~jwy)BS9?D`X24YWvZSo*J~|?4`VFUFTI-&^A^6 zk1FQtHsBr0F>o-2J)n5xKbJJ7bSJ^_2q$hAm^o)V829AG8E#znz7e;h^SyffE8tk4 zr+BLN^iPA&cB`Bd>jGhaKTni`hs)LrY&|tJ+J<7;(I=Nq>>ZMkAg~2DFqy6NKH1L^r)xhgzc)nKp&z{lZ5-Oat08evd zrV#RK7Vua%$Xf%$FJG3aD7549LQsB>6Dl)QsvfHGO_#4%2Z)pPogsjA^00qaQUVxH zf@+w=zz_ODii9-$Dt8)a-bvV&Vx+DtAJ4&bw77QXk5v_q?s;GTJ4XcC{%BdwH-$Fm zZJ9t*XzPok7{@6g#e0f^=#sT8H3y{3U^rsbb5UC}a`c8$=o_b?3jiU(36s z#Dtr&5(S(8FttG7);q+&wR$n!dSGWg74QsiiS+=8Jy#N5oq7SY_7wB}eC}?Z$*vQt z8V6{842UcLO%KUK?RBXguaZ~+Y%R+Bo&|=xAN|!(D^6o|OAO$x1b=|UE9C!Fn-qJs zCBWo0g%$R2O!m(b)oaHXBLhJE)Z9Kd`q-qM7~c$RxspS@5QQ7&AA&HEh>tzUZX zVY+HFK*r%G=d(O4`z3dI-j73U=t$x)v1q68?|TK&VrzYUN63@oIYTkoMU?1d^_((Q z%&XXP{W*Uf{MNtJe2Zt-$q!%8IvO~Mth$3jAvD$|Zh$pK?VqkG51pq?D&5V%(gzMt z`UYa!lCdDWeyJ|T6t%h}!K_Q+UBCd#qqCgtkrR_-=Srt;7-rzLw?3J>~qVU4_?>;C~!5D z{rXje0%eCPLi$#soJ^OYZ zJT`oy9y+re(%B-Llhw(3D+Oi(RWBjM9hTSr1a$ygo=-VhwAWv}-ngcs9b0*>=4#9d zr8Qo2o!|PrKUvEa#vSWuE&I{t&HDo+vy-%5WwW!35UFGZ@*Zee2%J8!I6y1w-vusV z?Ida)q)53GE`6EZt#%cn$C@aCZ9XpgFQdtnh617HmlR7^dB9`AfEk#cr%JFw>rSu1 z=7#r+60EnMl2<|A7U`l9%<{Oe9r;1Z5ccL-dD%JI(V80bE>r^rxD|<+>1v@tKbDcx z+{D^>WRXTIudI4|AfQc|B9aG(e86w#CK8?`UO_Z_f5;PQLG%-Z_U!^!S!dJVi89YF z!F%0zR^8uLK}C3}|7Z*^|b26vDuB5_5&(Xl3*#k+7TfPonlscUqutgyhx&A7sF{R?fQcwvVC5MPnz8cU4j#=ufbOW!Z3l=^kA z#*mNmTmqij9*FJ=!9^S`i;Tmk}DldqdD zc=*s|<0Wy+e3y~dLu%-XkOJLVhSD9PZ4dDE%Ad}o&Z&)C?ZbCF9bQiGW1wKGg4f~R zF?aff-O+}h$_m)L@+5hhXjjjKhNPr>avxJ3H%Rry5>Bihji*&*7{@aouX}ysE!}SAN*k;}0 ze={Vg!cUtL`pGMTob{>6T>&}&@LPNRt>FH9kb@n#3jc8n`a2QxQp?jml$y!rU@jF* zKAv$8njQ$~oF$9_&5S%C_In#hRlT8xdCxdG{)_nWB1=5yjxExWv-Xx1A8jdZv+tR3 z#MKn1sIfma{kLsE6KU%zsXVy~xfdbV`1vXK03xJabpC;sSIdVil@bbs6djUGWT6o5 zR^usUwDMo$Bbt4>lOX#odT;h;ayvUjN31YRyiNVbvsDBFr8XV@dZ^ASxGp|+IRMxF zAa%*|>f@*8GxnE&ed9Tap7m6qWaVS;rFsqWp=N3kO&2j8-PLDdKt$0fMFVIQA zSKYVCZ{Gv;(a3}zSvEZ|f7jB_0O12N&ILmMLmnqgZ#?sU$?!h znnlI9v1_aambFU5)4W!rE1<;lFAxA-r~5+r+CaTSK`o;SxT7OR8Q7rV(Tsac8{UB! zQ>pnnduWzmLO~2=nju4UVMd9p%jUY~SjA2XtIM+AKYs{u1~`7E`!mq=p1f^U-^{U& zHms4n2z1i*S>>3mh||VphiLEy@wZ!WnkyYXAjA?xPp)zpwbvjvL|U>J9ZE2hxd-brho-wTI4np+1nT5qhYhbp|UH4w}NB>dxBoO3hW zhG7t0WjjKNo}ClcziSU)MW%j(<<5OZd!lXQ6*g~ z>8RxCS<`Rf&;5US7}93-O^*n{k0Sn&iGCOCHqK4^cfDSkn)YA6pTpVv5w`fJY|xhH zLZ_df7BYDeCd;n)h?%mU8(>c@g3ZfEQrw|-s-wW(x1-Y`?a|xmM~N!;GBs4om-Crf z8JmT2+a`>Ul}p0hUD*hFjY16=k)1~UN$Sbxbc&!ls4YY{6s0X_guN8px2d8~3S~pA z{(Q7pa1GFJx)7@(Mq&q+#ymp4)pef?R5GW z;Y(6pQuQ>W9B9Zvu6|8ylDBT@QeT4}pg-&Z**xGq`x$N=qx?Wf(V%R5yS;I0+&uyk zex!Z>`x_aQndsKe&b)_zV8j3YZA?`*&~R&X>P)<`%(~xC2GdKIl@-;hw;J?R@~!5G zyCuOOCVD5j2RV6qDj9B+XtXOO2fbLs8ZdUumE0zEG4uq`vGoIDlr|G}3Nkc^esqd{ zxV-KbaCB0uY92+(cDAo)eBcKZ1Y!?_BH*tJ>V60*UXx=NAz{=4YLOJ`QuVagdVQI-2?@F+vypJ!j>VTX3{Rqqk#0Wp1M?P$^XPCZ@s zni>WuL+%1k_AI|S%eJ>5UA#e43a!uADEI=mq2EcwnoHT#9TGyL3I{N=@9pin!|#Rz zr%kBXaK4~`dwmKgx{4+Lr3qrqy}9FIM*)84ImYGphd|c_^u%*-%aYfCtE=A6uaQ$F z4csCsCaOy8KqNmS8N}9ZREaOo)1AfNMA{|pc7=G>dn>L2Naq;ln_b4f_#BFk&(N9d zCr85v$Y!m(z*+;A)nkn@RJ{unoIuUA%An#p`pU5iQqzwDuJjMckv9&TDlAr7gbn}@ ztP%M1^Mpa`bD2IcE4%wY=iFE6a<+~Cc?7rX2^yAH>Z^Ie`w`bXccEC68}p|XX<^iq4SV@yi!tt|C^$a z&=Y(&^m&B1O{go^0RQ)Ggs}CZ;DKk|?^7-@X}o&ezI%y$sOnL7NHq{ z1gqlzV0rE;#Ci*|-ngU-_ZU0rl_t-o-&~h(QvXg0Or@>Yi8p>`>7d=mPq(+Bxk`ce zTDo89OF}ozYi$bM2)}d|_ynVvg9-~O-{0h$?koMl=*XU+hn-*UWB2j%4vB0jGCRon zv}uR-?LGUSpF9rMT<5KbGu{7uKjWr=bFa84S#`a!yg_rIx2?F*qp~+G!oEqbPO#?N zDp_W*0MkYP0P~)C4!`K}PFZ4!o<^q%>sh+?8D|aYScQY@hD8tZM-WS+#;odCuv7A_ zJtvTF_$h2NJyU|c4{2WPGqY6#DI;xpk+<>C#XB!~70sQ02s0xd-Hh8rWE7 z@uI0cL`M6PwL4|o!2l5QRB%)RyW8qpzM}T#XC@D@8!kWIn$rl>DcoC}_;VGpiG`&C zw-lnx6l~1$rsD(R3LA^BD{92mLJg(OSEja=7wsu^7*~v33VE)Hi0Zb@QH(vbvb@tp z5eXPScdJ-M%>2fl^8V1VG-@VgDZ2&{G={I}(-o7GMR8(=Sx`I2PC7PY%D&f}yl@wr zj-8SbS1AfPCK+?i9y`eJ3u4kc~IO*2G2?=%C*X{hAN3i*J{jto}T@d2nV^%X^_=m@K zi?aj)+}6aU&>ZYzyXAaBrt@KvjjK!q@%sD;zU)|EfhUo*P|}SJ;6Sk_NP)U<0+_&d zf}K-=hTQK3)`K^IcWgAR!15fH$9pFsnHS&UI8zD3)L_|}~EmeiB0$e@XnyTU|7TcZjD07ykEzUB>fO_KO7NRg} zemGRxp*paDS+|p5=$x>wN#x1R-$GM@s1G9g9Ru{6x@TG%vIF#{-NwQv)_0yBe0mGO zWrVt@2&Auv&JdrSTe807;(Wlg#Te?il}@y{%NHpogcf+HX=8Km$V~S%B*4Yx>GJL! z{CvRR_c8JkkV(!^^%ak-5W9_Y&wb}qoLD{7MixPL*|?U#p16kA37S$$tgSen{(M8U z<#Xu`;LfXWA8($fm4U`Y+-N^XTstc^f>Y<#nf;yyY>T3}sMTaT$i~S%i^Z?yqm-CS z#qyV;vEB^ph8T!iXB6L6W>@RO;|IATUeS14EAT@JH%oBIQp6lrBg(E>cAcNvAX{_H z-+MRVvbSANtuZA#Qy+}rsZjZinDr6F_Y=@VML5G&6sh6<4%1FCOITsy4twl_fNop< z-;3OYQS~*ANI+;5cZBVaIhWbtQ5p!_1gu0n-G;l8?5tjZEP6`|DHu0|AS|~?_}e=G z4kw*8_OYg%6*Waq9g6;3no|z%>3k<}zhZYAoaInY6Ww<>&_Ao^)9-bhb&k3>EPx)o zu4}MaBIl&`CQP=n?oJU$;wy5XOzu7UVA2IsFEmZemNxWTXWJk#?*+D?@K%`KPYKon zk4PJ>v%LoQiK^6YZah@H4_EiDfmaa;>=OJJy}3^0?4C&R_qT6(1(8L*=_)Pr*GSaQ z)jjrCB>%)BQ=klJHuEt0d9TMD9i>KFk|9=Ot1jz>(moFjTwgQg&ex3YauqAkQb!!k z*Pl+pGX)f5ROahvHgF+7vIm!3rh2AX4APfihqQZLU`_JY;a~HnGZO@{*-3yxh=mr{QZrM^V+lJh4&SfM z2dx=$L=Y4H`U?A}uy)X9%<-}HN^XGJ0%LW2aw7ELCA44rMh@{^=MHtd7K%azW|eP}gabYvuTnaxj3SVRQ{vp%>U!6i37Xl%uDrnQKZanoJHhQs%2 z|D{+{4ct(wFfJM}_=sBQ8QA?N`ty0aV40I}*KsHoR6RR8G=N(*nN!XIKfW2!e+*_) z7i5EIKMZU>e)51NH@4g@p8^wDKNg9y%Ribzr9E}GLq^`NQKfW*wNmPRQ`(MG<7$(W zRb{WWl>REy&^4-Y8%gw(yi)$1cfXgiZoT5A+#mDfoz(cIICOt?HFa3${9t6^(~h31 z@$!3Rc*HV@a?eaQlihBP6i;)s==}NVct>!@>yDot$3F+}!!$>(Ay-Qwj40T*jsN)D zU*`1~@u9pN^J=7a6%O1#bhGKO!SJc!)5B+m&kmm(K0o{q8a+E0yuy$- zwn0qo0k;aT>q9LzyZT%v`<-*(MIRZv%UolR-@Z1+R6v45SqrYssuiMgfGw&6wkWw5 zmya#ByA7^5bq=@~iLwvCjnm}R6b#0qp*TkVOo_?a?0mChPeI-Qtx<J-e}$p>6^~PQq5(P z2go5XUwH5uVV4R$Wvl}XZ0dwJkV{QBfZvq&ZTu_94Q}FFV7!X= zckYS(Z)cp+hBY~aBcT?Jt3Q^6Es9&-Y5GgY22;ETvP_-N&hWldGke698Q@ms9PTZD zixj4oaRw^Ah!@tVv6GQ-2mpNBmXXH4W4wL3?h%YOK1qIXDCbfYk1yc<&pK;J@G5?L zm2C93t6pmvO#-OEVSf}1K8B|*(p{g6e-%s0^9Xe^D_e$2t zrr)aE#<4KRGo5-+gHOK##Yu6(lIyi zo?&sztj~Gu(Uf$lun8m!8hW`bx|>MxWam1CNe2cb!|lvlJTv-EK+7Bm7^cPCBHr<} zQ{1hlks5DG?+G=#Zf4Jkg~gv&$uli|x+$aOE~uo$Eg2x?v5a9&Q}*|elCevj^NZ9n zjj%68gihw00LJX+6Tn^8uGkOOah;1IWO&h4#NGBJyH39+I~E>6sZOnNDZMwkCuV*Y z!CIHM>JgasrI>2-sCHBGRksF5`!eOQFN0-7ZxEC4Az4oW>7XIPs!UF1nnc4N^4-%w^rE?&QdisDwjR$A zPd!3Po$ClE^0*CgKCfg{^(wDV#9MO*ZVTIL0Tf|I-2_j`a6r;$o??4zMcJi!&$B((oZi*t7J~dUmlt!My|_ma?-9j8Ks|e_Rjm^K+>o(X+FwJs)AF zSk?FQewFa2b3PBoUQT-X0I@AFS0(OTyI+hsG#xj`H*On#33C?HPk%9k@?2q77cX9P z$+dPcoWKr5u$Xij@!8R9RI*y0d*ys*BKxktAh_zMh|b=%bfGa>ao*}$?f_0?c42UL zzdqBS*0Rk|dAfEDQ=ov@7m6bH*AVGcWg{Or%A* z89xx|18%^&JoErJ=OtONU)Y`AoAAAPZ@kj8+%CvHM1}T}3ymqa1Mp%Ezr5J9FlUXxem9%@L7t}_KJ;tNOK$o1 z+uA7pFgL_O2>zls%SB4+H^aLq@}i4CuuQGvKz##9?I!JfF1wuVKMnlz7|DvfZBzzw ziS@|?sD5bnCz81p2Jzh$SXa3fweaxN{sbN{O8O;y;J;Tt>fs(A(YOHZJHiIe)0u&p zItMIF^bNPXrjJV?j2k`DlWpkDDXJ@WMPienlD)3E$(@x|bBL z)D4|YPE6?HK4lBoVlq{XD#OE5wk3l2C_6cd#LshcvdB6@3^;}dxd99u?qjwII83Yd z@;1mio|`XMeroUKp0nj=;LOLvbN>|g=jiQP0pM*7V16)js~bzr)EtEIq}WI!+kJD# zD`NsGJsnNB1ZMiah$3eLdg&e%7%09N3z3Cd_QEC1DMceqvB|QaypR{b?PM8E5@$Cv zYs!wb$AxJWNPV9Fq1V5KwaE#z0ql#&0C|$8EBcSA05XCO$bajFKSs-T6nE*VBAOCq zb)d+lSEEsN?x&G5ZlVXivq+zHK~uz1AHz;omtOKYXR)3|ZBcu(*6FZ*pX8nKcA6S+ zksA|QABb@twouupHEu0&yEQ;ai@8&S#d|?mSfotbYE z_L3?{B}NY%>S)*kt=XIeoR}-8?P&kfciL&ETBvd^0f0V{c9FaXXO}p~@Cv0^$R^7V z`t2~LAI(~9{4?Ig#XU{EpMzgatxFsUhTUtdMmfCuj(@()?9vN0*#K_2p?|jwIOHKq z|Cnjr*nub1YsS-YZx-wek`EoSIy()G|Zb5fjF#_@~3mfKAUsl&Ry? znQrw82A!pDuBE5Dq62-N*3pm?F@|#(N*Vih`GG3JX2fF3hmN=@w6M?>(9@jP6xH<0 zZdS*9jv-y^Lh_KMFoF^wbt)kBNvoNcjH1PPoUBUtZmMR4^<~N!b{uhmhL$z|&+(cZ z_gj7ea8RgrSW-(8q&8S(1tOI>B?987BVgkT5&?19+aV2f#MYF7%F-I<%&~SRjBFlk zU&l)M6hwF?&Hj#@2vBd}%2_h=rElhph)CN7dM1qJzAN+KB}z}CPuwNeMi^HFjtp$U|~bPdH=#v8EGLtx!hmDD8a`M9Q0 zwR4y9Yp}}wWg}fnPkX9*!zymGgORpjx?EhQ6S`Q5%r3ycqhSD!Q@(M;$BQXdHSF(! z6B_EoUo#tO0w4U}2jh_T;qKGsq_YPqyK;QOkoGW^Q7c)FQ*M~V9;Hv7FL%Sn=S^uv zEA&W+fyz#C1r@5R3EHbEpQfGM*bUuYp-vapyu6EcC7&fU{6Xzp9^z)_jjFO}W>J9U^th=7 zzFld(VtWoMUC$t$S)%YUU6kT#elaS85T88e zxr-Cbop@VMV()A7>KyElY-DxWCd?317lj@u@4}9{pKar7a)+ zZ-0)0agi6Y)uuWqU>brb-4Hgmc6_p;577w+kiNa(GQ*J$rlU!G9~K$418F7nL? zHFs(NZ48680)Y z(=b0q0f}dhJO2E6^H4LJWPvK`F;6ik2QLTYl7BIvGA)WGNh>$X&nP2HSQh$b%+XKx zuUA!NH6h}*VeFfdN?bq6=LrV+g}P|B@YW5KWHPA=l>2olv@(WQTK zxhIh+^>P8g$pO-MS$&#-v>lnz+X`-DJF$TIqC0qK2She<44Qp z?dUXW8P|)4r-Bv;UK(VJsTtp=WFtv;W&`aFK^ z^DJ+7=Pb}=R4)Gd*mzCr99$PUwu=&{XZteEr_;^cpNy2#fSUmP*T#m|MI1p&rEqx$ z;K1=3VU74?g&Ntg(?TgI(2vetnNN$QvC1*Nl)HBERx`!afP(;==7x2j?vKpNoLYD1 zl3jnMC-+x~?$eXNuNJt!nk-3Jag~n$S69i${j-At+@DWHc!5(YRd;fScn-Yu|K@Z5 zzZa+8)q=vZ5ty;AiAu)BpG&fek-0pwWLutlW`_c|e) znVE;&oF_Ari?}(v9kT8qF+tHr((B$s>Py_#d-!aok%oB+>2TRcU>AFqrACZtiJft| zMr-@}hq4i3H!=E%rPrbJl%)LXw4Qtrf+0&q1vqtD0%5>wtD9Bq1v1?qWNO;-p}#VS z#@cIIiDZW&?9WEs-$X!S@^0?vUnnhX6`|*xx^UL0_k8}PcRV4$9G>0^@RGrfzcTKz zJFRj5B8!K7uU4Q|6l2NyS!?{l9OH9wj(*n%EkDzBm#A}ybnft;IRvXI+p~yywiE9_ zr_stZ-%8x11M%4V(Z1?1;uOP%R(HTVxsahI4i3@L(V-KPebznsUXut1f_(*tcLFg_ zafIs#9Z!+W5K*Pt<3Lmg^pG^-pnOD0v>l`pb7E%b((h?x2NWQz%x`PNLits|<^N=R zrsssd!(z!UoV=^Fd|7ffb$?3XWK@JTMpk(zIdEc{2PXqyxbF*Rw8#8@V$v;?Fqz#$ zD1zL0wslJX$!uMS0J<$*uTmXXJY;C~@OvPJ5wBXra48uB^X)<1o%${T9n(h+)V+G@p20Y!To%!}WP>@|(col4POnL0k<=KXl zhI8GUG4sIT5m7NJ@^y8GCRCKtOADPG=ZHzL3$3GGp_UyRp34GjN-6be73tpYvU?vI zDr~NBVd1ejM+^hT#nMF*}@ed4mGHG&P5kf5LC{SRV3PpAAN&>8UJ<{(>C`KQ&yXnG}*{cArbX@Gk zg6DQ}y0$|!{#F~<_Rs!=R3A%Vnh${IqwrsD>`#U9n7G zXB|vQ+zzv$$7b6)T%EJp$)NMhpXZ8gn77ekM@^Tcz*9{d2qPP3Oj^2Q9lYaQ_}*do z1B#ht$%r-XdyUu;Qle?eBy(ilH$d3V@!bU>RtgY@=XP(+f+6f}cl0Y@_}j~-8uYzg z`n7@kaJ)DpT96Su)NZ69y0CWAr zoq!c8#j0$FA9fa3t~&GOmI4Qla_rQ#H|K;RlhbrBskxS0zkYXLTF2;HR8+LsVLLFn z$g`s0>e=Y*KF#F&GCVXu=D<66t{Wu0{Zo8-z- zwkTO%9;0J|3A`jbSo#nui_S^z)r9qB2LjhAe)kU(WcE<_9|{9A@{UE_wmciHaz(sc z19bJ;wH*CVVaf8z1EN>Q(Hmge9nh*BPnj6>kj@9(gKp*wN}(+=Ar-P);?LmkVT~}d9G5f+a%_PY z-s~X8voyMUi`NmD%983Mq7%<&rKc8Q3lp|(m7#R%=VBm?0}|MnJu9i}O44d9y3xu! zL%$$hH^gGMv~(8?g+k?dlES8|ZB#PdVbz+0Vk^FV6Cf5IRfQGzET^Aq@#D&1mqJFk zg2`BcujawCt<;_*2p;OJZ)qqAmb3QsxT`hOR8-9Z2V literal 0 HcmV?d00001 diff --git a/src/JT808.Gateway.CleintBenchmark/Configs/ClientBenchmarkOptions.cs b/src/JT808.Gateway.CleintBenchmark/Configs/ClientBenchmarkOptions.cs deleted file mode 100644 index f8dd628..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Configs/ClientBenchmarkOptions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.CleintBenchmark.Configs -{ - public class ClientBenchmarkOptions : IOptions - { - public string IP { get; set; } - public int Port { get; set; } - public int DeviceCount { get; set; } = 10; - ///

- /// 5000ms毫秒 - /// - public int Interval { get; set; } = 5000; - public ClientBenchmarkOptions Value =>this; - } -} diff --git a/src/JT808.Gateway.CleintBenchmark/Configs/NLog.xsd b/src/JT808.Gateway.CleintBenchmark/Configs/NLog.xsd deleted file mode 100644 index 2f57d09..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Configs/NLog.xsd +++ /dev/null @@ -1,3106 +0,0 @@ - - - - - - - - - - - - - - - Watch config file for changes and reload automatically. - - - - - Print internal NLog messages to the console. Default value is: false - - - - - Print internal NLog messages to the console error output. Default value is: false - - - - - Write internal NLog messages to the specified file. - - - - - Log level threshold for internal log messages. Default value is: Info. - - - - - Global log level threshold for application log messages. Messages below this level won't be logged.. - - - - - Throw an exception when there is an internal error. Default value is: false. - - - - - Throw an exception when there is a configuration error. If not set, determined by throwExceptions. - - - - - Gets or sets a value indicating whether Variables should be kept on configuration reload. Default value is: false. - - - - - Write internal NLog messages to the System.Diagnostics.Trace. Default value is: false. - - - - - Write timestamps for internal NLog messages. Default value is: true. - - - - - Use InvariantCulture as default culture instead of CurrentCulture. Default value is: false. - - - - - Perform mesage template parsing and formatting of LogEvent messages (true = Always, false = Never, empty = Auto Detect). Default value is: empty. - - - - - - - - - - - - - - Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes). - - - - - - - - - - - - - - - - - Prefix for targets/layout renderers/filters/conditions loaded from this assembly. - - - - - Load NLog extensions from the specified file (*.dll) - - - - - Load NLog extensions from the specified assembly. Assembly name should be fully qualified. - - - - - - - - - - Name of the logger. May include '*' character which acts like a wildcard. Allowed forms are: *, Name, *Name, Name* and *Name* - - - - - Comma separated list of levels that this rule matches. - - - - - Minimum level that this rule matches. - - - - - Maximum level that this rule matches. - - - - - Level that this rule matches. - - - - - Comma separated list of target names. - - - - - Ignore further rules if this one matches. - - - - - Enable or disable logging rule. Disabled rules are ignored. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the file to be included. You could use * wildcard. The name is relative to the name of the current config file. - - - - - Ignore any errors in the include file. - - - - - - - Variable name. - - - - - Variable value. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Number of log events that should be processed in a batch by the lazy writer thread. - - - - - Limit of full s to write before yielding into Performance is better when writing many small batches, than writing a single large batch - - - - - Action to be taken when the lazy writer thread request queue count exceeds the set limit. - - - - - Limit on the number of requests in the lazy writer thread request queue. - - - - - Time in milliseconds to sleep between batches. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Delay the flush until the LogEvent has been confirmed as written - - - - - Condition expression. Log events who meet this condition will cause a flush on the wrapped target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Number of log events to be buffered. - - - - - Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes. - - - - - Indicates whether to use sliding timeout. - - - - - Action to take if the buffer overflows. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Encoding to be used. - - - - - Instance of that is used to format log messages. - - - - - End of line value if a newline is appended at the end of log message . - - - - - Maximum message size in bytes. - - - - - Indicates whether to append newline at the end of log message. - - - - - Action that should be taken if the will be more connections than . - - - - - Action that should be taken if the message is larger than maxMessageSize. - - - - - Maximum current connections. 0 = no maximum. - - - - - Indicates whether to keep connection open whenever possible. - - - - - Size of the connection cache (number of connections which are kept alive). - - - - - Network address. - - - - - Maximum queue size. - - - - - NDC item separator. - - - - - Indicates whether to include source info (file name and line number) in the information sent over the network. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include contents of the stack. - - - - - Indicates whether to include stack contents. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include call site (class and method name) in the information sent over the network. - - - - - Option to include all properties from the log events - - - - - AppInfo field. By default it's the friendly name of the current AppDomain. - - - - - Indicates whether to include NLog-specific extensions to log4j schema. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - Layout that should be use to calcuate the value for the parameter. - - - - - Viewer parameter name. - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Indicates whether to use default row highlighting rules. - - - - - Indicates whether to auto-check if the console is available. - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) - - - - - The encoding for writing messages to the . - - - - - Indicates whether the error stream (stderr) should be used instead of the output stream (stdout). - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Condition that must be met in order to set the specified foreground and background color. - - - - - Background color. - - - - - Foreground color. - - - - - - - - - - - - - - - - Indicates whether to ignore case when comparing texts. - - - - - Regular expression to be matched. You must specify either text or regex. - - - - - Text to be matched. You must specify either text or regex. - - - - - Indicates whether to match whole words only. - - - - - Compile the ? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used. - - - - - Background color. - - - - - Foreground color. - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Indicates whether to send the log messages to the standard error instead of the standard output. - - - - - Indicates whether to auto-check if the console is available - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) - - - - - The encoding for writing messages to the . - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Obsolete - value will be ignored! The logging code always runs outside of transaction. Gets or sets a value indicating whether to use database transactions. Some data providers require this. - - - - - Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string. - - - - - Name of the database provider. - - - - - Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string. - - - - - Indicates whether to keep the database connection open between the log events. - - - - - Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string. - - - - - Name of the connection string (as specified in <connectionStrings> configuration section. - - - - - Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase. - - - - - Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string. - - - - - Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Text of the SQL command to be run on each log level. - - - - - Type of the SQL command to be run on each log level. - - - - - - - - - - - - - - - - - - - - - - - Type of the command. - - - - - Connection string to run the command against. If not provided, connection string from the target is used. - - - - - Indicates whether to ignore failures. - - - - - Command text. - - - - - - - - - - - - - - Layout that should be use to calcuate the value for the parameter. - - - - - Database parameter name. - - - - - Database parameter precision. - - - - - Database parameter scale. - - - - - Database parameter size. - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Layout that renders event Category. - - - - - Layout that renders event ID. - - - - - Name of the Event Log to write to. This can be System, Application or any user-defined name. - - - - - Name of the machine on which Event Log service is running. - - - - - Value to be used as the event Source. - - - - - Action to take if the message is larger than the option. - - - - - Optional entrytype. When not set, or when not convertable to then determined by - - - - - Maximum Event log size in kilobytes. If null, the value won't be set. Default is 512 Kilobytes as specified by Eventlog API - - - - - Message length limit to write to the Event Log. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Indicates whether to return to the first target after any successful write. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - File encoding. - - - - - Line ending mode. - - - - - Way file archives are numbered. - - - - - Name of the file to be used for an archive. - - - - - Indicates whether to automatically archive log files every time the specified time passes. - - - - - Size in bytes above which log files will be automatically archived. Warning: combining this with isn't supported. We cannot create multiple archive files, if they should have the same name. Choose: - - - - - Indicates whether to compress archive files into the zip archive format. - - - - - Maximum number of archive files that should be kept. - - - - - Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation. - - - - - Is the an absolute or relative path? - - - - - Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong. - - - - - Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write - - - - - Is the an absolute or relative path? - - - - - Value indicationg whether file creation calls should be synchronized by a system global mutex. - - - - - Maximum number of log filenames that should be stored as existing. - - - - - Indicates whether the footer should be written only when the file is archived. - - - - - Name of the file to write to. - - - - - Value specifying the date format to use when archiving files. - - - - - Indicates whether to archive old log file on startup. - - - - - Indicates whether to create directories if they do not exist. - - - - - File attributes (Windows only). - - - - - Indicates whether to delete old log file on startup. - - - - - Indicates whether to replace file contents on each write instead of appending log message at the end. - - - - - Indicates whether to enable log file(s) to be deleted. - - - - - Number of times the write is appended on the file before NLog discards the log message. - - - - - Indicates whether concurrent writes to the log file by multiple processes on the same host. - - - - - Indicates whether to keep log file open instead of opening and closing it on each logging event. - - - - - Indicates whether concurrent writes to the log file by multiple processes on different network hosts. - - - - - Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger). - - - - - Maximum number of seconds that files are kept open. If this number is negative the files are not automatically closed after a period of inactivity. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Log file buffer size in bytes. - - - - - Indicates whether to automatically flush the file buffers after each log message. - - - - - Delay in milliseconds to wait before attempting to write to the file again. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Condition expression. Log events who meet this condition will be forwarded to the wrapped target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Windows domain name to change context to. - - - - - Required impersonation level. - - - - - Type of the logon provider. - - - - - Logon Type. - - - - - User account password. - - - - - Indicates whether to revert to the credentials of the process instead of impersonating another user. - - - - - Username to change context to. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Interval in which messages will be written up to the number of messages. - - - - - Maximum allowed number of messages written per . - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Endpoint address. - - - - - Name of the endpoint configuration in WCF configuration file. - - - - - Indicates whether to use a WCF service contract that is one way (fire and forget) or two way (request-reply) - - - - - Client ID. - - - - - Indicates whether to include per-event properties in the payload sent to the server. - - - - - Indicates whether to use binary message encoding. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Layout that should be use to calculate the value for the parameter. - - - - - Name of the parameter. - - - - - Type of the parameter. - - - - - Type of the parameter. Obsolete alias for - - - - - Parameter can combine multiple LogEvents into a single parameter value - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Indicates whether to send message as HTML instead of plain text. - - - - - Encoding to be used for sending e-mail. - - - - - Indicates whether to add new lines between log entries. - - - - - CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). - - - - - Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). - - - - - BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). - - - - - Mail message body (repeated for each log message send in one mail). - - - - - Mail subject. - - - - - Sender's email address (e.g. joe@domain.com). - - - - - Indicates the SMTP client timeout. - - - - - Priority used for sending mails. - - - - - Indicates whether NewLine characters in the body should be replaced with tags. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - SMTP Server to be used for sending. - - - - - SMTP Authentication mode. - - - - - Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic"). - - - - - Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic"). - - - - - Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server. - - - - - Port number that SMTP Server is listening on. - - - - - Indicates whether the default Settings from System.Net.MailSettings should be used. - - - - - Folder where applications save mail messages to be processed by the local SMTP server. - - - - - Specifies how outgoing email messages will be handled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Class name. - - - - - Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Encoding to be used. - - - - - End of line value if a newline is appended at the end of log message . - - - - - Maximum message size in bytes. - - - - - Indicates whether to append newline at the end of log message. - - - - - Action that should be taken if the will be more connections than . - - - - - Action that should be taken if the message is larger than maxMessageSize. - - - - - Network address. - - - - - Size of the connection cache (number of connections which are kept alive). - - - - - Indicates whether to keep connection open whenever possible. - - - - - Maximum current connections. 0 = no maximum. - - - - - Maximum queue size. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Encoding to be used. - - - - - Instance of that is used to format log messages. - - - - - End of line value if a newline is appended at the end of log message . - - - - - Maximum message size in bytes. - - - - - Indicates whether to append newline at the end of log message. - - - - - Action that should be taken if the will be more connections than . - - - - - Action that should be taken if the message is larger than maxMessageSize. - - - - - Maximum current connections. 0 = no maximum. - - - - - Indicates whether to keep connection open whenever possible. - - - - - Size of the connection cache (number of connections which are kept alive). - - - - - Network address. - - - - - Maximum queue size. - - - - - NDC item separator. - - - - - Indicates whether to include source info (file name and line number) in the information sent over the network. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include contents of the stack. - - - - - Indicates whether to include stack contents. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include call site (class and method name) in the information sent over the network. - - - - - Option to include all properties from the log events - - - - - AppInfo field. By default it's the friendly name of the current AppDomain. - - - - - Indicates whether to include NLog-specific extensions to log4j schema. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Indicates whether to perform layout calculation. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Indicates whether performance counter should be automatically created. - - - - - Name of the performance counter category. - - - - - Counter help text. - - - - - Name of the performance counter. - - - - - Performance counter type. - - - - - The value by which to increment the counter. - - - - - Performance counter instance name. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Default filter to be applied when no specific rule matches. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - Condition to be tested. - - - - - Resulting filter to be applied when the condition matches. - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Number of times to repeat each log message. - - - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Number of retries that should be attempted on the wrapped target in case of a failure. - - - - - Time to wait between retries in milliseconds. - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Always use independent of - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Should we include the BOM (Byte-order-mark) for UTF? Influences the property. This will only work for UTF-8. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Encoding. - - - - - Value whether escaping be done according to the old NLog style (Very non-standard) - - - - - Value whether escaping be done according to Rfc3986 (Supports Internationalized Resource Identifiers - IRIs) - - - - - Web service method name. Only used with Soap. - - - - - Web service namespace. Only used with Soap. - - - - - Indicates whether to pre-authenticate the HttpWebRequest (Requires 'Authorization' in parameters) - - - - - Protocol to be used when calling web service. - - - - - Web service URL. - - - - - Name of the root XML element, if POST of XML document chosen. If so, this property must not be null. (see and ). - - - - - (optional) root namespace of the XML document, if POST of XML document chosen. (see and ). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Footer layout. - - - - - Header layout. - - - - - Body layout (can be repeated multiple times). - - - - - Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom'). - - - - - Column delimiter. - - - - - Quote Character. - - - - - Quoting mode. - - - - - Indicates whether CVS should include header. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Layout of the column. - - - - - Name of the column. - - - - - - - - - - - - - - - - - - List of property names to exclude when is true - - - - - Option to include all properties from the log events - - - - - Indicates whether to include contents of the dictionary. - - - - - Indicates whether to include contents of the dictionary. - - - - - Option to render the empty object value {} - - - - - Option to suppress the extra spaces in the output json - - - - - - - - - - - - - - - Determines wether or not this attribute will be Json encoded. - - - - - Indicates whether to escape non-ascii characters - - - - - Layout that will be rendered as the attribute's value. - - - - - Name of the attribute. - - - - - - - - - - - - - - Footer layout. - - - - - Header layout. - - - - - Body layout (can be repeated multiple times). - - - - - - - - - - - - - - - - - - Option to include all properties from the log events - - - - - Indicates whether to include contents of the dictionary. - - - - - Indicates whether to include contents of the dictionary. - - - - - Indicates whether to include contents of the stack. - - - - - Indicates whether to include contents of the stack. - - - - - - - - - - - - - - Layout text. - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Condition expression. - - - - - - - - - - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - Substring to be matched. - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - String to compare the layout to. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - Substring to be matched. - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - String to compare the layout to. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - - - - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Layout to be used to filter log messages. - - - - - Default number of unique filter values to expect, will automatically increase if needed - - - - - Append FilterCount to the when an event is no longer filtered - - - - - Insert FilterCount value into when an event is no longer filtered - - - - - Applies the configured action to the initial logevent that starts the timeout period. Used to configure that it should ignore all events until timeout. - - - - - Max number of unique filter values to expect simultaneously - - - - - Max length of filter values, will truncate if above limit - - - - - Default buffer size for the internal buffers - - - - - Reuse internal buffers, and doesn't have to constantly allocate new buffers - - - - - How long before a filter expires, and logging is accepted again - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/JT808.Gateway.CleintBenchmark/Configs/nlog.unix.config b/src/JT808.Gateway.CleintBenchmark/Configs/nlog.unix.config deleted file mode 100644 index 2c8b777..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Configs/nlog.unix.config +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/JT808.Gateway.CleintBenchmark/Configs/nlog.win.config b/src/JT808.Gateway.CleintBenchmark/Configs/nlog.win.config deleted file mode 100644 index 14d4a10..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Configs/nlog.win.config +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/JT808.Gateway.CleintBenchmark/JT808.Gateway.CleintBenchmark.csproj b/src/JT808.Gateway.CleintBenchmark/JT808.Gateway.CleintBenchmark.csproj deleted file mode 100644 index ad20926..0000000 --- a/src/JT808.Gateway.CleintBenchmark/JT808.Gateway.CleintBenchmark.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - - - - - - Always - - - Always - - - Always - - - Always - - - - diff --git a/src/JT808.Gateway.CleintBenchmark/Program.cs b/src/JT808.Gateway.CleintBenchmark/Program.cs deleted file mode 100644 index 88451ca..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Program.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using NLog.Extensions.Logging; -using System; -using System.Threading.Tasks; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using JT808.Gateway.CleintBenchmark.Configs; -using JT808.Gateway.Client; -using JT808.Gateway.CleintBenchmark.Services; - -namespace JT808.Gateway.CleintBenchmark -{ - class Program - { - static async Task Main(string[] args) - { - var serverHostBuilder = new HostBuilder() - .ConfigureAppConfiguration((hostingContext, config) => - { - config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); - }) - .ConfigureLogging((context, logging) => - { - if (Environment.OSVersion.Platform == PlatformID.Unix) - { - NLog.LogManager.LoadConfiguration("Configs/nlog.unix.config"); - } - else - { - NLog.LogManager.LoadConfiguration("Configs/nlog.win.config"); - } - logging.AddNLog(); - logging.SetMinimumLevel(LogLevel.Trace); - }) - .ConfigureServices((hostContext, services) => - { - services.Configure(hostContext.Configuration.GetSection("ClientBenchmarkOptions")); - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddJT808Configure() - .AddJT808Client(); - services.AddHostedService(); - services.AddHostedService(); - }); - await serverHostBuilder.RunConsoleAsync(); - } - } -} diff --git a/src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkHostedService.cs b/src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkHostedService.cs deleted file mode 100644 index 8cfa879..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkHostedService.cs +++ /dev/null @@ -1,82 +0,0 @@ -using JT808.Gateway.CleintBenchmark.Configs; -using JT808.Gateway.Client; -using JT808.Protocol.MessageBody; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - - -namespace JT808.Gateway.CleintBenchmark.Services -{ - public class CleintBenchmarkHostedService : IHostedService - { - private readonly ClientBenchmarkOptions clientBenchmarkOptions; - - private readonly ILogger logger; - - private readonly IJT808TcpClientFactory jT808TcpClientFactory; - - private CancellationTokenSource cts=new CancellationTokenSource(); - - private TaskFactory taskFactory; - - public CleintBenchmarkHostedService( - ILoggerFactory loggerFactory, - IJT808TcpClientFactory jT808TcpClientFactory, - IOptions clientBenchmarkOptionsAccessor) - { - this.jT808TcpClientFactory = jT808TcpClientFactory; - clientBenchmarkOptions = clientBenchmarkOptionsAccessor.Value; - logger = loggerFactory.CreateLogger("CleintBenchmarkHostedService"); - taskFactory = new TaskFactory(); - } - public Task StartAsync(CancellationToken cancellationToken) - { - logger.LogInformation("StartAsync..."); - ThreadPool.GetMinThreads(out var minWorkerThreads, out var minCompletionPortThreads); - ThreadPool.GetMaxThreads(out var maxWorkerThreads, out var maxCompletionPortThreads); - logger.LogInformation($"GetMinThreads:{minWorkerThreads}-{minCompletionPortThreads}"); - logger.LogInformation($"GetMaxThreads:{maxWorkerThreads}-{maxCompletionPortThreads}"); - //ThreadPool.SetMaxThreads(20, 20); - //ThreadPool.GetMaxThreads(out var setMaxWorkerThreads, out var setMaxCompletionPortThreads); - //logger.LogInformation($"SetMaxThreads:{setMaxWorkerThreads}-{setMaxCompletionPortThreads}"); - for (int i=0;i< clientBenchmarkOptions.DeviceCount; i++) - { - taskFactory.StartNew((item) => - { - var client = jT808TcpClientFactory.Create(new DeviceConfig(((int)item).ToString(), clientBenchmarkOptions.IP, clientBenchmarkOptions.Port)); - int lat = new Random(1000).Next(100000, 180000); - int Lng = new Random(1000).Next(100000, 180000); - while (!cts.IsCancellationRequested) - { - client.Send(new JT808_0x0200() - { - Lat = lat, - Lng = Lng, - GPSTime = DateTime.Now, - Speed = 50, - Direction = 30, - AlarmFlag = 5, - Altitude = 50, - StatusFlag = 10 - }); - Thread.Sleep(clientBenchmarkOptions.Interval); - } - }, i,cts.Token); - } - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - cts.Cancel(); - logger.LogInformation("StopAsync..."); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkReportHostedService.cs b/src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkReportHostedService.cs deleted file mode 100644 index 768f475..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkReportHostedService.cs +++ /dev/null @@ -1,53 +0,0 @@ -using JT808.Gateway.Services; -using JT808.Protocol.MessageBody; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - - -namespace JT808.Gateway.CleintBenchmark.Services -{ - public class CleintBenchmarkReportHostedService : IHostedService - { - private readonly JT808ClientReportService jT808ReportService; - - private CancellationTokenSource cts=new CancellationTokenSource(); - - private readonly ILogger logger; - public CleintBenchmarkReportHostedService( - ILoggerFactory loggerFactory, - JT808ClientReportService jT808ReportService) - { - this.jT808ReportService = jT808ReportService; - logger = loggerFactory.CreateLogger("CleintBenchmarkReportHostedService"); - } - public Task StartAsync(CancellationToken cancellationToken) - { - logger.LogInformation("StartAsync..."); - Task.Run(() => { - while (!cts.IsCancellationRequested) - { - logger.LogInformation(JsonConvert.SerializeObject(jT808ReportService.JT808Reports.LastOrDefault())); - Thread.Sleep(3000); - } - }, cts.Token); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - logger.LogInformation("StopAsync..."); - cts.Cancel(); - logger.LogInformation("正在生成报表..."); - logger.LogInformation(JsonConvert.SerializeObject(jT808ReportService.JT808Reports,Formatting.Indented)); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808ConsumerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808ConsumerConfig.cs deleted file mode 100644 index 9d2aa55..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808ConsumerConfig.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808ConsumerConfig: ConsumerConfig, IOptions - { - public string TopicName { get; set; } - - public JT808ConsumerConfig Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808MsgConsumerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808MsgConsumerConfig.cs deleted file mode 100644 index 53746e2..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808MsgConsumerConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808MsgConsumerConfig : JT808ConsumerConfig, IOptions - { - JT808MsgConsumerConfig IOptions.Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808MsgProducerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808MsgProducerConfig.cs deleted file mode 100644 index d55b2ce..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808MsgProducerConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808MsgProducerConfig : JT808ProducerConfig, IOptions - { - JT808MsgProducerConfig IOptions.Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808MsgReplyConsumerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808MsgReplyConsumerConfig.cs deleted file mode 100644 index 79f4c3c..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808MsgReplyConsumerConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808MsgReplyConsumerConfig : JT808ConsumerConfig, IOptions - { - JT808MsgReplyConsumerConfig IOptions.Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808MsgReplyProducerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808MsgReplyProducerConfig.cs deleted file mode 100644 index 9b62e6e..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808MsgReplyProducerConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808MsgReplyProducerConfig : JT808ProducerConfig, IOptions - { - JT808MsgReplyProducerConfig IOptions.Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808ProducerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808ProducerConfig.cs deleted file mode 100644 index fca47cd..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808ProducerConfig.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808ProducerConfig : ProducerConfig,IOptions - { - public string TopicName { get; set; } - - public JT808ProducerConfig Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808SessionConsumerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808SessionConsumerConfig.cs deleted file mode 100644 index 6b57a0a..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808SessionConsumerConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808SessionConsumerConfig : JT808ConsumerConfig, IOptions - { - JT808SessionConsumerConfig IOptions.Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808SessionProducerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808SessionProducerConfig.cs deleted file mode 100644 index bba6871..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808SessionProducerConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808SessionProducerConfig : JT808ProducerConfig, IOptions - { - JT808SessionProducerConfig IOptions.Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/JT808.Gateway.Kafka.csproj b/src/JT808.Gateway.Kafka/JT808.Gateway.Kafka.csproj deleted file mode 100644 index f68e24b..0000000 --- a/src/JT808.Gateway.Kafka/JT808.Gateway.Kafka.csproj +++ /dev/null @@ -1,39 +0,0 @@ - - - - netstandard2.0 - 8.0 - Copyright 2018. - SmallChi(Koike) - https://github.com/SmallChi/JT808DotNetty - https://github.com/SmallChi/JT808DotNetty - https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE - https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE - false - 1.0.0-preview1 - false - LICENSE - true - JT808.Gateway.Kafka - JT808.Gateway.Kafka - 基于Kafka的JT808消息发布与订阅 - 基于Kafka的JT808消息发布与订阅 - - - - - - - - - - - - - - - - - - - diff --git a/src/JT808.Gateway.Kafka/JT808ClientBuilderDefault.cs b/src/JT808.Gateway.Kafka/JT808ClientBuilderDefault.cs deleted file mode 100644 index 3279c64..0000000 --- a/src/JT808.Gateway.Kafka/JT808ClientBuilderDefault.cs +++ /dev/null @@ -1,24 +0,0 @@ -using JT808.Protocol; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Kafka -{ - internal class JT808ClientBuilderDefault : IJT808ClientBuilder - { - public IJT808Builder JT808Builder { get; } - - public JT808ClientBuilderDefault(IJT808Builder builder) - { - JT808Builder = builder; - } - - public IJT808Builder Builder() - { - return JT808Builder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway.Kafka/JT808ClientKafkaExtensions.cs b/src/JT808.Gateway.Kafka/JT808ClientKafkaExtensions.cs deleted file mode 100644 index b334097..0000000 --- a/src/JT808.Gateway.Kafka/JT808ClientKafkaExtensions.cs +++ /dev/null @@ -1,66 +0,0 @@ -using JJT808.Gateway.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; - -namespace JT808.Gateway.Kafka -{ - public static class JT808ClientKafkaExtensions - { - public static IJT808ClientBuilder AddJT808ClientKafka(this IJT808Builder builder) - { - return new JT808ClientBuilderDefault(builder); - } - /// - /// - /// - /// - /// GetSection("JT808MsgConsumerConfig") - /// - public static IJT808ClientBuilder AddMsgConsumer(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) - { - jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808MsgConsumerConfig")); - jT808ClientBuilder.JT808Builder.Services.TryAddSingleton(); - return jT808ClientBuilder; - } - /// - /// - /// - /// - /// GetSection("JT808MsgReplyProducerConfig") - /// - public static IJT808ClientBuilder AddMsgReplyProducer(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) - { - jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808MsgReplyProducerConfig")); - jT808ClientBuilder.JT808Builder.Services.TryAddSingleton(); - return jT808ClientBuilder; - } - /// - /// - /// - /// - /// GetSection("JT808MsgReplyConsumerConfig") - /// - public static IJT808ClientBuilder AddMsgReplyConsumer(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) - { - jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808MsgReplyConsumerConfig")); - jT808ClientBuilder.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808MsgReplyConsumer), typeof(JT808MsgReplyConsumer), ServiceLifetime.Singleton)); - return jT808ClientBuilder; - } - /// - /// - /// - /// - /// GetSection("JT808SessionConsumerConfig") - /// - public static IJT808ClientBuilder AddSessionConsumer(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) - { - jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808SessionConsumerConfig")); - jT808ClientBuilder.JT808Builder.Services.TryAddSingleton(); - return jT808ClientBuilder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway.Kafka/JT808MsgConsumer.cs b/src/JT808.Gateway.Kafka/JT808MsgConsumer.cs deleted file mode 100644 index 56818f2..0000000 --- a/src/JT808.Gateway.Kafka/JT808MsgConsumer.cs +++ /dev/null @@ -1,82 +0,0 @@ -using Confluent.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Kafka -{ - public class JT808MsgConsumer : IJT808MsgConsumer - { - public CancellationTokenSource Cts => new CancellationTokenSource(); - - private readonly IConsumer consumer; - - private readonly ILogger logger; - - public string TopicName { get; } - - public JT808MsgConsumer( - IOptions consumerConfigAccessor, - ILoggerFactory loggerFactory) - { - consumer = new ConsumerBuilder(consumerConfigAccessor.Value).Build(); - TopicName = consumerConfigAccessor.Value.TopicName; - logger = loggerFactory.CreateLogger("JT808MsgConsumer"); - } - - public void OnMessage(Action<(string TerminalNo, byte[] Data)> callback) - { - Task.Run(() => - { - while (!Cts.IsCancellationRequested) - { - try - { - //如果不指定分区,根据kafka的机制会从多个分区中拉取数据 - //如果指定分区,根据kafka的机制会从相应的分区中拉取数据 - var data = consumer.Consume(Cts.Token); - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug($"Topic: {data.Topic} Key: {data.Key} Partition: {data.Partition} Offset: {data.Offset} TopicPartitionOffset:{data.TopicPartitionOffset}"); - } - callback((data.Key, data.Value)); - } - catch (ConsumeException ex) - { - logger.LogError(ex, TopicName); - } - catch (OperationCanceledException ex) - { - logger.LogError(ex, TopicName); - } - catch (Exception ex) - { - logger.LogError(ex, TopicName); - } - } - }, Cts.Token); - } - - public void Subscribe() - { - consumer.Subscribe(TopicName); - } - - public void Unsubscribe() - { - consumer.Unsubscribe(); - } - - public void Dispose() - { - consumer.Close(); - consumer.Dispose(); - } - } -} diff --git a/src/JT808.Gateway.Kafka/JT808MsgProducer.cs b/src/JT808.Gateway.Kafka/JT808MsgProducer.cs deleted file mode 100644 index 67d6d1b..0000000 --- a/src/JT808.Gateway.Kafka/JT808MsgProducer.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Confluent.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.Gateway.Kafka -{ - public class JT808MsgProducer : IJT808MsgProducer - { - public string TopicName { get; } - - private readonly IProducer producer; - public JT808MsgProducer( - IOptions producerConfigAccessor) - { - producer = new ProducerBuilder(producerConfigAccessor.Value).Build(); - TopicName = producerConfigAccessor.Value.TopicName; - } - - public void Dispose() - { - producer.Dispose(); - } - - public async Task ProduceAsync(string terminalNo, byte[] data) - { - await producer.ProduceAsync(TopicName, new Message - { - Key = terminalNo, - Value = data - }); - } - } -} diff --git a/src/JT808.Gateway.Kafka/JT808MsgReplyConsumer.cs b/src/JT808.Gateway.Kafka/JT808MsgReplyConsumer.cs deleted file mode 100644 index 004a391..0000000 --- a/src/JT808.Gateway.Kafka/JT808MsgReplyConsumer.cs +++ /dev/null @@ -1,82 +0,0 @@ -using Confluent.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Kafka -{ - public class JT808MsgReplyConsumer : IJT808MsgReplyConsumer - { - public CancellationTokenSource Cts => new CancellationTokenSource(); - - private readonly IConsumer consumer; - - private readonly ILogger logger; - - public string TopicName { get; } - - public JT808MsgReplyConsumer( - IOptions consumerConfigAccessor, - ILoggerFactory loggerFactory) - { - consumer = new ConsumerBuilder(consumerConfigAccessor.Value).Build(); - TopicName = consumerConfigAccessor.Value.TopicName; - logger = loggerFactory.CreateLogger("JT808MsgReplyConsumer"); - } - - public void OnMessage(Action<(string TerminalNo, byte[] Data)> callback) - { - Task.Run(() => - { - while (!Cts.IsCancellationRequested) - { - try - { - //如果不指定分区,根据kafka的机制会从多个分区中拉取数据 - //如果指定分区,根据kafka的机制会从相应的分区中拉取数据 - var data = consumer.Consume(Cts.Token); - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug($"Topic: {data.Topic} Key: {data.Key} Partition: {data.Partition} Offset: {data.Offset} TopicPartitionOffset:{data.TopicPartitionOffset}"); - } - callback((data.Key, data.Value)); - } - catch (ConsumeException ex) - { - logger.LogError(ex, TopicName); - } - catch (OperationCanceledException ex) - { - logger.LogError(ex, TopicName); - } - catch (Exception ex) - { - logger.LogError(ex, TopicName); - } - } - }, Cts.Token); - } - - public void Subscribe() - { - consumer.Subscribe(TopicName); - } - - public void Unsubscribe() - { - consumer.Unsubscribe(); - } - - public void Dispose() - { - consumer.Close(); - consumer.Dispose(); - } - } -} diff --git a/src/JT808.Gateway.Kafka/JT808MsgReplyProducer.cs b/src/JT808.Gateway.Kafka/JT808MsgReplyProducer.cs deleted file mode 100644 index f29e9be..0000000 --- a/src/JT808.Gateway.Kafka/JT808MsgReplyProducer.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Confluent.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JJT808.Gateway.Kafka -{ - public class JT808MsgReplyProducer : IJT808MsgReplyProducer - { - public string TopicName { get;} - - private IProducer producer; - public JT808MsgReplyProducer( - IOptions producerConfigAccessor) - { - producer = new ProducerBuilder(producerConfigAccessor.Value).Build(); - TopicName = producerConfigAccessor.Value.TopicName; - } - - public void Dispose() - { - producer.Dispose(); - } - - public async Task ProduceAsync(string terminalNo, byte[] data) - { - await producer.ProduceAsync(TopicName, new Message - { - Key = terminalNo, - Value = data - }); - } - } -} diff --git a/src/JT808.Gateway.Kafka/JT808ServerKafkaExtensions.cs b/src/JT808.Gateway.Kafka/JT808ServerKafkaExtensions.cs deleted file mode 100644 index e8e1dc1..0000000 --- a/src/JT808.Gateway.Kafka/JT808ServerKafkaExtensions.cs +++ /dev/null @@ -1,48 +0,0 @@ -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; - -namespace JT808.Gateway.Kafka -{ - public static class JT808ServerKafkaExtensions - { - /// - /// - /// - /// - /// GetSection("JT808MsgProducerConfig") - /// - public static IJT808GatewayBuilder AddJT808ServerKafkaMsgProducer(this IJT808GatewayBuilder jT808GatewayBuilder, IConfiguration configuration) - { - jT808GatewayBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808MsgProducerConfig")); - jT808GatewayBuilder.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808MsgProducer), typeof(JT808MsgProducer), ServiceLifetime.Singleton)); - return jT808GatewayBuilder; - } - /// - /// - /// - /// - /// GetSection("JT808MsgReplyConsumerConfig") - /// - public static IJT808GatewayBuilder AddJT808ServerKafkaMsgReplyConsumer(this IJT808GatewayBuilder jT808GatewayBuilder, IConfiguration configuration) - { - jT808GatewayBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808MsgReplyConsumerConfig")); - jT808GatewayBuilder.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808MsgReplyConsumer), typeof(JT808MsgReplyConsumer), ServiceLifetime.Singleton)); - return jT808GatewayBuilder; - } - /// - /// - /// - /// - /// GetSection("JT808SessionProducerConfig") - /// - public static IJT808GatewayBuilder AddJT808ServerKafkaSessionProducer(this IJT808GatewayBuilder jT808GatewayBuilder, IConfiguration configuration) - { - jT808GatewayBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808SessionProducerConfig")); - jT808GatewayBuilder.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808SessionProducer), typeof(JT808SessionProducer), ServiceLifetime.Singleton)); - return jT808GatewayBuilder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway.Kafka/JT808SessionConsumer.cs b/src/JT808.Gateway.Kafka/JT808SessionConsumer.cs deleted file mode 100644 index 9ccf830..0000000 --- a/src/JT808.Gateway.Kafka/JT808SessionConsumer.cs +++ /dev/null @@ -1,82 +0,0 @@ -using Confluent.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Kafka -{ - public class JT808SessionConsumer : IJT808SessionConsumer - { - public CancellationTokenSource Cts => new CancellationTokenSource(); - - private readonly IConsumer consumer; - - private readonly ILogger logger; - - public string TopicName { get; } - - public JT808SessionConsumer( - IOptions consumerConfigAccessor, - ILoggerFactory loggerFactory) - { - consumer = new ConsumerBuilder(consumerConfigAccessor.Value).Build(); - TopicName = consumerConfigAccessor.Value.TopicName; - logger = loggerFactory.CreateLogger("JT808SessionConsumer"); - } - - public void OnMessage(Action<(string Notice, string TerminalNo)> callback) - { - Task.Run(() => - { - while (!Cts.IsCancellationRequested) - { - try - { - //如果不指定分区,根据kafka的机制会从多个分区中拉取数据 - //如果指定分区,根据kafka的机制会从相应的分区中拉取数据 - var data = consumer.Consume(Cts.Token); - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug($"Topic: {data.Topic} Key: {data.Key} Partition: {data.Partition} Offset: {data.Offset} TopicPartitionOffset:{data.TopicPartitionOffset}"); - } - callback((data.Key, data.Value)); - } - catch (ConsumeException ex) - { - logger.LogError(ex, TopicName); - } - catch (OperationCanceledException ex) - { - logger.LogError(ex, TopicName); - } - catch (Exception ex) - { - logger.LogError(ex, TopicName); - } - } - }, Cts.Token); - } - - public void Subscribe() - { - consumer.Subscribe(TopicName); - } - - public void Unsubscribe() - { - consumer.Unsubscribe(); - } - - public void Dispose() - { - consumer.Close(); - consumer.Dispose(); - } - } -} diff --git a/src/JT808.Gateway.Kafka/JT808SessionProducer.cs b/src/JT808.Gateway.Kafka/JT808SessionProducer.cs deleted file mode 100644 index 3b6494f..0000000 --- a/src/JT808.Gateway.Kafka/JT808SessionProducer.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Confluent.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.Gateway.Kafka -{ - public class JT808SessionProducer : IJT808SessionProducer - { - public string TopicName { get; } - - private readonly IProducer producer; - public JT808SessionProducer( - IOptions producerConfigAccessor) - { - producer = new ProducerBuilder(producerConfigAccessor.Value).Build(); - TopicName = producerConfigAccessor.Value.TopicName; - } - - public void Dispose() - { - producer.Dispose(); - } - - public async Task ProduceAsync(string notice,string terminalNo) - { - await producer.ProduceAsync(TopicName, new Message - { - Key = notice, - Value = terminalNo - }); - } - } -} diff --git a/src/JT808.Gateway.SimpleClient/JT808.Gateway.SimpleClient.csproj b/src/JT808.Gateway.SimpleClient/JT808.Gateway.SimpleClient.csproj deleted file mode 100644 index 597fe2f..0000000 --- a/src/JT808.Gateway.SimpleClient/JT808.Gateway.SimpleClient.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - - - - diff --git a/src/JT808.Gateway.SimpleClient/Program.cs b/src/JT808.Gateway.SimpleClient/Program.cs deleted file mode 100644 index e58a3d5..0000000 --- a/src/JT808.Gateway.SimpleClient/Program.cs +++ /dev/null @@ -1,52 +0,0 @@ -using JT808.Gateway.Client; -using JT808.Gateway.SimpleClient.Services; -using JT808.Protocol; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; -using Grpc.Net.Client; -using JT808.Gateway.GrpcService; -using System.Net; - -namespace JT808.Gateway.SimpleClient -{ - class Program - { - static async Task Main(string[] args) - { - //ref https://docs.microsoft.com/zh-cn/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0#call-insecure-grpc-services-with-net-core-client - //ref https://docs.microsoft.com/zh-cn/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0 - - //先执行 dotnet dev-certs https --trust 命令生成开发证书 - //使用 certmgr.msc 导出证书在服务端配置对应证书文件 - //Uri "https://localhost:5001" - - var serverHostBuilder = new HostBuilder() - .ConfigureLogging((context, logging) => - { - logging.AddConsole(); - logging.SetMinimumLevel(LogLevel.Trace); - }) - .ConfigureServices((hostContext, services) => - { - services.AddGrpcClient(o => - { - o.Address = new Uri("https://localhost:5001"); - }); - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddLogging(options => { - options.AddConsole(); - options.SetMinimumLevel(LogLevel.Trace); - }); - services.AddJT808Configure() - .AddJT808Client(); - services.AddHostedService(); - //services.AddHostedService(); - }); - await serverHostBuilder.RunConsoleAsync(); - } - } -} diff --git a/src/JT808.Gateway.SimpleClient/Services/GrpcClientService.cs b/src/JT808.Gateway.SimpleClient/Services/GrpcClientService.cs deleted file mode 100644 index e21a3dc..0000000 --- a/src/JT808.Gateway.SimpleClient/Services/GrpcClientService.cs +++ /dev/null @@ -1,68 +0,0 @@ -using JT808.Gateway.Client; -using JT808.Protocol.MessageBody; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using JT808.Gateway.GrpcService; -using static JT808.Gateway.GrpcService.JT808Gateway; -using Google.Protobuf; -using System.Text.Json; -using JT808.Protocol.Extensions; - -namespace JT808.Gateway.SimpleClient.Services -{ - public class GrpcClientService : IHostedService - { - private readonly ILogger logger; - private readonly JT808GatewayClient client; - - public GrpcClientService( - ILoggerFactory loggerFactory, - JT808GatewayClient jT808GatewayClient) - { - this.client = jT808GatewayClient; - logger = loggerFactory.CreateLogger("GrpcClientService"); - } - - public Task StartAsync(CancellationToken cancellationToken) - { - Task.Run(() => { - //while (!cancellationToken.IsCancellationRequested) - //{ - Thread.Sleep(1000 * 10); - var result1 = client.GetTcpAtomicCounter(new Empty()); - var result2 = client.GetUdpAtomicCounter(new Empty()); - var result3 = client.GetTcpSessionAll(new Empty()); - var result4 = client.GetUdpSessionAll(new Empty()); - var result5 = client.UnificationSend(new UnificationSendRequest() - { - TerminalPhoneNo= "12345678910", - Data= ByteString.CopyFrom("7E 02 00 00 26 12 34 56 78 90 12 00 7D 02 00 00 00 01 00 00 00 02 00 BA 7F 0E 07 E4 F1 1C 00 28 00 3C 00 00 18 10 15 10 10 10 01 04 00 00 00 64 02 02 00 7D 01 13 7E".ToHexBytes()) - }); - var result6 = client.RemoveSessionByTerminalPhoneNo(new SessionRemoveRequest() - { - TerminalPhoneNo= "12345678910" - }); - - logger.LogDebug(JsonSerializer.Serialize(result1)); - logger.LogDebug(JsonSerializer.Serialize(result2)); - logger.LogDebug(JsonSerializer.Serialize(result3)); - logger.LogDebug(JsonSerializer.Serialize(result4)); - logger.LogDebug(JsonSerializer.Serialize(result5)); - logger.LogDebug(JsonSerializer.Serialize(result6)); - //} - }, cancellationToken); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway.SimpleClient/Services/UpService.cs b/src/JT808.Gateway.SimpleClient/Services/UpService.cs deleted file mode 100644 index a9a9d83..0000000 --- a/src/JT808.Gateway.SimpleClient/Services/UpService.cs +++ /dev/null @@ -1,68 +0,0 @@ -using JT808.Gateway.Client; -using JT808.Protocol.MessageBody; -using Microsoft.Extensions.Hosting; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.SimpleClient.Services -{ - public class UpService : IHostedService - { - private readonly IJT808TcpClientFactory jT808TcpClientFactory; - - public UpService(IJT808TcpClientFactory jT808TcpClientFactory) - { - this.jT808TcpClientFactory = jT808TcpClientFactory; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - JT808TcpClient client1 = jT808TcpClientFactory.Create(new DeviceConfig("12345678910", "127.0.0.1", 808)); - //1.终端注册 - client1.Send(new JT808_0x0100() - { - PlateNo = "粤A12345", - PlateColor = 2, - AreaID = 0, - CityOrCountyId = 0, - MakerId = "Koike001", - TerminalId = "Koike001", - TerminalModel = "Koike001" - }); - //2.终端鉴权 - client1.Send(new JT808_0x0102() - { - Code = "1234" - }); - Task.Run(() => { - while (true) - { - var i = 0; - //3.每5000秒发一次 - client1.Send(new JT808_0x0200() - { - Lat = 110000 + i, - Lng = 100000 + i, - GPSTime = DateTime.Now, - Speed = 50, - Direction = 30, - AlarmFlag = 5, - Altitude = 50, - StatusFlag = 10 - }); - i++; - Thread.Sleep(5000); - } - }); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway.SimpleServer/Configs/NLog.xsd b/src/JT808.Gateway.SimpleServer/Configs/NLog.xsd deleted file mode 100644 index 2f57d09..0000000 --- a/src/JT808.Gateway.SimpleServer/Configs/NLog.xsd +++ /dev/null @@ -1,3106 +0,0 @@ - - - - - - - - - - - - - - - Watch config file for changes and reload automatically. - - - - - Print internal NLog messages to the console. Default value is: false - - - - - Print internal NLog messages to the console error output. Default value is: false - - - - - Write internal NLog messages to the specified file. - - - - - Log level threshold for internal log messages. Default value is: Info. - - - - - Global log level threshold for application log messages. Messages below this level won't be logged.. - - - - - Throw an exception when there is an internal error. Default value is: false. - - - - - Throw an exception when there is a configuration error. If not set, determined by throwExceptions. - - - - - Gets or sets a value indicating whether Variables should be kept on configuration reload. Default value is: false. - - - - - Write internal NLog messages to the System.Diagnostics.Trace. Default value is: false. - - - - - Write timestamps for internal NLog messages. Default value is: true. - - - - - Use InvariantCulture as default culture instead of CurrentCulture. Default value is: false. - - - - - Perform mesage template parsing and formatting of LogEvent messages (true = Always, false = Never, empty = Auto Detect). Default value is: empty. - - - - - - - - - - - - - - Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes). - - - - - - - - - - - - - - - - - Prefix for targets/layout renderers/filters/conditions loaded from this assembly. - - - - - Load NLog extensions from the specified file (*.dll) - - - - - Load NLog extensions from the specified assembly. Assembly name should be fully qualified. - - - - - - - - - - Name of the logger. May include '*' character which acts like a wildcard. Allowed forms are: *, Name, *Name, Name* and *Name* - - - - - Comma separated list of levels that this rule matches. - - - - - Minimum level that this rule matches. - - - - - Maximum level that this rule matches. - - - - - Level that this rule matches. - - - - - Comma separated list of target names. - - - - - Ignore further rules if this one matches. - - - - - Enable or disable logging rule. Disabled rules are ignored. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the file to be included. You could use * wildcard. The name is relative to the name of the current config file. - - - - - Ignore any errors in the include file. - - - - - - - Variable name. - - - - - Variable value. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Number of log events that should be processed in a batch by the lazy writer thread. - - - - - Limit of full s to write before yielding into Performance is better when writing many small batches, than writing a single large batch - - - - - Action to be taken when the lazy writer thread request queue count exceeds the set limit. - - - - - Limit on the number of requests in the lazy writer thread request queue. - - - - - Time in milliseconds to sleep between batches. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Delay the flush until the LogEvent has been confirmed as written - - - - - Condition expression. Log events who meet this condition will cause a flush on the wrapped target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Number of log events to be buffered. - - - - - Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes. - - - - - Indicates whether to use sliding timeout. - - - - - Action to take if the buffer overflows. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Encoding to be used. - - - - - Instance of that is used to format log messages. - - - - - End of line value if a newline is appended at the end of log message . - - - - - Maximum message size in bytes. - - - - - Indicates whether to append newline at the end of log message. - - - - - Action that should be taken if the will be more connections than . - - - - - Action that should be taken if the message is larger than maxMessageSize. - - - - - Maximum current connections. 0 = no maximum. - - - - - Indicates whether to keep connection open whenever possible. - - - - - Size of the connection cache (number of connections which are kept alive). - - - - - Network address. - - - - - Maximum queue size. - - - - - NDC item separator. - - - - - Indicates whether to include source info (file name and line number) in the information sent over the network. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include contents of the stack. - - - - - Indicates whether to include stack contents. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include call site (class and method name) in the information sent over the network. - - - - - Option to include all properties from the log events - - - - - AppInfo field. By default it's the friendly name of the current AppDomain. - - - - - Indicates whether to include NLog-specific extensions to log4j schema. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - Layout that should be use to calcuate the value for the parameter. - - - - - Viewer parameter name. - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Indicates whether to use default row highlighting rules. - - - - - Indicates whether to auto-check if the console is available. - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) - - - - - The encoding for writing messages to the . - - - - - Indicates whether the error stream (stderr) should be used instead of the output stream (stdout). - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Condition that must be met in order to set the specified foreground and background color. - - - - - Background color. - - - - - Foreground color. - - - - - - - - - - - - - - - - Indicates whether to ignore case when comparing texts. - - - - - Regular expression to be matched. You must specify either text or regex. - - - - - Text to be matched. You must specify either text or regex. - - - - - Indicates whether to match whole words only. - - - - - Compile the ? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used. - - - - - Background color. - - - - - Foreground color. - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Indicates whether to send the log messages to the standard error instead of the standard output. - - - - - Indicates whether to auto-check if the console is available - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) - - - - - The encoding for writing messages to the . - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Obsolete - value will be ignored! The logging code always runs outside of transaction. Gets or sets a value indicating whether to use database transactions. Some data providers require this. - - - - - Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string. - - - - - Name of the database provider. - - - - - Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string. - - - - - Indicates whether to keep the database connection open between the log events. - - - - - Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string. - - - - - Name of the connection string (as specified in <connectionStrings> configuration section. - - - - - Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase. - - - - - Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string. - - - - - Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Text of the SQL command to be run on each log level. - - - - - Type of the SQL command to be run on each log level. - - - - - - - - - - - - - - - - - - - - - - - Type of the command. - - - - - Connection string to run the command against. If not provided, connection string from the target is used. - - - - - Indicates whether to ignore failures. - - - - - Command text. - - - - - - - - - - - - - - Layout that should be use to calcuate the value for the parameter. - - - - - Database parameter name. - - - - - Database parameter precision. - - - - - Database parameter scale. - - - - - Database parameter size. - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Layout that renders event Category. - - - - - Layout that renders event ID. - - - - - Name of the Event Log to write to. This can be System, Application or any user-defined name. - - - - - Name of the machine on which Event Log service is running. - - - - - Value to be used as the event Source. - - - - - Action to take if the message is larger than the option. - - - - - Optional entrytype. When not set, or when not convertable to then determined by - - - - - Maximum Event log size in kilobytes. If null, the value won't be set. Default is 512 Kilobytes as specified by Eventlog API - - - - - Message length limit to write to the Event Log. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Indicates whether to return to the first target after any successful write. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - File encoding. - - - - - Line ending mode. - - - - - Way file archives are numbered. - - - - - Name of the file to be used for an archive. - - - - - Indicates whether to automatically archive log files every time the specified time passes. - - - - - Size in bytes above which log files will be automatically archived. Warning: combining this with isn't supported. We cannot create multiple archive files, if they should have the same name. Choose: - - - - - Indicates whether to compress archive files into the zip archive format. - - - - - Maximum number of archive files that should be kept. - - - - - Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation. - - - - - Is the an absolute or relative path? - - - - - Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong. - - - - - Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write - - - - - Is the an absolute or relative path? - - - - - Value indicationg whether file creation calls should be synchronized by a system global mutex. - - - - - Maximum number of log filenames that should be stored as existing. - - - - - Indicates whether the footer should be written only when the file is archived. - - - - - Name of the file to write to. - - - - - Value specifying the date format to use when archiving files. - - - - - Indicates whether to archive old log file on startup. - - - - - Indicates whether to create directories if they do not exist. - - - - - File attributes (Windows only). - - - - - Indicates whether to delete old log file on startup. - - - - - Indicates whether to replace file contents on each write instead of appending log message at the end. - - - - - Indicates whether to enable log file(s) to be deleted. - - - - - Number of times the write is appended on the file before NLog discards the log message. - - - - - Indicates whether concurrent writes to the log file by multiple processes on the same host. - - - - - Indicates whether to keep log file open instead of opening and closing it on each logging event. - - - - - Indicates whether concurrent writes to the log file by multiple processes on different network hosts. - - - - - Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger). - - - - - Maximum number of seconds that files are kept open. If this number is negative the files are not automatically closed after a period of inactivity. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Log file buffer size in bytes. - - - - - Indicates whether to automatically flush the file buffers after each log message. - - - - - Delay in milliseconds to wait before attempting to write to the file again. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Condition expression. Log events who meet this condition will be forwarded to the wrapped target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Windows domain name to change context to. - - - - - Required impersonation level. - - - - - Type of the logon provider. - - - - - Logon Type. - - - - - User account password. - - - - - Indicates whether to revert to the credentials of the process instead of impersonating another user. - - - - - Username to change context to. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Interval in which messages will be written up to the number of messages. - - - - - Maximum allowed number of messages written per . - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Endpoint address. - - - - - Name of the endpoint configuration in WCF configuration file. - - - - - Indicates whether to use a WCF service contract that is one way (fire and forget) or two way (request-reply) - - - - - Client ID. - - - - - Indicates whether to include per-event properties in the payload sent to the server. - - - - - Indicates whether to use binary message encoding. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Layout that should be use to calculate the value for the parameter. - - - - - Name of the parameter. - - - - - Type of the parameter. - - - - - Type of the parameter. Obsolete alias for - - - - - Parameter can combine multiple LogEvents into a single parameter value - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Indicates whether to send message as HTML instead of plain text. - - - - - Encoding to be used for sending e-mail. - - - - - Indicates whether to add new lines between log entries. - - - - - CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). - - - - - Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). - - - - - BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). - - - - - Mail message body (repeated for each log message send in one mail). - - - - - Mail subject. - - - - - Sender's email address (e.g. joe@domain.com). - - - - - Indicates the SMTP client timeout. - - - - - Priority used for sending mails. - - - - - Indicates whether NewLine characters in the body should be replaced with tags. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - SMTP Server to be used for sending. - - - - - SMTP Authentication mode. - - - - - Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic"). - - - - - Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic"). - - - - - Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server. - - - - - Port number that SMTP Server is listening on. - - - - - Indicates whether the default Settings from System.Net.MailSettings should be used. - - - - - Folder where applications save mail messages to be processed by the local SMTP server. - - - - - Specifies how outgoing email messages will be handled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Class name. - - - - - Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Encoding to be used. - - - - - End of line value if a newline is appended at the end of log message . - - - - - Maximum message size in bytes. - - - - - Indicates whether to append newline at the end of log message. - - - - - Action that should be taken if the will be more connections than . - - - - - Action that should be taken if the message is larger than maxMessageSize. - - - - - Network address. - - - - - Size of the connection cache (number of connections which are kept alive). - - - - - Indicates whether to keep connection open whenever possible. - - - - - Maximum current connections. 0 = no maximum. - - - - - Maximum queue size. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Encoding to be used. - - - - - Instance of that is used to format log messages. - - - - - End of line value if a newline is appended at the end of log message . - - - - - Maximum message size in bytes. - - - - - Indicates whether to append newline at the end of log message. - - - - - Action that should be taken if the will be more connections than . - - - - - Action that should be taken if the message is larger than maxMessageSize. - - - - - Maximum current connections. 0 = no maximum. - - - - - Indicates whether to keep connection open whenever possible. - - - - - Size of the connection cache (number of connections which are kept alive). - - - - - Network address. - - - - - Maximum queue size. - - - - - NDC item separator. - - - - - Indicates whether to include source info (file name and line number) in the information sent over the network. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include contents of the stack. - - - - - Indicates whether to include stack contents. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include call site (class and method name) in the information sent over the network. - - - - - Option to include all properties from the log events - - - - - AppInfo field. By default it's the friendly name of the current AppDomain. - - - - - Indicates whether to include NLog-specific extensions to log4j schema. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Indicates whether to perform layout calculation. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Indicates whether performance counter should be automatically created. - - - - - Name of the performance counter category. - - - - - Counter help text. - - - - - Name of the performance counter. - - - - - Performance counter type. - - - - - The value by which to increment the counter. - - - - - Performance counter instance name. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Default filter to be applied when no specific rule matches. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - Condition to be tested. - - - - - Resulting filter to be applied when the condition matches. - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Number of times to repeat each log message. - - - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Number of retries that should be attempted on the wrapped target in case of a failure. - - - - - Time to wait between retries in milliseconds. - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Always use independent of - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Should we include the BOM (Byte-order-mark) for UTF? Influences the property. This will only work for UTF-8. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Encoding. - - - - - Value whether escaping be done according to the old NLog style (Very non-standard) - - - - - Value whether escaping be done according to Rfc3986 (Supports Internationalized Resource Identifiers - IRIs) - - - - - Web service method name. Only used with Soap. - - - - - Web service namespace. Only used with Soap. - - - - - Indicates whether to pre-authenticate the HttpWebRequest (Requires 'Authorization' in parameters) - - - - - Protocol to be used when calling web service. - - - - - Web service URL. - - - - - Name of the root XML element, if POST of XML document chosen. If so, this property must not be null. (see and ). - - - - - (optional) root namespace of the XML document, if POST of XML document chosen. (see and ). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Footer layout. - - - - - Header layout. - - - - - Body layout (can be repeated multiple times). - - - - - Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom'). - - - - - Column delimiter. - - - - - Quote Character. - - - - - Quoting mode. - - - - - Indicates whether CVS should include header. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Layout of the column. - - - - - Name of the column. - - - - - - - - - - - - - - - - - - List of property names to exclude when is true - - - - - Option to include all properties from the log events - - - - - Indicates whether to include contents of the dictionary. - - - - - Indicates whether to include contents of the dictionary. - - - - - Option to render the empty object value {} - - - - - Option to suppress the extra spaces in the output json - - - - - - - - - - - - - - - Determines wether or not this attribute will be Json encoded. - - - - - Indicates whether to escape non-ascii characters - - - - - Layout that will be rendered as the attribute's value. - - - - - Name of the attribute. - - - - - - - - - - - - - - Footer layout. - - - - - Header layout. - - - - - Body layout (can be repeated multiple times). - - - - - - - - - - - - - - - - - - Option to include all properties from the log events - - - - - Indicates whether to include contents of the dictionary. - - - - - Indicates whether to include contents of the dictionary. - - - - - Indicates whether to include contents of the stack. - - - - - Indicates whether to include contents of the stack. - - - - - - - - - - - - - - Layout text. - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Condition expression. - - - - - - - - - - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - Substring to be matched. - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - String to compare the layout to. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - Substring to be matched. - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - String to compare the layout to. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - - - - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Layout to be used to filter log messages. - - - - - Default number of unique filter values to expect, will automatically increase if needed - - - - - Append FilterCount to the when an event is no longer filtered - - - - - Insert FilterCount value into when an event is no longer filtered - - - - - Applies the configured action to the initial logevent that starts the timeout period. Used to configure that it should ignore all events until timeout. - - - - - Max number of unique filter values to expect simultaneously - - - - - Max length of filter values, will truncate if above limit - - - - - Default buffer size for the internal buffers - - - - - Reuse internal buffers, and doesn't have to constantly allocate new buffers - - - - - How long before a filter expires, and logging is accepted again - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/JT808.Gateway.SimpleServer/Configs/nlog.Unix.config b/src/JT808.Gateway.SimpleServer/Configs/nlog.Unix.config deleted file mode 100644 index ee227dd..0000000 --- a/src/JT808.Gateway.SimpleServer/Configs/nlog.Unix.config +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/JT808.Gateway.SimpleServer/Configs/nlog.Win32NT.config b/src/JT808.Gateway.SimpleServer/Configs/nlog.Win32NT.config deleted file mode 100644 index ec26e74..0000000 --- a/src/JT808.Gateway.SimpleServer/Configs/nlog.Win32NT.config +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/JT808.Gateway.SimpleServer/Configs/test.cer b/src/JT808.Gateway.SimpleServer/Configs/test.cer deleted file mode 100644 index 04963c13899644cbd857fd8651659b7a0fd1f9a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 784 zcmXqLV&*YuV*IjznTe5!iNoVPn`ZU4>~jXZY@Awc9&O)w85y}*84N@Wg$xAPm_u2Z zg*kKblM{0?@{3ChSmwcO}=MdiWuH}`HTB!%+kt^H6~2I9z8ixx_9B( zEuE70Z(8irT=Vx)^Yn?Yd>@yl%+hd?6_@#VeMgVM3PzKeomE-=1rwPVv}<%_{$F;A z-^sFmGh3X;BX!oUoF>QrpSc%Ks=Tk3E3*A;z34XWJ+-Z})AgFH&narMHG~_b&)nL- zoNcd|?97Y?;vjKBkT|aacN0={@w0IO6|pcjnTId}DMsX207fz} z78n_n17#0vZ+%)(^X~Qw;~s+B$3M zEaj~d(=2}|8k`c5DY$-sTevB9ipuE)KaO6tOJx07F}aAzVLL-bG~eo|rw(BbJQ7 diff --git a/src/JT808.Gateway.SimpleServer/JT808.Gateway.SimpleServer.csproj b/src/JT808.Gateway.SimpleServer/JT808.Gateway.SimpleServer.csproj deleted file mode 100644 index d8666d6..0000000 --- a/src/JT808.Gateway.SimpleServer/JT808.Gateway.SimpleServer.csproj +++ /dev/null @@ -1,39 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - - - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - - - diff --git a/src/JT808.Gateway.SimpleServer/Program.cs b/src/JT808.Gateway.SimpleServer/Program.cs deleted file mode 100644 index 2590e7f..0000000 --- a/src/JT808.Gateway.SimpleServer/Program.cs +++ /dev/null @@ -1,71 +0,0 @@ -using JT808.Gateway.Services; -using JT808.Gateway.Tcp; -using JT808.Gateway.Udp; -using JT808.Protocol; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using NLog.Extensions.Logging; -using System; -using System.IO; -using System.Net; - -namespace JT808.Gateway.SimpleServer -{ - class Program - { - static void Main(string[] args) - { - Host.CreateDefaultBuilder(args) - .ConfigureAppConfiguration((hostingContext, config) => - { - config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); - }) - .ConfigureLogging((hostContext, configLogging) => { - Console.WriteLine($"Environment.OSVersion.Platform:{Environment.OSVersion.Platform.ToString()}"); - NLog.LogManager.LoadConfiguration($"Configs/nlog.{Environment.OSVersion.Platform.ToString()}.config"); - configLogging.AddNLog(new NLogProviderOptions { CaptureMessageTemplates = true, CaptureMessageProperties = true }); - configLogging.SetMinimumLevel(LogLevel.Trace); - }) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder - .ConfigureKestrel(options => - { - options.Listen(IPAddress.Any, 5001, listenOptions => - { - listenOptions.Protocols = HttpProtocols.Http2; - listenOptions.UseHttps($"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Configs", "test.cer")}", ""); - }); - }) - .Configure(app => - { - app.UseRouting(); - app.UseEndpoints(endpoints => - { - endpoints.MapGrpcService(); - }); - }); - }) - .ConfigureServices((hostContext,services) => - { - //services.Configure(hostContext.Configuration.GetSection("Kestrel")); - services.AddGrpc(); - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddJT808Configure() - .AddJT808Gateway(hostContext.Configuration) - .AddJT808GatewayTcpHost() - .AddJT808GatewayUdpHost() - .Builder(); - }) - .Build() - .Run(); - } - } -} diff --git a/src/JT808.Gateway.sln b/src/JT808.Gateway.sln deleted file mode 100644 index b6b12d5..0000000 --- a/src/JT808.Gateway.sln +++ /dev/null @@ -1,102 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29411.108 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway", "JT808.Gateway\JT808.Gateway.csproj", "{A42A396F-D32B-4AC2-B554-735AA7E2DBA8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.Gateway.SimpleServer", "JT808.Gateway.SimpleServer\JT808.Gateway.SimpleServer.csproj", "{F9ABFDDB-84A2-44C8-A162-A1FE4EA4D332}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.Gateway.SimpleClient", "JT808.Gateway.SimpleClient\JT808.Gateway.SimpleClient.csproj", "{886D4937-7265-40DC-87CC-85CE35553214}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.Gateway.Kafka", "JT808.Gateway.Kafka\JT808.Gateway.Kafka.csproj", "{790E132C-7D92-4A6A-8CF0-2C181331FB31}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.Gateway.CleintBenchmark", "JT808.Gateway.CleintBenchmark\JT808.Gateway.CleintBenchmark.csproj", "{1A925C08-2590-4E55-84F2-96F01306D34D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{DC0E0AC1-C4BD-4291-AD16-744080411C3D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Traffic.Test", "JT808.Gateway.Tests\JT808.Gateway.Traffic.Test\JT808.Gateway.Traffic.Test.csproj", "{D4DF5285-612A-417D-BDE4-690BDF0C07C6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Transmit.Test", "JT808.Gateway.Tests\JT808.Gateway.Transmit.Test\JT808.Gateway.Transmit.Test.csproj", "{5E2C290C-637B-4F8B-AE03-1A4B669F7FFB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.SessionNotice.Test", "JT808.Gateway.Tests\JT808.Gateway.SessionNotice.Test\JT808.Gateway.SessionNotice.Test.csproj", "{562B16BD-1D4C-40FD-86CF-7845DBC9C1EE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.ReplyMessage.Test", "JT808.Gateway.Tests\JT808.Gateway.ReplyMessage.Test\JT808.Gateway.ReplyMessage.Test.csproj", "{CDE064DE-0E8E-4165-8F6A-6C03A8783506}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.MsgLogging.Test", "JT808.Gateway.Tests\JT808.Gateway.MsgLogging.Test\JT808.Gateway.MsgLogging.Test.csproj", "{8BD638B1-1F16-4BA8-8506-1B83DA4A884E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.MsgIdHandler.Test", "JT808.Gateway.Tests\JT808.Gateway.MsgIdHandler.Test\JT808.Gateway.MsgIdHandler.Test.csproj", "{CC2ABC8E-CC78-4B68-8670-90C2BCAB434E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.Gateway.Test", "JT808.Gateway.Tests\JT808.Gateway.Test\JT808.Gateway.Test.csproj", "{F1031636-69CF-4C44-AF0B-F8BE8DE03864}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A42A396F-D32B-4AC2-B554-735AA7E2DBA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A42A396F-D32B-4AC2-B554-735AA7E2DBA8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A42A396F-D32B-4AC2-B554-735AA7E2DBA8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A42A396F-D32B-4AC2-B554-735AA7E2DBA8}.Release|Any CPU.Build.0 = Release|Any CPU - {F9ABFDDB-84A2-44C8-A162-A1FE4EA4D332}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F9ABFDDB-84A2-44C8-A162-A1FE4EA4D332}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F9ABFDDB-84A2-44C8-A162-A1FE4EA4D332}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F9ABFDDB-84A2-44C8-A162-A1FE4EA4D332}.Release|Any CPU.Build.0 = Release|Any CPU - {886D4937-7265-40DC-87CC-85CE35553214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {886D4937-7265-40DC-87CC-85CE35553214}.Debug|Any CPU.Build.0 = Debug|Any CPU - {886D4937-7265-40DC-87CC-85CE35553214}.Release|Any CPU.ActiveCfg = Release|Any CPU - {886D4937-7265-40DC-87CC-85CE35553214}.Release|Any CPU.Build.0 = Release|Any CPU - {790E132C-7D92-4A6A-8CF0-2C181331FB31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {790E132C-7D92-4A6A-8CF0-2C181331FB31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {790E132C-7D92-4A6A-8CF0-2C181331FB31}.Release|Any CPU.ActiveCfg = Release|Any CPU - {790E132C-7D92-4A6A-8CF0-2C181331FB31}.Release|Any CPU.Build.0 = Release|Any CPU - {1A925C08-2590-4E55-84F2-96F01306D34D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1A925C08-2590-4E55-84F2-96F01306D34D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1A925C08-2590-4E55-84F2-96F01306D34D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1A925C08-2590-4E55-84F2-96F01306D34D}.Release|Any CPU.Build.0 = Release|Any CPU - {D4DF5285-612A-417D-BDE4-690BDF0C07C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D4DF5285-612A-417D-BDE4-690BDF0C07C6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D4DF5285-612A-417D-BDE4-690BDF0C07C6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D4DF5285-612A-417D-BDE4-690BDF0C07C6}.Release|Any CPU.Build.0 = Release|Any CPU - {5E2C290C-637B-4F8B-AE03-1A4B669F7FFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5E2C290C-637B-4F8B-AE03-1A4B669F7FFB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5E2C290C-637B-4F8B-AE03-1A4B669F7FFB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5E2C290C-637B-4F8B-AE03-1A4B669F7FFB}.Release|Any CPU.Build.0 = Release|Any CPU - {562B16BD-1D4C-40FD-86CF-7845DBC9C1EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {562B16BD-1D4C-40FD-86CF-7845DBC9C1EE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {562B16BD-1D4C-40FD-86CF-7845DBC9C1EE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {562B16BD-1D4C-40FD-86CF-7845DBC9C1EE}.Release|Any CPU.Build.0 = Release|Any CPU - {CDE064DE-0E8E-4165-8F6A-6C03A8783506}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CDE064DE-0E8E-4165-8F6A-6C03A8783506}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CDE064DE-0E8E-4165-8F6A-6C03A8783506}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CDE064DE-0E8E-4165-8F6A-6C03A8783506}.Release|Any CPU.Build.0 = Release|Any CPU - {8BD638B1-1F16-4BA8-8506-1B83DA4A884E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8BD638B1-1F16-4BA8-8506-1B83DA4A884E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8BD638B1-1F16-4BA8-8506-1B83DA4A884E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8BD638B1-1F16-4BA8-8506-1B83DA4A884E}.Release|Any CPU.Build.0 = Release|Any CPU - {CC2ABC8E-CC78-4B68-8670-90C2BCAB434E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CC2ABC8E-CC78-4B68-8670-90C2BCAB434E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CC2ABC8E-CC78-4B68-8670-90C2BCAB434E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CC2ABC8E-CC78-4B68-8670-90C2BCAB434E}.Release|Any CPU.Build.0 = Release|Any CPU - {F1031636-69CF-4C44-AF0B-F8BE8DE03864}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F1031636-69CF-4C44-AF0B-F8BE8DE03864}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F1031636-69CF-4C44-AF0B-F8BE8DE03864}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F1031636-69CF-4C44-AF0B-F8BE8DE03864}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {D4DF5285-612A-417D-BDE4-690BDF0C07C6} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - {5E2C290C-637B-4F8B-AE03-1A4B669F7FFB} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - {562B16BD-1D4C-40FD-86CF-7845DBC9C1EE} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - {CDE064DE-0E8E-4165-8F6A-6C03A8783506} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - {8BD638B1-1F16-4BA8-8506-1B83DA4A884E} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - {CC2ABC8E-CC78-4B68-8670-90C2BCAB434E} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - {F1031636-69CF-4C44-AF0B-F8BE8DE03864} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {F5671BD2-B44A-4A7C-80EA-E060A512992D} - EndGlobalSection -EndGlobal diff --git a/src/JT808.Gateway/BusinessServices/MsgIdHandler/IJT808MsgIdHandler.cs b/src/JT808.Gateway/BusinessServices/MsgIdHandler/IJT808MsgIdHandler.cs deleted file mode 100644 index 59bf986..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgIdHandler/IJT808MsgIdHandler.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.MsgIdHandler -{ - /// - /// JT808消息Id处理程序 - /// - public interface IJT808MsgIdHandler - { - void Processor((string TerminalNo, byte[] Data) parameter); - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerExtensions.cs b/src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerExtensions.cs deleted file mode 100644 index 433e065..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.MsgIdHandler -{ - public static class JT808MsgIdHandlerExtensions - { - public static IJT808ClientBuilder AddJT808MsgIdHandler(this IJT808ClientBuilder jT808ClientBuilder) - where TJT808MsgIdHandler: IJT808MsgIdHandler - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(typeof(IJT808MsgIdHandler),typeof(TJT808MsgIdHandler)); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerHostedService.cs b/src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerHostedService.cs deleted file mode 100644 index d85eb04..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerHostedService.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.MsgIdHandler -{ - public class JT808MsgIdHandlerHostedService : IHostedService - { - private readonly IJT808MsgConsumer jT808MsgConsumer; - - private readonly IJT808MsgIdHandler jT808MsgIdHandler; - public JT808MsgIdHandlerHostedService( - IJT808MsgIdHandler jT808DotNettyMsgIdHandler, - IJT808MsgConsumer jT808MsgConsumer) - { - this.jT808MsgIdHandler = jT808DotNettyMsgIdHandler; - this.jT808MsgConsumer = jT808MsgConsumer; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Subscribe(); - jT808MsgConsumer.OnMessage(jT808MsgIdHandler.Processor); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgLogging/IJT808MsgLogging.cs b/src/JT808.Gateway/BusinessServices/MsgLogging/IJT808MsgLogging.cs deleted file mode 100644 index b3daf96..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgLogging/IJT808MsgLogging.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.Gateway.BusinessServices.MsgLogging -{ - /// - /// 808数据上下行日志接口 - /// - public interface IJT808MsgLogging - { - void Processor((string TerminalNo, byte[] Data) parameter, JT808MsgLoggingType jT808MsgLoggingType); - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgDownLoggingHostedService.cs b/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgDownLoggingHostedService.cs deleted file mode 100644 index 7c52f15..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgDownLoggingHostedService.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.MsgLogging -{ - public class JT808MsgDownLoggingHostedService : IHostedService - { - private readonly IJT808MsgReplyConsumer jT808MsgReplyConsumer; - private readonly IJT808MsgLogging jT808MsgLogging; - public JT808MsgDownLoggingHostedService( - IJT808MsgLogging jT808MsgLogging, - IJT808MsgReplyConsumer jT808MsgReplyConsumer) - { - this.jT808MsgReplyConsumer = jT808MsgReplyConsumer; - this.jT808MsgLogging = jT808MsgLogging; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808MsgReplyConsumer.Subscribe(); - jT808MsgReplyConsumer.OnMessage(item=> - { - jT808MsgLogging.Processor(item, JT808MsgLoggingType.down); - }); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808MsgReplyConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingExtensions.cs b/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingExtensions.cs deleted file mode 100644 index 00f16ac..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.MsgLogging -{ - public static class JT808MsgLoggingExtensions - { - public static IJT808ClientBuilder AddJT808MsgLogging(this IJT808ClientBuilder jT808ClientBuilder) - where TJT808MsgLogging: IJT808MsgLogging - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(typeof(IJT808MsgLogging),typeof(TJT808MsgLogging)); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingType.cs b/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingType.cs deleted file mode 100644 index 1c83329..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingType.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.MsgLogging -{ - public enum JT808MsgLoggingType - { - /// - /// 数据上行 - /// - up, - /// - /// 数据下行 - /// - down - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgUpLoggingHostedService.cs b/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgUpLoggingHostedService.cs deleted file mode 100644 index be257b7..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgUpLoggingHostedService.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.MsgLogging -{ - public class JT808MsgUpLoggingHostedService : IHostedService - { - private readonly IJT808MsgConsumer jT808MsgConsumer; - private readonly IJT808MsgLogging jT808MsgLogging; - public JT808MsgUpLoggingHostedService( - IJT808MsgLogging jT808MsgLogging, - IJT808MsgConsumer jT808MsgConsumer) - { - this.jT808MsgConsumer = jT808MsgConsumer; - this.jT808MsgLogging = jT808MsgLogging; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Subscribe(); - jT808MsgConsumer.OnMessage(item=> - { - jT808MsgLogging.Processor(item, JT808MsgLoggingType.up); - }); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageExtensions.cs b/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageExtensions.cs deleted file mode 100644 index 049f824..0000000 --- a/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.ReplyMessage -{ - public static class JT808ReplyMessageExtensions - { - /// - /// 独享消息应答服务(不同的消费者实例) - /// - /// - /// - public static IJT808ClientBuilder AddInprocJT808ReplyMessage(this IJT808ClientBuilder jT808ClientBuilder) - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - /// - /// 独享消息应答服务(不同的消费者实例) - /// - /// 自定义消息回复服务 - /// - /// - public static IJT808ClientBuilder AddInprocJT808ReplyMessage(this IJT808ClientBuilder jT808ClientBuilder) - where TReplyMessageService : JT808ReplyMessageService - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - /// - /// 共享消息应答服务(消费者单实例) - /// - /// 自定义消息回复服务 - /// - /// - public static IJT808ClientBuilder AddShareJT808ReplyMessage(this IJT808ClientBuilder jT808ClientBuilder) - where TReplyMessageService : JT808ReplyMessageService - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - return jT808ClientBuilder; - } - /// - /// 共享消息应答服务(消费者单实例) - /// - /// - /// - public static IJT808ClientBuilder AddShareJT808ReplyMessage(this IJT808ClientBuilder jT808ClientBuilder) - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - return jT808ClientBuilder; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageHostedService.cs b/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageHostedService.cs deleted file mode 100644 index 1bd7e74..0000000 --- a/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageHostedService.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.ReplyMessage -{ - public class JT808ReplyMessageHostedService : IHostedService - { - private readonly IJT808MsgConsumer jT808MsgConsumer; - private readonly JT808ReplyMessageService jT808DotNettyReplyMessageService; - - public JT808ReplyMessageHostedService( - JT808ReplyMessageService jT808DotNettyReplyMessageService, - IJT808MsgConsumer jT808MsgConsumer) - { - this.jT808MsgConsumer = jT808MsgConsumer; - this.jT808DotNettyReplyMessageService = jT808DotNettyReplyMessageService; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Subscribe(); - jT808MsgConsumer.OnMessage(jT808DotNettyReplyMessageService.Processor); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageService.cs b/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageService.cs deleted file mode 100644 index 3fc64f6..0000000 --- a/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageService.cs +++ /dev/null @@ -1,165 +0,0 @@ -using JT808.Gateway.PubSub; -using JT808.Protocol; -using JT808.Protocol.Enums; -using JT808.Protocol.Extensions; -using JT808.Protocol.MessageBody; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.ReplyMessage -{ - public class JT808ReplyMessageService - { - protected Dictionary> HandlerDict { get; } - - protected JT808Serializer JT808Serializer { get; } - protected IJT808MsgReplyProducer JT808MsgReplyProducer { get; } - public JT808ReplyMessageService( - IJT808Config jT808Config, - IJT808MsgReplyProducer jT808MsgReplyProducer) - { - this.JT808Serializer = jT808Config.GetSerializer(); - this.JT808MsgReplyProducer = jT808MsgReplyProducer; - HandlerDict = new Dictionary> { - {JT808MsgId.终端通用应答.ToUInt16Value(), Msg0x0001}, - {JT808MsgId.终端鉴权.ToUInt16Value(), Msg0x0102}, - {JT808MsgId.终端心跳.ToUInt16Value(), Msg0x0002}, - {JT808MsgId.终端注销.ToUInt16Value(), Msg0x0003}, - {JT808MsgId.终端注册.ToUInt16Value(), Msg0x0100}, - {JT808MsgId.位置信息汇报.ToUInt16Value(),Msg0x0200 }, - {JT808MsgId.定位数据批量上传.ToUInt16Value(),Msg0x0704 }, - {JT808MsgId.数据上行透传.ToUInt16Value(),Msg0x0900 } - }; - } - - public virtual void Processor((string TerminalNo, byte[] Data) parameter) - { - try - { - var request = JT808Serializer.HeaderDeserialize(parameter.Data); - if (HandlerDict.TryGetValue(request.Header.MsgId, out var func)) - { - var buffer = func(request); - if (buffer != null) - { - JT808MsgReplyProducer.ProduceAsync(parameter.TerminalNo, buffer); - } - } - } - catch - { - } - } - - /// - /// 终端通用应答 - /// 平台无需回复 - /// 实现自己的业务 - /// - /// - /// - public virtual byte[] Msg0x0001(JT808HeaderPackage request) - { - return null; - } - /// - /// 终端心跳 - /// - /// - /// - public virtual byte[] Msg0x0002(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 终端注销 - /// - /// - /// - public virtual byte[] Msg0x0003(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 终端注册 - /// - /// - /// - public virtual byte[] Msg0x0100(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.终端注册应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8100() - { - Code = "J" + request.Header.TerminalPhoneNo, - JT808TerminalRegisterResult = JT808TerminalRegisterResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 终端鉴权 - /// - /// - /// - public virtual byte[] Msg0x0102(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 位置信息汇报 - /// - /// - /// - public virtual byte[] Msg0x0200(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 定位数据批量上传 - /// - /// - /// - public virtual byte[] Msg0x0704(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 数据上行透传 - /// - /// - /// - public virtual byte[] Msg0x0900(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeExtensions.cs b/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeExtensions.cs deleted file mode 100644 index c2c3b9b..0000000 --- a/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeExtensions.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.SessionNotice -{ - public static class JT808SessionNoticeExtensions - { - /// - /// 独享消息会话通知服务(不同的消费者实例) - /// - /// - /// - public static IJT808ClientBuilder AddInprocJT808SessionNotice(this IJT808ClientBuilder jT808ClientBuilder) - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - - /// - /// 独享消息会话通知服务(不同的消费者实例) - /// - /// 自定义会话通知服务 - /// - /// - public static IJT808ClientBuilder AddInprocJT808SessionNotice(this IJT808ClientBuilder jT808ClientBuilder) - where TSessionNoticeService : JT808SessionNoticeService - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - - /// - /// 共享消息会话通知服务(消费者单实例) - /// - /// 自定义会话通知服务 - /// - /// - public static IJT808ClientBuilder AddShareJT808SessionNotice(this IJT808ClientBuilder jT808ClientBuilder) - where TSessionNoticeService : JT808SessionNoticeService - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - return jT808ClientBuilder; - } - - /// - /// 共享消息会话通知服务(消费者单实例) - /// - /// - /// - public static IJT808ClientBuilder AddShareJT808SessionNotice(this IJT808ClientBuilder jT808ClientBuilder) - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - return jT808ClientBuilder; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeHostedService.cs b/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeHostedService.cs deleted file mode 100644 index 44c04ae..0000000 --- a/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeHostedService.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Threading.Tasks; -using JT808.Protocol; -using JT808.Protocol.Interfaces; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.SessionNotice -{ - public class JT808SessionNoticeHostedService : IHostedService - { - private readonly JT808SessionNoticeService jT808DotNettySessionNoticeService; - private readonly IJT808SessionConsumer jT808SessionConsumer; - public JT808SessionNoticeHostedService( - IJT808SessionConsumer jT808SessionConsumer, - JT808SessionNoticeService jT808DotNettySessionNoticeService) - { - this.jT808DotNettySessionNoticeService = jT808DotNettySessionNoticeService; - this.jT808SessionConsumer = jT808SessionConsumer; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808SessionConsumer.Subscribe(); - jT808SessionConsumer.OnMessage(jT808DotNettySessionNoticeService.Processor); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808SessionConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeService.cs b/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeService.cs deleted file mode 100644 index ccf4ace..0000000 --- a/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeService.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.SessionNotice -{ - public class JT808SessionNoticeService - { - protected ILogger logger { get; } - public JT808SessionNoticeService(ILoggerFactory loggerFactory) - { - logger = loggerFactory.CreateLogger("JT808DotNettySessionNoticeService"); - } - public virtual void Processor((string Notice, string TerminalNo) parameter) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug($"{parameter.Notice}-{parameter.TerminalNo}"); - } - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficService.cs b/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficService.cs deleted file mode 100644 index f028a5d..0000000 --- a/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficService.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Microsoft.Extensions.Configuration; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.Traffic -{ - public class JT808TrafficService:IDisposable - { - private readonly CSRedis.CSRedisClient redisClien; - public JT808TrafficService(IConfiguration configuration) - { - redisClien = new CSRedis.CSRedisClient(configuration.GetConnectionString("TrafficRedisHost")); - TrafficRedisClient.Initialization(redisClien); - } - - public void Dispose() - { - redisClien.Dispose(); - } - - /// - /// 按设备每天统计sim卡流量 - /// - /// - /// - public void Processor(string terminalNo,int len) - { - TrafficRedisClient.HIncrBy(terminalNo, DateTime.Now.ToString("yyyyMMdd"), len); - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceExtensions.cs b/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceExtensions.cs deleted file mode 100644 index 4a83b0d..0000000 --- a/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.Traffic -{ - public static class JT808TrafficServiceExtensions - { - /// - /// 独享消息流量统计服务(不同的消费者实例) - /// - /// - /// - public static IJT808ClientBuilder AddInprocJT808Traffic(this IJT808ClientBuilder jT808ClientBuilder) - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - /// - /// 共享消息流量统计服务(消费者单实例) - /// - /// - /// - /// - public static IJT808ClientBuilder AddShareJT808Traffic(this IJT808ClientBuilder jT808ClientBuilder) - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - return jT808ClientBuilder; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceHostedService.cs b/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceHostedService.cs deleted file mode 100644 index 84c4299..0000000 --- a/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceHostedService.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Protocol.Extensions; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.Traffic -{ - public class JT808TrafficServiceHostedService : IHostedService - { - private readonly IJT808MsgConsumer jT808MsgConsumer; - private readonly JT808TrafficService jT808DotNettyTrafficService; - - public JT808TrafficServiceHostedService( - JT808TrafficService jT808DotNettyTrafficService, - IJT808MsgConsumer jT808MsgConsumer) - { - this.jT808MsgConsumer = jT808MsgConsumer; - this.jT808DotNettyTrafficService = jT808DotNettyTrafficService; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Subscribe(); - jT808MsgConsumer.OnMessage((item)=> { - string str = item.Data.ToHexString(); - jT808DotNettyTrafficService.Processor(item.TerminalNo, item.Data.Length); - }); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Traffic/TrafficRedisClient.cs b/src/JT808.Gateway/BusinessServices/Traffic/TrafficRedisClient.cs deleted file mode 100644 index eb04aa0..0000000 --- a/src/JT808.Gateway/BusinessServices/Traffic/TrafficRedisClient.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.Traffic -{ - class TrafficRedisClient: RedisHelper - { } -} diff --git a/src/JT808.Gateway/BusinessServices/Transmit/Configs/DataTransferOptions.cs b/src/JT808.Gateway/BusinessServices/Transmit/Configs/DataTransferOptions.cs deleted file mode 100644 index 5a50189..0000000 --- a/src/JT808.Gateway/BusinessServices/Transmit/Configs/DataTransferOptions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.Transmit.Configs -{ - public class DataTransferOptions - { - public string Host { get; set; } - - public List TerminalNos { get; set; } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Transmit/Configs/RemoteServerOptions.cs b/src/JT808.Gateway/BusinessServices/Transmit/Configs/RemoteServerOptions.cs deleted file mode 100644 index b9872cb..0000000 --- a/src/JT808.Gateway/BusinessServices/Transmit/Configs/RemoteServerOptions.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.Transmit.Configs -{ - public class RemoteServerOptions - { - public List DataTransfer { get; set; } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Transmit/Handlers/ClientConnectionHandler.cs b/src/JT808.Gateway/BusinessServices/Transmit/Handlers/ClientConnectionHandler.cs deleted file mode 100644 index 397b063..0000000 --- a/src/JT808.Gateway/BusinessServices/Transmit/Handlers/ClientConnectionHandler.cs +++ /dev/null @@ -1,76 +0,0 @@ -using DotNetty.Transport.Bootstrapping; -using DotNetty.Transport.Channels; -using DotNetty.Transport.Channels.Sockets; -using Polly; -using System; -using System.Linq; -using System.Collections.Generic; -using System.Net; -using System.Text; -using Microsoft.Extensions.Logging; - -namespace JT808.Gateway.BusinessServices.Transmit.Handlers -{ - public class ClientConnectionHandler : ChannelHandlerAdapter - { - private readonly Bootstrap bootstrap; - public Dictionary channeldic; - private readonly ILogger logger; - public ClientConnectionHandler(Bootstrap bootstrap, - Dictionary channeldic, - ILoggerFactory loggerFactory) - { - this.bootstrap = bootstrap; - this.channeldic = channeldic; - logger = loggerFactory.CreateLogger(); - } - public override void ChannelInactive(IChannelHandlerContext context) - { - Policy.HandleResult(context.Channel.Open) - .WaitAndRetryForeverAsync(retryAttempt => - { - return retryAttempt > 20 ? TimeSpan.FromSeconds(Math.Pow(2, 50)) : TimeSpan.FromSeconds(Math.Pow(2, retryAttempt));//超过重试20次,之后重试都是接近12个小时重试一次 - }, - (exception, timespan, ctx) => - { - logger.LogError($"服务端断开{context.Channel.RemoteAddress},重试结果{exception.Result},重试次数{timespan},下次重试间隔(s){ctx.TotalSeconds}"); - }) - .ExecuteAsync(async () => - { - try - { - var oldChannel = channeldic.FirstOrDefault(m => m.Value == context.Channel); - if (default(KeyValuePair).Equals(oldChannel)) - { - if(logger.IsEnabled( LogLevel.Debug)) - logger.LogDebug($"服务器已经删除了{oldChannel.Key}远程服务器配置"); - return true; - } - var channel = await bootstrap.ConnectAsync(context.Channel.RemoteAddress); - channeldic.Remove(oldChannel.Key); - channeldic.Add(oldChannel.Key, channel); - return channel.Open; - } - catch (Exception ex) - { - logger.LogError($"服务端断开后{context.Channel.RemoteAddress},重连异常:{ex}"); - return false; - } - }); - } - - public override void ChannelRead(IChannelHandlerContext context, object message) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogError($"服务端返回消息{message}"); - } - } - - public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) - { - logger.LogError($"服务端Exception: {exception}"); - context.CloseAsync(); - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitExtensions.cs b/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitExtensions.cs deleted file mode 100644 index 969b2fd..0000000 --- a/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using JT808.Gateway.BusinessServices.Transmit.Configs; - -namespace JT808.Gateway.BusinessServices.Transmit -{ - public static class JT808DotNettyTransmitExtensions - { - /// - /// 独享转发服务(不同的消费者实例) - /// - /// - /// - /// - public static IJT808ClientBuilder AddInprocJT808Transmit(this IJT808ClientBuilder jT808ClientBuilder,IConfiguration configuration) - { - jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("RemoteServerOptions")); - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - /// - /// 共享转发服务(消费者单实例) - /// - /// - /// - /// - public static IJT808ClientBuilder AddShareJT808Transmit(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) - { - jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("RemoteServerOptions")); - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - return jT808ClientBuilder; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitHostedService.cs b/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitHostedService.cs deleted file mode 100644 index 51504b5..0000000 --- a/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitHostedService.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.Transmit -{ - public class JT808DotNettyTransmitHostedService:IHostedService - { - private readonly JT808DotNettyTransmitService jT808DotNettyTransmitService; - private readonly IJT808MsgConsumer jT808MsgConsumer; - public JT808DotNettyTransmitHostedService( - IJT808MsgConsumer jT808MsgConsumer, - JT808DotNettyTransmitService jT808DotNettyTransmitService) - { - this.jT808DotNettyTransmitService = jT808DotNettyTransmitService; - this.jT808MsgConsumer = jT808MsgConsumer; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Subscribe(); - jT808MsgConsumer.OnMessage(jT808DotNettyTransmitService.Send); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitService.cs b/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitService.cs deleted file mode 100644 index 1c2d8c3..0000000 --- a/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitService.cs +++ /dev/null @@ -1,236 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Transport.Bootstrapping; -using DotNetty.Transport.Channels; -using DotNetty.Transport.Channels.Sockets; -using System; -using System.Collections.Generic; -using System.Net; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System.Linq; -using JT808.Gateway.BusinessServices.Transmit.Configs; -using JT808.Gateway.BusinessServices.Transmit.Handlers; - -namespace JT808.Gateway.BusinessServices.Transmit -{ - public class JT808DotNettyTransmitService - { - private readonly ILogger logger; - private readonly ILoggerFactory loggerFactory; - private IOptionsMonitor optionsMonitor; - public Dictionary channeldic = new Dictionary(); - public JT808DotNettyTransmitService(ILoggerFactory loggerFactory, - IOptionsMonitor optionsMonitor) - { - this.loggerFactory = loggerFactory; - logger = loggerFactory.CreateLogger("JT808DotNettyTransmitService"); - this.optionsMonitor = optionsMonitor; - InitialDispatcherClient(); - } - public void Send((string TerminalNo, byte[] Data) parameter) - { - if (optionsMonitor.CurrentValue.DataTransfer != null) - { - foreach (var item in optionsMonitor.CurrentValue.DataTransfer) - { - if (channeldic.TryGetValue($"all_{item.Host}", out var allClientChannel)) - { - try - { - if (allClientChannel.Open) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug($"转发所有数据到该网关{item.Host}"); - } - allClientChannel.WriteAndFlushAsync(Unpooled.WrappedBuffer(parameter.Data)); - } - else - { - logger.LogError($"{item.Host}链接已关闭"); - } - } - catch (Exception ex) - { - logger.LogError($"{item.Host}发送数据出现异常:{ex}"); - } - } - else - { - if (item.TerminalNos.Contains(parameter.TerminalNo) && channeldic.TryGetValue($"{parameter.TerminalNo}_{item.Host}", out var clientChannel)) - { - try - { - if (clientChannel.Open) - { - if (logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - logger.LogDebug($"转发{parameter.TerminalNo}到该网关{item.Host}"); - clientChannel.WriteAndFlushAsync(Unpooled.WrappedBuffer(parameter.Data)); - } - else - { - logger.LogError($"{item.Host},{parameter.TerminalNo}链接已关闭"); - } - } - catch (Exception ex) - { - logger.LogError($"{item.Host},{parameter.TerminalNo}发送数据出现异常:{ex}"); - } - } - } - } - } - } - - public void InitialDispatcherClient() - { - Task.Run(async () => - { - var group = new MultithreadEventLoopGroup(); - var bootstrap = new Bootstrap(); - bootstrap.Group(group) - .Channel() - .Option(ChannelOption.TcpNodelay, true) - .Handler(new ActionChannelInitializer(channel => - { - IChannelPipeline pipeline = channel.Pipeline; - pipeline.AddLast(new ClientConnectionHandler(bootstrap, channeldic, loggerFactory)); - })); - optionsMonitor.OnChange(options => - { - List lastRemoteServers = new List(); - if (options.DataTransfer != null) - { - if (options.DataTransfer.Any()) - { - foreach (var item in options.DataTransfer) - { - if (item.TerminalNos != null) - { - if (item.TerminalNos.Any()) - { - foreach (var terminal in item.TerminalNos) - { - lastRemoteServers.Add($"{terminal}_{item.Host}"); - } - } - else - { - lastRemoteServers.Add($"all_{item.Host}"); - } - } - else - { - lastRemoteServers.Add($"all_{item.Host}"); - } - } - } - } - DelRemoteServsers(lastRemoteServers); - AddRemoteServsers(bootstrap, lastRemoteServers); - }); - await InitRemoteServsers(bootstrap); - }); - } - /// - /// 初始化远程服务器 - /// - /// - /// - /// - private async Task InitRemoteServsers(Bootstrap bootstrap) - { - List remoteServers = new List(); - if (optionsMonitor.CurrentValue.DataTransfer != null) - { - if (optionsMonitor.CurrentValue.DataTransfer.Any()) - { - foreach (var item in optionsMonitor.CurrentValue.DataTransfer) - { - if (item.TerminalNos != null) - { - if (item.TerminalNos.Any()) - { - foreach (var terminal in item.TerminalNos) - { - remoteServers.Add($"{terminal}_{item.Host}"); - } - } - else - { - remoteServers.Add($"all_{item.Host}"); - } - } - else - { - remoteServers.Add($"all_{item.Host}"); - } - } - } - } - foreach (var item in remoteServers) - { - try - { - string ip_port = item.Split('_')[1]; - IChannel clientChannel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip_port.Split(':')[0]), int.Parse(ip_port.Split(':')[1]))); - channeldic.Add(item, clientChannel); - if (clientChannel.Open) - { - if (logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - logger.LogDebug($"该终端{item.Replace("_", "已连接上该服务器")}"); - } - } - } - catch (Exception ex) - { - logger.LogError($"初始化配置链接远程服务端{item},链接异常:{ex}"); - } - } - await Task.CompletedTask; - } - /// - /// 动态删除远程服务器 - /// - /// - private void DelRemoteServsers(List lastRemoteServers) - { - var delChannels = channeldic.Keys.Except(lastRemoteServers).ToList(); - foreach (var item in delChannels) - { - channeldic[item].CloseAsync(); - channeldic.Remove(item); - } - } - /// - /// 动态添加远程服务器 - /// - /// - /// - private void AddRemoteServsers(Bootstrap bootstrap, List lastRemoteServers) - { - var addChannels = lastRemoteServers.Except(channeldic.Keys).ToList(); - foreach (var item in addChannels) - { - try - { - var ip_port = item.Split('_')[1]; - IChannel clientChannel = bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip_port.Split(':')[0]), int.Parse(ip_port.Split(':')[1]))).Result; - channeldic.Add(item, clientChannel); - if (clientChannel.Open) { - if (logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - logger.LogDebug($"该终端{item.Replace("_", "已连接上该服务器")}"); - } - } - } - catch (Exception ex) - { - logger.LogError($"变更配置后链接远程服务端{item},重连异常:{ex}"); - } - } - } - } -} diff --git a/src/JT808.Gateway/Client/DeviceConfig.cs b/src/JT808.Gateway/Client/DeviceConfig.cs deleted file mode 100644 index 53518ef..0000000 --- a/src/JT808.Gateway/Client/DeviceConfig.cs +++ /dev/null @@ -1,28 +0,0 @@ -using JT808.Protocol; -using JT808.Protocol.Interfaces; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Client -{ - public class DeviceConfig - { - public DeviceConfig(string terminalPhoneNo, string tcpHost,int tcpPort) - { - TerminalPhoneNo = terminalPhoneNo; - TcpHost = tcpHost; - TcpPort = tcpPort; - MsgSNDistributed = new JT808ClientMsgSNDistributedImpl(); - } - public string TerminalPhoneNo { get; private set; } - public string TcpHost { get; private set; } - public int TcpPort { get; private set; } - /// - /// 心跳时间(秒) - /// - public int Heartbeat { get; set; } = 30; - - public IJT808MsgSNDistributed MsgSNDistributed { get; } - } -} diff --git a/src/JT808.Gateway/Client/JT808ClientDotnettyExtensions.cs b/src/JT808.Gateway/Client/JT808ClientDotnettyExtensions.cs deleted file mode 100644 index 05d998f..0000000 --- a/src/JT808.Gateway/Client/JT808ClientDotnettyExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ - -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; -using JT808.Protocol; -using JT808.Gateway.Services; - -namespace JT808.Gateway.Client -{ - public static class JT808ClientDotnettyExtensions - { - public static IJT808Builder AddJT808Client(this IJT808Builder jT808Builder) - { - jT808Builder.Services.AddSingleton(); - jT808Builder.Services.AddSingleton(); - jT808Builder.Services.AddSingleton(); - jT808Builder.Services.AddSingleton(); - jT808Builder.Services.AddHostedService(); - return jT808Builder; - } - } -} diff --git a/src/JT808.Gateway/Client/JT808ClientMsgSNDistributedImpl.cs b/src/JT808.Gateway/Client/JT808ClientMsgSNDistributedImpl.cs deleted file mode 100644 index a7c11b6..0000000 --- a/src/JT808.Gateway/Client/JT808ClientMsgSNDistributedImpl.cs +++ /dev/null @@ -1,16 +0,0 @@ -using JT808.Protocol; -using JT808.Protocol.Interfaces; -using System.Threading; - -namespace JT808.Gateway.Client -{ - internal class JT808ClientMsgSNDistributedImpl : IJT808MsgSNDistributed - { - int _counter = 0; - - public ushort Increment() - { - return (ushort)Interlocked.Increment(ref _counter); - } - } -} diff --git a/src/JT808.Gateway/Client/JT808TcpClient.cs b/src/JT808.Gateway/Client/JT808TcpClient.cs deleted file mode 100644 index 9b6b93c..0000000 --- a/src/JT808.Gateway/Client/JT808TcpClient.cs +++ /dev/null @@ -1,112 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using DotNetty.Handlers.Timeout; -using DotNetty.Transport.Bootstrapping; -using DotNetty.Transport.Channels; -using DotNetty.Transport.Channels.Sockets; -using Microsoft.Extensions.Logging; -using System; -using System.Runtime.InteropServices; -using Microsoft.Extensions.DependencyInjection; -using System.Net; -using JT808.Protocol; -using JT808.Gateway.Services; -using JT808.Gateway.Codecs; -using JT808.Gateway.Handlers; -using JT808.Gateway.Metadata; - -namespace JT808.Gateway.Client -{ - public sealed class JT808TcpClient : IDisposable - { - private MultithreadEventLoopGroup group; - - private IChannel clientChannel; - - private bool disposed = false; - - public DeviceConfig DeviceConfig { get; private set; } - - public ILoggerFactory LoggerFactory { get; private set; } - - public JT808TcpClient(DeviceConfig deviceConfig, IServiceProvider serviceProvider) - { - DeviceConfig = deviceConfig; - LoggerFactory = serviceProvider.GetRequiredService(); - JT808ClientSendAtomicCounterService jT808SendAtomicCounterService = serviceProvider.GetRequiredService(); - JT808ClientReceiveAtomicCounterService jT808ReceiveAtomicCounterService = serviceProvider.GetRequiredService(); - IJT808Config jT808Config = serviceProvider.GetRequiredService(); - group = new MultithreadEventLoopGroup(1); - Bootstrap bootstrap = new Bootstrap(); - bootstrap.Group(group); - bootstrap.Channel(); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - bootstrap.Option(ChannelOption.SoReuseport, true); - } - bootstrap - .Option(ChannelOption.SoBacklog, 8192) - .Handler(new ActionChannelInitializer(channel => - { - channel.Pipeline.AddLast("jt808TcpBuffer", new DelimiterBasedFrameDecoder(int.MaxValue, - Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), - Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); - channel.Pipeline.AddLast("systemIdleState", new IdleStateHandler(60, deviceConfig.Heartbeat, 3600)); - channel.Pipeline.AddLast("jt808TcpDecode", new JT808ClientTcpDecoder()); - channel.Pipeline.AddLast("jt808TcpEncode", new JT808ClientTcpEncoder(jT808Config,jT808SendAtomicCounterService, LoggerFactory)); - channel.Pipeline.AddLast("jt808TcpClientConnection", new JT808TcpClientConnectionHandler(this)); - channel.Pipeline.AddLast("jt808TcpService", new JT808TcpClientHandler(jT808ReceiveAtomicCounterService,this)); - })); - clientChannel = bootstrap.ConnectAsync(IPAddress.Parse(DeviceConfig.TcpHost), DeviceConfig.TcpPort).Result; - } - - public async void Send(JT808ClientRequest request) - { - if (disposed) return; - if (clientChannel == null) throw new NullReferenceException("Channel is empty."); - if (request == null) throw new ArgumentNullException("JT808ClientRequest Parameter is empty."); - if (clientChannel.Active && clientChannel.Open) - { - await clientChannel.WriteAndFlushAsync(request); - } - } - - public bool IsOpen - { - get - { - if (clientChannel == null) return false; - return clientChannel.Active && clientChannel.Open; - } - } - - private void Dispose(bool disposing) - { - if (disposed) - { - return; - } - if (disposing) - { - // 清理托管资源 - group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)); - } - disposed = true; - } - - ~JT808TcpClient() - { - //必须为false - //这表明,隐式清理时,只要处理非托管资源就可以了。 - Dispose(false); - } - - public void Dispose() - { - //必须为true - Dispose(true); - //通知垃圾回收机制不再调用终结器(析构器) - GC.SuppressFinalize(this); - } - } -} diff --git a/src/JT808.Gateway/Client/JT808TcpClientExtensions.cs b/src/JT808.Gateway/Client/JT808TcpClientExtensions.cs deleted file mode 100644 index 919405e..0000000 --- a/src/JT808.Gateway/Client/JT808TcpClientExtensions.cs +++ /dev/null @@ -1,103 +0,0 @@ -using JT808.Protocol; -using JT808.Protocol.MessageBody; -using System; -using System.Collections.Generic; -using System.Text; -using JT808.Protocol.Enums; -using JT808.Protocol.Extensions; -using JT808.Gateway.Metadata; - -namespace JT808.Gateway.Client -{ - public static class JT808TcpClientExtensions - { - public static void Send(this JT808TcpClient client, JT808Header header, JT808Bodies bodies, int minBufferSize = 1024) - { - JT808Package package = new JT808Package(); - package.Header = header; - package.Bodies = bodies; - package.Header.TerminalPhoneNo = client.DeviceConfig.TerminalPhoneNo; - package.Header.MsgNum = client.DeviceConfig.MsgSNDistributed.Increment(); - JT808ClientRequest request = new JT808ClientRequest(package, minBufferSize); - client.Send(request); - } - - /// - /// 终端通用应答 - /// - /// - /// - /// - public static void Send(this JT808TcpClient client, JT808_0x0001 bodies, int minBufferSize = 100) - { - JT808Header header = new JT808Header(); - header.MsgId = JT808MsgId.终端通用应答.ToUInt16Value(); - client.Send(header, bodies, minBufferSize); - } - - /// - /// 终端心跳 - /// - /// - /// - /// - public static void Send(this JT808TcpClient client, JT808_0x0002 bodies, int minBufferSize = 100) - { - JT808Header header = new JT808Header(); - header.MsgId = JT808MsgId.终端心跳.ToUInt16Value(); - client.Send(header, bodies, minBufferSize); - } - - /// - /// 终端注销 - /// - /// - /// - /// - public static void Send(this JT808TcpClient client, JT808_0x0003 bodies, int minBufferSize = 100) - { - JT808Header header = new JT808Header(); - header.MsgId = JT808MsgId.终端注销.ToUInt16Value(); - client.Send(header, bodies, minBufferSize); - } - - /// - /// 终端鉴权 - /// - /// - /// - /// - public static void Send(this JT808TcpClient client, JT808_0x0102 bodies, int minBufferSize = 100) - { - JT808Header header = new JT808Header(); - header.MsgId = JT808MsgId.终端鉴权.ToUInt16Value(); - client.Send(header, bodies, minBufferSize); - } - - /// - /// 终端注册 - /// - /// - /// - /// - public static void Send(this JT808TcpClient client, JT808_0x0100 bodies, int minBufferSize = 100) - { - JT808Header header = new JT808Header(); - header.MsgId = JT808MsgId.终端注册.ToUInt16Value(); - client.Send(header, bodies, minBufferSize); - } - - /// - /// 位置信息汇报 - /// - /// - /// - /// - public static void Send(this JT808TcpClient client, JT808_0x0200 bodies, int minBufferSize = 200) - { - JT808Header header = new JT808Header(); - header.MsgId = JT808MsgId.位置信息汇报.ToUInt16Value(); - client.Send(header, bodies, minBufferSize); - } - } -} diff --git a/src/JT808.Gateway/Client/JT808TcpClientFactory.cs b/src/JT808.Gateway/Client/JT808TcpClientFactory.cs deleted file mode 100644 index 1e78b8a..0000000 --- a/src/JT808.Gateway/Client/JT808TcpClientFactory.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; - -namespace JT808.Gateway.Client -{ - public interface IJT808TcpClientFactory : IDisposable - { - JT808TcpClient Create(DeviceConfig deviceConfig); - - List GetAll(); - } - - public class JT808TcpClientFactory: IJT808TcpClientFactory - { - private readonly ConcurrentDictionary dict; - - private readonly IServiceProvider serviceProvider; - - public JT808TcpClientFactory(IServiceProvider serviceProvider) - { - dict = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - this.serviceProvider = serviceProvider; - } - - public JT808TcpClient Create(DeviceConfig deviceConfig) - { - if(dict.TryGetValue(deviceConfig.TerminalPhoneNo,out var client)) - { - return client; - } - else - { - JT808TcpClient jT808TcpClient = new JT808TcpClient(deviceConfig, serviceProvider); - dict.TryAdd(deviceConfig.TerminalPhoneNo, jT808TcpClient); - return jT808TcpClient; - } - } - - public void Dispose() - { - foreach(var client in dict) - { - try - { - client.Value.Dispose(); - } - catch - { - } - } - } - - public List GetAll() - { - return dict.Values.ToList(); - } - } -} diff --git a/src/JT808.Gateway/Codecs/JT808ClientTcpDecoder.cs b/src/JT808.Gateway/Codecs/JT808ClientTcpDecoder.cs deleted file mode 100644 index c3aa8f1..0000000 --- a/src/JT808.Gateway/Codecs/JT808ClientTcpDecoder.cs +++ /dev/null @@ -1,20 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using System.Collections.Generic; -using JT808.Protocol; -using DotNetty.Transport.Channels; - -namespace JT808.Gateway.Codecs -{ - public class JT808ClientTcpDecoder : ByteToMessageDecoder - { - protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List output) - { - byte[] buffer = new byte[input.Capacity + 2]; - input.ReadBytes(buffer, 1, input.Capacity); - buffer[0] = JT808Package.BeginFlag; - buffer[input.Capacity + 1] = JT808Package.EndFlag; - output.Add(buffer); - } - } -} diff --git a/src/JT808.Gateway/Codecs/JT808ClientTcpEncoder.cs b/src/JT808.Gateway/Codecs/JT808ClientTcpEncoder.cs deleted file mode 100644 index eddc19c..0000000 --- a/src/JT808.Gateway/Codecs/JT808ClientTcpEncoder.cs +++ /dev/null @@ -1,52 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using JT808.Protocol; -using DotNetty.Transport.Channels; -using Microsoft.Extensions.Logging; -using JT808.Gateway.Metadata; -using JT808.Gateway.Services; - -namespace JT808.Gateway.Codecs -{ - public class JT808ClientTcpEncoder : MessageToByteEncoder - { - private readonly ILogger logger; - private readonly JT808ClientSendAtomicCounterService jT808SendAtomicCounterService; - private readonly JT808Serializer JT808Serializer; - - public JT808ClientTcpEncoder( - IJT808Config jT808Config, - JT808ClientSendAtomicCounterService jT808SendAtomicCounterService,ILoggerFactory loggerFactory) - { - logger=loggerFactory.CreateLogger(); - this.jT808SendAtomicCounterService = jT808SendAtomicCounterService; - JT808Serializer = jT808Config.GetSerializer(); - } - - protected override void Encode(IChannelHandlerContext context, JT808ClientRequest message, IByteBuffer output) - { - if (message.Package != null) - { - try - { - var sendData = JT808Serializer.Serialize(message.Package, message.MinBufferSize); - output.WriteBytes(sendData); - jT808SendAtomicCounterService.MsgSuccessIncrement(); - } - catch (JT808.Protocol.Exceptions.JT808Exception ex) - { - logger.LogError(ex, context.Channel.Id.AsShortText()); - } - catch (System.Exception ex) - { - logger.LogError(ex, context.Channel.Id.AsShortText()); - } - } - else if (message.HexData != null) - { - output.WriteBytes(message.HexData); - jT808SendAtomicCounterService.MsgSuccessIncrement(); - } - } - } -} diff --git a/src/JT808.Gateway/Codecs/JT808TcpDecoder.cs b/src/JT808.Gateway/Codecs/JT808TcpDecoder.cs deleted file mode 100644 index 10e3ff1..0000000 --- a/src/JT808.Gateway/Codecs/JT808TcpDecoder.cs +++ /dev/null @@ -1,32 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using System.Collections.Generic; -using JT808.Protocol; -using DotNetty.Transport.Channels; - -namespace JT808.Gateway.Codecs -{ - public class JT808TcpDecoder : ByteToMessageDecoder - { - protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List output) - { - //过滤掉不是808标准包 - //不包括头尾标识 - //(消息 ID )2+(消息体属性)2+(终端手机号)6+(消息流水号)2+(检验码 )1 - if (input.Capacity < 12) - { - byte[] buffer = new byte[input.Capacity]; - input.ReadBytes(buffer, 0, input.Capacity); - return; - } - else - { - byte[] buffer = new byte[input.Capacity + 2]; - input.ReadBytes(buffer, 1, input.Capacity); - buffer[0] = JT808Package.BeginFlag; - buffer[input.Capacity + 1] = JT808Package.EndFlag; - output.Add(buffer); - } - } - } -} diff --git a/src/JT808.Gateway/Codecs/JT808TcpEncoder.cs b/src/JT808.Gateway/Codecs/JT808TcpEncoder.cs deleted file mode 100644 index ca92147..0000000 --- a/src/JT808.Gateway/Codecs/JT808TcpEncoder.cs +++ /dev/null @@ -1,52 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using JT808.Protocol; -using DotNetty.Transport.Channels; -using Microsoft.Extensions.Logging; -using JT808.Protocol.Interfaces; -using JT808.Gateway.Interfaces; - -namespace JT808.Gateway.Codecs -{ - /// - /// tcp统一下发出口 - /// - public class JT808TcpEncoder : MessageToByteEncoder - { - private readonly ILogger logger; - - private readonly JT808Serializer JT808Serializer; - - public JT808TcpEncoder( - IJT808Config jT808Config, - ILoggerFactory loggerFactory) - { - logger = loggerFactory.CreateLogger(); - this.JT808Serializer = jT808Config.GetSerializer(); - } - - protected override void Encode(IChannelHandlerContext context, IJT808Reply message, IByteBuffer output) - { - if (message.Package != null) - { - try - { - var sendData = JT808Serializer.Serialize(message.Package, message.MinBufferSize); - output.WriteBytes(Unpooled.WrappedBuffer(sendData)); - } - catch (JT808.Protocol.Exceptions.JT808Exception ex) - { - logger.LogError(ex, context.Channel.Id.AsShortText()); - } - catch (System.Exception ex) - { - logger.LogError(ex, context.Channel.Id.AsShortText()); - } - } - else if (message.HexData != null) - { - output.WriteBytes(Unpooled.WrappedBuffer(message.HexData)); - } - } - } -} diff --git a/src/JT808.Gateway/Codecs/JT808UdpDecoder.cs b/src/JT808.Gateway/Codecs/JT808UdpDecoder.cs deleted file mode 100644 index d3018f8..0000000 --- a/src/JT808.Gateway/Codecs/JT808UdpDecoder.cs +++ /dev/null @@ -1,33 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using DotNetty.Transport.Channels; -using System.Collections.Generic; -using DotNetty.Transport.Channels.Sockets; -using JT808.Gateway.Metadata; - -namespace JT808.Gateway.Codecs -{ - public class JT808UdpDecoder : MessageToMessageDecoder - { - protected override void Decode(IChannelHandlerContext context, DatagramPacket message, List output) - { - if (!message.Content.IsReadable()) return; - IByteBuffer byteBuffer = message.Content; - //过滤掉非808标准包 - //不包括头尾标识 - //(消息 ID )2+(消息体属性)2+(终端手机号)6+(消息流水号)2+(检验码 )1 - if (byteBuffer.ReadableBytes < 12) - { - byte[] buffer = new byte[byteBuffer.ReadableBytes]; - byteBuffer.ReadBytes(buffer, 0, byteBuffer.ReadableBytes); - return; - } - else - { - byte[] buffer = new byte[byteBuffer.ReadableBytes]; - byteBuffer.ReadBytes(buffer); - output.Add(new JT808UdpPackage(buffer, message.Sender)); - } - } - } -} diff --git a/src/JT808.Gateway/Configurations/JT808Configuration.cs b/src/JT808.Gateway/Configurations/JT808Configuration.cs deleted file mode 100644 index c39ab4e..0000000 --- a/src/JT808.Gateway/Configurations/JT808Configuration.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configurations -{ - public class JT808Configuration - { - public int TcpPort { get; set; } = 808; - - public int UdpPort { get; set; } = 808; - - public int QuietPeriodSeconds { get; set; } = 1; - - public TimeSpan QuietPeriodTimeSpan => TimeSpan.FromSeconds(QuietPeriodSeconds); - - public int ShutdownTimeoutSeconds { get; set; } = 3; - - public TimeSpan ShutdownTimeoutTimeSpan => TimeSpan.FromSeconds(ShutdownTimeoutSeconds); - - public int SoBacklog { get; set; } = 8192; - - public int EventLoopCount { get; set; } = Environment.ProcessorCount; - - public int ReaderIdleTimeSeconds { get; set; } = 3600; - - public int WriterIdleTimeSeconds { get; set; } = 3600; - - public int AllIdleTimeSeconds { get; set; } = 3600; - - /// - /// 转发远程地址 (可选项)知道转发的地址有利于提升性能 - /// 按照808的消息,有些请求必须要应答,但是转发可以不需要有应答可以节省部分资源包括: - // 1.消息的序列化 - // 2.消息的下发 - // 都有一定的性能损耗,那么不需要判断写超时 IdleState.WriterIdle - // 就跟神兽貔貅一样。。。 - /// - public List ForwardingRemoteIPAddress { get; set; } - } -} diff --git a/src/JT808.Gateway/Dtos/JT808ResultDto.cs b/src/JT808.Gateway/Dtos/JT808ResultDto.cs deleted file mode 100644 index 0b72015..0000000 --- a/src/JT808.Gateway/Dtos/JT808ResultDto.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Dtos -{ - public class JT808ResultDto - { - public JT808ResultDto() - { - Code = JT808ResultCode.Ok; - } - - public string Message { get; set; } - - public int Code { get; set; } - - public T Data { get; set; } - } - - public class JT808ResultCode - { - 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/JT808.Gateway/Dtos/JT808TcpSessionInfoDto.cs b/src/JT808.Gateway/Dtos/JT808TcpSessionInfoDto.cs deleted file mode 100644 index 423381e..0000000 --- a/src/JT808.Gateway/Dtos/JT808TcpSessionInfoDto.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace JT808.Gateway.Dtos -{ - public class JT808TcpSessionInfoDto - { - /// - /// 最后上线时间 - /// - public DateTime LastActiveTime { get; set; } - /// - /// 上线时间 - /// - public DateTime StartTime { get; set; } - /// - /// 终端手机号 - /// - public string TerminalPhoneNo { get; set; } - /// - /// 远程ip地址 - /// - public string RemoteAddressIP { get; set; } - } -} diff --git a/src/JT808.Gateway/Dtos/JT808UdpSessionInfoDto.cs b/src/JT808.Gateway/Dtos/JT808UdpSessionInfoDto.cs deleted file mode 100644 index 9ba9c16..0000000 --- a/src/JT808.Gateway/Dtos/JT808UdpSessionInfoDto.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace JT808.Gateway.Dtos -{ - public class JT808UdpSessionInfoDto - { - /// - /// 最后上线时间 - /// - public DateTime LastActiveTime { get; set; } - /// - /// 上线时间 - /// - public DateTime StartTime { get; set; } - /// - /// 终端手机号 - /// - public string TerminalPhoneNo { get; set; } - /// - /// 远程ip地址 - /// - public string RemoteAddressIP { get; set; } - } -} diff --git a/src/JT808.Gateway/Enums/JT808TransportProtocolType.cs b/src/JT808.Gateway/Enums/JT808TransportProtocolType.cs deleted file mode 100644 index ce9bb9f..0000000 --- a/src/JT808.Gateway/Enums/JT808TransportProtocolType.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Enums -{ - /// - /// 传输协议类型 - /// - public enum JT808TransportProtocolType - { - tcp=1, - udp = 2 - } -} diff --git a/src/JT808.Gateway/Handlers/JT808TcpClientConnectionHandler.cs b/src/JT808.Gateway/Handlers/JT808TcpClientConnectionHandler.cs deleted file mode 100644 index 26ea698..0000000 --- a/src/JT808.Gateway/Handlers/JT808TcpClientConnectionHandler.cs +++ /dev/null @@ -1,96 +0,0 @@ -using DotNetty.Handlers.Timeout; -using DotNetty.Transport.Channels; -using JT808.Gateway.Client; -using JT808.Protocol.MessageBody; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; - -namespace JT808.Gateway.Handlers -{ - /// - /// JT808客户端连接通道处理程序 - /// - public class JT808TcpClientConnectionHandler : ChannelHandlerAdapter - { - private readonly ILogger logger; - private readonly JT808TcpClient jT808TcpClient; - - public JT808TcpClientConnectionHandler( - JT808TcpClient jT808TcpClient) - { - logger = jT808TcpClient.LoggerFactory.CreateLogger(); - this.jT808TcpClient = jT808TcpClient; - } - - /// - /// 通道激活 - /// - /// - public override void ChannelActive(IChannelHandlerContext context) - { - string channelId = context.Channel.Id.AsShortText(); - if (logger.IsEnabled(LogLevel.Debug)) - logger.LogDebug($"<<<{ channelId } Successful client connection to server."); - base.ChannelActive(context); - } - - /// - /// 设备主动断开 - /// - /// - public override void ChannelInactive(IChannelHandlerContext context) - { - string channelId = context.Channel.Id.AsShortText(); - if (logger.IsEnabled(LogLevel.Debug)) - logger.LogDebug($">>>{ channelId } The client disconnects from the server."); - - base.ChannelInactive(context); - } - - /// - /// 服务器主动断开 - /// - /// - /// - public override Task CloseAsync(IChannelHandlerContext context) - { - string channelId = context.Channel.Id.AsShortText(); - if (logger.IsEnabled(LogLevel.Debug)) - logger.LogDebug($"<<<{ channelId } The server disconnects from the client."); - - return base.CloseAsync(context); - } - - public override void ChannelReadComplete(IChannelHandlerContext context)=> context.Flush(); - - /// - /// 超时策略 - /// - /// - /// - public override void UserEventTriggered(IChannelHandlerContext context, object evt) - { - IdleStateEvent idleStateEvent = evt as IdleStateEvent; - if (idleStateEvent != null) - { - if(idleStateEvent.State== IdleState.WriterIdle) - { - string channelId = context.Channel.Id.AsShortText(); - logger.LogInformation($"{idleStateEvent.State.ToString()}>>>{channelId}"); - jT808TcpClient.Send(new JT808_0x0002()); - } - } - base.UserEventTriggered(context, evt); - } - - public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) - { - string channelId = context.Channel.Id.AsShortText(); - logger.LogError(exception,$"{channelId} {exception.Message}" ); - - context.CloseAsync(); - } - } -} - diff --git a/src/JT808.Gateway/Handlers/JT808TcpClientHandler.cs b/src/JT808.Gateway/Handlers/JT808TcpClientHandler.cs deleted file mode 100644 index f619a2b..0000000 --- a/src/JT808.Gateway/Handlers/JT808TcpClientHandler.cs +++ /dev/null @@ -1,31 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Transport.Channels; -using System; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.DependencyInjection; -using JT808.Gateway.Services; -using JT808.Gateway.Client; - -namespace JT808.Gateway.Handlers -{ - /// - /// JT808客户端处理程序 - /// - internal class JT808TcpClientHandler : SimpleChannelInboundHandler - { - private readonly ILogger logger; - private readonly JT808ClientReceiveAtomicCounterService jT808ReceiveAtomicCounterService; - public JT808TcpClientHandler(JT808ClientReceiveAtomicCounterService jT808ReceiveAtomicCounterService,JT808TcpClient jT808TcpClient) - { - logger = jT808TcpClient.LoggerFactory.CreateLogger(); - this.jT808ReceiveAtomicCounterService= jT808ReceiveAtomicCounterService; - } - - protected override void ChannelRead0(IChannelHandlerContext ctx, byte[] msg) - { - if(logger.IsEnabled(LogLevel.Trace)) - logger.LogTrace("accept msg<<<" + ByteBufferUtil.HexDump(msg)); - jT808ReceiveAtomicCounterService.MsgSuccessIncrement(); - } - } -} diff --git a/src/JT808.Gateway/Handlers/JT808TcpConnectionHandler.cs b/src/JT808.Gateway/Handlers/JT808TcpConnectionHandler.cs deleted file mode 100644 index 36f7008..0000000 --- a/src/JT808.Gateway/Handlers/JT808TcpConnectionHandler.cs +++ /dev/null @@ -1,104 +0,0 @@ -using DotNetty.Handlers.Timeout; -using DotNetty.Transport.Channels; -using JT808.Gateway.Session; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; - -namespace JT808.Gateway.Handlers -{ - /// - /// JT808服务通道处理程序 - /// - internal class JT808TcpConnectionHandler : ChannelHandlerAdapter - { - private readonly ILogger logger; - - private readonly JT808SessionManager jT808SessionManager; - - public JT808TcpConnectionHandler( - JT808SessionManager jT808SessionManager, - ILoggerFactory loggerFactory) - { - this.jT808SessionManager = jT808SessionManager; - logger = loggerFactory.CreateLogger(); - } - - /// - /// 通道激活 - /// - /// - public override void ChannelActive(IChannelHandlerContext context) - { - string channelId = context.Channel.Id.AsShortText(); - if (logger.IsEnabled(LogLevel.Debug)) - logger.LogDebug($"<<<{ channelId } Successful client connection to server."); - base.ChannelActive(context); - } - - /// - /// 设备主动断开 - /// - /// - public override void ChannelInactive(IChannelHandlerContext context) - { - string channelId = context.Channel.Id.AsShortText(); - if (logger.IsEnabled(LogLevel.Debug)) - logger.LogDebug($">>>{ channelId } The client disconnects from the server."); - jT808SessionManager.RemoveSessionByChannel(context.Channel); - base.ChannelInactive(context); - } - - /// - /// 服务器主动断开 - /// - /// - /// - public override Task CloseAsync(IChannelHandlerContext context) - { - string channelId = context.Channel.Id.AsShortText(); - if (logger.IsEnabled(LogLevel.Debug)) - logger.LogDebug($"<<<{ channelId } The server disconnects from the client."); - jT808SessionManager.RemoveSessionByChannel(context.Channel); - return base.CloseAsync(context); - } - - public override void ChannelReadComplete(IChannelHandlerContext context)=> context.Flush(); - - /// - /// 超时策略 - /// - /// - /// - public override void UserEventTriggered(IChannelHandlerContext context, object evt) - { - IdleStateEvent idleStateEvent = evt as IdleStateEvent; - if (idleStateEvent != null) - { - if(idleStateEvent.State== IdleState.ReaderIdle) - { - string channelId = context.Channel.Id.AsShortText(); - logger.LogInformation($"{idleStateEvent.State.ToString()}>>>{channelId}"); - // 由于808是设备发心跳,如果很久没有上报数据,那么就由服务器主动关闭连接。 - jT808SessionManager.RemoveSessionByChannel(context.Channel); - context.CloseAsync(); - } - // 按照808的消息,有些请求必须要应答,但是转发可以不需要有应答可以节省部分资源包括: - // 1.消息的序列化 - // 2.消息的下发 - // 都有一定的性能损耗,那么不需要判断写超时 IdleState.WriterIdle - // 就跟神兽貔貅一样。。。 - } - base.UserEventTriggered(context, evt); - } - - public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) - { - string channelId = context.Channel.Id.AsShortText(); - logger.LogError(exception,$"{channelId} {exception.Message}" ); - jT808SessionManager.RemoveSessionByChannel(context.Channel); - context.CloseAsync(); - } - } -} - diff --git a/src/JT808.Gateway/Handlers/JT808TcpServerHandler.cs b/src/JT808.Gateway/Handlers/JT808TcpServerHandler.cs deleted file mode 100644 index 35dda80..0000000 --- a/src/JT808.Gateway/Handlers/JT808TcpServerHandler.cs +++ /dev/null @@ -1,77 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Transport.Channels; -using JT808.Protocol; -using System; -using Microsoft.Extensions.Logging; -using JT808.Protocol.Exceptions; -using JT808.Gateway.Session; -using JT808.Gateway.Services; -using JT808.Gateway.PubSub; -using JT808.Gateway.Enums; - -namespace JT808.Gateway.Handlers -{ - /// - /// JT808服务端处理程序 - /// - internal class JT808TcpServerHandler : SimpleChannelInboundHandler - { - private readonly JT808SessionManager jT808SessionManager; - - private readonly JT808AtomicCounterService jT808AtomicCounterService; - - private readonly ILogger logger; - - private readonly JT808Serializer JT808Serializer; - - private readonly IJT808MsgProducer JT808MsgProducer; - - public JT808TcpServerHandler( - IJT808MsgProducer jT808MsgProducer, - IJT808Config jT808Config, - ILoggerFactory loggerFactory, - JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory, - JT808SessionManager jT808SessionManager) - { - this.jT808SessionManager = jT808SessionManager; - this.JT808MsgProducer = jT808MsgProducer; - this.jT808AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp); - this.JT808Serializer = jT808Config.GetSerializer(); - logger = loggerFactory.CreateLogger(); - } - - protected override void ChannelRead0(IChannelHandlerContext ctx, byte[] msg) - { - try - { - //解析到头部,然后根据具体的消息Id通过队列去进行消费 - //要是一定要解析到数据体可以在JT808MsgIdHandlerBase类中根据具体的消息, - //解析具体的消息体,具体调用JT808Serializer.Deserialize - JT808HeaderPackage jT808HeaderPackage = JT808Serializer.Deserialize(msg); - if (logger.IsEnabled(LogLevel.Trace)) - { - logger.LogTrace($"accept package success count=>{jT808AtomicCounterService.MsgSuccessCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg)}"); - } - jT808AtomicCounterService.MsgSuccessIncrement(); - jT808SessionManager.TryAdd(jT808HeaderPackage.Header.TerminalPhoneNo,ctx.Channel); - JT808MsgProducer.ProduceAsync(jT808HeaderPackage.Header.TerminalPhoneNo, msg); - } - catch (JT808Exception ex) - { - jT808AtomicCounterService.MsgFailIncrement(); - if (logger.IsEnabled(LogLevel.Error)) - { - logger.LogError(ex,$"accept package fail count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg)}"); - } - } - catch (Exception ex) - { - jT808AtomicCounterService.MsgFailIncrement(); - if (logger.IsEnabled(LogLevel.Error)) - { - logger.LogError(ex, $"accept package fail count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg)}"); - } - } - } - } -} diff --git a/src/JT808.Gateway/Handlers/JT808UdpServerHandler.cs b/src/JT808.Gateway/Handlers/JT808UdpServerHandler.cs deleted file mode 100644 index 3ae3972..0000000 --- a/src/JT808.Gateway/Handlers/JT808UdpServerHandler.cs +++ /dev/null @@ -1,79 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Transport.Channels; -using JT808.Protocol; -using System; -using Microsoft.Extensions.Logging; -using JT808.Gateway.Services; -using JT808.Gateway.Session; -using JT808.Gateway.PubSub; -using JT808.Gateway.Metadata; -using JT808.Gateway.Enums; - -namespace JT808.Gateway.Handlers -{ - /// - /// JT808 Udp服务端处理程序 - /// - internal class JT808UdpServerHandler : SimpleChannelInboundHandler - { - private readonly JT808AtomicCounterService jT808AtomicCounterService; - - private readonly ILogger logger; - - private readonly JT808SessionManager jT808UdpSessionManager; - - private readonly JT808Serializer JT808Serializer; - - private readonly IJT808MsgProducer JT808MsgProducer; - - public JT808UdpServerHandler( - IJT808MsgProducer jT808MsgProducer, - IJT808Config jT808Config, - ILoggerFactory loggerFactory, - JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory, - JT808SessionManager jT808UdpSessionManager) - { - this.JT808MsgProducer = jT808MsgProducer; - this.jT808AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.udp); - this.jT808UdpSessionManager = jT808UdpSessionManager; - logger = loggerFactory.CreateLogger(); - JT808Serializer = jT808Config.GetSerializer(); - } - - protected override void ChannelRead0(IChannelHandlerContext ctx, JT808UdpPackage msg) - { - try - { - //解析到头部,然后根据具体的消息Id通过队列去进行消费 - //要是一定要解析到数据体可以在JT808MsgIdHandlerBase类中根据具体的消息, - //解析具体的消息体,具体调用JT808Serializer.Deserialize - JT808HeaderPackage jT808HeaderPackage = JT808Serializer.Deserialize(msg.Buffer); - if (logger.IsEnabled(LogLevel.Trace)) - { - logger.LogTrace($"accept package success count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg.Buffer)}"); - } - jT808AtomicCounterService.MsgSuccessIncrement(); - jT808UdpSessionManager.TryAdd(ctx.Channel, msg.Sender, jT808HeaderPackage.Header.TerminalPhoneNo); - JT808MsgProducer.ProduceAsync(jT808HeaderPackage.Header.TerminalPhoneNo, msg.Buffer); - } - catch (JT808.Protocol.Exceptions.JT808Exception ex) - { - jT808AtomicCounterService.MsgFailIncrement(); - if (logger.IsEnabled(LogLevel.Error)) - { - logger.LogError(ex, $"accept package fail count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg.Buffer)}"); - } - } - catch (Exception ex) - { - jT808AtomicCounterService.MsgFailIncrement(); - if (logger.IsEnabled(LogLevel.Error)) - { - logger.LogError(ex, $"accept package fail count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg.Buffer)}"); - } - } - } - - public override void ChannelReadComplete(IChannelHandlerContext context) => context.Flush(); - } -} diff --git a/src/JT808.Gateway/IJT808ClientBuilder.cs b/src/JT808.Gateway/IJT808ClientBuilder.cs deleted file mode 100644 index e8681b9..0000000 --- a/src/JT808.Gateway/IJT808ClientBuilder.cs +++ /dev/null @@ -1,14 +0,0 @@ -using JT808.Protocol; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway -{ - public interface IJT808ClientBuilder - { - IJT808Builder JT808Builder { get; } - IJT808Builder Builder(); - } -} diff --git a/src/JT808.Gateway/IJT808GatewayBuilder.cs b/src/JT808.Gateway/IJT808GatewayBuilder.cs deleted file mode 100644 index 6160c23..0000000 --- a/src/JT808.Gateway/IJT808GatewayBuilder.cs +++ /dev/null @@ -1,14 +0,0 @@ -using JT808.Protocol; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway -{ - public interface IJT808GatewayBuilder - { - IJT808Builder JT808Builder { get; } - IJT808Builder Builder(); - } -} diff --git a/src/JT808.Gateway/Impls/JT808DatagramPacketImpl.cs b/src/JT808.Gateway/Impls/JT808DatagramPacketImpl.cs deleted file mode 100644 index 12bf62b..0000000 --- a/src/JT808.Gateway/Impls/JT808DatagramPacketImpl.cs +++ /dev/null @@ -1,18 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Transport.Channels.Sockets; -using JT808.Gateway.Interfaces; -using System; -using System.Collections.Generic; -using System.Net; -using System.Text; - -namespace JT808.Gateway.Impls -{ - class JT808DatagramPacketImpl : IJT808DatagramPacket - { - public DatagramPacket Create(byte[] message, EndPoint recipient) - { - return new DatagramPacket(Unpooled.WrappedBuffer(message), recipient); - } - } -} diff --git a/src/JT808.Gateway/Impls/JT808GatewayBuilderDefault.cs b/src/JT808.Gateway/Impls/JT808GatewayBuilderDefault.cs deleted file mode 100644 index d5e79b5..0000000 --- a/src/JT808.Gateway/Impls/JT808GatewayBuilderDefault.cs +++ /dev/null @@ -1,25 +0,0 @@ -using JT808.Gateway; -using JT808.Protocol; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Impls -{ - internal class JT808GatewayBuilderDefault : IJT808GatewayBuilder - { - public IJT808Builder JT808Builder { get; } - - public JT808GatewayBuilderDefault(IJT808Builder builder) - { - JT808Builder = builder; - } - - public IJT808Builder Builder() - { - return JT808Builder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Impls/JT808MsgProducerDefaultImpl.cs b/src/JT808.Gateway/Impls/JT808MsgProducerDefaultImpl.cs deleted file mode 100644 index 6c68938..0000000 --- a/src/JT808.Gateway/Impls/JT808MsgProducerDefaultImpl.cs +++ /dev/null @@ -1,30 +0,0 @@ -using JT808.Gateway; -using JT808.Gateway.PubSub; -using JT808.Gateway.Services; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.Gateway.Impls -{ - internal class JT808MsgProducerDefaultImpl : IJT808MsgProducer - { - private readonly JT808MsgService JT808MsgService; - public string TopicName => JT808GatewayConstants.MsgTopic; - public JT808MsgProducerDefaultImpl(JT808MsgService jT808MsgService) - { - JT808MsgService = jT808MsgService; - } - public void Dispose() - { - - } - - public Task ProduceAsync(string terminalNo, byte[] data) - { - JT808MsgService.MsgQueue.Add((terminalNo, data)); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/Impls/JT808MsgReplyConsumerDefaultImpl.cs b/src/JT808.Gateway/Impls/JT808MsgReplyConsumerDefaultImpl.cs deleted file mode 100644 index ed86362..0000000 --- a/src/JT808.Gateway/Impls/JT808MsgReplyConsumerDefaultImpl.cs +++ /dev/null @@ -1,193 +0,0 @@ -using JT808.Gateway; -using JT808.Gateway.PubSub; -using JT808.Gateway.Services; -using JT808.Protocol; -using JT808.Protocol.Enums; -using JT808.Protocol.Extensions; -using JT808.Protocol.MessageBody; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Impls -{ - internal class JT808MsgReplyConsumerDefaultImpl : IJT808MsgReplyConsumer - { - private readonly JT808MsgService JT808MsgService; - private readonly JT808Serializer JT808Serializer; - private Dictionary> HandlerDict; - public JT808MsgReplyConsumerDefaultImpl( - IJT808Config jT808Config, - JT808MsgService jT808MsgService) - { - JT808MsgService = jT808MsgService; - this.JT808Serializer = jT808Config.GetSerializer(); - HandlerDict = new Dictionary> { - {JT808MsgId.终端通用应答.ToUInt16Value(), Msg0x0001}, - {JT808MsgId.终端鉴权.ToUInt16Value(), Msg0x0102}, - {JT808MsgId.终端心跳.ToUInt16Value(), Msg0x0002}, - {JT808MsgId.终端注销.ToUInt16Value(), Msg0x0003}, - {JT808MsgId.终端注册.ToUInt16Value(), Msg0x0100}, - {JT808MsgId.位置信息汇报.ToUInt16Value(),Msg0x0200 }, - {JT808MsgId.定位数据批量上传.ToUInt16Value(),Msg0x0704 }, - {JT808MsgId.数据上行透传.ToUInt16Value(),Msg0x0900 } - }; - } - public CancellationTokenSource Cts =>new CancellationTokenSource(); - - public string TopicName => JT808GatewayConstants.MsgReplyTopic; - - public void Dispose() - { - Cts.Dispose(); - } - - public void OnMessage(Action<(string TerminalNo, byte[] Data)> callback) - { - Task.Run(() => - { - foreach(var item in JT808MsgService.MsgQueue.GetConsumingEnumerable()) - { - try - { - var package = JT808Serializer.HeaderDeserialize(item.Data); - if (HandlerDict.TryGetValue(package.Header.MsgId, out var func)) - { - var buffer = func(package); - if (buffer != null) - { - callback((item.TerminalNo, buffer)); - } - } - } - catch (Exception ex) - { - - } - } - }, Cts.Token); - } - - public void Subscribe() - { - - } - - public void Unsubscribe() - { - Cts.Cancel(); - } - - /// - /// 终端通用应答 - /// 平台无需回复 - /// 实现自己的业务 - /// - /// - /// - public byte[] Msg0x0001(JT808HeaderPackage request) - { - return null; - } - /// - /// 终端心跳 - /// - /// - /// - public byte[] Msg0x0002(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 终端注销 - /// - /// - /// - public byte[] Msg0x0003(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 终端注册 - /// - /// - /// - public byte[] Msg0x0100(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.终端注册应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8100() - { - Code = "J" + request.Header.TerminalPhoneNo, - JT808TerminalRegisterResult = JT808TerminalRegisterResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 终端鉴权 - /// - /// - /// - public byte[] Msg0x0102(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 位置信息汇报 - /// - /// - /// - public byte[] Msg0x0200(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 定位数据批量上传 - /// - /// - /// - public byte[] Msg0x0704(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 数据上行透传 - /// - /// - /// - public byte[] Msg0x0900(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - } -} diff --git a/src/JT808.Gateway/Impls/JT808SessionProducerDefaultImpl.cs b/src/JT808.Gateway/Impls/JT808SessionProducerDefaultImpl.cs deleted file mode 100644 index 4651d85..0000000 --- a/src/JT808.Gateway/Impls/JT808SessionProducerDefaultImpl.cs +++ /dev/null @@ -1,32 +0,0 @@ -using JT808.Gateway; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; - -namespace JT808.Gateway.Impls -{ - internal class JT808SessionProducerDefaultImpl : IJT808SessionProducer - { - private readonly ILogger logger; - public JT808SessionProducerDefaultImpl(ILoggerFactory loggerFactory) - { - logger = loggerFactory.CreateLogger(); - } - - public string TopicName => JT808GatewayConstants.SessionTopic; - - public void Dispose() - { - - } - - public Task ProduceAsync(string terminalNo, string notice) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug($"{terminalNo}-{notice}"); - } - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/Interfaces/IJT808DatagramPacket.cs b/src/JT808.Gateway/Interfaces/IJT808DatagramPacket.cs deleted file mode 100644 index dcfd9d0..0000000 --- a/src/JT808.Gateway/Interfaces/IJT808DatagramPacket.cs +++ /dev/null @@ -1,13 +0,0 @@ -using DotNetty.Transport.Channels.Sockets; -using System.Net; - -namespace JT808.Gateway.Interfaces -{ - /// - /// 基于udp的创建发送包 - /// - public interface IJT808DatagramPacket - { - DatagramPacket Create(byte[] message, EndPoint recipient); - } -} diff --git a/src/JT808.Gateway/Interfaces/IJT808Reply.cs b/src/JT808.Gateway/Interfaces/IJT808Reply.cs deleted file mode 100644 index d515cd7..0000000 --- a/src/JT808.Gateway/Interfaces/IJT808Reply.cs +++ /dev/null @@ -1,17 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Interfaces -{ - public interface IJT808Reply - { - JT808Package Package { get; set; } - byte[] HexData { get; set; } - /// - /// 根据实际情况适当调整包的大小 - /// - int MinBufferSize { get; set; } - } -} diff --git a/src/JT808.Gateway/Interfaces/IJT808Session.cs b/src/JT808.Gateway/Interfaces/IJT808Session.cs deleted file mode 100644 index 80cae87..0000000 --- a/src/JT808.Gateway/Interfaces/IJT808Session.cs +++ /dev/null @@ -1,20 +0,0 @@ -using DotNetty.Transport.Channels; -using JT808.Gateway.Enums; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Interfaces -{ - public interface IJT808Session - { - /// - /// 终端手机号 - /// - string TerminalPhoneNo { get; set; } - IChannel Channel { get; set; } - DateTime LastActiveTime { get; set; } - DateTime StartTime { get; set; } - JT808TransportProtocolType TransportProtocolType { get; set; } - } -} diff --git a/src/JT808.Gateway/Interfaces/IJT808SessionService.cs b/src/JT808.Gateway/Interfaces/IJT808SessionService.cs deleted file mode 100644 index c8e58e5..0000000 --- a/src/JT808.Gateway/Interfaces/IJT808SessionService.cs +++ /dev/null @@ -1,30 +0,0 @@ -using JT808.Gateway.Dtos; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Interfaces -{ - /// - /// JT808会话服务 - /// - public interface IJT808SessionService - { - /// - /// 获取udp会话集合 - /// - /// - JT808ResultDto> GetUdpAll(); - /// - /// 获取tcp会话集合 - /// - /// - JT808ResultDto> GetTcpAll(); - /// - /// 通过设备终端号移除对应会话 - /// - /// - /// - JT808ResultDto RemoveByTerminalPhoneNo(string terminalPhoneNo); - } -} diff --git a/src/JT808.Gateway/Interfaces/IJT808UnificationSendService.cs b/src/JT808.Gateway/Interfaces/IJT808UnificationSendService.cs deleted file mode 100644 index 227e225..0000000 --- a/src/JT808.Gateway/Interfaces/IJT808UnificationSendService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using JT808.Gateway.Dtos; - -namespace JT808.Gateway.Interfaces -{ - /// - /// JT808统一下发命令服务 - /// - public interface IJT808UnificationSendService - { - JT808ResultDto Send(string terminalPhoneNo, byte[] data); - } -} diff --git a/src/JT808.Gateway/JT808.Gateway.csproj b/src/JT808.Gateway/JT808.Gateway.csproj deleted file mode 100644 index ff7b4aa..0000000 --- a/src/JT808.Gateway/JT808.Gateway.csproj +++ /dev/null @@ -1,45 +0,0 @@ - - - - netstandard2.0 - 8.0 - Copyright 2018. - SmallChi(Koike) - https://github.com/SmallChi/JT808DotNetty - https://github.com/SmallChi/JT808DotNetty - https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE - https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE - false - 1.0.0-preview1 - false - LICENSE - true - JT808.Gateway - JT808.Gateway - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - diff --git a/src/JT808.Gateway/JT808GatewayConstants.cs b/src/JT808.Gateway/JT808GatewayConstants.cs deleted file mode 100644 index b09709a..0000000 --- a/src/JT808.Gateway/JT808GatewayConstants.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace JT808.Gateway -{ - public static class JT808GatewayConstants - { - public const string SessionOnline= "JT808SessionOnline"; - - public const string SessionOffline = "JT808SessionOffline"; - public const string SessionTopic = "jt808session"; - public const string MsgTopic = "jt808msgdefault"; - public const string MsgReplyTopic = "jt808msgreplydefault"; - - public static class JT808WebApiRouteTable - { - public const string RouteTablePrefix = "/jt808api"; - - public const string SessionPrefix = "Session"; - - public const string TcpPrefix = "Tcp"; - - public const string UdpPrefix = "Udp"; - - /// - /// 基于Tcp的包计数器 - /// - public static string GetTcpAtomicCounter = $"{RouteTablePrefix}/{TcpPrefix}/GetAtomicCounter"; - /// - /// 基于Tcp的会话服务集合 - /// - public static string SessionTcpGetAll = $"{RouteTablePrefix}/{TcpPrefix}/{SessionPrefix}/GetAll"; - /// - /// 会话服务-通过设备终端号移除对应会话 - /// - public static string SessionRemoveByTerminalPhoneNo = $"{RouteTablePrefix}/{SessionPrefix}/RemoveByTerminalPhoneNo"; - /// - /// 统一下发信息 - /// - public static string UnificationSend = $"{RouteTablePrefix}/UnificationSend"; - /// - /// 获取Udp包计数器 - /// - public static string GetUdpAtomicCounter = $"{RouteTablePrefix}/{UdpPrefix}/GetAtomicCounter"; - /// - /// 基于Udp的会话服务集合 - /// - public static string SessionUdpGetAll = $"{RouteTablePrefix}/{UdpPrefix}/{SessionPrefix}/GetAll"; - } - } -} diff --git a/src/JT808.Gateway/JT808GatewayExtensions.cs b/src/JT808.Gateway/JT808GatewayExtensions.cs deleted file mode 100644 index 17ed1b0..0000000 --- a/src/JT808.Gateway/JT808GatewayExtensions.cs +++ /dev/null @@ -1,54 +0,0 @@ -using JT808.Gateway; -using JT808.Gateway.Configurations; -using JT808.Gateway.Impls; -using JT808.Gateway.Interfaces; -using JT808.Gateway.PubSub; -using JT808.Gateway.Services; -using JT808.Gateway.Session; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Options; -using System; -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("JT808.Gateway.Test")] - -namespace JT808.Gateway -{ - public static class JT808GatewayExtensions - { - public static IJT808GatewayBuilder AddJT808Gateway(this IJT808Builder jt808Builder, IConfiguration configuration) - { - IJT808GatewayBuilder nettyBuilder = new JT808GatewayBuilderDefault(jt808Builder); - nettyBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808Configuration")); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.AddHostedService(); - return nettyBuilder; - } - - public static IJT808GatewayBuilder AddJT808Gateway(this IJT808Builder jt808Builder, Action jt808Options) - { - IJT808GatewayBuilder nettyBuilder = new JT808GatewayBuilderDefault(jt808Builder); - nettyBuilder.JT808Builder.Services.Configure(jt808Options); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.AddHostedService(); - return nettyBuilder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Metadata/JT808AtomicCounter.cs b/src/JT808.Gateway/Metadata/JT808AtomicCounter.cs deleted file mode 100644 index 6362905..0000000 --- a/src/JT808.Gateway/Metadata/JT808AtomicCounter.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace JT808.Gateway.Metadata -{ - /// - /// - /// - /// - internal class JT808AtomicCounter - { - long counter = 0; - - public JT808AtomicCounter(long initialCount = 0) - { - this.counter = initialCount; - } - - public void Reset() - { - Interlocked.Exchange(ref counter, 0); - } - - public long Increment() - { - return Interlocked.Increment(ref counter); - } - - public long Add(long len) - { - return Interlocked.Add(ref counter,len); - } - - public long Decrement() - { - return Interlocked.Decrement(ref counter); - } - - public long Count - { - get - { - return Interlocked.Read(ref counter); - } - } - } -} diff --git a/src/JT808.Gateway/Metadata/JT808ClientReport.cs b/src/JT808.Gateway/Metadata/JT808ClientReport.cs deleted file mode 100644 index 6896252..0000000 --- a/src/JT808.Gateway/Metadata/JT808ClientReport.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Metadata -{ - public class JT808ClientReport - { - public long SendTotalCount { get; set; } - public long ReceiveTotalCount { get; set; } - public DateTime CurrentDate { get; set; } - public int Connections { get; set; } - public int OnlineConnections { get; set; } - public int OfflineConnections { get; set; } - } -} diff --git a/src/JT808.Gateway/Metadata/JT808ClientRequest.cs b/src/JT808.Gateway/Metadata/JT808ClientRequest.cs deleted file mode 100644 index 9122dcd..0000000 --- a/src/JT808.Gateway/Metadata/JT808ClientRequest.cs +++ /dev/null @@ -1,30 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace JT808.Gateway.Metadata -{ - public class JT808ClientRequest - { - public JT808Package Package { get; } - - public byte[] HexData { get; } - - /// - /// 根据实际情况适当调整包的大小 - /// - public int MinBufferSize { get;} - - public JT808ClientRequest(JT808Package package,int minBufferSize=1024) - { - Package = package; - MinBufferSize = minBufferSize; - } - - public JT808ClientRequest(byte[] hexData) - { - HexData = hexData; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Metadata/JT808HttpRequest.cs b/src/JT808.Gateway/Metadata/JT808HttpRequest.cs deleted file mode 100644 index 8c21e94..0000000 --- a/src/JT808.Gateway/Metadata/JT808HttpRequest.cs +++ /dev/null @@ -1,22 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace JT808.Gateway.Metadata -{ - public class JT808HttpRequest - { - public string Json { get; set; } - - public JT808HttpRequest() - { - - } - - public JT808HttpRequest(string json) - { - Json = json; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Metadata/JT808HttpResponse.cs b/src/JT808.Gateway/Metadata/JT808HttpResponse.cs deleted file mode 100644 index f018dcb..0000000 --- a/src/JT808.Gateway/Metadata/JT808HttpResponse.cs +++ /dev/null @@ -1,22 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace JT808.Gateway.Metadata -{ - public class JT808HttpResponse - { - public byte[] Data { get; set; } - - public JT808HttpResponse() - { - - } - - public JT808HttpResponse(byte[] data) - { - this.Data = data; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Metadata/JT808Request.cs b/src/JT808.Gateway/Metadata/JT808Request.cs deleted file mode 100644 index 5817ed8..0000000 --- a/src/JT808.Gateway/Metadata/JT808Request.cs +++ /dev/null @@ -1,23 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace JT808.Gateway.Metadata -{ - public class JT808Request - { - public JT808HeaderPackage Package { get; } - - /// - /// 用于消息发送 - /// - public byte[] OriginalPackage { get;} - - public JT808Request(JT808HeaderPackage package, byte[] originalPackage) - { - Package = package; - OriginalPackage = originalPackage; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Metadata/JT808Response.cs b/src/JT808.Gateway/Metadata/JT808Response.cs deleted file mode 100644 index 5425f73..0000000 --- a/src/JT808.Gateway/Metadata/JT808Response.cs +++ /dev/null @@ -1,31 +0,0 @@ -using JT808.Gateway.Interfaces; -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace JT808.Gateway.Metadata -{ - public class JT808Response: IJT808Reply - { - public JT808Package Package { get; set; } - public byte[] HexData { get; set; } - public int MinBufferSize { get; set; } - - public JT808Response() - { - - } - - public JT808Response(JT808Package package, int minBufferSize = 1024) - { - Package = package; - MinBufferSize = minBufferSize; - } - - public JT808Response(byte[] hexData) - { - HexData = hexData; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Metadata/JT808TcpSession.cs b/src/JT808.Gateway/Metadata/JT808TcpSession.cs deleted file mode 100644 index dff9d78..0000000 --- a/src/JT808.Gateway/Metadata/JT808TcpSession.cs +++ /dev/null @@ -1,32 +0,0 @@ -using DotNetty.Transport.Channels; -using JT808.Gateway.Enums; -using JT808.Gateway.Interfaces; -using System; - -namespace JT808.Gateway.Metadata -{ - public class JT808TcpSession: IJT808Session - { - public JT808TcpSession(IChannel channel, string terminalPhoneNo) - { - Channel = channel; - TerminalPhoneNo = terminalPhoneNo; - StartTime = DateTime.Now; - LastActiveTime = DateTime.Now; - } - - public JT808TcpSession() { } - - /// - /// 终端手机号 - /// - public string TerminalPhoneNo { get; set; } - - public IChannel Channel { get; set; } - - public DateTime LastActiveTime { get; set; } - - public DateTime StartTime { get; set; } - public JT808TransportProtocolType TransportProtocolType { get; set; } = JT808TransportProtocolType.tcp; - } -} diff --git a/src/JT808.Gateway/Metadata/JT808UdpPackage.cs b/src/JT808.Gateway/Metadata/JT808UdpPackage.cs deleted file mode 100644 index 3f7c4c1..0000000 --- a/src/JT808.Gateway/Metadata/JT808UdpPackage.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Text; - -namespace JT808.Gateway.Metadata -{ - public class JT808UdpPackage - { - public JT808UdpPackage(byte[] buffer, EndPoint sender) - { - Buffer = buffer; - Sender = sender; - } - - public byte[] Buffer { get; } - - public EndPoint Sender { get; } - } -} diff --git a/src/JT808.Gateway/Metadata/JT808UdpSession.cs b/src/JT808.Gateway/Metadata/JT808UdpSession.cs deleted file mode 100644 index b0c60c5..0000000 --- a/src/JT808.Gateway/Metadata/JT808UdpSession.cs +++ /dev/null @@ -1,38 +0,0 @@ -using DotNetty.Transport.Channels; -using JT808.Gateway.Enums; -using JT808.Gateway.Interfaces; -using System; -using System.Net; - -namespace JT808.Gateway.Metadata -{ - public class JT808UdpSession: IJT808Session - { - public JT808UdpSession(IChannel channel, - EndPoint sender, - string terminalPhoneNo) - { - Channel = channel; - TerminalPhoneNo = terminalPhoneNo; - StartTime = DateTime.Now; - LastActiveTime = DateTime.Now; - Sender = sender; - } - - public EndPoint Sender { get; set; } - - public JT808UdpSession() { } - - /// - /// 终端手机号 - /// - public string TerminalPhoneNo { get; set; } - - public IChannel Channel { get; set; } - - public DateTime LastActiveTime { get; set; } - - public DateTime StartTime { get; set; } - public JT808TransportProtocolType TransportProtocolType { get; set; } = JT808TransportProtocolType.udp; - } -} diff --git a/src/JT808.Gateway/Protos/JT808Gateway.proto b/src/JT808.Gateway/Protos/JT808Gateway.proto deleted file mode 100644 index 042fc89..0000000 --- a/src/JT808.Gateway/Protos/JT808Gateway.proto +++ /dev/null @@ -1,63 +0,0 @@ -syntax = "proto3"; - -option csharp_namespace = "JT808.Gateway.GrpcService"; - -package JT808GatewayGrpc; - -service JT808Gateway{ - // 会话服务-获取会话服务集合 - rpc GetTcpSessionAll(Empty) returns (TcpSessionInfoReply); - // 会话服务-通过设备终端号移除对应会话 - rpc RemoveSessionByTerminalPhoneNo(SessionRemoveRequest) returns (SessionRemoveReply); - // 统一下发信息 - rpc UnificationSend(UnificationSendRequest) returns (UnificationSendReply); - // 获取Tcp包计数器 - rpc GetTcpAtomicCounter(Empty) returns (TcpAtomicCounterReply); - // 会话服务-获取会话服务集合 - rpc GetUdpSessionAll(Empty) returns (UdpSessionInfoReply); - // 获取Udp包计数器 - rpc GetUdpAtomicCounter(Empty) returns (UdpAtomicCounterReply); -} - -message Empty{} - -message TcpSessionInfoReply{ - repeated SessionInfo TcpSessions=1; -} -message UdpSessionInfoReply{ - repeated SessionInfo UdpSessions=1; -} - -message SessionInfo{ - string StartTime=1; - string LastActiveTime=2; - string TerminalPhoneNo=3; - string RemoteAddressIP=4; -} - -message SessionRemoveRequest{ - string TerminalPhoneNo=1; -} - -message SessionRemoveReply{ - bool Success = 1; -} - -message UnificationSendRequest{ - string TerminalPhoneNo=1; - bytes Data=2; -} - -message UnificationSendReply{ - bool Success = 1; -} - -message TcpAtomicCounterReply{ - int64 MsgSuccessCount=1; - int64 MsgFailCount=2; -} - -message UdpAtomicCounterReply{ - int64 MsgSuccessCount=1; - int64 MsgFailCount=2; -} \ No newline at end of file diff --git a/src/JT808.Gateway/PubSub/IJT808MsgConsumer.cs b/src/JT808.Gateway/PubSub/IJT808MsgConsumer.cs deleted file mode 100644 index d247c8a..0000000 --- a/src/JT808.Gateway/PubSub/IJT808MsgConsumer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace JT808.Gateway.PubSub -{ - public interface IJT808MsgConsumer : IJT808PubSub, IDisposable - { - void OnMessage(Action<(string TerminalNo, byte[] Data)> callback); - CancellationTokenSource Cts { get; } - void Subscribe(); - void Unsubscribe(); - } -} diff --git a/src/JT808.Gateway/PubSub/IJT808MsgProducer.cs b/src/JT808.Gateway/PubSub/IJT808MsgProducer.cs deleted file mode 100644 index 33cb252..0000000 --- a/src/JT808.Gateway/PubSub/IJT808MsgProducer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.Gateway.PubSub -{ - public interface IJT808MsgProducer : IJT808PubSub, IDisposable - { - /// - /// - /// - /// 设备终端号 - /// 808 hex data - Task ProduceAsync(string terminalNo, byte[] data); - } -} diff --git a/src/JT808.Gateway/PubSub/IJT808MsgReplyConsumer.cs b/src/JT808.Gateway/PubSub/IJT808MsgReplyConsumer.cs deleted file mode 100644 index 3bbe675..0000000 --- a/src/JT808.Gateway/PubSub/IJT808MsgReplyConsumer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace JT808.Gateway.PubSub -{ - public interface IJT808MsgReplyConsumer : IJT808PubSub, IDisposable - { - void OnMessage(Action<(string TerminalNo, byte[] Data)> callback); - CancellationTokenSource Cts { get; } - void Subscribe(); - void Unsubscribe(); - } -} diff --git a/src/JT808.Gateway/PubSub/IJT808MsgReplyProducer.cs b/src/JT808.Gateway/PubSub/IJT808MsgReplyProducer.cs deleted file mode 100644 index 99b7ae3..0000000 --- a/src/JT808.Gateway/PubSub/IJT808MsgReplyProducer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.Gateway.PubSub -{ - public interface IJT808MsgReplyProducer : IJT808PubSub, IDisposable - { - /// - /// - /// - /// 设备终端号 - /// 808 hex data - Task ProduceAsync(string terminalNo, byte[] data); - } -} diff --git a/src/JT808.Gateway/PubSub/IJT808PubSub.cs b/src/JT808.Gateway/PubSub/IJT808PubSub.cs deleted file mode 100644 index 983c205..0000000 --- a/src/JT808.Gateway/PubSub/IJT808PubSub.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.PubSub -{ - public interface IJT808PubSub - { - string TopicName { get; } - } -} diff --git a/src/JT808.Gateway/PubSub/IJT808SessionConsumer.cs b/src/JT808.Gateway/PubSub/IJT808SessionConsumer.cs deleted file mode 100644 index eb3a03e..0000000 --- a/src/JT808.Gateway/PubSub/IJT808SessionConsumer.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace JT808.Gateway.PubSub -{ - /// - /// 会话通知(在线/离线) - /// - public interface IJT808SessionConsumer : IJT808PubSub, IDisposable - { - void OnMessage(Action<(string Notice, string TerminalNo)> callback); - CancellationTokenSource Cts { get; } - void Subscribe(); - void Unsubscribe(); - } -} diff --git a/src/JT808.Gateway/PubSub/IJT808SessionProducer.cs b/src/JT808.Gateway/PubSub/IJT808SessionProducer.cs deleted file mode 100644 index 572cd75..0000000 --- a/src/JT808.Gateway/PubSub/IJT808SessionProducer.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace JT808.Gateway.PubSub -{ - /// - /// 会话通知(在线/离线) - /// - public interface IJT808SessionProducer : IJT808PubSub, IDisposable - { - Task ProduceAsync(string notice,string terminalNo); - } -} diff --git a/src/JT808.Gateway/Services/JT808AtomicCounterService.cs b/src/JT808.Gateway/Services/JT808AtomicCounterService.cs deleted file mode 100644 index cddd31f..0000000 --- a/src/JT808.Gateway/Services/JT808AtomicCounterService.cs +++ /dev/null @@ -1,52 +0,0 @@ -using JT808.Gateway.Metadata; - -namespace JT808.Gateway.Services -{ - /// - /// 计数包服务 - /// - public class JT808AtomicCounterService - { - private readonly JT808AtomicCounter MsgSuccessCounter; - - private readonly JT808AtomicCounter MsgFailCounter; - - public JT808AtomicCounterService() - { - MsgSuccessCounter=new JT808AtomicCounter(); - MsgFailCounter = new JT808AtomicCounter(); - } - - public void Reset() - { - MsgSuccessCounter.Reset(); - MsgFailCounter.Reset(); - } - - public long MsgSuccessIncrement() - { - return MsgSuccessCounter.Increment(); - } - - public long MsgSuccessCount - { - get - { - return MsgSuccessCounter.Count; - } - } - - public long MsgFailIncrement() - { - return MsgFailCounter.Increment(); - } - - public long MsgFailCount - { - get - { - return MsgFailCounter.Count; - } - } - } -} diff --git a/src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs b/src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs deleted file mode 100644 index 087ddcc..0000000 --- a/src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs +++ /dev/null @@ -1,30 +0,0 @@ -using JT808.Gateway.Enums; -using System; -using System.Collections.Concurrent; - -namespace JT808.Gateway.Services -{ - public class JT808AtomicCounterServiceFactory - { - private readonly ConcurrentDictionary cache; - - public JT808AtomicCounterServiceFactory() - { - cache = new ConcurrentDictionary(); - } - - public JT808AtomicCounterService Create(JT808TransportProtocolType type) - { - if(cache.TryGetValue(type,out var service)) - { - return service; - } - else - { - var serviceNew = new JT808AtomicCounterService(); - cache.TryAdd(type, serviceNew); - return serviceNew; - } - } - } -} diff --git a/src/JT808.Gateway/Services/JT808ClientReceiveAtomicCounterService.cs b/src/JT808.Gateway/Services/JT808ClientReceiveAtomicCounterService.cs deleted file mode 100644 index 1239084..0000000 --- a/src/JT808.Gateway/Services/JT808ClientReceiveAtomicCounterService.cs +++ /dev/null @@ -1,35 +0,0 @@ -using JT808.Gateway.Metadata; - -namespace JT808.Gateway.Services -{ - /// - /// 接收计数包服务 - /// - public class JT808ClientReceiveAtomicCounterService - { - private readonly JT808AtomicCounter MsgSuccessCounter; - - public JT808ClientReceiveAtomicCounterService() - { - MsgSuccessCounter=new JT808AtomicCounter(); - } - - public void Reset() - { - MsgSuccessCounter.Reset(); - } - - public long MsgSuccessIncrement() - { - return MsgSuccessCounter.Increment(); - } - - public long MsgSuccessCount - { - get - { - return MsgSuccessCounter.Count; - } - } - } -} diff --git a/src/JT808.Gateway/Services/JT808ClientReportHostedService.cs b/src/JT808.Gateway/Services/JT808ClientReportHostedService.cs deleted file mode 100644 index be63e82..0000000 --- a/src/JT808.Gateway/Services/JT808ClientReportHostedService.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Microsoft.Extensions.Hosting; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Services -{ - public class JT808ClientReportHostedService : IHostedService - { - private readonly JT808ClientReportService jT808ReportService; - private CancellationTokenSource cts = new CancellationTokenSource(); - public JT808ClientReportHostedService(JT808ClientReportService jT808ReportService) - { - this.jT808ReportService = jT808ReportService; - } - public Task StartAsync(CancellationToken cancellationToken) - { - Task.Run(() => - { - while (!cts.IsCancellationRequested) - { - jT808ReportService.Create(); - Thread.Sleep(1000); - //Task.Delay(TimeSpan.FromSeconds(1), cts.Token); - } - }, cts.Token); - return Task.CompletedTask; - } - public Task StopAsync(CancellationToken cancellationToken) - { - cts.Cancel(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/Services/JT808ClientReportService.cs b/src/JT808.Gateway/Services/JT808ClientReportService.cs deleted file mode 100644 index da27f8a..0000000 --- a/src/JT808.Gateway/Services/JT808ClientReportService.cs +++ /dev/null @@ -1,43 +0,0 @@ -using JT808.Gateway.Client; -using JT808.Gateway.Metadata; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace JT808.Gateway.Services -{ - public class JT808ClientReportService - { - private readonly JT808ClientReceiveAtomicCounterService jT808ReceiveAtomicCounterService; - private readonly JT808ClientSendAtomicCounterService jT808SendAtomicCounterService; - private readonly IJT808TcpClientFactory jT808TcpClientFactory; - - public List JT808Reports { get; private set; } - - public JT808ClientReportService( - JT808ClientReceiveAtomicCounterService jT808ReceiveAtomicCounterService, - JT808ClientSendAtomicCounterService jT808SendAtomicCounterService, - IJT808TcpClientFactory jT808TcpClientFactory) - { - this.jT808ReceiveAtomicCounterService = jT808ReceiveAtomicCounterService; - this.jT808SendAtomicCounterService = jT808SendAtomicCounterService; - this.jT808TcpClientFactory = jT808TcpClientFactory; - JT808Reports = new List(); - } - - public void Create() - { - var clients = jT808TcpClientFactory.GetAll(); - JT808Reports.Add(new JT808ClientReport() - { - SendTotalCount= jT808SendAtomicCounterService.MsgSuccessCount, - ReceiveTotalCount= jT808ReceiveAtomicCounterService.MsgSuccessCount, - CurrentDate=DateTime.Now, - Connections= clients.Count, - OnlineConnections= clients.Where(w => w.IsOpen).Count(), - OfflineConnections= clients.Where(w => !w.IsOpen).Count(), - }); - } - } -} diff --git a/src/JT808.Gateway/Services/JT808ClientSendAtomicCounterService.cs b/src/JT808.Gateway/Services/JT808ClientSendAtomicCounterService.cs deleted file mode 100644 index 62b12c4..0000000 --- a/src/JT808.Gateway/Services/JT808ClientSendAtomicCounterService.cs +++ /dev/null @@ -1,35 +0,0 @@ -using JT808.Gateway.Metadata; - -namespace JT808.Gateway.Services -{ - /// - /// 发送计数包服务 - /// - public class JT808ClientSendAtomicCounterService - { - private readonly JT808AtomicCounter MsgSuccessCounter; - - public JT808ClientSendAtomicCounterService() - { - MsgSuccessCounter=new JT808AtomicCounter(); - } - - public void Reset() - { - MsgSuccessCounter.Reset(); - } - - public long MsgSuccessIncrement() - { - return MsgSuccessCounter.Increment(); - } - - public long MsgSuccessCount - { - get - { - return MsgSuccessCounter.Count; - } - } - } -} diff --git a/src/JT808.Gateway/Services/JT808GatewayService.cs b/src/JT808.Gateway/Services/JT808GatewayService.cs deleted file mode 100644 index 9a97d18..0000000 --- a/src/JT808.Gateway/Services/JT808GatewayService.cs +++ /dev/null @@ -1,102 +0,0 @@ -using JT808.Gateway.Interfaces; -using System; -using System.Collections.Generic; -using System.Text; -using JT808.Gateway.Enums; -using JT808.Gateway.GrpcService; -using Grpc.Core; -using System.Threading.Tasks; - -namespace JT808.Gateway.Services -{ - public class JT808GatewayService: JT808Gateway.JT808GatewayBase - { - private readonly JT808AtomicCounterService jT808TcpAtomicCounterService; - - private readonly JT808AtomicCounterService jT808UdpAtomicCounterService; - - private readonly IJT808SessionService jT808SessionService; - - private readonly IJT808UnificationSendService jT808UnificationSendService; - - public JT808GatewayService( - IJT808UnificationSendService jT808UnificationSendService, - IJT808SessionService jT808SessionService, - JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory - ) - { - this.jT808UnificationSendService = jT808UnificationSendService; - this.jT808SessionService = jT808SessionService; - this.jT808TcpAtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp); - this.jT808UdpAtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.udp); - } - - public override Task GetTcpSessionAll(Empty request, ServerCallContext context) - { - var result = jT808SessionService.GetTcpAll(); - TcpSessionInfoReply reply = new TcpSessionInfoReply(); - if (result.Data != null) - { - foreach (var item in result.Data) - { - reply.TcpSessions.Add(new SessionInfo - { - LastActiveTime = item.LastActiveTime.ToString("yyyy-MM-dd HH:mm:ss"), - StartTime = item.StartTime.ToString("yyyy-MM-dd HH:mm:ss"), - RemoteAddressIP = item.RemoteAddressIP, - TerminalPhoneNo = item.TerminalPhoneNo - }); - } - } - return Task.FromResult(reply); - } - - public override Task RemoveSessionByTerminalPhoneNo(SessionRemoveRequest request, ServerCallContext context) - { - var result = jT808SessionService.RemoveByTerminalPhoneNo(request.TerminalPhoneNo); - return Task.FromResult(new SessionRemoveReply { Success = result.Data }); - } - - public override Task GetUdpSessionAll(Empty request, ServerCallContext context) - { - var result = jT808SessionService.GetUdpAll(); - UdpSessionInfoReply reply = new UdpSessionInfoReply(); - if (result.Data != null) - { - foreach (var item in result.Data) - { - reply.UdpSessions.Add(new SessionInfo - { - LastActiveTime = item.LastActiveTime.ToString("yyyy-MM-dd HH:mm:ss"), - StartTime = item.StartTime.ToString("yyyy-MM-dd HH:mm:ss"), - RemoteAddressIP = item.RemoteAddressIP, - TerminalPhoneNo = item.TerminalPhoneNo - }); - } - } - return Task.FromResult(reply); - } - - public override Task UnificationSend(UnificationSendRequest request, ServerCallContext context) - { - var result = jT808UnificationSendService.Send(request.TerminalPhoneNo, request.Data.ToByteArray()); - return Task.FromResult(new UnificationSendReply { Success = result.Data }); - } - - public override Task GetTcpAtomicCounter(Empty request, ServerCallContext context) - { - TcpAtomicCounterReply reply = new TcpAtomicCounterReply(); - reply.MsgFailCount=jT808TcpAtomicCounterService.MsgFailCount; - reply.MsgSuccessCount=jT808TcpAtomicCounterService.MsgSuccessCount; - return Task.FromResult(reply); - } - - public override Task GetUdpAtomicCounter(Empty request, ServerCallContext context) - { - UdpAtomicCounterReply reply = new UdpAtomicCounterReply(); - reply.MsgFailCount = jT808UdpAtomicCounterService.MsgFailCount; - reply.MsgSuccessCount = jT808UdpAtomicCounterService.MsgSuccessCount; - return Task.FromResult(reply); - } - } -} diff --git a/src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs b/src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs deleted file mode 100644 index ccb3030..0000000 --- a/src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs +++ /dev/null @@ -1,42 +0,0 @@ -using JT808.Gateway.PubSub; -using JT808.Gateway.Session; -using Microsoft.Extensions.Hosting; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Services -{ - internal class JT808MsgReplyHostedService : IHostedService - { - private readonly JT808SessionManager JT808SessionManager; - - private readonly IJT808MsgReplyConsumer JT808MsgReplyConsumer; - - public JT808MsgReplyHostedService( - IJT808MsgReplyConsumer jT808MsgReplyConsumer, - JT808SessionManager jT808SessionManager) - { - JT808MsgReplyConsumer = jT808MsgReplyConsumer; - JT808SessionManager = jT808SessionManager; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - JT808MsgReplyConsumer.OnMessage(item => - { - JT808SessionManager.Send(item.TerminalNo, item.Data); - }); - JT808MsgReplyConsumer.Subscribe(); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - JT808MsgReplyConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/Services/JT808MsgService.cs b/src/JT808.Gateway/Services/JT808MsgService.cs deleted file mode 100644 index 68c1b96..0000000 --- a/src/JT808.Gateway/Services/JT808MsgService.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Services -{ - internal class JT808MsgService - { - public System.Collections.Concurrent.BlockingCollection<(string TerminalNo, byte[] Data)> MsgQueue { get; set; } = new System.Collections.Concurrent.BlockingCollection<(string TerminalNo, byte[] Data)>(); - } -} diff --git a/src/JT808.Gateway/Services/JT808SessionService.cs b/src/JT808.Gateway/Services/JT808SessionService.cs deleted file mode 100644 index f2ecb8c..0000000 --- a/src/JT808.Gateway/Services/JT808SessionService.cs +++ /dev/null @@ -1,98 +0,0 @@ -using JT808.Gateway.Dtos; -using JT808.Gateway.Interfaces; -using JT808.Gateway.Session; -using System; -using System.Collections.Generic; -using System.Linq; - - -namespace JT808.Gateway.Services -{ - internal class JT808SessionService : IJT808SessionService - { - private readonly JT808SessionManager jT808SessionManager; - - public JT808SessionService( - JT808SessionManager jT808SessionManager) - { - this.jT808SessionManager = jT808SessionManager; - } - - public JT808ResultDto> GetTcpAll() - { - JT808ResultDto> resultDto = new JT808ResultDto>(); - try - { - resultDto.Data = jT808SessionManager.GetAll().Select(s => new JT808TcpSessionInfoDto - { - LastActiveTime = s.LastActiveTime, - StartTime = s.StartTime, - TerminalPhoneNo = s.TerminalPhoneNo, - RemoteAddressIP = s.Channel.RemoteAddress.ToString(), - }).ToList(); - resultDto.Code = JT808ResultCode.Ok; - } - catch (Exception ex) - { - resultDto.Data = null; - resultDto.Code = JT808ResultCode.Error; - resultDto.Message =ex.Message; - } - return resultDto; - } - - public JT808ResultDto> GetUdpAll() - { - JT808ResultDto> resultDto = new JT808ResultDto>(); - try - { - resultDto.Data = jT808SessionManager.GetUdpAll().Select(s => new JT808UdpSessionInfoDto - { - LastActiveTime = s.LastActiveTime, - StartTime = s.StartTime, - TerminalPhoneNo = s.TerminalPhoneNo, - RemoteAddressIP = s.Sender.ToString() - }).ToList(); - resultDto.Code = JT808ResultCode.Ok; - } - catch (Exception ex) - { - resultDto.Data = null; - resultDto.Code = JT808ResultCode.Error; - resultDto.Message = ex.Message; - } - return resultDto; - } - - public JT808ResultDto RemoveByTerminalPhoneNo(string terminalPhoneNo) - { - JT808ResultDto resultDto = new JT808ResultDto(); - try - { - var session = jT808SessionManager.RemoveSession(terminalPhoneNo); - if (session != null) - { - if(session.Channel.Open) - { - session.Channel.CloseAsync(); - } - } - resultDto.Code = JT808ResultCode.Ok; - resultDto.Data = true; - } - catch (AggregateException ex) - { - resultDto.Data = false; - resultDto.Code = 500; - resultDto.Message = ex.Message; - } - catch (Exception ex) - { - resultDto.Data = false; - resultDto.Code = JT808ResultCode.Error; - resultDto.Message = ex.Message; - } - return resultDto; - } - } -} diff --git a/src/JT808.Gateway/Services/JT808UnificationSendService.cs b/src/JT808.Gateway/Services/JT808UnificationSendService.cs deleted file mode 100644 index d7d54e3..0000000 --- a/src/JT808.Gateway/Services/JT808UnificationSendService.cs +++ /dev/null @@ -1,45 +0,0 @@ -using JT808.Gateway.Dtos; -using JT808.Gateway.Interfaces; -using JT808.Gateway.Session; -using System; - -namespace JT808.Gateway.Services -{ - internal class JT808UnificationSendService : IJT808UnificationSendService - { - private readonly JT808SessionManager jT808SessionManager; - - public JT808UnificationSendService( - JT808SessionManager jT808SessionManager) - { - this.jT808SessionManager = jT808SessionManager; - } - - public JT808ResultDto Send(string terminalPhoneNo, byte[] data) - { - JT808ResultDto resultDto = new JT808ResultDto(); - try - { - if(jT808SessionManager.TrySend(terminalPhoneNo, data, out var message)) - { - resultDto.Code = JT808ResultCode.Ok; - resultDto.Data = true; - resultDto.Message = message; - } - else - { - resultDto.Code = JT808ResultCode.Ok; - resultDto.Data = false; - resultDto.Message = message; - } - } - catch (Exception ex) - { - resultDto.Data = false; - resultDto.Code = JT808ResultCode.Error; - resultDto.Message = ex.Message; - } - return resultDto; - } - } -} diff --git a/src/JT808.Gateway/Session/JT808SessionManager.cs b/src/JT808.Gateway/Session/JT808SessionManager.cs deleted file mode 100644 index d5cf82f..0000000 --- a/src/JT808.Gateway/Session/JT808SessionManager.cs +++ /dev/null @@ -1,304 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Transport.Channels; -using JT808.Gateway.Enums; -using JT808.Gateway.Interfaces; -using JT808.Gateway.Metadata; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; - -namespace JT808.Gateway.Session -{ - public class JT808SessionManager - { - private readonly ILogger logger; - - private readonly IJT808DatagramPacket jT808DatagramPacket; - public IJT808SessionProducer JT808SessionProducer { get; } - - public ConcurrentDictionary Sessions { get; } - - public JT808SessionManager( - IJT808SessionProducer jT808SessionProducer, - ILoggerFactory loggerFactory - ) - { - Sessions = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - JT808SessionProducer = jT808SessionProducer; - logger = loggerFactory.CreateLogger(); - } - - public JT808SessionManager( - IJT808SessionProducer jT808SessionProducer, - ILoggerFactory loggerFactory, - IJT808DatagramPacket jT808DatagramPacket) - { - Sessions = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - JT808SessionProducer = jT808SessionProducer; - logger = loggerFactory.CreateLogger(); - this.jT808DatagramPacket = jT808DatagramPacket; - } - - public int SessionCount - { - get - { - return Sessions.Count; - } - } - public IJT808Session GetSessionByTerminalPhoneNo(string terminalPhoneNo) - { - if (string.IsNullOrEmpty(terminalPhoneNo)) - return default; - if (Sessions.TryGetValue(terminalPhoneNo, out IJT808Session targetSession)) - { - return targetSession; - } - else - { - return default; - } - } - public JT808TcpSession GetTcpSessionByTerminalPhoneNo(string terminalPhoneNo) - { - return (JT808TcpSession)GetSessionByTerminalPhoneNo(terminalPhoneNo); - } - public JT808UdpSession GetUdpSessionByTerminalPhoneNo(string terminalPhoneNo) - { - return (JT808UdpSession)GetSessionByTerminalPhoneNo(terminalPhoneNo); - } - public void Heartbeat(string terminalPhoneNo) - { - if (string.IsNullOrEmpty(terminalPhoneNo)) return; - if (Sessions.TryGetValue(terminalPhoneNo, out IJT808Session oldjT808Session)) - { - oldjT808Session.LastActiveTime = DateTime.Now; - Sessions.TryUpdate(terminalPhoneNo, oldjT808Session, oldjT808Session); - } - } - public bool TrySend(string terminalPhoneNo, byte[] data, out string message) - { - bool isSuccessed; - var session = GetSessionByTerminalPhoneNo(terminalPhoneNo); - if (session != null) - { - //判断转发数据是下发不了消息的 - if (Sessions.Select(s => s.Value).Count(c => c.Channel.Id == session.Channel.Id) > 1) - { - isSuccessed = false; - message = "not support transmit data send."; - } - else - { - if(session.TransportProtocolType== JT808TransportProtocolType.tcp) - { - session.Channel.WriteAndFlushAsync(Unpooled.WrappedBuffer(data)); - isSuccessed = true; - message = "ok"; - } - else if (session.TransportProtocolType == JT808TransportProtocolType.udp) - { - isSuccessed = true; - message = "ok"; - session.Channel.WriteAndFlushAsync(jT808DatagramPacket.Create(data, ((JT808UdpSession)session).Sender)); - } - else - { - isSuccessed = false; - message = "unknow type"; - } - } - } - else - { - isSuccessed = false; - message = "offline"; - } - return isSuccessed; - } - internal void Send(string terminalPhoneNo, byte[] data) - { - var session = GetSessionByTerminalPhoneNo(terminalPhoneNo); - if (session != null) - { - if (session.TransportProtocolType == JT808TransportProtocolType.tcp) - { - session.Channel.WriteAndFlushAsync(Unpooled.WrappedBuffer(data)); - } - else if (session.TransportProtocolType == JT808TransportProtocolType.udp) - { - session.Channel.WriteAndFlushAsync(jT808DatagramPacket.Create(data, ((JT808UdpSession)session).Sender)); - } - } - } - public bool TrySend(string terminalPhoneNo, IJT808Reply reply, out string message) - { - bool isSuccessed; - var session = GetSessionByTerminalPhoneNo(terminalPhoneNo); - if (session != null) - { - //判断转发数据是下发不了消息的 - if (Sessions.Select(s => s.Value).Count(c => c.Channel.Id == session.Channel.Id) > 1) - { - isSuccessed = false; - message = "not support transmit data send."; - } - else - { - if (session.TransportProtocolType == JT808TransportProtocolType.tcp) - { - isSuccessed = true; - message = "ok"; - session.Channel.WriteAndFlushAsync(reply); - } - else if (session.TransportProtocolType == JT808TransportProtocolType.udp) - { - isSuccessed = true; - message = "ok"; - session.Channel.WriteAndFlushAsync(jT808DatagramPacket.Create(reply.HexData, ((JT808UdpSession)session).Sender)); - } - else - { - isSuccessed = false; - message = "unknow type"; - } - } - } - else - { - isSuccessed = false; - message = "offline"; - } - return isSuccessed; - } - public void TryAdd(string terminalPhoneNo, IChannel channel) - { - // 解决了设备号跟通道绑定到一起,不需要用到通道本身的SessionId - // 不管设备下发更改了设备终端号,只要是没有在内存中就当是新的 - // 存在的问题: - // 1.原先老的如何销毁 - // 2.这时候用的通道是相同的,设备终端是不同的 - // 当设备主动或者服务器断开以后,可以释放,这点内存忽略不计,况且更改设备号不是很频繁。 - - //修复第一次通过转发过来的数据,再次通过直连后通道没有改变导致下发不成功,所以每次进行通道的更新操作。 - if (Sessions.TryGetValue(terminalPhoneNo, out IJT808Session oldJT808Session)) - { - oldJT808Session.LastActiveTime = DateTime.Now; - oldJT808Session.Channel = channel; - Sessions.TryUpdate(terminalPhoneNo, oldJT808Session, oldJT808Session); - } - else - { - JT808TcpSession jT808TcpSession = new JT808TcpSession(channel, terminalPhoneNo); - if (Sessions.TryAdd(terminalPhoneNo, jT808TcpSession)) - { - //使用场景: - //部标的超长待机设备,不会像正常的设备一样一直连着,可能10几分钟连上了,然后发完就关闭连接, - //这时候想下发数据需要知道设备什么时候上线,在这边做通知最好不过了。 - //有设备关联上来可以进行通知 例如:使用Redis发布订阅 - JT808SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOnline,jT808TcpSession.TerminalPhoneNo); - } - } - } - public void TryAdd(IChannel channel, EndPoint sender, string terminalPhoneNo) - { - //1.先判断是否在缓存里面 - if (Sessions.TryGetValue(terminalPhoneNo, out IJT808Session jT808UdpSession)) - { - if(jT808UdpSession is JT808UdpSession convertSession) - { - convertSession.LastActiveTime = DateTime.Now; - convertSession.Sender = sender; - convertSession.Channel = channel; - Sessions.TryUpdate(terminalPhoneNo, convertSession, convertSession); - } - } - else - { - //添加缓存 - //使用场景: - //部标的超长待机设备,不会像正常的设备一样一直连着,可能10几分钟连上了,然后发完就关闭连接, - //这时候想下发数据需要知道设备什么时候上线,在这边做通知最好不过了。 - //有设备关联上来可以进行通知 例如:使用Redis发布订阅 - Sessions.TryAdd(terminalPhoneNo, new JT808UdpSession(channel, sender, terminalPhoneNo)); - } - //移动是个大的内网,不跟随下发,根本就发不出来 - //移动很多卡,存储的那个socket地址端口,有效期非常短 - //不速度快点下发,那个socket地址端口就可能映射到别的对应卡去了 - //所以此处采用跟随设备消息下发指令 - JT808SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOnline,terminalPhoneNo); - } - public IJT808Session RemoveSession(string terminalPhoneNo) - { - //设备离线可以进行通知 - //使用Redis 发布订阅 - if (string.IsNullOrEmpty(terminalPhoneNo)) return default; - if (!Sessions.TryGetValue(terminalPhoneNo, out IJT808Session jT808Session)) - { - return default; - } - // 处理转发过来的是数据 这时候通道对设备是1对多关系,需要清理垃圾数据 - //1.用当前会话的通道Id找出通过转发过来的其他设备的终端号 - var terminalPhoneNos = Sessions.Where(w => w.Value.Channel.Id == jT808Session.Channel.Id).Select(s => s.Key).ToList(); - //2.存在则一个个移除 - if (terminalPhoneNos.Count > 1) - { - //3.移除包括当前的设备号 - foreach (var key in terminalPhoneNos) - { - Sessions.TryRemove(key, out IJT808Session jT808SessionRemove); - } - string nos = string.Join(",", terminalPhoneNos); - logger.LogInformation($">>>{terminalPhoneNo}-{nos} 1-n Session Remove."); - JT808SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOffline, nos); - return jT808Session; - } - else - { - if (Sessions.TryRemove(terminalPhoneNo, out IJT808Session jT808SessionRemove)) - { - logger.LogInformation($">>>{terminalPhoneNo} Session Remove."); - JT808SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOffline, terminalPhoneNo); - return jT808SessionRemove; - } - else - { - return default; - } - } - } - public void RemoveSessionByChannel(IChannel channel) - { - //设备离线可以进行通知 - //使用Redis 发布订阅 - var terminalPhoneNos = Sessions.Where(w => w.Value.Channel.Id == channel.Id).Select(s => s.Key).ToList(); - if (terminalPhoneNos.Count > 0) - { - foreach (var key in terminalPhoneNos) - { - Sessions.TryRemove(key, out IJT808Session jT808SessionRemove); - } - string nos = string.Join(",", terminalPhoneNos); - logger.LogInformation($">>>{nos} Channel Remove."); - JT808SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOffline, nos); - } - } - public IEnumerable GetAll() - { - return Sessions.Select(s => s.Value).ToList(); - } - public IEnumerable GetTcpAll() - { - return Sessions.Select(s => (JT808TcpSession)s.Value).Where(w => w.TransportProtocolType == JT808TransportProtocolType.tcp).ToList(); - } - public IEnumerable GetUdpAll() - { - return Sessions.Select(s => (JT808UdpSession)s.Value).Where(w => w.TransportProtocolType == JT808TransportProtocolType.udp).ToList(); - } - } -} diff --git a/src/JT808.Gateway/Simples/JT808SimpleTcpClient.cs b/src/JT808.Gateway/Simples/JT808SimpleTcpClient.cs deleted file mode 100644 index 34102ed..0000000 --- a/src/JT808.Gateway/Simples/JT808SimpleTcpClient.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Diagnostics; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Simples -{ - internal class JT808SimpleTcpClient - { - private TcpClient tcpClient; - - public JT808SimpleTcpClient(IPEndPoint remoteAddress) - { - tcpClient = new TcpClient(); - tcpClient.Connect(remoteAddress); - Task.Run(()=> { - while (true) - { - try - { - byte[] buffer = new byte[100]; - tcpClient.GetStream().Read(buffer, 0, 100); - Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " " + string.Join(" ", buffer)); - - } - catch - { - - - } - Thread.Sleep(1000); - } - }); - } - - - - public void WriteAsync(byte[] data) - { - tcpClient.GetStream().WriteAsync(data, 0, data.Length); - } - - public void Down() - { - tcpClient.Close(); - } - } -} diff --git a/src/JT808.Gateway/Simples/JT808SimpleUdpClient.cs b/src/JT808.Gateway/Simples/JT808SimpleUdpClient.cs deleted file mode 100644 index 67c3111..0000000 --- a/src/JT808.Gateway/Simples/JT808SimpleUdpClient.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Diagnostics; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Simples -{ - internal class JT808SimpleUdpClient - { - private UdpClient udpClient; - - public JT808SimpleUdpClient(IPEndPoint remoteAddress) - { - udpClient = new UdpClient(); - udpClient.Connect(remoteAddress); - Task.Run(() => - { - while (true) - { - try - { - string tmp = string.Join(" ", udpClient.Receive(ref remoteAddress)); - Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " " + tmp); - Thread.Sleep(1000); - } - catch - { - - - } - Thread.Sleep(1000); - } - }); - } - - public void WriteAsync(byte[] data) - { - udpClient.SendAsync(data, data.Length); - } - - public void Down() - { - udpClient.Close(); - } - } -} diff --git a/src/JT808.Gateway/Tcp/JT808TcpDotnettyExtensions.cs b/src/JT808.Gateway/Tcp/JT808TcpDotnettyExtensions.cs deleted file mode 100644 index bf513eb..0000000 --- a/src/JT808.Gateway/Tcp/JT808TcpDotnettyExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using JT808.Gateway.Codecs; -using JT808.Gateway.Handlers; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using System.Runtime.CompilerServices; - -namespace JT808.Gateway.Tcp -{ - public static class JT808TcpDotnettyExtensions - { - public static IJT808GatewayBuilder AddJT808GatewayTcpHost(this IJT808GatewayBuilder jT808NettyBuilder) - { - jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.AddHostedService(); - return jT808NettyBuilder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Tcp/JT808TcpServerHost.cs b/src/JT808.Gateway/Tcp/JT808TcpServerHost.cs deleted file mode 100644 index 3134eaf..0000000 --- a/src/JT808.Gateway/Tcp/JT808TcpServerHost.cs +++ /dev/null @@ -1,95 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using DotNetty.Handlers.Timeout; -using DotNetty.Transport.Bootstrapping; -using DotNetty.Transport.Channels; -using DotNetty.Transport.Libuv; -using JT808.Gateway.Codecs; -using JT808.Gateway.Configurations; -using JT808.Gateway.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.Gateway.Tcp -{ - /// - /// JT808 Tcp网关服务 - /// - internal class JT808TcpServerHost : IHostedService - { - private readonly IServiceProvider serviceProvider; - private readonly JT808Configuration configuration; - private readonly ILogger logger; - private DispatcherEventLoopGroup bossGroup; - private WorkerEventLoopGroup workerGroup; - private IChannel bootstrapChannel; - private IByteBufferAllocator serverBufferAllocator; - - public JT808TcpServerHost( - 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, configuration.EventLoopCount); - serverBufferAllocator = new PooledByteBufferAllocator(); - 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, configuration.SoBacklog) - .ChildOption(ChannelOption.Allocator, serverBufferAllocator) - .ChildHandler(new ActionChannelInitializer(channel => - { - IChannelPipeline pipeline = channel.Pipeline; - using (var scope = serviceProvider.CreateScope()) - { - channel.Pipeline.AddLast("jt808TcpBuffer", new DelimiterBasedFrameDecoder(int.MaxValue, - Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), - Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); - channel.Pipeline.AddLast("jt808TcpDecode", scope.ServiceProvider.GetRequiredService()); - channel.Pipeline.AddLast("jt808TcpEncode", scope.ServiceProvider.GetRequiredService()); - channel.Pipeline.AddLast("systemIdleState", new IdleStateHandler( - configuration.ReaderIdleTimeSeconds, - configuration.WriterIdleTimeSeconds, - configuration.AllIdleTimeSeconds)); - channel.Pipeline.AddLast("jt808TcpConnection", scope.ServiceProvider.GetRequiredService()); - channel.Pipeline.AddLast("jt808TcpService", scope.ServiceProvider.GetRequiredService()); - } - })); - logger.LogInformation($"JT808 TCP Server start at {IPAddress.Any}:{configuration.TcpPort}."); - return bootstrap.BindAsync(configuration.TcpPort) - .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.Gateway/Udp/JT808UdpDotnettyExtensions.cs b/src/JT808.Gateway/Udp/JT808UdpDotnettyExtensions.cs deleted file mode 100644 index 554eaf4..0000000 --- a/src/JT808.Gateway/Udp/JT808UdpDotnettyExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -using JT808.Gateway.Codecs; -using JT808.Gateway.Handlers; -using JT808.Gateway.Impls; -using JT808.Gateway.Interfaces; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using System.Runtime.CompilerServices; - -namespace JT808.Gateway.Udp -{ - public static class JT808UdpDotnettyExtensions - { - public static IJT808GatewayBuilder AddJT808GatewayUdpHost(this IJT808GatewayBuilder jT808NettyBuilder) - { - jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); - jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.AddHostedService(); - return jT808NettyBuilder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Udp/JT808UdpServerHost.cs b/src/JT808.Gateway/Udp/JT808UdpServerHost.cs deleted file mode 100644 index 3e1636e..0000000 --- a/src/JT808.Gateway/Udp/JT808UdpServerHost.cs +++ /dev/null @@ -1,76 +0,0 @@ -using DotNetty.Transport.Bootstrapping; -using DotNetty.Transport.Channels; -using DotNetty.Transport.Channels.Sockets; -using JT808.Gateway.Codecs; -using JT808.Gateway.Configurations; -using JT808.Gateway.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.Gateway.Udp -{ - /// - /// JT808 Udp网关服务 - /// - internal class JT808UdpServerHost : IHostedService - { - private readonly IServiceProvider serviceProvider; - private readonly JT808Configuration configuration; - private readonly ILogger logger; - private MultithreadEventLoopGroup group; - private IChannel bootstrapChannel; - - public JT808UdpServerHost( - IServiceProvider provider, - ILoggerFactory loggerFactory, - IOptions jT808ConfigurationAccessor) - { - serviceProvider = provider; - configuration = jT808ConfigurationAccessor.Value; - logger=loggerFactory.CreateLogger(); - } - - public Task StartAsync(CancellationToken cancellationToken) - { - group = new MultithreadEventLoopGroup(); - Bootstrap bootstrap = new Bootstrap(); - bootstrap.Group(group); - bootstrap.Channel(); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) - || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - bootstrap - .Option(ChannelOption.SoReuseport, true); - } - bootstrap - .Option(ChannelOption.SoBroadcast, true) - .Handler(new ActionChannelInitializer(channel => - { - IChannelPipeline pipeline = channel.Pipeline; - using (var scope = serviceProvider.CreateScope()) - { - pipeline.AddLast("jt808UdpDecoder", scope.ServiceProvider.GetRequiredService()); - pipeline.AddLast("jt808UdpService", scope.ServiceProvider.GetRequiredService()); - } - })); - logger.LogInformation($"JT808 Udp Server start at {IPAddress.Any}:{configuration.UdpPort}."); - return bootstrap.BindAsync(configuration.UdpPort) - .ContinueWith(i => bootstrapChannel = i.Result); - } - - public async Task StopAsync(CancellationToken cancellationToken) - { - await bootstrapChannel.CloseAsync(); - var quietPeriod = configuration.QuietPeriodTimeSpan; - var shutdownTimeout = configuration.ShutdownTimeoutTimeSpan; - await group.ShutdownGracefullyAsync(quietPeriod, shutdownTimeout); - } - } -}