소스 검색

添加项目文件。

master
H Vs 9 달 전
부모
커밋
c486772191
28개의 변경된 파일1143개의 추가작업 그리고 0개의 파일을 삭제
  1. +30
    -0
      .dockerignore
  2. +9
    -0
      .gitignore
  3. +7
    -0
      NearCardAttendance.Common/Class1.cs
  4. +26
    -0
      NearCardAttendance.Common/Consts.cs
  5. +14
    -0
      NearCardAttendance.Common/NearCardAttendance.Common.csproj
  6. +128
    -0
      NearCardAttendance.Common/helper/HttpHelper.cs
  7. +7
    -0
      NearCardAttendance.Model/Class1.cs
  8. +9
    -0
      NearCardAttendance.Model/NearCardAttendance.Model.csproj
  9. +7
    -0
      NearCardAttendance.Service/Class1.cs
  10. +19
    -0
      NearCardAttendance.Service/NearCardAttendance.Service.csproj
  11. +91
    -0
      NearCardAttendance.Service/TcpServer/Handler/ProtocolHandler.cs
  12. +142
    -0
      NearCardAttendance.Service/TcpServer/Handler/RegisterHandler.cs
  13. +21
    -0
      NearCardAttendance.Service/TcpServer/Mapper/ScheduleResendManager.cs
  14. +23
    -0
      NearCardAttendance.Service/TcpServer/Mapper/TcpClientsManager.cs
  15. +47
    -0
      NearCardAttendance.Service/TcpServer/Protocol/ProtocolParser.cs
  16. +39
    -0
      NearCardAttendance.Service/TcpServer/Protocol/ProtocolWrapper.cs
  17. +31
    -0
      NearCardAttendance.TcpServer/Config/ThreadInfoEnricher.cs
  18. +33
    -0
      NearCardAttendance.TcpServer/Dockerfile
  19. +44
    -0
      NearCardAttendance.TcpServer/NearCardAttendance.TcpServer.csproj
  20. +112
    -0
      NearCardAttendance.TcpServer/Program.cs
  21. +10
    -0
      NearCardAttendance.TcpServer/Properties/launchSettings.json
  22. +77
    -0
      NearCardAttendance.TcpServer/Server.cs
  23. +4
    -0
      NearCardAttendance.TcpServer/appsettings.debug.json
  24. +121
    -0
      NearCardAttendance.TcpServer/appsettings.json
  25. +3
    -0
      NearCardAttendance.TcpServer/appsettings.test.json
  26. +43
    -0
      NearCardAttendance.sln
  27. +29
    -0
      near_card_attendance_run.sh
  28. +17
    -0
      setup_test.sh

+ 30
- 0
.dockerignore 파일 보기

@@ -0,0 +1,30 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**

+ 9
- 0
.gitignore 파일 보기

@@ -0,0 +1,9 @@
*.user
*.suo
.vs/
*.log
obj/
bin/
.idea/
.vscode/
publish/

+ 7
- 0
NearCardAttendance.Common/Class1.cs 파일 보기

@@ -0,0 +1,7 @@
namespace NearCardAttendance.Common
{
public class Class1
{

}
}

+ 26
- 0
NearCardAttendance.Common/Consts.cs 파일 보기

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NearCardAttendance.Common
{
public class Consts
{
/// <summary>
/// HttpClient常用配置分组名称
/// </summary>
public const string DEFAULT_HTTPCLIENT_NAME = "DEFAULT_HTTP";

/// <summary>
/// 纪元时间(UTC时间戳起始计算时间)
/// </summary>
public static DateTime EraUtcTime = DateTime.Parse("1970/01/01");

/// <summary>
/// 有效定位的半径阈值(大于该值则为无效定位)
/// </summary>
public static int RadiusThreshold = 150;
}
}

+ 14
- 0
NearCardAttendance.Common/NearCardAttendance.Common.csproj 파일 보기

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

</Project>

+ 128
- 0
NearCardAttendance.Common/helper/HttpHelper.cs 파일 보기

@@ -0,0 +1,128 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Net.Security;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Microsoft.Extensions.Logging;

namespace NearCardAttendance.Common.helper
{

public class HttpHelper
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger<HttpHelper> _logger;

public HttpHelper(IHttpClientFactory httpClientFactory, ILogger<HttpHelper> logger)
{
_httpClientFactory = httpClientFactory;
_logger = logger;

ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult!);
}


public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
return true;
}

public async Task<string?> HttpToGetAsync(string url)
{
return await HttpToGetAsync(url, new List<KeyValuePair<string, string>>());
}

public async Task<string?> HttpToGetAsync(string url, List<KeyValuePair<string, string>> headers)
{
var client = _httpClientFactory.CreateClient(Consts.DEFAULT_HTTPCLIENT_NAME);
if (headers != null && headers.Count > 0) //指定请求头
{
headers.ForEach(e =>
{
client.DefaultRequestHeaders.Add(e.Key, e.Value);
});
}

try
{
using (var response = await client.GetAsync(url).ConfigureAwait(false))
{
if (!response.IsSuccessStatusCode) return null;
else
{
var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return result;
}
}
}
catch (Exception ex)
{
_logger.LogError($"HttpToGetAsync发生异常, Msg:{ex.Message}\n{ex.StackTrace}");
return null;
}
}

public async Task<string?> HttpToPostAsync(string url, object data)
{
return await HttpToPostAsync(url, data, new List<KeyValuePair<string, string>>());
}

public async Task<string?> HttpToPostAsync(string url, object data, List<KeyValuePair<string, string>> headers)
{
if (data == null) return null;

var client = _httpClientFactory.CreateClient(Consts.DEFAULT_HTTPCLIENT_NAME);
if (headers != null && headers.Count > 0) //指定请求头
{
headers.ForEach(e =>
{
client.DefaultRequestHeaders.Add(e.Key, e.Value);
});

}

string? body;
if (data is string) body = data as string;
else body = JsonConvert.SerializeObject(data);

try
{
using (var content = new StringContent(body!))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (var response = await client.PostAsync(url, content).ConfigureAwait(false))
{
if (!response.IsSuccessStatusCode) return null;
else
{
var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return result;
}
}
}
}
catch (Exception ex)
{
_logger.LogError($"HttpToPostAsync发生异常, Msg:{ex.Message}\n{ex.StackTrace}");
return null;
}
}
/// <summary>
/// Authorization 的 Base64 加密
/// </summary>
/// <param name="username"></param>
/// <param name="password"></param>
/// <returns></returns>
public string GetEncodedCredentials(string username, string password)
{
string mergedCredentials = string.Format("{0}:{1}", username, password);
byte[] byteCredentials = UTF8Encoding.UTF8.GetBytes(mergedCredentials);
return Convert.ToBase64String(byteCredentials);
}
}
}

+ 7
- 0
NearCardAttendance.Model/Class1.cs 파일 보기

@@ -0,0 +1,7 @@
namespace NearCardAttendance.Model
{
public class Class1
{

}
}

+ 9
- 0
NearCardAttendance.Model/NearCardAttendance.Model.csproj 파일 보기

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>

+ 7
- 0
NearCardAttendance.Service/Class1.cs 파일 보기

@@ -0,0 +1,7 @@
namespace NearCardAttendance.Service
{
public class Class1
{

}
}

+ 19
- 0
NearCardAttendance.Service/NearCardAttendance.Service.csproj 파일 보기

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="DotNetty.Handlers" Version="0.7.5" />
<PackageReference Include="DotNetty.Transport" Version="0.7.5" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\NearCardAttendance.Common\NearCardAttendance.Common.csproj" />
</ItemGroup>

</Project>

+ 91
- 0
NearCardAttendance.Service/TcpServer/Handler/ProtocolHandler.cs 파일 보기

@@ -0,0 +1,91 @@
using DotNetty.Buffers;
using DotNetty.Transport.Channels;
using Microsoft.Extensions.Logging;
using NearCardAttendance.Service.TcpServer.Protocol;
using System;
using System.Text;

namespace NearCardAttendance.Service.TcpServer.Handler
{
public class ProtocolHandler : SimpleChannelInboundHandler<IByteBuffer>
{
private IByteBuffer? buffer;
private readonly ILogger<ProtocolHandler> _logger;

public ProtocolHandler(ILogger<ProtocolHandler> logger)
{
_logger = logger;
}

public override async void ChannelActive(IChannelHandlerContext context)
{
// Handle channel active event
}

public override void ChannelInactive(IChannelHandlerContext context)
{
ReleaseBuffer();
base.ChannelInactive(context);
}

protected override void ChannelRead0(IChannelHandlerContext context, IByteBuffer message)
{
try
{
string content = message.ToString(Encoding.ASCII);
_logger.LogInformation($"{nameof(ProtocolHandler)} -- {nameof(ChannelRead0)} -- 最开始接受内容:{content}");

ProcessMessage(context, content);
}
catch (Exception ex)
{
ReleaseBuffer();
_logger.LogInformation($"{nameof(ProtocolHandler)} --- {nameof(ChannelRead0)} 处理出错\n{ex.Message}\n{ex.StackTrace}");
}
}

private void ProcessMessage(IChannelHandlerContext context, string content)
{
buffer ??= Unpooled.Buffer();

byte[] bytes = Encoding.ASCII.GetBytes(content);
buffer.WriteBytes(Unpooled.WrappedBuffer(bytes));

if (int.TryParse(buffer.ToString(Encoding.ASCII).Substring(0, 4), out int messageLength))
{
Console.WriteLine(buffer.ToString(Encoding.ASCII));
if (buffer.ToString(Encoding.ASCII).Length == messageLength)
{
//var parser = buffer.ToString(Encoding.ASCII);
ProtocolParser parser = new(buffer.ToString(Encoding.ASCII));
context.FireChannelRead(parser);
Console.WriteLine($"发送正常:{parser}");
//ProtocolWrapper wrapper = new ProtocolWrapper("82", parser.SeqNo, DateTime.Now.ToString("yyyyMMddHHmmss"));
//Console.WriteLine(wrapper.GenerateProtocolString());
Console.WriteLine($"length:{parser.MessageLength},func_no:{parser.FuncNo},seq_no:{parser.SeqNo},data:{ parser.Data}");
ReleaseBuffer();
}
else if (buffer.ToString(Encoding.ASCII).Length > messageLength)
{
// var parser = buffer.ToString(Encoding.ASCII).Substring(0, messageLength);
ProtocolParser parser = new(buffer.ToString(Encoding.ASCII).Substring(0, messageLength));
context.FireChannelRead(parser);
//ReleaseBuffer();

var overLongbuffer = Unpooled.Buffer();
Console.WriteLine($"过长消息:{buffer.ToString(Encoding.ASCII).Substring(messageLength)}");
overLongbuffer.WriteBytes(Unpooled.WrappedBuffer(Encoding.ASCII.GetBytes(buffer.ToString(Encoding.ASCII).Substring(messageLength))));
ReleaseBuffer();
buffer = overLongbuffer;
Console.WriteLine($"剩余消息{buffer.ToString(Encoding.ASCII)}");
}
}
}

private void ReleaseBuffer()
{
buffer?.Release();
buffer = null;
}
}
}

+ 142
- 0
NearCardAttendance.Service/TcpServer/Handler/RegisterHandler.cs 파일 보기

@@ -0,0 +1,142 @@
using DotNetty.Buffers;
using DotNetty.Transport.Channels;
using Microsoft.Extensions.Logging;
using NearCardAttendance.Common.helper;
using NearCardAttendance.Service.TcpServer.Mapper;
using NearCardAttendance.Service.TcpServer.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NearCardAttendance.Service.TcpServer.Handler
{
public class RegisterHandler : ChannelHandlerAdapter
{
private readonly ILogger<RegisterHandler> _logger;
private readonly HttpHelper _httpHelper = default!;
private readonly IDisposable _loggerScope = default!;

private readonly TcpClientsManager _managerTcpClients;
private readonly ScheduleResendManager _managerScheduleResend;

public RegisterHandler(ILogger<RegisterHandler> logger,HttpHelper httpHelper)
{
_logger = logger;
_httpHelper = httpHelper;
}

public override void ChannelActive(IChannelHandlerContext context)
{
base.ChannelActive(context); // Pass the event to the next handler
}

public override async void ChannelInactive(IChannelHandlerContext context)
{
try
{

}
catch (Exception ex)
{
_logger.LogInformation($"{nameof(RegisterHandler)} --- {nameof(ChannelInactive)} 出错\n{ex.Message}\n{ex.StackTrace}");
}
}

public override void HandlerRemoved(IChannelHandlerContext context)
{
base.HandlerRemoved(context);
}

public override async void ChannelRead(IChannelHandlerContext context, object message)
{
if (message is ProtocolParser parser)
{
try
{
using (_logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = parser.SeqNo }))
{
//认证
if (parser.FuncNo.Equals("10"))
{
#region 认证业务
// PHONE_AUTHEN
ProtocolWrapper phoneAuthWrapper = new(parser.FuncNo, parser.SeqNo, "1");
await SendToTcpClientAsync(phoneAuthWrapper, context.Channel);

// ABT_STATUS 延时3秒 给终端同步时间
await context.Channel.EventLoop.Schedule(async () =>
{
ProtocolWrapper abtStatusWrapper = new("82", parser.SeqNo, DateTime.Now.ToString("yyyyMMddHHmmss"));
await SendToTcpClientAsync(abtStatusWrapper, context.Channel);
},TimeSpan.FromSeconds(3));

#endregion
}
else if (parser.FuncNo.Equals("82"))
{
// 认证成功
_logger.LogInformation($"认证成功{parser.Data}.");
}
// 心跳
else if (parser.FuncNo.Equals("05"))
{
ProtocolWrapper stdtSignRecsWrapper = new(parser.FuncNo, parser.SeqNo,"");
await SendToTcpClientAsync(stdtSignRecsWrapper, context.Channel);
} // STDT_SIGN_RECS
else if (parser.FuncNo.Equals("04"))
{
// 回应设备
ProtocolWrapper stdtSignRecsWrapper = new(parser.FuncNo, parser.SeqNo,"1");
await SendToTcpClientAsync(stdtSignRecsWrapper, context.Channel);
// 刷卡考勤信息,需要推送给第三方平台

//var url = "";

//await _httpHelper.HttpToPostAsync(url, new object());
}


//switch (parser.FuncNo)
//{
// case "10":
// break;

// case "82":
// break;
// default:
// break;
//}
}
}
catch (Exception ex)
{
_logger.LogInformation($"{nameof(RegisterHandler)} --- {nameof(ChannelRead)} 处理消息 {parser.SeqNo} 出错\n{ex.Message}\n{ex.StackTrace}");

}

}
}

/// <summary>
/// 发送到TCP客户端
/// </summary>
/// <param name="wrapper"></param>
/// <param name="channel"></param>
private async Task SendToTcpClientAsync(ProtocolWrapper wrapper, IChannel channel)
{

string protocolMsg = wrapper.GenerateProtocolString();

// 发送protocolMsg到tcp客户端
await channel
.WriteAndFlushAsync(Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(protocolMsg)))
.ContinueWith(Action => {
_logger.LogInformation($"{nameof(RegisterHandler)} -- {nameof(SendToTcpClientAsync)} -- 下发设备内容:\n{protocolMsg}");
});
}

}
}

+ 21
- 0
NearCardAttendance.Service/TcpServer/Mapper/ScheduleResendManager.cs 파일 보기

@@ -0,0 +1,21 @@
using DotNetty.Common.Concurrency;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NearCardAttendance.Service.TcpServer.Mapper
{
public class ScheduleResendManager : ConcurrentDictionary<string, IScheduledTask>
{
private readonly ILogger<ScheduleResendManager> _logger;

public ScheduleResendManager(ILogger<ScheduleResendManager> logger)
{
_logger = logger;
}
}
}

+ 23
- 0
NearCardAttendance.Service/TcpServer/Mapper/TcpClientsManager.cs 파일 보기

@@ -0,0 +1,23 @@
using DotNetty.Transport.Channels;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NearCardAttendance.Service.TcpServer.Mapper
{
public class TcpClientsManager : ConcurrentDictionary<string, IChannel>
{
private readonly ILogger<TcpClientsManager> _logger;

public TcpClientsManager(ILogger<TcpClientsManager> logger)
{
_logger = logger;
}


}
}

+ 47
- 0
NearCardAttendance.Service/TcpServer/Protocol/ProtocolParser.cs 파일 보기

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NearCardAttendance.Service.TcpServer.Protocol
{

public class ProtocolParser
{
public int MessageLength { get; private set; } = default!;

public string FuncNo { get; private set; } = default!;

public string SeqNo { get; private set; } = default!;

public string Data { get; private set; } = default!;
//private string _protocolString { get; set; } = default!;
public ProtocolParser(string protocolString)
{
ParseProtocolString(protocolString);
//_protocolString = protocolString;
}

private void ParseProtocolString(string protocolString)
{
try
{
_ = int.TryParse(protocolString.AsSpan(0, 4), out int messageLength);
MessageLength = messageLength;
FuncNo = protocolString.Substring(4,2);
SeqNo = protocolString.Substring(6,4);
Data = protocolString.Substring(10).TrimEnd();
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
// throw new ArgumentException("Invalid protocol string format.");
}
}
}


}

+ 39
- 0
NearCardAttendance.Service/TcpServer/Protocol/ProtocolWrapper.cs 파일 보기

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NearCardAttendance.Service.TcpServer.Protocol
{
public class ProtocolWrapper
{
private string Length { get; }

private string FuncNo { get; }
private string SeqNo { get; }

private string Data { get; }


public ProtocolWrapper(string funcNo,string seqNo,string data)
{
FuncNo =funcNo;
SeqNo=seqNo;
Data=data;
Length = CalculateMessageLength();
}

private string CalculateMessageLength()
{
return string.Format("{0:D4}", GenerateProtocolString().Length + 4);
}

public string GenerateProtocolString()
{
return $"{Length}{FuncNo}{SeqNo}{Data}";
}
}
}

+ 31
- 0
NearCardAttendance.TcpServer/Config/ThreadInfoEnricher.cs 파일 보기

@@ -0,0 +1,31 @@
using Serilog.Configuration;
using Serilog.Core;
using Serilog.Events;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NearCardAttendance.TcpServer.Config
{
public class ThreadInfoEnricher : ILogEventEnricher
{
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{

logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadId", Thread.CurrentThread.ManagedThreadId));
}
}

public static class EnricherExtensions
{
public static LoggerConfiguration WithThreadInfo(this LoggerEnrichmentConfiguration enrich)
{
if (enrich == null)
throw new ArgumentNullException(nameof(enrich));
return enrich.With<ThreadInfoEnricher>();
}
}
}

+ 33
- 0
NearCardAttendance.TcpServer/Dockerfile 파일 보기

@@ -0,0 +1,33 @@
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

#FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 16662

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["NearCardAttendance.TcpServer/NearCardAttendance.TcpServer.csproj", "NearCardAttendance.TcpServer/"]
COPY ["NearCardAttendance.Common/NearCardAttendance.Common.csproj", "NearCardAttendance.Common/"]
COPY ["NearCardAttendance.Service/NearCardAttendance.Service.csproj", "NearCardAttendance.Service/"]
RUN dotnet restore "./NearCardAttendance.TcpServer/./NearCardAttendance.TcpServer.csproj"
COPY . .
WORKDIR "/src/NearCardAttendance.TcpServer"
RUN dotnet build "./NearCardAttendance.TcpServer.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./NearCardAttendance.TcpServer.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

ENV environment=Development
ENV TimeZone=Asia/Shanghai
ENV LANG C.UTF-8
RUN ln -snf /usr/share/zoneinfo/$TimeZone /etc/localtime && echo $TimeZone > /etc/timezone

#ENTRYPOINT ["dotnet", "NearCardAttendance.TcpServer.dll"]
ENTRYPOINT ["sh", "-c", "dotnet NearCardAttendance.TcpServer.dll --environment=$environment"]

+ 44
- 0
NearCardAttendance.TcpServer/NearCardAttendance.TcpServer.csproj 파일 보기

@@ -0,0 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>

<ItemGroup>
<None Remove="appsettings.debug.json" />
<None Remove="appsettings.json" />
<None Remove="appsettings.test.json" />
</ItemGroup>

<ItemGroup>
<Content Include="appsettings.test.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="appsettings.debug.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="DotNetty.Handlers" Version="0.7.5" />
<PackageReference Include="DotNetty.Transport" Version="0.7.5" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.Expressions" Version="3.4.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\NearCardAttendance.Common\NearCardAttendance.Common.csproj" />
<ProjectReference Include="..\NearCardAttendance.Service\NearCardAttendance.Service.csproj" />
</ItemGroup>

</Project>

+ 112
- 0
NearCardAttendance.TcpServer/Program.cs 파일 보기

@@ -0,0 +1,112 @@
using DotNetty.Codecs;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using NearCardAttendance.Common;
using NearCardAttendance.Common.helper;
using NearCardAttendance.Service.TcpServer.Handler;
using NearCardAttendance.Service.TcpServer.Mapper;
using NearCardAttendance.TcpServer.Config;
using Serilog;
using System.Text;

namespace NearCardAttendance.TcpServer
{
internal class Program
{
static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(config).Enrich.WithThreadInfo()
.Filter.ByExcluding(logEvent => logEvent.Level == Serilog.Events.LogEventLevel.Verbose) // 过滤掉VRB级别的日志
.CreateLogger();
try
{
Log.Information("Starting up");

CreateHostBuilder(args).Build().Run();



}
catch (Exception ex)
{
Log.Fatal(ex, "Application start-up failed");
}
finally
{
Log.CloseAndFlush();
}
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureServices((hostContext, services) => {
var configuration = hostContext.Configuration;

#region 配置信息
//services
// .Configure<ServiceConfig>(configuration.GetSection("ServiceConfig"))
// ;
#endregion

#region Http请求
services
.AddSingleton<HttpHelper>()
.AddHttpClient(Consts.DEFAULT_HTTPCLIENT_NAME, c =>
{
c.Timeout = TimeSpan.FromSeconds(10); //超时限制
c.DefaultRequestHeaders.Add("Accept", "application/json");
})
;
#endregion

#region TcpService
services
.AddSingleton<ServerBootstrap>(provider =>
{
var bossGroup = new MultithreadEventLoopGroup();
var workerGroup = new MultithreadEventLoopGroup();

var bootstrap = new ServerBootstrap();
bootstrap.Group(bossGroup, workerGroup)
.Channel<TcpServerSocketChannel>()
.Option(ChannelOption.SoBacklog, 100)
.ChildOption(ChannelOption.TcpNodelay, true) // 低延迟
.ChildHandler(new ActionChannelInitializer<IChannel>(channel =>
{
// var handler = provider.GetRequiredService<ProtocolHandler>();
// var handler = provider.GetRequiredService<SomeServerHandler>();
var pipeline = channel.Pipeline;
pipeline.AddLast(new StringEncoder(Encoding.ASCII));
pipeline.AddLast(
provider.GetRequiredService<ProtocolHandler>(),
provider.GetRequiredService<RegisterHandler>()
//provider.GetRequiredService<HeartBeatHandler>(),
//provider.GetRequiredService<PassThroughHandler>()
); // Add the injected handler
}));
return bootstrap;
})
.AddSingleton<TcpClientsManager>()
.AddSingleton<ScheduleResendManager>()
.AddTransient<ProtocolHandler>()
.AddTransient<RegisterHandler>()
//.AddTransient<HeartBeatHandler>()
//.AddTransient<PassThroughHandler>()
.AddHostedService<Server>()
;
#endregion

});
}
}

+ 10
- 0
NearCardAttendance.TcpServer/Properties/launchSettings.json 파일 보기

@@ -0,0 +1,10 @@
{
"profiles": {
"NearCardAttendance.TcpServer": {
"commandName": "Project",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "debug"
}
}
}
}

+ 77
- 0
NearCardAttendance.TcpServer/Server.cs 파일 보기

@@ -0,0 +1,77 @@
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace NearCardAttendance.TcpServer
{
public class Server : BackgroundService
{
private readonly ILogger<Server> _logger;
private readonly IServiceProvider _serviceProvider;
private readonly ServerBootstrap _serverBootstrap;
private IChannel _serverChannel = default!;
private CancellationTokenSource _tokenSource = null!;

public Server(
ILogger<Server> logger,
ServerBootstrap serverBootstrap,
IServiceProvider serviceProvider)
{
_logger = logger;
_serviceProvider = serviceProvider;
_serverBootstrap = serverBootstrap;
}
public override Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("------StartAsync");
_tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
return base.StartAsync(cancellationToken);
}

public override Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("------StopAsync");
_tokenSource.Cancel(); //停止工作线程
return base.StopAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{

_logger.LogInformation("DotNetty server starting...");

//var address = new IPEndPoint(IPAddress.Any, 12345);

//IChannel _serverChannel = await _serverBootstrap.BindAsync(address);

string ipAddress = "0.0.0.0";
int port = 16662;
var endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
IChannel _serverChannel = await _serverBootstrap.BindAsync(endPoint);
// _serverChannel.GetAttribute(MessageIdAttribute.Key).Set("SomeRequestId");

//_logger.LogInformation("DotNetty server started on {0}.", address);
_logger.LogInformation("DotNetty server started on {0}.", endPoint);

// Wait until the service is stopped
stoppingToken.WaitHandle.WaitOne();

_logger.LogInformation("DotNetty server stopping...");

// Close the server channel and release resources
await _serverChannel.CloseAsync();
_logger.LogInformation("DotNetty server stopped.");
}


}
}

+ 4
- 0
NearCardAttendance.TcpServer/appsettings.debug.json 파일 보기

@@ -0,0 +1,4 @@
{
"AllowedHosts": "*"
}

+ 121
- 0
NearCardAttendance.TcpServer/appsettings.json 파일 보기

@@ -0,0 +1,121 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"HttpClient": "Information"
}
},

"Serilog": {
"Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Async", "Serilog.Sinks.Console", "Serilog.Expressions" ],
"MinimumLevel": {
"Default": "Verbose",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"HttpClient": "Information"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"restrictedToMinimumLevel": "Verbose",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff }[{Level:u3}] [Thread-{ThreadId}] [{SourceContext:l}] [{RequestId}] {Message:lj}{NewLine}{Exception}",
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console"
}
},
{
"Name": "Logger",
"Args": {
"ConfigureLogger": {
"WriteTo": [
{
"Name": "File",
"Args": {
"RestrictedToMinimumLevel": "Information",
"RollingInterval": "Day",
"RollOnFileSizeLimit": "true",
"OutputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff }[{Level:u3}] [Thread-{ThreadId}] [{SourceContext:l}] [{RequestId}] {Message:lj}{NewLine}{Exception}",
"Path": "/var/near_card_attendance/logs/infos/info.log",
"RetainedFileCountLimit": 10 // "--设置日志文件个数最大值,默认31,意思就是只保留最近的31个日志文件", "等于null时永远保留文件": null
//"FileSizeLimitBytes": 20971520, //设置单个文件大小为3M 默认1G
//"RollOnFileSizeLimit": true //超过文件大小后创建新的
}
}
],
"Filter": [
{
"Name": "ByIncludingOnly",
"Args": {
"Expression": "@l = 'Information'"
}
}
]
}
}
},
{
"Name": "Logger",
"Args": {
"ConfigureLogger": {
"WriteTo": [
{
"Name": "File",
"Args": {
"RestrictedToMinimumLevel": "Warning",
"RollingInterval": "Day",
"RollOnFileSizeLimit": "true",
"OutputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff }[{Level:u3}] [Thread-{ThreadId}] [{SourceContext:l}] [{RequestId}] {Message:lj}{NewLine}",
"Path": "/var/near_card_attendance/logs/warnings/warn.log",
"RetainedFileCountLimit": 10
}
}
],
"Filter": [
{
"Name": "ByIncludingOnly",
"Args": {
"Expression": "@l = 'Warning'"
}
}
]
}
}
},
{
"Name": "Logger",
"Args": {
"ConfigureLogger": {
"WriteTo": [
{
"Name": "File",
"Args": {
"RestrictedToMinimumLevel": "Error",
"RollingInterval": "Day",
"RollOnFileSizeLimit": "true",
"OutputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff }[{Level:u3}] [Thread-{ThreadId}][{SourceContext:l}] [{RequestId}] {Message:lj}{NewLine}{Exception}",
"Path": "/var/near_card_attendance/logs/errors/error.log",
"RetainedFileCountLimit": 15 // "--设置日志文件个数最大值,默认31,意思就是只保留最近的31个日志文件", "等于null时永远保留文件": null
//"FileSizeLimitBytes": 20971520, //设置单个文件大小为3M 默认1G
//"RollOnFileSizeLimit": true //超过文件大小后创建新的

}
}
],
"Filter": [
{
"Name": "ByIncludingOnly",
"Args": {
"Expression": "@l = 'Error'"
}
}
]
}
}
}
]
}
}

+ 3
- 0
NearCardAttendance.TcpServer/appsettings.test.json 파일 보기

@@ -0,0 +1,3 @@
{
"AllowedHosts": "*"
}

+ 43
- 0
NearCardAttendance.sln 파일 보기

@@ -0,0 +1,43 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34330.188
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NearCardAttendance.TcpServer", "NearCardAttendance.TcpServer\NearCardAttendance.TcpServer.csproj", "{46A2FEAF-7333-4D41-83F2-5ACDDDD850F5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NearCardAttendance.Service", "NearCardAttendance.Service\NearCardAttendance.Service.csproj", "{2394B5EA-8A6A-4FC4-9218-2EED87E3FC14}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NearCardAttendance.Common", "NearCardAttendance.Common\NearCardAttendance.Common.csproj", "{CC1A7D30-569C-497A-8D94-C23BA11C870D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NearCardAttendance.Model", "NearCardAttendance.Model\NearCardAttendance.Model.csproj", "{10C81D50-6839-4F3C-92C9-C4E6554B8566}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{46A2FEAF-7333-4D41-83F2-5ACDDDD850F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{46A2FEAF-7333-4D41-83F2-5ACDDDD850F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{46A2FEAF-7333-4D41-83F2-5ACDDDD850F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{46A2FEAF-7333-4D41-83F2-5ACDDDD850F5}.Release|Any CPU.Build.0 = Release|Any CPU
{2394B5EA-8A6A-4FC4-9218-2EED87E3FC14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2394B5EA-8A6A-4FC4-9218-2EED87E3FC14}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2394B5EA-8A6A-4FC4-9218-2EED87E3FC14}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2394B5EA-8A6A-4FC4-9218-2EED87E3FC14}.Release|Any CPU.Build.0 = Release|Any CPU
{CC1A7D30-569C-497A-8D94-C23BA11C870D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CC1A7D30-569C-497A-8D94-C23BA11C870D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC1A7D30-569C-497A-8D94-C23BA11C870D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC1A7D30-569C-497A-8D94-C23BA11C870D}.Release|Any CPU.Build.0 = Release|Any CPU
{10C81D50-6839-4F3C-92C9-C4E6554B8566}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{10C81D50-6839-4F3C-92C9-C4E6554B8566}.Debug|Any CPU.Build.0 = Debug|Any CPU
{10C81D50-6839-4F3C-92C9-C4E6554B8566}.Release|Any CPU.ActiveCfg = Release|Any CPU
{10C81D50-6839-4F3C-92C9-C4E6554B8566}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2A15CF2F-2E7D-42D5-B8D7-9A22592049A0}
EndGlobalSection
EndGlobal

+ 29
- 0
near_card_attendance_run.sh 파일 보기

@@ -0,0 +1,29 @@
#!/bin/bash
environment=$1
version=$2
echo "环境变量为${environment},版本为$version!"
if [[ ${environment} == 'production' ]]; then
echo "开始远程构建容器"
docker stop near_card_attendance || true
docker rm near_card_attendance || true
docker rmi -f $(docker images | grep registry.cn-shanghai.aliyuncs.com/gps_card/near_card_attendance | awk '{print $3}')
#docker login --username=telpo_linwl@1111649216405698 --password=telpo#1234 registry.cn-shanghai.aliyuncs.com
docker login --username=rzl_wangjx@1111649216405698 --password=telpo.123 registry.cn-shanghai.aliyuncs.com
docker pull registry.cn-shanghai.aliyuncs.com/gps_card/near_card_attendance:$version
docker run --network=host -p 16662:16662 -d -e environment=production -v /home/data/near_card_attendance/log:/var/near_card_attendance/logs --restart=always --name near_card_attendance registry.cn-shanghai.aliyuncs.com/gps_card/near_card_attendance:$version;
#删除产生的None镜像
docker rmi -f $(docker images | grep none | awk '{print $3}')
docker ps -a

elif [[ ${environment} == 'test' || ${environment} == 'presure' ]]; then
echo "开始在测试环境远程构建容器"
docker stop near_card_attendance || true
docker rm near_card_attendance || true
docker rmi -f $(docker images | grep 139.224.254.18:5000/near_card_attendance | awk '{print $3}')
docker pull 139.224.254.18:5000/near_card_attendance:$version
docker run --network=host -d -p 16662:16662 -e environment=${environment} -v /home/data/near_card_attendance/log:/var/near_card_attendance/logs --restart=always --name near_card_attendance 139.224.254.18:5000/near_card_attendance:$version;
#删除产生的None镜像
docker rmi -f $(docker images | grep none | awk '{print $3}')
docker ps -a

fi

+ 17
- 0
setup_test.sh 파일 보기

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
image_version=$version
# 删除镜像
docker rmi -f $(
docker images | grep 139.224.254.18:5000/near_card_attendance | awk '{print $3}'
)
# 构建telpo/mrp:$image_version镜像
docker build -f ./NearCardAttendance.TcpServer/Dockerfile . -t telpo/near_card_attendance:$image_version
#TODO:推送镜像到私有仓库
echo '=================开始推送镜像======================='
docker tag telpo/near_card_attendance:$image_version 139.224.254.18:5000/near_card_attendance:$image_version
docker push 139.224.254.18:5000/near_card_attendance:$image_version
echo '=================推送镜像完成======================='
#删除产生的None镜像
docker rmi -f $(docker images | grep none | awk '{print $3}')
# 查看镜像列表
docker images

Loading…
취소
저장