@@ -1,90 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Codecs; | |||
using DotNetty.Transport.Bootstrapping; | |||
using DotNetty.Transport.Channels; | |||
using DotNetty.Transport.Libuv; | |||
using JT808.DotNetty.Codecs; | |||
using JT808.DotNetty.Dtos; | |||
using JT808.DotNetty.Metadata; | |||
using JT808.Protocol; | |||
using JT808.Protocol.Extensions; | |||
using JT808.Protocol.MessageBody; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Net.Http; | |||
using System.Runtime.InteropServices; | |||
using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
using Xunit; | |||
namespace JT808.DotNetty.Test.Internal | |||
{ | |||
public class JT808AtomicCounterServiceTest: TestBase | |||
{ | |||
private IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6565); | |||
public JT808SimpleTcpClient SimpleTcpClient; | |||
public JT808AtomicCounterServiceTest() | |||
{ | |||
SimpleTcpClient = new JT808SimpleTcpClient(endPoint); | |||
} | |||
[Fact] | |||
public void Test1() | |||
{ | |||
JT808AtomicCounter jT808AtomicCounter = new JT808AtomicCounter(); | |||
JT808AtomicCounter jT808AtomicCounter1 = new JT808AtomicCounter(); | |||
Parallel.For(0, 1000, (i) => | |||
{ | |||
jT808AtomicCounter.Increment(); | |||
}); | |||
Assert.Equal(1000, jT808AtomicCounter.Count); | |||
Parallel.For(0, 1000, (i) => | |||
{ | |||
jT808AtomicCounter1.Increment(); | |||
}); | |||
Assert.Equal(1000, jT808AtomicCounter1.Count); | |||
} | |||
[Fact] | |||
public void Test2() | |||
{ | |||
// 心跳会话包 | |||
JT808Package jT808Package1 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789001"); | |||
SimpleTcpClient.WriteAsync(JT808Serializer.Serialize(jT808Package1)); | |||
// 心跳会话包 | |||
JT808Package jT808Package2 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789002"); | |||
SimpleTcpClient.WriteAsync(JT808Serializer.Serialize(jT808Package2)); | |||
// 心跳会话包 | |||
JT808Package jT808Package3 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789003"); | |||
SimpleTcpClient.WriteAsync(JT808Serializer.Serialize(jT808Package3)); | |||
// 心跳会话包 | |||
JT808Package jT808Package4 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789004"); | |||
SimpleTcpClient.WriteAsync(JT808Serializer.Serialize(jT808Package4)); | |||
// 心跳会话包 | |||
JT808Package jT808Package5 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789005"); | |||
SimpleTcpClient.WriteAsync(JT808Serializer.Serialize(jT808Package5)); | |||
// 异步的需要延时下 | |||
Thread.Sleep(1000); | |||
HttpClient httpClient = new HttpClient(); | |||
// 调用内置的http服务接收文本信息下发 | |||
var result = httpClient.GetAsync("http://127.0.0.1:828/jt808api/GetAtomicCounter").Result; | |||
string content = result.Content.ReadAsStringAsync().Result; | |||
JT808ResultDto<JT808AtomicCounterDto> jt808Result = JsonConvert.DeserializeObject<JT808ResultDto<JT808AtomicCounterDto>>(content); | |||
Assert.Equal(200, jt808Result.Code); | |||
Assert.Equal(5,jt808Result.Data.MsgSuccessCount); | |||
Assert.Equal(0, jt808Result.Data.MsgFailCount); | |||
SimpleTcpClient.Down(); | |||
} | |||
} | |||
} |
@@ -1,78 +0,0 @@ | |||
using JT808.DotNetty.Internal; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using JT808.DotNetty.Configurations; | |||
using Microsoft.Extensions.Options; | |||
using Xunit; | |||
using System.Threading.Tasks; | |||
using System.Threading; | |||
using StackExchange.Redis; | |||
namespace JT808.DotNetty.Test.Internal | |||
{ | |||
public class JT808SessionPublishingRedisImplTest: TestBase | |||
{ | |||
JT808SessionPublishingRedisImpl jT808SessionPublishingRedisImpl; | |||
public JT808SessionPublishingRedisImplTest() | |||
{ | |||
jT808SessionPublishingRedisImpl = new JT808SessionPublishingRedisImpl( | |||
ServiceProvider.GetRequiredService<IOptionsMonitor<JT808Configuration>>()); | |||
} | |||
[Fact] | |||
public void Test1() | |||
{ | |||
int i = 10000; | |||
Task.Run(() => { | |||
while (i > 0) | |||
{ | |||
jT808SessionPublishingRedisImpl.PublishAsync(JT808Constants.SessionOnline, null, Guid.NewGuid().ToString("N")); | |||
jT808SessionPublishingRedisImpl.PublishAsync(JT808Constants.SessionOffline, null, Guid.NewGuid().ToString("N")); | |||
i--; | |||
Thread.Sleep(1000); | |||
} | |||
}); | |||
Thread.Sleep(1000); | |||
List<string> SessionOnlines = new List<string>(); | |||
ChannelMessageQueue channelMessageQueue= jT808SessionPublishingRedisImpl.Subscriber.Subscribe(JT808Constants.SessionOnline); | |||
channelMessageQueue.OnMessage((msg) => { | |||
SessionOnlines.Add(msg.Message); | |||
}); | |||
List<string> SessionOfflines = new List<string>(); | |||
ChannelMessageQueue channelMessageQueue1 = jT808SessionPublishingRedisImpl.Subscriber.Subscribe(JT808Constants.SessionOffline); | |||
channelMessageQueue1.OnMessage((msg) => { | |||
SessionOfflines.Add(msg.Message); | |||
}); | |||
Thread.Sleep(3000); | |||
} | |||
[Fact] | |||
public void Test2() | |||
{ | |||
int i = 100000; | |||
Task.Run(() => { | |||
while (i > 0) | |||
{ | |||
jT808SessionPublishingRedisImpl.PublishAsync(JT808Constants.SessionOnline, null, Guid.NewGuid().ToString("N")); | |||
jT808SessionPublishingRedisImpl.PublishAsync(JT808Constants.SessionOffline, null, Guid.NewGuid().ToString("N")); | |||
i--; | |||
Thread.Sleep(1000); | |||
} | |||
}); | |||
Thread.Sleep(1000); | |||
List<string> SessionOnlines = new List<string>(); | |||
List<string> SessionOfflines = new List<string>(); | |||
ChannelMessageQueue channelMessageQueue = jT808SessionPublishingRedisImpl.Subscriber.Subscribe(JT808Constants.SessionOnline); | |||
channelMessageQueue.OnMessage((msg) => { | |||
SessionOnlines.Add(msg.Message); | |||
}); | |||
ChannelMessageQueue channelMessageQueue1 = jT808SessionPublishingRedisImpl.Subscriber.Subscribe(JT808Constants.SessionOffline); | |||
channelMessageQueue1.OnMessage((msg) => { | |||
SessionOfflines.Add(msg.Message); | |||
}); | |||
} | |||
} | |||
} |
@@ -1,62 +0,0 @@ | |||
using JT808.DotNetty.Internal; | |||
using System; | |||
using System.Linq; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using System.Net; | |||
using JT808.Protocol; | |||
using JT808.Protocol.Extensions; | |||
using System.Threading; | |||
using Xunit; | |||
using JT808.DotNetty.Interfaces; | |||
namespace JT808.DotNetty.Test.Internal | |||
{ | |||
public class JT808SessionServiceDefaultImplTest : TestBase | |||
{ | |||
static IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6565); | |||
[Fact] | |||
public void Test1() | |||
{ | |||
IJT808SessionService jT808SessionServiceDefaultImpl = ServiceProvider.GetService<IJT808SessionService>(); | |||
JT808SimpleTcpClient SimpleTcpClient1 = new JT808SimpleTcpClient(endPoint); | |||
JT808SimpleTcpClient SimpleTcpClient2 = new JT808SimpleTcpClient(endPoint); | |||
JT808SimpleTcpClient SimpleTcpClient3 = new JT808SimpleTcpClient(endPoint); | |||
JT808SimpleTcpClient SimpleTcpClient4 = new JT808SimpleTcpClient(endPoint); | |||
JT808SimpleTcpClient SimpleTcpClient5 = new JT808SimpleTcpClient(endPoint); | |||
// 心跳会话包 | |||
JT808Package jT808Package1 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789001"); | |||
SimpleTcpClient1.WriteAsync(JT808Serializer.Serialize(jT808Package1)); | |||
// 心跳会话包 | |||
JT808Package jT808Package2 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789002"); | |||
SimpleTcpClient2.WriteAsync(JT808Serializer.Serialize(jT808Package2)); | |||
// 心跳会话包 | |||
JT808Package jT808Package3 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789003"); | |||
SimpleTcpClient3.WriteAsync(JT808Serializer.Serialize(jT808Package3)); | |||
// 心跳会话包 | |||
JT808Package jT808Package4 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789004"); | |||
SimpleTcpClient4.WriteAsync(JT808Serializer.Serialize(jT808Package4)); | |||
// 心跳会话包 | |||
JT808Package jT808Package5 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789005"); | |||
SimpleTcpClient5.WriteAsync(JT808Serializer.Serialize(jT808Package5)); | |||
Thread.Sleep(1000); | |||
var result = jT808SessionServiceDefaultImpl.GetAll(); | |||
var result1 = jT808SessionServiceDefaultImpl.GetAll(); | |||
Thread.Sleep(10000); | |||
SimpleTcpClient1.Down(); | |||
SimpleTcpClient2.Down(); | |||
SimpleTcpClient3.Down(); | |||
SimpleTcpClient4.Down(); | |||
SimpleTcpClient5.Down(); | |||
} | |||
} | |||
} |
@@ -1,146 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Codecs; | |||
using DotNetty.Transport.Bootstrapping; | |||
using DotNetty.Transport.Channels; | |||
using DotNetty.Transport.Libuv; | |||
using JT808.DotNetty.Codecs; | |||
using JT808.DotNetty.Configurations; | |||
using JT808.DotNetty.Internal; | |||
using JT808.Protocol; | |||
using JT808.Protocol.Extensions; | |||
using Microsoft.Extensions.Configuration; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Hosting; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Runtime.InteropServices; | |||
using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
using Xunit; | |||
namespace JT808.DotNetty.Test.Internal | |||
{ | |||
public class JT808SourcePackageChannelServiceTest:TestBase | |||
{ | |||
private JT808SourcePackageChannelService jT808SourcePackageChannelService; | |||
private IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6565); | |||
public JT808SimpleTcpClient SimpleTcpClient; | |||
/// <summary> | |||
/// 需要使用 SocketTool 创建tcp服务器 | |||
/// </summary> | |||
public JT808SourcePackageChannelServiceTest() | |||
{ | |||
SimpleTcpClient = new JT808SimpleTcpClient(endPoint, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6555)); | |||
//作为设备5秒上传 | |||
Task.Run(() => | |||
{ | |||
Random random = new Random(); | |||
while (true) | |||
{ | |||
JT808Package jT808Package = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("12345678900"+ random.Next(0,2).ToString()); | |||
SimpleTcpClient.WriteAsync(JT808Serializer.Serialize(jT808Package)); | |||
Thread.Sleep(1000); | |||
} | |||
}); | |||
// 作为源包转发服务端 | |||
DispatcherEventLoopGroup bossGroup = new DispatcherEventLoopGroup(); | |||
WorkerEventLoopGroup workerGroup = new WorkerEventLoopGroup(bossGroup, 1); | |||
ServerBootstrap bootstrap = new ServerBootstrap(); | |||
bootstrap.Group(bossGroup, workerGroup); | |||
bootstrap.Channel<TcpServerChannel>(); | |||
bootstrap | |||
.ChildHandler(new ActionChannelInitializer<IChannel>(channel => | |||
{ | |||
IChannelPipeline pipeline = channel.Pipeline; | |||
channel.Pipeline.AddLast("jt808Buffer", new DelimiterBasedFrameDecoder(int.MaxValue, | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); | |||
channel.Pipeline.AddLast("jt808Decode", new JT808ClientDecoder()); | |||
})); | |||
bootstrap.BindAsync(6655); | |||
DispatcherEventLoopGroup bossGroup1 = new DispatcherEventLoopGroup(); | |||
WorkerEventLoopGroup workerGroup1 = new WorkerEventLoopGroup(bossGroup1, 1); | |||
ServerBootstrap bootstrap1 = new ServerBootstrap(); | |||
bootstrap1.Group(bossGroup1, workerGroup1); | |||
bootstrap1.Channel<TcpServerChannel>(); | |||
bootstrap1 | |||
.ChildHandler(new ActionChannelInitializer<IChannel>(channel => | |||
{ | |||
IChannelPipeline pipeline = channel.Pipeline; | |||
channel.Pipeline.AddLast("jt808Buffer", new DelimiterBasedFrameDecoder(int.MaxValue, | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); | |||
channel.Pipeline.AddLast("jt808Decode", new JT808ClientDecoder()); | |||
})); | |||
bootstrap1.BindAsync(6656); | |||
} | |||
[Fact] | |||
public void Test1() | |||
{ | |||
//预热 | |||
Thread.Sleep(3000); | |||
jT808SourcePackageChannelService = ServiceProvider.GetService<JT808SourcePackageChannelService>(); | |||
var result = jT808SourcePackageChannelService.GetAll(); | |||
//创建服务 | |||
DispatcherEventLoopGroup bossGroup2 = new DispatcherEventLoopGroup(); | |||
WorkerEventLoopGroup workerGroup2 = new WorkerEventLoopGroup(bossGroup2, 1); | |||
ServerBootstrap bootstrap2 = new ServerBootstrap(); | |||
bootstrap2.Group(bossGroup2, workerGroup2); | |||
bootstrap2.Channel<TcpServerChannel>(); | |||
bootstrap2 | |||
.ChildHandler(new ActionChannelInitializer<IChannel>(channel => | |||
{ | |||
IChannelPipeline pipeline = channel.Pipeline; | |||
channel.Pipeline.AddLast("jt808Buffer", new DelimiterBasedFrameDecoder(int.MaxValue, | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); | |||
channel.Pipeline.AddLast("jt808Decode", new JT808ClientDecoder()); | |||
})); | |||
bootstrap2.BindAsync(6522); | |||
//添加服务 | |||
var addResult = jT808SourcePackageChannelService.Add(new Dtos.JT808IPAddressDto | |||
{ | |||
Host = "127.0.0.1", | |||
Port = 6522 | |||
}).Result; | |||
Thread.Sleep(1000); | |||
var result1 = jT808SourcePackageChannelService.GetAll(); | |||
//删除 | |||
var result2 = jT808SourcePackageChannelService.Remove(new Dtos.JT808IPAddressDto | |||
{ | |||
Host = "127.0.0.1", | |||
Port = 6522 | |||
}).Result; | |||
//[::ffff:127.0.0.1]:13196 | |||
var result3 = jT808SourcePackageChannelService.GetAll(); | |||
} | |||
[Fact] | |||
public void Test2() | |||
{ | |||
//[::ffff:127.0.0.1]:13196 | |||
var str = "[::ffff:127.0.0.1]:13196"; | |||
IPAddress.TryParse(str, out IPAddress ip); | |||
var a = ip.MapToIPv4().ToString(); | |||
var a1 = str.Replace("[::ffff:", "").Replace("]", ""); | |||
} | |||
} | |||
} |
@@ -1,72 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Text; | |||
using Xunit; | |||
using JT808.Protocol.Extensions; | |||
using System.Threading; | |||
using DotNetty.Transport.Channels; | |||
using System.Runtime.InteropServices; | |||
using DotNetty.Transport.Libuv; | |||
using DotNetty.Transport.Bootstrapping; | |||
using DotNetty.Buffers; | |||
using DotNetty.Codecs; | |||
using JT808.DotNetty.Codecs; | |||
namespace JT808.DotNetty.Test.Internal | |||
{ | |||
public class JT808SourcePackageDispatcherDefaultImplTest: TestBase | |||
{ | |||
private IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6565); | |||
public JT808SimpleTcpClient SimpleTcpClient; | |||
public JT808SourcePackageDispatcherDefaultImplTest() | |||
{ | |||
SimpleTcpClient = new JT808SimpleTcpClient(endPoint, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6561)); | |||
} | |||
[Fact] | |||
public void Test1() | |||
{ | |||
// 作为源包转发服务端 | |||
DispatcherEventLoopGroup bossGroup = new DispatcherEventLoopGroup(); | |||
WorkerEventLoopGroup workerGroup = new WorkerEventLoopGroup(bossGroup, 1); | |||
ServerBootstrap bootstrap = new ServerBootstrap(); | |||
bootstrap.Group(bossGroup, workerGroup); | |||
bootstrap.Channel<TcpServerChannel>(); | |||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) | |||
|| RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) | |||
{ | |||
bootstrap | |||
.Option(ChannelOption.SoReuseport, true) | |||
.ChildOption(ChannelOption.SoReuseaddr, true); | |||
} | |||
bootstrap | |||
.ChildHandler(new ActionChannelInitializer<IChannel>(channel => | |||
{ | |||
IChannelPipeline pipeline = channel.Pipeline; | |||
channel.Pipeline.AddLast("jt808Buffer", new DelimiterBasedFrameDecoder(int.MaxValue, | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); | |||
channel.Pipeline.AddLast("jt808Decode", new JT808ClientDecoder()); | |||
})); | |||
bootstrap.BindAsync(6655); | |||
//作为设备上传 | |||
byte[] bytes = "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(); | |||
SimpleTcpClient.WriteAsync(bytes); | |||
Thread.Sleep(10000); | |||
SimpleTcpClient.Down(); | |||
} | |||
[Fact] | |||
public void Test2() | |||
{ | |||
//原包转发 不下发 - 貔貅 | |||
byte[] bytes = "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(); | |||
SimpleTcpClient.WriteAsync(bytes); | |||
Thread.Sleep(3000); | |||
SimpleTcpClient.Down(); | |||
} | |||
} | |||
} |
@@ -1,104 +0,0 @@ | |||
using JT808.DotNetty.Configurations; | |||
using JT808.DotNetty.Dtos; | |||
using JT808.DotNetty.Internal; | |||
using Microsoft.Extensions.Configuration; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Hosting; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using Xunit; | |||
namespace JT808.DotNetty.Test.Internal | |||
{ | |||
public class JT808TransmitAddressFilterServiceTest | |||
{ | |||
private JT808TransmitAddressFilterService jT808TransmitAddressFilterService; | |||
public JT808TransmitAddressFilterServiceTest() | |||
{ | |||
var serverHostBuilder = new HostBuilder() | |||
.ConfigureAppConfiguration((hostingContext, config) => | |||
{ | |||
config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); | |||
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); | |||
}) | |||
.ConfigureServices((hostContext, services) => | |||
{ | |||
services.AddSingleton<ILoggerFactory, LoggerFactory>(); | |||
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); | |||
services.Configure<JT808Configuration>(hostContext.Configuration.GetSection("JT808Configuration")); | |||
services.AddSingleton<JT808TransmitAddressFilterService>(); | |||
}); | |||
var serviceProvider = serverHostBuilder.Build().Services; | |||
jT808TransmitAddressFilterService = serviceProvider.GetService<JT808TransmitAddressFilterService>(); | |||
jT808TransmitAddressFilterService.Add(new Dtos.JT808IPAddressDto | |||
{ | |||
Host = "127.0.0.1", | |||
Port = 12345 | |||
}); | |||
jT808TransmitAddressFilterService.Add(new Dtos.JT808IPAddressDto | |||
{ | |||
Host = "127.0.0.1", | |||
Port = 12346 | |||
}); | |||
jT808TransmitAddressFilterService.Add(new Dtos.JT808IPAddressDto | |||
{ | |||
Host = "127.0.0.1", | |||
Port = 12347 | |||
}); | |||
jT808TransmitAddressFilterService.Add(new Dtos.JT808IPAddressDto | |||
{ | |||
Host = "127.0.0.1", | |||
Port = 12348 | |||
}); | |||
} | |||
[Fact] | |||
public void Test1() | |||
{ | |||
Assert.True(jT808TransmitAddressFilterService.ContainsKey(new Dtos.JT808IPAddressDto | |||
{ | |||
Host = "127.0.0.1", | |||
Port = 12348 | |||
}.EndPoint)); | |||
} | |||
[Fact] | |||
public void Test2() | |||
{ | |||
var result = jT808TransmitAddressFilterService.GetAll(); | |||
} | |||
[Fact] | |||
public void Test3() | |||
{ | |||
var ip1 = new Dtos.JT808IPAddressDto | |||
{ | |||
Host = "127.0.0.1", | |||
Port = 12349 | |||
}; | |||
var result1= jT808TransmitAddressFilterService.Add(ip1); | |||
Assert.Equal(JT808ResultCode.Ok, result1.Code); | |||
Assert.True(result1.Data); | |||
var result2 = jT808TransmitAddressFilterService.Remove(ip1); | |||
Assert.Equal(JT808ResultCode.Ok, result2.Code); | |||
Assert.True(result2.Data); | |||
} | |||
[Fact] | |||
public void Test4() | |||
{ | |||
var configIp = new Dtos.JT808IPAddressDto | |||
{ | |||
Host = "127.0.0.1", | |||
Port = 6561 | |||
}; | |||
var result2 = jT808TransmitAddressFilterService.Remove(configIp); | |||
Assert.Equal(JT808ResultCode.Ok, result2.Code); | |||
Assert.False(result2.Data); | |||
Assert.Equal("不能删除服务器配置的地址", result2.Message); | |||
} | |||
} | |||
} |
@@ -1,87 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Codecs; | |||
using DotNetty.Transport.Bootstrapping; | |||
using DotNetty.Transport.Channels; | |||
using DotNetty.Transport.Libuv; | |||
using JT808.DotNetty.Codecs; | |||
using JT808.DotNetty.Dtos; | |||
using JT808.Protocol; | |||
using JT808.Protocol.Extensions; | |||
using JT808.Protocol.MessageBody; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Net.Http; | |||
using System.Runtime.InteropServices; | |||
using System.Text; | |||
using System.Threading; | |||
using Xunit; | |||
namespace JT808.DotNetty.Test.Internal | |||
{ | |||
public class JT808UnificationSendServiceDefaultImplTest : TestBase | |||
{ | |||
private IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6565); | |||
public JT808SimpleTcpClient SimpleTcpClient; | |||
public JT808UnificationSendServiceDefaultImplTest() | |||
{ | |||
SimpleTcpClient = new JT808SimpleTcpClient(endPoint); | |||
} | |||
[Fact] | |||
public void Test1() | |||
{ | |||
// 文本信息包 | |||
JT808Package jT808Package2 = JT808.Protocol.Enums.JT808MsgId.文本信息下发.Create("123456789012", new JT808_0x8300 | |||
{ | |||
TextFlag = 5, | |||
TextInfo = "smallchi 518" | |||
}); | |||
var data = JT808Serializer.Serialize(jT808Package2); | |||
JT808UnificationSendRequestDto jT808UnificationSendRequestDto = new JT808UnificationSendRequestDto(); | |||
jT808UnificationSendRequestDto.TerminalPhoneNo = "123456789012"; | |||
jT808UnificationSendRequestDto.Data = data; | |||
HttpClient httpClient = new HttpClient(); | |||
// 调用内置的http服务接收文本信息下发 | |||
var result = httpClient.PostAsync("http://127.0.0.1:828/jt808api/UnificationSend", new StringContent(JsonConvert.SerializeObject(jT808UnificationSendRequestDto))).Result; | |||
string content = result.Content.ReadAsStringAsync().Result; | |||
JT808ResultDto<bool> jt808Result = JsonConvert.DeserializeObject<JT808ResultDto<bool>>(content); | |||
Assert.Equal(200, jt808Result.Code); | |||
Assert.False(jt808Result.Data); | |||
} | |||
[Fact] | |||
public void Test2() | |||
{ | |||
// 心跳会话包 | |||
JT808Package jT808Package1 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789012"); | |||
SimpleTcpClient.WriteAsync(JT808Serializer.Serialize(jT808Package1)); | |||
// 文本信息包 | |||
JT808Package jT808Package2 = JT808.Protocol.Enums.JT808MsgId.文本信息下发.Create("123456789012", new JT808_0x8300 | |||
{ | |||
TextFlag=5, | |||
TextInfo= "smallchi 518" | |||
}); | |||
var data = JT808Serializer.Serialize(jT808Package2); | |||
JT808UnificationSendRequestDto jT808UnificationSendRequestDto = new JT808UnificationSendRequestDto(); | |||
jT808UnificationSendRequestDto.TerminalPhoneNo = "123456789012"; | |||
jT808UnificationSendRequestDto.Data = data; | |||
HttpClient httpClient = new HttpClient(); | |||
// 调用内置的http服务接收文本信息下发 | |||
var result =httpClient.PostAsync("http://127.0.0.1:828/jt808api/UnificationSend", new StringContent(JsonConvert.SerializeObject(jT808UnificationSendRequestDto))).Result; | |||
string content = result.Content.ReadAsStringAsync().Result; | |||
JT808ResultDto<bool> jt808Result = JsonConvert.DeserializeObject<JT808ResultDto<bool>>(content); | |||
Assert.Equal(200, jt808Result.Code); | |||
Assert.True(jt808Result.Data); | |||
SimpleTcpClient.Down(); | |||
} | |||
} | |||
} |
@@ -1,32 +0,0 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<TargetFramework>netcoreapp2.2</TargetFramework> | |||
<IsPackable>false</IsPackable> | |||
<LangVersion>7.1</LangVersion> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" /> | |||
<PackageReference Include="xunit" Version="2.4.1" /> | |||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1"> | |||
<PrivateAssets>all</PrivateAssets> | |||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> | |||
</PackageReference> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\JT808.DotNetty\JT808.DotNetty.csproj" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Update="appsettings.json"> | |||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||
</None> | |||
</ItemGroup> | |||
</Project> |
@@ -1,39 +0,0 @@ | |||
using DotNetty.Transport.Channels; | |||
using JT808.DotNetty.Metadata; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Test | |||
{ | |||
public class JT808DefaultChannelId : IChannelId | |||
{ | |||
private static readonly JT808AtomicCounter jT808AtomicCounter = new JT808AtomicCounter(); | |||
private string Id { | |||
get | |||
{ | |||
return Guid.NewGuid().ToString("N"); | |||
} | |||
} | |||
public string AsLongText() | |||
{ | |||
return Id; | |||
} | |||
public string AsShortText() | |||
{ | |||
return Id; | |||
} | |||
public int CompareTo(IChannelId other) | |||
{ | |||
if(other.AsShortText()== Id) | |||
{ | |||
return 1; | |||
} | |||
return 0; | |||
} | |||
} | |||
} |
@@ -1,85 +0,0 @@ | |||
using DotNetty.Transport.Channels.Embedded; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using System.Threading; | |||
using Xunit; | |||
namespace JT808.DotNetty.Test | |||
{ | |||
public class JT808SessionManagerTest: SeedSession | |||
{ | |||
[Fact] | |||
public void Test1() | |||
{ | |||
var no = "test150"; | |||
var channel = new EmbeddedChannel(new JT808DefaultChannelId()); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel, no)); | |||
Thread.Sleep(1000); | |||
jT808SessionManager.Heartbeat(no); | |||
} | |||
[Fact] | |||
public void Test2() | |||
{ | |||
var no = "test151"; | |||
var channel = new EmbeddedChannel(new JT808DefaultChannelId()); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel, no)); | |||
var sessionInfo = jT808SessionManager.RemoveSession(no); | |||
Assert.Equal(no, sessionInfo.TerminalPhoneNo); | |||
} | |||
[Fact] | |||
public void Test3() | |||
{ | |||
var realSessionInfos = jT808SessionManager.GetAll(); | |||
} | |||
[Fact] | |||
public void Test4() | |||
{ | |||
var realSessionCount = jT808SessionManager.SessionCount; | |||
} | |||
[Fact] | |||
public void Test5() | |||
{ | |||
//转发过来的数据 1:n 一个通道对应多个设备 | |||
var no = "test1"; | |||
var no1 = "test2"; | |||
var no2 = "test3"; | |||
var no3 = "test4"; | |||
var no4 = "test5"; | |||
var channel = new EmbeddedChannel(new JT808DefaultChannelId()); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel, no)); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel, no1)); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel, no2)); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel, no3)); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel, no4)); | |||
var removeSession = jT808SessionManager.RemoveSession(no); | |||
Assert.Equal(no, removeSession.TerminalPhoneNo); | |||
Assert.Equal(channel, removeSession.Channel); | |||
Assert.Equal(channel.Id, removeSession.Channel.Id); | |||
} | |||
[Fact] | |||
public void Test6() | |||
{ | |||
//转发过来的数据 1:n 一个通道对应多个设备 | |||
var no = "test61"; | |||
var no1 = "test62"; | |||
var no2 = "test63"; | |||
var no3 = "test64"; | |||
var no4 = "test65"; | |||
var channel1 = new EmbeddedChannel(new JT808DefaultChannelId()); | |||
var channel2 = new EmbeddedChannel(new JT808DefaultChannelId()); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel1, no)); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel1, no1)); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel1, no2)); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel2, no3)); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel2, no4)); | |||
jT808SessionManager.RemoveSessionByChannel(channel1); | |||
} | |||
} | |||
} |
@@ -1,90 +0,0 @@ | |||
using JT808.DotNetty.Dtos; | |||
using JT808.Protocol; | |||
using JT808.Protocol.Extensions; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Net; | |||
using System.Net.Http; | |||
using System.Text; | |||
using System.Threading; | |||
using Xunit; | |||
namespace JT808.DotNetty.Test | |||
{ | |||
public class JT808WebAPIServiceTest: TestBase | |||
{ | |||
private IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6565); | |||
public JT808SimpleTcpClient SimpleTcpClient; | |||
private HttpClient httpClient; | |||
private const string Url = "http://127.0.0.1:828/jt808api"; | |||
private const string sessionRoutePrefix = "Session"; | |||
private const int length = 10; | |||
public JT808WebAPIServiceTest() | |||
{ | |||
SimpleTcpClient = new JT808SimpleTcpClient(endPoint); | |||
httpClient = new HttpClient(); | |||
for (var i = 1; i <= length; i++) | |||
{ | |||
// 心跳会话包 | |||
JT808Package jT808Package1 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create($"{i.ToString()}"); | |||
SimpleTcpClient.WriteAsync(JT808Serializer.Serialize(jT808Package1)); | |||
} | |||
Thread.Sleep(300); | |||
} | |||
[Fact] | |||
public void GetAllTest() | |||
{ | |||
var result = httpClient.GetAsync($"{Url}/{sessionRoutePrefix}/GetAll").Result; | |||
string content = result.Content.ReadAsStringAsync().Result; | |||
JT808ResultDto<IEnumerable<JT808SessionInfoDto>> jt808Result = JsonConvert.DeserializeObject<JT808ResultDto<IEnumerable<JT808SessionInfoDto>>>(content); | |||
Assert.Equal(200, jt808Result.Code); | |||
Assert.Equal(10,jt808Result.Data.Count()); | |||
} | |||
[Fact] | |||
public void RemoveByChannelIdTest() | |||
{ | |||
// 心跳会话包 | |||
JT808Package jT808Package1 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("99"); | |||
SimpleTcpClient.WriteAsync(JT808Serializer.Serialize(jT808Package1)); | |||
var result4 = httpClient.PostAsync($"{Url}/{sessionRoutePrefix}/RemoveByChannelId", new StringContent("99")).Result; | |||
string content4 = result4.Content.ReadAsStringAsync().Result; | |||
JT808ResultDto<bool> jt808Result4= JsonConvert.DeserializeObject<JT808ResultDto<bool>>(content4); | |||
Assert.Equal(200, jt808Result4.Code); | |||
Assert.True(jt808Result4.Data); | |||
} | |||
[Fact] | |||
public void RemoveByTerminalPhoneNoTest() | |||
{ | |||
// 心跳会话包 | |||
JT808Package jT808Package1 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("999"); | |||
SimpleTcpClient.WriteAsync(JT808Serializer.Serialize(jT808Package1)); | |||
var result4 = httpClient.PostAsync($"{Url}/{sessionRoutePrefix}/RemoveByTerminalPhoneNo", new StringContent("999")).Result; | |||
string content4 = result4.Content.ReadAsStringAsync().Result; | |||
JT808ResultDto<bool> jt808Result4 = JsonConvert.DeserializeObject<JT808ResultDto<bool>>(content4); | |||
Assert.Equal(200, jt808Result4.Code); | |||
Assert.True(jt808Result4.Data); | |||
} | |||
public override void Dispose() | |||
{ | |||
base.Dispose(); | |||
SimpleTcpClient.Down(); | |||
} | |||
} | |||
} |
@@ -1,36 +0,0 @@ | |||
using DotNetty.Transport.Channels.Embedded; | |||
using JT808.DotNetty.Internal; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using Xunit; | |||
namespace JT808.DotNetty.Test | |||
{ | |||
public class SeedSession | |||
{ | |||
public JT808SessionManager jT808SessionManager = new JT808SessionManager( | |||
new JT808SessionPublishingEmptyImpl(), | |||
new LoggerFactory()); | |||
public SeedSession() | |||
{ | |||
for (var i = 0; i < 10; i++) | |||
{ | |||
var channel = new EmbeddedChannel(new JT808DefaultChannelId()); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel, i.ToString())); | |||
} | |||
} | |||
[Fact] | |||
public void Init() | |||
{ | |||
for (var i = 0; i < 10; i++) | |||
{ | |||
var channel = new EmbeddedChannel(new JT808DefaultChannelId()); | |||
jT808SessionManager.TryAdd(new Metadata.JT808Session(channel, i.ToString())); | |||
} | |||
} | |||
} | |||
} |
@@ -1,46 +0,0 @@ | |||
using JT808.DotNetty.Codecs; | |||
using JT808.DotNetty.Configurations; | |||
using JT808.DotNetty.Handlers; | |||
using JT808.DotNetty.Interfaces; | |||
using JT808.DotNetty.Internal; | |||
using Microsoft.Extensions.Configuration; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.DependencyInjection.Extensions; | |||
using Microsoft.Extensions.Hosting; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Net; | |||
using Xunit; | |||
namespace JT808.DotNetty.Test | |||
{ | |||
public class TestBase:IDisposable | |||
{ | |||
public static IServiceProvider ServiceProvider; | |||
static TestBase() | |||
{ | |||
var serverHostBuilder = new HostBuilder() | |||
.ConfigureAppConfiguration((hostingContext, config) => | |||
{ | |||
config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); | |||
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); | |||
}) | |||
.ConfigureServices((hostContext, services) => | |||
{ | |||
services.AddSingleton<ILoggerFactory, LoggerFactory>(); | |||
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); | |||
}) | |||
.UseJT808Host(); | |||
var build = serverHostBuilder.Build(); | |||
build.Start(); | |||
ServiceProvider = build.Services; | |||
} | |||
public virtual void Dispose() | |||
{ | |||
} | |||
} | |||
} |
@@ -1,39 +0,0 @@ | |||
{ | |||
"Logging": { | |||
"IncludeScopes": false, | |||
"Debug": { | |||
"LogLevel": { | |||
"Default": "Trace" | |||
} | |||
}, | |||
"Console": { | |||
"LogLevel": { | |||
"Default": "Trace" | |||
} | |||
} | |||
}, | |||
"JT808Configuration": { | |||
"Port": 6565, | |||
"SourcePackageDispatcherClientConfigurations": [ | |||
{ | |||
"Host": "127.0.0.1", | |||
"Port": 6655 | |||
}, | |||
{ | |||
"Host": "127.0.0.1", | |||
"Port": 6656 | |||
} | |||
], | |||
"ForwardingRemoteAddress": [ | |||
{ | |||
"Host": "127.0.0.1", | |||
"Port": 6561 | |||
}, | |||
{ | |||
"Host": "127.0.0.1", | |||
"Port": 6562 | |||
} | |||
], | |||
"RedisHost": "127.0.0.1:6379" | |||
} | |||
} |
@@ -1,59 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Codecs; | |||
using DotNetty.Transport.Channels; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Collections.Generic; | |||
using JT808.Protocol; | |||
using JT808.DotNetty.Metadata; | |||
namespace JT808.DotNetty.Codecs | |||
{ | |||
/// <summary> | |||
/// JT808客户端解码(测试客户端) | |||
/// </summary> | |||
internal class JT808ClientDecoder : ByteToMessageDecoder | |||
{ | |||
private static readonly ILogger<JT808ClientDecoder> logger=new LoggerFactory().CreateLogger<JT808ClientDecoder>(); | |||
private static readonly JT808AtomicCounter MsgSuccessCounter = new JT808AtomicCounter(); | |||
private static readonly JT808AtomicCounter MsgFailCounter = new JT808AtomicCounter(); | |||
protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> output) | |||
{ | |||
byte[] buffer = new byte[input.Capacity + 2]; | |||
try | |||
{ | |||
input.ReadBytes(buffer, 1, input.Capacity); | |||
buffer[0] = JT808Package.BeginFlag; | |||
buffer[input.Capacity + 1] = JT808Package.EndFlag; | |||
JT808Package jT808Package = JT808Serializer.Deserialize<JT808Package>(buffer); | |||
MsgSuccessCounter.Increment(); | |||
output.Add(jT808Package); | |||
if (logger.IsEnabled(LogLevel.Debug)) | |||
{ | |||
logger.LogDebug("accept package success count<<<" + MsgSuccessCounter.Count.ToString()); | |||
} | |||
} | |||
catch (JT808.Protocol.Exceptions.JT808Exception ex) | |||
{ | |||
MsgFailCounter.Increment(); | |||
if (logger.IsEnabled(LogLevel.Error)) | |||
{ | |||
logger.LogError("accept package fail count<<<" + MsgFailCounter.Count.ToString()); | |||
logger.LogError(ex, "accept msg<<<" + buffer); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
MsgFailCounter.Increment(); | |||
if (logger.IsEnabled(LogLevel.Error)) | |||
{ | |||
logger.LogError("accept package fail count<<<" + MsgFailCounter.Count.ToString()); | |||
logger.LogError(ex, "accept msg<<<" + buffer); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,28 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Codecs; | |||
using DotNetty.Transport.Channels; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using JT808.Protocol; | |||
using JT808.DotNetty.Internal; | |||
using JT808.DotNetty.Interfaces; | |||
namespace JT808.DotNetty.Codecs | |||
{ | |||
/// <summary> | |||
/// JT808解码 | |||
/// </summary> | |||
internal class JT808Decoder : ByteToMessageDecoder | |||
{ | |||
protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> 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); | |||
} | |||
} | |||
} |
@@ -1,31 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Codecs; | |||
using DotNetty.Transport.Channels; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using JT808.Protocol; | |||
using JT808.DotNetty.Internal; | |||
using JT808.DotNetty.Interfaces; | |||
using DotNetty.Transport.Channels.Sockets; | |||
using JT808.DotNetty.Metadata; | |||
namespace JT808.DotNetty.Codecs | |||
{ | |||
/// <summary> | |||
/// JT808 UDP解码 | |||
/// </summary> | |||
internal class JT808UDPDecoder : MessageToMessageDecoder<DatagramPacket> | |||
{ | |||
protected override void Decode(IChannelHandlerContext context, DatagramPacket message, List<object> output) | |||
{ | |||
IByteBuffer byteBuffer = message.Content; | |||
byte[] buffer = new byte[byteBuffer.ReadableBytes]; | |||
byteBuffer.ReadBytes(buffer); | |||
output.Add(new JT808UDPPackage(buffer, message.Sender)); | |||
} | |||
} | |||
} |
@@ -1,35 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Text; | |||
namespace JT808.DotNetty.Configurations | |||
{ | |||
public class JT808ClientConfiguration | |||
{ | |||
public string Host { get; set; } | |||
public int Port { get; set; } | |||
private EndPoint endPoint; | |||
public EndPoint EndPoint | |||
{ | |||
get | |||
{ | |||
if (endPoint == null) | |||
{ | |||
if (IPAddress.TryParse(Host, out IPAddress ip)) | |||
{ | |||
endPoint = new IPEndPoint(ip, Port); | |||
} | |||
else | |||
{ | |||
endPoint = new DnsEndPoint(Host, Port); | |||
} | |||
} | |||
return endPoint; | |||
} | |||
} | |||
} | |||
} |
@@ -1,54 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Configurations | |||
{ | |||
public class JT808Configuration | |||
{ | |||
public int Port { get; set; } = 808; | |||
public int UDPPort { get; set; } = 809; | |||
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; | |||
/// <summary> | |||
/// WebApi服务 | |||
/// 默认828端口 | |||
/// </summary> | |||
public int WebApiPort { get; set; } = 828; | |||
/// <summary> | |||
/// 源包分发器配置 | |||
/// </summary> | |||
public List<JT808ClientConfiguration> SourcePackageDispatcherClientConfigurations { get; set; } | |||
/// <summary> | |||
/// 转发远程地址 (可选项)知道转发的地址有利于提升性能 | |||
/// 按照808的消息,有些请求必须要应答,但是转发可以不需要有应答可以节省部分资源包括: | |||
// 1.消息的序列化 | |||
// 2.消息的下发 | |||
// 都有一定的性能损耗,那么不需要判断写超时 IdleState.WriterIdle | |||
// 就跟神兽貔貅一样。。。 | |||
/// </summary> | |||
public List<JT808ClientConfiguration> ForwardingRemoteAddress { get; set; } | |||
public string RedisHost { get; set; } | |||
} | |||
} |
@@ -1,16 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Dtos | |||
{ | |||
/// <summary> | |||
/// 包计数器服务 | |||
/// </summary> | |||
public class JT808AtomicCounterDto | |||
{ | |||
public long MsgSuccessCount { get; set; } | |||
public long MsgFailCount { get; set; } | |||
} | |||
} |
@@ -1,15 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Dtos | |||
{ | |||
public class JT808DefaultResultDto: JT808ResultDto<string> | |||
{ | |||
public JT808DefaultResultDto() | |||
{ | |||
Data = "Hello,JT808 WebAPI"; | |||
Code = JT808ResultCode.Ok; | |||
} | |||
} | |||
} |
@@ -1,35 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Text; | |||
namespace JT808.DotNetty.Dtos | |||
{ | |||
public class JT808IPAddressDto | |||
{ | |||
public string Host { get; set; } | |||
public int Port { get; set; } | |||
private EndPoint endPoint; | |||
public EndPoint EndPoint | |||
{ | |||
get | |||
{ | |||
if (endPoint == null) | |||
{ | |||
if (IPAddress.TryParse(Host, out IPAddress ip)) | |||
{ | |||
endPoint = new IPEndPoint(ip, Port); | |||
} | |||
else | |||
{ | |||
endPoint = new DnsEndPoint(Host, Port); | |||
} | |||
} | |||
return endPoint; | |||
} | |||
} | |||
} | |||
} |
@@ -1,24 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Dtos | |||
{ | |||
public class JT808ResultDto<T> | |||
{ | |||
public string Message { get; set; } | |||
public int Code { get; set; } | |||
public T Data { get; set; } | |||
} | |||
internal 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; | |||
} | |||
} |
@@ -1,30 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Dtos | |||
{ | |||
public class JT808SessionInfoDto | |||
{ | |||
/// <summary> | |||
/// 通道Id | |||
/// </summary> | |||
public string ChannelId { get; set; } | |||
/// <summary> | |||
/// 最后上线时间 | |||
/// </summary> | |||
public DateTime LastActiveTime { get; set; } | |||
/// <summary> | |||
/// 上线时间 | |||
/// </summary> | |||
public DateTime StartTime { get; set; } | |||
/// <summary> | |||
/// 终端手机号 | |||
/// </summary> | |||
public string TerminalPhoneNo { get; set; } | |||
/// <summary> | |||
/// 远程ip地址 | |||
/// </summary> | |||
public string RemoteAddressIP { get; set; } | |||
} | |||
} |
@@ -1,33 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Dtos | |||
{ | |||
/// <summary> | |||
/// 原包通道信息 | |||
/// </summary> | |||
public class JT808SourcePackageChannelInfoDto | |||
{ | |||
/// <summary> | |||
/// 远程地址 | |||
/// </summary> | |||
public string RemoteAddress { get; set; } | |||
/// <summary> | |||
/// 本地地址 | |||
/// </summary> | |||
public string LocalAddress { get; set; } | |||
/// <summary> | |||
/// 是否注册 | |||
/// </summary> | |||
public bool Registered { get; set; } | |||
/// <summary> | |||
/// 是否活动 | |||
/// </summary> | |||
public bool Active { get; set; } | |||
/// <summary> | |||
/// 是否打开 | |||
/// </summary> | |||
public bool Open { get; set; } | |||
} | |||
} |
@@ -1,15 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Dtos | |||
{ | |||
/// <summary> | |||
/// 统一下发请求参数 | |||
/// </summary> | |||
public class JT808UnificationSendRequestDto | |||
{ | |||
public string TerminalPhoneNo { get; set; } | |||
public byte[] Data { get; set; } | |||
} | |||
} |
@@ -1,107 +0,0 @@ | |||
using DotNetty.Handlers.Timeout; | |||
using DotNetty.Transport.Channels; | |||
using JT808.DotNetty.Metadata; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace JT808.DotNetty.Handlers | |||
{ | |||
/// <summary> | |||
/// JT808服务通道处理程序 | |||
/// </summary> | |||
internal class JT808ConnectionHandler : ChannelHandlerAdapter | |||
{ | |||
private readonly ILogger<JT808ConnectionHandler> logger; | |||
private readonly JT808SessionManager jT808SessionManager; | |||
public JT808ConnectionHandler( | |||
JT808SessionManager jT808SessionManager, | |||
ILoggerFactory loggerFactory) | |||
{ | |||
this.jT808SessionManager = jT808SessionManager; | |||
logger = loggerFactory.CreateLogger<JT808ConnectionHandler>(); | |||
} | |||
/// <summary> | |||
/// 通道激活 | |||
/// </summary> | |||
/// <param name="context"></param> | |||
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); | |||
} | |||
/// <summary> | |||
/// 设备主动断开 | |||
/// </summary> | |||
/// <param name="context"></param> | |||
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); | |||
} | |||
/// <summary> | |||
/// 服务器主动断开 | |||
/// </summary> | |||
/// <param name="context"></param> | |||
/// <returns></returns> | |||
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(); | |||
/// <summary> | |||
/// 超时策略 | |||
/// </summary> | |||
/// <param name="context"></param> | |||
/// <param name="evt"></param> | |||
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(); | |||
} | |||
} | |||
} | |||
@@ -1,96 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Transport.Channels; | |||
using JT808.Protocol; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using JT808.DotNetty.Metadata; | |||
using JT808.DotNetty.Internal; | |||
using JT808.DotNetty.Interfaces; | |||
using Microsoft.Extensions.Logging; | |||
namespace JT808.DotNetty.Handlers | |||
{ | |||
/// <summary> | |||
/// JT808服务端处理程序 | |||
/// </summary> | |||
internal class JT808ServerHandler : SimpleChannelInboundHandler<byte[]> | |||
{ | |||
private readonly JT808MsgIdHandlerBase handler; | |||
private readonly JT808SessionManager jT808SessionManager; | |||
private readonly JT808TransmitAddressFilterService jT808TransmitAddressFilterService; | |||
private readonly IJT808SourcePackageDispatcher jT808SourcePackageDispatcher; | |||
private readonly JT808AtomicCounterService jT808AtomicCounterService; | |||
private readonly ILogger<JT808ServerHandler> logger; | |||
public JT808ServerHandler( | |||
ILoggerFactory loggerFactory, | |||
JT808TransmitAddressFilterService jT808TransmitAddressFilterService, | |||
IJT808SourcePackageDispatcher jT808SourcePackageDispatcher, | |||
JT808MsgIdHandlerBase handler, | |||
JT808AtomicCounterService jT808AtomicCounterService, | |||
JT808SessionManager jT808SessionManager) | |||
{ | |||
this.jT808TransmitAddressFilterService = jT808TransmitAddressFilterService; | |||
this.handler = handler; | |||
this.jT808SessionManager = jT808SessionManager; | |||
this.jT808SourcePackageDispatcher = jT808SourcePackageDispatcher; | |||
this.jT808AtomicCounterService = jT808AtomicCounterService; | |||
logger = loggerFactory.CreateLogger<JT808ServerHandler>(); | |||
} | |||
protected override void ChannelRead0(IChannelHandlerContext ctx, byte[] msg) | |||
{ | |||
try | |||
{ | |||
jT808SourcePackageDispatcher?.SendAsync(msg); | |||
//解析到头部,然后根据具体的消息Id通过队列去进行消费 | |||
//要是一定要解析到数据体可以在JT808MsgIdHandlerBase类中根据具体的消息, | |||
//解析具体的消息体,具体调用JT808Serializer.Deserialize<T> | |||
JT808HeaderPackage jT808HeaderPackage = JT808Serializer.Deserialize<JT808HeaderPackage>(msg); | |||
jT808AtomicCounterService.MsgSuccessIncrement(); | |||
if (logger.IsEnabled(LogLevel.Debug)) | |||
{ | |||
logger.LogDebug("accept package success count<<<" + jT808AtomicCounterService.MsgSuccessCount.ToString()); | |||
} | |||
jT808SessionManager.TryAdd(new JT808Session(ctx.Channel, jT808HeaderPackage.Header.TerminalPhoneNo)); | |||
Func<JT808Request, JT808Response> handlerFunc; | |||
if (handler.HandlerDict.TryGetValue(jT808HeaderPackage.Header.MsgId, out handlerFunc)) | |||
{ | |||
JT808Response jT808Response = handlerFunc(new JT808Request(jT808HeaderPackage, msg)); | |||
if (jT808Response != null) | |||
{ | |||
if (!jT808TransmitAddressFilterService.ContainsKey(ctx.Channel.RemoteAddress)) | |||
{ | |||
ctx.WriteAndFlushAsync(Unpooled.WrappedBuffer(JT808Serializer.Serialize(jT808Response.Package, jT808Response.MinBufferSize))); | |||
} | |||
} | |||
} | |||
} | |||
catch (JT808.Protocol.Exceptions.JT808Exception ex) | |||
{ | |||
jT808AtomicCounterService.MsgFailIncrement(); | |||
if (logger.IsEnabled(LogLevel.Error)) | |||
{ | |||
logger.LogError("accept package fail count<<<" + jT808AtomicCounterService.MsgFailCount.ToString()); | |||
logger.LogError(ex, "accept msg<<<" + ByteBufferUtil.HexDump(msg)); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
jT808AtomicCounterService.MsgFailIncrement(); | |||
if (logger.IsEnabled(LogLevel.Error)) | |||
{ | |||
logger.LogError("accept package fail count<<<" + jT808AtomicCounterService.MsgFailCount.ToString()); | |||
logger.LogError(ex, "accept msg<<<" + ByteBufferUtil.HexDump(msg)); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,70 +0,0 @@ | |||
using DotNetty.Transport.Channels; | |||
using JT808.DotNetty.Internal; | |||
using Microsoft.Extensions.Logging; | |||
using Polly; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Net; | |||
using System.Text; | |||
namespace JT808.DotNetty.Handlers | |||
{ | |||
internal class JT808SourcePackageDispatcherHandler: ChannelHandlerAdapter | |||
{ | |||
private readonly ILogger<JT808SourcePackageDispatcherHandler> logger; | |||
private readonly JT808SourcePackageChannelService jT808SourcePackageChannelService; | |||
public JT808SourcePackageDispatcherHandler(JT808SourcePackageChannelService jT808SourcePackageChannelService) | |||
{ | |||
logger= jT808SourcePackageChannelService.LoggerFactory.CreateLogger<JT808SourcePackageDispatcherHandler>(); | |||
this.jT808SourcePackageChannelService = jT808SourcePackageChannelService; | |||
} | |||
public override void ChannelInactive(IChannelHandlerContext context) | |||
{ | |||
Policy.HandleResult<bool>(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($"Server Disconnection {context.Channel.RemoteAddress.ToString()},Retry Results{exception.Result},Retry Number{timespan},Next Retry Interval(s){ctx.TotalSeconds}"); | |||
}) | |||
.ExecuteAsync(async () => | |||
{ | |||
try | |||
{ | |||
var newChannel = jT808SourcePackageChannelService.channels.FirstOrDefault(m => m.Value == context.Channel); | |||
if (default(KeyValuePair<EndPoint, IChannel>).Equals(newChannel)) | |||
{ | |||
if(logger.IsEnabled(LogLevel.Debug)) | |||
logger.LogDebug($"Server already deleted {context.Channel.RemoteAddress.ToString()} remote server configuration"); | |||
return true; | |||
} | |||
var channel = await jT808SourcePackageChannelService.bootstrap.ConnectAsync(context.Channel.RemoteAddress); | |||
jT808SourcePackageChannelService.channels.AddOrUpdate(newChannel.Key, channel, (x, y) => channel); | |||
return channel.Open; | |||
} | |||
catch (Exception ex) | |||
{ | |||
logger.LogError(ex,$"Reconnection abnormal:After the server is disconnected {context.Channel.RemoteAddress.ToString()}"); | |||
return false; | |||
} | |||
}); | |||
} | |||
public override void ChannelRead(IChannelHandlerContext context, object message) | |||
{ | |||
if(logger.IsEnabled(LogLevel.Debug)) | |||
logger.LogDebug($"The server returns a message {message.ToString()}"); | |||
} | |||
public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) | |||
{ | |||
logger.LogError(exception, context.Channel.RemoteAddress.ToString()); | |||
context.CloseAsync(); | |||
} | |||
} | |||
} |
@@ -1,88 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Transport.Channels; | |||
using JT808.Protocol; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using JT808.DotNetty.Metadata; | |||
using JT808.DotNetty.Internal; | |||
using JT808.DotNetty.Interfaces; | |||
using Microsoft.Extensions.Logging; | |||
using DotNetty.Transport.Channels.Sockets; | |||
namespace JT808.DotNetty.Handlers | |||
{ | |||
/// <summary> | |||
/// JT808 UDP服务端处理程序 | |||
/// </summary> | |||
internal class JT808UDPServerHandler : SimpleChannelInboundHandler<JT808UDPPackage> | |||
{ | |||
private readonly JT808MsgIdHandlerBase handler; | |||
private readonly JT808SessionManager jT808SessionManager; | |||
private readonly IJT808SourcePackageDispatcher jT808SourcePackageDispatcher; | |||
private readonly JT808AtomicCounterService jT808AtomicCounterService; | |||
private readonly ILogger<JT808UDPServerHandler> logger; | |||
public JT808UDPServerHandler( | |||
ILoggerFactory loggerFactory, | |||
IJT808SourcePackageDispatcher jT808SourcePackageDispatcher, | |||
JT808MsgIdHandlerBase handler, | |||
JT808AtomicCounterService jT808AtomicCounterService, | |||
JT808SessionManager jT808SessionManager) | |||
{ | |||
this.handler = handler; | |||
this.jT808SessionManager = jT808SessionManager; | |||
this.jT808SourcePackageDispatcher = jT808SourcePackageDispatcher; | |||
this.jT808AtomicCounterService = jT808AtomicCounterService; | |||
logger = loggerFactory.CreateLogger<JT808UDPServerHandler>(); | |||
} | |||
protected override void ChannelRead0(IChannelHandlerContext ctx, JT808UDPPackage msg) | |||
{ | |||
try | |||
{ | |||
jT808SourcePackageDispatcher?.SendAsync(msg.Buffer); | |||
//解析到头部,然后根据具体的消息Id通过队列去进行消费 | |||
//要是一定要解析到数据体可以在JT808MsgIdHandlerBase类中根据具体的消息, | |||
//解析具体的消息体,具体调用JT808Serializer.Deserialize<T> | |||
JT808HeaderPackage jT808HeaderPackage = JT808Serializer.Deserialize<JT808HeaderPackage>(msg.Buffer); | |||
jT808AtomicCounterService.MsgSuccessIncrement(); | |||
if (logger.IsEnabled(LogLevel.Debug)) | |||
{ | |||
logger.LogDebug("accept package success count<<<" + jT808AtomicCounterService.MsgSuccessCount.ToString()); | |||
} | |||
Func<JT808Request, JT808Response> handlerFunc; | |||
if (handler.HandlerDict.TryGetValue(jT808HeaderPackage.Header.MsgId, out handlerFunc)) | |||
{ | |||
JT808Response jT808Response = handlerFunc(new JT808Request(jT808HeaderPackage, msg.Buffer)); | |||
if (jT808Response != null) | |||
{ | |||
ctx.WriteAndFlushAsync(new DatagramPacket(Unpooled.WrappedBuffer(JT808Serializer.Serialize(jT808Response.Package, jT808Response.MinBufferSize)), msg.Sender)); | |||
} | |||
} | |||
} | |||
catch (JT808.Protocol.Exceptions.JT808Exception ex) | |||
{ | |||
jT808AtomicCounterService.MsgFailIncrement(); | |||
if (logger.IsEnabled(LogLevel.Error)) | |||
{ | |||
logger.LogError("accept package fail count<<<" + jT808AtomicCounterService.MsgFailCount.ToString()); | |||
logger.LogError(ex, "accept msg<<<" + ByteBufferUtil.HexDump(msg.Buffer)); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
jT808AtomicCounterService.MsgFailIncrement(); | |||
if (logger.IsEnabled(LogLevel.Error)) | |||
{ | |||
logger.LogError("accept package fail count<<<" + jT808AtomicCounterService.MsgFailCount.ToString()); | |||
logger.LogError(ex, "accept msg<<<" + ByteBufferUtil.HexDump(msg.Buffer)); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,82 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Codecs.Http; | |||
using DotNetty.Common.Utilities; | |||
using DotNetty.Transport.Channels; | |||
using JT808.DotNetty.Internal; | |||
using JT808.DotNetty.Metadata; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Text; | |||
namespace JT808.DotNetty.Handlers | |||
{ | |||
/// <summary> | |||
/// jt808 webapi服务 | |||
/// 请求量不大,只支持JSON格式并且只支持post发数据 | |||
/// ref: dotnetty HttpServer | |||
/// </summary> | |||
internal class JT808WebAPIServerHandler : SimpleChannelInboundHandler<IFullHttpRequest> | |||
{ | |||
private static readonly AsciiString TypeJson = AsciiString.Cached("application/json"); | |||
private static readonly AsciiString ServerName = AsciiString.Cached("JT808WebAPINetty"); | |||
private static readonly AsciiString ContentTypeEntity = HttpHeaderNames.ContentType; | |||
private static readonly AsciiString DateEntity = HttpHeaderNames.Date; | |||
private static readonly AsciiString ContentLengthEntity = HttpHeaderNames.ContentLength; | |||
private static readonly AsciiString ServerEntity = HttpHeaderNames.Server; | |||
private readonly JT808WebAPIService jT808WebAPIService; | |||
private readonly ILogger<JT808WebAPIServerHandler> logger; | |||
public JT808WebAPIServerHandler( | |||
JT808WebAPIService jT808WebAPIService, | |||
ILoggerFactory loggerFactory) | |||
{ | |||
this.jT808WebAPIService = jT808WebAPIService; | |||
logger = loggerFactory.CreateLogger<JT808WebAPIServerHandler>(); | |||
} | |||
protected override void ChannelRead0(IChannelHandlerContext ctx, IFullHttpRequest msg) | |||
{ | |||
if (logger.IsEnabled(LogLevel.Debug)) | |||
{ | |||
logger.LogDebug($"Uri:{msg.Uri}"); | |||
logger.LogDebug($"Content:{msg.Content.ToString(Encoding.UTF8)}"); | |||
} | |||
JT808HttpResponse jT808HttpResponse = null; | |||
if (jT808WebAPIService.HandlerDict.TryGetValue(msg.Uri,out var funcHandler)) | |||
{ | |||
jT808HttpResponse = funcHandler( new JT808HttpRequest() { Json = msg.Content.ToString(Encoding.UTF8)}); | |||
} | |||
else | |||
{ | |||
jT808HttpResponse = jT808WebAPIService.NotFoundHttpResponse(); | |||
} | |||
if (jT808HttpResponse != null) | |||
{ | |||
WriteResponse(ctx, Unpooled.WrappedBuffer(jT808HttpResponse.Data), TypeJson, jT808HttpResponse.Data.Length); | |||
} | |||
} | |||
private void WriteResponse(IChannelHandlerContext ctx, IByteBuffer buf, ICharSequence contentType, int contentLength) | |||
{ | |||
// Build the response object. | |||
var response = new DefaultFullHttpResponse(HttpVersion.Http11, HttpResponseStatus.OK, buf, false); | |||
HttpHeaders headers = response.Headers; | |||
headers.Set(ContentTypeEntity, contentType); | |||
headers.Set(ServerEntity, ServerName); | |||
headers.Set(DateEntity, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")); | |||
headers.Set(ContentLengthEntity, contentLength); | |||
// Close the non-keep-alive connection after the write operation is done. | |||
ctx.WriteAndFlushAsync(response); | |||
ctx.CloseAsync(); | |||
} | |||
public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) | |||
{ | |||
WriteResponse(context, Unpooled.WrappedBuffer(jT808WebAPIService.ErrorHttpResponse(exception).Data), TypeJson, jT808WebAPIService.ErrorHttpResponse(exception).Data.Length); | |||
logger.LogError(exception, exception.Message); | |||
context.CloseAsync(); | |||
} | |||
public override void ChannelReadComplete(IChannelHandlerContext context) => context.Flush(); | |||
} | |||
} |
@@ -1,12 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace JT808.DotNetty.Interfaces | |||
{ | |||
public interface IJT808SessionPublishing | |||
{ | |||
Task PublishAsync(string topicName, string key, string value); | |||
} | |||
} |
@@ -1,25 +0,0 @@ | |||
using JT808.DotNetty.Dtos; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Interfaces | |||
{ | |||
/// <summary> | |||
/// JT808会话服务 | |||
/// </summary> | |||
internal interface IJT808SessionService | |||
{ | |||
/// <summary> | |||
/// 获取会话集合 | |||
/// </summary> | |||
/// <returns></returns> | |||
JT808ResultDto<List<JT808SessionInfoDto>> GetAll(); | |||
/// <summary> | |||
/// 通过设备终端号移除对应会话 | |||
/// </summary> | |||
/// <param name="terminalPhoneNo"></param> | |||
/// <returns></returns> | |||
JT808ResultDto<bool> RemoveByTerminalPhoneNo(string terminalPhoneNo); | |||
} | |||
} |
@@ -1,18 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace JT808.DotNetty.Interfaces | |||
{ | |||
/// <summary> | |||
/// 源包分发器 | |||
/// 自定义源包分发器业务 | |||
/// ConfigureServices: | |||
/// services.Replace(new ServiceDescriptor(typeof(IJT808SourcePackageDispatcher),typeof(JT808SourcePackageDispatcherDefaultImpl),ServiceLifetime.Singleton)); | |||
/// </summary> | |||
public interface IJT808SourcePackageDispatcher | |||
{ | |||
Task SendAsync(byte[] data); | |||
} | |||
} |
@@ -1,15 +0,0 @@ | |||
using JT808.DotNetty.Dtos; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Interfaces | |||
{ | |||
/// <summary> | |||
/// JT808统一下发命令 | |||
/// </summary> | |||
internal interface IJT808UnificationSendService | |||
{ | |||
JT808ResultDto<bool> Send(string terminalPhoneNo, byte[] data); | |||
} | |||
} |
@@ -1,48 +0,0 @@ | |||
using JT808.DotNetty.Metadata; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Internal | |||
{ | |||
/// <summary> | |||
/// 计数包服务 | |||
/// </summary> | |||
internal class JT808AtomicCounterService | |||
{ | |||
private static readonly JT808AtomicCounter MsgSuccessCounter = new JT808AtomicCounter(); | |||
private static readonly JT808AtomicCounter MsgFailCounter = new JT808AtomicCounter(); | |||
public JT808AtomicCounterService() | |||
{ | |||
} | |||
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; | |||
} | |||
} | |||
} | |||
} |
@@ -1,16 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Internal | |||
{ | |||
/// <summary> | |||
/// 默认消息处理业务实现 | |||
/// </summary> | |||
internal class JT808MsgIdDefaultHandler : JT808MsgIdHandlerBase | |||
{ | |||
public JT808MsgIdDefaultHandler(JT808SessionManager sessionManager) : base(sessionManager) | |||
{ | |||
} | |||
} | |||
} |
@@ -1,16 +0,0 @@ | |||
using JT808.DotNetty.Interfaces; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace JT808.DotNetty.Internal | |||
{ | |||
internal class JT808SessionPublishingEmptyImpl : IJT808SessionPublishing | |||
{ | |||
public Task PublishAsync(string topicName, string key, string value) | |||
{ | |||
return Task.CompletedTask; | |||
} | |||
} | |||
} |
@@ -1,75 +0,0 @@ | |||
using JT808.DotNetty.Interfaces; | |||
using System; | |||
using System.Threading.Tasks; | |||
using StackExchange.Redis; | |||
using Microsoft.Extensions.Options; | |||
using JT808.DotNetty.Configurations; | |||
namespace JT808.DotNetty.Internal | |||
{ | |||
internal class JT808SessionPublishingRedisImpl : IJT808SessionPublishing,IDisposable | |||
{ | |||
private IConnectionMultiplexer connectionMultiplexer; | |||
private IOptionsMonitor<JT808Configuration> optionsMonitor; | |||
private string redisHost; | |||
private IDisposable optionsMonitorDisposable; | |||
public JT808SessionPublishingRedisImpl( | |||
IOptionsMonitor<JT808Configuration> optionsMonitor | |||
) | |||
{ | |||
this.optionsMonitor = optionsMonitor; | |||
redisHost = optionsMonitor.CurrentValue.RedisHost; | |||
try | |||
{ | |||
connectionMultiplexer = ConnectionMultiplexer.Connect(redisHost); | |||
} | |||
catch | |||
{ | |||
} | |||
optionsMonitorDisposable= this.optionsMonitor.OnChange((config,str) => | |||
{ | |||
if(config.RedisHost!= redisHost) | |||
{ | |||
redisHost = config.RedisHost; | |||
connectionMultiplexer.Close(); | |||
try | |||
{ | |||
connectionMultiplexer = ConnectionMultiplexer.Connect(redisHost); | |||
} | |||
catch | |||
{ | |||
} | |||
} | |||
}); | |||
} | |||
public Task PublishAsync(string topicName, string key, string value) | |||
{ | |||
if (connectionMultiplexer.IsConnected) | |||
{ | |||
Subscriber?.PublishAsync(topicName, value); | |||
} | |||
return Task.CompletedTask; | |||
} | |||
internal ISubscriber Subscriber | |||
{ | |||
get | |||
{ | |||
return connectionMultiplexer.GetSubscriber(); | |||
} | |||
} | |||
public void Dispose() | |||
{ | |||
connectionMultiplexer.Close(); | |||
optionsMonitorDisposable.Dispose(); | |||
} | |||
} | |||
} |
@@ -1,77 +0,0 @@ | |||
using JT808.DotNetty.Dtos; | |||
using JT808.DotNetty.Interfaces; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Runtime.CompilerServices; | |||
using Microsoft.Extensions.Options; | |||
using JT808.DotNetty.Configurations; | |||
namespace JT808.DotNetty.Internal | |||
{ | |||
internal class JT808SessionServiceDefaultImpl : IJT808SessionService | |||
{ | |||
private readonly JT808SessionManager jT808SessionManager; | |||
public JT808SessionServiceDefaultImpl( | |||
JT808SessionManager jT808SessionManager) | |||
{ | |||
this.jT808SessionManager = jT808SessionManager; | |||
} | |||
public JT808ResultDto<List<JT808SessionInfoDto>> GetAll() | |||
{ | |||
JT808ResultDto<List<JT808SessionInfoDto>> resultDto = new JT808ResultDto<List<JT808SessionInfoDto>>(); | |||
try | |||
{ | |||
resultDto.Data = jT808SessionManager.GetAll().Select(s => new JT808SessionInfoDto | |||
{ | |||
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 = Newtonsoft.Json.JsonConvert.SerializeObject(ex); | |||
} | |||
return resultDto; | |||
} | |||
public JT808ResultDto<bool> RemoveByTerminalPhoneNo(string terminalPhoneNo) | |||
{ | |||
JT808ResultDto<bool> resultDto = new JT808ResultDto<bool>(); | |||
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 = Newtonsoft.Json.JsonConvert.SerializeObject(ex); | |||
} | |||
catch (Exception ex) | |||
{ | |||
resultDto.Data = false; | |||
resultDto.Code = JT808ResultCode.Error; | |||
resultDto.Message = Newtonsoft.Json.JsonConvert.SerializeObject(ex); | |||
} | |||
return resultDto; | |||
} | |||
} | |||
} |
@@ -1,290 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Transport.Bootstrapping; | |||
using DotNetty.Transport.Channels; | |||
using DotNetty.Transport.Channels.Sockets; | |||
using JT808.DotNetty.Configurations; | |||
using JT808.DotNetty.Dtos; | |||
using JT808.DotNetty.Handlers; | |||
using Microsoft.Extensions.Logging; | |||
using Microsoft.Extensions.Options; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Net; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace JT808.DotNetty.Internal | |||
{ | |||
/// <summary> | |||
/// 原包分发器通道服务 | |||
/// </summary> | |||
internal class JT808SourcePackageChannelService:IDisposable | |||
{ | |||
private readonly IOptionsMonitor<JT808Configuration> jT808ConfigurationOptionsMonitor; | |||
internal readonly ConcurrentDictionary<EndPoint, IChannel> channels; | |||
private readonly ILogger<JT808SourcePackageChannelService> logger; | |||
private readonly MultithreadEventLoopGroup group; | |||
internal readonly ILoggerFactory LoggerFactory; | |||
internal readonly Bootstrap bootstrap; | |||
private IDisposable jT808ConfigurationOptionsMonitorDisposable; | |||
public JT808SourcePackageChannelService( | |||
ILoggerFactory loggerFactory, | |||
IOptionsMonitor<JT808Configuration> jT808ConfigurationOptionsMonitor) | |||
{ | |||
this.LoggerFactory = loggerFactory; | |||
this.logger = loggerFactory.CreateLogger<JT808SourcePackageChannelService>(); | |||
this.channels = new ConcurrentDictionary<EndPoint, IChannel>(); | |||
this.jT808ConfigurationOptionsMonitor = jT808ConfigurationOptionsMonitor; | |||
this.group = new MultithreadEventLoopGroup(); | |||
this.bootstrap = new Bootstrap(); | |||
jT808ConfigurationOptionsMonitorDisposable = jT808ConfigurationOptionsMonitor.OnChange(options => | |||
{ | |||
List<JT808ClientConfiguration> chgRemoteServers = new List<JT808ClientConfiguration>(); | |||
if (jT808ConfigurationOptionsMonitor.CurrentValue.SourcePackageDispatcherClientConfigurations != null && jT808ConfigurationOptionsMonitor.CurrentValue.SourcePackageDispatcherClientConfigurations.Count > 0) | |||
{ | |||
chgRemoteServers = options.SourcePackageDispatcherClientConfigurations; | |||
} | |||
DelRemoteServsers(chgRemoteServers); | |||
AddRemoteServsers(chgRemoteServers); | |||
}); | |||
StartAsync(); | |||
} | |||
/// <summary> | |||
/// 下发数据 | |||
/// </summary> | |||
/// <param name="data"></param> | |||
/// <returns></returns> | |||
public Task SendAsync(byte[] data) | |||
{ | |||
foreach (var item in channels) | |||
{ | |||
try | |||
{ | |||
if (item.Value.Open && item.Value.Active) | |||
{ | |||
item.Value.WriteAndFlushAsync(Unpooled.WrappedBuffer(data)); | |||
} | |||
else | |||
{ | |||
logger.LogInformation($"{item} link closed."); | |||
} | |||
} | |||
catch (AggregateException ex) | |||
{ | |||
logger.LogError(ex, $"{item} Send Data Error."); | |||
} | |||
catch (Exception ex) | |||
{ | |||
logger.LogError(ex, $"{item} Send Data Error."); | |||
} | |||
} | |||
return Task.CompletedTask; | |||
} | |||
/// <summary> | |||
/// 获取通道信息集合 | |||
/// </summary> | |||
/// <returns></returns> | |||
public JT808ResultDto<List<JT808SourcePackageChannelInfoDto>> GetAll() | |||
{ | |||
JT808ResultDto<List<JT808SourcePackageChannelInfoDto>> jT808ResultDto = new JT808ResultDto<List<JT808SourcePackageChannelInfoDto>>(); | |||
jT808ResultDto.Data = new List<JT808SourcePackageChannelInfoDto>(); | |||
jT808ResultDto.Code = JT808ResultCode.Ok; | |||
foreach (var item in channels) | |||
{ | |||
JT808SourcePackageChannelInfoDto jT808SourcePackageChannelInfoDto = new JT808SourcePackageChannelInfoDto(); | |||
jT808SourcePackageChannelInfoDto.Active = item.Value.Active; | |||
jT808SourcePackageChannelInfoDto.Open = item.Value.Open; | |||
jT808SourcePackageChannelInfoDto.Registered = item.Value.Registered; | |||
jT808SourcePackageChannelInfoDto.LocalAddress = item.Value.LocalAddress.ToString().Replace("[::ffff:", "").Replace("]", ""); | |||
jT808SourcePackageChannelInfoDto.RemoteAddress = item.Value.RemoteAddress.ToString().Replace("[::ffff:", "").Replace("]", ""); | |||
jT808ResultDto.Data.Add(jT808SourcePackageChannelInfoDto); | |||
} | |||
return jT808ResultDto; | |||
} | |||
/// <summary> | |||
/// 添加地址 | |||
/// </summary> | |||
/// <returns></returns> | |||
public async Task<JT808ResultDto<bool>> Add(JT808IPAddressDto jT808IPAddressDto) | |||
{ | |||
JT808ResultDto<bool> jT808ResultDto = new JT808ResultDto<bool>(); | |||
jT808ResultDto.Code= JT808ResultCode.Ok; | |||
jT808ResultDto.Data = true; | |||
if (!channels.ContainsKey(jT808IPAddressDto.EndPoint)) | |||
{ | |||
try | |||
{ | |||
IChannel clientChannel = await bootstrap.ConnectAsync(jT808IPAddressDto.EndPoint); | |||
channels.TryAdd(jT808IPAddressDto.EndPoint, clientChannel); | |||
} | |||
catch (AggregateException ex) | |||
{ | |||
jT808ResultDto.Data = false; | |||
jT808ResultDto.Code = JT808ResultCode.Error; | |||
jT808ResultDto.Message = JsonConvert.SerializeObject(ex); | |||
} | |||
catch (Exception ex) | |||
{ | |||
jT808ResultDto.Data = false; | |||
jT808ResultDto.Code= JT808ResultCode.Error; | |||
jT808ResultDto.Message = JsonConvert.SerializeObject(ex); | |||
} | |||
} | |||
return jT808ResultDto; | |||
} | |||
/// <summary> | |||
/// 删除地址 | |||
/// </summary> | |||
/// <returns></returns> | |||
public async Task<JT808ResultDto<bool>> Remove(JT808IPAddressDto jT808IPAddressDto) | |||
{ | |||
JT808ResultDto<bool> jT808ResultDto = new JT808ResultDto<bool>(); | |||
jT808ResultDto.Code = JT808ResultCode.Ok; | |||
jT808ResultDto.Data = true; | |||
if(jT808ConfigurationOptionsMonitor.CurrentValue.SourcePackageDispatcherClientConfigurations!=null && | |||
jT808ConfigurationOptionsMonitor.CurrentValue.SourcePackageDispatcherClientConfigurations.Any(a=>a.EndPoint.ToString()== jT808IPAddressDto.EndPoint.ToString()) | |||
) | |||
{ | |||
jT808ResultDto.Data = false; | |||
jT808ResultDto.Message = "不能删除服务器配置的地址"; | |||
} | |||
else | |||
{ | |||
if (channels.TryRemove(jT808IPAddressDto.EndPoint, out var channel)) | |||
{ | |||
try | |||
{ | |||
await channel.CloseAsync(); | |||
} | |||
catch (AggregateException ex) | |||
{ | |||
jT808ResultDto.Data = false; | |||
jT808ResultDto.Code = JT808ResultCode.Error; | |||
jT808ResultDto.Message = JsonConvert.SerializeObject(ex); | |||
} | |||
catch (Exception ex) | |||
{ | |||
jT808ResultDto.Data = false; | |||
jT808ResultDto.Code = JT808ResultCode.Error; | |||
jT808ResultDto.Message = JsonConvert.SerializeObject(ex); | |||
} | |||
} | |||
} | |||
return jT808ResultDto; | |||
} | |||
private void StartAsync() | |||
{ | |||
bootstrap | |||
.Group(group) | |||
.Channel<TcpSocketChannel>() | |||
.Option(ChannelOption.TcpNodelay, true) | |||
.Handler(new ActionChannelInitializer<IChannel>(channel => | |||
{ | |||
channel.Pipeline.AddLast(new JT808SourcePackageDispatcherHandler(this)); | |||
})); | |||
if (jT808ConfigurationOptionsMonitor.CurrentValue.SourcePackageDispatcherClientConfigurations != null && | |||
jT808ConfigurationOptionsMonitor.CurrentValue.SourcePackageDispatcherClientConfigurations.Count > 0) | |||
{ | |||
foreach (var item in jT808ConfigurationOptionsMonitor.CurrentValue.SourcePackageDispatcherClientConfigurations) | |||
{ | |||
try | |||
{ | |||
Task.Run(async () => | |||
{ | |||
IChannel clientChannel = await bootstrap.ConnectAsync(item.EndPoint); | |||
channels.TryAdd(item.EndPoint, clientChannel); | |||
logger.LogInformation($"init remote link {item.EndPoint.ToString()}."); | |||
}); | |||
} | |||
catch (Exception ex) | |||
{ | |||
logger.LogError(ex, $"there is an exception in sending data {item}."); | |||
} | |||
} | |||
} | |||
} | |||
private Task StopAsync() | |||
{ | |||
foreach (var channel in channels) | |||
{ | |||
try | |||
{ | |||
channel.Value.CloseAsync(); | |||
} | |||
catch | |||
{ | |||
} | |||
} | |||
group.ShutdownGracefullyAsync(jT808ConfigurationOptionsMonitor.CurrentValue.QuietPeriodTimeSpan, jT808ConfigurationOptionsMonitor.CurrentValue.ShutdownTimeoutTimeSpan); | |||
return Task.CompletedTask; | |||
} | |||
/// <summary> | |||
/// 动态删除远程服务器 | |||
/// </summary> | |||
/// <param name="chgRemoteServers"></param> | |||
private void DelRemoteServsers(List<JT808ClientConfiguration> chgRemoteServers) | |||
{ | |||
var delChannels = channels.Keys.Except(chgRemoteServers.Select(s => s.EndPoint)).ToList(); | |||
foreach (var item in delChannels) | |||
{ | |||
try | |||
{ | |||
channels.TryRemove(item, out var channel); | |||
channel.CloseAsync(); | |||
} | |||
catch | |||
{ | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// 动态添加远程服务器 | |||
/// </summary> | |||
/// <param name="bootstrap"></param> | |||
/// <param name="chgRemoteServers"></param> | |||
private async void AddRemoteServsers(List<JT808ClientConfiguration> chgRemoteServers) | |||
{ | |||
var addChannels = chgRemoteServers.Select(s => s.EndPoint).Except(channels.Keys).ToList(); | |||
foreach (var item in addChannels) | |||
{ | |||
try | |||
{ | |||
IChannel clientChannel = await bootstrap.ConnectAsync(item); | |||
channels.TryAdd(item, clientChannel); | |||
logger.LogInformation($"link to the remote server after the change {item}."); | |||
} | |||
catch (Exception ex) | |||
{ | |||
logger.LogError(ex, $"reconnect the remote server after the exception changes {item}."); | |||
} | |||
} | |||
} | |||
public void Dispose() | |||
{ | |||
jT808ConfigurationOptionsMonitorDisposable.Dispose(); | |||
StopAsync(); | |||
} | |||
} | |||
} |
@@ -1,39 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Transport.Bootstrapping; | |||
using DotNetty.Transport.Channels; | |||
using DotNetty.Transport.Channels.Sockets; | |||
using JT808.DotNetty.Configurations; | |||
using JT808.DotNetty.Handlers; | |||
using JT808.DotNetty.Interfaces; | |||
using Microsoft.Extensions.Hosting; | |||
using Microsoft.Extensions.Logging; | |||
using Microsoft.Extensions.Options; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Net; | |||
using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace JT808.DotNetty.Internal | |||
{ | |||
/// <summary> | |||
/// 原包分发器默认实现 | |||
/// </summary> | |||
internal class JT808SourcePackageDispatcherDefaultImpl : IJT808SourcePackageDispatcher | |||
{ | |||
private readonly JT808SourcePackageChannelService jT808SourcePackageChannelService; | |||
public JT808SourcePackageDispatcherDefaultImpl(JT808SourcePackageChannelService jT808SourcePackageChannelService) | |||
{ | |||
this.jT808SourcePackageChannelService = jT808SourcePackageChannelService; | |||
} | |||
public async Task SendAsync(byte[] data) | |||
{ | |||
await jT808SourcePackageChannelService.SendAsync(data); | |||
} | |||
} | |||
} |
@@ -1,88 +0,0 @@ | |||
using JT808.DotNetty.Configurations; | |||
using JT808.DotNetty.Dtos; | |||
using Microsoft.Extensions.Options; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Net; | |||
namespace JT808.DotNetty.Internal | |||
{ | |||
/// <summary> | |||
/// JT808转发地址过滤服务 | |||
/// 按照808的消息,有些请求必须要应答,但是转发可以不需要有应答可以节省部分资源包括: | |||
// 1.消息的序列化 | |||
// 2.消息的下发 | |||
// 都有一定的性能损耗,那么不需要判断写超时 IdleState.WriterIdle | |||
// 就跟神兽貔貅一样。。。 | |||
/// </summary> | |||
public class JT808TransmitAddressFilterService : IDisposable | |||
{ | |||
private readonly IOptionsMonitor<JT808Configuration> jT808ConfigurationOptionsMonitor; | |||
private ConcurrentDictionary<string,int> ForwardingRemoteAddresssDict; | |||
private IDisposable jT808ConfigurationOptionsMonitorDisposable; | |||
public JT808TransmitAddressFilterService( | |||
IOptionsMonitor<JT808Configuration> jT808ConfigurationOptionsMonitor) | |||
{ | |||
this.jT808ConfigurationOptionsMonitor = jT808ConfigurationOptionsMonitor; | |||
ForwardingRemoteAddresssDict = new ConcurrentDictionary<string, int>(); | |||
InitForwardingRemoteAddress(jT808ConfigurationOptionsMonitor.CurrentValue.ForwardingRemoteAddress); | |||
//OnChange 源码多播委托 | |||
jT808ConfigurationOptionsMonitorDisposable = this.jT808ConfigurationOptionsMonitor.OnChange(options => | |||
{ | |||
InitForwardingRemoteAddress(options.ForwardingRemoteAddress); | |||
}); | |||
} | |||
private void InitForwardingRemoteAddress(List<JT808ClientConfiguration> jT808ClientConfigurations) | |||
{ | |||
if (jT808ClientConfigurations != null && jT808ClientConfigurations.Count > 0) | |||
{ | |||
foreach (var item in jT808ClientConfigurations) | |||
{ | |||
string host = item.EndPoint.ToString(); | |||
ForwardingRemoteAddresssDict.TryAdd(host, 0); | |||
} | |||
} | |||
} | |||
public bool ContainsKey(EndPoint endPoint) | |||
{ | |||
return ForwardingRemoteAddresssDict.ContainsKey(endPoint.ToString()); | |||
} | |||
public JT808ResultDto<bool> Add(JT808IPAddressDto jT808IPAddressDto) | |||
{ | |||
string host = jT808IPAddressDto.EndPoint.ToString(); | |||
return new JT808ResultDto<bool>() { Code = JT808ResultCode.Ok, Data = ForwardingRemoteAddresssDict.TryAdd(host,0) }; | |||
} | |||
public JT808ResultDto<bool> Remove(JT808IPAddressDto jT808IPAddressDto) | |||
{ | |||
string host = jT808IPAddressDto.EndPoint.ToString(); | |||
if(jT808ConfigurationOptionsMonitor.CurrentValue.ForwardingRemoteAddress!=null && | |||
jT808ConfigurationOptionsMonitor.CurrentValue.ForwardingRemoteAddress.Any(w=>w.EndPoint.ToString()== host)) | |||
{ | |||
return new JT808ResultDto<bool>() { Code = JT808ResultCode.Ok, Data = false,Message="不能删除服务器配置的地址" }; | |||
} | |||
else | |||
{ | |||
return new JT808ResultDto<bool>() { Code = JT808ResultCode.Ok, Data = ForwardingRemoteAddresssDict.TryRemove(host,out var temp) }; | |||
} | |||
} | |||
public JT808ResultDto<List<string>> GetAll() | |||
{ | |||
return new JT808ResultDto<List<string>>(){ Code = JT808ResultCode.Ok, Data = ForwardingRemoteAddresssDict.Select(s=>s.Key).ToList() }; | |||
} | |||
public void Dispose() | |||
{ | |||
jT808ConfigurationOptionsMonitorDisposable.Dispose(); | |||
} | |||
} | |||
} |
@@ -1,56 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using JT808.DotNetty.Dtos; | |||
using JT808.DotNetty.Interfaces; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Internal | |||
{ | |||
internal class JT808UnificationSendServiceDefaultImpl : IJT808UnificationSendService | |||
{ | |||
private readonly JT808SessionManager jT808SessionManager; | |||
public JT808UnificationSendServiceDefaultImpl(JT808SessionManager jT808SessionManager) | |||
{ | |||
this.jT808SessionManager = jT808SessionManager; | |||
} | |||
public JT808ResultDto<bool> Send(string terminalPhoneNo, byte[] data) | |||
{ | |||
JT808ResultDto<bool> resultDto = new JT808ResultDto<bool>(); | |||
try | |||
{ | |||
var session = jT808SessionManager.GetSession(terminalPhoneNo); | |||
if (session != null) | |||
{ | |||
if (session.Channel.Open) | |||
{ | |||
session.Channel.WriteAndFlushAsync(Unpooled.WrappedBuffer(data)); | |||
resultDto.Code = JT808ResultCode.Ok; | |||
resultDto.Data = true; | |||
} | |||
else | |||
{ | |||
resultDto.Code = JT808ResultCode.Ok; | |||
resultDto.Data = false; | |||
resultDto.Message = "offline"; | |||
} | |||
} | |||
else | |||
{ | |||
resultDto.Code = JT808ResultCode.Ok; | |||
resultDto.Data = false; | |||
resultDto.Message = "offline"; | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
resultDto.Data = false; | |||
resultDto.Code = JT808ResultCode.Error; | |||
resultDto.Message = Newtonsoft.Json.JsonConvert.SerializeObject(ex); | |||
} | |||
return resultDto; | |||
} | |||
} | |||
} |
@@ -1,253 +0,0 @@ | |||
using JT808.DotNetty.Dtos; | |||
using JT808.DotNetty.Interfaces; | |||
using JT808.DotNetty.Metadata; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Internal | |||
{ | |||
/// <summary> | |||
/// JT808 WebApi 业务服务 | |||
/// </summary> | |||
internal class JT808WebAPIService | |||
{ | |||
public Dictionary<string, Func<JT808HttpRequest, JT808HttpResponse>> HandlerDict { get; protected set; } | |||
private const string RouteTablePrefix = "/jt808api"; | |||
private const string sessionRoutePrefix = "Session"; | |||
private const string sourcePackagePrefix = "SourcePackage"; | |||
private const string transmitPrefix = "Transmit"; | |||
private readonly IJT808SessionService jT808SessionService; | |||
private readonly IJT808UnificationSendService jT808UnificationSendService; | |||
private readonly JT808AtomicCounterService jT808AtomicCounterService; | |||
private readonly JT808SourcePackageChannelService jT808SourcePackageChannelService; | |||
private readonly JT808TransmitAddressFilterService jT808TransmitAddressFilterService; | |||
/// <summary> | |||
/// 初始化消息处理业务 | |||
/// </summary> | |||
public JT808WebAPIService( | |||
JT808AtomicCounterService jT808AtomicCounterService, | |||
JT808SourcePackageChannelService jT808SourcePackageChannelService, | |||
JT808TransmitAddressFilterService jT808TransmitAddressFilterService, | |||
IJT808SessionService jT808SessionService, | |||
IJT808UnificationSendService jT808UnificationSendService) | |||
{ | |||
this.jT808AtomicCounterService = jT808AtomicCounterService; | |||
this.jT808SourcePackageChannelService = jT808SourcePackageChannelService; | |||
this.jT808TransmitAddressFilterService = jT808TransmitAddressFilterService; | |||
this.jT808SessionService = jT808SessionService; | |||
this.jT808UnificationSendService = jT808UnificationSendService; | |||
HandlerDict = new Dictionary<string, Func<JT808HttpRequest, JT808HttpResponse>> | |||
{ | |||
{$"{RouteTablePrefix}/UnificationSend", UnificationSend}, | |||
{$"{RouteTablePrefix}/{sessionRoutePrefix}/GetAll", GetSessionAll}, | |||
{$"{RouteTablePrefix}/{sessionRoutePrefix}/RemoveByTerminalPhoneNo", RemoveByTerminalPhoneNo}, | |||
{$"{RouteTablePrefix}/GetAtomicCounter", GetAtomicCounter}, | |||
{$"{RouteTablePrefix}/{sourcePackagePrefix}/Add", AddSourcePackageAddress}, | |||
{$"{RouteTablePrefix}/{sourcePackagePrefix}/Remove", RemoveSourcePackageAddress}, | |||
{$"{RouteTablePrefix}/{sourcePackagePrefix}/GetAll", GetSourcePackageAll}, | |||
{$"{RouteTablePrefix}/{transmitPrefix}/Add", AddTransmitAddress}, | |||
{$"{RouteTablePrefix}/{transmitPrefix}/Remove", RemoveTransmitAddress}, | |||
{$"{RouteTablePrefix}/{transmitPrefix}/GetAll", GetTransmitAll}, | |||
}; | |||
} | |||
/// <summary> | |||
/// 统一下发信息 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public JT808HttpResponse UnificationSend(JT808HttpRequest request) | |||
{ | |||
if (string.IsNullOrEmpty(request.Json)) | |||
{ | |||
return EmptyHttpResponse(); | |||
} | |||
JT808UnificationSendRequestDto jT808UnificationSendRequestDto = JsonConvert.DeserializeObject<JT808UnificationSendRequestDto>(request.Json); | |||
var result = jT808UnificationSendService.Send(jT808UnificationSendRequestDto.TerminalPhoneNo, jT808UnificationSendRequestDto.Data); | |||
return CreateJT808HttpResponse(result); | |||
} | |||
/// <summary> | |||
/// 会话服务集合 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public JT808HttpResponse GetSessionAll(JT808HttpRequest request) | |||
{ | |||
var result = jT808SessionService.GetAll(); | |||
return CreateJT808HttpResponse(result); | |||
} | |||
/// <summary> | |||
/// 会话服务-通过设备终端号移除对应会话 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public JT808HttpResponse RemoveByTerminalPhoneNo(JT808HttpRequest request) | |||
{ | |||
if (string.IsNullOrEmpty(request.Json)) | |||
{ | |||
return EmptyHttpResponse(); | |||
} | |||
var result = jT808SessionService.RemoveByTerminalPhoneNo(request.Json); | |||
return CreateJT808HttpResponse(result); | |||
} | |||
/// <summary> | |||
/// 获取包计数器 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public JT808HttpResponse GetAtomicCounter(JT808HttpRequest request) | |||
{ | |||
JT808AtomicCounterDto jT808AtomicCounterDto = new JT808AtomicCounterDto(); | |||
jT808AtomicCounterDto.MsgFailCount = jT808AtomicCounterService.MsgFailCount; | |||
jT808AtomicCounterDto.MsgSuccessCount = jT808AtomicCounterService.MsgSuccessCount; | |||
return CreateJT808HttpResponse(new JT808ResultDto<JT808AtomicCounterDto> | |||
{ | |||
Code=JT808ResultCode.Ok, | |||
Data= jT808AtomicCounterDto | |||
}); | |||
} | |||
/// <summary> | |||
/// 添加原包转发地址 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public JT808HttpResponse AddSourcePackageAddress(JT808HttpRequest request) | |||
{ | |||
if (string.IsNullOrEmpty(request.Json)) | |||
{ | |||
return EmptyHttpResponse(); | |||
} | |||
JT808IPAddressDto jT808IPAddressDto = JsonConvert.DeserializeObject<JT808IPAddressDto>(request.Json); | |||
return CreateJT808HttpResponse(jT808SourcePackageChannelService.Add(jT808IPAddressDto).Result); | |||
} | |||
/// <summary> | |||
/// 删除原包转发地址(不能删除在网关服务器配置文件配的地址) | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public JT808HttpResponse RemoveSourcePackageAddress(JT808HttpRequest request) | |||
{ | |||
if (string.IsNullOrEmpty(request.Json)) | |||
{ | |||
return EmptyHttpResponse(); | |||
} | |||
JT808IPAddressDto jT808IPAddressDto = JsonConvert.DeserializeObject<JT808IPAddressDto>(request.Json); | |||
return CreateJT808HttpResponse(jT808SourcePackageChannelService.Remove(jT808IPAddressDto).Result); | |||
} | |||
/// <summary> | |||
/// 获取原包信息集合 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public JT808HttpResponse GetSourcePackageAll(JT808HttpRequest request) | |||
{ | |||
return CreateJT808HttpResponse(jT808SourcePackageChannelService.GetAll()); | |||
} | |||
/// <summary> | |||
/// 添加转发过滤地址 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public JT808HttpResponse AddTransmitAddress(JT808HttpRequest request) | |||
{ | |||
if (string.IsNullOrEmpty(request.Json)) | |||
{ | |||
return EmptyHttpResponse(); | |||
} | |||
JT808IPAddressDto jT808IPAddressDto = JsonConvert.DeserializeObject<JT808IPAddressDto>(request.Json); | |||
return CreateJT808HttpResponse(jT808TransmitAddressFilterService.Add(jT808IPAddressDto)); | |||
} | |||
/// <summary> | |||
/// 删除转发过滤地址(不能删除在网关服务器配置文件配的地址) | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public JT808HttpResponse RemoveTransmitAddress(JT808HttpRequest request) | |||
{ | |||
if (string.IsNullOrEmpty(request.Json)) | |||
{ | |||
return EmptyHttpResponse(); | |||
} | |||
JT808IPAddressDto jT808IPAddressDto = JsonConvert.DeserializeObject<JT808IPAddressDto>(request.Json); | |||
return CreateJT808HttpResponse(jT808TransmitAddressFilterService.Remove(jT808IPAddressDto)); | |||
} | |||
/// <summary> | |||
/// 获取转发过滤地址信息集合 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public JT808HttpResponse GetTransmitAll(JT808HttpRequest request) | |||
{ | |||
return CreateJT808HttpResponse(jT808TransmitAddressFilterService.GetAll()); | |||
} | |||
private JT808HttpResponse CreateJT808HttpResponse(dynamic dynamicObject) | |||
{ | |||
byte[] data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(dynamicObject)); | |||
return new JT808HttpResponse() | |||
{ | |||
Data = data | |||
}; | |||
} | |||
public JT808HttpResponse DefaultHttpResponse() | |||
{ | |||
byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT808DefaultResultDto())); | |||
return new JT808HttpResponse(json); | |||
} | |||
public JT808HttpResponse EmptyHttpResponse() | |||
{ | |||
byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT808ResultDto<string>() | |||
{ | |||
Code = JT808ResultCode.Empty, | |||
Message ="内容为空", | |||
Data="Content Empty" | |||
})); | |||
return new JT808HttpResponse(json); | |||
} | |||
public JT808HttpResponse NotFoundHttpResponse() | |||
{ | |||
byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT808ResultDto<string>() | |||
{ | |||
Code= JT808ResultCode.NotFound, | |||
Message="没有该服务", | |||
Data= "没有该服务" | |||
})); | |||
return new JT808HttpResponse(json); | |||
} | |||
public JT808HttpResponse ErrorHttpResponse(Exception ex) | |||
{ | |||
byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT808ResultDto<string>() | |||
{ | |||
Code = JT808ResultCode.Error, | |||
Message = JsonConvert.SerializeObject(ex), | |||
Data= ex.Message | |||
})); | |||
return new JT808HttpResponse(json); | |||
} | |||
} | |||
} |
@@ -1,46 +0,0 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<TargetFramework>netstandard2.0</TargetFramework> | |||
<LangVersion>latest</LangVersion> | |||
<Copyright>Copyright 2018.</Copyright> | |||
<Authors>SmallChi</Authors> | |||
<PackageId>JT808DotNetty</PackageId> | |||
<Product>JT808DotNetty</Product> | |||
<Description>基于DotNetty封装的JT808DotNetty专注消息业务处理</Description> | |||
<PackageReleaseNotes>基于DotNetty封装的JT808DotNetty专注消息业务处理</PackageReleaseNotes> | |||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance> | |||
<RepositoryUrl>https://github.com/SmallChi/JT808DotNetty</RepositoryUrl> | |||
<PackageProjectUrl>https://github.com/SmallChi/JT808DotNetty</PackageProjectUrl> | |||
<PackageLicenseUrl>https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE</PackageLicenseUrl> | |||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> | |||
<Version>1.0.0</Version> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> | |||
<DocumentationFile></DocumentationFile> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> | |||
<DocumentationFile>E:\koike\My Project\JT808DotNetty\src\JT808.DotNetty\JT808.DotNetty.xml</DocumentationFile> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<PackageReference Include="DotNetty.Codecs" Version="0.6.0" /> | |||
<PackageReference Include="DotNetty.Codecs.Http" Version="0.6.0" /> | |||
<PackageReference Include="DotNetty.Handlers" Version="0.6.0" /> | |||
<PackageReference Include="DotNetty.Transport.Libuv" Version="0.6.0" /> | |||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.Extensions.Options" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.2.0" /> | |||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" /> | |||
<PackageReference Include="Polly" Version="6.1.2" /> | |||
<PackageReference Include="StackExchange.Redis" Version="2.0.519" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\JT808.Protocol\src\JT808.Protocol\JT808.Protocol.csproj" /> | |||
</ItemGroup> | |||
</Project> |
@@ -1,418 +0,0 @@ | |||
<?xml version="1.0"?> | |||
<doc> | |||
<assembly> | |||
<name>JT808.DotNetty</name> | |||
</assembly> | |||
<members> | |||
<member name="T:JT808.DotNetty.Codecs.JT808ClientDecoder"> | |||
<summary> | |||
JT808客户端解码(测试客户端) | |||
</summary> | |||
</member> | |||
<member name="T:JT808.DotNetty.Codecs.JT808Decoder"> | |||
<summary> | |||
JT808解码 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Configurations.JT808Configuration.WebApiPort"> | |||
<summary> | |||
WebApi服务 | |||
默认828端口 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Configurations.JT808Configuration.SourcePackageDispatcherClientConfigurations"> | |||
<summary> | |||
源包分发器配置 | |||
</summary> | |||
</member> | |||
<!-- 对于成员“P:JT808.DotNetty.Configurations.JT808Configuration.ForwardingRemoteAddress”忽略有格式错误的 XML 注释 --> | |||
<member name="T:JT808.DotNetty.Dtos.JT808AtomicCounterDto"> | |||
<summary> | |||
包计数器服务 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Dtos.JT808SessionInfoDto.ChannelId"> | |||
<summary> | |||
通道Id | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Dtos.JT808SessionInfoDto.LastActiveTime"> | |||
<summary> | |||
最后上线时间 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Dtos.JT808SessionInfoDto.StartTime"> | |||
<summary> | |||
上线时间 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Dtos.JT808SessionInfoDto.TerminalPhoneNo"> | |||
<summary> | |||
终端手机号 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Dtos.JT808SessionInfoDto.LoaclAddressIP"> | |||
<summary> | |||
本地ip地址 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Dtos.JT808SessionInfoDto.WebApiPort"> | |||
<summary> | |||
WebApi端口号 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Dtos.JT808SessionInfoDto.RemoteAddressIP"> | |||
<summary> | |||
远程ip地址 | |||
</summary> | |||
</member> | |||
<member name="T:JT808.DotNetty.Dtos.JT808SourcePackageChannelInfoDto"> | |||
<summary> | |||
原包通道信息 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Dtos.JT808SourcePackageChannelInfoDto.RemoteAddress"> | |||
<summary> | |||
远程地址 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Dtos.JT808SourcePackageChannelInfoDto.LocalAddress"> | |||
<summary> | |||
本地地址 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Dtos.JT808SourcePackageChannelInfoDto.Registered"> | |||
<summary> | |||
是否注册 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Dtos.JT808SourcePackageChannelInfoDto.Active"> | |||
<summary> | |||
是否活动 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Dtos.JT808SourcePackageChannelInfoDto.Open"> | |||
<summary> | |||
是否打开 | |||
</summary> | |||
</member> | |||
<member name="T:JT808.DotNetty.Dtos.JT808UnificationSendRequestDto"> | |||
<summary> | |||
统一下发请求参数 | |||
</summary> | |||
</member> | |||
<member name="M:JT808.DotNetty.Handlers.JT808ConnectionHandler.ChannelActive(DotNetty.Transport.Channels.IChannelHandlerContext)"> | |||
<summary> | |||
通道激活 | |||
</summary> | |||
<param name="context"></param> | |||
</member> | |||
<member name="M:JT808.DotNetty.Handlers.JT808ConnectionHandler.ChannelInactive(DotNetty.Transport.Channels.IChannelHandlerContext)"> | |||
<summary> | |||
设备主动断开 | |||
</summary> | |||
<param name="context"></param> | |||
</member> | |||
<member name="M:JT808.DotNetty.Handlers.JT808ConnectionHandler.CloseAsync(DotNetty.Transport.Channels.IChannelHandlerContext)"> | |||
<summary> | |||
服务器主动断开 | |||
</summary> | |||
<param name="context"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Handlers.JT808ConnectionHandler.UserEventTriggered(DotNetty.Transport.Channels.IChannelHandlerContext,System.Object)"> | |||
<summary> | |||
超时策略 | |||
</summary> | |||
<param name="context"></param> | |||
<param name="evt"></param> | |||
</member> | |||
<member name="T:JT808.DotNetty.Handlers.JT808WebAPIServerHandler"> | |||
<summary> | |||
jt808 webapi服务 | |||
请求量不大,只支持JSON格式并且只支持post发数据 | |||
ref: dotnetty HttpServer | |||
</summary> | |||
</member> | |||
<member name="T:JT808.DotNetty.Interfaces.IJT808SessionService"> | |||
<summary> | |||
JT808会话服务 | |||
</summary> | |||
</member> | |||
<member name="M:JT808.DotNetty.Interfaces.IJT808SessionService.GetAll"> | |||
<summary> | |||
获取会话集合 | |||
</summary> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Interfaces.IJT808SessionService.RemoveByChannelId(System.String)"> | |||
<summary> | |||
通过通道Id移除对应会话 | |||
</summary> | |||
<param name="channelId"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Interfaces.IJT808SessionService.RemoveByTerminalPhoneNo(System.String)"> | |||
<summary> | |||
通过设备终端号移除对应会话 | |||
</summary> | |||
<param name="terminalPhoneNo"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="T:JT808.DotNetty.Interfaces.IJT808SourcePackageDispatcher"> | |||
<summary> | |||
源包分发器 | |||
自定义源包分发器业务 | |||
ConfigureServices: | |||
services.Replace(new ServiceDescriptor(typeof(IJT808SourcePackageDispatcher),typeof(JT808SourcePackageDispatcherDefaultImpl),ServiceLifetime.Singleton)); | |||
</summary> | |||
</member> | |||
<member name="T:JT808.DotNetty.Interfaces.IJT808UnificationSendService"> | |||
<summary> | |||
JT808统一下发命令 | |||
</summary> | |||
</member> | |||
<member name="T:JT808.DotNetty.Internal.JT808AtomicCounterService"> | |||
<summary> | |||
计数包服务 | |||
</summary> | |||
</member> | |||
<member name="T:JT808.DotNetty.Internal.JT808MsgIdDefaultHandler"> | |||
<summary> | |||
默认消息处理业务实现 | |||
</summary> | |||
</member> | |||
<!-- 对于成员“T:JT808.DotNetty.Internal.JT808RemoteAddressTransmitConfigurationService”忽略有格式错误的 XML 注释 --> | |||
<member name="T:JT808.DotNetty.Internal.JT808SourcePackageChannelService"> | |||
<summary> | |||
原包分发器通道服务 | |||
</summary> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808SourcePackageChannelService.SendAsync(System.Byte[])"> | |||
<summary> | |||
下发数据 | |||
</summary> | |||
<param name="data"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808SourcePackageChannelService.GetAll"> | |||
<summary> | |||
获取通道信息集合 | |||
</summary> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808SourcePackageChannelService.Add(JT808.DotNetty.Dtos.JT808IPAddressDto)"> | |||
<summary> | |||
添加地址 | |||
</summary> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808SourcePackageChannelService.Remove(JT808.DotNetty.Dtos.JT808IPAddressDto)"> | |||
<summary> | |||
删除地址 | |||
</summary> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808SourcePackageChannelService.DelRemoteServsers(System.Collections.Generic.List{JT808.DotNetty.Configurations.JT808ClientConfiguration})"> | |||
<summary> | |||
动态删除远程服务器 | |||
</summary> | |||
<param name="chgRemoteServers"></param> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808SourcePackageChannelService.AddRemoteServsers(System.Collections.Generic.List{JT808.DotNetty.Configurations.JT808ClientConfiguration})"> | |||
<summary> | |||
动态添加远程服务器 | |||
</summary> | |||
<param name="bootstrap"></param> | |||
<param name="chgRemoteServers"></param> | |||
</member> | |||
<member name="T:JT808.DotNetty.Internal.JT808SourcePackageDispatcherDefaultImpl"> | |||
<summary> | |||
原包分发器默认实现 | |||
</summary> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808WebAPIService.#ctor(JT808.DotNetty.Internal.JT808AtomicCounterService,JT808.DotNetty.Internal.JT808SourcePackageChannelService,JT808.DotNetty.Interfaces.IJT808SessionService,JT808.DotNetty.Interfaces.IJT808UnificationSendService)"> | |||
<summary> | |||
初始化消息处理业务 | |||
</summary> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808WebAPIService.UnificationSend(JT808.DotNetty.Metadata.JT808HttpRequest)"> | |||
<summary> | |||
统一下发信息 | |||
</summary> | |||
<param name="request"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808WebAPIService.GetSessionAll(JT808.DotNetty.Metadata.JT808HttpRequest)"> | |||
<summary> | |||
会话服务集合 | |||
</summary> | |||
<param name="request"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808WebAPIService.RemoveByChannelId(JT808.DotNetty.Metadata.JT808HttpRequest)"> | |||
<summary> | |||
会话服务-通过通道Id移除对应会话 | |||
</summary> | |||
<param name="request"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808WebAPIService.RemoveByTerminalPhoneNo(JT808.DotNetty.Metadata.JT808HttpRequest)"> | |||
<summary> | |||
会话服务-通过设备终端号移除对应会话 | |||
</summary> | |||
<param name="request"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808WebAPIService.GetAtomicCounter(JT808.DotNetty.Metadata.JT808HttpRequest)"> | |||
<summary> | |||
获取包计数器 | |||
</summary> | |||
<param name="request"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808WebAPIService.AddSourcePackageAddress(JT808.DotNetty.Metadata.JT808HttpRequest)"> | |||
<summary> | |||
添加原包转发地址 | |||
</summary> | |||
<param name="request"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808WebAPIService.RemoveSourcePackageAddress(JT808.DotNetty.Metadata.JT808HttpRequest)"> | |||
<summary> | |||
删除原包转发地址(不能删除在网关服务器配置文件配的地址) | |||
</summary> | |||
<param name="request"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.Internal.JT808WebAPIService.GetSourcePackageAll(JT808.DotNetty.Metadata.JT808HttpRequest)"> | |||
<summary> | |||
获取原包信息集合 | |||
</summary> | |||
<param name="request"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="T:JT808.DotNetty.JT808MsgIdHandlerBase"> | |||
<summary> | |||
抽象消息处理业务 | |||
自定义消息处理业务 | |||
ConfigureServices: | |||
services.Replace(new ServiceDescriptor(typeof(JT808MsgIdHandlerBase),typeof(JT808MsgIdCustomHandlerImpl),ServiceLifetime.Singleton)); | |||
</summary> | |||
</member> | |||
<member name="M:JT808.DotNetty.JT808MsgIdHandlerBase.#ctor(JT808.DotNetty.JT808SessionManager)"> | |||
<summary> | |||
初始化消息处理业务 | |||
</summary> | |||
</member> | |||
<member name="M:JT808.DotNetty.JT808MsgIdHandlerBase.Msg0x0001(JT808.DotNetty.Metadata.JT808Request)"> | |||
<summary> | |||
终端通用应答 | |||
</summary> | |||
<param name="reqJT808Package"></param> | |||
<param name="ctx"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.JT808MsgIdHandlerBase.Msg0x0002(JT808.DotNetty.Metadata.JT808Request)"> | |||
<summary> | |||
终端心跳 | |||
</summary> | |||
<param name="reqJT808Package"></param> | |||
<param name="ctx"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.JT808MsgIdHandlerBase.Msg0x0003(JT808.DotNetty.Metadata.JT808Request)"> | |||
<summary> | |||
终端注销 | |||
</summary> | |||
<param name="reqJT808Package"></param> | |||
<param name="ctx"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.JT808MsgIdHandlerBase.Msg0x0100(JT808.DotNetty.Metadata.JT808Request)"> | |||
<summary> | |||
终端注册 | |||
</summary> | |||
<param name="reqJT808Package"></param> | |||
<param name="ctx"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.JT808MsgIdHandlerBase.Msg0x0102(JT808.DotNetty.Metadata.JT808Request)"> | |||
<summary> | |||
终端鉴权 | |||
</summary> | |||
<param name="reqJT808Package"></param> | |||
<param name="ctx"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.JT808MsgIdHandlerBase.Msg0x0200(JT808.DotNetty.Metadata.JT808Request)"> | |||
<summary> | |||
位置信息汇报 | |||
</summary> | |||
<param name="reqJT808Package"></param> | |||
<param name="ctx"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.JT808MsgIdHandlerBase.Msg0x0704(JT808.DotNetty.Metadata.JT808Request)"> | |||
<summary> | |||
定位数据批量上传 | |||
</summary> | |||
<param name="reqJT808Package"></param> | |||
<param name="ctx"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="M:JT808.DotNetty.JT808MsgIdHandlerBase.Msg0x0900(JT808.DotNetty.Metadata.JT808Request)"> | |||
<summary> | |||
数据上行透传 | |||
</summary> | |||
<param name="reqJT808Package"></param> | |||
<param name="ctx"></param> | |||
<returns></returns> | |||
</member> | |||
<member name="F:JT808.DotNetty.JT808SessionManager.SessionIdDict"> | |||
<summary> | |||
Netty生成的sessionID和Session的对应关系 | |||
key = seession id | |||
value = Session | |||
</summary> | |||
</member> | |||
<member name="F:JT808.DotNetty.JT808SessionManager.TerminalPhoneNo_SessionId_Dict"> | |||
<summary> | |||
终端手机号和netty生成的sessionID的对应关系 | |||
key = 终端手机号 | |||
value = seession id | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.JT808SessionManager.RealSessionCount"> | |||
<summary> | |||
获取实际连接数 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.JT808SessionManager.RelevanceSessionCount"> | |||
<summary> | |||
获取设备相关连的连接数 | |||
</summary> | |||
</member> | |||
<member name="T:JT808.DotNetty.JT808WebAPIServerHost"> | |||
<summary> | |||
集成一个webapi服务 | |||
</summary> | |||
</member> | |||
<member name="T:JT808.DotNetty.Metadata.JT808AtomicCounter"> | |||
<summary> | |||
<see cref="!:Grpc.Core.Internal"/> | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Metadata.JT808Response.MinBufferSize"> | |||
<summary> | |||
根据实际情况适当调整包的大小 | |||
</summary> | |||
</member> | |||
<member name="P:JT808.DotNetty.Metadata.JT808Session.TerminalPhoneNo"> | |||
<summary> | |||
终端手机号 | |||
</summary> | |||
</member> | |||
</members> | |||
</doc> |
@@ -1,13 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty | |||
{ | |||
public static class JT808Constants | |||
{ | |||
public const string SessionOnline= "JT808SessionOnline"; | |||
public const string SessionOffline = "JT808SessionOffline"; | |||
} | |||
} |
@@ -1,58 +0,0 @@ | |||
using JT808.DotNetty.Codecs; | |||
using JT808.DotNetty.Configurations; | |||
using JT808.DotNetty.Handlers; | |||
using JT808.DotNetty.Interfaces; | |||
using JT808.DotNetty.Internal; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.DependencyInjection.Extensions; | |||
using Microsoft.Extensions.Hosting; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
[assembly: InternalsVisibleTo("JT808.DotNetty.Test")] | |||
namespace JT808.DotNetty | |||
{ | |||
public static class JT808DotnettyExtensions | |||
{ | |||
static JT808DotnettyExtensions() | |||
{ | |||
JsonSerializerSettings setting = new JsonSerializerSettings(); | |||
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() => | |||
{ | |||
//日期类型默认格式化处理 | |||
setting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; | |||
setting.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat; | |||
setting.DateFormatString = "yyyy-MM-dd HH:mm:ss"; | |||
setting.NullValueHandling = NullValueHandling.Include; | |||
return setting; | |||
}); | |||
} | |||
public static IHostBuilder UseJT808Host(this IHostBuilder builder) | |||
{ | |||
return builder.ConfigureServices((hostContext, services) => | |||
{ | |||
services.Configure<JT808Configuration>(hostContext.Configuration.GetSection("JT808Configuration")); | |||
services.TryAddSingleton<IJT808SessionPublishing, JT808SessionPublishingEmptyImpl>(); | |||
services.TryAddSingleton<JT808SessionManager>(); | |||
services.TryAddSingleton<JT808AtomicCounterService>(); | |||
services.TryAddSingleton<JT808TransmitAddressFilterService>(); | |||
services.TryAddSingleton<JT808MsgIdHandlerBase,JT808MsgIdDefaultHandler>(); | |||
services.TryAddSingleton<JT808SourcePackageChannelService>(); | |||
services.TryAddSingleton<IJT808SourcePackageDispatcher, JT808SourcePackageDispatcherDefaultImpl>(); | |||
services.TryAddScoped<JT808ConnectionHandler>(); | |||
services.TryAddScoped<JT808Decoder>(); | |||
services.TryAddScoped<JT808ServerHandler>(); | |||
services.TryAddScoped<JT808UDPServerHandler>(); | |||
services.TryAddSingleton<IJT808SessionService, JT808SessionServiceDefaultImpl>(); | |||
services.TryAddSingleton<IJT808UnificationSendService, JT808UnificationSendServiceDefaultImpl>(); | |||
services.TryAddSingleton<JT808WebAPIService>(); | |||
services.TryAddScoped<JT808WebAPIServerHandler>(); | |||
services.AddHostedService<JT808ServerHost>(); | |||
services.AddHostedService<JT808WebAPIServerHost>(); | |||
}); | |||
} | |||
} | |||
} |
@@ -1,160 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using JT808.DotNetty.Metadata; | |||
using JT808.Protocol.Enums; | |||
using JT808.Protocol.Extensions; | |||
using JT808.Protocol.MessageBody; | |||
namespace JT808.DotNetty | |||
{ | |||
/// <summary> | |||
/// 抽象消息处理业务 | |||
/// 自定义消息处理业务 | |||
/// 注意: | |||
/// 1.ConfigureServices: | |||
/// services.Replace(new ServiceDescriptor(typeof(JT808MsgIdHandlerBase),typeof(JT808MsgIdCustomHandlerImpl),ServiceLifetime.Singleton)); | |||
/// 2.解析具体的消息体,具体消息调用具体的JT808Serializer.Deserialize<T> | |||
/// </summary> | |||
public abstract class JT808MsgIdHandlerBase | |||
{ | |||
protected JT808SessionManager sessionManager { get; } | |||
/// <summary> | |||
/// 初始化消息处理业务 | |||
/// </summary> | |||
protected JT808MsgIdHandlerBase(JT808SessionManager sessionManager) | |||
{ | |||
this.sessionManager = sessionManager; | |||
HandlerDict = new Dictionary<ushort, Func<JT808Request, JT808Response>> | |||
{ | |||
{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 Dictionary<ushort, Func<JT808Request, JT808Response>> HandlerDict { get; protected set; } | |||
/// <summary> | |||
/// 终端通用应答 | |||
/// 平台无需回复 | |||
/// 实现自己的业务 | |||
/// </summary> | |||
/// <param name="reqJT808Package"></param> | |||
/// <param name="ctx"></param> | |||
/// <returns></returns> | |||
public virtual JT808Response Msg0x0001(JT808Request request) | |||
{ | |||
return null; | |||
} | |||
/// <summary> | |||
/// 终端心跳 | |||
/// </summary> | |||
/// <param name="reqJT808Package"></param> | |||
/// <param name="ctx"></param> | |||
/// <returns></returns> | |||
public virtual JT808Response Msg0x0002(JT808Request request) | |||
{ | |||
sessionManager.Heartbeat(request.Package.Header.TerminalPhoneNo); | |||
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001() | |||
{ | |||
MsgId = request.Package.Header.MsgId, | |||
JT808PlatformResult = JT808PlatformResult.成功, | |||
MsgNum = request.Package.Header.MsgNum | |||
})); | |||
} | |||
/// <summary> | |||
/// 终端注销 | |||
/// </summary> | |||
/// <param name="reqJT808Package"></param> | |||
/// <param name="ctx"></param> | |||
/// <returns></returns> | |||
public virtual JT808Response Msg0x0003(JT808Request request) | |||
{ | |||
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001() | |||
{ | |||
MsgId = request.Package.Header.MsgId, | |||
JT808PlatformResult = JT808PlatformResult.成功, | |||
MsgNum = request.Package.Header.MsgNum | |||
})); | |||
} | |||
/// <summary> | |||
/// 终端注册 | |||
/// </summary> | |||
/// <param name="reqJT808Package"></param> | |||
/// <param name="ctx"></param> | |||
/// <returns></returns> | |||
public virtual JT808Response Msg0x0100(JT808Request request) | |||
{ | |||
return new JT808Response(JT808MsgId.终端注册应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8100() | |||
{ | |||
Code = "J" + request.Package.Header.TerminalPhoneNo, | |||
JT808TerminalRegisterResult = JT808TerminalRegisterResult.成功, | |||
MsgNum = request.Package.Header.MsgNum | |||
})); | |||
} | |||
/// <summary> | |||
/// 终端鉴权 | |||
/// </summary> | |||
/// <param name="reqJT808Package"></param> | |||
/// <param name="ctx"></param> | |||
/// <returns></returns> | |||
public virtual JT808Response Msg0x0102(JT808Request request) | |||
{ | |||
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001() | |||
{ | |||
MsgId = request.Package.Header.MsgId, | |||
JT808PlatformResult = JT808PlatformResult.成功, | |||
MsgNum = request.Package.Header.MsgNum | |||
})); | |||
} | |||
/// <summary> | |||
/// 位置信息汇报 | |||
/// </summary> | |||
/// <param name="reqJT808Package"></param> | |||
/// <param name="ctx"></param> | |||
/// <returns></returns> | |||
public virtual JT808Response Msg0x0200(JT808Request request) | |||
{ | |||
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001() | |||
{ | |||
MsgId = request.Package.Header.MsgId, | |||
JT808PlatformResult = JT808PlatformResult.成功, | |||
MsgNum = request.Package.Header.MsgNum | |||
})); | |||
} | |||
/// <summary> | |||
/// 定位数据批量上传 | |||
/// </summary> | |||
/// <param name="reqJT808Package"></param> | |||
/// <param name="ctx"></param> | |||
/// <returns></returns> | |||
public virtual JT808Response Msg0x0704(JT808Request request) | |||
{ | |||
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001() | |||
{ | |||
MsgId =request.Package.Header.MsgId, | |||
JT808PlatformResult = JT808PlatformResult.成功, | |||
MsgNum = request.Package.Header.MsgNum | |||
})); | |||
} | |||
/// <summary> | |||
/// 数据上行透传 | |||
/// </summary> | |||
/// <param name="reqJT808Package"></param> | |||
/// <param name="ctx"></param> | |||
/// <returns></returns> | |||
public virtual JT808Response Msg0x0900(JT808Request request) | |||
{ | |||
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001() | |||
{ | |||
MsgId =request.Package.Header.MsgId, | |||
JT808PlatformResult = JT808PlatformResult.成功, | |||
MsgNum = request.Package.Header.MsgNum | |||
})); | |||
} | |||
} | |||
} |
@@ -1,96 +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.DotNetty.Codecs; | |||
using JT808.DotNetty.Configurations; | |||
using JT808.DotNetty.Handlers; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Hosting; | |||
using Microsoft.Extensions.Logging; | |||
using Microsoft.Extensions.Options; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Runtime.InteropServices; | |||
using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace JT808.DotNetty | |||
{ | |||
/// <summary> | |||
/// JT808 网关服务 | |||
/// </summary> | |||
internal class JT808ServerHost : IHostedService | |||
{ | |||
private readonly IServiceProvider serviceProvider; | |||
private readonly JT808Configuration configuration; | |||
private readonly ILogger<JT808ServerHost> logger; | |||
private DispatcherEventLoopGroup bossGroup; | |||
private WorkerEventLoopGroup workerGroup; | |||
private IChannel bootstrapChannel; | |||
private IByteBufferAllocator serverBufferAllocator; | |||
public JT808ServerHost( | |||
IServiceProvider provider, | |||
ILoggerFactory loggerFactory, | |||
IOptions<JT808Configuration> jT808ConfigurationAccessor) | |||
{ | |||
serviceProvider = provider; | |||
configuration = jT808ConfigurationAccessor.Value; | |||
logger=loggerFactory.CreateLogger<JT808ServerHost>(); | |||
} | |||
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<TcpServerChannel>(); | |||
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<IChannel>(channel => | |||
{ | |||
IChannelPipeline pipeline = channel.Pipeline; | |||
using (var scope = serviceProvider.CreateScope()) | |||
{ | |||
channel.Pipeline.AddLast("systemIdleState", new IdleStateHandler( | |||
configuration.ReaderIdleTimeSeconds, | |||
configuration.WriterIdleTimeSeconds, | |||
configuration.AllIdleTimeSeconds)); | |||
channel.Pipeline.AddLast("jt808Connection", scope.ServiceProvider.GetRequiredService<JT808ConnectionHandler>()); | |||
channel.Pipeline.AddLast("jt808Buffer", new DelimiterBasedFrameDecoder(int.MaxValue, | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); | |||
channel.Pipeline.AddLast("jt808Decode", scope.ServiceProvider.GetRequiredService<JT808Decoder>()); | |||
channel.Pipeline.AddLast("jt808Service", scope.ServiceProvider.GetRequiredService<JT808ServerHandler>()); | |||
} | |||
})); | |||
logger.LogInformation($"Server start at {IPAddress.Any}:{configuration.Port}."); | |||
return bootstrap.BindAsync(configuration.Port) | |||
.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); | |||
} | |||
} | |||
} |
@@ -1,141 +0,0 @@ | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using JT808.DotNetty.Metadata; | |||
using DotNetty.Transport.Channels; | |||
using JT808.DotNetty.Interfaces; | |||
namespace JT808.DotNetty | |||
{ | |||
/// <summary> | |||
/// JT808会话管理 | |||
/// </summary> | |||
public class JT808SessionManager | |||
{ | |||
private readonly ILogger<JT808SessionManager> logger; | |||
private readonly IJT808SessionPublishing jT808SessionPublishing; | |||
public JT808SessionManager( | |||
IJT808SessionPublishing jT808SessionPublishing, | |||
ILoggerFactory loggerFactory) | |||
{ | |||
this.jT808SessionPublishing = jT808SessionPublishing; | |||
logger = loggerFactory.CreateLogger<JT808SessionManager>(); | |||
} | |||
private ConcurrentDictionary<string, JT808Session> SessionIdDict = new ConcurrentDictionary<string, JT808Session>(StringComparer.OrdinalIgnoreCase); | |||
public int SessionCount | |||
{ | |||
get | |||
{ | |||
return SessionIdDict.Count; | |||
} | |||
} | |||
public JT808Session GetSession(string terminalPhoneNo) | |||
{ | |||
if (string.IsNullOrEmpty(terminalPhoneNo)) | |||
return default; | |||
if (SessionIdDict.TryGetValue(terminalPhoneNo, out JT808Session targetSession)) | |||
{ | |||
return targetSession; | |||
} | |||
else | |||
{ | |||
return default; | |||
} | |||
} | |||
public void Heartbeat(string terminalPhoneNo) | |||
{ | |||
if (string.IsNullOrEmpty(terminalPhoneNo)) return; | |||
if (SessionIdDict.TryGetValue(terminalPhoneNo, out JT808Session oldjT808Session)) | |||
{ | |||
oldjT808Session.LastActiveTime = DateTime.Now; | |||
SessionIdDict.TryUpdate(terminalPhoneNo, oldjT808Session, oldjT808Session); | |||
} | |||
} | |||
public void TryAdd(JT808Session appSession) | |||
{ | |||
// 解决了设备号跟通道绑定到一起,不需要用到通道本身的SessionId | |||
// 不管设备下发更改了设备终端号,只要是没有在内存中就当是新的 | |||
// 存在的问题: | |||
// 1.原先老的如何销毁 | |||
// 2.这时候用的通道是相同的,设备终端是不同的 | |||
// 当设备主动或者服务器断开以后,可以释放,这点内存忽略不计,况且更改设备号不是很频繁。 | |||
if (SessionIdDict.TryAdd(appSession.TerminalPhoneNo, appSession)) | |||
{ | |||
//使用场景: | |||
//部标的超长待机设备,不会像正常的设备一样一直连着,可能10几分钟连上了,然后发完就关闭连接, | |||
//这时候想下发数据需要知道设备什么时候上线,在这边做通知最好不过了。 | |||
//todo: 有设备关联上来可以进行通知 例如:使用Redis发布订阅 | |||
jT808SessionPublishing.PublishAsync(JT808Constants.SessionOnline,null, appSession.TerminalPhoneNo); | |||
} | |||
} | |||
public JT808Session RemoveSession(string terminalPhoneNo) | |||
{ | |||
//todo: 设备离线可以进行通知 | |||
//todo: 使用Redis 发布订阅 | |||
if (string.IsNullOrEmpty(terminalPhoneNo)) return default; | |||
if (!SessionIdDict.TryGetValue(terminalPhoneNo, out JT808Session jT808Session)) | |||
{ | |||
return default; | |||
} | |||
// 处理转发过来的是数据 这时候通道对设备是1对多关系,需要清理垃圾数据 | |||
//1.用当前会话的通道Id找出通过转发过来的其他设备的终端号 | |||
var terminalPhoneNos = SessionIdDict.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) | |||
{ | |||
SessionIdDict.TryRemove(key, out JT808Session jT808SessionRemove); | |||
} | |||
string nos = string.Join(",", terminalPhoneNos); | |||
logger.LogInformation($">>>{terminalPhoneNo}-{nos} 1-n Session Remove."); | |||
jT808SessionPublishing.PublishAsync(JT808Constants.SessionOffline, null, nos); | |||
return jT808Session; | |||
} | |||
else | |||
{ | |||
if (SessionIdDict.TryRemove(terminalPhoneNo, out JT808Session jT808SessionRemove)) | |||
{ | |||
logger.LogInformation($">>>{terminalPhoneNo} Session Remove."); | |||
jT808SessionPublishing.PublishAsync(JT808Constants.SessionOffline, null, terminalPhoneNo); | |||
return jT808SessionRemove; | |||
} | |||
else | |||
{ | |||
return default; | |||
} | |||
} | |||
} | |||
internal void RemoveSessionByChannel(IChannel channel) | |||
{ | |||
//todo: 设备离线可以进行通知 | |||
//todo: 使用Redis 发布订阅 | |||
var terminalPhoneNos = SessionIdDict.Where(w => w.Value.Channel.Id == channel.Id).Select(s => s.Key).ToList(); | |||
foreach (var key in terminalPhoneNos) | |||
{ | |||
SessionIdDict.TryRemove(key, out JT808Session jT808SessionRemove); | |||
} | |||
string nos = string.Join(",", terminalPhoneNos); | |||
logger.LogInformation($">>>{nos} Channel Remove."); | |||
jT808SessionPublishing.PublishAsync(JT808Constants.SessionOffline, null, nos); | |||
} | |||
public IEnumerable<JT808Session> GetAll() | |||
{ | |||
return SessionIdDict.Select(s => s.Value).ToList(); | |||
} | |||
} | |||
} | |||
@@ -1,77 +0,0 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Codecs; | |||
using DotNetty.Transport.Bootstrapping; | |||
using DotNetty.Transport.Channels; | |||
using DotNetty.Transport.Channels.Sockets; | |||
using DotNetty.Transport.Libuv; | |||
using JT808.DotNetty.Codecs; | |||
using JT808.DotNetty.Configurations; | |||
using JT808.DotNetty.Handlers; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace JT808.DotNetty | |||
{ | |||
public class JT808SimpleTcpClient | |||
{ | |||
private Bootstrap cb; | |||
private MultithreadEventLoopGroup clientGroup; | |||
private IChannel clientChannel; | |||
private IByteBufferAllocator clientBufferAllocator; | |||
public JT808SimpleTcpClient(EndPoint remoteAddress) | |||
{ | |||
clientBufferAllocator = new PooledByteBufferAllocator(); | |||
clientGroup = new MultithreadEventLoopGroup(1); | |||
cb = new Bootstrap() | |||
.Group(clientGroup) | |||
.Channel<TcpSocketChannel>() | |||
.Option(ChannelOption.TcpNodelay, true) | |||
.Option(ChannelOption.Allocator, clientBufferAllocator) | |||
.Handler(new ActionChannelInitializer<TcpSocketChannel>(channel => | |||
{ | |||
channel.Pipeline.AddLast("jt808Buffer", new DelimiterBasedFrameDecoder(int.MaxValue, | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); | |||
channel.Pipeline.AddLast("jt808Decode", new JT808ClientDecoder()); | |||
})); | |||
clientChannel = cb.ConnectAsync(remoteAddress).Result; | |||
} | |||
public JT808SimpleTcpClient(EndPoint remoteAddress, EndPoint localAddress) | |||
{ | |||
clientBufferAllocator = new PooledByteBufferAllocator(); | |||
clientGroup = new MultithreadEventLoopGroup(1); | |||
cb = new Bootstrap() | |||
.Group(clientGroup) | |||
.Channel<TcpSocketChannel>() | |||
.Option(ChannelOption.TcpNodelay, true) | |||
.Option(ChannelOption.Allocator, clientBufferAllocator) | |||
.Handler(new ActionChannelInitializer<TcpSocketChannel>(channel => | |||
{ | |||
channel.Pipeline.AddLast("jt808Buffer", new DelimiterBasedFrameDecoder(int.MaxValue, | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), | |||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); | |||
channel.Pipeline.AddLast("jt808Decode", new JT808ClientDecoder()); | |||
})); | |||
clientChannel = cb.ConnectAsync(remoteAddress, localAddress).Result; | |||
} | |||
public void WriteAsync(byte[] data) | |||
{ | |||
clientChannel.WriteAndFlushAsync(Unpooled.WrappedBuffer(data)); | |||
} | |||
public void Down() | |||
{ | |||
this.clientChannel?.CloseAsync().Wait(); | |||
Task.WaitAll(this.clientGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1))); | |||
} | |||
} | |||
} |
@@ -1,82 +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 DotNetty.Transport.Libuv; | |||
using JT808.DotNetty.Codecs; | |||
using JT808.DotNetty.Configurations; | |||
using JT808.DotNetty.Handlers; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Hosting; | |||
using Microsoft.Extensions.Logging; | |||
using Microsoft.Extensions.Options; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Runtime.InteropServices; | |||
using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace JT808.DotNetty | |||
{ | |||
/// <summary> | |||
/// JT808 Udp网关服务 | |||
/// </summary> | |||
internal class JT808UdpServerHost : IHostedService | |||
{ | |||
private readonly IServiceProvider serviceProvider; | |||
private readonly JT808Configuration configuration; | |||
private readonly ILogger<JT808UdpServerHost> logger; | |||
private MultithreadEventLoopGroup group; | |||
private IChannel bootstrapChannel; | |||
public JT808UdpServerHost( | |||
IServiceProvider provider, | |||
ILoggerFactory loggerFactory, | |||
IOptions<JT808Configuration> jT808ConfigurationAccessor) | |||
{ | |||
serviceProvider = provider; | |||
configuration = jT808ConfigurationAccessor.Value; | |||
logger=loggerFactory.CreateLogger<JT808UdpServerHost>(); | |||
} | |||
public Task StartAsync(CancellationToken cancellationToken) | |||
{ | |||
group = new MultithreadEventLoopGroup(); | |||
Bootstrap bootstrap = new Bootstrap(); | |||
bootstrap.Group(group); | |||
bootstrap.Channel<SocketDatagramChannel>(); | |||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) | |||
|| RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) | |||
{ | |||
bootstrap | |||
.Option(ChannelOption.SoReuseport, true); | |||
} | |||
bootstrap | |||
.Option(ChannelOption.SoBacklog, configuration.SoBacklog) | |||
.Handler(new ActionChannelInitializer<IChannel>(channel => | |||
{ | |||
IChannelPipeline pipeline = channel.Pipeline; | |||
using (var scope = serviceProvider.CreateScope()) | |||
{ | |||
pipeline.AddLast(new JT808UDPDecoder()); | |||
pipeline.AddLast("jt808UDPService", scope.ServiceProvider.GetRequiredService<JT808UDPServerHandler>()); | |||
} | |||
})); | |||
logger.LogInformation($"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); | |||
} | |||
} | |||
} |
@@ -1,82 +0,0 @@ | |||
using DotNetty.Codecs.Http; | |||
using DotNetty.Transport.Bootstrapping; | |||
using DotNetty.Transport.Channels; | |||
using DotNetty.Transport.Libuv; | |||
using JT808.DotNetty.Configurations; | |||
using JT808.DotNetty.Handlers; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Hosting; | |||
using Microsoft.Extensions.Logging; | |||
using Microsoft.Extensions.Options; | |||
using System; | |||
using System.Net; | |||
using System.Runtime.InteropServices; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
namespace JT808.DotNetty | |||
{ | |||
/// <summary> | |||
/// 集成一个webapi服务 | |||
/// </summary> | |||
internal class JT808WebAPIServerHost : IHostedService | |||
{ | |||
private readonly IServiceProvider serviceProvider; | |||
private readonly JT808Configuration configuration; | |||
private readonly ILogger<JT808WebAPIServerHost> logger; | |||
private DispatcherEventLoopGroup bossGroup; | |||
private WorkerEventLoopGroup workerGroup; | |||
private IChannel bootstrapChannel; | |||
public JT808WebAPIServerHost( | |||
IServiceProvider provider, | |||
ILoggerFactory loggerFactory, | |||
IOptions<JT808Configuration> jT808ConfigurationAccessor) | |||
{ | |||
serviceProvider = provider; | |||
configuration = jT808ConfigurationAccessor.Value; | |||
logger = loggerFactory.CreateLogger<JT808WebAPIServerHost>(); | |||
} | |||
public Task StartAsync(CancellationToken cancellationToken) | |||
{ | |||
bossGroup = new DispatcherEventLoopGroup(); | |||
workerGroup = new WorkerEventLoopGroup(bossGroup, 1); | |||
ServerBootstrap bootstrap = new ServerBootstrap(); | |||
bootstrap.Group(bossGroup, workerGroup); | |||
bootstrap.Channel<TcpServerChannel>(); | |||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) | |||
|| RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) | |||
{ | |||
bootstrap | |||
.Option(ChannelOption.SoReuseport, true) | |||
.ChildOption(ChannelOption.SoReuseaddr, true); | |||
} | |||
bootstrap | |||
.Option(ChannelOption.SoBacklog, 8192) | |||
.ChildHandler(new ActionChannelInitializer<IChannel>(channel => | |||
{ | |||
IChannelPipeline pipeline = channel.Pipeline; | |||
using (var scope = serviceProvider.CreateScope()) | |||
{ | |||
pipeline.AddLast("http_encoder", new HttpResponseEncoder()); | |||
pipeline.AddLast("http_decoder", new HttpRequestDecoder(4096, 8192, 8192, false)); | |||
//将多个消息转换为单一的request或者response对象 =>IFullHttpRequest | |||
pipeline.AddLast("http_aggregator", new HttpObjectAggregator(65536)); | |||
pipeline.AddLast("http_jt808webapihandler", scope.ServiceProvider.GetRequiredService<JT808WebAPIServerHandler>()); | |||
} | |||
})); | |||
logger.LogInformation($"WebAPI Server start at {IPAddress.Any}:{configuration.WebApiPort}."); | |||
return bootstrap.BindAsync(configuration.WebApiPort).ContinueWith(i => bootstrapChannel = i.Result); | |||
} | |||
public async Task StopAsync(CancellationToken cancellationToken) | |||
{ | |||
await bootstrapChannel.CloseAsync(); | |||
var quietPeriod = configuration.QuietPeriodTimeSpan; | |||
var shutdownTimeout = configuration.ShutdownTimeoutTimeSpan; | |||
await workerGroup.ShutdownGracefullyAsync(quietPeriod, shutdownTimeout); | |||
await bossGroup.ShutdownGracefullyAsync(quietPeriod, shutdownTimeout); | |||
} | |||
} | |||
} |
@@ -1,44 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using System.Threading; | |||
namespace JT808.DotNetty.Metadata | |||
{ | |||
/// <summary> | |||
/// | |||
/// <see cref="Grpc.Core.Internal"/> | |||
/// </summary> | |||
internal class JT808AtomicCounter | |||
{ | |||
long counter = 0; | |||
public JT808AtomicCounter(long initialCount = 0) | |||
{ | |||
this.counter = initialCount; | |||
} | |||
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); | |||
} | |||
} | |||
} | |||
} |
@@ -1,22 +0,0 @@ | |||
using JT808.Protocol; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
namespace JT808.DotNetty.Metadata | |||
{ | |||
public class JT808HttpRequest | |||
{ | |||
public string Json { get; set; } | |||
public JT808HttpRequest() | |||
{ | |||
} | |||
public JT808HttpRequest(string json) | |||
{ | |||
Json = json; | |||
} | |||
} | |||
} |
@@ -1,22 +0,0 @@ | |||
using JT808.Protocol; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
namespace JT808.DotNetty.Metadata | |||
{ | |||
public class JT808HttpResponse | |||
{ | |||
public byte[] Data { get; set; } | |||
public JT808HttpResponse() | |||
{ | |||
} | |||
public JT808HttpResponse(byte[] data) | |||
{ | |||
this.Data = data; | |||
} | |||
} | |||
} |
@@ -1,23 +0,0 @@ | |||
using JT808.Protocol; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
namespace JT808.DotNetty.Metadata | |||
{ | |||
public class JT808Request | |||
{ | |||
public JT808HeaderPackage Package { get; } | |||
/// <summary> | |||
/// 用于消息发送 | |||
/// </summary> | |||
public byte[] OriginalPackage { get;} | |||
public JT808Request(JT808HeaderPackage package, byte[] originalPackage) | |||
{ | |||
Package = package; | |||
OriginalPackage = originalPackage; | |||
} | |||
} | |||
} |
@@ -1,27 +0,0 @@ | |||
using JT808.Protocol; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
namespace JT808.DotNetty.Metadata | |||
{ | |||
public class JT808Response | |||
{ | |||
public JT808Package Package { get; set; } | |||
/// <summary> | |||
/// 根据实际情况适当调整包的大小 | |||
/// </summary> | |||
public int MinBufferSize { get; set; } | |||
public JT808Response() | |||
{ | |||
} | |||
public JT808Response(JT808Package package, int minBufferSize = 1024) | |||
{ | |||
Package = package; | |||
MinBufferSize = minBufferSize; | |||
} | |||
} | |||
} |
@@ -1,31 +0,0 @@ | |||
using DotNetty.Transport.Channels; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT808.DotNetty.Metadata | |||
{ | |||
public class JT808Session | |||
{ | |||
public JT808Session(IChannel channel, string terminalPhoneNo) | |||
{ | |||
Channel = channel; | |||
TerminalPhoneNo = terminalPhoneNo; | |||
StartTime = DateTime.Now; | |||
LastActiveTime = DateTime.Now; | |||
} | |||
public JT808Session() { } | |||
/// <summary> | |||
/// 终端手机号 | |||
/// </summary> | |||
public string TerminalPhoneNo { get; set; } | |||
public IChannel Channel { get; set; } | |||
public DateTime LastActiveTime { get; set; } | |||
public DateTime StartTime { get; set; } | |||
} | |||
} |
@@ -1,20 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Text; | |||
namespace JT808.DotNetty.Metadata | |||
{ | |||
internal class JT808UDPPackage | |||
{ | |||
public JT808UDPPackage(byte[] buffer, EndPoint sender) | |||
{ | |||
Buffer = buffer; | |||
Sender = sender; | |||
} | |||
public byte[] Buffer { get; } | |||
public EndPoint Sender { get; } | |||
} | |||
} |