Compare commits

..

No commits in common. "c972c6a8bf66849c7c897e43690ff6eaefacac7c" and "6e98f5d4a907175afd7d3945f2fea7173ecb0225" have entirely different histories.

5 changed files with 79 additions and 4526 deletions

View File

@ -31,11 +31,6 @@ namespace JiShe.IoT.BusinessSystemAggregation
ServerApplicationOptions serverOptions = options.Value; ServerApplicationOptions serverOptions = options.Value;
IoTDBOptions ioTDBOptions = _ioTDBOptions.Value; IoTDBOptions ioTDBOptions = _ioTDBOptions.Value;
private const string LUA_SCRIPT = @"
local hashKey = KEYS[1]
local fieldKeys = ARGV
return redis.call('HMGET', hashKey, unpack(fieldKeys))";
/// <summary> /// <summary>
/// 接收业务系统指令信息 /// 接收业务系统指令信息
/// </summary> /// </summary>
@ -123,14 +118,9 @@ namespace JiShe.IoT.BusinessSystemAggregation
return HttpDataResultExtensions.Success("指令下发成功"); return HttpDataResultExtensions.Success("指令下发成功");
} }
catch (UserFriendlyException)
{
throw; // 重新抛出用户友好异常
}
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "接收业务系统指令信息时发生异常"); return HttpDataResultExtensions.Failed($"指令处理失败,发送异常:{ex.Message}", -106);
return HttpDataResultExtensions.Failed("指令处理失败,发送异常", -106);
} }
} }
@ -157,19 +147,16 @@ namespace JiShe.IoT.BusinessSystemAggregation
return HttpDataResultExtensions.Failed<List<IoTDBDynamicObject>>(null, "设备地址不能为空", -103); return HttpDataResultExtensions.Failed<List<IoTDBDynamicObject>>(null, "设备地址不能为空", -103);
} }
// 验证设备地址格式,防止注入攻击 // Lua脚本
foreach (var deviceAddress in messageBody.DeviceAddresses) string luaScript = @"
{ local hashKey = KEYS[1]
if (!IsValidDeviceAddress(deviceAddress)) local fieldKeys = ARGV
{ return redis.call('HMGET', hashKey, unpack(fieldKeys))";
return HttpDataResultExtensions.Failed<List<IoTDBDynamicObject>>(null, $"设备地址格式不正确: {deviceAddress}", -107);
}
}
//执行脚本 //执行脚本
var result = await FreeRedisProvider.Instance.EvalAsync var result = await FreeRedisProvider.Instance.EvalAsync
( (
LUA_SCRIPT, luaScript,
new[] { RedisConst.CacheAllDeviceInfoHashKey }, new[] { RedisConst.CacheAllDeviceInfoHashKey },
messageBody.DeviceAddresses.ToArray() messageBody.DeviceAddresses.ToArray()
); );
@ -180,24 +167,16 @@ namespace JiShe.IoT.BusinessSystemAggregation
if (result is object[] values) if (result is object[] values)
{ {
foreach (var value in values) foreach (var value in values)
{
if (value != null)
{ {
var tempFocusInfo = ServiceProJsonSerializer.Deserialize<DeviceCacheInfos>(value as string); var tempFocusInfo = ServiceProJsonSerializer.Deserialize<DeviceCacheInfos>(value as string);
deviceCacheInfos.Add(tempFocusInfo); deviceCacheInfos.Add(tempFocusInfo);
} }
else
{
deviceCacheInfos.Add(null); // 添加空值以保持索引对应
}
}
} }
List<IoTDBDynamicObject> queryResult = new List<IoTDBDynamicObject>(); List<IoTDBDynamicObject> queryResult = new List<IoTDBDynamicObject>();
for (int i = 0; i < messageBody.DeviceAddresses.Count; i++) foreach (var deviceAddress in messageBody.DeviceAddresses)
{ {
var deviceAddress = messageBody.DeviceAddresses[i]; var deviceCacheInfo = deviceCacheInfos.FirstOrDefault(x => x.DeviceAddress == deviceAddress);
var deviceCacheInfo = deviceCacheInfos.Count > i ? deviceCacheInfos[i] : null;
if (deviceCacheInfo == null) if (deviceCacheInfo == null)
{ {
@ -228,8 +207,8 @@ namespace JiShe.IoT.BusinessSystemAggregation
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "批量查询设备数据时发生异常");
return HttpDataResultExtensions.Failed<List<IoTDBDynamicObject>>(null, "查询设备数据失败", -106); return HttpDataResultExtensions.Failed<List<IoTDBDynamicObject>>(null, $"查询设备数据失败,发送异常:{ex.Message}", -106);
} }
} }
@ -256,16 +235,16 @@ namespace JiShe.IoT.BusinessSystemAggregation
return HttpDataResultExtensions.Failed<List<IoTDBDynamicObject>>(null, "设备地址不能为空", -103); return HttpDataResultExtensions.Failed<List<IoTDBDynamicObject>>(null, "设备地址不能为空", -103);
} }
// 验证设备地址格式,防止注入攻击 // Lua脚本
if (!IsValidDeviceAddress(messageBody.DeviceAddress)) string luaScript = @"
{ local hashKey = KEYS[1]
return HttpDataResultExtensions.Failed<List<IoTDBDynamicObject>>(null, $"设备地址格式不正确: {messageBody.DeviceAddress}", -107); local fieldKeys = ARGV
} return redis.call('HMGET', hashKey, unpack(fieldKeys))";
//执行脚本 //执行脚本
var result = await FreeRedisProvider.Instance.EvalAsync var result = await FreeRedisProvider.Instance.EvalAsync
( (
LUA_SCRIPT, luaScript,
new[] { RedisConst.CacheAllDeviceInfoHashKey }, new[] { RedisConst.CacheAllDeviceInfoHashKey },
new List<string>() { messageBody.DeviceAddress }.ToArray() new List<string>() { messageBody.DeviceAddress }.ToArray()
); );
@ -276,26 +255,18 @@ namespace JiShe.IoT.BusinessSystemAggregation
if (result is object[] values) if (result is object[] values)
{ {
foreach (var value in values) foreach (var value in values)
{
if (value != null)
{ {
var tempFocusInfo = ServiceProJsonSerializer.Deserialize<DeviceCacheInfos>(value as string); var tempFocusInfo = ServiceProJsonSerializer.Deserialize<DeviceCacheInfos>(value as string);
deviceCacheInfos.Add(tempFocusInfo); deviceCacheInfos.Add(tempFocusInfo);
} }
else
{
deviceCacheInfos.Add(null);
}
}
} }
List<IoTDBDynamicObject> queryResult = new List<IoTDBDynamicObject>(); List<IoTDBDynamicObject> queryResult = new List<IoTDBDynamicObject>();
var deviceCacheInfo = deviceCacheInfos.FirstOrDefault(); var deviceCacheInfo = deviceCacheInfos.FirstOrDefault(x => x.DeviceAddress == messageBody.DeviceAddress);
if (deviceCacheInfo == null) if (deviceCacheInfo == null)
{ {
_logger.LogError($"{nameof(QueryDeviceDataInfoAsync)} 业务系统单个查询设备数据,设备地址:{messageBody.DeviceAddress}未找到设备地址缓存信息,消息体为:{input.Serialize()}"); _logger.LogError($"{nameof(BatchQueryDeviceDataInfoAsync)} 业务系统单个查询设备数据,设备地址:{messageBody.DeviceAddress}未找到设备地址缓存信息,消息体为:{input.Serialize()}");
return HttpDataResultExtensions.Failed<List<IoTDBDynamicObject>>(null, "设备信息不存在", -108);
} }
var pageResult = await treeModelService.OpenRequestDeviceDataInfoPageAsync(new DeviceTreeModelDataInfoInput() var pageResult = await treeModelService.OpenRequestDeviceDataInfoPageAsync(new DeviceTreeModelDataInfoInput()
@ -321,8 +292,8 @@ namespace JiShe.IoT.BusinessSystemAggregation
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "查询单个设备数据时发生异常");
return HttpDataResultExtensions.Failed<List<IoTDBDynamicObject>>(null, "查询设备数据失败", -106); return HttpDataResultExtensions.Failed<List<IoTDBDynamicObject>>(null, $"查询设备数据失败,发送异常:{ex.Message}", -106);
} }
} }
@ -363,26 +334,8 @@ namespace JiShe.IoT.BusinessSystemAggregation
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "批量新增设备数据时发生异常"); return HttpDataResultExtensions.Failed($"查询设备数据失败,发送异常:{ex.Message}", -106);
return HttpDataResultExtensions.Failed("新增设备失败", -106);
} }
} }
/// <summary>
/// 验证设备地址格式是否合法
/// </summary>
/// <param name="deviceAddress">设备地址</param>
/// <returns>是否合法</returns>
private bool IsValidDeviceAddress(string deviceAddress)
{
if (string.IsNullOrWhiteSpace(deviceAddress))
return false;
// 可根据实际业务规则调整验证逻辑
// 这里简单检查是否包含非法字符
return !deviceAddress.Contains("..") &&
!deviceAddress.Contains("*") &&
!deviceAddress.Contains("~");
}
} }
} }

View File

@ -24,7 +24,6 @@ using Microsoft.Extensions.Options;
using StackExchange.Redis; using StackExchange.Redis;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Content; using Volo.Abp.Content;
using static FreeSql.Internal.GlobalFilter;
namespace JiShe.IoT.DeviceAggregation namespace JiShe.IoT.DeviceAggregation
{ {
@ -277,10 +276,8 @@ namespace JiShe.IoT.DeviceAggregation
UpdateDeviceInput updateDeviceInput = input.Adapt<UpdateDeviceInput>(); UpdateDeviceInput updateDeviceInput = input.Adapt<UpdateDeviceInput>();
updateDeviceInput.IoTPlatformResponse = pushResult.Serialize(); updateDeviceInput.IoTPlatformResponse = pushResult.Serialize();
updateDeviceInput.IsPlatformPushSuccess = true; updateDeviceInput.IsPlatformPushSuccess = true;
if (!string.IsNullOrWhiteSpace(updateDeviceInput.PlatformPassword))
{
updateDeviceInput.PlatformPassword = platformPassword; updateDeviceInput.PlatformPassword = platformPassword;
}
var updateResult = await deviceAppService.UpdateAsync(updateDeviceInput); var updateResult = await deviceAppService.UpdateAsync(updateDeviceInput);
if (updateResult == null) if (updateResult == null)
@ -802,29 +799,28 @@ namespace JiShe.IoT.DeviceAggregation
IoTPlatformProductId = input.IoTPlatformProductId, IoTPlatformProductId = input.IoTPlatformProductId,
}); });
foreach (var item in input.DeviceInfos) foreach (var item in input.AddressList)
{ {
if (checkDevicesInfos != null) if (checkDevicesInfos != null)
{ {
if (checkDevicesInfos.Any(e => e.DeviceAddress == item))
var checkDevices = checkDevicesInfos.Where(e => e.DeviceAddress == item.DeviceAddress).FirstOrDefault();
if (checkDevices != null && checkDevices.IsPlatformPushSuccess)
{ {
logger.LogError($"{nameof(OneNETDeviceBatchCreateAsync)} 平台{input.IoTPlatform} 产品 {input.IoTPlatformProductId} 下设备信息已存在:{item.DeviceAddress}"); logger.LogError($"{nameof(OneNETDeviceBatchCreateAsync)} 平台{input.IoTPlatform} 产品 {input.IoTPlatformProductId} 下设备信息已存在:{item}");
continue; continue;
} }
} }
CreateDeviceInput createDeviceInput = input.Adapt<CreateDeviceInput>(); CreateDeviceInput createDeviceInput = input.Adapt<CreateDeviceInput>();
createDeviceInput.DeviceName = item.DeviceAddress; createDeviceInput.DeviceName = item;
createDeviceInput.DeviceAddress = item.DeviceAddress; createDeviceInput.DeviceAddress = item;
createDeviceInput.IoTPlatformAccountId = productInfo.OneNETAccountId; createDeviceInput.IoTPlatformAccountId = productInfo.OneNETAccountId;
createDeviceInput.IoTPlatformDeviceOpenInfo = $"{input.IoTPlatformProductId}{item.DeviceAddress}"; createDeviceInput.IoTPlatformDeviceOpenInfo = $"{input.IoTPlatformProductId}{item}";
createDeviceInput.PlatformPassword = productInfo.ProductAccesskey; createDeviceInput.PlatformPassword = productInfo.ProductAccesskey;
createDeviceInput.IoTPlatformProductName = productInfo.ProductName; createDeviceInput.IoTPlatformProductName = productInfo.ProductName;
createDeviceInput.AccountPhoneNumber = productInfo.AccountPhoneNumber; createDeviceInput.AccountPhoneNumber = productInfo.AccountPhoneNumber;
createDeviceInput.DeviceSourceType = input.DeviceSourceType.Value;
createDeviceInput.DeviceType = input.DeviceType.Value;
if (input.DeviceSourceType.HasValue) if (input.DeviceSourceType.HasValue)
{ {
@ -836,26 +832,18 @@ namespace JiShe.IoT.DeviceAggregation
createDeviceInput.DeviceType = input.DeviceType.Value; createDeviceInput.DeviceType = input.DeviceType.Value;
} }
if (item.BusinessSystemDeviceDataId.HasValue)
{
createDeviceInput.BusinessSystemDeviceDataId = item.BusinessSystemDeviceDataId.Value;
}
batchCreateDeviceInput.DeviceInputs.Add(createDeviceInput); batchCreateDeviceInput.DeviceInputs.Add(createDeviceInput);
} }
if (batchCreateDeviceInput.DeviceInputs != null || batchCreateDeviceInput.DeviceInputs.Count > 0)
{
var insertResult = await deviceAppService.BatchCreateAsync(batchCreateDeviceInput); var insertResult = await deviceAppService.BatchCreateAsync(batchCreateDeviceInput);
if (insertResult == null) if (insertResult == null)
{ {
logger.LogError($"{nameof(OneNETDeviceBatchCreateAsync)} OneNET设备批量创建添加设备信息失败{input.Serialize()}"); logger.LogError($"{nameof(OneNETDeviceBatchCreateAsync)} OneNET设备批量创建添加设备信息失败{input.Serialize()}");
return false; return false;
} }
//网关或者直连设备 推送至OneNET平台
//推送至OneNET平台
var oneNETBatchCreateDeviceInfoInput = new BatchCreateDeviceInfoInput() var oneNETBatchCreateDeviceInfoInput = new BatchCreateDeviceInfoInput()
{ {
ProductId = productInfo.IoTPlatformProductId, ProductId = productInfo.IoTPlatformProductId,
@ -882,9 +870,6 @@ namespace JiShe.IoT.DeviceAggregation
await DeviceUpdateHandler(item, HttpDataResultExtensions.Success(successEntity), successEntity.SecurityKey); await DeviceUpdateHandler(item, HttpDataResultExtensions.Success(successEntity), successEntity.SecurityKey);
} }
} }
}
//暂不考虑子设备地址信息,由网关设备主动上报
return true; return true;
} }
@ -1143,36 +1128,6 @@ namespace JiShe.IoT.DeviceAggregation
upgradeRecordInput.UpgradeMessage = upgradeRequest.Serialize(); upgradeRecordInput.UpgradeMessage = upgradeRequest.Serialize();
upgradeRecordInput.FirmwareSignature = upgradeRequest.SignatureValue; upgradeRecordInput.FirmwareSignature = upgradeRequest.SignatureValue;
string upgradeMessageHexString = upgradeRecordInput.UpgradeMessage.ToHexString();
//检查长度是否超过了OneNET平台升级属性标识符的长度限制
var thingModelInfoStr = ((OneNETProductInfos)productInfo).ThingModelInfos;
if (string.IsNullOrWhiteSpace(thingModelInfoStr))
{
logger.LogError($"{nameof(DeviceUpgradeCommandToOneNET)} 通过OneNET产品ID和属性标识符获取属性配置信息失败属性信息为空");
return false;
}
var thingModelInfo = thingModelInfoStr.Deserialize<OneNETAllThingModel>();
if (thingModelInfo.Properties == null)
{
logger.LogError($"{nameof(DeviceUpgradeCommandToOneNET)} 通过OneNET产品ID和属性标识符获取属性配置信息失败属性信息为空");
return false;
}
var property = thingModelInfo.Properties.Where(d => d.Identifier == upgradeProperty.IoTPlatformRawFieldName).FirstOrDefault(); //精准匹配
if (property == null)
{
logger.LogError($"{nameof(DeviceUpgradeCommandToOneNET)} 通过OneNET产品ID和属性标识符获取属性配置信息失败没有找到属性标识升级对应的属性平台信息");
return false;
}
var length = ((OneNETModelStringSpecs)property.DataType.Specs).Length;
if (upgradeMessageHexString.Length > length)
{
throw new UserFriendlyException($"设备{deviceInfo.DeviceAddress}平台端物模型信息属性标识符{upgradeProperty.IoTPlatformRawFieldName}长度超过OneNET平台限制请检查物模型属性标识符长度是否超过了{length}");
}
var insertResult = await deviceUpgradeRecordService.CreateAsync(upgradeRecordInput); var insertResult = await deviceUpgradeRecordService.CreateAsync(upgradeRecordInput);
if (insertResult == null) if (insertResult == null)
@ -1183,7 +1138,7 @@ namespace JiShe.IoT.DeviceAggregation
//发送OneNET平台设备升级指令HEX格式字符串 //发送OneNET平台设备升级指令HEX格式字符串
taskInput.Commands = new Dictionary<string, object>() taskInput.Commands = new Dictionary<string, object>()
{ {
{ upgradeProperty.IoTPlatformRawFieldName, upgradeMessageHexString } { upgradeProperty.IoTPlatformRawFieldName, upgradeRecordInput.UpgradeMessage.ToHexString() }
}; };
var commandRequest = new OpenApiRequest() var commandRequest = new OpenApiRequest()

View File

@ -1,74 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace JiShe.IoT.Migrations
{
/// <inheritdoc />
public partial class updatetable202601201031 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "BusinessSystemSubDeviceDataId",
table: "ServiceProSubDeviceManagementInfo");
migrationBuilder.DropColumn(
name: "BusinessSystemDeviceDataId",
table: "ServiceProDeviceInfo");
migrationBuilder.AlterTable(
name: "ServiceProSubDeviceManagementInfo",
comment: "子设备信息,需要下发配置的网关设备才用到",
oldComment: "子设备信息");
migrationBuilder.AddColumn<bool>(
name: "IsSynced",
table: "ServiceProSubDeviceManagementInfo",
type: "boolean",
nullable: false,
defaultValue: false,
comment: "是否同步");
migrationBuilder.AddColumn<int>(
name: "SubDeviceCapacity",
table: "ServiceProDeviceInfo",
type: "integer",
nullable: false,
defaultValue: 64,
comment: "子设备容量");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsSynced",
table: "ServiceProSubDeviceManagementInfo");
migrationBuilder.DropColumn(
name: "SubDeviceCapacity",
table: "ServiceProDeviceInfo");
migrationBuilder.AlterTable(
name: "ServiceProSubDeviceManagementInfo",
comment: "子设备信息",
oldComment: "子设备信息,需要下发配置的网关设备才用到");
migrationBuilder.AddColumn<long>(
name: "BusinessSystemSubDeviceDataId",
table: "ServiceProSubDeviceManagementInfo",
type: "bigint",
nullable: true,
comment: "业务系统子设备数据Id");
migrationBuilder.AddColumn<long>(
name: "BusinessSystemDeviceDataId",
table: "ServiceProDeviceInfo",
type: "bigint",
nullable: true,
comment: "业务系统设备数据Id");
}
}
}

View File

@ -695,6 +695,10 @@ namespace JiShe.IoT.Migrations
.HasColumnType("character varying(50)") .HasColumnType("character varying(50)")
.HasComment("账户手机号"); .HasComment("账户手机号");
b.Property<long?>("BusinessSystemDeviceDataId")
.HasColumnType("bigint")
.HasComment("业务系统设备数据Id");
b.Property<string>("ConcurrencyStamp") b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken() .IsConcurrencyToken()
.IsRequired() .IsRequired()
@ -840,12 +844,6 @@ namespace JiShe.IoT.Migrations
.HasColumnType("text") .HasColumnType("text")
.HasComment("备注"); .HasComment("备注");
b.Property<int>("SubDeviceCapacity")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(64)
.HasComment("子设备容量");
b.Property<Guid?>("TenantId") b.Property<Guid?>("TenantId")
.HasColumnType("uuid") .HasColumnType("uuid")
.HasColumnName("TenantId") .HasColumnName("TenantId")
@ -1023,6 +1021,10 @@ namespace JiShe.IoT.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uuid"); .HasColumnType("uuid");
b.Property<long?>("BusinessSystemSubDeviceDataId")
.HasColumnType("bigint")
.HasComment("业务系统子设备数据Id");
b.Property<string>("ConcurrencyStamp") b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken() .IsConcurrencyToken()
.IsRequired() .IsRequired()
@ -1067,10 +1069,6 @@ namespace JiShe.IoT.Migrations
.HasDefaultValue(false) .HasDefaultValue(false)
.HasColumnName("IsDeleted"); .HasColumnName("IsDeleted");
b.Property<bool>("IsSynced")
.HasColumnType("boolean")
.HasComment("是否同步");
b.Property<DateTime?>("LastModificationTime") b.Property<DateTime?>("LastModificationTime")
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("LastModificationTime"); .HasColumnName("LastModificationTime");
@ -1137,7 +1135,7 @@ namespace JiShe.IoT.Migrations
b.ToTable("ServiceProSubDeviceManagementInfo", null, t => b.ToTable("ServiceProSubDeviceManagementInfo", null, t =>
{ {
t.HasComment("子设备信息,需要下发配置的网关设备才用到"); t.HasComment("子设备信息");
}); });
}); });