初始化

This commit is contained in:
cli 2024-12-19 16:07:07 +08:00
parent 66814a4fae
commit c416579507
313 changed files with 7701 additions and 4608 deletions

2
.editorconfig Normal file
View File

@ -0,0 +1,2 @@
[*.csproj]
indent_size = 2

45
.gitignore vendored
View File

@ -1,7 +1,7 @@
## Ignore Visual Studio temporary files, build results, and ## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons. ## files generated by popular Visual Studio add-ons.
## ##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files # User-specific files
*.rsuser *.rsuser
@ -29,7 +29,6 @@ x86/
bld/ bld/
[Bb]in/ [Bb]in/
[Oo]bj/ [Oo]bj/
[Oo]ut/
[Ll]og/ [Ll]og/
[Ll]ogs/ [Ll]ogs/
@ -91,6 +90,7 @@ StyleCopReport.xml
*.tmp_proj *.tmp_proj
*_wpftmp.csproj *_wpftmp.csproj
*.log *.log
*.tlog
*.vspscc *.vspscc
*.vssscc *.vssscc
.builds .builds
@ -294,6 +294,17 @@ node_modules/
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw *.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output # Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts **/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts
@ -350,6 +361,9 @@ ASALocalRun/
# Local History for Visual Studio # Local History for Visual Studio
.localhistory/ .localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database # BeatPulse healthcheck temp database
healthchecksdb healthchecksdb
@ -361,4 +375,29 @@ MigrationBackup/
# Fody - auto-generated XML schema # Fody - auto-generated XML schema
FodyWeavers.xsd FodyWeavers.xsd
/JiShe.CollectBus.Console/Plugins/*.dll
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
**/.idea/
*.sln.iml
# ABP Studio
**/.abpstudio/
/src/JiShe.CollectBus.Host/Plugins/*.dll

View File

@ -1,9 +0,0 @@
namespace JiShe.CollectBus.Application.Contracts
{
public interface ICommandService
{
Task<bool> AmmeterParameterSendAsync();
bool AmmeterParameterReading();
bool ActivePowerIndicationReading();
}
}

View File

@ -1,9 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -1,116 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JiShe.CollectBus.Application.Contracts;
using JiShe.CollectBus.Common.Enums;
using JiShe.CollectBus.Common.Extensions;
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.MQ.Sender;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
namespace JiShe.CollectBus.Application
{
public class CommandService: ICommandService,ISingletonDependency
{
private readonly ILogger<CommandService> _logger;
private readonly INSender _nSender;
public async Task<bool> AmmeterParameterSendAsync()
{
var listMeter = new List<AmmeterParameter>()
{
new AmmeterParameter()
{
Pn = 1,
BaudRate = 3,
Port = 2,
ProtocolType = CommunicationProtocolType.DLT6452007,
Address = "312408006642",
Password = "000000",
RateNumber = 4,
IntegerBitNumber = 4,
DecimalBitNumber = 4,
CollectorAddress = "000000000000",
UserCategoryNumber = 0,
UserSubclassNumber = 0
}
};
var bytes = HexStringExtensions.BuildAmmeterParameterSetSendCmd(new ReqParameter2()
{
AFN = AFN.,
FunCode = (int)CMasterStationFunCode.1,
A = "322009872",
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = 10,
},
MSA = 13,
Pn = 0,
Fn = 10
}, listMeter);
await _nSender.SendToIssuedAsync(new MessageIssuedEvent { DeviceNo = "322009872", Message = bytes, Type = IssuedEventType.Data, MessageId = Guid.NewGuid().ToString() });
return true;
}
public bool AmmeterParameterReading()
{
HexStringExtensions.BuildAmmeterParameterReadingSendCmd(new ReqParameter2()
{
AFN = AFN.,
FunCode = (int)CMasterStationFunCode.2,
A = "322009872",
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = 2,
},
MSA = 13,
Pn = 0,
Fn = 10
}, new List<int>() { 1, 2 });
return true;
}
public bool ActivePowerIndicationReading()
{
//var str = "68A600A6006888203290261A0A6200000201010001000100621E426622082431000000000000040300000000000000CA16";
//var cmdResult = new BuildCommand().AnalysisCmd(str);
//if(cmdResult != null)
//{
// var list = new BuildCommand().AnalysisAFN04F10DataUnit(cmdResult.HexDatas);
//}
HexStringExtensions.BuildSendCommandBytes(new ReqParameter2()
{
AFN = AFN.,
FunCode = (int)CMasterStationFunCode.2,
A = "322009872",
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = 2,
},
MSA = 13,
Pn = 1,
Fn = 129
});
//HexStringExtensions.AmmeterValveControl("312408006642", "", "000000", true);
return true;
}
}
}

View File

@ -1,36 +0,0 @@
using Hangfire;
using Microsoft.Extensions.Configuration;
using System.Reflection;
using JiShe.CollectBus.Common.Jobs;
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
/// <summary>
/// 添加TcpService服务。
/// </summary>
public static IServiceCollection AddJobs(this IServiceCollection services, IConfiguration configuration)
{
var interfaceType = typeof(IBaseJob);
var assembly = Assembly.GetExecutingAssembly();
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.IsClass && type.GetInterfaces().Contains(interfaceType))
{
var instance = services.GetServiceProviderOrNull().GetService(type);
//var instance = services.GetObject<IBaseJob>();
//var instance = Activator.CreateInstance(type);
RecurringJob.AddOrUpdate(type.Name, () => type.GetMethod("Execute").Invoke(instance,null), Cron.Minutely);
}
}
return services;
}
}
}

View File

@ -1,19 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Hangfire.Core" Version="1.8.15" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JiShe.CollectBus.Application.Contracts\JiShe.CollectBus.Application.Contracts.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.RabbitMQ\JiShe.CollectBus.MQ.Sender.csproj" />
</ItemGroup>
</Project>

View File

@ -1,46 +0,0 @@
using System.Collections.Generic;
using System.Reflection;
using Hangfire;
using JiShe.CollectBus.Common.Jobs;
using JiShe.CollectBus.MQ.Sender;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.Modularity;
namespace JiShe.CollectBus.Application
{
[DependsOn(typeof(JiSheCollectBusMqSenderModule))]
public class JiSheCollectBusApplicationModule: AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton<ISendEndpointProvider>();
//var configuration = context.Services.GetConfiguration();
//context.Services.AddJobs(configuration);
}
public override void OnPostApplicationInitialization(ApplicationInitializationContext context)
{
var interfaceType = typeof(IBaseJob);
var assembly = Assembly.GetExecutingAssembly();
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.IsClass && type.GetInterfaces().Contains(interfaceType))
{
var instance = context.ServiceProvider.GetService(type);
//var instance = services.GetObject<IBaseJob>();
//var instance = Activator.CreateInstance(type);
RecurringJob.AddOrUpdate(type.Name, () => type.GetMethod("Execute").Invoke(instance, null), Cron.Minutely);
}
}
}
}
}

View File

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JiShe.CollectBus.Common.Jobs;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
namespace JiShe.CollectBus.Application.Jobs
{
public class TestJob : IBaseJob,ISingletonDependency
{
private readonly ILogger<TestJob> _logger;
private readonly IConfiguration _configuration;
public TestJob(ILogger<TestJob> logger, IConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
}
public async Task Execute()
{
//to do something
await Task.CompletedTask;
}
}
}

View File

@ -1,173 +0,0 @@
namespace JiShe.CollectBus.Common.Enums
{
/// <summary>
/// 规约标识 高位在前 D1+D0
/// </summary>
public enum ProtocolIdentification
{
= 00,
= 01,
使 = 10,
= 11
}
/// <summary>
/// 传输方向位
/// </summary>
public enum DIR
{
= 0,
= 1
}
/// <summary>
/// 启动标识位
/// </summary>
public enum PRM
{
= 0,
= 1,
}
/// <summary>
/// 帧计数有效位
/// </summary>
public enum FCV
{
FCB位无效 = 0,
FCB位有效 = 1
}
/// <summary>
/// 控制域PRM=1启动站功能码
/// </summary>
public enum CMasterStationFunCode
{
= 1,
= 4,
= 9,
1 = 10,
2 = 11
}
/// <summary>
/// 控制域PRM=0从动站功能码
/// </summary>
public enum CFromStationFunCode
{
= 0,
= 8,
= 9,
= 11
}
/// <summary>
/// 应用层功能码
/// </summary>
public enum AFN
{
= 00,
= 01,
= 02,
= 03,
= 04,
= 05,
= 06,
= 07,
= 08,
= 09,
= 10,
= 11,
= 12,
= 13,
= 14,
= 15,
= 16,
}
/// <summary>
/// 帧时间标签有效位
/// </summary>
public enum TpV
{
= 0,
= 1
}
/// <summary>
/// 首帧末帧标志
/// </summary>
public enum FIRFIN
{
= 00,
= 01,
= 10,
= 11
}
/// <summary>
/// 请求确认标志位
/// </summary>
public enum CON
{
= 0,
= 1
}
/// <summary>
/// 通信协议类型 数值0-255
/// </summary>
public enum CommunicationProtocolType
{
DLT6451997 = 1,
= 2,
DLT6452007 = 30,
= 31
}
public enum BaudRate
{
Br300 = 0,
Br600 = 1,
Br1200 = 2,
Br2400 = 3,
Br4800 = 4,
Br7200 = 5,
Br9600 = 6,
Br19200 = 7
}
public enum StopBit
{
Stop1 = 0,
Stop2
}
public enum Parity
{
None = 0,
/// <summary>
/// 偶校验
/// </summary>
Even,
/// <summary>
/// 奇校验
/// </summary>
Odd
}
/// <summary>
/// 数据位
/// </summary>
public enum DataBit
{
D5 = 0,
D6,
D7,
D8
}
public enum IssuedEventType
{
Heartbeat,
Login,
Data
}
}

View File

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace JiShe.CollectBus.Common.Enums
{
public enum CommandChunkEnum188
{
A = 2,
C=9,
L=10,
DI=11,
Data=14
}
}

View File

@ -1,757 +0,0 @@
using JiShe.CollectBus.Common.Enums;
using JiShe.CollectBus.Common.Models;
namespace JiShe.CollectBus.Common.Extensions
{
public static class HexStringExtensions
{
//起始字符
private const string startStr = "68";
//结束字符
private const string endStr = "16";
//头部字节长度
private const int hearderLen = 6;
//消息认证码字段长度
private const int pWLen = 16;
private const int tPLen = 6;
private const int FixedLength = 18;
public static object GetAnalyzeValue(this List<string> hexStringList, CommandChunkEnum chunk)
{
if (hexStringList.Count < hearderLen || hexStringList[0] != startStr || hexStringList[5] != startStr || hexStringList.Count < FixedLength)
{
return null;
}
switch (chunk)
{
case CommandChunkEnum.AFN:
var aFn = hexStringList[(int)CommandChunkEnum.AFN].HexToDec();//1字节
return aFn;
case CommandChunkEnum.FN:
//(DT2*8)+DT1=fn
var dt1Bin = hexStringList[(int)CommandChunkEnum.FN - 1].HexToBin();
var dt1 = dt1Bin != "0" ? dt1Bin.Length : 0;
var dt2 = hexStringList[(int)CommandChunkEnum.FN].HexToDec();
var fn = dt2 * 8 + dt1;
return fn;
case CommandChunkEnum.A:
var aHexList = hexStringList.Skip((int)CommandChunkEnum.A).Take(5).ToList();
var a1 = aHexList[1] + aHexList[0];
var a2 = aHexList[3] + aHexList[2];
var a2Dec = a2.HexToDec();
var a3 = aHexList[4];
var a = $"{a1}{a2Dec.ToString().PadLeft(5, '0')}";
var a3Bin = aHexList[4].HexToBin().PadLeft(8, '0');
var msa = a3Bin.Substring(0, 7).BinToDec();
return new Tuple<string,int>(a, msa);
case CommandChunkEnum.SEQ:
var seq = hexStringList[(int)CommandChunkEnum.SEQ].HexToBin().PadLeft(8, '0');
var tpV = (TpV)Convert.ToInt32(seq.Substring(0, 1));
var firfin = (FIRFIN)Convert.ToInt32(seq.Substring(1, 2));
var con = (CON)Convert.ToInt32(seq.Substring(3, 1));
var prseqBin = seq.Substring(4, 4);
return new Seq
{
CON = con,
FIRFIN = firfin,
PRSEQ = prseqBin.BinToDec(),
TpV = tpV
};
case CommandChunkEnum.Data:
var lenIndex = (int)CommandChunkEnum.Len;
var lenBin = (hexStringList[lenIndex + 1]+hexStringList[lenIndex]).HexToBin();
var len = lenBin.Remove(lenBin.Length - 2).BinToDec();
//验证长度 2=(帧校验和+结束字符)
if (hexStringList.Count - 2 != hearderLen + len)
return null;
var dataHexList = hexStringList.Skip(FixedLength).Take(len + hearderLen - FixedLength).ToList();
return dataHexList;
default:
throw new ArgumentOutOfRangeException(nameof(chunk), chunk, null);
}
}
public static bool IsStartStr(this string str)
{
return str == startStr ? true : false;
}
/// <summary>
/// 字节加33
/// </summary>
/// <param name="hexStringList"></param>
/// <returns></returns>
public static List<string> AddHex33(this List<string> hexStringList)
{
for (int i = 0; i < hexStringList.Count; i++)
{
hexStringList[i] = (Convert.ToInt32(hexStringList[i], 16) + Convert.ToInt32("33", 16)).ToString("X2");
if (hexStringList[i].Length > 2)
{
hexStringList[i] = hexStringList[i].Substring(hexStringList[i].Length - 2);
}
}
return hexStringList;
}
#region 376.1
/// <summary>
/// 构建电表参数设置-下发命令
/// </summary>
/// <param name="reqParameter"></param>
/// <param name="meterParameters"></param>
/// <returns></returns>
public static byte[] BuildAmmeterParameterSetSendCmd(ReqParameter reqParameter, List<AmmeterParameter> meterParameters)
{
var dataUnit = BuildAmmeterParameterSendDataUnit(meterParameters);
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
return bytes;
}
/// <summary>
/// 构建电表参数读取-下发命令
/// </summary>
/// <param name="reqParameter"></param>
/// <param name="meterNumberList">对象序号</param>
public static void BuildAmmeterParameterReadingSendCmd(ReqParameter reqParameter, List<int> meterNumberList)
{
var dataUnit = new List<string>();
var countHex = meterNumberList.Count().DecToHex().PadLeft(4, '0');
var countHexPairs = countHex.StringToPairs();
countHexPairs.Reverse();
dataUnit.AddRange(countHexPairs);
foreach (var number in meterNumberList)
{
var numberHex = number.DecToHex().PadLeft(4, '0');
var numberHexPairs = numberHex.StringToPairs();
numberHexPairs.Reverse();
dataUnit.AddRange(numberHexPairs);
}
var bytes = BuildSendCommandBytes(reqParameter, dataUnit);
}
/// <summary>
/// 构建透明转发-下发数据单元
/// </summary>
/// <param name="port">终端通信端口 1~31</param>
/// <param name="baudRate">0~7 对应300,600,1200,2400,4800,7200,9600,19200</param>
/// <param name="stopBit">停止位</param>
/// <param name="parity">校验方式</param>
/// <param name="dataBit">数据位</param>
/// <param name="waitContentTimeout">等待报文超时时间/s</param>
/// <param name="waitByteTimeout">等待字节超时时间/ms</param>
/// <param name="datas">转发内容</param>
/// <returns></returns>
public static List<string> BuildTransparentForwardingSendDataUnit(int port, BaudRate baudRate, StopBit stopBit, Parity parity, DataBit dataBit,
int waitContentTimeout, int waitByteTimeout, List<string> datas)
{
var dataUnit = new List<string>();
var portHex = port.DecToHex().PadLeft(2, '0');
dataUnit.Add(portHex);
var baudRateBin = ((int)baudRate).DecToBin().PadLeft(3, '0');
var stopBitBin = ((int)stopBit).DecToBin();
var parityBin = parity != Parity.None ? $"1{((int)parity).DecToBin()}" : $"0{((int)parity).DecToBin()}";
var dataBitBin = ((int)dataBit).DecToBin().PadLeft(2, '0');
var controlHex = $"{baudRateBin}{stopBitBin}{parityBin}{dataBitBin}".BinToHex().PadLeft(2, '0'); ;
dataUnit.Add(controlHex);
var waitContentTimeoutBin = $"1{waitContentTimeout.DecToBin().PadLeft(7, '0')}";
var waitContentTimeoutHex = waitContentTimeoutBin.BinToHex().PadLeft(2, '0');
var waitByteTimeoutHex = waitByteTimeout.DecToHex().PadLeft(2, '0');
dataUnit.Add(waitContentTimeoutHex);
dataUnit.Add(waitByteTimeoutHex);
var countHex = datas.Count.DecToHex().PadLeft(4, '0');
var countHexPairs = countHex.StringToPairs();
countHexPairs.Reverse();
dataUnit.AddRange(countHexPairs);
dataUnit.AddRange(datas);
return dataUnit;
}
/// <summary>
/// 构建下发命令
/// </summary>
/// <param name="reqParameter"></param>
/// <param name="dataUnit"></param>
/// <returns></returns>
public static byte[] BuildSendCommandBytes(ReqParameter reqParameter, List<string>? dataUnit = null)
{
var cmdStrList = new List<string>();
var userDatas = BuildUserData(reqParameter, dataUnit);
var hearders = BuildHeaders(userDatas.Count);
var cs = GetCS(userDatas);
cmdStrList.AddRange(hearders);
cmdStrList.AddRange(userDatas);
cmdStrList.Add(cs);
cmdStrList.Add(endStr);
var bytes = cmdStrList.Select(x => Convert.ToByte(x, 16)).ToArray();
return bytes;
}
/// <summary>
/// 构建电表参数设置-下发数据单元
/// </summary>
/// <param name="meterParameters"></param>
/// <returns></returns>
private static List<string> BuildAmmeterParameterSendDataUnit(List<AmmeterParameter> meterParameters)
{
var hexDatas = new List<string>();
var countHex = meterParameters.Count().DecToHex().PadLeft(4, '0');
hexDatas.Add(countHex);
//TODO 优化代码:目标数据入参,返回类型为出参
for (int i = 0; i <= meterParameters.Count - 1; i++)
{
var meter = meterParameters[i];
var indexHex = (i + 1).DecToHex().PadLeft(4, '0');
hexDatas.Add(indexHex);
var pnHex = meter.Pn.DecToHex().PadLeft(4, '0');
hexDatas.Add(pnHex);
var baudRateBin = meter.BaudRate.DecToBin().PadLeft(3, '0');
var portBin = meter.Port.DecToBin().PadLeft(5, '0');
var baudRateAndPortHex = $"{baudRateBin}{portBin}".BinToHex().PadLeft(2, '0');
hexDatas.Add(baudRateAndPortHex);
var protocolTypeHex = ((int)meter.ProtocolType).DecToHex().PadLeft(2, '0');
hexDatas.Add(protocolTypeHex);
hexDatas.Add(meter.Address);
hexDatas.Add(meter.Password.PadLeft(12, '0'));
var rateNumberBin = $"0000{meter.RateNumber.DecToBin().PadLeft(4, '0')}";
var rateNumberHex = rateNumberBin.BinToHex().PadLeft(2, '0');
hexDatas.Add(rateNumberHex);
var intBitNumberBin = (meter.IntegerBitNumber - 4).DecToBin().PadLeft(2, '0');
var decBitNumberBin = (meter.DecimalBitNumber - 1).DecToBin().PadLeft(2, '0');
var intAndDecBitNumberBin = $"0000{intBitNumberBin}{decBitNumberBin}";
var intAndDecBitNumberHex = intAndDecBitNumberBin.BinToHex().PadLeft(2, '0');
hexDatas.Add(intAndDecBitNumberHex);
hexDatas.Add(meter.CollectorAddress.PadLeft(12, '0'));
var userCategoryNumberBin = meter.UserCategoryNumber.DecToBin().PadLeft(4, '0');
var userSubclassNumberBin = meter.UserSubclassNumber.DecToBin().PadLeft(4, '0');
var userNumberHex = $"{userCategoryNumberBin}{userSubclassNumberBin}".BinToHex().PadLeft(2, '0');
hexDatas.Add(userNumberHex);
}
//高位在前,低位在后
var datas = new List<string>();
foreach (var hexData in hexDatas)
{
if (hexData.Length == 2)
datas.Add(hexData);
else
{
var lst = hexData.StringToPairs();
lst.Reverse();
datas.AddRange(lst);
}
}
datas.AddRange(GetPW());
return datas;
}
//AUX=消息认证码字段PW,16个字节
private static List<string> GetPW()
{
var str = "00";
var pWList = Enumerable.Repeat(str, pWLen).ToList();
return pWList;
}
/// <summary>
/// 帧校验和
/// </summary>
/// <param name="userData">用户数据区</param>
/// <returns></returns>
private static string GetCS(List<string> userData)
{
byte sum = 0;
foreach (var d in userData)
{
var b = Convert.ToByte(d, 16);
sum += b;
}
return sum.ToString("X2");
}
/// <summary>
/// 用户数据区
/// </summary>
/// <param name="reqParameter"></param>
/// <returns></returns>
private static List<string> BuildUserData(ReqParameter reqParameter, List<string>? dataUnit)
{
var c = BuildC(reqParameter.FunCode, reqParameter.PRM);
var a = BuildAList(reqParameter.A, reqParameter.MSA);
var linkUserData = BuildLinkUserData(reqParameter.AFN, reqParameter.Seq,
((ReqParameter2)reqParameter).Pn, ((ReqParameter2)reqParameter).Fn, dataUnit);
var list = new List<string>() { c };
list.AddRange(a);
list.AddRange(linkUserData);
return list;
}
/// <summary>
/// 固定长度的报文头 起始字符+长度+长度+起始字符
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
private static List<string> BuildHeaders(int length)
{
var headers = new List<string>();
headers.Add(startStr);
var l = BuildLength(length);
headers.AddRange(l);
headers.AddRange(l);
headers.Add(startStr);
return headers;
}
/// <summary>
/// 长度 2字节 [用户数据区长度]
/// </summary>
/// <returns></returns>
private static List<string> BuildLength(int length1)
{
var binaryLen = length1.DecToBin();
var protocolIdentification = Enum.Format(typeof(ProtocolIdentification),
ProtocolIdentification.使, "d").PadLeft(2, '0');
var lenStr = $"{binaryLen}{protocolIdentification}";
var hexLen = lenStr.BinToHex();
hexLen = hexLen.PadLeft(4, '0');
var list = hexLen.StringToPairs();
list.Reverse();
return list;
}
/// <summary>
/// 控制域
/// </summary>
/// <param name="funCode">功能码</param>
/// <param name="fcb"></param>
/// <param name="fcv"></param>
/// <returns></returns>
private static string BuildC(int funCode, PRM pRM, int fcb = 0, FCV fcv = FCV.FCB位无效)
{
var cMasterStationFunCodeHex = funCode.DecToBin();
cMasterStationFunCodeHex = cMasterStationFunCodeHex.ToString().PadLeft(4, '0');
var strC = $"{(int)DIR.主站下行报文}{(int)pRM}{fcb}{(int)fcv}{cMasterStationFunCodeHex}";
var hexC = strC.BinToHex().PadLeft(2, '0');
return hexC;
}
/// <summary>
/// 地址域 3220 09872
/// </summary>
/// <param name="a1">行政区划码 BCD码 3220=2032</param>
/// <param name="a2">逻辑地址 BIN 09872=2690=>9026</param>
/// <param name="a3">主站地址 BIN 0~127</param>
/// <returns></returns>
private static List<string> BuildAList(string a, int mSA)
{
var list = new List<string>();
var a1 = a.Substring(0, 4);
var a1Pairs = a1.StringToPairs();
a1Pairs.Reverse();
list.AddRange(a1Pairs);
var a2 = Convert.ToInt32(a.Substring(4));
var decA2 = a2.DecToHex();
var a2Pairs = decA2.PadLeft(4, '0').StringToPairs();
a2Pairs.Reverse();
list.AddRange(a2Pairs);
//TODO:主站地址和组地址标志
var a3Bin = $"{mSA.DecToBin().PadLeft(7, '0')}0";
list.Add(a3Bin.BinToHex().PadLeft(2, '0'));
return list;
}
private static List<string> BuildLinkUserData(AFN aFN, Seq seq, int pn, int fn, List<string>? dataUnit)
{
var aFNValue = ((int)aFN).DecToHex().PadLeft(2, '0');
var sEQ = BuildSEQ(seq.TpV, seq.FIRFIN, seq.CON, seq.PRSEQ);
var dA = BuildDA(pn);
var dT = BuildDT(fn);
var list = new List<string>() { aFNValue, sEQ };
list.AddRange(dA);
list.AddRange(dT);
if (dataUnit != null)
{
list.AddRange(dataUnit);
}
//list.AddRange(GetDataUnit(aFN,seq));
if (seq.TpV == TpV.)
list.AddRange(BuildTp("00"));
return list;
}
/// <summary>
/// 帧序列域
/// </summary>
/// <param name="tpV"></param>
/// <param name="fIRFIN"></param>
/// <param name="cON"></param>
/// <returns></returns>
private static string BuildSEQ(TpV tpV, FIRFIN fIRFIN, CON cON, int pRSEQ)
{
var tpVValue = Enum.Format(typeof(TpV),
tpV, "d");
var fIRFINValue = Enum.Format(typeof(FIRFIN),
fIRFIN, "d");
var cONValue = (int)cON;
var sEQBin = $"{tpVValue}{fIRFINValue}{cONValue}{pRSEQ.DecToBin().PadLeft(4, '0')}";
var hexSEQ = sEQBin.BinToHex().PadLeft(2, '0');
return hexSEQ;
}
/// <summary>
/// 信息点标识
/// </summary>
/// <param name="pn">计量点</param>
/// <returns></returns>
private static List<string> BuildDA(int pn)
{
if (pn == 0)
return new List<string>() { "00", "00" };
var dA2 = (pn - 1) / 8 + 1;//信息点组从1开始 第几组
var dA1 = pn - (dA2 - 1) * 8;//pn % 8
var dA1Hex = "1".PadRight(dA1, '0').BinToHex();//对位信息 第几位 二进制有效位
var dA2Hex = dA2.DecToHex();
return new List<string>() { dA1Hex.PadLeft(2, '0'), dA2Hex.PadLeft(2, '0') };
}
/// <summary>
/// 数据单元标识
/// </summary>
/// <param name="fn"></param>
/// <returns></returns>
private static List<string> BuildDT(int fn)
{
var dT2 = (fn - 1) / 8;//从零开始 第几组
var dT1 = fn - dT2 * 8;
var dT1Hex = "1".PadRight(dT1, '0').BinToHex();//对位信息 第几位 二进制有效位
var dT2Hex = dT2.DecToHex();
return new List<string>() { dT1Hex.PadLeft(2, '0'), dT2Hex.PadLeft(2, '0') };
}
/// <summary>
/// 时间标签
/// </summary>
/// <param name="pFC">启动帧帧序号计数器PFC 1字节</param>
/// <param name="delayTime">允许发送传输延时时间 min 1字节</param>
/// <returns></returns>
private static List<string> BuildTp(string pFC = "00", int delayTime = 0)
{
var now = DateTime.Now; // 获取当前时间
var seconds = now.Second.ToString().PadLeft(2, '0'); // 获取当前秒数
var minutes = now.Minute.ToString().PadLeft(2, '0'); // 获取当前分钟数
var hours = now.Hour.ToString().PadLeft(2, '0'); // 获取当前小时数
var day = now.Day.ToString().PadLeft(2, '0'); // 获取当前日期的日数
return new List<string>() { pFC, seconds, minutes, hours, day, delayTime.ToString().PadLeft(2, '0') };
}
#endregion
#region 645
/// <summary>
/// 构建电表阀控下发数据单元
/// </summary>
/// <param name="address">电表地址</param>
/// <param name="specialControlCode">特殊控制码</param>
/// <param name="password">密码</param>
/// <param name="state">是否为开阀</param>
/// <param name="modelCode">型号码</param>
/// <returns></returns>
public static List<string> BuildAmmeterValveControlSendDataUnit(string address, string specialControlCode, string password, bool state, string modelCode = "")
{
var code = string.Empty;
if (state)
{
if (string.IsNullOrEmpty(specialControlCode))
code = "1B";
else
code = specialControlCode == "1B" || specialControlCode == "1C" ? specialControlCode : "1C";
}
else
code = "1A";//跳闸
if (specialControlCode == "1W")
{
if (state)
code = "1A";
else
code = "1C";
}
var pwdLevel = "02";
if (modelCode == "HL_DTSU2625" || modelCode == "DDZY9866")
pwdLevel = "04";
else if (modelCode == "DDS2705")
pwdLevel = "03"; //不带安全认证密级
if (!string.IsNullOrWhiteSpace(password) && password.Contains("|"))
{
var sp = password.Split('|');
pwdLevel = sp[1];
password = sp[0];
}
var strDate = DateTime.Now.AddYears(3).ToString("000012ddMMyy").StrAddSpan();//命令有效截止时间
if (specialControlCode == "1D" || modelCode == "SZBD_DDZY1225")
strDate = "FF FF FF FF FF FF";
var strP = password.StrAddSpan().StrReverseOrder();
var strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + code + " 00 " + strDate;
var dataUnit = strSJY.Replace(" ", "").StringToPairs();
var dataList = Build645SendCommand(address, "1C", dataUnit);
return dataList;
//string strLen = (strSJY.Replace(" ", "").Length / 2).ToString("X2");
//string strReturn = "68 " + address.StrAddSpan().StrReverseOrder() + " 68 1C " + strLen + " " + strSJY.StrAddHex33() + " ";
//string strSum = strReturn.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X");
//strReturn += strSum.Substring(strSum.Length - 2) + " 16";
//return strReturn.Split(' ').ToList();
}
/// <summary>
/// 构建电表保电下发数据单元
/// </summary>
/// <param name="address">电表地址</param>
/// <param name="password"></param>
/// <param name="state">true 保电 false 保电解除</param>
/// <param name="modelCode">型号码</param>
/// <returns></returns>
public static List<string> BuildAmmeterLockSendDataUnit(string address, string password, bool state, string modelCode = "")
{
var code = state ? "3A" : "3B";
var strDate = (code + DateTime.Now.AddDays(1).ToString("00000012ddMMyy")).StrAddSpan();
if (modelCode == "SZBD_DDZY1225")
strDate = $"{code} 00 FF FF FF FF FF FF";
var strP = password.StrAddSpan().StrReverseOrder();
var strSJY = " 02 " + strP + " 01 00 00 00 " + strDate;
var dataUnit = strSJY.Replace(" ", "").StringToPairs();
var dataList = Build645SendCommand(address, "1C", dataUnit);
return dataList;
}
/// <summary>
/// 构建645协议下发命令
/// </summary>
/// <param name="ammeterAddress">电表地址</param>
/// <param name="controlCode">控制码</param>
/// <param name="dataUnit">数据域 发送方按字节进行加33处理接收方按字节减33</param>
/// <returns></returns>
public static List<string> Build645SendCommand(string ammeterAddress, string controlCode, List<string>? dataUnit)
{
var cmdStrList = new List<string>();
cmdStrList.Add(startStr);
ammeterAddress = ammeterAddress.PadLeft(12, '0');
var addressList = ammeterAddress.StringToPairs();
addressList.Reverse();
cmdStrList.AddRange(addressList);
cmdStrList.Add(startStr);
var len = dataUnit != null ? dataUnit.Count.DecToHex().PadLeft(2, '0') : "00";
cmdStrList.Add(len);
if (dataUnit != null)
{
cmdStrList.AddRange(dataUnit.AddHex33());
}
var strSum = cmdStrList.Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X");
strSum = strSum.Substring(strSum.Length - 2);
cmdStrList.Add(strSum);
cmdStrList.Add(endStr);
return cmdStrList;
}
/// <summary>
/// 构建写数据 TODO:待优化
/// </summary>
/// <returns></returns>
public static List<string> AssembleWrite(string address, string password, string Di0_3, string[] data)
{
var address_str = address.StrAddSpan().StrReverseOrder();
var L = (12 + data.Length).ToString("X2");
var m = "00 11 22 33";
var Di0_3_str = Di0_3.StrAddSpan().StrReverseOrder();
var pwd_str = password.StrAddSpan().StrReverseOrder();
var data_str = string.Join(" ", data);
var data_add33 = (Di0_3_str + " 02 " + pwd_str + " " + m + " " + data_str).StrAddHex33();
var frame = $"68 {address_str} 68 14 {L} {data_add33}";
string strSum = frame.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X");
var cs = strSum.Substring(strSum.Length - 2);
return $"{frame} {cs} 16".Split(' ').ToList();
}
#endregion
#region 188
/// <summary>
/// 标准 188协议阀控 WaterMeterSend
/// </summary>
/// <param name="waterMeterAddress"></param>
/// <param name="mtype">表计类型</param>
/// <returns></returns>
public static List<string> BuildConfirm188WaterValve(string waterMeterAddress, bool state, string mtype = "10")
{
if (string.IsNullOrWhiteSpace(waterMeterAddress)) return null;
var dataUnit = new List<string>() { "A0", "17", "00", state ? "55" : "99" };
var dataList = Build188SendCommand(waterMeterAddress, "04", dataUnit);
return dataList;
}
/// <summary>
/// 构建188水表抄读下发数据单元
/// </summary>
/// <param name="waterMeterAddress"></param>
/// <returns></returns>
public static List<string> Build188WaterMeterReadingSendDataUnit(string waterMeterAddress)
{
//TODO:90 1F 还是1F 90
var dataUnit = new List<string>() { "90", "1F", "00" };
var dataList = Build188SendCommand(waterMeterAddress, "01", dataUnit);
return dataList;
}
/// <summary>
/// 构建188协议下发命令
/// </summary>
/// <param name="waterMeterAddress">水表地址</param>
/// <param name="controlCode">控制码</param>
/// <param name="dataUnit">数据域</param>
/// <param name="meterType">表类型</param>
/// <returns></returns>
public static List<string> Build188SendCommand(string waterMeterAddress, string controlCode, List<string>? dataUnit = null, string meterType = "10")
{
var cmdStrList = new List<string>();
cmdStrList.Add(startStr);
cmdStrList.Add(meterType);
waterMeterAddress = waterMeterAddress.PadLeft(14, '0');
var addressList = waterMeterAddress.StringToPairs();
addressList.Reverse();
cmdStrList.AddRange(addressList);
//控制码
cmdStrList.Add(controlCode);
var len = dataUnit != null ? dataUnit.Count.DecToHex().PadLeft(2, '0') : "00";
cmdStrList.Add(len);
if (dataUnit != null)
{
cmdStrList.AddRange(dataUnit);
}
var strSum = cmdStrList.Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X");
strSum = strSum.Substring(strSum.Length - 2);
cmdStrList.Add(strSum);
cmdStrList.Add(endStr);
return cmdStrList;
}
public static string GetCRC(List<string> inputFrm, int startIndex = 0)
{
int sum = 0;
for (int i = startIndex; i < inputFrm.Count; i++)
{
sum += (Convert.ToInt32(inputFrm[i], 16));
}
var sum16 = Convert.ToString(sum, 16);
return sum16.Substring(sum16.Length - 2, 2).ToUpper();
}
public static object GetAnalyzeValue(this List<string> hexStringList, CommandChunkEnum188 chunk)
{
if (hexStringList.Count < 11)
{
return null;
}
switch (chunk)
{
case CommandChunkEnum188.A:
var aHexList = hexStringList[(int)CommandChunkEnum188.A].Take(7).ToList();
aHexList.Reverse();
return string.Join("", aHexList.Skip(1).Take(6).ToList());
case CommandChunkEnum188.C:
var cHex = hexStringList[(int)CommandChunkEnum188.C];
return cHex;
case CommandChunkEnum188.Data:
var lenIndex = (int)CommandChunkEnum188.L;
var len = hexStringList[lenIndex].HexToDec();
//验证长度 2=(帧校验和+结束字符)
if (hexStringList.Count - 2 != 11 + len)
return null;
var dataHexList = hexStringList.Skip(11).Take(len).ToList();
return dataHexList;
default:
throw new ArgumentOutOfRangeException(nameof(chunk), chunk, null);
}
}
//public double AnalyzeCurrentTotalRate(List<string> hexList)
//{
// var str = string.Join("", hexList);
// var number = Convert.ToInt32(str) * 0.01;
// return number;
//}
#endregion
}
}

View File

@ -1,92 +0,0 @@
//using JiShe.CollectBus.Common.Extensions.DependencyInjections;
//using JiShe.CollectBus.Protocol.Contracts.Attributes;
//using System.Reflection;
//using TouchSocket.Core;
//using System;
//using Serilog;
//// ReSharper disable once CheckNamespace
//namespace Microsoft.Extensions.DependencyInjection
//{
// public static class DependencyInjectionExtensions
// {
// public static void PluginServiceRegister(this IServiceCollection services, string pluginPath = "")
// {
// if (pluginPath.IsNullOrWhiteSpace())
// {
// pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
// }
// var assemblies = GetAssembliesFromFolder(pluginPath);
// foreach (var assembly in assemblies)
// {
// var allTypes = assembly.GetTypes();
// foreach (var type in allTypes)
// {
// if (typeof(ISingletonDependency).IsAssignableFrom(type) && type is { IsClass: true, IsAbstract: false })
// {
// var interfaceTypes = type.GetInterfaces().Where(p => p.FullName != null && !p.FullName.Contains("ISingletonDependency"));
// foreach (var interfaceType in interfaceTypes)
// {
// var attr = type.GetCustomAttribute<ProtocolNameAttribute>();
// if (attr == null) continue;
// Log.Logger.Information($"正在加载插件{attr.Name}...");
// var serviceDescriptor = new ServiceDescriptor(interfaceType, attr.Name, type, ServiceLifetime.Singleton);
// services.Add(serviceDescriptor);
// }
// }
// if (typeof(ITransientDependency).IsAssignableFrom(type) && type is { IsClass: true, IsAbstract: false })
// {
// var interfaceTypes = type.GetInterfaces().Where(p => p.FullName != null && !p.FullName.Contains("ITransientDependency"));
// foreach (var interfaceType in interfaceTypes)
// {
// var attr = type.GetCustomAttribute<ProtocolNameAttribute>();
// if (attr == null) continue;
// Log.Logger.Information($"正在加载插件{attr.Name}...");
// var serviceDescriptor = new ServiceDescriptor(interfaceType, attr.Name, type, ServiceLifetime.Transient);
// services.Add(serviceDescriptor);
// }
// }
// if (typeof(IScopedDependency).IsAssignableFrom(type) && type is { IsClass: true, IsAbstract: false })
// {
// var interfaceTypes = type.GetInterfaces().Where(p => p.FullName != null && !p.FullName.Contains("IScopedDependency"));
// foreach (var interfaceType in interfaceTypes)
// {
// var attr = type.GetCustomAttribute<ProtocolNameAttribute>();
// if (attr == null) continue;
// Log.Logger.Information($"正在加载插件{attr.Name}...");
// var serviceDescriptor = new ServiceDescriptor(interfaceType, attr.Name, type, ServiceLifetime.Scoped);
// services.Add(serviceDescriptor);
// }
// }
// }
// }
// }
// private static IEnumerable<Assembly> GetAssembliesFromFolder(string folderPath)
// {
// var directory = new DirectoryInfo(folderPath);
// if (!directory.Exists) return [];
// var files = directory.GetFiles("*.dll");
// var assemblies = new List<Assembly>();
// foreach (var file in files)
// {
// try
// {
// var assembly = Assembly.LoadFrom(file.FullName);
// assemblies.Add(assembly);
// }
// catch (Exception ex)
// {
// Console.WriteLine($"Error loading assembly from {file.FullName}: {ex.Message}");
// }
// }
// return assemblies;
// }
// }
//}

View File

@ -1,60 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization>
<JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>
<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
<PackageReference Include="Serilog" Version="4.1.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.4" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JiShe.CollectBus.Application\JiShe.CollectBus.Application.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.Core\JiShe.CollectBus.Network.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.EntityFrameworkCore\JiShe.CollectBus.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.Protocol.Contracts\JiShe.CollectBus.Protocol.Contracts.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.RabbitMQ\JiShe.CollectBus.MQ.Sender.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.Service\JiShe.CollectBus.MQ.Consumer.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Plugins\JiShe.CollectBus.Protocol.Demo.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Plugins\JiShe.CollectBus.Protocol.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -1,72 +0,0 @@
using JiShe.CollectBus.MQ.Consumer;
using JiShe.CollectBus.Network;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Volo.Abp;
namespace JiShe.CollectBus.Console
{
internal class Program
{
static void Main(string[] args)
{
try
{
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Application terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(ConfigureAppConfiguration)
.ConfigureServices((hostContext, services) => { ConfigureServices(services, hostContext); });
private static void ConfigureAppConfiguration(HostBuilderContext hostContext, IConfigurationBuilder config)
{
var env = hostContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
config.AddEnvironmentVariables();
}
private static void ConfigureServices(IServiceCollection services, HostBuilderContext hostContext)
{
var configuration = hostContext.Configuration;
services.AddSerilog((context, lc) =>
{
lc.ReadFrom.Configuration(configuration)
.ReadFrom.Services(context);
});
services.AddApplication<JiSheCollectBusMqConsumerModule>();
services.AddApplication<JiSheCollectBusNetworkModule>();
services.AddPluginApplications();
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = configuration["RedisCache:ConnectionString"];
options.InstanceName = configuration["RedisCache:InstanceName"];
});
}
}
}

View File

@ -1,57 +0,0 @@
{
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
"MinimumLevel": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": {
"path": "Logs/log-.txt",
"rollingInterval": "Day"
//"rollOnFileSizeLimit": true,
//"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
"Properties": {
"Application": "CollectBus",
"Environment": "Development"
}
},
"ConnectionStrings": {
"Default": "Data Source=192.168.111.248;Port=3306;Database=JiSheCollectBus;uid=root;pwd=123456abcD;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true"
},
"MongoSettings": {
"Connection": "mongodb://backups_admin:jishe_mongodb_backups@118.190.144.92:27037",
"DatabaseName": "JiSheCollectBus"
},
"TCP": {
"Port": 10500
},
"UDP": {
"Port": 10500
},
"RedisCache": {
"ConnectionString": "123456@qwer@localhost:6379",
"InstanceName": "CollectBus"
},
"MQ": {
"Host": "118.190.144.92",
"Port": "5672",
"VirtualHost": "/",
"UserName": "collectbus",
"Password": "123456",
"Queue": {
"Received": "Received_Command",
"Issued": "Issued_Command"
}
}
}

View File

@ -1,27 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Extensions\**" />
<EmbeddedResource Remove="Extensions\**" />
<None Remove="Extensions\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="2.1.9" />
<PackageReference Include="TouchSocket.Hosting" Version="2.1.9" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JiShe.CollectBus.MongoDB\JiShe.CollectBus.MongoDB.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.RabbitMQ\JiShe.CollectBus.MQ.Sender.csproj" />
</ItemGroup>
</Project>

View File

@ -1,50 +0,0 @@
using JiShe.CollectBus.MongoDB;
using JiShe.CollectBus.MQ.Sender;
using JiShe.CollectBus.Network.Plugins;
using Microsoft.Extensions.DependencyInjection;
using TouchSocket.Core;
using TouchSocket.Sockets;
using Volo.Abp;
using Volo.Abp.Modularity;
using ServerMonitor = JiShe.CollectBus.Network.Plugins.ServerMonitor;
namespace JiShe.CollectBus.Network
{
[DependsOn(typeof(JiSheCollectBusMongoDbModule),
typeof(JiSheCollectBusMqSenderModule))]
public class JiSheCollectBusNetworkModule : AbpModule
{
public override async void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
context.Services.AddTcpService(config =>
{
config.SetListenIPHosts(int.Parse(configuration["TCP:ClientPort"] ?? "10500"))
//.SetTcpDataHandlingAdapter(()=>new StandardFixedHeaderDataHandlingAdapter())
.ConfigurePlugins(a =>
{
a.Add<TcpCloseMonitor>();
a.Add<TcpMonitor>();
a.Add<ServerMonitor>();
});
});
context.Services.AddUdpSession(config =>
{
config.SetBindIPHost(int.Parse(configuration["UDP:ClientPort"] ?? "10500"))
.ConfigurePlugins(a =>
{
a.Add<UdpMonitor>();
a.Add<ServerMonitor>();
})
.UseBroadcast()
.SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter());
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
}
}
}

View File

@ -1,109 +0,0 @@
using JiShe.CollectBus.Common.Enums;
using JiShe.CollectBus.Common.Extensions;
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.MongoDB;
using JiShe.CollectBus.MQ.Sender;
using MassTransit;
using Microsoft.Extensions.Logging;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace JiShe.CollectBus.Network.Plugins
{
public partial class TcpMonitor(
INSender nSender,
ILogger<TcpMonitor> logger,
IMongoRepository<MessageReceivedHeartbeatEvent> mongoHeartbeatRepository,
IMongoRepository<MessageReceivedLoginEvent> mongoLoginRepository)
: PluginBase
{
[GeneratorPlugin(typeof(ITcpReceivedPlugin))]
public async Task OnTcpReceived(ITcpSessionClient client, ReceivedDataEventArgs e)
{
var messageHexString = Convert.ToHexString(e.ByteBlock.Span);
var hexStringList = messageHexString.StringToPairs();
var aFn = (int?)hexStringList.GetAnalyzeValue(CommandChunkEnum.AFN);
var fn = (int?)hexStringList.GetAnalyzeValue(CommandChunkEnum.FN);
var aTuple = (Tuple<string, int>)hexStringList.GetAnalyzeValue(CommandChunkEnum.A);
if (aFn.HasValue && fn.HasValue)
{
if ((AFN)aFn == AFN.)
{
switch (fn)
{
case 1://登录
var messageReceivedLoginEvent = new MessageReceivedLoginEvent
{
ClientId = client.Id,
ClientIp = client.IP,
ClientPort = client.Port,
MessageHexString = messageHexString,
DeviceNo = aTuple.Item1,
MessageId = NewId.NextGuid().ToString()
};
await mongoLoginRepository.AddAsync(messageReceivedLoginEvent);
await nSender.SendToReceivedLoginAsync(messageReceivedLoginEvent);
break;
case 3://心跳
var messageReceivedHeartbeatEvent = new MessageReceivedHeartbeatEvent
{
ClientId = client.Id,
ClientIp = client.IP,
ClientPort = client.Port,
MessageHexString = messageHexString,
DeviceNo = aTuple.Item1,
MessageId = NewId.NextGuid().ToString()
};
await mongoHeartbeatRepository.AddAsync(messageReceivedHeartbeatEvent);
await nSender.SendToReceivedHeartbeatAsync(messageReceivedHeartbeatEvent);
break;
default:
logger.LogError($"指令初步解析失败,指令内容:{messageHexString}");
break;
}
}
else
{
await nSender.SendToReceivedAsync(new MessageReceivedEvent
{
ClientId = client.Id,
ClientIp = client.IP,
ClientPort = client.Port,
MessageHexString = messageHexString,
DeviceNo = aTuple.Item1,
MessageId = NewId.NextGuid().ToString()
});
}
}
else
{
logger.LogError($"指令初步解析失败,指令内容:{messageHexString}");
}
await e.InvokeNext();
}
[GeneratorPlugin(typeof(ITcpConnectingPlugin))]
public async Task OnTcpConnecting(ITcpSessionClient client,ConnectingEventArgs e)
{
logger.LogInformation($"[TCP] ID:{client.Id} IP:{client.GetIPPort()}正在连接中...");
await e.InvokeNext();
}
[GeneratorPlugin(typeof(ITcpConnectedPlugin))]
public async Task OnTcpConnected(ITcpSessionClient client,ConnectedEventArgs e)
{
logger.LogInformation($"[TCP] ID:{client.Id} IP:{client.GetIPPort()}已连接");
await e.InvokeNext();
}
[GeneratorPlugin(typeof(ITcpClosedPlugin))]
public async Task OnTcpClosed(ITcpSessionClient client, ClosedEventArgs e)
{
logger.LogInformation($"[TCP] ID:{client.Id} IP:{client.GetIPPort()}已关闭连接");
await e.InvokeNext();
}
}
}

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JiShe.CollectBus.EntityFrameworkCore.Entities;
namespace JiShe.CollectBus.EntityFrameworkCore.AuditLogs
{
public class AuditLog : EntityBase<Guid>,ICreationAudited<long?>
{
public long? CreatorId { get; set; }
public DateTime CreationTime { get; set; }
}
}

View File

@ -1,29 +0,0 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
namespace JiShe.CollectBus.EntityFrameworkCore
{
public class CollectBusDbContext : DbContext
{
private readonly IConfiguration _configuration;
private DbSet<Device> Devices { set; get; }
public CollectBusDbContext(IConfiguration configuration)
{
_configuration = configuration;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseMySql(_configuration.GetConnectionString("Default"),ServerVersion.AutoDetect(_configuration.GetConnectionString("Default")));
}
}
}

View File

@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JiShe.CollectBus.EntityFrameworkCore.Entities;
namespace JiShe.CollectBus.EntityFrameworkCore
{
public class Device : EntityBase<Guid>, ICreationAudited<long?>, IModificationAudited<long?>
{
public string DeviceNo { get; set; }
public DeviceStatusEnum DeviceStatus { get; set; }
public long? CreatorId { get; set; }
public DateTime CreationTime { get; set; }
public long? LastModifierId { get; set; }
public DateTime? LastModificationTime { get; set; }
}
public enum DeviceStatusEnum
{
Unknown = 0,
Online = 1,
Offline = 2,
}
}

View File

@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.EntityFrameworkCore.Entities
{
public class EntityBase<TKey> : IEntity<TKey>
{
public TKey Id { get; set; }
}
}

View File

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.EntityFrameworkCore.Entities
{
public class FullAuditedEntity<TKey, TUser> : EntityBase<TKey>, ICreationAudited<TUser>, IModificationAudited<TUser>, IDeletionAudited<TUser>
{
public TUser CreatorId { get; set; }
public DateTime CreationTime { get; set; }
public TUser LastModifierId { get; set; }
public DateTime? LastModificationTime { get; set; }
public TUser DeleterId { get; set; }
public bool IsDeleted { get; set; }
public DateTime? DeletionTime { get; set; }
}
}

View File

@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.EntityFrameworkCore.Entities
{
public interface ICreationAudited<TUser> : IHasCreator<TUser>, IHasCreationTime
{
}
public interface IHasCreator<TUser>
{
TUser CreatorId { get; set; }
}
public interface IHasCreationTime
{
DateTime CreationTime { get; set; }
}
}

View File

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.EntityFrameworkCore.Entities
{
public interface IDeletionAudited<TUser> : IHasDeleter<TUser>, ISoftDelete, IHasDeletionTime
{
}
public interface ISoftDelete
{
bool IsDeleted { get; set; }
}
public interface IHasDeleter<TUser>
{
TUser DeleterId { get; set; }
}
public interface IHasDeletionTime
{
DateTime? DeletionTime { get; set; }
}
}

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.EntityFrameworkCore.Entities
{
public interface IExtendableObject
{
/// <summary>
/// Gets or sets the extension data.
/// </summary>
/// <value>
/// The extension data.
/// </value>
string ExtensionData { get; set; }
}
}

View File

@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.EntityFrameworkCore.Entities
{
public interface IModificationAudited<TUser> : IHasLastModifier<TUser>, IHasLastModificationTime
{
}
public interface IHasLastModifier<TUser>
{
TUser LastModifierId { get; set; }
}
public interface IHasLastModificationTime
{
DateTime? LastModificationTime { get; set; }
}
}

View File

@ -1,153 +0,0 @@
using JiShe.CollectBus.EntityFrameworkCore.Entities;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using JetBrains.Annotations;
using JiShe.CollectBus.Common.Helpers;
using Newtonsoft.Json.Linq;
using Formatting = Newtonsoft.Json.Formatting;
namespace JiShe.CollectBus.EntityFrameworkCore.Extensions
{
public static class ExtendableObjectExtensions
{
public static T GetData<T>(this IExtendableObject extendableObject, string name, bool handleType = false)
{
return extendableObject.GetData<T>(
name,
handleType
? new JsonSerializer { TypeNameHandling = TypeNameHandling.All }
: JsonSerializer.CreateDefault()
);
}
public static T GetData<T>(this IExtendableObject extendableObject, string name, JsonSerializer? jsonSerializer)
{
if (extendableObject.ExtensionData == null)
{
return default(T);
}
var json = JObject.Parse(extendableObject.ExtensionData);
var prop = json[name];
if (prop == null)
{
return default(T);
}
if (TypeHelper.IsPrimitiveExtendedIncludingNullable(typeof(T)))
{
return prop.Value<T>();
}
else
{
return (T)prop.ToObject(typeof(T), jsonSerializer ?? JsonSerializer.CreateDefault());
}
}
public static void SetData<T>(this IExtendableObject extendableObject, string name, T? value, bool handleType = false)
{
extendableObject.SetData(
name,
value,
handleType
? new JsonSerializer { TypeNameHandling = TypeNameHandling.All }
: JsonSerializer.CreateDefault()
);
}
public static void SetData<T>(this IExtendableObject extendableObject, string name, T? value, JsonSerializer? jsonSerializer)
{
if (extendableObject == null)
{
throw new ArgumentNullException(nameof(extendableObject));
}
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
if (jsonSerializer == null)
{
jsonSerializer = JsonSerializer.CreateDefault();
}
if (extendableObject.ExtensionData == null)
{
if (EqualityComparer<T>.Default.Equals(value, default(T)))
{
return;
}
extendableObject.ExtensionData = "{}";
}
var json = JObject.Parse(extendableObject.ExtensionData);
if (value == null || EqualityComparer<T>.Default.Equals(value, default(T)))
{
if (json[name] != null)
{
json.Remove(name);
}
}
else if (TypeHelper.IsPrimitiveExtendedIncludingNullable(value.GetType()))
{
json[name] = new JValue(value);
}
else
{
json[name] = JToken.FromObject(value, jsonSerializer);
}
var data = json.ToString(Formatting.None);
if (data == "{}")
{
data = null;
}
extendableObject.ExtensionData = data;
}
public static bool RemoveData(this IExtendableObject extendableObject, string name)
{
if (extendableObject == null)
{
throw new ArgumentNullException(nameof(extendableObject));
}
if (extendableObject.ExtensionData == null)
{
return false;
}
var json = JObject.Parse(extendableObject.ExtensionData);
var token = json[name];
if (token == null)
{
return false;
}
json.Remove(name);
var data = json.ToString(Formatting.None);
if (data == "{}")
{
data = null;
}
extendableObject.ExtensionData = data;
return true;
}
}
}

View File

@ -1,25 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
</ItemGroup>
</Project>

View File

@ -1,11 +0,0 @@
using Volo.Abp.Modularity;
namespace JiShe.CollectBus.EntityFrameworkCore
{
public class JiSheCollectBusEntityFrameworkCoreModule: AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
}
}

View File

@ -1,60 +0,0 @@
// <auto-generated />
using System;
using JiShe.CollectBus.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace JiShe.CollectBus.EntityFrameworkCore.Migrations
{
[DbContext(typeof(CollectBusDbContext))]
[Migration("20241022055227_Init")]
partial class Init
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
modelBuilder.Entity("JiShe.CollectBus.EntityFrameworkCore.Device", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime(6)");
b.Property<long?>("CreatorId")
.HasColumnType("bigint");
b.Property<string>("DeviceNo")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("DeviceStatus")
.HasColumnType("int");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime(6)");
b.Property<long?>("LastModifierId")
.HasColumnType("bigint");
b.HasKey("Id");
b.ToTable("Devices");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,44 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace JiShe.CollectBus.EntityFrameworkCore.Migrations
{
/// <inheritdoc />
public partial class Init : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "Devices",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
DeviceNo = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
DeviceStatus = table.Column<int>(type: "int", nullable: false),
CreatorId = table.Column<long>(type: "bigint", nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false),
LastModifierId = table.Column<long>(type: "bigint", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime(6)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Devices", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Devices");
}
}
}

View File

@ -1,57 +0,0 @@
// <auto-generated />
using System;
using JiShe.CollectBus.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace JiShe.CollectBus.EntityFrameworkCore.Migrations
{
[DbContext(typeof(CollectBusDbContext))]
partial class CollectBusDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
modelBuilder.Entity("JiShe.CollectBus.EntityFrameworkCore.Device", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime(6)");
b.Property<long?>("CreatorId")
.HasColumnType("bigint");
b.Property<string>("DeviceNo")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("DeviceStatus")
.HasColumnType("int");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime(6)");
b.Property<long?>("LastModifierId")
.HasColumnType("bigint");
b.HasKey("Id");
b.ToTable("Devices");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,62 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using JiShe.CollectBus.EntityFrameworkCore.Entities;
namespace JiShe.CollectBus.EntityFrameworkCore.Repositories
{
public interface IRepository<TEntity, TPrimaryKey> where TEntity : class, IEntity<TPrimaryKey>
{
IQueryable<TEntity> GetAll(params Expression<Func<TEntity, object>>[] propertySelectors);
IQueryable<TEntity> GetAll(Expression<Func<TEntity, bool>> expression,
params Expression<Func<TEntity, object>>[] propertySelectors);
TEntity Find(TPrimaryKey id);
Task<TEntity> FindAsync(TPrimaryKey id);
TEntity Get(Expression<Func<TEntity, bool>> expression,
params Expression<Func<TEntity, object>>[] propertySelectors);
Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> expression,
params Expression<Func<TEntity, object>>[] propertySelectors);
void Insert(TEntity entity, bool autoSave = true);
Task InsertAsync(TEntity entity, bool autoSave = true);
Task<TPrimaryKey> InsertAndGetIdAsync(TEntity entity, bool autoSave = true);
void InsertList(List<TEntity> entities, bool autoSave = true);
Task InsertListAsync(List<TEntity> entities, bool autoSave = true);
void Update(TEntity entity, bool autoSave = true);
Task UpdateAsync(TEntity entity, bool autoSave = true);
void UpdateList(IEnumerable<TEntity> entities);
Task UpdateListAsync(IEnumerable<TEntity> entities);
void Delete(TPrimaryKey id, bool autoSave = true);
Task DeleteAsync(TPrimaryKey id, bool autoSave = true);
void Delete(TEntity entity, bool autoSave = true);
Task DeleteAsync(TEntity entity, bool autoSave = true);
void HardDelete(TPrimaryKey id, bool autoSave = true);
Task HardDeleteAsync(TPrimaryKey id, bool autoSave = true);
void HardDelete(TEntity entity, bool autoSave = true);
Task HardDeleteAsync(TEntity entity, bool autoSave = true);
}
}

View File

@ -1,295 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using JiShe.CollectBus.Common.Extensions;
using JiShe.CollectBus.EntityFrameworkCore.Entities;
using Microsoft.EntityFrameworkCore;
namespace JiShe.CollectBus.EntityFrameworkCore.Repositories
{
public class Repository<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
{
public virtual CollectBusDbContext DbContext { private set; get; }
public virtual DbSet<TEntity> Table => DbContext.Set<TEntity>();
public Repository(CollectBusDbContext dbContext)
{
DbContext = dbContext;
}
public virtual IQueryable<TEntity> GetAll(params Expression<Func<TEntity, object>>[] propertySelectors)
{
var query = Table.AsNoTracking();
if (!propertySelectors.IsNullOrEmpty())
{
foreach (var propertySelector in propertySelectors)
{
query = query.Include(propertySelector);
}
}
return query;
}
public virtual IQueryable<TEntity> GetAll(Expression<Func<TEntity, bool>> expression, params Expression<Func<TEntity, object>>[] propertySelectors)
{
var query = Table.Where(expression);
if (!propertySelectors.IsNullOrEmpty())
{
foreach (var propertySelector in propertySelectors)
{
query = query.Include(propertySelector);
}
}
return query;
}
public virtual TEntity Find(TPrimaryKey id)
{
return Table.Find(id);
}
public virtual async Task<TEntity> FindAsync(TPrimaryKey id)
{
return await Table.FindAsync(id);
}
public virtual TEntity Get(Expression<Func<TEntity, bool>> expression, params Expression<Func<TEntity, object>>[] propertySelectors)
{
var query = GetAll();
if (!propertySelectors.IsNullOrEmpty())
{
foreach (var propertySelector in propertySelectors)
{
query = query.Include(propertySelector);
}
return query.FirstOrDefault(expression);
}
return Table.FirstOrDefault(expression);
}
public virtual async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> expression, params Expression<Func<TEntity, object>>[] propertySelectors)
{
var query = GetAll();
if (!propertySelectors.IsNullOrEmpty())
{
foreach (var propertySelector in propertySelectors)
{
query = query.Include(propertySelector);
}
return await query.FirstOrDefaultAsync(expression);
}
return await Table.FirstOrDefaultAsync(expression);
}
public virtual void Insert(TEntity entity, bool autoSave = true)
{
var hasCreationTime = typeof(IHasCreationTime).IsAssignableFrom(typeof(TEntity));
if (hasCreationTime)
{
((IHasCreationTime)entity).CreationTime = DateTime.Now;
}
((IHasCreationTime)entity).CreationTime = DateTime.Now;
Table.Add(entity);
if (autoSave)
{
DbContext.SaveChanges();
}
}
public virtual async Task InsertAsync(TEntity entity, bool autoSave = true)
{
var hasCreationTime = typeof(IHasCreationTime).IsAssignableFrom(typeof(TEntity));
if (hasCreationTime)
{
((IHasCreationTime)entity).CreationTime = DateTime.Now;
}
await Table.AddAsync(entity);
if (autoSave)
{
await DbContext.SaveChangesAsync();
}
}
public virtual async Task<TPrimaryKey> InsertAndGetIdAsync(TEntity entity, bool autoSave = true)
{
var hasCreationTime = typeof(IHasCreationTime).IsAssignableFrom(typeof(TEntity));
if (hasCreationTime)
{
((IHasCreationTime)entity).CreationTime = DateTime.Now;
}
await Table.AddAsync(entity);
if (autoSave)
{
await DbContext.SaveChangesAsync();
}
return entity.Id;
}
public virtual void InsertList(List<TEntity> entities, bool autoSave = true)
{
var hasCreationTime = typeof(IHasCreationTime).IsAssignableFrom(typeof(TEntity));
if (hasCreationTime)
{
foreach (var entity in entities)
{
((IHasCreationTime)entity).CreationTime = DateTime.Now;
}
}
Table.AddRange(entities);
if (autoSave)
{
DbContext.SaveChanges();
}
}
public virtual async Task InsertListAsync(List<TEntity> entities, bool autoSave = true)
{
var hasCreationTime = typeof(IHasCreationTime).IsAssignableFrom(typeof(TEntity));
if (hasCreationTime)
{
foreach (var entity in entities)
{
((IHasCreationTime)entity).CreationTime = DateTime.Now;
}
}
await Table.AddRangeAsync(entities);
if (autoSave)
{
await DbContext.SaveChangesAsync();
}
}
public virtual void Update(TEntity entity, bool autoSave = true)
{
var hasLastModificationTime = typeof(IHasLastModificationTime).IsAssignableFrom(typeof(TEntity));
if (hasLastModificationTime)
{
((IHasLastModificationTime)entity).LastModificationTime = DateTime.Now;
}
Table.Update(entity);
if (autoSave)
{
DbContext.SaveChanges();
}
}
public virtual async Task UpdateAsync(TEntity entity, bool autoSave = true)
{
var hasLastModificationTime = typeof(IHasLastModificationTime).IsAssignableFrom(typeof(TEntity));
if (hasLastModificationTime)
{
((IHasLastModificationTime)entity).LastModificationTime = DateTime.Now;
}
Table.Update(entity);
if (autoSave)
{
await DbContext.SaveChangesAsync();
}
}
public virtual void UpdateList(IEnumerable<TEntity> entities)
{
Table.UpdateRange(entities);
DbContext.SaveChanges();
}
public virtual async Task UpdateListAsync(IEnumerable<TEntity> entities)
{
Table.UpdateRange(entities);
await DbContext.SaveChangesAsync();
}
public virtual void Delete(TPrimaryKey id, bool autoSave = true)
{
var entity = Find(id);
if (entity == null)
{
throw new ArgumentNullException();
}
Delete(entity, autoSave);
}
public virtual async Task DeleteAsync(TPrimaryKey id, bool autoSave = true)
{
var entity = await FindAsync(id);
if (entity == null)
{
throw new ArgumentNullException();
}
await DeleteAsync(entity, autoSave);
}
public virtual void Delete(TEntity entity, bool autoSave = true)
{
var hasDeletionTime = typeof(IHasDeletionTime).IsAssignableFrom(typeof(TEntity));
if (hasDeletionTime)
{
((IHasDeletionTime)entity).DeletionTime = DateTime.Now;
}
var isDeleteEntity = typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity));
if (isDeleteEntity)
{
((ISoftDelete)entity).IsDeleted = true;
}
Update(entity, autoSave);
}
public virtual async Task DeleteAsync(TEntity entity, bool autoSave = true)
{
var hasDeletionTime = typeof(IHasDeletionTime).IsAssignableFrom(typeof(TEntity));
if (hasDeletionTime)
{
((IHasDeletionTime)entity).DeletionTime = DateTime.Now;
}
var isDeleteEntity = typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity));
if (isDeleteEntity)
{
((ISoftDelete)entity).IsDeleted = true;
}
await UpdateAsync(entity, autoSave);
}
public virtual void HardDelete(TPrimaryKey id, bool autoSave = true)
{
var entity = Find(id);
if (entity == null)
{
throw new ArgumentNullException();
}
HardDelete(entity, autoSave);
}
public async Task HardDeleteAsync(TPrimaryKey id, bool autoSave = true)
{
var entity = await FindAsync(id);
if (entity == null)
{
throw new ArgumentNullException();
}
await HardDeleteAsync(entity, autoSave);
}
public virtual void HardDelete(TEntity entity, bool autoSave = true)
{
Table.Remove(entity);
if (autoSave)
{
DbContext.SaveChanges();
}
}
public virtual async Task HardDeleteAsync(TEntity entity, bool autoSave = true)
{
Table.Remove(entity);
if (autoSave)
{
await DbContext.SaveChangesAsync();
}
}
}
}

View File

@ -1,36 +0,0 @@
using JiShe.CollectBus.Application.Contracts;
using Volo.Abp.AspNetCore.Mvc;
namespace JiShe.CollectBus.Host.Controllers
{
public class CommandController : AbpController
{
private readonly ILogger<CommandController> _logger;
private readonly ICommandService _commandService;
public CommandController(ILogger<CommandController> logger, ICommandService commandService)
{
_logger = logger;
_commandService = commandService;
}
public async Task<bool> AmmeterParameterSendAsync()
{
return await _commandService.AmmeterParameterSendAsync();
}
public bool AmmeterParameterReading()
{
return _commandService.AmmeterParameterReading();
}
public bool ActivePowerIndicationReading()
{
return _commandService.ActivePowerIndicationReading();
}
}
}

View File

@ -1,49 +0,0 @@
using System.Reflection;
using Volo.Abp.Modularity;
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
public static void AddPluginApplications(this IServiceCollection services, string pluginPath = "")
{
if (string.IsNullOrWhiteSpace(pluginPath))
{
pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
}
var assemblies = GetAssembliesFromFolder(pluginPath);
foreach (var assembly in assemblies)
{
var applicationServiceType = assembly.GetTypes()
.FirstOrDefault(a => a.IsClass && !a.IsAbstract && typeof(AbpModule).IsAssignableFrom(a));
services.AddApplication(applicationServiceType);
}
}
private static IEnumerable<Assembly> GetAssembliesFromFolder(string folderPath)
{
var directory = new DirectoryInfo(folderPath);
if (!directory.Exists) return [];
var files = directory.GetFiles("*.dll");
var assemblies = new List<Assembly>();
foreach (var file in files)
{
try
{
var assembly = Assembly.LoadFrom(file.FullName);
assemblies.Add(assembly);
}
catch (Exception ex)
{
Console.WriteLine($"Error loading assembly from {file.FullName}: {ex.Message}");
}
}
return assemblies;
}
}
}

View File

@ -1,35 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Abp" Version="9.4.2" />
<PackageReference Include="Hangfire" Version="1.8.15" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.15" />
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
<PackageReference Include="Hangfire.HttpJob" Version="3.8.5" />
<PackageReference Include="Hangfire.MySqlStorage" Version="2.0.3" />
<PackageReference Include="Serilog" Version="4.1.0" />
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.4" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Volo.Abp.AspNetCore" Version="8.3.3" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="8.3.3" />
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.10" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JiShe.CollectBus.Application.Contracts\JiShe.CollectBus.Application.Contracts.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.Application\JiShe.CollectBus.Application.csproj" />
</ItemGroup>
</Project>

View File

@ -1,26 +0,0 @@
using Abp.Dependency;
using DeviceDetectorNET.Parser.Device;
using Serilog;
using Volo.Abp.Modularity;
namespace JiShe.CollectBus.Host
{
public class JiSheCollectBusHostModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
var configuration = IocManager.Instance.Resolve<IConfiguration>();
//services.AddApplication<JiSheCollectBusMqConsumerModule>();
//services.AddApplication<JiSheCollectBusNetworkModule>();
services.AddPluginApplications();
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = configuration["RedisCache:ConnectionString"];
options.InstanceName = configuration["RedisCache:InstanceName"];
});
}
}
}

View File

@ -1,33 +0,0 @@
using JiShe.CollectBus.Common.Enums;
namespace JiShe.CollectBus.Host.Models
{
public class GeneralIssuedInput
{
/// <summary>
/// 测量点号 0~2040 为0被删除
/// </summary>
public int Pn { get; set; }
/// <summary>
/// 波特率600起 1~7
/// </summary>
public int BaudRate { get; set; }
/// <summary>
/// 端口号 1-31
/// </summary>
public int Port { get; set; }
public CommunicationProtocolType ProtocolType { get; set; }
/// <summary>
/// 通信地址 0~999999999999
/// </summary>
public string Address { get; set; }
/// <summary>
/// 通信密码
/// </summary>
public string Password { get; set; } = "000000";
}
}

View File

@ -1,42 +0,0 @@
using JiShe.CollectBus.Host;
using Serilog;
public class Program
{
public static void Main(string[] args)
{
try
{
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Application terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
}
private static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel((context, options) => { options.Limits.MaxRequestBodySize = 1024 * 50; });
webBuilder.UseStartup<Startup>();
})
.UseSerilog((context, loggerConfiguration) =>
{
loggerConfiguration.ReadFrom.Configuration(context.Configuration);
});
}

View File

@ -1,90 +0,0 @@
using Hangfire;
using Hangfire.Dashboard.BasicAuthorization;
using Hangfire.HttpJob;
using Hangfire.MySql;
using JiShe.CollectBus.Application;
namespace JiShe.CollectBus.Host
{
public class Startup(IConfiguration configuration)
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddApplication<JiSheCollectBusApplicationModule>();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
services.AddHangfire(config =>
{
config.SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings();
config.UseStorage(
new MySqlStorage(
configuration.GetConnectionString("Default"),
new MySqlStorageOptions
{
QueuePollInterval = TimeSpan.FromSeconds(15), //- 作业队列轮询间隔。默认值为15秒。
JobExpirationCheckInterval = TimeSpan.FromHours(1), //- 作业到期检查间隔管理过期记录。默认值为1小时。
CountersAggregateInterval = TimeSpan.FromMinutes(5), //- 聚合计数器的间隔。默认为5分钟。
PrepareSchemaIfNecessary = true, //- 如果设置为true则创建数据库表。默认是true。
DashboardJobListLimit = 50000, //- 仪表板作业列表限制。默认值为50000。
TransactionTimeout = TimeSpan.FromMinutes(1), //- 交易超时。默认为1分钟。
}));
config.UseHangfireHttpJob();
});
services.AddHangfireServer();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
var dashboardOptions = new DashboardOptions();
if (env.IsProduction())
dashboardOptions = new DashboardOptions
{
Authorization = new[]
{
new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions
{
SslRedirect = false,
RequireSsl = false,
LoginCaseSensitive = false,
Users =
[
new BasicAuthAuthorizationUser
{
Login = "admin",
PasswordClear = "lixiao1980"
}
]
})
}
};
app.UseHangfireDashboard("/hangfire", dashboardOptions);
//app.UseEndpoints(endpoints =>
//{
// endpoints.MapRazorPages();
//});
app.UseConfiguredEndpoints();
}
}
}

View File

@ -1,52 +0,0 @@
{
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
"MinimumLevel": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": {
"path": "Logs/log-.txt",
"rollingInterval": "Day"
//"rollOnFileSizeLimit": true,
//"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
"Properties": {
"Application": "CollectBus",
"Environment": "Development"
}
},
"ConnectionStrings": {
"Default": "Data Source=192.168.111.248;Port=3306;Database=JiSheCollectBus;uid=root;pwd=123456abcD;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true",
//"Default": "Data Source=localhost;Port=3306;Database=JiSheCollectBus;uid=root;pwd=123456abcD;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true"
},
"MongoSettings": {
"Connection": "mongodb://backups_admin:jishe_mongodb_backups@118.190.144.92:27037",
"DatabaseName": "JiSheCollectBus"
},
"RedisCache": {
"ConnectionString": "123456@qwer@localhost:6379",
"InstanceName": "CollectBus"
},
"MQ": {
"Host": "118.190.144.92",
"Port": "5672",
"VirtualHost": "/",
"UserName": "collectbus",
"Password": "123456",
"Queue": {
"Received": "Received_Command",
"Issued": "Issued_Command"
}
}
}

View File

@ -1,37 +0,0 @@
using MongoDB.Driver;
namespace JiShe.CollectBus.MongoDB
{
public interface IMongoContext : IDisposable
{
/// <summary>
/// 添加命令操作
/// </summary>
/// <param name="func">委托 方法接受一个 Func<IClientSessionHandle,Task> 委托作为参数,该委托表示一个需要 IClientSessionHandle 对象作为参数并返回一个异步任务的方法</param>
/// <returns></returns>
Task AddCommandAsync(Func<IClientSessionHandle, Task> func);
/// <summary>
/// 提交更改并返回受影响的行数
/// TODOMongoDB单机服务器不支持事务【使用MongoDB事务会报错Standalone servers do not support transactions】,只有在集群情况下才支持事务
/// 原因MongoDB在使用分布式事务时需要进行多节点之间的协调和通信而单机环境下无法实现这样的分布式协调和通信机制。但是在MongoDB部署为一个集群cluster将多个计算机连接为一个整体通过协调和通信机制实现了分布式事务的正常使用。从数据一致性和可靠性的角度来看在分布式系统中实现事务处理是至关重要的。而在单机环境下不支持事务只有在集群情况下才支持事务的设计方式是为了保证数据一致性和可靠性并且也符合分布式系统的设计思想。
/// </summary>
/// <param name="session">MongoDB 会话session对象</param>
/// <returns></returns>
Task<int> SaveChangesAsync(IClientSessionHandle session);
/// <summary>
/// 初始化Mongodb会话对象session
/// </summary>
/// <returns></returns>
Task<IClientSessionHandle> StartSessionAsync();
/// <summary>
/// 获取集合数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
IMongoCollection<T> GetCollection<T>(string name);
}
}

View File

@ -1,176 +0,0 @@
using MongoDB.Driver;
using System.Linq.Expressions;
namespace JiShe.CollectBus.MongoDB
{
public interface IMongoRepository<T> where T : class, new()
{
#region
/// <summary>
/// 事务添加数据
/// </summary>
/// <param name="session">MongoDB 会话session对象</param>
/// <param name="objData">添加数据</param>
/// <returns></returns>
Task AddTransactionsAsync(IClientSessionHandle session, T objData);
/// <summary>
/// 事务数据删除
/// </summary>
/// <param name="session">MongoDB 会话session对象</param>
/// <param name="id">objectId</param>
/// <returns></returns>
Task DeleteTransactionsAsync(IClientSessionHandle session, string id);
/// <summary>
/// 事务异步局部更新(仅更新一条记录)
/// </summary>
/// <param name="session">MongoDB 会话session对象</param>
/// <param name="filter">过滤器</param>
/// <param name="update">更新条件</param>
/// <returns></returns>
Task UpdateTransactionsAsync(IClientSessionHandle session, FilterDefinition<T> filter, UpdateDefinition<T> update);
#endregion
#region
/// <summary>
/// 添加数据
/// </summary>
/// <param name="objData">添加数据</param>
/// <returns></returns>
Task AddAsync(T objData);
/// <summary>
/// 批量插入
/// </summary>
/// <param name="objDatas">实体集合</param>
/// <returns></returns>
Task InsertManyAsync(List<T> objDatas);
#endregion
#region
/// <summary>
/// 数据删除
/// </summary>
/// <param name="id">objectId</param>
/// <returns></returns>
Task DeleteAsync(string id);
/// <summary>
/// 异步删除多条数据
/// </summary>
/// <param name="filter">删除的条件</param>
/// <returns></returns>
Task<DeleteResult> DeleteManyAsync(FilterDefinition<T> filter);
#endregion
#region
/// <summary>
/// 指定对象异步修改一条数据
/// </summary>
/// <param name="obj">要修改的对象</param>
/// <param name="id">修改条件</param>
/// <returns></returns>
Task UpdateAsync(T obj, string id);
/// <summary>
/// 局部更新(仅更新一条记录)
/// <para><![CDATA[expression 参数示例x => x.Id == 1 && x.Age > 18 && x.Gender == 0]]></para>
/// <para><![CDATA[entity 参数示例y => new T{ RealName = "Ray", Gender = 1}]]></para>
/// </summary>
/// <param name="expression">筛选条件</param>
/// <param name="entity">更新条件</param>
/// <returns></returns>
Task UpdateAsync(Expression<Func<T, bool>> expression, Expression<Action<T>> entity);
/// <summary>
/// 异步局部更新(仅更新一条记录)
/// </summary>
/// <param name="filter">过滤器</param>
/// <param name="update">更新条件</param>
/// <returns></returns>
Task UpdateAsync(FilterDefinition<T> filter, UpdateDefinition<T> update);
/// <summary>
/// 异步局部更新(仅更新多条记录)
/// </summary>
/// <param name="expression">筛选条件</param>
/// <param name="update">更新条件</param>
/// <returns></returns>
Task UpdateManyAsync(Expression<Func<T, bool>> expression, UpdateDefinition<T> update);
/// <summary>
/// 异步批量修改数据
/// </summary>
/// <param name="dic">要修改的字段</param>
/// <param name="filter">更新条件</param>
/// <returns></returns>
Task<UpdateResult> UpdateManayAsync(Dictionary<string, string> dic, FilterDefinition<T> filter);
#endregion
#region
/// <summary>
/// 通过ID主键获取数据
/// </summary>
/// <param name="id">objectId</param>
/// <returns></returns>
Task<T> GetByIdAsync(string id);
/// <summary>
/// 获取所有数据
/// </summary>
/// <returns></returns>
Task<IEnumerable<T>> GetAllAsync();
/// <summary>
/// 获取记录数
/// </summary>
/// <param name="expression">筛选条件</param>
/// <returns></returns>
Task<long> CountAsync(Expression<Func<T, bool>> expression);
/// <summary>
/// 获取记录数
/// </summary>
/// <param name="filter">过滤器</param>
/// <returns></returns>
Task<long> CountAsync(FilterDefinition<T> filter);
/// <summary>
/// 判断是否存在
/// </summary>
/// <param name="predicate">条件</param>
/// <returns></returns>
Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate);
/// <summary>
/// 异步查询集合
/// </summary>
/// <param name="filter">查询条件</param>
/// <param name="field">要查询的字段,不写时查询全部</param>
/// <param name="sort">要排序的字段</param>
/// <returns></returns>
Task<List<T>> FindListAsync(FilterDefinition<T> filter, string[]? field = null, SortDefinition<T>? sort = null);
/// <summary>
/// 异步分页查询集合
/// </summary>
/// <param name="filter">查询条件</param>
/// <param name="pageIndex">当前页</param>
/// <param name="pageSize">页容量</param>
/// <param name="field">要查询的字段,不写时查询全部</param>
/// <param name="sort">要排序的字段</param>
/// <returns></returns>
Task<List<T>> FindListByPageAsync(FilterDefinition<T> filter, int pageIndex, int pageSize, string[]? field = null, SortDefinition<T>? sort = null);
#endregion
}
}

View File

@ -1,25 +0,0 @@
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.MongoDB
{
public interface IUnitOfWork : IDisposable
{
/// <summary>
/// 提交保存更改
/// </summary>
/// <param name="session">MongoDB 会话session对象</param>
/// <returns></returns>
Task<bool> Commit(IClientSessionHandle session);
/// <summary>
/// 初始化MongoDB会话对象session
/// </summary>
/// <returns></returns>
Task<IClientSessionHandle> InitTransaction();
}
}

View File

@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="MongoDB.Driver" Version="3.0.0" />
<PackageReference Include="Volo.Abp.Timing" Version="8.3.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.EntityFrameworkCore\JiShe.CollectBus.EntityFrameworkCore.csproj" />
</ItemGroup>
</Project>

View File

@ -1,29 +0,0 @@
using JiShe.CollectBus.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
using Volo.Abp.Timing;
namespace JiShe.CollectBus.MongoDB
{
[DependsOn(typeof(AbpTimingModule),
typeof(JiSheCollectBusEntityFrameworkCoreModule))]
public class JiSheCollectBusMongoDbModule: AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton<IMongoContext, MongoContext>();
context.Services.AddSingleton<IUnitOfWork, UnitOfWork>();
context.Services.AddSingleton(typeof(IMongoRepository<>), typeof(MongoBaseRepository<>));
Configure<AbpClockOptions>(options =>
{
options.Kind = DateTimeKind.Local;
});
}
}
}

View File

@ -1,352 +0,0 @@
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using JiShe.CollectBus.Common.Interfaces;
using JiShe.CollectBus.EntityFrameworkCore;
using Volo.Abp.Timing;
namespace JiShe.CollectBus.MongoDB
{
public class MongoBaseRepository<T> : IMongoRepository<T> where T : class, new()
{
private readonly IMongoContext _context;
private readonly IMongoCollection<T> _dbSet;
private readonly IClock _clock;
public MongoBaseRepository(IMongoContext context, IClock clock)
{
_context = context;
_clock = clock;
var collectionName = typeof(T).GetCustomAttribute<TableAttribute>()?.Name ?? typeof(T).Name;
_dbSet = _context.GetCollection<T>(collectionName);
}
#region
/// <summary>
/// 事务添加数据
/// </summary>
/// <param name="session">MongoDB 会话session对象</param>
/// <param name="objData">添加数据</param>
/// <returns></returns>
public async Task AddTransactionsAsync(IClientSessionHandle session, T objData)
{
await _context.AddCommandAsync(async (session) => await _dbSet.InsertOneAsync(objData));
}
/// <summary>
/// 事务数据删除
/// </summary>
/// <param name="session">MongoDB 会话session对象</param>
/// <param name="id">objectId</param>
/// <returns></returns>
public async Task DeleteTransactionsAsync(IClientSessionHandle session, string id)
{
await _context.AddCommandAsync((session) => _dbSet.DeleteOneAsync(Builders<T>.Filter.Eq(" _id ", id)));
}
/// <summary>
/// 事务异步局部更新(仅更新一条记录)
/// </summary>
/// <param name="session">MongoDB 会话session对象</param>
/// <param name="filter">过滤器</param>
/// <param name="update">更新条件</param>
/// <returns></returns>
public async Task UpdateTransactionsAsync(IClientSessionHandle session, FilterDefinition<T> filter, UpdateDefinition<T> update)
{
await _context.AddCommandAsync((session) => _dbSet.UpdateOneAsync(filter, update));
}
#endregion
#region
/// <summary>
/// 添加数据
/// </summary>
/// <param name="objData">添加数据</param>
/// <returns></returns>
public async Task AddAsync(T objData)
{
if (typeof(IReceived).IsAssignableFrom(typeof(T)))
{
(objData as IReceived)!.ReceivedTime = $"{_clock.Now:yyyy-MM-dd HH:mm:ss}";
}
await _dbSet.InsertOneAsync(objData);
}
/// <summary>
/// 批量插入
/// </summary>
/// <param name="objDatas">实体集合</param>
/// <returns></returns>
public async Task InsertManyAsync(List<T> objDatas)
{
await _dbSet.InsertManyAsync(objDatas);
}
#endregion
#region
/// <summary>
/// 数据删除
/// </summary>
/// <param name="id">objectId</param>
/// <returns></returns>
public async Task DeleteAsync(string id)
{
await _dbSet.DeleteOneAsync(Builders<T>.Filter.Eq("_id", new ObjectId(id)));
}
/// <summary>
/// 异步删除多条数据
/// </summary>
/// <param name="filter">删除的条件</param>
/// <returns></returns>
public async Task<DeleteResult> DeleteManyAsync(FilterDefinition<T> filter)
{
return await _dbSet.DeleteManyAsync(filter);
}
#endregion
#region
/// <summary>
/// 指定对象异步修改一条数据
/// </summary>
/// <param name="obj">要修改的对象</param>
/// <param name="id">修改条件</param>
/// <returns></returns>
public async Task UpdateAsync(T obj, string id)
{
//修改条件
FilterDefinition<T> filter = Builders<T>.Filter.Eq("_id", new ObjectId(id));
//要修改的字段
var list = new List<UpdateDefinition<T>>();
foreach (var item in obj.GetType().GetProperties())
{
if (item.Name.ToLower() == "id") continue;
list.Add(Builders<T>.Update.Set(item.Name, item.GetValue(obj)));
}
var updatefilter = Builders<T>.Update.Combine(list);
await _dbSet.UpdateOneAsync(filter, updatefilter);
}
/// <summary>
/// 局部更新(仅更新一条记录)
/// <para><![CDATA[expression 参数示例x => x.Id == 1 && x.Age > 18 && x.Gender == 0]]></para>
/// <para><![CDATA[entity 参数示例y => new T{ RealName = "Ray", Gender = 1}]]></para>
/// </summary>
/// <param name="expression">筛选条件</param>
/// <param name="entity">更新条件</param>
/// <returns></returns>
public async Task UpdateAsync(Expression<Func<T, bool>> expression, Expression<Action<T>> entity)
{
var fieldList = new List<UpdateDefinition<T>>();
if (entity.Body is MemberInitExpression param)
{
foreach (var item in param.Bindings)
{
var propertyName = item.Member.Name;
object propertyValue = null;
if (item is not MemberAssignment memberAssignment) continue;
if (memberAssignment.Expression.NodeType == ExpressionType.Constant)
{
if (memberAssignment.Expression is ConstantExpression constantExpression)
propertyValue = constantExpression.Value;
}
else
{
propertyValue = Expression.Lambda(memberAssignment.Expression, null).Compile().DynamicInvoke();
}
if (propertyName != "_id") //实体键_id不允许更新
{
fieldList.Add(Builders<T>.Update.Set(propertyName, propertyValue));
}
}
}
await _dbSet.UpdateOneAsync(expression, Builders<T>.Update.Combine(fieldList));
}
/// <summary>
/// 异步局部更新(仅更新一条记录)
/// </summary>
/// <param name="filter">过滤器</param>
/// <param name="update">更新条件</param>
/// <returns></returns>
public async Task UpdateAsync(FilterDefinition<T> filter, UpdateDefinition<T> update)
{
await _dbSet.UpdateOneAsync(filter, update);
}
/// <summary>
/// 异步局部更新(仅更新多条记录)
/// </summary>
/// <param name="expression">筛选条件</param>
/// <param name="update">更新条件</param>
/// <returns></returns>
public async Task UpdateManyAsync(Expression<Func<T, bool>> expression, UpdateDefinition<T> update)
{
await _dbSet.UpdateManyAsync(expression, update);
}
/// <summary>
/// 异步批量修改数据
/// </summary>
/// <param name="dic">要修改的字段</param>
/// <param name="filter">更新条件</param>
/// <returns></returns>
public async Task<UpdateResult> UpdateManayAsync(Dictionary<string, string> dic, FilterDefinition<T> filter)
{
T t = new T();
//要修改的字段
var list = new List<UpdateDefinition<T>>();
foreach (var item in t.GetType().GetProperties())
{
if (!dic.ContainsKey(item.Name)) continue;
var value = dic[item.Name];
list.Add(Builders<T>.Update.Set(item.Name, value));
}
var updatefilter = Builders<T>.Update.Combine(list);
return await _dbSet.UpdateManyAsync(filter, updatefilter);
}
#endregion
#region
/// <summary>
/// 通过ID主键获取数据
/// </summary>
/// <param name="id">objectId</param>
/// <returns></returns>
public async Task<T> GetByIdAsync(string id)
{
var queryData = await _dbSet.FindAsync(Builders<T>.Filter.Eq("_id", new ObjectId(id)));
return queryData.FirstOrDefault();
}
/// <summary>
/// 获取所有数据
/// </summary>
/// <returns></returns>
public async Task<IEnumerable<T>> GetAllAsync()
{
var queryAllData = await _dbSet.FindAsync(Builders<T>.Filter.Empty);
return queryAllData.ToList();
}
/// <summary>
/// 获取记录数
/// </summary>
/// <param name="expression">筛选条件</param>
/// <returns></returns>
public async Task<long> CountAsync(Expression<Func<T, bool>> expression)
{
return await _dbSet.CountDocumentsAsync(expression);
}
/// <summary>
/// 获取记录数
/// </summary>
/// <param name="filter">过滤器</param>
/// <returns></returns>
public async Task<long> CountAsync(FilterDefinition<T> filter)
{
return await _dbSet.CountDocumentsAsync(filter);
}
/// <summary>
/// 判断是否存在
/// </summary>
/// <param name="predicate">条件</param>
/// <returns></returns>
public async Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate)
{
return await Task.FromResult(_dbSet.AsQueryable().Any(predicate));
}
/// <summary>
/// 异步查询集合
/// </summary>
/// <param name="filter">查询条件</param>
/// <param name="field">要查询的字段,不写时查询全部</param>
/// <param name="sort">要排序的字段</param>
/// <returns></returns>
public async Task<List<T>> FindListAsync(FilterDefinition<T> filter, string[]? field = null, SortDefinition<T>? sort = null)
{
//不指定查询字段
if (field == null || field.Length == 0)
{
if (sort == null) return await _dbSet.Find(filter).ToListAsync();
return await _dbSet.Find(filter).Sort(sort).ToListAsync();
}
//指定查询字段
var fieldList = new List<ProjectionDefinition<T>>();
for (int i = 0; i < field.Length; i++)
{
fieldList.Add(Builders<T>.Projection.Include(field[i].ToString()));
}
var projection = Builders<T>.Projection.Combine(fieldList);
fieldList?.Clear();
//不排序
if (sort == null) return await _dbSet.Find(filter).Project<T>(projection).ToListAsync();
//排序查询
return await _dbSet.Find(filter).Sort(sort).Project<T>(projection).ToListAsync();
}
/// <summary>
/// 异步分页查询集合
/// </summary>
/// <param name="filter">查询条件</param>
/// <param name="pageIndex">当前页</param>
/// <param name="pageSize">页容量</param>
/// <param name="field">要查询的字段,不写时查询全部</param>
/// <param name="sort">要排序的字段</param>
/// <returns></returns>
public async Task<List<T>> FindListByPageAsync(FilterDefinition<T> filter, int pageIndex, int pageSize, string[]? field = null, SortDefinition<T>? sort = null)
{
//不指定查询字段
if (field == null || field.Length == 0)
{
if (sort == null) return await _dbSet.Find(filter).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();
//进行排序
return await _dbSet.Find(filter).Sort(sort).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();
}
//指定查询字段
var fieldList = new List<ProjectionDefinition<T>>();
for (int i = 0; i < field.Length; i++)
{
fieldList.Add(Builders<T>.Projection.Include(field[i].ToString()));
}
var projection = Builders<T>.Projection.Combine(fieldList);
fieldList?.Clear();
//不排序
if (sort == null) return await _dbSet.Find(filter).Project<T>(projection).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();
//排序查询
return await _dbSet.Find(filter).Sort(sort).Project<T>(projection).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync();
}
#endregion
}
}

View File

@ -1,93 +0,0 @@
using Microsoft.Extensions.Configuration;
using MongoDB.Driver;
namespace JiShe.CollectBus.MongoDB
{
public class MongoContext : IMongoContext
{
private readonly IMongoDatabase _database;
private readonly MongoClient _mongoClient;
//这里将 _commands 中的每个元素都定义为一个 Func<IClientSessionHandle, Task> 委托,此委托表示一个需要 IClientSessionHandle 对象作为参数并返回一个异步任务的方法
//每个委托都表示一个MongoDB 会话session对象和要执行的命令
private readonly List<Func<IClientSessionHandle, Task>> _commands = [];
public MongoContext(IConfiguration configuration)
{
_mongoClient = new MongoClient(configuration["MongoSettings:Connection"]);
_database = _mongoClient.GetDatabase(configuration["MongoSettings:DatabaseName"]);
}
/// <summary>
/// 添加命令操作
/// </summary>
/// <param name="func">方法接受一个 Func<IClientSessionHandle, Task> 委托作为参数,该委托表示一个需要 IClientSessionHandle 对象作为参数并返回一个异步任务的方法</param>
/// <returns></returns>
public async Task AddCommandAsync(Func<IClientSessionHandle, Task> func)
{
_commands.Add(func);
await Task.CompletedTask;
}
/// <summary>
/// 提交更改并返回受影响的行数
/// TODOMongoDB单机服务器不支持事务【使用MongoDB事务会报错Standalone servers do not support transactions】,只有在集群情况下才支持事务
/// 原因MongoDB在使用分布式事务时需要进行多节点之间的协调和通信而单机环境下无法实现这样的分布式协调和通信机制。但是在MongoDB部署为一个集群cluster将多个计算机连接为一个整体通过协调和通信机制实现了分布式事务的正常使用。从数据一致性和可靠性的角度来看在分布式系统中实现事务处理是至关重要的。而在单机环境下不支持事务只有在集群情况下才支持事务的设计方式是为了保证数据一致性和可靠性并且也符合分布式系统的设计思想。
/// </summary>
/// <param name="session">MongoDB 会话session对象</param>
/// <returns></returns>
public async Task<int> SaveChangesAsync(IClientSessionHandle session)
{
try
{
session.StartTransaction();//开始事务
foreach (var command in _commands)
{
await command(session);
}
await session.CommitTransactionAsync();//提交事务
return _commands.Count;
}
catch (Exception ex)
{
await session.AbortTransactionAsync();//回滚事务
return 0;
}
finally
{
_commands.Clear();//清空_commands列表中的元素
}
}
/// <summary>
/// 初始化Mongodb会话对象session
/// </summary>
/// <returns></returns>
public async Task<IClientSessionHandle> StartSessionAsync()
{
var session = await _mongoClient.StartSessionAsync();
return session;
}
/// <summary>
/// 获取MongoDB集合
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name">集合名称</param>
/// <returns></returns>
public IMongoCollection<T> GetCollection<T>(string name)
{
return _database.GetCollection<T>(name);
}
/// <summary>
/// 释放上下文
/// </summary>
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
}

View File

@ -1,43 +0,0 @@
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.MongoDB
{
public class UnitOfWork : IUnitOfWork
{
private readonly IMongoContext _context;
public UnitOfWork(IMongoContext context)
{
_context = context;
}
/// <summary>
/// 提交保存更改
/// </summary>
/// <param name="session">MongoDB 会话session对象</param>
/// <returns></returns>
public async Task<bool> Commit(IClientSessionHandle session)
{
return await _context.SaveChangesAsync(session) > 0;
}
/// <summary>
/// 初始化MongoDB会话对象session
/// </summary>
/// <returns></returns>
public async Task<IClientSessionHandle> InitTransaction()
{
return await _context.StartSessionAsync();
}
public void Dispose()
{
_context.Dispose();
}
}
}

View File

@ -1,19 +0,0 @@
using System;
using System.Threading.Tasks;
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.Protocol.Contracts.Models;
using TouchSocket.Sockets;
namespace JiShe.CollectBus.Protocol.Contracts.Interfaces
{
public interface IProtocolPlugin
{
Task<ProtocolInfo> GetAsync();
Task AnalyzeAsync(MessageReceivedEvent messageReceivedEvent, Action<byte[]>? sendAction = null);
Task LoginAsync(MessageReceivedLoginEvent messageReceivedEvent, Action<byte[]>? sendAction = null);
Task HeartbeatAsync(MessageReceivedHeartbeatEvent messageReceivedEvent, Action<byte[]>? sendAction = null);
}
}

View File

@ -1,18 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\JiShe.CollectBus.Protocol.Contracts\JiShe.CollectBus.Protocol.Contracts.csproj" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="copy $(TargetDir)JiShe.CollectBus.Protocol.Demo.dll $(ProjectDir)..\JiShe.CollectBus.Console\Plugins\" />
</Target>
</Project>

View File

@ -1,20 +0,0 @@
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.Modularity;
namespace JiShe.CollectBus.Protocol.Demo
{
public class JiSheCollectBusTestProtocolModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddKeyedSingleton<IProtocolPlugin, TestProtocolPlugin>("Test");
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
}
}
}

View File

@ -1,27 +0,0 @@
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.Protocol.Contracts.Abstracts;
using JiShe.CollectBus.Protocol.Contracts.Attributes;
using JiShe.CollectBus.Protocol.Contracts.Models;
using Microsoft.Extensions.Logging;
namespace JiShe.CollectBus.Protocol.Demo
{
[ProtocolName("TestProtocol")]
public class TestProtocolPlugin : BaseProtocolPlugin
{
public TestProtocolPlugin(ILogger<BaseProtocolPlugin> logger) : base(logger)
{
}
public override async Task<ProtocolInfo> GetAsync()
{
var info = new ProtocolInfo("Test", "376.1", "TCP", "376.1协议", "DTS1980");
return await Task.FromResult(info);
}
public override Task AnalyzeAsync(MessageReceivedEvent messageReceivedEvent, Action<byte[]>? sendAction = null)
{
throw new NotImplementedException();
}
}
}

View File

@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.MQ.Sender
{
public interface INSender
{
Task SendToIssuedAsync<T>(T message, CancellationToken cancellationToken = default) where T : class;
Task SendToIssuedAsync(object message, CancellationToken cancellationToken = default);
Task SendToReceivedAsync<T>(T message, CancellationToken cancellationToken = default) where T : class;
Task SendToReceivedAsync(object message, CancellationToken cancellationToken = default);
Task SendToReceivedLoginAsync<T>(T message, CancellationToken cancellationToken = default) where T : class;
Task SendToReceivedLoginAsync(object message, CancellationToken cancellationToken = default);
Task SendToReceivedHeartbeatAsync<T>(T message, CancellationToken cancellationToken = default) where T : class;
Task SendToReceivedHeartbeatAsync(object message, CancellationToken cancellationToken = default);
Task SendAsync(string queueKey, object message, CancellationToken cancellationToken = default);
}
}

View File

@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
<JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MassTransit" Version="8.3.0" />
<PackageReference Include="MassTransit.RabbitMQ" Version="8.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
</ItemGroup>
</Project>

View File

@ -1,17 +0,0 @@
using Volo.Abp;
using Volo.Abp.Modularity;
namespace JiShe.CollectBus.MQ.Sender
{
public class JiSheCollectBusMqSenderModule: AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
}
}
}

View File

@ -1,71 +0,0 @@
using MassTransit;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
namespace JiShe.CollectBus.MQ.Sender
{
public class NSender : INSender, ISingletonDependency
{
private readonly ServiceProvider _serviceProvider;
private readonly string _issuedKey;
private readonly string _receivedKey;
public NSender(IConfiguration configuration, ServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_issuedKey = configuration["MQ:Queue:Issued"]!;
_receivedKey = configuration["MQ:Queue:Received"]!;
}
public async Task SendToIssuedAsync<T>(T message, CancellationToken cancellationToken = default) where T : class
{
await SendAsync(_issuedKey, message, cancellationToken);
}
public async Task SendToIssuedAsync(object message, CancellationToken cancellationToken = default)
{
await SendAsync(_issuedKey, message, cancellationToken);
}
public async Task SendToReceivedAsync<T>(T message, CancellationToken cancellationToken = default) where T : class
{
await SendAsync(_receivedKey, message, cancellationToken);
}
public async Task SendToReceivedAsync(object message, CancellationToken cancellationToken = default)
{
await SendAsync(_receivedKey, message, cancellationToken);
}
public async Task SendToReceivedLoginAsync<T>(T message, CancellationToken cancellationToken = default) where T : class
{
await SendAsync($"{_receivedKey}_Login", message, cancellationToken);
}
public async Task SendToReceivedLoginAsync(object message, CancellationToken cancellationToken = default)
{
await SendAsync($"{_receivedKey}_Login", message, cancellationToken);
}
public async Task SendToReceivedHeartbeatAsync<T>(T message, CancellationToken cancellationToken = default) where T : class
{
await SendAsync($"{_receivedKey}_Heartbeat", message, cancellationToken);
}
public async Task SendToReceivedHeartbeatAsync(object message, CancellationToken cancellationToken = default)
{
await SendAsync($"{_receivedKey}_Heartbeat", message, cancellationToken);
}
public async Task SendAsync(string queueKey, object message, CancellationToken cancellationToken = default)
{
using var scope = _serviceProvider.CreateScope();
var scopedService = scope.ServiceProvider.GetRequiredService<ISendEndpointProvider>();
var endpoint = await scopedService.GetSendEndpoint(new Uri($"queue:{queueKey}"));
await endpoint.Send(message, cancellationToken);
}
}
}

View File

@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Core" Version="8.3.3" />
<PackageReference Include="MassTransit" Version="8.3.0" />
<PackageReference Include="MassTransit.RabbitMQ" Version="8.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JiShe.CollectBus.Core\JiShe.CollectBus.Network.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.Protocol.Contracts\JiShe.CollectBus.Protocol.Contracts.csproj" />
</ItemGroup>
</Project>

View File

@ -1,87 +0,0 @@
using JiShe.CollectBus.Network;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.Modularity;
namespace JiShe.CollectBus.MQ.Consumer
{
[DependsOn(typeof(JiSheCollectBusNetworkModule))]
public class JiSheCollectBusMqConsumerModule: AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
context.Services.AddMassTransit(x =>
{
x.AddConsumer<MessageReceivedConsumer>(cfg =>
{
cfg.Options<BatchOptions>(options => options
.SetMessageLimit(100)
.SetTimeLimit(s: 1)
.SetTimeLimitStart(BatchTimeLimitStart.FromLast)
//.GroupBy<MyMessage, string>(x => x.CustomerId)
.SetConcurrencyLimit(10));
});
x.AddConsumer<MessageIssuedConsumer>();
x.AddConsumer<MessageReceivedLoginConsumer>();
x.AddConsumer<MessageReceivedHeartbeatConsumer>();
x.AddConfigureEndpointsCallback((c, name, cfg) =>
{
cfg.UseDelayedRedelivery(r => r.Intervals(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(30)));
cfg.UseMessageRetry(r => r.Immediate(5));
cfg.UseInMemoryOutbox(c);
//cfg.UseMessageRetry(r =>
//{
// r.Immediate(5);
// r.Handle<DataException>(x => x.Message.Contains("SQL"));
//});
});
x.UsingRabbitMq((c, cfg) =>
{
cfg.Host(configuration["MQ:Host"], ushort.Parse(configuration["MQ:Port"] ?? string.Empty), configuration["MQ:VirtualHost"], h =>
{
h.Username(configuration["MQ:UserName"] ?? string.Empty);
h.Password(configuration["MQ:Password"] ?? string.Empty);
});
// 消息接收队列
cfg.ReceiveEndpoint(configuration["MQ:Queue:Received"] ?? string.Empty, configurator =>
{
configurator.ConfigureConsumeTopology = false;
configurator.Consumer<MessageReceivedConsumer>(c);
configurator.Durable = true;
});
// 登录
cfg.ReceiveEndpoint($"{configuration["MQ:Queue:Received"]}_Login", configurator =>
{
configurator.ConfigureConsumeTopology = false;
configurator.Consumer<MessageReceivedLoginConsumer>(c);
configurator.Durable = true;
});
// 心跳
cfg.ReceiveEndpoint($"{configuration["MQ:Queue:Received"]}_Heartbeat", configurator =>
{
configurator.ConfigureConsumeTopology = false;
configurator.Consumer<MessageReceivedHeartbeatConsumer>(c);
configurator.Durable = true;
});
// 消息下发队列
cfg.ReceiveEndpoint(configuration["MQ:Queue:Issued"] ?? string.Empty, configurator =>
{
configurator.ConfigureConsumeTopology = false;
configurator.Consumer<MessageIssuedConsumer>(c);
configurator.Durable = true;
});
});
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
}
}
}

View File

@ -1,35 +0,0 @@
using JiShe.CollectBus.Common.Enums;
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.MongoDB;
using MassTransit;
using Microsoft.Extensions.Logging;
using TouchSocket.Sockets;
namespace JiShe.CollectBus.MQ.Consumer
{
public class MessageIssuedConsumer(
ILogger<MessageIssuedEvent> logger,
ITcpService tcpService,
IMongoRepository<MessageReceivedHeartbeatEvent> mongoHeartbeatRepository,
IMongoRepository<MessageReceivedLoginEvent> mongoLoginRepository)
: IConsumer<MessageIssuedEvent>
{
public async Task Consume(ConsumeContext<MessageIssuedEvent> context)
{
switch (context.Message.Type)
{
case IssuedEventType.Heartbeat:
await mongoHeartbeatRepository.UpdateAsync(a => a.MessageId == context.Message.MessageId, b => new MessageReceivedHeartbeatEvent { IsAck = true, AckTime = DateTime.Now });
break;
case IssuedEventType.Login:
await mongoLoginRepository.UpdateAsync(a => a.MessageId == context.Message.MessageId, b => new MessageReceivedLoginEvent { IsAck = true, AckTime = DateTime.Now });
break;
case IssuedEventType.Data:
break;
default:
throw new ArgumentOutOfRangeException();
}
await tcpService.SendAsync(context.Message.ClientId, context.Message.Message);
}
}
}

View File

@ -1,13 +0,0 @@
using JiShe.CollectBus.Common.Models;
using MassTransit;
namespace JiShe.CollectBus.MQ.Consumer
{
public class MessageIssuedFaultConsumer : IConsumer<Fault<MessageIssuedEvent>>
{
public Task Consume(ConsumeContext<Fault<MessageIssuedEvent>> context)
{
throw new NotImplementedException();
}
}
}

View File

@ -1,39 +0,0 @@
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.MongoDB;
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace JiShe.CollectBus.MQ.Consumer
{
/// <summary>
/// Batch 一次最多 100 个,最多 10 个并发批次
/// </summary>
public class MessageReceivedConsumer(
ILogger<MessageReceivedConsumer> logger,
IServiceProvider serviceProvider,
IMongoRepository<MessageReceivedEvent> mongoReceivedRepository)
: IConsumer<Batch<MessageReceivedEvent>>
{
public async Task Consume(ConsumeContext<Batch<MessageReceivedEvent>> context)
{
const string protocolType = "Standard";
var protocolPlugin = serviceProvider.GetKeyedService<IProtocolPlugin>(protocolType);
if (protocolPlugin == null)
{
logger.LogError("协议不存在!");
}
else
{
var list = new List<MessageReceivedEvent>();
foreach (var contextItem in context.Message)
{
await protocolPlugin.AnalyzeAsync(contextItem.Message);
list.Add(contextItem.Message);
}
await mongoReceivedRepository.InsertManyAsync(list);
}
}
}
}

View File

@ -1,13 +0,0 @@
using JiShe.CollectBus.Common.Models;
using MassTransit;
namespace JiShe.CollectBus.MQ.Consumer
{
public class MessageReceivedFaultConsumer: IConsumer<Fault<Batch<MessageReceivedEvent>>>
{
public Task Consume(ConsumeContext<Fault<Batch<MessageReceivedEvent>>> context)
{
throw new NotImplementedException();
}
}
}

View File

@ -1,29 +0,0 @@
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace JiShe.CollectBus.MQ.Consumer
{
public class MessageReceivedHeartbeatConsumer(
ILogger<MessageReceivedHeartbeatConsumer> logger,
IServiceProvider serviceProvider)
: IConsumer<MessageReceivedHeartbeatEvent>
{
public async Task Consume(ConsumeContext<MessageReceivedHeartbeatEvent> context)
{
logger.LogInformation("心跳消费队列开始处理");
var protocolPlugin = serviceProvider.GetKeyedService<IProtocolPlugin>("Standard");
if (protocolPlugin == null)
{
logger.LogError("【心跳消费队列开始处理】协议不存在!");
}
else
{
await protocolPlugin.HeartbeatAsync(context.Message);
logger.LogInformation("心跳消费队列完成处理");
}
}
}
}

View File

@ -1,29 +0,0 @@
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace JiShe.CollectBus.MQ.Consumer
{
public class MessageReceivedLoginConsumer(
ILogger<MessageReceivedLoginConsumer> logger,
IServiceProvider serviceProvider)
: IConsumer<MessageReceivedLoginEvent>
{
public async Task Consume(ConsumeContext<MessageReceivedLoginEvent> context)
{
logger.LogInformation("登录消费队列开始处理");
var protocolPlugin = serviceProvider.GetKeyedService<IProtocolPlugin>("Standard");
if (protocolPlugin == null)
{
logger.LogError("【登录消费队列开始处理】协议不存在!");
}
else
{
await protocolPlugin.LoginAsync(context.Message);
logger.LogInformation("登录消费队列完成处理");
}
}
}
}

View File

@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JiShe.CollectBus.Common.Enums;
using JiShe.CollectBus.Common.Extensions;
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.MQ.Sender;
using JiShe.CollectBus.Protocol.Contracts.Models;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit.Abstractions;
namespace JiShe.CollectBus.Test
{
public class BusUnitTest
{
private INSender _nSender;
public BusUnitTest()
{
_nSender = new Mock<INSender>().Object;
}
[Fact]
public async void AmmeterParameterSend()
{
var listMeter = new List<AmmeterParameter>()
{
new()
{
Pn = 1,
BaudRate = 3,
Port = 2,
ProtocolType = CommunicationProtocolType.DLT6452007,
Address = "312408006642",
Password = "000000",
RateNumber = 4,
IntegerBitNumber = 4,
DecimalBitNumber = 4,
CollectorAddress = "000000000000",
UserCategoryNumber = 0,
UserSubclassNumber = 0
}
};
var bytes = HexStringExtensions.BuildAmmeterParameterSetSendCmd(new ReqParameter2()
{
AFN = AFN.,
FunCode = (int)CMasterStationFunCode.1,
A = "322009872",
Seq = new Seq()
{
TpV = TpV.,
FIRFIN = FIRFIN.,
CON = CON.,
PRSEQ = 10,
},
MSA = 13,
Pn = 0,
Fn = 10
}, listMeter);
Assert.NotEmpty(bytes);
await _nSender.SendToIssuedAsync(new MessageIssuedEvent { DeviceNo = "322009872", Message = bytes, Type = IssuedEventType.Data, MessageId = Guid.NewGuid().ToString() });
}
}
}

View File

@ -1,29 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JiShe.CollectBus.Protocol.Contracts\JiShe.CollectBus.Protocol.Contracts.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.RabbitMQ\JiShe.CollectBus.MQ.Sender.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
</Project>

62
JiShe.CollectBus.abpmdl Normal file
View File

@ -0,0 +1,62 @@
{
"folders": {
"items": {
"src": {},
"test": {}
}
},
"packages": {
"JiShe.CollectBus.Domain": {
"path": "src/JiShe.CollectBus.Domain/JiShe.CollectBus.Domain.abppkg",
"folder": "src"
},
"JiShe.CollectBus.Application.Contracts": {
"path": "src/JiShe.CollectBus.Application.Contracts/JiShe.CollectBus.Application.Contracts.abppkg",
"folder": "src"
},
"JiShe.CollectBus.Application": {
"path": "src/JiShe.CollectBus.Application/JiShe.CollectBus.Application.abppkg",
"folder": "src"
},
"JiShe.CollectBus.EntityFrameworkCore": {
"path": "src/JiShe.CollectBus.EntityFrameworkCore/JiShe.CollectBus.EntityFrameworkCore.abppkg",
"folder": "src"
},
"JiShe.CollectBus.MongoDB": {
"path": "src/JiShe.CollectBus.MongoDB/JiShe.CollectBus.MongoDB.abppkg",
"folder": "src"
},
"JiShe.CollectBus.HttpApi": {
"path": "src/JiShe.CollectBus.HttpApi/JiShe.CollectBus.HttpApi.abppkg",
"folder": "src"
},
"JiShe.CollectBus.HttpApi.Client": {
"path": "src/JiShe.CollectBus.HttpApi.Client/JiShe.CollectBus.HttpApi.Client.abppkg",
"folder": "src"
},
"JiShe.CollectBus.TestBase": {
"path": "test/JiShe.CollectBus.TestBase/JiShe.CollectBus.TestBase.abppkg",
"folder": "test"
},
"JiShe.CollectBus.EntityFrameworkCore.Tests": {
"path": "test/JiShe.CollectBus.EntityFrameworkCore.Tests/JiShe.CollectBus.EntityFrameworkCore.Tests.abppkg",
"folder": "test"
},
"JiShe.CollectBus.MongoDB.Tests": {
"path": "test/JiShe.CollectBus.MongoDB.Tests/JiShe.CollectBus.MongoDB.Tests.abppkg",
"folder": "test"
},
"JiShe.CollectBus.Domain.Tests": {
"path": "test/JiShe.CollectBus.Domain.Tests/JiShe.CollectBus.Domain.Tests.abppkg",
"folder": "test"
},
"JiShe.CollectBus.Application.Tests": {
"path": "test/JiShe.CollectBus.Application.Tests/JiShe.CollectBus.Application.Tests.abppkg",
"folder": "test"
},
"JiShe.CollectBus.Domain.Shared": {
"path": "src/JiShe.CollectBus.Domain.Shared/JiShe.CollectBus.Domain.Shared.abppkg",
"folder": "src"
}
}
}

9
JiShe.CollectBus.abpsln Normal file
View File

@ -0,0 +1,9 @@
{
"id": "ff9a1137-9bbc-4a8f-9b0b-0765c3bfc2e0",
"template": "empty",
"modules": {
"JiShe.CollectBus": {
"path": "JiShe.CollectBus.abpmdl"
}
}
}

View File

@ -3,41 +3,31 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.9.34728.123 VisualStudioVersion = 17.9.34728.123
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Network", "JiShe.CollectBus.Core\JiShe.CollectBus.Network.csproj", "{F1360C93-5B6B-4E65-9D81-1DA38740F32D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Domain.Shared", "src\JiShe.CollectBus.Domain.Shared\JiShe.CollectBus.Domain.Shared.csproj", "{D64C1577-4929-4B60-939E-96DE1534891A}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Console", "JiShe.CollectBus.Console\JiShe.CollectBus.Console.csproj", "{40C4F834-3080-451B-9510-6FE7BC4F801F}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Domain", "src\JiShe.CollectBus.Domain\JiShe.CollectBus.Domain.csproj", "{F2840BC7-0188-4606-9126-DADD0F5ABF7A}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Protocol", "JiShe.CollectBus.Protocol\JiShe.CollectBus.Protocol.csproj", "{B2C476F1-AE32-419D-BDA2-291FCE639CF6}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Application.Contracts", "src\JiShe.CollectBus.Application.Contracts\JiShe.CollectBus.Application.Contracts.csproj", "{BD65D04F-08D5-40C1-8C24-77CA0BACB877}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Protocol.Contracts", "JiShe.CollectBus.Protocol.Contracts\JiShe.CollectBus.Protocol.Contracts.csproj", "{4468B52D-3AAE-4918-B4D6-E6E8F000825D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Application", "src\JiShe.CollectBus.Application\JiShe.CollectBus.Application.csproj", "{78040F9E-3501-4A40-82DF-00A597710F35}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Common", "JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj", "{1D3A5A4E-B977-4E33-A1AF-62508110C3B7}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{649A3FFA-182F-4E56-9717-E6A9A2BEC545}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3.test", "3.test", "{3A04FB29-EA75-4499-BBF3-AF24C7D46A1D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.MongoDB", "src\JiShe.CollectBus.MongoDB\JiShe.CollectBus.MongoDB.csproj", "{F1C58097-4C08-4D88-8976-6B3389391481}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2.core", "2.core", "{C7DEC9FB-3F75-4584-85B0-16EA3CB222E5}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.HttpApi", "src\JiShe.CollectBus.HttpApi\JiShe.CollectBus.HttpApi.csproj", "{077AA5F8-8B61-420C-A6B5-0150A66FDB34}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Protocol.Demo", "JiShe.CollectBus.Protocol.Test\JiShe.CollectBus.Protocol.Demo.csproj", "{289196B4-FFBE-4E40-A3A1-FCFADBE945ED}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Host", "src\JiShe.CollectBus.Host\JiShe.CollectBus.Host.csproj", "{35829A15-4127-4F69-8BDE-9405DEAACA9A}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.EntityFrameworkCore", "JiShe.CollectBus.EntityFrameworkCore\JiShe.CollectBus.EntityFrameworkCore.csproj", "{16D42BCF-EDB8-4153-B37D-0B10FB6DF36C}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Common", "src\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj", "{AD2F1928-4411-4511-B564-5FB996EC08B9}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.MQ.Sender", "JiShe.CollectBus.RabbitMQ\JiShe.CollectBus.MQ.Sender.csproj", "{DB46D90E-304D-48B7-9ED6-F4DCC95D3824}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Protocol", "src\JiShe.CollectBus.Protocol\JiShe.CollectBus.Protocol.csproj", "{C62EFF95-5C32-435F-BD78-6977E828F894}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.MongoDB", "JiShe.CollectBus.MongoDB\JiShe.CollectBus.MongoDB.csproj", "{223DBDB1-6CD3-4D4E-8795-42550BC0A871}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Protocol.Contracts", "src\JiShe.CollectBus.Protocol.Contracts\JiShe.CollectBus.Protocol.Contracts.csproj", "{38C1808B-009A-418B-B17B-AB3626341B5D}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1.host", "1.host", "{B68027BA-BD9D-4110-A383-708B87BC425D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.DbMigrator", "src\JiShe.CollectBus.DbMigrator\JiShe.CollectBus.DbMigrator.csproj", "{8BA01C3D-297D-42DF-BD63-EF07202A0A67}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Host", "JiShe.CollectBus.Host\JiShe.CollectBus.Host.csproj", "{FFA010F6-F33A-4705-8A42-B0FA3B3D2131}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.FreeSql", "src\JiShe.CollectBus.FreeSql\JiShe.CollectBus.FreeSql.csproj", "{FE0457D9-4038-4A17-8808-DCAD06CFC0A0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4.demo", "4.demo", "{43E8E19B-555A-4633-9926-B4F3C01D972A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiShe.CollectBus.Test", "JiShe.CollectBus.Test\JiShe.CollectBus.Test.csproj", "{6ED66F52-B4A0-403E-AE89-8E9A679C0885}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JiShe.CollectBus.Application", "JiShe.CollectBus.Application\JiShe.CollectBus.Application.csproj", "{2760AC98-D2FA-4074-8396-FAE10BE20A3C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JiShe.CollectBus.Application.Contracts", "JiShe.CollectBus.Application.Contracts\JiShe.CollectBus.Application.Contracts.csproj", "{47B9A51B-70B5-42ED-A92A-FFEFB864CB14}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JiShe.CollectBus.MQ.Consumer", "JiShe.CollectBus.Service\JiShe.CollectBus.MQ.Consumer.csproj", "{024086CC-49D0-436E-8B84-A67766A30CDE}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -45,83 +35,73 @@ Global
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F1360C93-5B6B-4E65-9D81-1DA38740F32D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D64C1577-4929-4B60-939E-96DE1534891A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F1360C93-5B6B-4E65-9D81-1DA38740F32D}.Debug|Any CPU.Build.0 = Debug|Any CPU {D64C1577-4929-4B60-939E-96DE1534891A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F1360C93-5B6B-4E65-9D81-1DA38740F32D}.Release|Any CPU.ActiveCfg = Release|Any CPU {D64C1577-4929-4B60-939E-96DE1534891A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F1360C93-5B6B-4E65-9D81-1DA38740F32D}.Release|Any CPU.Build.0 = Release|Any CPU {D64C1577-4929-4B60-939E-96DE1534891A}.Release|Any CPU.Build.0 = Release|Any CPU
{40C4F834-3080-451B-9510-6FE7BC4F801F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{40C4F834-3080-451B-9510-6FE7BC4F801F}.Debug|Any CPU.Build.0 = Debug|Any CPU {F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40C4F834-3080-451B-9510-6FE7BC4F801F}.Release|Any CPU.ActiveCfg = Release|Any CPU {F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40C4F834-3080-451B-9510-6FE7BC4F801F}.Release|Any CPU.Build.0 = Release|Any CPU {F2840BC7-0188-4606-9126-DADD0F5ABF7A}.Release|Any CPU.Build.0 = Release|Any CPU
{B2C476F1-AE32-419D-BDA2-291FCE639CF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BD65D04F-08D5-40C1-8C24-77CA0BACB877}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2C476F1-AE32-419D-BDA2-291FCE639CF6}.Debug|Any CPU.Build.0 = Debug|Any CPU {BD65D04F-08D5-40C1-8C24-77CA0BACB877}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2C476F1-AE32-419D-BDA2-291FCE639CF6}.Release|Any CPU.ActiveCfg = Release|Any CPU {BD65D04F-08D5-40C1-8C24-77CA0BACB877}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2C476F1-AE32-419D-BDA2-291FCE639CF6}.Release|Any CPU.Build.0 = Release|Any CPU {BD65D04F-08D5-40C1-8C24-77CA0BACB877}.Release|Any CPU.Build.0 = Release|Any CPU
{4468B52D-3AAE-4918-B4D6-E6E8F000825D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {78040F9E-3501-4A40-82DF-00A597710F35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4468B52D-3AAE-4918-B4D6-E6E8F000825D}.Debug|Any CPU.Build.0 = Debug|Any CPU {78040F9E-3501-4A40-82DF-00A597710F35}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4468B52D-3AAE-4918-B4D6-E6E8F000825D}.Release|Any CPU.ActiveCfg = Release|Any CPU {78040F9E-3501-4A40-82DF-00A597710F35}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4468B52D-3AAE-4918-B4D6-E6E8F000825D}.Release|Any CPU.Build.0 = Release|Any CPU {78040F9E-3501-4A40-82DF-00A597710F35}.Release|Any CPU.Build.0 = Release|Any CPU
{1D3A5A4E-B977-4E33-A1AF-62508110C3B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F1C58097-4C08-4D88-8976-6B3389391481}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D3A5A4E-B977-4E33-A1AF-62508110C3B7}.Debug|Any CPU.Build.0 = Debug|Any CPU {F1C58097-4C08-4D88-8976-6B3389391481}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D3A5A4E-B977-4E33-A1AF-62508110C3B7}.Release|Any CPU.ActiveCfg = Release|Any CPU {F1C58097-4C08-4D88-8976-6B3389391481}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D3A5A4E-B977-4E33-A1AF-62508110C3B7}.Release|Any CPU.Build.0 = Release|Any CPU {F1C58097-4C08-4D88-8976-6B3389391481}.Release|Any CPU.Build.0 = Release|Any CPU
{289196B4-FFBE-4E40-A3A1-FCFADBE945ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {077AA5F8-8B61-420C-A6B5-0150A66FDB34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{289196B4-FFBE-4E40-A3A1-FCFADBE945ED}.Debug|Any CPU.Build.0 = Debug|Any CPU {077AA5F8-8B61-420C-A6B5-0150A66FDB34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{289196B4-FFBE-4E40-A3A1-FCFADBE945ED}.Release|Any CPU.ActiveCfg = Release|Any CPU {077AA5F8-8B61-420C-A6B5-0150A66FDB34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{289196B4-FFBE-4E40-A3A1-FCFADBE945ED}.Release|Any CPU.Build.0 = Release|Any CPU {077AA5F8-8B61-420C-A6B5-0150A66FDB34}.Release|Any CPU.Build.0 = Release|Any CPU
{16D42BCF-EDB8-4153-B37D-0B10FB6DF36C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {35829A15-4127-4F69-8BDE-9405DEAACA9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{16D42BCF-EDB8-4153-B37D-0B10FB6DF36C}.Debug|Any CPU.Build.0 = Debug|Any CPU {35829A15-4127-4F69-8BDE-9405DEAACA9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{16D42BCF-EDB8-4153-B37D-0B10FB6DF36C}.Release|Any CPU.ActiveCfg = Release|Any CPU {35829A15-4127-4F69-8BDE-9405DEAACA9A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{16D42BCF-EDB8-4153-B37D-0B10FB6DF36C}.Release|Any CPU.Build.0 = Release|Any CPU {35829A15-4127-4F69-8BDE-9405DEAACA9A}.Release|Any CPU.Build.0 = Release|Any CPU
{DB46D90E-304D-48B7-9ED6-F4DCC95D3824}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AD2F1928-4411-4511-B564-5FB996EC08B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB46D90E-304D-48B7-9ED6-F4DCC95D3824}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD2F1928-4411-4511-B564-5FB996EC08B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB46D90E-304D-48B7-9ED6-F4DCC95D3824}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD2F1928-4411-4511-B564-5FB996EC08B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB46D90E-304D-48B7-9ED6-F4DCC95D3824}.Release|Any CPU.Build.0 = Release|Any CPU {AD2F1928-4411-4511-B564-5FB996EC08B9}.Release|Any CPU.Build.0 = Release|Any CPU
{223DBDB1-6CD3-4D4E-8795-42550BC0A871}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C62EFF95-5C32-435F-BD78-6977E828F894}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{223DBDB1-6CD3-4D4E-8795-42550BC0A871}.Debug|Any CPU.Build.0 = Debug|Any CPU {C62EFF95-5C32-435F-BD78-6977E828F894}.Debug|Any CPU.Build.0 = Debug|Any CPU
{223DBDB1-6CD3-4D4E-8795-42550BC0A871}.Release|Any CPU.ActiveCfg = Release|Any CPU {C62EFF95-5C32-435F-BD78-6977E828F894}.Release|Any CPU.ActiveCfg = Release|Any CPU
{223DBDB1-6CD3-4D4E-8795-42550BC0A871}.Release|Any CPU.Build.0 = Release|Any CPU {C62EFF95-5C32-435F-BD78-6977E828F894}.Release|Any CPU.Build.0 = Release|Any CPU
{FFA010F6-F33A-4705-8A42-B0FA3B3D2131}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {38C1808B-009A-418B-B17B-AB3626341B5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FFA010F6-F33A-4705-8A42-B0FA3B3D2131}.Debug|Any CPU.Build.0 = Debug|Any CPU {38C1808B-009A-418B-B17B-AB3626341B5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FFA010F6-F33A-4705-8A42-B0FA3B3D2131}.Release|Any CPU.ActiveCfg = Release|Any CPU {38C1808B-009A-418B-B17B-AB3626341B5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FFA010F6-F33A-4705-8A42-B0FA3B3D2131}.Release|Any CPU.Build.0 = Release|Any CPU {38C1808B-009A-418B-B17B-AB3626341B5D}.Release|Any CPU.Build.0 = Release|Any CPU
{6ED66F52-B4A0-403E-AE89-8E9A679C0885}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8BA01C3D-297D-42DF-BD63-EF07202A0A67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6ED66F52-B4A0-403E-AE89-8E9A679C0885}.Debug|Any CPU.Build.0 = Debug|Any CPU {8BA01C3D-297D-42DF-BD63-EF07202A0A67}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6ED66F52-B4A0-403E-AE89-8E9A679C0885}.Release|Any CPU.ActiveCfg = Release|Any CPU {8BA01C3D-297D-42DF-BD63-EF07202A0A67}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6ED66F52-B4A0-403E-AE89-8E9A679C0885}.Release|Any CPU.Build.0 = Release|Any CPU {8BA01C3D-297D-42DF-BD63-EF07202A0A67}.Release|Any CPU.Build.0 = Release|Any CPU
{2760AC98-D2FA-4074-8396-FAE10BE20A3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FE0457D9-4038-4A17-8808-DCAD06CFC0A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2760AC98-D2FA-4074-8396-FAE10BE20A3C}.Debug|Any CPU.Build.0 = Debug|Any CPU {FE0457D9-4038-4A17-8808-DCAD06CFC0A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2760AC98-D2FA-4074-8396-FAE10BE20A3C}.Release|Any CPU.ActiveCfg = Release|Any CPU {FE0457D9-4038-4A17-8808-DCAD06CFC0A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2760AC98-D2FA-4074-8396-FAE10BE20A3C}.Release|Any CPU.Build.0 = Release|Any CPU {FE0457D9-4038-4A17-8808-DCAD06CFC0A0}.Release|Any CPU.Build.0 = Release|Any CPU
{47B9A51B-70B5-42ED-A92A-FFEFB864CB14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47B9A51B-70B5-42ED-A92A-FFEFB864CB14}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47B9A51B-70B5-42ED-A92A-FFEFB864CB14}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47B9A51B-70B5-42ED-A92A-FFEFB864CB14}.Release|Any CPU.Build.0 = Release|Any CPU
{024086CC-49D0-436E-8B84-A67766A30CDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{024086CC-49D0-436E-8B84-A67766A30CDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{024086CC-49D0-436E-8B84-A67766A30CDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{024086CC-49D0-436E-8B84-A67766A30CDE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{F1360C93-5B6B-4E65-9D81-1DA38740F32D} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5} {D64C1577-4929-4B60-939E-96DE1534891A} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{40C4F834-3080-451B-9510-6FE7BC4F801F} = {B68027BA-BD9D-4110-A383-708B87BC425D} {F2840BC7-0188-4606-9126-DADD0F5ABF7A} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{B2C476F1-AE32-419D-BDA2-291FCE639CF6} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5} {BD65D04F-08D5-40C1-8C24-77CA0BACB877} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{4468B52D-3AAE-4918-B4D6-E6E8F000825D} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5} {78040F9E-3501-4A40-82DF-00A597710F35} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{1D3A5A4E-B977-4E33-A1AF-62508110C3B7} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5} {F1C58097-4C08-4D88-8976-6B3389391481} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{289196B4-FFBE-4E40-A3A1-FCFADBE945ED} = {43E8E19B-555A-4633-9926-B4F3C01D972A} {077AA5F8-8B61-420C-A6B5-0150A66FDB34} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{16D42BCF-EDB8-4153-B37D-0B10FB6DF36C} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5} {35829A15-4127-4F69-8BDE-9405DEAACA9A} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{DB46D90E-304D-48B7-9ED6-F4DCC95D3824} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5} {AD2F1928-4411-4511-B564-5FB996EC08B9} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{223DBDB1-6CD3-4D4E-8795-42550BC0A871} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5} {C62EFF95-5C32-435F-BD78-6977E828F894} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{FFA010F6-F33A-4705-8A42-B0FA3B3D2131} = {B68027BA-BD9D-4110-A383-708B87BC425D} {38C1808B-009A-418B-B17B-AB3626341B5D} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{6ED66F52-B4A0-403E-AE89-8E9A679C0885} = {3A04FB29-EA75-4499-BBF3-AF24C7D46A1D} {8BA01C3D-297D-42DF-BD63-EF07202A0A67} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{2760AC98-D2FA-4074-8396-FAE10BE20A3C} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5} {FE0457D9-4038-4A17-8808-DCAD06CFC0A0} = {649A3FFA-182F-4E56-9717-E6A9A2BEC545}
{47B9A51B-70B5-42ED-A92A-FFEFB864CB14} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5}
{024086CC-49D0-436E-8B84-A67766A30CDE} = {C7DEC9FB-3F75-4584-85B0-16EA3CB222E5}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {33261859-9CD1-4A43-B181-AB75C247D1CD} SolutionGuid = {4324B3B4-B60B-4E3C-91D8-59576B4E26DD}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

27
common.props Normal file
View File

@ -0,0 +1,27 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>1.0.0</Version>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<AbpProjectType>module</AbpProjectType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ConfigureAwait.Fody" Version="3.3.1" PrivateAssets="All" />
<PackageReference Include="Fody" Version="6.5.3">
<PrivateAssets>All</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<Target Name="NoWarnOnRazorViewImportedTypeConflicts" BeforeTargets="RazorCoreCompile">
<PropertyGroup>
<NoWarn>$(NoWarn);0436</NoWarn>
</PropertyGroup>
</Target>
<ItemGroup>
<Content Remove="$(UserProfile)\.nuget\packages\*\*\contentFiles\any\*\*.abppkg*" />
</ItemGroup>
</Project>

View File

@ -1,21 +0,0 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 10500
EXPOSE 443
ENV TZ=Asia/Shanghai
ENV ASPNETCORE_ENVIRONMENT=Production
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
WORKDIR "/src/JiShe.CollectBus.Console"
RUN dotnet build "JiShe.CollectBus.Console.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "JiShe.CollectBus.Console.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "JiShe.CollectBus.Console.dll"]

View File

@ -0,0 +1,32 @@
namespace JiShe.CollectBus;
/// <summary>
/// BaseResultDto
/// </summary>
/// <typeparam name="T"></typeparam>
public class BaseResultDto<T> where T : class
{
/// <summary>
/// Gets or sets a value indicating whether this <see cref="BaseResultDto{T}" /> is status.
/// </summary>
/// <value>
/// <c>true</c> if status; otherwise, <c>false</c>.
/// </value>
public bool Status { get; set; }
/// <summary>
/// Gets or sets the MSG.
/// </summary>
/// <value>
/// The MSG.
/// </value>
public string Msg { get; set; }
/// <summary>
/// Gets or sets the data.
/// </summary>
/// <value>
/// The data.
/// </value>
public T Data { get; set; }
}

View File

@ -0,0 +1,15 @@
using Volo.Abp.Application;
using Volo.Abp.Modularity;
using Volo.Abp.Authorization;
namespace JiShe.CollectBus;
[DependsOn(
typeof(CollectBusDomainSharedModule),
typeof(AbpDddApplicationContractsModule),
typeof(AbpAuthorizationModule)
)]
public class CollectBusApplicationContractsModule : AbpModule
{
}

View File

@ -0,0 +1,8 @@
namespace JiShe.CollectBus;
public class CollectBusRemoteServiceConsts
{
public const string RemoteServiceName = "CollectBus";
public const string ModuleName = "collectBus";
}

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.EnergySystem.Dto
{
/// <summary>
/// 阀控输入
/// </summary>
public class ValveControlInput
{
/// <summary>
/// 集中器区位码
/// </summary>
public string AreaCode { get; set; }
/// <summary>
/// 集中器地址
/// </summary>
public string Address { get; set; }
/// <summary>
/// 表号
/// </summary>
public int AmmeterId { get; set; }
/// <summary>
/// 0 合闸,开阀, 1 断开、跳闸,关阀
/// </summary>
public int TripState { get; set; }
/// <summary>
/// 采集端端口号
/// </summary>
public string GatherCode { get; set; }
/// <summary>
/// 表1水表2燃气表3热能表4 水表流量计5燃气表流量计6特殊电表7
/// </summary>
public int MeterType { get; set; }
}
}

View File

@ -0,0 +1,17 @@
namespace JiShe.CollectBus.EnergySystem.Dto
{
/// <summary>
/// 阀控输入
/// </summary>
public class ValveControlOutput
{
/// <summary>
/// true: 成功false失败
/// </summary>
public bool ValidData { get; set; }
/// <summary>
/// 备注(业务系统未使用)
/// </summary>
public string Remark { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System.Threading.Tasks;
using JiShe.CollectBus.EnergySystem.Dto;
using Volo.Abp.Application.Services;
namespace JiShe.CollectBus.EnergySystem;
public interface IEnergySystemAppService : IApplicationService
{
/// <summary>
/// 电表阀控、水表阀控
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
Task<BaseResultDto<ValveControlOutput>> ValveControl(ValveControlInput input);
}

View File

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

View File

@ -4,10 +4,9 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace JiShe.CollectBus.EntityFrameworkCore.Entities namespace JiShe.CollectBus
{ {
public interface IEntity<TKey> public interface ICollectWorker
{ {
TKey Id { get; }
} }
} }

View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>JiShe.CollectBus</RootNamespace>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<None Remove="FodyWeavers.xml" />
<None Remove="JiShe.CollectBus.Application.Contracts.abppkg" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="8.3.3" />
<PackageReference Include="Volo.Abp.Authorization" Version="8.3.3" />
<ProjectReference Include="..\JiShe.CollectBus.Domain.Shared\JiShe.CollectBus.Domain.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="新文件夹\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,3 @@
{
"role": "lib.application-contracts"
}

View File

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>JiShe.CollectBus</RootNamespace>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<None Remove="FodyWeavers.xml" />
<None Remove="JiShe.CollectBus.Application.Contracts.abppkg" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="8.3.3" />
<PackageReference Include="Volo.Abp.Authorization" Version="8.3.3" />
<ProjectReference Include="..\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.Domain.Shared\JiShe.CollectBus.Domain.Shared.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.Domain\JiShe.CollectBus.Domain.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,18 @@
using JiShe.CollectBus.Localization;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Localization;
namespace JiShe.CollectBus.Permissions;
public class CollectBusPermissionDefinitionProvider : PermissionDefinitionProvider
{
public override void Define(IPermissionDefinitionContext context)
{
var myGroup = context.AddGroup(CollectBusPermissions.GroupName, L("Permission:CollectBus"));
}
private static LocalizableString L(string name)
{
return LocalizableString.Create<CollectBusResource>(name);
}
}

View File

@ -0,0 +1,13 @@
using Volo.Abp.Reflection;
namespace JiShe.CollectBus.Permissions;
public class CollectBusPermissions
{
public const string GroupName = "CollectBus";
public static string[] GetAll()
{
return ReflectionHelper.GetPublicConstantsRecursively(typeof(CollectBusPermissions));
}
}

View File

@ -0,0 +1,11 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace JiShe.CollectBus.Samples;
public interface ISampleAppService : IApplicationService
{
Task<SampleDto> GetAsync();
Task<SampleDto> GetAuthorizedAsync();
}

View File

@ -0,0 +1,6 @@
namespace JiShe.CollectBus.Samples;
public class SampleDto
{
public int Value { get; set; }
}

View File

@ -0,0 +1,15 @@
using System.Threading.Tasks;
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.MessageReceiveds;
using Volo.Abp.Application.Services;
namespace JiShe.CollectBus.Subscribers
{
public interface ISubscriberAppService : IApplicationService
{
Task IssuedEvent(IssuedEventMessage issuedEventMessage);
Task ReceivedEvent(MessageReceived receivedMessage);
Task ReceivedHeartbeatEvent(MessageReceivedHeartbeat receivedHeartbeatMessage);
Task ReceivedLoginEvent(MessageReceivedLogin receivedLoginMessage);
}
}

View File

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.Ammeters
{
public class AmmeterInfo
{
public int ID { get; set; }
public string Name { get; set; }
public int FocusID { get; set; }
public string Address { get; set; }
public string AreaCode { get; set; }
/// <summary>
/// 电表类别 1单相、2三相三线、3三相四线,
/// 07协议 开合闸指令(1A开闸断电,1C单相表合闸,1B多相表合闸) 645 2007 表
/// 97协议//true(合闸);false(跳闸) 545 1997 没有单相多相 之分 "true" ? "9966" : "3355"
/// </summary>
public int TypeName { get; set; }
/// <summary>
/// 跳合闸状态字段: 0 合闸1 跳闸
/// 电表TripState 0 合闸-通电, 1 断开、跳闸);
/// </summary>
public int TripState { get; set; }
/// <summary>
/// 规约 -电表default(30) 197协议3007协议
/// </summary>
public int? Protocol { get; set; }
/// <summary>
/// 一个集中器下的[MeteringCode]必须唯一。 PN
/// </summary>
public int MeteringCode { get; set; }
/// <summary>
/// 电表通信地址
/// </summary>
public string AmmerterAddress { get; set; }
/// <summary>
/// 波特率 default(2400)
/// </summary>
public int Baudrate { get; set; }
/// <summary>
/// MeteringPort 端口就几个可以枚举。
/// </summary>
public int MeteringPort { get; set; }
/// <summary>
/// 电表密码
/// </summary>
public string Password { get; set; }
/// <summary>
/// 采集时间间隔(分钟如15)
/// </summary>
public int TimeDensity { get; set; }
/// <summary>
/// 该电表方案下采集项0D_80
/// </summary>
public string ItemCodes { get; set; }
/// <summary>
/// State表状态:
/// 0新装未下发1运行(档案下发成功时设置状态值1) 2暂停, 100销表销表后是否重新启用
/// 特定State -1 已删除
/// </summary>
public int State { get; set; }
/// <summary>
/// 是否自动采集(0:主动采集1自动采集)
/// </summary>
public int AutomaticReport { get; set; }
/// <summary>
/// 该电表方案下采集项编号
/// </summary>
public string DataTypes { get; set; }
/// <summary>
/// 品牌型号
/// </summary>
public string BrandType { get; set; }
/// <summary>
/// 采集器编号
/// </summary>
public string GatherCode { get; set; }
/// <summary>
/// 是否特殊表
/// </summary>
public int Special { get; set; }
/// <summary>
/// 费率类型,单、多 (SingleRate :单费率单相表1多费率其他0 与TypeName字段无关)
/// SingleRate ? "单" : "复"
/// [SingleRate] --0 复费率 false 1 单费率 true 与PayPlanID保持一致
///对应 TB_PayPlan.Type: 1复费率2单费率
/// </summary>
public bool SingleRate { get; set; }
public int ProjectID { get; set; }
/// <summary>
/// 是否异常集中器 0:正常1异常
/// </summary>
public int AbnormalState { get; set; }
public DateTime LastTime { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using JiShe.CollectBus.FreeSql;
using JiShe.CollectBus.Localization;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Application.Services;
namespace JiShe.CollectBus;
[ApiExplorerSettings(GroupName = CollectBusDomainSharedConsts.Business)]
public abstract class CollectBusAppService : ApplicationService
{
public IFreeSqlProvider SqlProvider => LazyServiceProvider.LazyGetRequiredService<IFreeSqlProvider>();
protected CollectBusAppService()
{
LocalizationResource = typeof(CollectBusResource);
ObjectMapperContext = typeof(CollectBusApplicationModule);
}
}

View File

@ -0,0 +1,13 @@
using AutoMapper;
namespace JiShe.CollectBus;
public class CollectBusApplicationAutoMapperProfile : Profile
{
public CollectBusApplicationAutoMapperProfile()
{
/* You can configure your AutoMapper mapping configuration here.
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */
}
}

View File

@ -0,0 +1,53 @@
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
using Volo.Abp.Application;
using Volo.Abp.BackgroundWorkers;
using System.Threading.Tasks;
using Volo.Abp;
using System.Reflection;
using JiShe.CollectBus.FreeSql;
using System;
using Volo.Abp.AspNetCore.Mvc.AntiForgery;
namespace JiShe.CollectBus;
[DependsOn(
typeof(CollectBusDomainModule),
typeof(CollectBusApplicationContractsModule),
typeof(AbpDddApplicationModule),
typeof(AbpAutoMapperModule),
typeof(AbpBackgroundWorkersModule),
typeof(CollectBusFreeSqlModule)
)]
public class CollectBusApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<CollectBusApplicationModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<CollectBusApplicationModule>(validate: true);
});
Configure<AbpAntiForgeryOptions>(options =>
{
options.TokenCookie.Expiration = TimeSpan.FromDays(365);
options.AutoValidateIgnoredHttpMethods.Add("POST");
});
}
public override async Task OnApplicationInitializationAsync(
ApplicationInitializationContext context)
{
var assembly = Assembly.GetExecutingAssembly();
var types = assembly.GetTypes().Where(t => typeof(ICollectWorker).IsAssignableFrom(t) && !t.IsInterface).ToList();
foreach (var type in types)
{
await context.AddBackgroundWorkerAsync(type);
}
}
}

View File

@ -0,0 +1,64 @@
using System;
using System.Threading.Tasks;
using JiShe.CollectBus.Common.Enums;
using JiShe.CollectBus.MessageIssueds;
using JiShe.CollectBus.MessageReceiveds;
using MassTransit;
using Microsoft.Extensions.Logging;
using TouchSocket.Sockets;
using Volo.Abp.Domain.Repositories;
namespace JiShe.CollectBus.Consumers
{
public class IssuedConsumer: IConsumer<MessageIssued>
{
private readonly ILogger<ReceivedHeartbeatConsumer> _logger;
private readonly ITcpService _tcpService;
private readonly IRepository<MessageReceivedLogin, Guid> _messageReceivedLoginEventRepository;
private readonly IRepository<MessageReceivedHeartbeat, Guid> _messageReceivedHeartbeatEventRepository;
/// <summary>
/// IssuedConsumer
/// </summary>
/// <param name="logger"></param>
/// <param name="tcpService"></param>
/// <param name="messageReceivedLoginEventRepository"></param>
/// <param name="messageReceivedHeartbeatEventRepository"></param>
public IssuedConsumer(ILogger<ReceivedHeartbeatConsumer> logger,
ITcpService tcpService,
IRepository<MessageReceivedLogin, Guid> messageReceivedLoginEventRepository,
IRepository<MessageReceivedHeartbeat, Guid> messageReceivedHeartbeatEventRepository)
{
_logger = logger;
_tcpService = tcpService;
_messageReceivedLoginEventRepository = messageReceivedLoginEventRepository;
_messageReceivedHeartbeatEventRepository = messageReceivedHeartbeatEventRepository;
}
public async Task Consume(ConsumeContext<MessageIssued> context)
{
switch (context.Message.Type)
{
case IssuedEventType.Heartbeat:
_logger.LogInformation($"IssuedEvent:{context.Message.MessageId}");
var heartbeatEntity = await _messageReceivedHeartbeatEventRepository.GetAsync(a => a.MessageId == context.Message.MessageId);
heartbeatEntity.AckTime = DateTime.Now;
heartbeatEntity.IsAck = true;
await _messageReceivedHeartbeatEventRepository.UpdateAsync(heartbeatEntity);
break;
case IssuedEventType.Login:
var loginEntity = await _messageReceivedLoginEventRepository.GetAsync(a => a.MessageId == context.Message.MessageId);
loginEntity.AckTime = DateTime.Now;
loginEntity.IsAck = true;
await _messageReceivedLoginEventRepository.UpdateAsync(loginEntity);
break;
case IssuedEventType.Data:
break;
default:
throw new ArgumentOutOfRangeException();
}
await _tcpService.SendAsync(context.Message.ClientId, context.Message.Message);
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Threading.Tasks;
using JiShe.CollectBus.MessageIssueds;
using MassTransit;
namespace JiShe.CollectBus.Consumers
{
public class IssuedFaultConsumer : IConsumer<Fault<MessageIssued>>
{
public Task Consume(ConsumeContext<Fault<MessageIssued>> context)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using JiShe.CollectBus.MessageReceiveds;
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Volo.Abp.Domain.Repositories;
namespace JiShe.CollectBus.Consumers
{
/// <summary>
/// Batch 一次最多 100 个,最多 10 个并发批次
/// </summary>
public class ReceivedConsumer: IConsumer<Batch<MessageReceived>>
{
private readonly ILogger<ReceivedConsumer> _logger;
private readonly IServiceProvider _serviceProvider;
private readonly IRepository<MessageReceived, Guid> _messageReceivedEventRepository;
/// <summary>
/// MessageReceivedConsumer
/// </summary>
/// <param name="logger"></param>
/// <param name="serviceProvider"></param>
/// <param name="messageReceivedEventRepository"></param>
public ReceivedConsumer(ILogger<ReceivedConsumer> logger,
IServiceProvider serviceProvider,
IRepository<MessageReceived, Guid> messageReceivedEventRepository)
{
_logger = logger;
_serviceProvider = serviceProvider;
_messageReceivedEventRepository = messageReceivedEventRepository;
}
public async Task Consume(ConsumeContext<Batch<MessageReceived>> context)
{
const string protocolType = "Standard";
var protocolPlugin = _serviceProvider.GetKeyedService<IProtocolPlugin>(protocolType);
if (protocolPlugin == null)
{
_logger.LogError("协议不存在!");
}
else
{
var list = new List<MessageReceived>();
foreach (var contextItem in context.Message)
{
await protocolPlugin.AnalyzeAsync(contextItem.Message);
list.Add(contextItem.Message);
}
await _messageReceivedEventRepository.InsertManyAsync(list);
}
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Threading.Tasks;
using JiShe.CollectBus.MessageReceiveds;
using MassTransit;
namespace JiShe.CollectBus.Consumers
{
public class ReceivedFaultConsumer: IConsumer<Fault<Batch<MessageReceived>>>
{
public Task Consume(ConsumeContext<Fault<Batch<MessageReceived>>> context)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.MessageReceiveds;
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace JiShe.CollectBus.Consumers
{
public class ReceivedHeartbeatConsumer:IConsumer<MessageReceivedHeartbeat>
{
private readonly ILogger<ReceivedHeartbeatConsumer> _logger;
private readonly IServiceProvider _serviceProvider;
/// <summary>
///
/// </summary>
/// <param name="serviceProvider"></param>
/// <param name="logger"></param>
public ReceivedHeartbeatConsumer(IServiceProvider serviceProvider, ILogger<ReceivedHeartbeatConsumer> logger)
{
this._serviceProvider = serviceProvider;
this._logger = logger;
}
public async Task Consume(ConsumeContext<MessageReceivedHeartbeat> context)
{
_logger.LogInformation("心跳消费队列开始处理");
var protocolPlugin = _serviceProvider.GetKeyedService<IProtocolPlugin>("Standard");
if (protocolPlugin == null)
{
_logger.LogError("【心跳消费队列开始处理】协议不存在!");
}
else
{
await protocolPlugin.HeartbeatAsync(context.Message);
_logger.LogInformation("心跳消费队列完成处理");
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More