!提交代码
This commit is contained in:
182
WCS.BLL/Tool/Api/ApiHelp.cs
Normal file
182
WCS.BLL/Tool/Api/ApiHelp.cs
Normal file
@ -0,0 +1,182 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using WCS.BLL.Tool.Api.Models;
|
||||
|
||||
namespace WCS.BLL.Tool.Api
|
||||
{
|
||||
public static class ApiHelp
|
||||
{
|
||||
public static HttpClient httpClient;
|
||||
static ApiHelp()
|
||||
{
|
||||
httpClient = new HttpClient();
|
||||
httpClient.Timeout = TimeSpan.FromSeconds(5);
|
||||
httpClient.DefaultRequestHeaders.Add("User-Agent", "Chrome/95.0.4638.69 Safari/537.36");
|
||||
//ServicePointManager.Expect100Continue = false;
|
||||
}
|
||||
|
||||
public static ApiResult Get(string uri, object? query = null, object? body = null)
|
||||
{
|
||||
return Send(HttpMethod.Get, uri, query, body);
|
||||
}
|
||||
|
||||
public static ApiResult Get(IEnumerable<object> uri, object? query = null, object? body = null)
|
||||
{
|
||||
return Send(HttpMethod.Get, uri, query, body);
|
||||
}
|
||||
|
||||
public static ApiResult<T> Get<T>(string uri, object? query = null, object? body = null)
|
||||
{
|
||||
return Send<T>(HttpMethod.Get, uri, query, body);
|
||||
}
|
||||
|
||||
public static ApiResult<T> Get<T>(IEnumerable<object> uri, object? query = null, object? body = null)
|
||||
{
|
||||
return Send<T>(HttpMethod.Get, uri, query, body);
|
||||
}
|
||||
|
||||
public static ApiResult Post(string uri, object? body = null, object? query = null)
|
||||
{
|
||||
return Send(HttpMethod.Post, uri, query, body);
|
||||
}
|
||||
|
||||
public static ApiResult Post(IEnumerable<object> uri, object? body = null, object? query = null)
|
||||
{
|
||||
return Send(HttpMethod.Post, uri, query, body);
|
||||
}
|
||||
|
||||
public static ApiResult<T> Post<T>(string uri, object? body = null, object? query = null)
|
||||
{
|
||||
return Send<T>(HttpMethod.Post, uri, query, body);
|
||||
}
|
||||
|
||||
public static ApiResult<T> Post<T>(IEnumerable<object> uri, object? body = null, object? query = null)
|
||||
{
|
||||
return Send<T>(HttpMethod.Post, uri, query, body);
|
||||
}
|
||||
|
||||
public static ApiResult Send(HttpMethod method, string uri, object? query = null, object? body = null)
|
||||
{
|
||||
return Send(method, new string[] { uri }, query, body);
|
||||
}
|
||||
|
||||
public static ApiResult Send(HttpMethod method, IEnumerable<object> uri, object? query = null, object? body = null)
|
||||
{
|
||||
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, "".AppendPathSegments(uri).SetQueryParams(query));
|
||||
|
||||
if (body != null)
|
||||
{
|
||||
var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
|
||||
httpRequestMessage.Content = content;
|
||||
}
|
||||
|
||||
var re = httpClient.SendAsync(httpRequestMessage).Result;
|
||||
if (!re.IsSuccessStatusCode)
|
||||
return new ApiResult() { Code = ((int)re.StatusCode).ToString() };
|
||||
|
||||
var con = re.Content.ReadAsStringAsync().Result;
|
||||
return JsonConvert.DeserializeObject<ApiResult>(con) ?? new ApiResult();
|
||||
}
|
||||
|
||||
public static ApiResult<T> Send<T>(HttpMethod method, string uri, object? query = null, object? body = null)
|
||||
{
|
||||
return Send<T>(method, new string[] { uri }, query, body);
|
||||
}
|
||||
|
||||
public static ApiResult<T> Send<T>(HttpMethod method, IEnumerable<object> uri, object? query = null, object? body = null)
|
||||
{
|
||||
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, "".AppendPathSegments(uri).SetQueryParams(query));
|
||||
|
||||
if (body != null)
|
||||
{
|
||||
var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
|
||||
httpRequestMessage.Content = content;
|
||||
}
|
||||
|
||||
var re = httpClient.SendAsync(httpRequestMessage).Result;
|
||||
if (!re.IsSuccessStatusCode)
|
||||
return new ApiResult<T>() { Code = ((int)re.StatusCode).ToString() };
|
||||
|
||||
var con = re.Content.ReadAsStringAsync().Result;
|
||||
return JsonConvert.DeserializeObject<ApiResult<T>>(con) ?? new ApiResult<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 追加路径片段(有更高要求可以使用Flurl库)
|
||||
/// </summary>
|
||||
/// <param name="url">地址,如 https://www.baidu.com</param>
|
||||
/// <param name="segments">路径片段</param>
|
||||
/// <returns>地址</returns>
|
||||
public static string AppendPathSegments(this string url, IEnumerable<object> segments)
|
||||
{
|
||||
string urlStr = url;
|
||||
foreach (var segment in segments)
|
||||
{
|
||||
var val = segment?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(val))
|
||||
continue;
|
||||
|
||||
if (urlStr.EndsWith("/"))
|
||||
urlStr = urlStr.Substring(0, urlStr.Length - 1);
|
||||
|
||||
urlStr += val!.StartsWith("/") ? val : $"/{val}";
|
||||
}
|
||||
return urlStr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置Query参数(有更高要求可以使用Flurl库)
|
||||
/// </summary>
|
||||
/// <param name="url">地址,如 https://www.baidu.com/s</param>
|
||||
/// <param name="values">参数,支持字典和对象</param>
|
||||
/// <returns>地址</returns>
|
||||
public static string SetQueryParams(this string url, object? values)
|
||||
{
|
||||
string urlStr = url;
|
||||
if (values == null)
|
||||
return urlStr;
|
||||
|
||||
List<string> kv = new List<string>();
|
||||
if (values is IEnumerable jh)
|
||||
{
|
||||
if (jh is IDictionary dict)
|
||||
{
|
||||
foreach (DictionaryEntry item in dict)
|
||||
kv.Add($"{item.Key?.ToString()}={item.Value?.ToString()}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in values.GetType().GetProperties())
|
||||
{
|
||||
if (item.CanRead)
|
||||
kv.Add($"{item.Name}={item.GetValue(values)?.ToString()}");
|
||||
}
|
||||
}
|
||||
|
||||
if (kv.Any())
|
||||
{
|
||||
if (!urlStr.Contains("?"))
|
||||
urlStr += "?";
|
||||
else
|
||||
{
|
||||
if (!urlStr.EndsWith("&"))
|
||||
urlStr += "&";
|
||||
}
|
||||
|
||||
urlStr += string.Join("&", kv);
|
||||
}
|
||||
|
||||
return urlStr;
|
||||
}
|
||||
}
|
||||
}
|
19
WCS.BLL/Tool/Api/Models/ApiResult.cs
Normal file
19
WCS.BLL/Tool/Api/Models/ApiResult.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WCS.BLL.Tool.Api.Models
|
||||
{
|
||||
public class ApiResult
|
||||
{
|
||||
public string Code { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
|
||||
public class ApiResult<T> : ApiResult
|
||||
{
|
||||
public T Data { get; set; }
|
||||
}
|
||||
}
|
161
WCS.BLL/Tool/Logs.cs
Normal file
161
WCS.BLL/Tool/Logs.cs
Normal file
@ -0,0 +1,161 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using WCS.BLL.Config;
|
||||
using WCS.DAL;
|
||||
using WCS.Model;
|
||||
|
||||
namespace WCS.BLL
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志类型
|
||||
/// </summary>
|
||||
public enum LogsType
|
||||
{
|
||||
/// <summary>
|
||||
/// 信息
|
||||
/// </summary>
|
||||
Info,
|
||||
/// <summary>
|
||||
/// 警告
|
||||
/// </summary>
|
||||
Warning,
|
||||
/// <summary>
|
||||
/// 错误
|
||||
/// </summary>
|
||||
Err,
|
||||
/// <summary>
|
||||
/// 数据库错误
|
||||
/// </summary>
|
||||
DbErr,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 日志
|
||||
/// </summary>
|
||||
public static class Logs
|
||||
{
|
||||
static object obj = new object();
|
||||
const string logExtension = ".log";
|
||||
/// <summary>
|
||||
/// 写入日志失败
|
||||
/// </summary>
|
||||
public static Action<IEnumerable<string>, DateTime, LogsType, Exception> WriteErr = null;
|
||||
|
||||
/// <summary>
|
||||
/// 写入日志
|
||||
/// </summary>
|
||||
/// <param name="content">内容</param>
|
||||
/// <param name="type">类型</param>
|
||||
/// <returns>是否写入成功</returns>
|
||||
public static void Write(IEnumerable<string> content, LogsType type = LogsType.Info)
|
||||
{
|
||||
if (content == null || !content.Any())
|
||||
return;
|
||||
|
||||
var dt = DateTime.Now;
|
||||
string hms = dt.ToString("HH:mm:ss.fff");
|
||||
List<string> lines = new List<string>(content.Count());
|
||||
|
||||
try
|
||||
{
|
||||
string path = Path.Combine(Config.LocalFile.LogDir, type.ToString(), $"{(dt.ToString("yyyyMMdd"))}{logExtension}");
|
||||
foreach (var item in content)
|
||||
lines.AddRange($"[{hms}]{item}".Split(new string[] { Environment.NewLine }, StringSplitOptions.None));
|
||||
|
||||
lock (obj)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
File.AppendAllLines(path, lines, Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteErr?.Invoke(content, dt, type, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入日志
|
||||
/// </summary>
|
||||
/// <param name="content">内容对象</param>
|
||||
/// <param name="type">类型</param>
|
||||
/// <returns>是否写入成功</returns>
|
||||
public static void Write(string content, LogsType type = LogsType.Info)
|
||||
{
|
||||
Write(new string[] { content }, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入日志
|
||||
/// </summary>
|
||||
/// <param name="content">内容对象</param>
|
||||
/// <param name="type">类型</param>
|
||||
/// <returns>是否写入成功</returns>
|
||||
public static void Write(object content, LogsType type = LogsType.Info)
|
||||
{
|
||||
Write(JsonConvert.SerializeObject(content), type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入日志
|
||||
/// </summary>
|
||||
/// <param name="content">内容</param>
|
||||
/// <param name="contentTitle">内容标题</param>
|
||||
/// <param name="type">类型</param>
|
||||
/// <returns>是否写入成功</returns>
|
||||
public static void Write(object content, string contentTitle, LogsType type = LogsType.Info)
|
||||
{
|
||||
Write($"{contentTitle} {JsonConvert.SerializeObject(content)}", type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入日志
|
||||
/// </summary>
|
||||
/// <param name="ex">错误</param>
|
||||
/// <returns>是否写入成功</returns>
|
||||
public static void Write(Exception ex, LogsType type = LogsType.Err)
|
||||
{
|
||||
Write(ex.ToString(), type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除日志
|
||||
/// </summary>
|
||||
/// <param name="time">保留时间</param>
|
||||
/// <returns>清理的大小(字节)</returns>
|
||||
public static long Clear(TimeSpan time)
|
||||
{
|
||||
long size = 0;
|
||||
var rs = EnumHelps.GetEnumList(typeof(LogsType));
|
||||
foreach (var item in rs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = Path.Combine(Config.LocalFile.LogDir, item);
|
||||
DirectoryInfo directoryInfo = new DirectoryInfo(path);
|
||||
if (!directoryInfo.Exists)
|
||||
continue;
|
||||
|
||||
var files = directoryInfo.GetFiles($"**{logExtension}", SearchOption.TopDirectoryOnly);
|
||||
var fileDel = files.Where(o => o.CreationTime < (DateTime.Now - time));
|
||||
foreach (var item2 in fileDel)
|
||||
{
|
||||
size += item2.Length;
|
||||
item2.Delete();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
223
WCS.BLL/Tool/TCPClient.cs
Normal file
223
WCS.BLL/Tool/TCPClient.cs
Normal file
@ -0,0 +1,223 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Text;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
|
||||
namespace WCS.BLL
|
||||
{
|
||||
/// <summary>
|
||||
/// 对TouchSocket的封装 主要完成TCP的连接 状态更新 发送接收通信
|
||||
/// </summary>
|
||||
public class TCPClient
|
||||
{
|
||||
public string RemoteIPHost { get; set; } = "127.0.0.1:20002";
|
||||
|
||||
public string BindIPHost { get; set; } = "127.0.0.1:20003";
|
||||
|
||||
public bool IsOnline { get; set; } = false;
|
||||
|
||||
//can模块协议前缀
|
||||
public readonly byte[] Prefix = new byte[] { 0x08, 0x00, 0x00 };
|
||||
//can模块协议前缀长度
|
||||
public readonly int PreFixLength = 3;
|
||||
//协议数据部分长度
|
||||
public readonly int DataLength = 10;
|
||||
|
||||
public ConcurrentDictionary<int, MessageDto> MessageList { get; set; } = new ConcurrentDictionary<int, MessageDto>();
|
||||
|
||||
public TcpClient tcpClient { get; set; }
|
||||
|
||||
public object receivdLockObject = new object();
|
||||
public object sendLockObject = new object();
|
||||
|
||||
public bool Connect()
|
||||
{
|
||||
try
|
||||
{
|
||||
tcpClient.Connect();//调用连接,当连接不成功时,会抛出异常。
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//连接失败
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化配置连接
|
||||
/// </summary>
|
||||
/// <param name="remoteIPHost"></param>
|
||||
public TCPClient(string remoteIPHost, string bindIPHost)
|
||||
{
|
||||
try
|
||||
{
|
||||
RemoteIPHost = remoteIPHost;
|
||||
BindIPHost = bindIPHost;
|
||||
|
||||
tcpClient = new TcpClient();
|
||||
//载入配置
|
||||
tcpClient.Setup(new TouchSocketConfig()
|
||||
.SetRemoteIPHost(RemoteIPHost)
|
||||
.SetBindIPHost(BindIPHost)
|
||||
.ConfigurePlugins(a =>
|
||||
{
|
||||
//配置断线重连
|
||||
a.UseReconnection(-1, true, 1000);
|
||||
})
|
||||
.ConfigureContainer(a =>
|
||||
{
|
||||
//添加控制台日志注入
|
||||
a.AddConsoleLogger();
|
||||
}));
|
||||
|
||||
//添加接收事件 匹配已发送的指令
|
||||
tcpClient.Received += (client, e) =>
|
||||
{
|
||||
var data = e.ByteBlock.Buffer.Take((int)e.ByteBlock.Length).ToArray();
|
||||
e.ByteBlock.Clear();
|
||||
var len = data.Length;
|
||||
for (int index = 0; index < data.Length - PreFixLength; index++)
|
||||
{
|
||||
//协议拆包 通过前缀校验是否为完整数据包
|
||||
var prefixInData = data.Skip(index).Take(PreFixLength);
|
||||
var isEqual = prefixInData.SequenceEqual(Prefix);
|
||||
if (isEqual)
|
||||
{
|
||||
var dataTemp = data.Skip(index).Take(PreFixLength + DataLength).ToArray();
|
||||
if (dataTemp.Length < PreFixLength + DataLength)//拆包后不满足一条指令的长度
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//获取返回指令的板子ID
|
||||
var boardId = (data[PreFixLength + 0] << 8) + data[PreFixLength + 1];
|
||||
//查询当前板子是否有待验证的指令
|
||||
var message = new MessageDto();
|
||||
MessageList.TryGetValue(boardId, out message);
|
||||
//功能位校验 功能位相同视为已响应指令 删除对应的指令
|
||||
if (message?.Message[PreFixLength + 2] == dataTemp[PreFixLength + 2])
|
||||
{
|
||||
MessageList.TryRemove(boardId, out message);
|
||||
}
|
||||
index += (PreFixLength + DataLength - 1);//每次循环index会+1 所以这里-1
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
tcpClient.Connected += (client, e) =>
|
||||
{
|
||||
this.IsOnline = true;
|
||||
return EasyTask.CompletedTask;
|
||||
};
|
||||
|
||||
tcpClient.Disconnected += (client, e) =>
|
||||
{
|
||||
this.IsOnline = false;
|
||||
return EasyTask.CompletedTask;
|
||||
};
|
||||
|
||||
//配置数据重发机制
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
//TO DO如果指令未回应n次 则取消重发
|
||||
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
|
||||
await Task.Delay(3000);
|
||||
if (MessageList.Count > 0)
|
||||
{
|
||||
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
|
||||
foreach (var item in MessageList)
|
||||
{
|
||||
if (item.Value.LastSendTime < DateTime.Now.AddSeconds(3))
|
||||
{
|
||||
tcpClient.Send(item.Value.Message);
|
||||
item.Value.SendTimes++;
|
||||
item.Value.LastSendTime = DateTime.Now;
|
||||
await Task.Delay(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void Send(byte[] message)
|
||||
{
|
||||
var boardId = (message[3] << 8) + message[4];
|
||||
//记录发送指令 用于通信校验 同Id只校验最后一个指令
|
||||
////MessageList.AddOrUpdate(boardId, new MessageDto()
|
||||
////{
|
||||
//// ID = boardId,
|
||||
//// Message = message,
|
||||
////}, (key, oldValue) => oldValue = new MessageDto()
|
||||
////{
|
||||
//// ID = boardId,
|
||||
//// Message = message,
|
||||
////});
|
||||
lock (sendLockObject)
|
||||
{
|
||||
tcpClient.Send(message);
|
||||
//发送自带10ms间隔
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
//生成协议明细
|
||||
public byte[] GenerateMessage(int boardId, byte[] data)
|
||||
{
|
||||
var message = new byte[Prefix.Length + 2 + data.Length];
|
||||
var boardIdData = BitConverter.GetBytes(unchecked((short)boardId));
|
||||
// 检查是否需要交换字节
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
// 如果是小端序系统,则交换字节
|
||||
byte temp = boardIdData[0];
|
||||
boardIdData[0] = boardIdData[1];
|
||||
boardIdData[1] = temp;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(Prefix, 0, message, 0, Prefix.Length);
|
||||
Buffer.BlockCopy(boardIdData, 0, message, Prefix.Length, boardIdData.Length);
|
||||
Buffer.BlockCopy(data, 0, message, Prefix.Length + boardIdData.Length, data.Length);
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//发送指令的记录
|
||||
public class MessageDto
|
||||
{
|
||||
public int ID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最后一次发送时间
|
||||
/// </summary>
|
||||
public DateTime LastSendTime { get; set; } = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// 发送内容
|
||||
/// </summary>
|
||||
public byte[] Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送次数
|
||||
/// </summary>
|
||||
public int SendTimes { get; set; } = 0;//第几次发送
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user