From b4ea22c52eba3aea0ea66d2b6c0e14ee99652245 Mon Sep 17 00:00:00 2001 From: smallchi <564952747@qq.com> Date: Tue, 3 Sep 2019 18:34:24 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=A2=9E=E5=8A=A0=E6=B6=88=E6=81=AF=E4=B8=8A?= =?UTF-8?q?=E4=B8=8B=E8=A1=8C=E6=97=A5=E5=BF=97=E6=9C=8D=E5=8A=A1=202.?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AE=BE=E5=A4=87=E4=BC=9A=E8=AF=9D=E9=80=9A?= =?UTF-8?q?=E7=9F=A5=E6=9C=8D=E5=8A=A1=203.=E5=A2=9E=E5=8A=A0=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E6=B5=81=E9=87=8F=E7=BB=9F=E8=AE=A1=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=204.=E5=AE=8C=E5=96=84=E6=95=B0=E6=8D=AE=E8=BD=AC=E5=8F=91?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=205.=E5=A2=9E=E5=8A=A0=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E5=BA=94=E7=AD=94=E6=9C=8D=E5=8A=A1=206.=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E4=B8=9A=E5=8A=A1=E5=A4=84=E7=90=86=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/img/design_model.png | Bin 56916 -> 59323 bytes .../JT808.DotNetty.SimpleClient/Program.cs | 4 +- src/JT808.DotNetty.CleintBenchmark/Program.cs | 4 +- .../JT808ClientDotnettyExtensions.cs | 15 +- .../Session/JT808SessionManager.cs | 9 +- .../JT808ClientBuilderDefault.cs | 25 +++ .../JT808ClientKafkaExtensions.cs | 29 +-- src/JT808.DotNetty.Kafka/JT808MsgConsumer.cs | 3 - .../JT808MsgReplyConsumer.cs | 3 - .../JT808SessionConsumer.cs | 3 - .../JT808.DotNetty.MsgIdHandler.Test.csproj | 8 + .../Program.cs | 12 ++ .../JT808.DotNetty.MsgLogging.Test.csproj | 8 + .../JT808.DotNetty.MsgLogging.Test/Program.cs | 12 ++ .../JT808.DotNetty.ReplyMessage.Test.csproj | 8 + .../Program.cs | 12 ++ .../JT808.DotNetty.SessionNotice.Test.csproj | 8 + .../Program.cs | 12 ++ .../JT808.DotNetty.Traffic.Test.csproj | 8 + .../JT808.DotNetty.Traffic.Test/Program.cs | 12 ++ .../JT808.DotNetty.Transmit.Test.csproj | 8 + .../JT808.DotNetty.Transmit.Test/Program.cs | 12 ++ .../IJT808DotNettyMsgIdHandler.cs | 14 ++ .../IJT808DotNettyMsgIdHandlerExtensions.cs | 19 ++ .../JT808.DotNetty.MsgIdHandler.csproj | 25 +++ .../JT808DotNettyMsgIdHandlerHostedService.cs | 34 ++++ .../IJT808MsgLogging.cs | 15 ++ .../JT808.DotNetty.MsgLogging.csproj | 25 +++ ...T808DotNettyMsgDownLoggingHostedService.cs | 36 ++++ .../JT808DotNettyMsgLoggingExtensions.cs | 20 +++ .../JT808DotNettyMsgUpLoggingHostedService.cs | 36 ++++ .../JT808MsgLoggingType.cs | 18 ++ .../JT808.DotNetty.ReplyMessage.csproj | 24 +++ .../JT808DotNettyReplyMessageExtensions.cs | 58 ++++++ .../JT808DotNettyReplyMessageHostedService.cs | 34 ++++ .../JT808DotNettyReplyMessageService.cs | 165 ++++++++++++++++++ .../JT808.DotNetty.SessionNotice.csproj | 25 +++ .../JT808DotNettySessionNoticeExtensions.cs | 61 +++++++ ...JT808DotNettySessionNoticeHostedService.cs | 35 ++++ .../JT808DotNettySessionNoticeService.cs | 25 +++ .../JT808.DotNetty.Traffic.csproj | 27 +++ .../JT808DotNettyTrafficService.cs | 32 ++++ .../JT808DotNettyTrafficServiceExtensions.cs | 34 ++++ ...T808DotNettyTrafficServiceHostedService.cs | 36 ++++ .../TrafficRedisClient.cs | 9 + .../JT808.DotNetty.Transmit.csproj | 57 +++--- .../JT808DotNettyTransmitExtensions.cs | 22 ++- .../JT808DotNettyTransmitHostedService.cs | 4 +- .../JT808DotNettyTransmitService.cs | 16 +- src/JT808.DotNetty.sln | 89 +++++++++- 50 files changed, 1127 insertions(+), 83 deletions(-) create mode 100644 src/JT808.DotNetty.Kafka/JT808ClientBuilderDefault.cs create mode 100644 src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgIdHandler.Test/JT808.DotNetty.MsgIdHandler.Test.csproj create mode 100644 src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgIdHandler.Test/Program.cs create mode 100644 src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgLogging.Test/JT808.DotNetty.MsgLogging.Test.csproj create mode 100644 src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgLogging.Test/Program.cs create mode 100644 src/JT808.DotNetty.Services.Tests/JT808.DotNetty.ReplyMessage.Test/JT808.DotNetty.ReplyMessage.Test.csproj create mode 100644 src/JT808.DotNetty.Services.Tests/JT808.DotNetty.ReplyMessage.Test/Program.cs create mode 100644 src/JT808.DotNetty.Services.Tests/JT808.DotNetty.SessionNotice.Test/JT808.DotNetty.SessionNotice.Test.csproj create mode 100644 src/JT808.DotNetty.Services.Tests/JT808.DotNetty.SessionNotice.Test/Program.cs create mode 100644 src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Traffic.Test/JT808.DotNetty.Traffic.Test.csproj create mode 100644 src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Traffic.Test/Program.cs create mode 100644 src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Transmit.Test/JT808.DotNetty.Transmit.Test.csproj create mode 100644 src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Transmit.Test/Program.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/IJT808DotNettyMsgIdHandler.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/IJT808DotNettyMsgIdHandlerExtensions.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/JT808.DotNetty.MsgIdHandler.csproj create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/JT808DotNettyMsgIdHandlerHostedService.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/IJT808MsgLogging.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808.DotNetty.MsgLogging.csproj create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808DotNettyMsgDownLoggingHostedService.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808DotNettyMsgLoggingExtensions.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808DotNettyMsgUpLoggingHostedService.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808MsgLoggingType.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808.DotNetty.ReplyMessage.csproj create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808DotNettyReplyMessageExtensions.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808DotNettyReplyMessageHostedService.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808DotNettyReplyMessageService.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808.DotNetty.SessionNotice.csproj create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808DotNettySessionNoticeExtensions.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808DotNettySessionNoticeHostedService.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808DotNettySessionNoticeService.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808.DotNetty.Traffic.csproj create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808DotNettyTrafficService.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808DotNettyTrafficServiceExtensions.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808DotNettyTrafficServiceHostedService.cs create mode 100644 src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/TrafficRedisClient.cs diff --git a/doc/img/design_model.png b/doc/img/design_model.png index 207d690baaf4b55616817f07340cfbd0b9285c0c..d55b18a33e93871e8e07735a86c4a4bf7a1290a1 100644 GIT binary patch delta 26687 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 L{ezhrb{GB!D=Xm% delta 24335 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

mNVNx(vw;bVt^a|`%gpfHIbu_G@v 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 diff --git a/simples/JT808.DotNetty.SimpleClient/Program.cs b/simples/JT808.DotNetty.SimpleClient/Program.cs index 2f549bb..f8cf3ca 100644 --- a/simples/JT808.DotNetty.SimpleClient/Program.cs +++ b/simples/JT808.DotNetty.SimpleClient/Program.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; +using JT808.Protocol; using JT808.Protocol.MessageBody; using System.Text; using System.Threading.Tasks; @@ -29,7 +30,8 @@ namespace JT808.DotNetty.SimpleClient options.AddConsole(); options.SetMinimumLevel(LogLevel.Trace); }); - services.AddJT808Client(); + services.AddJT808Configure() + .AddJT808Client(); services.AddHostedService(); }); await serverHostBuilder.RunConsoleAsync(); diff --git a/src/JT808.DotNetty.CleintBenchmark/Program.cs b/src/JT808.DotNetty.CleintBenchmark/Program.cs index de57c88..45d5d8f 100644 --- a/src/JT808.DotNetty.CleintBenchmark/Program.cs +++ b/src/JT808.DotNetty.CleintBenchmark/Program.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging; using NLog.Extensions.Logging; using System; using System.Threading.Tasks; +using JT808.Protocol; using JT808.DotNetty.Client; using JT808.DotNetty.CleintBenchmark.Configs; using JT808.DotNetty.CleintBenchmark.Services; @@ -39,7 +40,8 @@ namespace JT808.DotNetty.CleintBenchmark services.Configure(hostContext.Configuration.GetSection("ClientBenchmarkOptions")); services.AddSingleton(); services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddJT808Client(); + services.AddJT808Configure() + .AddJT808Client(); services.AddHostedService(); services.AddHostedService(); }); diff --git a/src/JT808.DotNetty.Client/JT808ClientDotnettyExtensions.cs b/src/JT808.DotNetty.Client/JT808ClientDotnettyExtensions.cs index 9550e2f..aa22498 100644 --- a/src/JT808.DotNetty.Client/JT808ClientDotnettyExtensions.cs +++ b/src/JT808.DotNetty.Client/JT808ClientDotnettyExtensions.cs @@ -9,15 +9,14 @@ namespace JT808.DotNetty.Client { public static class JT808ClientDotnettyExtensions { - public static IServiceCollection AddJT808Client(this IServiceCollection serviceDescriptors) + public static IJT808Builder AddJT808Client(this IJT808Builder jT808Builder) { - serviceDescriptors.AddJT808Configure(); - serviceDescriptors.AddSingleton(); - serviceDescriptors.AddSingleton(); - serviceDescriptors.AddSingleton(); - serviceDescriptors.AddSingleton(); - serviceDescriptors.AddHostedService(); - return serviceDescriptors; + jT808Builder.Services.AddSingleton(); + jT808Builder.Services.AddSingleton(); + jT808Builder.Services.AddSingleton(); + jT808Builder.Services.AddSingleton(); + jT808Builder.Services.AddHostedService(); + return jT808Builder; } } } diff --git a/src/JT808.DotNetty.Core/Session/JT808SessionManager.cs b/src/JT808.DotNetty.Core/Session/JT808SessionManager.cs index f59f2e5..601958b 100644 --- a/src/JT808.DotNetty.Core/Session/JT808SessionManager.cs +++ b/src/JT808.DotNetty.Core/Session/JT808SessionManager.cs @@ -1,4 +1,5 @@ -using DotNetty.Transport.Channels; +using DotNetty.Buffers; +using DotNetty.Transport.Channels; using JT808.DotNetty.Abstractions; using JT808.DotNetty.Abstractions.Enums; using JT808.DotNetty.Core.Interfaces; @@ -96,7 +97,7 @@ namespace JT808.DotNetty.Core.Session { if(session.TransportProtocolType== JT808TransportProtocolType.tcp) { - session.Channel.WriteAndFlushAsync(new JT808Response(data)); + session.Channel.WriteAndFlushAsync(Unpooled.WrappedBuffer(data)); isSuccessed = true; message = "ok"; } @@ -120,14 +121,14 @@ namespace JT808.DotNetty.Core.Session } return isSuccessed; } - public void Send(string terminalPhoneNo, byte[] data) + internal void Send(string terminalPhoneNo, byte[] data) { var session = GetSessionByTerminalPhoneNo(terminalPhoneNo); if (session != null) { if (session.TransportProtocolType == JT808TransportProtocolType.tcp) { - session.Channel.WriteAndFlushAsync(new JT808Response(data)); + session.Channel.WriteAndFlushAsync(Unpooled.WrappedBuffer(data)); } else if (session.TransportProtocolType == JT808TransportProtocolType.udp) { diff --git a/src/JT808.DotNetty.Kafka/JT808ClientBuilderDefault.cs b/src/JT808.DotNetty.Kafka/JT808ClientBuilderDefault.cs new file mode 100644 index 0000000..245125c --- /dev/null +++ b/src/JT808.DotNetty.Kafka/JT808ClientBuilderDefault.cs @@ -0,0 +1,25 @@ +using JT808.DotNetty.Abstractions; +using JT808.Protocol; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.DotNetty.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.DotNetty.Kafka/JT808ClientKafkaExtensions.cs b/src/JT808.DotNetty.Kafka/JT808ClientKafkaExtensions.cs index b4d2faa..c03bcd9 100644 --- a/src/JT808.DotNetty.Kafka/JT808ClientKafkaExtensions.cs +++ b/src/JT808.DotNetty.Kafka/JT808ClientKafkaExtensions.cs @@ -1,4 +1,5 @@ using JT808.DotNetty.Abstractions; +using JT808.Protocol; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -7,17 +8,21 @@ namespace JT808.DotNetty.Kafka { public static class JT808ClientKafkaExtensions { + public static IJT808ClientBuilder AddJT808ClientKafka(this IJT808Builder builder) + { + return new JT808ClientBuilderDefault(builder); + } ///

/// /// /// /// GetSection("JT808MsgConsumerConfig") /// - public static IServiceCollection AddJT808ClientKafkaMsgConsumer(this IServiceCollection serviceDescriptors, IConfiguration configuration) + public static IJT808ClientBuilder AddMsgConsumer(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) { - serviceDescriptors.Configure(configuration.GetSection("JT808MsgConsumerConfig")); - serviceDescriptors.TryAddSingleton(); - return serviceDescriptors; + jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808MsgConsumerConfig")); + jT808ClientBuilder.JT808Builder.Services.TryAddSingleton(); + return jT808ClientBuilder; } /// /// @@ -25,11 +30,11 @@ namespace JT808.DotNetty.Kafka /// /// GetSection("JT808MsgReplyProducerConfig") /// - public static IServiceCollection AddJT808ClientKafkaMsgReplyProducer(this IServiceCollection serviceDescriptors, IConfiguration configuration) + public static IJT808ClientBuilder AddMsgReplyProducer(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) { - serviceDescriptors.Configure(configuration.GetSection("JT808MsgReplyProducerConfig")); - serviceDescriptors.TryAddSingleton(); - return serviceDescriptors; + jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808MsgReplyProducerConfig")); + jT808ClientBuilder.JT808Builder.Services.TryAddSingleton(); + return jT808ClientBuilder; } /// /// @@ -37,11 +42,11 @@ namespace JT808.DotNetty.Kafka /// /// GetSection("JT808SessionConsumerConfig") /// - public static IServiceCollection AddJT808ClientKafkaSessionConsumer(this IServiceCollection serviceDescriptors, IConfiguration configuration) + public static IJT808ClientBuilder AddSessionConsumer(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) { - serviceDescriptors.Configure(configuration.GetSection("JT808SessionConsumerConfig")); - serviceDescriptors.TryAddSingleton(); - return serviceDescriptors; + jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808SessionConsumerConfig")); + jT808ClientBuilder.JT808Builder.Services.TryAddSingleton(); + return jT808ClientBuilder; } } } \ No newline at end of file diff --git a/src/JT808.DotNetty.Kafka/JT808MsgConsumer.cs b/src/JT808.DotNetty.Kafka/JT808MsgConsumer.cs index 7fea180..2545d45 100644 --- a/src/JT808.DotNetty.Kafka/JT808MsgConsumer.cs +++ b/src/JT808.DotNetty.Kafka/JT808MsgConsumer.cs @@ -49,17 +49,14 @@ namespace JT808.DotNetty.Kafka catch (ConsumeException ex) { logger.LogError(ex, TopicName); - Thread.Sleep(1000); } catch (OperationCanceledException ex) { logger.LogError(ex, TopicName); - Thread.Sleep(1000); } catch (Exception ex) { logger.LogError(ex, TopicName); - Thread.Sleep(1000); } } }, Cts.Token); diff --git a/src/JT808.DotNetty.Kafka/JT808MsgReplyConsumer.cs b/src/JT808.DotNetty.Kafka/JT808MsgReplyConsumer.cs index 09c459c..9f3f49c 100644 --- a/src/JT808.DotNetty.Kafka/JT808MsgReplyConsumer.cs +++ b/src/JT808.DotNetty.Kafka/JT808MsgReplyConsumer.cs @@ -49,17 +49,14 @@ namespace JT808.DotNetty.Kafka catch (ConsumeException ex) { logger.LogError(ex, TopicName); - Thread.Sleep(1000); } catch (OperationCanceledException ex) { logger.LogError(ex, TopicName); - Thread.Sleep(1000); } catch (Exception ex) { logger.LogError(ex, TopicName); - Thread.Sleep(1000); } } }, Cts.Token); diff --git a/src/JT808.DotNetty.Kafka/JT808SessionConsumer.cs b/src/JT808.DotNetty.Kafka/JT808SessionConsumer.cs index 6ddb83d..d4080d7 100644 --- a/src/JT808.DotNetty.Kafka/JT808SessionConsumer.cs +++ b/src/JT808.DotNetty.Kafka/JT808SessionConsumer.cs @@ -49,17 +49,14 @@ namespace JT808.DotNetty.Kafka catch (ConsumeException ex) { logger.LogError(ex, TopicName); - Thread.Sleep(1000); } catch (OperationCanceledException ex) { logger.LogError(ex, TopicName); - Thread.Sleep(1000); } catch (Exception ex) { logger.LogError(ex, TopicName); - Thread.Sleep(1000); } } }, Cts.Token); diff --git a/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgIdHandler.Test/JT808.DotNetty.MsgIdHandler.Test.csproj b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgIdHandler.Test/JT808.DotNetty.MsgIdHandler.Test.csproj new file mode 100644 index 0000000..21dff5c --- /dev/null +++ b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgIdHandler.Test/JT808.DotNetty.MsgIdHandler.Test.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp2.2 + + + diff --git a/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgIdHandler.Test/Program.cs b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgIdHandler.Test/Program.cs new file mode 100644 index 0000000..fd94ecb --- /dev/null +++ b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgIdHandler.Test/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace JT808.DotNetty.MsgIdHandler.Test +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgLogging.Test/JT808.DotNetty.MsgLogging.Test.csproj b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgLogging.Test/JT808.DotNetty.MsgLogging.Test.csproj new file mode 100644 index 0000000..21dff5c --- /dev/null +++ b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgLogging.Test/JT808.DotNetty.MsgLogging.Test.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp2.2 + + + diff --git a/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgLogging.Test/Program.cs b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgLogging.Test/Program.cs new file mode 100644 index 0000000..7b71d69 --- /dev/null +++ b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.MsgLogging.Test/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace JT808.DotNetty.MsgLogging.Test +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.ReplyMessage.Test/JT808.DotNetty.ReplyMessage.Test.csproj b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.ReplyMessage.Test/JT808.DotNetty.ReplyMessage.Test.csproj new file mode 100644 index 0000000..21dff5c --- /dev/null +++ b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.ReplyMessage.Test/JT808.DotNetty.ReplyMessage.Test.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp2.2 + + + diff --git a/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.ReplyMessage.Test/Program.cs b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.ReplyMessage.Test/Program.cs new file mode 100644 index 0000000..567bf0f --- /dev/null +++ b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.ReplyMessage.Test/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace JT808.DotNetty.ReplyMessage.Test +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.SessionNotice.Test/JT808.DotNetty.SessionNotice.Test.csproj b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.SessionNotice.Test/JT808.DotNetty.SessionNotice.Test.csproj new file mode 100644 index 0000000..21dff5c --- /dev/null +++ b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.SessionNotice.Test/JT808.DotNetty.SessionNotice.Test.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp2.2 + + + diff --git a/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.SessionNotice.Test/Program.cs b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.SessionNotice.Test/Program.cs new file mode 100644 index 0000000..60385e5 --- /dev/null +++ b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.SessionNotice.Test/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace JT808.DotNetty.SessionNotice.Test +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Traffic.Test/JT808.DotNetty.Traffic.Test.csproj b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Traffic.Test/JT808.DotNetty.Traffic.Test.csproj new file mode 100644 index 0000000..21dff5c --- /dev/null +++ b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Traffic.Test/JT808.DotNetty.Traffic.Test.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp2.2 + + + diff --git a/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Traffic.Test/Program.cs b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Traffic.Test/Program.cs new file mode 100644 index 0000000..89805f0 --- /dev/null +++ b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Traffic.Test/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace JT808.DotNetty.Traffic.Test +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Transmit.Test/JT808.DotNetty.Transmit.Test.csproj b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Transmit.Test/JT808.DotNetty.Transmit.Test.csproj new file mode 100644 index 0000000..21dff5c --- /dev/null +++ b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Transmit.Test/JT808.DotNetty.Transmit.Test.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp2.2 + + + diff --git a/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Transmit.Test/Program.cs b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Transmit.Test/Program.cs new file mode 100644 index 0000000..bc612c0 --- /dev/null +++ b/src/JT808.DotNetty.Services.Tests/JT808.DotNetty.Transmit.Test/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace JT808.DotNetty.Transmit.Test +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/IJT808DotNettyMsgIdHandler.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/IJT808DotNettyMsgIdHandler.cs new file mode 100644 index 0000000..1285d88 --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/IJT808DotNettyMsgIdHandler.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.DotNetty.MsgIdHandler +{ + /// + /// JT808消息Id处理程序 + /// + public interface IJT808DotNettyMsgIdHandler + { + void Processor((string TerminalNo, byte[] Data) parameter); + } +} diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/IJT808DotNettyMsgIdHandlerExtensions.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/IJT808DotNettyMsgIdHandlerExtensions.cs new file mode 100644 index 0000000..2802021 --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/IJT808DotNettyMsgIdHandlerExtensions.cs @@ -0,0 +1,19 @@ +using JT808.DotNetty.Abstractions; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.DotNetty.MsgIdHandler +{ + public static class IJT808DotNettyMsgIdHandlerExtensions + { + public static IJT808ClientBuilder AddJT808MsgIdHandler(this IJT808ClientBuilder jT808ClientBuilder) + where TJT808DotNettyMsgIdHandler: IJT808DotNettyMsgIdHandler + { + jT808ClientBuilder.JT808Builder.Services.AddSingleton(typeof(IJT808DotNettyMsgIdHandler),typeof(TJT808DotNettyMsgIdHandler)); + jT808ClientBuilder.JT808Builder.Services.AddHostedService(); + return jT808ClientBuilder; + } + } +} diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/JT808.DotNetty.MsgIdHandler.csproj b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/JT808.DotNetty.MsgIdHandler.csproj new file mode 100644 index 0000000..092f4c1 --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/JT808.DotNetty.MsgIdHandler.csproj @@ -0,0 +1,25 @@ + + + + + JT808.DotNetty.MsgIdHandler + JT808.DotNetty.MsgIdHandler + 基于JT808消息业务处理程序服务 + 基于JT808消息业务处理程序服务 + LICENSE + + + + + + + + + + + + True + + + + diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/JT808DotNettyMsgIdHandlerHostedService.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/JT808DotNettyMsgIdHandlerHostedService.cs new file mode 100644 index 0000000..b2209e5 --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgIdHandler/JT808DotNettyMsgIdHandlerHostedService.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using JT808.DotNetty.Abstractions; +using Microsoft.Extensions.Hosting; +using System.Threading; + +namespace JT808.DotNetty.MsgIdHandler +{ + public class JT808DotNettyMsgIdHandlerHostedService : IHostedService + { + private readonly IJT808MsgConsumer jT808MsgConsumer; + + private readonly IJT808DotNettyMsgIdHandler jT808DotNettyMsgIdHandler; + public JT808DotNettyMsgIdHandlerHostedService( + IJT808DotNettyMsgIdHandler jT808DotNettyMsgIdHandler, + IJT808MsgConsumer jT808MsgConsumer) + { + this.jT808DotNettyMsgIdHandler = jT808DotNettyMsgIdHandler; + this.jT808MsgConsumer = jT808MsgConsumer; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + jT808MsgConsumer.Subscribe(); + jT808MsgConsumer.OnMessage(jT808DotNettyMsgIdHandler.Processor); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + jT808MsgConsumer.Unsubscribe(); + return Task.CompletedTask; + } + } +} diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/IJT808MsgLogging.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/IJT808MsgLogging.cs new file mode 100644 index 0000000..948836e --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/IJT808MsgLogging.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace JT808.DotNetty.MsgLogging +{ + /// + /// 808数据上下行日志接口 + /// + public interface IJT808MsgLogging + { + void Processor((string TerminalNo, byte[] Data) parameter, JT808MsgLoggingType jT808MsgLoggingType); + } +} diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808.DotNetty.MsgLogging.csproj b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808.DotNetty.MsgLogging.csproj new file mode 100644 index 0000000..c8e79bf --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808.DotNetty.MsgLogging.csproj @@ -0,0 +1,25 @@ + + + + + JT808.DotNetty.MsgLogging + JT808.DotNetty.MsgLogging + 基于JT808消息上下行日志服务 + 基于JT808消息上下行日志服务 + LICENSE + + + + + + + + + True + + + + + + + diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808DotNettyMsgDownLoggingHostedService.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808DotNettyMsgDownLoggingHostedService.cs new file mode 100644 index 0000000..f7b9dd0 --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808DotNettyMsgDownLoggingHostedService.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using JT808.DotNetty.Abstractions; +using Microsoft.Extensions.Hosting; +using System.Threading; + +namespace JT808.DotNetty.MsgLogging +{ + public class JT808DotNettyMsgDownLoggingHostedService : IHostedService + { + private readonly IJT808MsgReplyConsumer jT808MsgReplyConsumer; + private readonly IJT808MsgLogging jT808MsgLogging; + public JT808DotNettyMsgDownLoggingHostedService( + 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.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808DotNettyMsgLoggingExtensions.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808DotNettyMsgLoggingExtensions.cs new file mode 100644 index 0000000..d5d7f7f --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808DotNettyMsgLoggingExtensions.cs @@ -0,0 +1,20 @@ +using JT808.DotNetty.Abstractions; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.DotNetty.MsgLogging +{ + public static class JT808DotNettyMsgLoggingExtensions + { + 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.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808DotNettyMsgUpLoggingHostedService.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808DotNettyMsgUpLoggingHostedService.cs new file mode 100644 index 0000000..2dea945 --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808DotNettyMsgUpLoggingHostedService.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using JT808.DotNetty.Abstractions; +using Microsoft.Extensions.Hosting; +using System.Threading; + +namespace JT808.DotNetty.MsgLogging +{ + public class JT808DotNettyMsgUpLoggingHostedService : IHostedService + { + private readonly IJT808MsgConsumer jT808MsgConsumer; + private readonly IJT808MsgLogging jT808MsgLogging; + public JT808DotNettyMsgUpLoggingHostedService( + 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.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808MsgLoggingType.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808MsgLoggingType.cs new file mode 100644 index 0000000..ae911cf --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.MsgLogging/JT808MsgLoggingType.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.DotNetty.MsgLogging +{ + public enum JT808MsgLoggingType + { + /// + /// 数据上行 + /// + up, + /// + /// 数据下行 + /// + down + } +} diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808.DotNetty.ReplyMessage.csproj b/src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808.DotNetty.ReplyMessage.csproj new file mode 100644 index 0000000..dd0ad9b --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808.DotNetty.ReplyMessage.csproj @@ -0,0 +1,24 @@ + + + + JT808.DotNetty.ReplyMessage + JT808.DotNetty.ReplyMessage + 基于JT808消息应答服务 + 基于JT808消息应答服务 + LICENSE + + + + + + + + + + + + True + + + + diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808DotNettyReplyMessageExtensions.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808DotNettyReplyMessageExtensions.cs new file mode 100644 index 0000000..92f7208 --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808DotNettyReplyMessageExtensions.cs @@ -0,0 +1,58 @@ +using JT808.DotNetty.Abstractions; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.DotNetty.ReplyMessage +{ + public static class JT808DotNettyReplyMessageExtensions + { + /// + /// 独享消息应答服务(不同的消费者实例) + /// + /// + /// + 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 : JT808DotNettyReplyMessageService + { + jT808ClientBuilder.JT808Builder.Services.AddSingleton(); + jT808ClientBuilder.JT808Builder.Services.AddHostedService(); + return jT808ClientBuilder; + } + /// + /// 共享消息应答服务(消费者单实例) + /// + /// 自定义消息回复服务 + /// + /// + public static IJT808ClientBuilder AddShareJT808ReplyMessage(this IJT808ClientBuilder jT808ClientBuilder) + where TReplyMessageService : JT808DotNettyReplyMessageService + { + jT808ClientBuilder.JT808Builder.Services.AddSingleton(); + return jT808ClientBuilder; + } + /// + /// 共享消息应答服务(消费者单实例) + /// + /// + /// + public static IJT808ClientBuilder AddShareJT808ReplyMessage(this IJT808ClientBuilder jT808ClientBuilder) + { + jT808ClientBuilder.JT808Builder.Services.AddSingleton(); + return jT808ClientBuilder; + } + } +} diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808DotNettyReplyMessageHostedService.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808DotNettyReplyMessageHostedService.cs new file mode 100644 index 0000000..36acede --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808DotNettyReplyMessageHostedService.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using JT808.DotNetty.Abstractions; +using Microsoft.Extensions.Hosting; +using System.Threading; + +namespace JT808.DotNetty.ReplyMessage +{ + public class JT808DotNettyReplyMessageHostedService : IHostedService + { + private readonly IJT808MsgConsumer jT808MsgConsumer; + private readonly JT808DotNettyReplyMessageService jT808DotNettyReplyMessageService; + + public JT808DotNettyReplyMessageHostedService( + JT808DotNettyReplyMessageService 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.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808DotNettyReplyMessageService.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808DotNettyReplyMessageService.cs new file mode 100644 index 0000000..66975ad --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.ReplyMessage/JT808DotNettyReplyMessageService.cs @@ -0,0 +1,165 @@ +using JT808.DotNetty.Abstractions; +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.DotNetty.ReplyMessage +{ + public class JT808DotNettyReplyMessageService + { + protected Dictionary> HandlerDict { get; } + + protected JT808Serializer JT808Serializer { get; } + protected IJT808MsgReplyProducer JT808MsgReplyProducer { get; } + public JT808DotNettyReplyMessageService( + 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.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808.DotNetty.SessionNotice.csproj b/src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808.DotNetty.SessionNotice.csproj new file mode 100644 index 0000000..84a759a --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808.DotNetty.SessionNotice.csproj @@ -0,0 +1,25 @@ + + + + + JT808.DotNetty.SessionNotice + JT808.DotNetty.SessionNotice + 基于JT808会话通知服务 + 基于JT808会话通知服务 + LICENSE + + + + + + + + + True + + + + + + + diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808DotNettySessionNoticeExtensions.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808DotNettySessionNoticeExtensions.cs new file mode 100644 index 0000000..8f9ae0b --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808DotNettySessionNoticeExtensions.cs @@ -0,0 +1,61 @@ +using JT808.DotNetty.Abstractions; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.DotNetty.SessionNotice +{ + public static class JT808DotNettySessionNoticeExtensions + { + /// + /// 独享消息会话通知服务(不同的消费者实例) + /// + /// + /// + 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 : JT808DotNettySessionNoticeService + { + jT808ClientBuilder.JT808Builder.Services.AddSingleton(); + jT808ClientBuilder.JT808Builder.Services.AddHostedService(); + return jT808ClientBuilder; + } + + /// + /// 共享消息会话通知服务(消费者单实例) + /// + /// 自定义会话通知服务 + /// + /// + public static IJT808ClientBuilder AddShareJT808SessionNotice(this IJT808ClientBuilder jT808ClientBuilder) + where TSessionNoticeService : JT808DotNettySessionNoticeService + { + jT808ClientBuilder.JT808Builder.Services.AddSingleton(); + return jT808ClientBuilder; + } + + /// + /// 共享消息会话通知服务(消费者单实例) + /// + /// + /// + public static IJT808ClientBuilder AddShareJT808SessionNotice(this IJT808ClientBuilder jT808ClientBuilder) + { + jT808ClientBuilder.JT808Builder.Services.AddSingleton(); + return jT808ClientBuilder; + } + } +} diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808DotNettySessionNoticeHostedService.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808DotNettySessionNoticeHostedService.cs new file mode 100644 index 0000000..a610ade --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808DotNettySessionNoticeHostedService.cs @@ -0,0 +1,35 @@ +using System.Threading.Tasks; +using JT808.DotNetty.Abstractions; +using JT808.Protocol; +using JT808.Protocol.Interfaces; +using Microsoft.Extensions.Hosting; +using System.Threading; + +namespace JT808.DotNetty.SessionNotice +{ + public class JT808DotNettySessionNoticeHostedService : IHostedService + { + private readonly JT808DotNettySessionNoticeService jT808DotNettySessionNoticeService; + private readonly IJT808SessionConsumer jT808SessionConsumer; + public JT808DotNettySessionNoticeHostedService( + IJT808SessionConsumer jT808SessionConsumer, + JT808DotNettySessionNoticeService 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.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808DotNettySessionNoticeService.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808DotNettySessionNoticeService.cs new file mode 100644 index 0000000..a4f164b --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.SessionNotice/JT808DotNettySessionNoticeService.cs @@ -0,0 +1,25 @@ +using JT808.DotNetty.Abstractions; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.DotNetty.SessionNotice +{ + public class JT808DotNettySessionNoticeService + { + protected ILogger logger { get; } + public JT808DotNettySessionNoticeService(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.DotNetty.Services/JT808.DotNetty.Traffic/JT808.DotNetty.Traffic.csproj b/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808.DotNetty.Traffic.csproj new file mode 100644 index 0000000..99be375 --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808.DotNetty.Traffic.csproj @@ -0,0 +1,27 @@ + + + + JT808.DotNetty.Traffic + JT808.DotNetty.Traffic + 基于JT808设备流量统计服务 + 基于JT808设备流量统计服务 + LICENSE + + + + + + + + + + + + True + + + + + + + diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808DotNettyTrafficService.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808DotNettyTrafficService.cs new file mode 100644 index 0000000..1dde491 --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808DotNettyTrafficService.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.DotNetty.Traffic +{ + public class JT808DotNettyTrafficService:IDisposable + { + private readonly CSRedis.CSRedisClient redisClien; + public JT808DotNettyTrafficService(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.DotNetty.Services/JT808.DotNetty.Traffic/JT808DotNettyTrafficServiceExtensions.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808DotNettyTrafficServiceExtensions.cs new file mode 100644 index 0000000..fdeac49 --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808DotNettyTrafficServiceExtensions.cs @@ -0,0 +1,34 @@ +using JT808.DotNetty.Abstractions; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.DotNetty.Traffic +{ + public static class JT808DotNettyTrafficServiceExtensions + { + /// + /// 独享消息流量统计服务(不同的消费者实例) + /// + /// + /// + 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.DotNetty.Services/JT808.DotNetty.Traffic/JT808DotNettyTrafficServiceHostedService.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808DotNettyTrafficServiceHostedService.cs new file mode 100644 index 0000000..bb83417 --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808DotNettyTrafficServiceHostedService.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using JT808.DotNetty.Abstractions; +using Microsoft.Extensions.Hosting; +using System.Threading; + +namespace JT808.DotNetty.Traffic +{ + public class JT808DotNettyTrafficServiceHostedService : IHostedService + { + private readonly IJT808MsgConsumer jT808MsgConsumer; + private readonly JT808DotNettyTrafficService jT808DotNettyTrafficService; + + public JT808DotNettyTrafficServiceHostedService( + JT808DotNettyTrafficService jT808DotNettyTrafficService, + IJT808MsgConsumer jT808MsgConsumer) + { + this.jT808MsgConsumer = jT808MsgConsumer; + this.jT808DotNettyTrafficService = jT808DotNettyTrafficService; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + jT808MsgConsumer.Subscribe(); + jT808MsgConsumer.OnMessage((item)=> { + 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.DotNetty.Services/JT808.DotNetty.Traffic/TrafficRedisClient.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/TrafficRedisClient.cs new file mode 100644 index 0000000..675dd10 --- /dev/null +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/TrafficRedisClient.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.DotNetty.Traffic +{ + class TrafficRedisClient: RedisHelper + { } +} diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808.DotNetty.Transmit.csproj b/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808.DotNetty.Transmit.csproj index f7b1f9c..cd826a9 100644 --- a/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808.DotNetty.Transmit.csproj +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808.DotNetty.Transmit.csproj @@ -1,30 +1,29 @@ - + - - - JT808.DotNetty.Transmit - JT808.DotNetty.Transmit - 基于DotNetty实现的JT808数据转发服务 - 基于DotNetty实现的JT808数据转发服务 - LICENSE - - - - - - - - - - - - - True - - - - - - - - + + + JT808.DotNetty.Transmit + JT808.DotNetty.Transmit + 基于DotNetty实现的JT808数据转发服务 + 基于DotNetty实现的JT808数据转发服务 + LICENSE + + + + + + + + + + + + + + + + True + + + + \ No newline at end of file diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808DotNettyTransmitExtensions.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808DotNettyTransmitExtensions.cs index eef4fbb..a5084b3 100644 --- a/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808DotNettyTransmitExtensions.cs +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808DotNettyTransmitExtensions.cs @@ -8,16 +8,34 @@ using JT808.DotNetty.Transmit; using Microsoft.Extensions.Configuration; using JT808.DotNetty.Transmit.Configs; -namespace JT808.DotNetty.Client +namespace JT808.DotNetty.Transmit { public static class JT808DotNettyTransmitExtensions { - public static IJT808ClientBuilder AddJT808Transmit(this IJT808ClientBuilder jT808ClientBuilder,IConfiguration configuration) + /// + /// 独享转发服务(不同的消费者实例) + /// + /// + /// + /// + 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.DotNetty.Services/JT808.DotNetty.Transmit/JT808DotNettyTransmitHostedService.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808DotNettyTransmitHostedService.cs index d9e3b7a..b050198 100644 --- a/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808DotNettyTransmitHostedService.cs +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808DotNettyTransmitHostedService.cs @@ -37,9 +37,7 @@ namespace JT808.DotNetty.Transmit public Task StartAsync(CancellationToken cancellationToken) { jT808MsgConsumer.Subscribe(); - jT808MsgConsumer.OnMessage(item=> { - jT808DotNettyTransmitService.SendAsync(item.TerminalNo,item.Data); - }); + jT808MsgConsumer.OnMessage(jT808DotNettyTransmitService.SendAsync); return Task.CompletedTask; } diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808DotNettyTransmitService.cs b/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808DotNettyTransmitService.cs index 2bbd8b1..260a7c2 100644 --- a/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808DotNettyTransmitService.cs +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.Transmit/JT808DotNettyTransmitService.cs @@ -28,7 +28,7 @@ namespace JT808.DotNetty.Transmit this.optionsMonitor = optionsMonitor; InitialDispatcherClient(); } - public void SendAsync(string terminalNo,byte[] data) + public void SendAsync((string TerminalNo, byte[] Data) parameter) { if (optionsMonitor.CurrentValue.DataTransfer != null) { @@ -40,11 +40,11 @@ namespace JT808.DotNetty.Transmit { if (allClientChannel.Open) { - if (logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + if (logger.IsEnabled(LogLevel.Debug)) { logger.LogDebug($"转发所有数据到该网关{item.Host}"); } - allClientChannel.WriteAndFlushAsync(Unpooled.WrappedBuffer(data)); + allClientChannel.WriteAndFlushAsync(Unpooled.WrappedBuffer(parameter.Data)); } else { @@ -58,24 +58,24 @@ namespace JT808.DotNetty.Transmit } else { - if (item.TerminalNos.Contains(terminalNo) && channeldic.TryGetValue($"{terminalNo}_{item.Host}", out var clientChannel)) + 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($"转发{terminalNo}到该网关{item.Host}"); - clientChannel.WriteAndFlushAsync(Unpooled.WrappedBuffer(data)); + logger.LogDebug($"转发{parameter.TerminalNo}到该网关{item.Host}"); + clientChannel.WriteAndFlushAsync(Unpooled.WrappedBuffer(parameter.Data)); } else { - logger.LogError($"{item.Host},{terminalNo}链接已关闭"); + logger.LogError($"{item.Host},{parameter.TerminalNo}链接已关闭"); } } catch (Exception ex) { - logger.LogError($"{item.Host},{terminalNo}发送数据出现异常:{ex}"); + logger.LogError($"{item.Host},{parameter.TerminalNo}发送数据出现异常:{ex}"); } } } diff --git a/src/JT808.DotNetty.sln b/src/JT808.DotNetty.sln index a97688e..25975a2 100644 --- a/src/JT808.DotNetty.sln +++ b/src/JT808.DotNetty.sln @@ -45,7 +45,29 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.RabbitMQ.Tes EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{7F077BD5-8E4C-402A-9E24-DECAF251A420}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.Transmit", "JT808.DotNetty.Services\JT808.DotNetty.Transmit\JT808.DotNetty.Transmit.csproj", "{A3A0D0E1-F9AC-4004-A306-9491D2EA6883}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.Transmit", "JT808.DotNetty.Services\JT808.DotNetty.Transmit\JT808.DotNetty.Transmit.csproj", "{0E2326F8-4C96-446B-9B91-285635870171}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.ReplyMessage", "JT808.DotNetty.Services\JT808.DotNetty.ReplyMessage\JT808.DotNetty.ReplyMessage.csproj", "{2DB0F94A-2CF9-4FC0-B560-C4A7C311B225}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.ReplyMessage.Test", "JT808.DotNetty.Services.Tests\JT808.DotNetty.ReplyMessage.Test\JT808.DotNetty.ReplyMessage.Test.csproj", "{4C01B160-543B-4659-B99C-B9C774B3DEE9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.Traffic", "JT808.DotNetty.Services\JT808.DotNetty.Traffic\JT808.DotNetty.Traffic.csproj", "{3C34D0D2-C9A5-42BB-830B-922C69AE74AE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.Traffic.Test", "JT808.DotNetty.Services.Tests\JT808.DotNetty.Traffic.Test\JT808.DotNetty.Traffic.Test.csproj", "{24E3A6DD-0BC4-4EDA-AC40-B07371BB5FDB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.SessionNotice", "JT808.DotNetty.Services\JT808.DotNetty.SessionNotice\JT808.DotNetty.SessionNotice.csproj", "{A09B9BF7-FEC6-4D6C-A635-77DD445A4082}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.SessionNotice.Test", "JT808.DotNetty.Services.Tests\JT808.DotNetty.SessionNotice.Test\JT808.DotNetty.SessionNotice.Test.csproj", "{81DE821F-0780-44B4-B02D-72998ECA6BD2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.MsgLogging", "JT808.DotNetty.Services\JT808.DotNetty.MsgLogging\JT808.DotNetty.MsgLogging.csproj", "{DBB89A8E-D2AB-4BC9-849F-FFB8018C069E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.Transmit.Test", "JT808.DotNetty.Services.Tests\JT808.DotNetty.Transmit.Test\JT808.DotNetty.Transmit.Test.csproj", "{EE5EF8D4-8B61-4706-81BB-412F643E8F51}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.MsgLogging.Test", "JT808.DotNetty.Services.Tests\JT808.DotNetty.MsgLogging.Test\JT808.DotNetty.MsgLogging.Test.csproj", "{591D7974-9AF5-41E2-9B3C-B271EE682943}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.MsgIdHandler", "JT808.DotNetty.Services\JT808.DotNetty.MsgIdHandler\JT808.DotNetty.MsgIdHandler.csproj", "{F361C47C-0511-4383-99C1-A169D4E8F4ED}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.MsgIdHandler.Test", "JT808.DotNetty.Services.Tests\JT808.DotNetty.MsgIdHandler.Test\JT808.DotNetty.MsgIdHandler.Test.csproj", "{B5C872E6-4187-479A-B3BA-CCE76A225DE9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -125,10 +147,54 @@ Global {D3CA0D73-1CCF-41BA-88D8-5BE50515CA64}.Debug|Any CPU.Build.0 = Debug|Any CPU {D3CA0D73-1CCF-41BA-88D8-5BE50515CA64}.Release|Any CPU.ActiveCfg = Release|Any CPU {D3CA0D73-1CCF-41BA-88D8-5BE50515CA64}.Release|Any CPU.Build.0 = Release|Any CPU - {A3A0D0E1-F9AC-4004-A306-9491D2EA6883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A3A0D0E1-F9AC-4004-A306-9491D2EA6883}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A3A0D0E1-F9AC-4004-A306-9491D2EA6883}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A3A0D0E1-F9AC-4004-A306-9491D2EA6883}.Release|Any CPU.Build.0 = Release|Any CPU + {0E2326F8-4C96-446B-9B91-285635870171}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E2326F8-4C96-446B-9B91-285635870171}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E2326F8-4C96-446B-9B91-285635870171}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E2326F8-4C96-446B-9B91-285635870171}.Release|Any CPU.Build.0 = Release|Any CPU + {2DB0F94A-2CF9-4FC0-B560-C4A7C311B225}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2DB0F94A-2CF9-4FC0-B560-C4A7C311B225}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2DB0F94A-2CF9-4FC0-B560-C4A7C311B225}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2DB0F94A-2CF9-4FC0-B560-C4A7C311B225}.Release|Any CPU.Build.0 = Release|Any CPU + {4C01B160-543B-4659-B99C-B9C774B3DEE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C01B160-543B-4659-B99C-B9C774B3DEE9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C01B160-543B-4659-B99C-B9C774B3DEE9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C01B160-543B-4659-B99C-B9C774B3DEE9}.Release|Any CPU.Build.0 = Release|Any CPU + {3C34D0D2-C9A5-42BB-830B-922C69AE74AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3C34D0D2-C9A5-42BB-830B-922C69AE74AE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C34D0D2-C9A5-42BB-830B-922C69AE74AE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3C34D0D2-C9A5-42BB-830B-922C69AE74AE}.Release|Any CPU.Build.0 = Release|Any CPU + {24E3A6DD-0BC4-4EDA-AC40-B07371BB5FDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {24E3A6DD-0BC4-4EDA-AC40-B07371BB5FDB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {24E3A6DD-0BC4-4EDA-AC40-B07371BB5FDB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {24E3A6DD-0BC4-4EDA-AC40-B07371BB5FDB}.Release|Any CPU.Build.0 = Release|Any CPU + {A09B9BF7-FEC6-4D6C-A635-77DD445A4082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A09B9BF7-FEC6-4D6C-A635-77DD445A4082}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A09B9BF7-FEC6-4D6C-A635-77DD445A4082}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A09B9BF7-FEC6-4D6C-A635-77DD445A4082}.Release|Any CPU.Build.0 = Release|Any CPU + {81DE821F-0780-44B4-B02D-72998ECA6BD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {81DE821F-0780-44B4-B02D-72998ECA6BD2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {81DE821F-0780-44B4-B02D-72998ECA6BD2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {81DE821F-0780-44B4-B02D-72998ECA6BD2}.Release|Any CPU.Build.0 = Release|Any CPU + {DBB89A8E-D2AB-4BC9-849F-FFB8018C069E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DBB89A8E-D2AB-4BC9-849F-FFB8018C069E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DBB89A8E-D2AB-4BC9-849F-FFB8018C069E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DBB89A8E-D2AB-4BC9-849F-FFB8018C069E}.Release|Any CPU.Build.0 = Release|Any CPU + {EE5EF8D4-8B61-4706-81BB-412F643E8F51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EE5EF8D4-8B61-4706-81BB-412F643E8F51}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EE5EF8D4-8B61-4706-81BB-412F643E8F51}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EE5EF8D4-8B61-4706-81BB-412F643E8F51}.Release|Any CPU.Build.0 = Release|Any CPU + {591D7974-9AF5-41E2-9B3C-B271EE682943}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {591D7974-9AF5-41E2-9B3C-B271EE682943}.Debug|Any CPU.Build.0 = Debug|Any CPU + {591D7974-9AF5-41E2-9B3C-B271EE682943}.Release|Any CPU.ActiveCfg = Release|Any CPU + {591D7974-9AF5-41E2-9B3C-B271EE682943}.Release|Any CPU.Build.0 = Release|Any CPU + {F361C47C-0511-4383-99C1-A169D4E8F4ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F361C47C-0511-4383-99C1-A169D4E8F4ED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F361C47C-0511-4383-99C1-A169D4E8F4ED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F361C47C-0511-4383-99C1-A169D4E8F4ED}.Release|Any CPU.Build.0 = Release|Any CPU + {B5C872E6-4187-479A-B3BA-CCE76A225DE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B5C872E6-4187-479A-B3BA-CCE76A225DE9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B5C872E6-4187-479A-B3BA-CCE76A225DE9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B5C872E6-4187-479A-B3BA-CCE76A225DE9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -143,7 +209,18 @@ Global {CCE6AEFB-1AB0-4BD9-8EA2-8B4CDD097E88} = {2459FB59-8A33-49A4-ADBC-A0B12C5886A6} {50A94BD5-5CDF-4777-AE4C-80BA769AEDAB} = {3BD7FF02-8516-4A77-A385-9FDCDD792E22} {D3CA0D73-1CCF-41BA-88D8-5BE50515CA64} = {3BD7FF02-8516-4A77-A385-9FDCDD792E22} - {A3A0D0E1-F9AC-4004-A306-9491D2EA6883} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} + {0E2326F8-4C96-446B-9B91-285635870171} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} + {2DB0F94A-2CF9-4FC0-B560-C4A7C311B225} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} + {4C01B160-543B-4659-B99C-B9C774B3DEE9} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} + {3C34D0D2-C9A5-42BB-830B-922C69AE74AE} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} + {24E3A6DD-0BC4-4EDA-AC40-B07371BB5FDB} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} + {A09B9BF7-FEC6-4D6C-A635-77DD445A4082} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} + {81DE821F-0780-44B4-B02D-72998ECA6BD2} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} + {DBB89A8E-D2AB-4BC9-849F-FFB8018C069E} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} + {EE5EF8D4-8B61-4706-81BB-412F643E8F51} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} + {591D7974-9AF5-41E2-9B3C-B271EE682943} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} + {F361C47C-0511-4383-99C1-A169D4E8F4ED} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} + {B5C872E6-4187-479A-B3BA-CCE76A225DE9} = {7F077BD5-8E4C-402A-9E24-DECAF251A420} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FC0FFCEA-E1EF-4C97-A1C5-F89418B6834B}