From aa78a01105f24533d0c26bb7707fc9fe762434c8 Mon Sep 17 00:00:00 2001 From: smallchi <564952747@qq.com> Date: Thu, 12 Sep 2019 18:45:08 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=A2=9E=E5=8A=A0RTMP=E6=B5=8B=E8=AF=95=202.?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0HTTPFLV=E6=B5=8B=E8=AF=95=203.=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E7=BB=9F=E4=B8=80=E7=89=88=E6=9C=AC=E5=8F=B7=E6=8E=A7?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../JT1078.DotNetty.Core.csproj | 17 +++- .../JT1078.DotNetty.Tcp.csproj | 12 ++- .../HTTPFLV/FFMPEGHTTPFLVPHostedService.cs | 53 +++++++++++ .../HTTPFLV/FFMPEGHTTPFLVPipingService.cs | 94 +++++++++++++++++++ .../Handlers/JT1078TcpMessageHandlers.cs | 2 +- .../JT1078.DotNetty.TestHosting.csproj | 3 + .../JT1078DataService.cs | 37 ++++++-- .../JT1078WebSocketPushHostedService.cs | 48 ++-------- src/JT1078.DotNetty.TestHosting/Program.cs | 22 +++-- .../RTMP/FFMPEGRTMPHostedService.cs | 54 +++++++++++ .../RTMP/FFMPEGRTMPPipingService.cs | 71 ++++++++++++++ .../JT1078.DotNetty.Udp.csproj | 17 +++- .../JT1078.DotNetty.WebSocket.csproj | 17 +++- src/SharedProperties.props | 19 ---- src/Version.props | 5 + 15 files changed, 388 insertions(+), 83 deletions(-) create mode 100644 src/JT1078.DotNetty.TestHosting/HTTPFLV/FFMPEGHTTPFLVPHostedService.cs create mode 100644 src/JT1078.DotNetty.TestHosting/HTTPFLV/FFMPEGHTTPFLVPipingService.cs create mode 100644 src/JT1078.DotNetty.TestHosting/RTMP/FFMPEGRTMPHostedService.cs create mode 100644 src/JT1078.DotNetty.TestHosting/RTMP/FFMPEGRTMPPipingService.cs delete mode 100644 src/SharedProperties.props create mode 100644 src/Version.props diff --git a/src/JT1078.DotNetty.Core/JT1078.DotNetty.Core.csproj b/src/JT1078.DotNetty.Core/JT1078.DotNetty.Core.csproj index 8b93036..8bfe7d0 100644 --- a/src/JT1078.DotNetty.Core/JT1078.DotNetty.Core.csproj +++ b/src/JT1078.DotNetty.Core/JT1078.DotNetty.Core.csproj @@ -1,11 +1,22 @@  - + netstandard2.0 + 7.3 + Copyright 2019. + SmallChi(Koike) JT1078.DotNetty.Core JT1078.DotNetty.Core 基于DotNetty实现的JT1078DotNetty的核心库 基于DotNetty实现的JT1078DotNetty的核心库 + https://github.com/SmallChi/JT1078DotNetty + https://github.com/SmallChi/JT1078DotNetty + https://github.com/SmallChi/JT1078DotNetty/blob/master/LICENSE + https://github.com/SmallChi/JT1078DotNetty/blob/master/LICENSE + false + false + LICENSE + true @@ -21,6 +32,10 @@ + + + + diff --git a/src/JT1078.DotNetty.Tcp/JT1078.DotNetty.Tcp.csproj b/src/JT1078.DotNetty.Tcp/JT1078.DotNetty.Tcp.csproj index 954b37d..07e0bdb 100644 --- a/src/JT1078.DotNetty.Tcp/JT1078.DotNetty.Tcp.csproj +++ b/src/JT1078.DotNetty.Tcp/JT1078.DotNetty.Tcp.csproj @@ -1,7 +1,10 @@  - + netstandard2.0 + 7.3 + Copyright 2019. + SmallChi(Koike) JT1078.DotNetty.Tcp JT1078.DotNetty.Tcp 基于DotNetty实现的JT1078DotNetty的Tcp服务 @@ -10,12 +13,19 @@ https://github.com/SmallChi/JT1078DotNetty https://github.com/SmallChi/JT1078DotNetty/blob/master/LICENSE https://github.com/SmallChi/JT1078DotNetty/blob/master/LICENSE + false + false + LICENSE + true + + + diff --git a/src/JT1078.DotNetty.TestHosting/HTTPFLV/FFMPEGHTTPFLVPHostedService.cs b/src/JT1078.DotNetty.TestHosting/HTTPFLV/FFMPEGHTTPFLVPHostedService.cs new file mode 100644 index 0000000..b95968b --- /dev/null +++ b/src/JT1078.DotNetty.TestHosting/HTTPFLV/FFMPEGHTTPFLVPHostedService.cs @@ -0,0 +1,53 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.Http.WebSockets; +using JT1078.DotNetty.Core.Session; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using JT1078.Protocol; +using System.Collections.Concurrent; +using JT1078.Protocol.Enums; + +namespace JT1078.DotNetty.TestHosting +{ + class FFMPEGHTTPFLVPHostedService : IHostedService + { + private readonly JT1078DataService jT1078DataService; + private readonly FFMPEGHTTPFLVPipingService fFMPEGHTTPFLVPipingService; + public FFMPEGHTTPFLVPHostedService( + JT1078DataService jT1078DataService) + { + this.jT1078DataService = jT1078DataService; + fFMPEGHTTPFLVPipingService = new FFMPEGHTTPFLVPipingService("demo2"); + } + public Task StartAsync(CancellationToken cancellationToken) + { + Task.Run(() => + { + try + { + foreach (var item in jT1078DataService.DataBlockingCollection.GetConsumingEnumerable(cancellationToken)) + { + fFMPEGHTTPFLVPipingService.Wirte(item); + } + } + catch(Exception ex) + { + Console.WriteLine(ex); + } + + }, cancellationToken); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + } +} diff --git a/src/JT1078.DotNetty.TestHosting/HTTPFLV/FFMPEGHTTPFLVPipingService.cs b/src/JT1078.DotNetty.TestHosting/HTTPFLV/FFMPEGHTTPFLVPipingService.cs new file mode 100644 index 0000000..176d18e --- /dev/null +++ b/src/JT1078.DotNetty.TestHosting/HTTPFLV/FFMPEGHTTPFLVPipingService.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Pipes; +using System.Text; +using System.Threading.Tasks; + +namespace JT1078.DotNetty.TestHosting +{ + + public class FFMPEGHTTPFLVPipingService : IDisposable + { + private readonly Process process; + private readonly NamedPipeServerStream pipeServer; + private readonly NamedPipeServerStream pipeServerOut; + public FFMPEGHTTPFLVPipingService(string pipeName) + { + pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); + pipeServerOut = new NamedPipeServerStream(pipeName+ "out", PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); + process = new Process + { + StartInfo = + { + FileName = @"C:\ffmpeg\bin\ffmpeg.exe", + Arguments = $@"-i \\.\pipe\{pipeName} -c copy -f flv -y \\.\pipe\{pipeName}out", + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardError = true + } + }; + process.Start(); + process.ErrorDataReceived += ErrorDataReceived; + pipeServer.WaitForConnection(); + Task.Run(() => + { + while (true) + { + try + { + if (pipeServerOut.IsConnected) + { + if (pipeServerOut.CanRead) + { + var value = pipeServerOut.ReadByte(); + Console.WriteLine(value); + } + } + else + { + pipeServerOut.WaitForConnectionAsync(); + } + + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + + } + }); + } + + public void ErrorDataReceived(object sender, DataReceivedEventArgs e) + { + Console.WriteLine(e.Data); + } + public void OutputDataReceived(object sender, DataReceivedEventArgs e) + { + Console.WriteLine(e.Data); + } + + public void Wirte(byte[] buffer) + { + if (pipeServer.IsConnected) + pipeServer.WriteAsync(buffer); + } + + public void Dispose() + { + try + { + process.WaitForExit(); + pipeServer.Flush(); + } + catch + { + + } + process.Dispose(); + pipeServer.Dispose(); + } + } +} diff --git a/src/JT1078.DotNetty.TestHosting/Handlers/JT1078TcpMessageHandlers.cs b/src/JT1078.DotNetty.TestHosting/Handlers/JT1078TcpMessageHandlers.cs index 3f24650..76d08be 100644 --- a/src/JT1078.DotNetty.TestHosting/Handlers/JT1078TcpMessageHandlers.cs +++ b/src/JT1078.DotNetty.TestHosting/Handlers/JT1078TcpMessageHandlers.cs @@ -29,7 +29,7 @@ namespace JT1078.DotNetty.TestHosting.Handlers { logger.LogInformation(JsonConvert.SerializeObject(request.Package)); hexLogger.LogInformation($"{request.Package.SIM},{request.Package.SN},{request.Package.LogicChannelNumber},{request.Package.Label3.DataType.ToString()},{request.Package.Label3.SubpackageType.ToString()},{ByteBufferUtil.HexDump(request.Src)}"); - jT1078DataService.DataBlockingCollection.TryAdd(request.Package); + jT1078DataService.DataBlockingCollection.TryAdd(request.Src); return Task.FromResult(default); } } diff --git a/src/JT1078.DotNetty.TestHosting/JT1078.DotNetty.TestHosting.csproj b/src/JT1078.DotNetty.TestHosting/JT1078.DotNetty.TestHosting.csproj index ddad0c9..26067fe 100644 --- a/src/JT1078.DotNetty.TestHosting/JT1078.DotNetty.TestHosting.csproj +++ b/src/JT1078.DotNetty.TestHosting/JT1078.DotNetty.TestHosting.csproj @@ -24,6 +24,9 @@ Always + + Always + Always diff --git a/src/JT1078.DotNetty.TestHosting/JT1078DataService.cs b/src/JT1078.DotNetty.TestHosting/JT1078DataService.cs index 7a5859f..fcae358 100644 --- a/src/JT1078.DotNetty.TestHosting/JT1078DataService.cs +++ b/src/JT1078.DotNetty.TestHosting/JT1078DataService.cs @@ -1,8 +1,10 @@ using JT1078.Protocol; +using JT1078.Protocol.Enums; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -11,12 +13,14 @@ namespace JT1078.DotNetty.TestHosting { public class JT1078DataService { - public BlockingCollection DataBlockingCollection { get; } + public BlockingCollection DataBlockingCollection { get; } + private readonly ConcurrentDictionary SubcontractKey; public JT1078DataService() { - DataBlockingCollection = new BlockingCollection(60000); - var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "2019-07-15.log")); + DataBlockingCollection = new BlockingCollection(60000); + SubcontractKey = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "2019-08-27-1.log")); Task.Run(() => { while (true) @@ -25,9 +29,30 @@ namespace JT1078.DotNetty.TestHosting { try { - var package = JT1078Serializer.Deserialize(lines[i].Split(',')[6].ToHexBytes()); - DataBlockingCollection.Add(package); - Thread.Sleep(300); + var item = JT1078Serializer.Deserialize(lines[i].Split(',')[6].ToHexBytes()); + if (item.Label3.SubpackageType == JT1078SubPackageType.分包处理时的第一个包) + { + SubcontractKey.TryRemove(item.SIM, out _); + SubcontractKey.TryAdd(item.SIM, item.Bodies); + } + else if (item.Label3.SubpackageType == JT1078SubPackageType.分包处理时的中间包) + { + if (SubcontractKey.TryGetValue(item.SIM, out var buffer)) + { + SubcontractKey[item.SIM] = buffer.Concat(item.Bodies).ToArray(); + } + } + else if (item.Label3.SubpackageType == JT1078SubPackageType.分包处理时的最后一个包) + { + if (SubcontractKey.TryGetValue(item.SIM, out var buffer)) + { + DataBlockingCollection.Add(buffer.Concat(item.Bodies).ToArray()); + } + } + else + { + DataBlockingCollection.Add(item.Bodies); + } } catch { diff --git a/src/JT1078.DotNetty.TestHosting/JT1078WebSocketPushHostedService.cs b/src/JT1078.DotNetty.TestHosting/JT1078WebSocketPushHostedService.cs index 82650cc..c314db7 100644 --- a/src/JT1078.DotNetty.TestHosting/JT1078WebSocketPushHostedService.cs +++ b/src/JT1078.DotNetty.TestHosting/JT1078WebSocketPushHostedService.cs @@ -20,6 +20,7 @@ namespace JT1078.DotNetty.TestHosting JT1078WebSocketSessionManager jT1078WebSocketSessionManager; private readonly JT1078DataService jT1078DataService; private readonly ConcurrentDictionary SubcontractKey; + public JT1078WebSocketPushHostedService( JT1078DataService jT1078DataService, JT1078WebSocketSessionManager jT1078WebSocketSessionManager) @@ -32,59 +33,24 @@ namespace JT1078.DotNetty.TestHosting { Task.Run(() => { - while (true) + while (!cancellationToken.IsCancellationRequested) { try { - foreach (var item in jT1078DataService.DataBlockingCollection.GetConsumingEnumerable()) + foreach (var item in jT1078DataService.DataBlockingCollection.GetConsumingEnumerable(cancellationToken)) { - //if (jT1078WebSocketSessionManager.GetAll().Count() > 0) - //{ - // Parallel.ForEach(jT1078WebSocketSessionManager.GetAll(), new ParallelOptions { MaxDegreeOfParallelism = 5 }, session => - // { - // //if (item.Label3.SubpackageType == JT1078SubPackageType.分包处理时的第一个包) - // //{ - // // SubcontractKey.TryRemove(item.SIM, out _); - - // // SubcontractKey.TryAdd(item.SIM, item.Bodies); - // //} - // //else if (item.Label3.SubpackageType == JT1078SubPackageType.分包处理时的中间包) - // //{ - // // if (SubcontractKey.TryGetValue(item.SIM, out var buffer)) - // // { - // // SubcontractKey[item.SIM] = buffer.Concat(item.Bodies).ToArray(); - // // } - // //} - // //else if (item.Label3.SubpackageType == JT1078SubPackageType.分包处理时的最后一个包) - // //{ - // // if (SubcontractKey.TryGetValue(item.SIM, out var buffer)) - // // { - // // session.Channel.WriteAndFlushAsync(new BinaryWebSocketFrame(Unpooled.WrappedBuffer(buffer.Concat(item.Bodies).ToArray()))); - // // } - // //} - // //else - // //{ - // session.Channel.WriteAndFlushAsync(new BinaryWebSocketFrame(Unpooled.WrappedBuffer(item.Bodies))); - // // } - // }); - //} - - if (jT1078WebSocketSessionManager.GetAll().Count() > 0) + Parallel.ForEach(jT1078WebSocketSessionManager.GetAll(), new ParallelOptions { MaxDegreeOfParallelism = 5 }, session => { - Parallel.ForEach(jT1078WebSocketSessionManager.GetAll(), new ParallelOptions { MaxDegreeOfParallelism = 5 }, session => - { - session.Channel.WriteAndFlushAsync(new BinaryWebSocketFrame(Unpooled.WrappedBuffer(item.Bodies))); - }); - } + session.Channel.WriteAndFlushAsync(new BinaryWebSocketFrame(Unpooled.WrappedBuffer(item))); + }); } } catch { } - Thread.Sleep(10000); } - }); + }, cancellationToken); return Task.CompletedTask; } diff --git a/src/JT1078.DotNetty.TestHosting/Program.cs b/src/JT1078.DotNetty.TestHosting/Program.cs index 0da1aa0..c8e95b9 100644 --- a/src/JT1078.DotNetty.TestHosting/Program.cs +++ b/src/JT1078.DotNetty.TestHosting/Program.cs @@ -58,17 +58,19 @@ namespace JT1078.DotNetty.TestHosting services.AddSingleton(); services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); services.AddSingleton(); - services.AddJT1078Core(hostContext.Configuration) - .AddJT1078TcpHost() - .Replace() - .Builder() - //.AddJT1078UdpHost() - //.Replace() - //.Builder() - .AddJT1078WebSocketHost() + services.AddJT1078Core(hostContext.Configuration); + // .AddJT1078TcpHost() + // .Replace() + // .Builder() + // .AddJT1078UdpHost() + // .Replace() + // .Builder() + // .AddJT1078WebSocketHost() // .Replace() - .Builder(); - services.AddHostedService(); + // .Builder(); + //services.AddHostedService(); + //services.AddHostedService(); + services.AddHostedService(); }); await serverHostBuilder.RunConsoleAsync(); diff --git a/src/JT1078.DotNetty.TestHosting/RTMP/FFMPEGRTMPHostedService.cs b/src/JT1078.DotNetty.TestHosting/RTMP/FFMPEGRTMPHostedService.cs new file mode 100644 index 0000000..ac0c685 --- /dev/null +++ b/src/JT1078.DotNetty.TestHosting/RTMP/FFMPEGRTMPHostedService.cs @@ -0,0 +1,54 @@ +using DotNetty.Buffers; +using DotNetty.Codecs.Http.WebSockets; +using JT1078.DotNetty.Core.Session; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using JT1078.Protocol; +using System.Collections.Concurrent; +using JT1078.Protocol.Enums; + +namespace JT1078.DotNetty.TestHosting +{ + class FFMPEGRTMPHostedService : IHostedService + { + private readonly JT1078DataService jT1078DataService; + private readonly FFMPEGRTMPPipingService fFMPEGPipingService; + public FFMPEGRTMPHostedService( + JT1078DataService jT1078DataService) + { + this.jT1078DataService = jT1078DataService; + fFMPEGPipingService = new FFMPEGRTMPPipingService("demo1"); + } + public Task StartAsync(CancellationToken cancellationToken) + { + Task.Run(() => + { + + try + { + foreach (var item in jT1078DataService.DataBlockingCollection.GetConsumingEnumerable(cancellationToken)) + { + fFMPEGPipingService.Wirte(item); + } + } + catch(Exception ex) + { + Console.WriteLine(ex); + } + + }, cancellationToken); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + } +} diff --git a/src/JT1078.DotNetty.TestHosting/RTMP/FFMPEGRTMPPipingService.cs b/src/JT1078.DotNetty.TestHosting/RTMP/FFMPEGRTMPPipingService.cs new file mode 100644 index 0000000..46e8276 --- /dev/null +++ b/src/JT1078.DotNetty.TestHosting/RTMP/FFMPEGRTMPPipingService.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Pipes; +using System.Text; + +namespace JT1078.DotNetty.TestHosting +{ + /// + /// 1.部署 RTMP 服务器 https://github.com/a1q123456/Harmonic + /// 2.使用ffplay播放器查看 ./ffplay rtmp://127.0.0.1/living/streamName + /// ref: + /// https://stackoverflow.com/questions/32157774/ffmpeg-output-pipeing-to-named-windows-pipe + /// https://mathewsachin.github.io/blog/2017/07/28/ffmpeg-pipe-csharp.html + /// https://csharp.hotexamples.com/examples/-/NamedPipeServerStream/-/php-namedpipeserverstream-class-examples.html + /// + /// ffmpeg pipe作为客户端 + /// NamedPipeServerStream作为服务端 + /// + public class FFMPEGRTMPPipingService : IDisposable + { + private readonly Process process; + private readonly NamedPipeServerStream pipeServer; + public FFMPEGRTMPPipingService(string pipeName) + { + pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.WriteThrough, 10000, 10000); + string rtmp = "rtmp://127.0.0.1/living/streamName"; + process = new Process + { + StartInfo = + { + FileName = @"C:\ffmpeg\bin\ffmpeg.exe", + Arguments = $@"-i \\.\pipe\{pipeName} -c copy -f flv {rtmp}", + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardError = true + } + }; + process.Start(); + process.ErrorDataReceived += ErrorDataReceived; + pipeServer.WaitForConnection(); + } + + public void ErrorDataReceived(object sender, DataReceivedEventArgs e) + { + Console.WriteLine(e.Data); + } + + public void Wirte(byte[] buffer) + { + if (pipeServer.IsConnected) + pipeServer.WriteAsync(buffer); + } + + public void Dispose() + { + try + { + process.Kill(); + pipeServer.Flush(); + } + catch + { + + } + process.Dispose(); + pipeServer.Dispose(); + } + } +} diff --git a/src/JT1078.DotNetty.Udp/JT1078.DotNetty.Udp.csproj b/src/JT1078.DotNetty.Udp/JT1078.DotNetty.Udp.csproj index 113f145..abe7219 100644 --- a/src/JT1078.DotNetty.Udp/JT1078.DotNetty.Udp.csproj +++ b/src/JT1078.DotNetty.Udp/JT1078.DotNetty.Udp.csproj @@ -1,15 +1,28 @@  - + netstandard2.0 + 7.3 + Copyright 2019. + SmallChi(Koike) JT1078.DotNetty.Udp JT1078.DotNetty.Udp 基于DotNetty实现的JT1078DotNetty的Udp服务 基于DotNetty实现的JT1078DotNetty的Udp服务 + https://github.com/SmallChi/JT1078DotNetty + https://github.com/SmallChi/JT1078DotNetty + https://github.com/SmallChi/JT1078DotNetty/blob/master/LICENSE + https://github.com/SmallChi/JT1078DotNetty/blob/master/LICENSE + false + false + LICENSE + true - + + + diff --git a/src/JT1078.DotNetty.WebSocket/JT1078.DotNetty.WebSocket.csproj b/src/JT1078.DotNetty.WebSocket/JT1078.DotNetty.WebSocket.csproj index 416873d..79385f5 100644 --- a/src/JT1078.DotNetty.WebSocket/JT1078.DotNetty.WebSocket.csproj +++ b/src/JT1078.DotNetty.WebSocket/JT1078.DotNetty.WebSocket.csproj @@ -1,11 +1,22 @@  - + netstandard2.0 + 7.3 + Copyright 2019. + SmallChi(Koike) JT1078.DotNetty.WebSocket JT1078.DotNetty.WebSocket 基于DotNetty实现的JT1078DotNetty的WebSocket服务 基于DotNetty实现的JT1078DotNetty的WebSocket服务 + https://github.com/SmallChi/JT1078DotNetty + https://github.com/SmallChi/JT1078DotNetty + https://github.com/SmallChi/JT1078DotNetty/blob/master/LICENSE + https://github.com/SmallChi/JT1078DotNetty/blob/master/LICENSE + false + false + LICENSE + true @@ -18,5 +29,7 @@ - + + + diff --git a/src/SharedProperties.props b/src/SharedProperties.props deleted file mode 100644 index 0ac4c30..0000000 --- a/src/SharedProperties.props +++ /dev/null @@ -1,19 +0,0 @@ - - - 7.3 - Copyright 2019. - SmallChi(Koike) - https://github.com/SmallChi/JT1078DotNetty - https://github.com/SmallChi/JT1078DotNetty - https://github.com/SmallChi/JT1078DotNetty/blob/master/LICENSE - https://github.com/SmallChi/JT1078DotNetty/blob/master/LICENSE - false - 1.0.0-preview2 - false - LICENSE - true - - - - - diff --git a/src/Version.props b/src/Version.props new file mode 100644 index 0000000..244968f --- /dev/null +++ b/src/Version.props @@ -0,0 +1,5 @@ + + + 1.0.0-preview2 + + \ No newline at end of file