update V 2.4.3.0
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
File diff suppressed because one or more lines are too long
@@ -4,11 +4,11 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Common.Net" Version="2.4.2" />
|
||||
<PackageReference Include="Common.Net" Version="2.4.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Common.Net" Version="2.4.2" />
|
||||
<PackageReference Include="Common.Net" Version="2.4.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
+2
-2
@@ -4,11 +4,11 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Common.Net" Version="2.4.2" />
|
||||
<PackageReference Include="Common.Net" Version="2.4.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
+2
-2
@@ -4,11 +4,11 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Common.Net" Version="2.4.2" />
|
||||
<PackageReference Include="Common.Net" Version="2.4.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
+2
-2
@@ -4,11 +4,11 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Common.Net" Version="2.4.2" />
|
||||
<PackageReference Include="Common.Net" Version="2.4.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
+2
-2
@@ -4,11 +4,11 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Common.Net" Version="2.4.2" />
|
||||
<PackageReference Include="Common.Net" Version="2.4.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Common.Net" Version="2.4.2" />
|
||||
<PackageReference Include="Common.Net" Version="2.4.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Common.Device" Version="2.4.2" />
|
||||
<PackageReference Include="Common.Device" Version="2.4.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Common.Device" Version="2.4.2" />
|
||||
<PackageReference Include="Common.Device" Version="2.4.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -5,19 +5,19 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<CETCompat>false</CETCompat>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
<AssemblyName>FASS.Scheduler</AssemblyName>
|
||||
<ApplicationIcon>Resources\App.ico</ApplicationIcon>
|
||||
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FASS.Boot" Version="2.4.2" />
|
||||
<PackageReference Include="FASS.Boot" Version="2.4.3" />
|
||||
<PackageReference Include="Grpc.AspNetCore" Version="2.80.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.10" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,6 +2,7 @@ using Common.NETCore;
|
||||
using Common.NETCore.Extensions;
|
||||
using Common.NETCore.Helpers;
|
||||
using Common.NETCore.Timing;
|
||||
using Common.Service.Helpers;
|
||||
using FASS.Boot.Services;
|
||||
using FASS.Core.Services.Data;
|
||||
using FASS.Data.Consts.Data;
|
||||
@@ -26,19 +27,9 @@ public sealed class RemoteService : Remote.RemoteBase
|
||||
private readonly Func<string?, string> _carStateName;
|
||||
private readonly Func<string?, string> _alarmLevelName;
|
||||
private readonly object _snapshotCacheLock = new();
|
||||
private SnapshotCacheEntry? _snapshotCache;
|
||||
|
||||
private readonly record struct SnapshotCacheKey(long DataVersion, int AlarmLimit);
|
||||
private sealed class SnapshotCacheEntry
|
||||
{
|
||||
internal SnapshotCacheEntry(SnapshotCacheKey key, RuntimeSnapshotReply reply)
|
||||
{
|
||||
Key = key;
|
||||
Reply = reply;
|
||||
}
|
||||
internal SnapshotCacheKey Key { get; }
|
||||
internal RuntimeSnapshotReply Reply { get; }
|
||||
}
|
||||
private long _snapshotCacheVersion;
|
||||
private int _snapshotCacheAlarmLimit;
|
||||
private RuntimeSnapshotReply? _snapshotCacheReply;
|
||||
|
||||
public RemoteService(
|
||||
ILogger<RemoteService> logger,
|
||||
@@ -149,17 +140,8 @@ public sealed class RemoteService : Remote.RemoteBase
|
||||
|
||||
private static List<T> ReadList<T>(string json) => Guard.NotNull(json.JsonTo<List<T>>());
|
||||
|
||||
private static string[] ToArrayOrEmpty(List<string> items) => items.Count == 0 ? Array.Empty<string>() : items.ToArray();
|
||||
|
||||
private static CancellationToken GetToken(ServerCallContext? context) => context?.CancellationToken ?? CancellationToken.None;
|
||||
|
||||
private static RuntimeSnapshotReply CreateFailedSnapshotReply(string message) => new()
|
||||
{
|
||||
Success = false,
|
||||
Message = message,
|
||||
Time = Clock.Now.ToMillisecondString()
|
||||
};
|
||||
|
||||
public override Task<ResponseReply> CarAdd(CarAddRequest request, ServerCallContext context) =>
|
||||
ReplyDtoAsync<CarDto>(nameof(CarAdd), request.Dto, _bootService.CarAddAsync, context);
|
||||
|
||||
@@ -265,8 +247,8 @@ public sealed class RemoteService : Remote.RemoteBase
|
||||
priority,
|
||||
isBreak,
|
||||
isPreempt,
|
||||
ToArrayOrEmpty(nodes),
|
||||
ToArrayOrEmpty(edges),
|
||||
nodes.Count == 0 ? Array.Empty<string>() : nodes.ToArray(),
|
||||
edges.Count == 0 ? Array.Empty<string>() : edges.ToArray(),
|
||||
token);
|
||||
},
|
||||
context);
|
||||
@@ -323,7 +305,7 @@ public sealed class RemoteService : Remote.RemoteBase
|
||||
watch.ElapsedMilliseconds,
|
||||
reply.Cars.Count,
|
||||
reply.Maps.Count,
|
||||
reply.Alarms.Count);
|
||||
reply.Alarms.Count);
|
||||
}
|
||||
|
||||
DebugHelper.ThrowIfCancellationRequested(cancellationToken);
|
||||
@@ -336,7 +318,12 @@ public sealed class RemoteService : Remote.RemoteBase
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "获取运行时快照失败。");
|
||||
return Task.FromResult(CreateFailedSnapshotReply(ex.Message));
|
||||
return Task.FromResult(new RuntimeSnapshotReply
|
||||
{
|
||||
Success = false,
|
||||
Message = ex.Message,
|
||||
Time = Clock.Now.ToMillisecondString()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,19 +331,22 @@ public sealed class RemoteService : Remote.RemoteBase
|
||||
{
|
||||
DebugHelper.ThrowIfCancellationRequested(cancellationToken);
|
||||
|
||||
var cacheKey = new SnapshotCacheKey(snapshot.Version, alarmLimit);
|
||||
lock (_snapshotCacheLock)
|
||||
{
|
||||
if (_snapshotCache is { } cacheEntry && cacheEntry.Key == cacheKey)
|
||||
if (_snapshotCacheReply is not null
|
||||
&& _snapshotCacheVersion == snapshot.Version
|
||||
&& _snapshotCacheAlarmLimit == alarmLimit)
|
||||
{
|
||||
return cacheEntry.Reply;
|
||||
return _snapshotCacheReply;
|
||||
}
|
||||
}
|
||||
|
||||
var reply = BuildSnapshotReplyCore(snapshot.Version, snapshot.EnabledCars, alarmLimit, cancellationToken);
|
||||
lock (_snapshotCacheLock)
|
||||
{
|
||||
_snapshotCache = new SnapshotCacheEntry(cacheKey, reply);
|
||||
_snapshotCacheVersion = snapshot.Version;
|
||||
_snapshotCacheAlarmLimit = alarmLimit;
|
||||
_snapshotCacheReply = reply;
|
||||
}
|
||||
|
||||
return reply;
|
||||
@@ -365,15 +355,13 @@ public sealed class RemoteService : Remote.RemoteBase
|
||||
private RuntimeSnapshotReply BuildSnapshotReplyCore(long version, IReadOnlyList<Car> cars, int alarmLimit, CancellationToken cancellationToken)
|
||||
{
|
||||
var reply = CreateRuntimeSnapshotReply(version);
|
||||
var orderedCars = RuntimeSnapshotProjection.OrderCars(cars);
|
||||
var runtimeCars = RuntimeSnapshotProjection.ToRuntimeCars(orderedCars, ResolveCarState);
|
||||
var runtimeMaps = RuntimeSnapshotProjection.ToRuntimeMaps(orderedCars);
|
||||
var runtimeAlarms = RuntimeSnapshotProjection.SelectLatestCarAlarms(orderedCars, alarmLimit, _alarmLevelName);
|
||||
for (var i = 0; i < runtimeCars.Count; i++)
|
||||
var projectedCars = RuntimeSnapshotProjection.ProjectCars(cars, ResolveCarState);
|
||||
var runtimeAlarms = RuntimeSnapshotProjection.SelectLatestCarAlarms(projectedCars.OrderedCars, alarmLimit, _alarmLevelName);
|
||||
for (var i = 0; i < projectedCars.Cars.Count; i++)
|
||||
{
|
||||
DebugHelper.ThrowIfCancellationRequested(cancellationToken);
|
||||
reply.Cars.Add(CreateRuntimeSnapshotCar(runtimeCars[i]));
|
||||
reply.Maps.Add(CreateRuntimeSnapshotMap(runtimeMaps[i]));
|
||||
reply.Cars.Add(CreateRuntimeSnapshotCar(projectedCars.Cars[i]));
|
||||
reply.Maps.Add(CreateRuntimeSnapshotMap(projectedCars.Maps[i]));
|
||||
}
|
||||
|
||||
for (var i = 0; i < runtimeAlarms.Count; i++)
|
||||
@@ -483,7 +471,9 @@ public sealed class RemoteService : Remote.RemoteBase
|
||||
{
|
||||
return new RuntimeSnapshotAlarm
|
||||
{
|
||||
Key = alarm.Key ?? RuntimeSnapshotProjection.BuildRuntimeAlarmStateKey(alarm),
|
||||
Key = string.IsNullOrWhiteSpace(alarm.Key)
|
||||
? RecordStateKeyHelper.Build(alarm.Level, alarm.Type, alarm.Code, alarm.State)
|
||||
: alarm.Key,
|
||||
Id = alarm.Id ?? string.Empty,
|
||||
Level = alarm.Level ?? string.Empty,
|
||||
Type = alarm.Type,
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FASS.Data" Version="2.4.2" />
|
||||
<PackageReference Include="FASS.Data" Version="2.4.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -8,6 +8,11 @@ namespace FASS.Service.Runtime.Helpers;
|
||||
|
||||
public static class RuntimeSnapshotProjection
|
||||
{
|
||||
public readonly record struct ProjectedCars(
|
||||
IReadOnlyList<DataCar> OrderedCars,
|
||||
IReadOnlyList<RuntimeModel.Car> Cars,
|
||||
IReadOnlyList<RuntimeModel.Map> Maps);
|
||||
|
||||
public static string? NormalizeAlarmLevelCode(string? value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
@@ -42,7 +47,7 @@ public static class RuntimeSnapshotProjection
|
||||
return stateNameResolver(currState);
|
||||
}
|
||||
|
||||
public static int CompareCarCode(string? left, string? right)
|
||||
private static int CompareCarCode(string? left, string? right)
|
||||
{
|
||||
var normalizedLeft = left ?? string.Empty;
|
||||
var normalizedRight = right ?? string.Empty;
|
||||
@@ -50,11 +55,16 @@ public static class RuntimeSnapshotProjection
|
||||
return byLength != 0 ? byLength : string.CompareOrdinal(normalizedLeft, normalizedRight);
|
||||
}
|
||||
|
||||
public static List<DataCar> OrderCars(IEnumerable<DataCar> cars)
|
||||
public static ProjectedCars ProjectCars(
|
||||
IEnumerable<DataCar> cars,
|
||||
Func<bool, bool, string?, string> carStateResolver)
|
||||
{
|
||||
var ordered = cars.ToList();
|
||||
ordered.Sort(static (left, right) => CompareCarCode(left.Code, right.Code));
|
||||
return ordered;
|
||||
var orderedCars = cars.ToList();
|
||||
orderedCars.Sort(static (left, right) => CompareCarCode(left.Code, right.Code));
|
||||
return new ProjectedCars(
|
||||
orderedCars,
|
||||
ToRuntimeCars(orderedCars, carStateResolver),
|
||||
ToRuntimeMaps(orderedCars));
|
||||
}
|
||||
|
||||
public static IReadOnlyList<RuntimeModel.Car> ToRuntimeCars(
|
||||
@@ -99,16 +109,18 @@ public static class RuntimeSnapshotProjection
|
||||
for (var i = 0; i < cars.Count; i++)
|
||||
{
|
||||
var car = cars[i];
|
||||
var edgeCount = car.CarEdges.Count;
|
||||
var nodeCount = car.CarNodes.Count;
|
||||
var routeSignature = car.RouteSignature != 0 || (car.CarEdges.Count == 0 && car.CarNodes.Count == 0)
|
||||
var carEdges = car.CarEdges;
|
||||
var carNodes = car.CarNodes;
|
||||
var edgeCount = carEdges.Count;
|
||||
var nodeCount = carNodes.Count;
|
||||
var routeSignature = car.RouteSignature != 0 || (edgeCount == 0 && nodeCount == 0)
|
||||
? car.RouteSignature
|
||||
: DataCar.BuildRouteSignature(car.CarNodes, car.CarEdges);
|
||||
: DataCar.BuildRouteSignature(carNodes, carEdges);
|
||||
result[i] = new RuntimeModel.Map
|
||||
{
|
||||
Type = Normalize(car.CarType?.Code),
|
||||
RouteSignature = routeSignature,
|
||||
HasRouteTopology = car.CarEdges.Count > 0 || car.CarNodes.Count > 0,
|
||||
HasRouteTopology = edgeCount > 0 || nodeCount > 0,
|
||||
Code = new RuntimeModel.Code
|
||||
{
|
||||
Text = car.Code
|
||||
@@ -145,7 +157,7 @@ public static class RuntimeSnapshotProjection
|
||||
var runtimeEdges = runtimeBase.CarEdges;
|
||||
for (var j = 0; j < edgeCount; j++)
|
||||
{
|
||||
var edge = car.CarEdges[j];
|
||||
var edge = carEdges[j];
|
||||
runtimeEdges.Add(new RuntimeModel.CarEdge
|
||||
{
|
||||
Id = NormalizeRuntimeId(edge.EdgeId),
|
||||
@@ -163,7 +175,7 @@ public static class RuntimeSnapshotProjection
|
||||
var runtimeNodes = runtimeBase.CarNodes;
|
||||
for (var j = 0; j < nodeCount; j++)
|
||||
{
|
||||
var node = car.CarNodes[j];
|
||||
var node = carNodes[j];
|
||||
runtimeNodes.Add(new RuntimeModel.CarNode
|
||||
{
|
||||
Id = NormalizeRuntimeId(node.NodeId),
|
||||
@@ -190,21 +202,23 @@ public static class RuntimeSnapshotProjection
|
||||
for (var i = 0; i < alarms.Count; i++)
|
||||
{
|
||||
var alarm = alarms[i];
|
||||
var level = NormalizeAlarmLevelCode(alarm.Level);
|
||||
level = levelResolver(level);
|
||||
|
||||
var key = RecordStateKeyHelper.Build(level, alarm.Type, alarm.Code, alarm.State);
|
||||
var runtimeAlarm = CreateRuntimeAlarm(
|
||||
key,
|
||||
alarm.Id,
|
||||
levelResolver(NormalizeAlarmLevelCode(alarm.Level)),
|
||||
level,
|
||||
alarm.Type,
|
||||
alarm.Code,
|
||||
alarm.State,
|
||||
alarm.Message,
|
||||
alarm.Data);
|
||||
var key = BuildRuntimeAlarmStateKey(runtimeAlarm);
|
||||
if (deduplicated.ContainsKey(key))
|
||||
if (!deduplicated.TryAdd(key, runtimeAlarm))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
deduplicated[key] = runtimeAlarm;
|
||||
if (deduplicated.Count >= alarmLimit)
|
||||
{
|
||||
break;
|
||||
@@ -216,17 +230,6 @@ public static class RuntimeSnapshotProjection
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string BuildRuntimeAlarmStateKey(
|
||||
AlarmDto alarm,
|
||||
Func<string?, string> levelResolver)
|
||||
{
|
||||
return RecordStateKeyHelper.Build(
|
||||
levelResolver(NormalizeAlarmLevelCode(alarm.Level)),
|
||||
alarm.Type,
|
||||
alarm.Code,
|
||||
alarm.State);
|
||||
}
|
||||
|
||||
public static int CompareRuntimeAlarms(RuntimeModel.Alarm? left, RuntimeModel.Alarm? right)
|
||||
{
|
||||
return RuntimeAlarmOrdering.Compare(
|
||||
@@ -240,16 +243,6 @@ public static class RuntimeSnapshotProjection
|
||||
right?.State);
|
||||
}
|
||||
|
||||
public static string BuildRuntimeAlarmStateKey(RuntimeModel.Alarm? alarm)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(alarm?.Key))
|
||||
{
|
||||
return alarm.Key;
|
||||
}
|
||||
|
||||
return RecordStateKeyHelper.Build(alarm?.Level, alarm?.Type, alarm?.Code, alarm?.State);
|
||||
}
|
||||
|
||||
public static void SortRuntimeAlarms(RuntimeModel.Alarm[] alarms)
|
||||
{
|
||||
if (alarms.Length <= 1)
|
||||
@@ -282,11 +275,17 @@ public static class RuntimeSnapshotProjection
|
||||
continue;
|
||||
}
|
||||
|
||||
var level = NormalizeAlarmLevelCode(alarm.Level);
|
||||
if (levelResolver is not null)
|
||||
{
|
||||
level = levelResolver(level);
|
||||
}
|
||||
|
||||
var key = RecordStateKeyHelper.Build(level, alarm.Type, alarm.Code, alarm.State);
|
||||
var runtimeAlarm = CreateRuntimeAlarm(
|
||||
key,
|
||||
alarm.Id,
|
||||
levelResolver is null
|
||||
? NormalizeAlarmLevelCode(alarm.Level)
|
||||
: levelResolver(NormalizeAlarmLevelCode(alarm.Level)),
|
||||
level,
|
||||
alarm.Type,
|
||||
alarm.Code,
|
||||
alarm.State,
|
||||
@@ -315,6 +314,7 @@ public static class RuntimeSnapshotProjection
|
||||
public static string? Normalize(string? value) => string.IsNullOrWhiteSpace(value) ? null : value;
|
||||
|
||||
private static RuntimeModel.Alarm CreateRuntimeAlarm(
|
||||
string key,
|
||||
string? id,
|
||||
string? level,
|
||||
string type,
|
||||
@@ -325,7 +325,7 @@ public static class RuntimeSnapshotProjection
|
||||
{
|
||||
return new RuntimeModel.Alarm
|
||||
{
|
||||
Key = RecordStateKeyHelper.Build(level, type, code, state),
|
||||
Key = key,
|
||||
Id = id ?? string.Empty,
|
||||
Level = level ?? string.Empty,
|
||||
Type = type,
|
||||
@@ -341,7 +341,9 @@ public static class RuntimeSnapshotProjection
|
||||
RuntimeModel.Alarm alarm,
|
||||
long createdAtTicks)
|
||||
{
|
||||
var stateKey = BuildRuntimeAlarmStateKey(alarm);
|
||||
var stateKey = string.IsNullOrWhiteSpace(alarm.Key)
|
||||
? RecordStateKeyHelper.Build(alarm.Level, alarm.Type, alarm.Code, alarm.State)
|
||||
: alarm.Key;
|
||||
var priority = new AlarmPriority(
|
||||
createdAtTicks,
|
||||
alarm.Level ?? string.Empty,
|
||||
|
||||
@@ -35,13 +35,6 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
IReadOnlyList<RuntimeModel.Alarm> Alarms,
|
||||
DateTime SnapshotAt);
|
||||
|
||||
private readonly record struct SnapshotPayload(
|
||||
long Version,
|
||||
string Time,
|
||||
IReadOnlyList<RuntimeModel.Car> Cars,
|
||||
IReadOnlyList<RuntimeModel.Map> Maps,
|
||||
IReadOnlyList<RuntimeModel.Alarm> Alarms);
|
||||
|
||||
private readonly record struct SnapshotBuildResult(
|
||||
RuntimeModel.Snapshot Snapshot,
|
||||
long AlarmRevision);
|
||||
@@ -113,6 +106,7 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
private long _sendCount;
|
||||
private long _dropped;
|
||||
private long _sent;
|
||||
private long _sendFailed;
|
||||
private long _version;
|
||||
private long _lastVersion;
|
||||
private DbSnapshot _db = new(0, [], [], [], DateTime.MinValue);
|
||||
@@ -170,9 +164,10 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
Task<RuntimeModel.Snapshot> snapshotTask;
|
||||
lock (_snapshotLock)
|
||||
{
|
||||
if (TryGetCachedNoLock(out var cached))
|
||||
var cache = _snapshotCache;
|
||||
if (cache.Snapshot is not null && Clock.UtcNow - cache.CachedAt <= _cacheInterval)
|
||||
{
|
||||
return Task.FromResult(cached);
|
||||
return Task.FromResult(cache.Snapshot);
|
||||
}
|
||||
|
||||
snapshotTask = _inFlight ??= LoadSnapshotAsync();
|
||||
@@ -272,7 +267,18 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
if (!IsStopped)
|
||||
{
|
||||
SetStopped(true);
|
||||
await EnqueueUpdateAsync(CreateIdleSnapshot(), cancellationToken);
|
||||
await EnqueueUpdateAsync(new RuntimeModel.Snapshot
|
||||
{
|
||||
IsRunning = IsRunning,
|
||||
Version = NextUpdateVersion(),
|
||||
Time = Clock.Now.ToMillisecondString(),
|
||||
Cars = [],
|
||||
Maps = [],
|
||||
Alarms = [],
|
||||
DataSource = IdleSource,
|
||||
IsDegraded = false,
|
||||
DataAgeMs = 0
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -310,9 +316,11 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
{
|
||||
Interlocked.Exchange(ref _queued, 0);
|
||||
var watch = Stopwatch.StartNew();
|
||||
var sent = false;
|
||||
try
|
||||
{
|
||||
await _publish(snapshot, cancellationToken);
|
||||
sent = true;
|
||||
}
|
||||
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -320,8 +328,8 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Interlocked.Increment(ref _sendFailed);
|
||||
_log.LogWarning(ex, "运行监控推送失败。");
|
||||
continue;
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -329,7 +337,6 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
}
|
||||
|
||||
RecordSendCost(watch.ElapsedMilliseconds);
|
||||
Interlocked.Increment(ref _sent);
|
||||
if (watch.ElapsedMilliseconds > _sendThresholdMs)
|
||||
{
|
||||
_log.LogWarning(
|
||||
@@ -337,6 +344,11 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
watch.ElapsedMilliseconds,
|
||||
_sendThresholdMs);
|
||||
}
|
||||
|
||||
if (sent)
|
||||
{
|
||||
Interlocked.Increment(ref _sent);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
||||
@@ -390,7 +402,17 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
return ApplyAlarmPresentationPolicy(BuildDbModeSnapshot(cancellationToken));
|
||||
}
|
||||
|
||||
if (TryTakePendingMemory(out var pending))
|
||||
RuntimeModel.Snapshot? pending;
|
||||
lock (_snapshotLock)
|
||||
{
|
||||
pending = _mode.PendingMemorySnapshot;
|
||||
if (pending is not null)
|
||||
{
|
||||
_mode = _mode with { PendingMemorySnapshot = null };
|
||||
}
|
||||
}
|
||||
|
||||
if (pending is not null)
|
||||
{
|
||||
return ApplyAlarmPresentationPolicy(CompleteMemorySnapshot(pending, 0));
|
||||
}
|
||||
@@ -427,7 +449,11 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
}
|
||||
|
||||
return CreateRuntimeSnapshot(
|
||||
CreateSnapshotPayload(snapshot),
|
||||
snapshot.Version,
|
||||
snapshot.SnapshotAt == DateTime.MinValue ? Clock.Now.ToMillisecondString() : snapshot.SnapshotAt.ToMillisecondString(),
|
||||
snapshot.Cars,
|
||||
snapshot.Maps,
|
||||
snapshot.Alarms,
|
||||
DatabaseSource,
|
||||
isDegraded: true,
|
||||
dataAgeMs: GetDataAgeMs(snapshot.SnapshotAt));
|
||||
@@ -461,7 +487,15 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
}
|
||||
|
||||
private RuntimeModel.Snapshot CompleteMemorySnapshot(RuntimeModel.Snapshot snapshot, long dataAgeMs) =>
|
||||
CreateRuntimeSnapshot(CreateSnapshotPayload(snapshot), MemorySource, isDegraded: false, dataAgeMs);
|
||||
CreateRuntimeSnapshot(
|
||||
snapshot.Version,
|
||||
string.IsNullOrWhiteSpace(snapshot.Time) ? Clock.Now.ToMillisecondString() : snapshot.Time,
|
||||
snapshot.Cars,
|
||||
snapshot.Maps,
|
||||
snapshot.Alarms,
|
||||
MemorySource,
|
||||
isDegraded: false,
|
||||
dataAgeMs: dataAgeMs);
|
||||
|
||||
private RuntimeModel.Snapshot BuildMemoryFailureSnapshot(string reason, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -494,19 +528,17 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
var carService = scope.ServiceProvider.GetRequiredService<ICarService>();
|
||||
var alarmService = scope.ServiceProvider.GetRequiredService<IAlarmService>();
|
||||
|
||||
var cars = RuntimeSnapshotProjection.OrderCars(carService.GetRuntime(car => car.IsEnable));
|
||||
var projectedCars = RuntimeSnapshotProjection.ProjectCars(carService.LoadRuntime(car => car.IsEnable), ResolveCarState);
|
||||
var enabledCarCodes = new HashSet<string>(StringComparer.Ordinal);
|
||||
for (var i = 0; i < cars.Count; i++)
|
||||
for (var i = 0; i < projectedCars.OrderedCars.Count; i++)
|
||||
{
|
||||
var code = cars[i].Code;
|
||||
var code = projectedCars.OrderedCars[i].Code;
|
||||
if (!string.IsNullOrWhiteSpace(code))
|
||||
{
|
||||
enabledCarCodes.Add(code);
|
||||
}
|
||||
}
|
||||
var alarmDtos = LoadDbAlarms(alarmService, enabledCarCodes);
|
||||
var runtimeCars = RuntimeSnapshotProjection.ToRuntimeCars(cars, ResolveCarState);
|
||||
var runtimeMaps = RuntimeSnapshotProjection.ToRuntimeMaps(cars);
|
||||
var runtimeAlarms = RuntimeSnapshotProjection.ToRuntimeAlarms(
|
||||
alarmDtos,
|
||||
value => ResolveNamedValue(_alarmLevels, value),
|
||||
@@ -516,8 +548,8 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
{
|
||||
_db = new DbSnapshot(
|
||||
NextUpdateVersion(),
|
||||
runtimeCars,
|
||||
runtimeMaps,
|
||||
projectedCars.Cars,
|
||||
projectedCars.Maps,
|
||||
runtimeAlarms,
|
||||
now);
|
||||
}
|
||||
@@ -533,64 +565,30 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private RuntimeModel.Snapshot CreateIdleSnapshot() => new()
|
||||
{
|
||||
IsRunning = IsRunning,
|
||||
Version = NextUpdateVersion(),
|
||||
Time = Clock.Now.ToMillisecondString(),
|
||||
Cars = [],
|
||||
Maps = [],
|
||||
Alarms = [],
|
||||
DataSource = IdleSource,
|
||||
IsDegraded = false,
|
||||
DataAgeMs = 0
|
||||
};
|
||||
|
||||
private RuntimeModel.Snapshot CreateRuntimeSnapshot(SnapshotPayload payload, string dataSource, bool isDegraded, long dataAgeMs)
|
||||
private RuntimeModel.Snapshot CreateRuntimeSnapshot(
|
||||
long version,
|
||||
string time,
|
||||
IReadOnlyList<RuntimeModel.Car> cars,
|
||||
IReadOnlyList<RuntimeModel.Map> maps,
|
||||
IReadOnlyList<RuntimeModel.Alarm> alarms,
|
||||
string dataSource,
|
||||
bool isDegraded,
|
||||
long dataAgeMs)
|
||||
{
|
||||
return new RuntimeModel.Snapshot
|
||||
{
|
||||
IsRunning = IsRunning,
|
||||
Version = payload.Version,
|
||||
Time = payload.Time,
|
||||
Cars = payload.Cars,
|
||||
Maps = payload.Maps,
|
||||
Alarms = payload.Alarms,
|
||||
Version = version,
|
||||
Time = time,
|
||||
Cars = cars,
|
||||
Maps = maps,
|
||||
Alarms = alarms,
|
||||
DataSource = dataSource,
|
||||
IsDegraded = isDegraded,
|
||||
DataAgeMs = dataAgeMs
|
||||
};
|
||||
}
|
||||
|
||||
private bool TryGetCachedNoLock(out RuntimeModel.Snapshot snapshot)
|
||||
{
|
||||
var cache = _snapshotCache;
|
||||
if (cache.Snapshot is not null && Clock.UtcNow - cache.CachedAt <= _cacheInterval)
|
||||
{
|
||||
snapshot = cache.Snapshot;
|
||||
return true;
|
||||
}
|
||||
|
||||
snapshot = null!;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryTakePendingMemory(out RuntimeModel.Snapshot snapshot)
|
||||
{
|
||||
lock (_snapshotLock)
|
||||
{
|
||||
if (_mode.PendingMemorySnapshot is not null)
|
||||
{
|
||||
snapshot = _mode.PendingMemorySnapshot;
|
||||
_mode = _mode with { PendingMemorySnapshot = null };
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
snapshot = null!;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void RefreshRunState()
|
||||
{
|
||||
var shouldRun = Volatile.Read(ref _subscribers) > 0;
|
||||
@@ -656,7 +654,7 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
RuntimeMode.Database,
|
||||
nextDatabaseRefreshAt: DateTime.MinValue);
|
||||
|
||||
_log.LogWarning("监控已切换为数据库降级模式,原因:{Reason}", NormalizeSwitchReason(reason));
|
||||
_log.LogWarning("监控已切换为数据库降级模式,原因:{Reason}", string.IsNullOrWhiteSpace(reason) ? "实时服务不可用。" : reason);
|
||||
}
|
||||
|
||||
private void ApplyRuntimeModeTransition(
|
||||
@@ -712,22 +710,6 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
_inFlight = null;
|
||||
}
|
||||
|
||||
private static SnapshotPayload CreateSnapshotPayload(RuntimeModel.Snapshot snapshot) =>
|
||||
new(
|
||||
snapshot.Version,
|
||||
string.IsNullOrWhiteSpace(snapshot.Time) ? Clock.Now.ToMillisecondString() : snapshot.Time,
|
||||
snapshot.Cars,
|
||||
snapshot.Maps,
|
||||
snapshot.Alarms);
|
||||
|
||||
private static SnapshotPayload CreateSnapshotPayload(DbSnapshot snapshot) =>
|
||||
new(
|
||||
snapshot.Version,
|
||||
snapshot.SnapshotAt == DateTime.MinValue ? Clock.Now.ToMillisecondString() : snapshot.SnapshotAt.ToMillisecondString(),
|
||||
snapshot.Cars,
|
||||
snapshot.Maps,
|
||||
snapshot.Alarms);
|
||||
|
||||
private SnapshotBuildResult ApplyAlarmPresentationPolicy(RuntimeModel.Snapshot snapshot)
|
||||
{
|
||||
var incomingAlarms = snapshot.Alarms ?? [];
|
||||
@@ -863,9 +845,6 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private static string NormalizeSwitchReason(string reason) =>
|
||||
string.IsNullOrWhiteSpace(reason) ? "实时服务不可用。" : reason;
|
||||
|
||||
private static Dictionary<string, string> BuildDictNameMap(IReadOnlyList<DictItemDto> items, string dictCode)
|
||||
{
|
||||
if (items.Count == 0)
|
||||
@@ -969,8 +948,10 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
&& Math.Max(0, sourceSnapshot.Version) == cache.SourceVersion
|
||||
&& alarmRevision == cache.AlarmRevision
|
||||
&& string.Equals(sourceSnapshot.DataSource ?? string.Empty, cache.Snapshot.DataSource ?? string.Empty, StringComparison.Ordinal)
|
||||
&& string.Equals(sourceSnapshot.Time ?? string.Empty, cache.Snapshot.Time ?? string.Empty, StringComparison.Ordinal)
|
||||
&& sourceSnapshot.IsRunning == cache.Snapshot.IsRunning
|
||||
&& sourceSnapshot.IsDegraded == cache.Snapshot.IsDegraded;
|
||||
&& sourceSnapshot.IsDegraded == cache.Snapshot.IsDegraded
|
||||
&& sourceSnapshot.DataAgeMs == cache.Snapshot.DataAgeMs;
|
||||
}
|
||||
|
||||
private RuntimeMode GetRuntimeMode()
|
||||
@@ -1036,8 +1017,9 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
var sendTotal = Interlocked.Exchange(ref _sendMs, 0);
|
||||
var dropped = Interlocked.Exchange(ref _dropped, 0);
|
||||
var sent = Interlocked.Exchange(ref _sent, 0);
|
||||
var sendFailed = Interlocked.Exchange(ref _sendFailed, 0);
|
||||
|
||||
if (updateCount == 0 && sendCount == 0 && dropped == 0 && sent == 0)
|
||||
if (updateCount == 0 && sendCount == 0 && dropped == 0 && sent == 0 && sendFailed == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1045,13 +1027,14 @@ internal sealed class MonitorService : IAsyncDisposable
|
||||
var updateAvg = updateCount == 0 ? 0 : Math.Round((double)updateTotal / updateCount, 2);
|
||||
var sendAvg = sendCount == 0 ? 0 : Math.Round((double)sendTotal / sendCount, 2);
|
||||
_log.LogInformation(
|
||||
"监控心跳:间隔[{HeartDueTime}ms] 更新均耗[{UpdateAvg}ms] 更新样本[{UpdateCount}] 推送均耗[{SendAvg}ms] 推送样本[{SendCount}] 已推送[{Sent}] 丢帧[{Dropped}]。",
|
||||
"监控心跳:间隔[{HeartDueTime}ms] 更新均耗[{UpdateAvg}ms] 更新样本[{UpdateCount}] 推送均耗[{SendAvg}ms] 推送样本[{SendCount}] 已推送[{Sent}] 推送失败[{SendFailed}] 丢帧[{Dropped}]。",
|
||||
(int)_probeInterval.TotalMilliseconds,
|
||||
updateAvg,
|
||||
updateCount,
|
||||
sendAvg,
|
||||
sendCount,
|
||||
sent,
|
||||
sendFailed,
|
||||
dropped);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UseWPF>true</UseWPF>
|
||||
<CETCompat>false</CETCompat>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
<AssemblyName>FASS.Simulator</AssemblyName>
|
||||
<ApplicationIcon>Assets\App.ico</ApplicationIcon>
|
||||
<InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration</InterceptorsNamespaces>
|
||||
@@ -15,11 +15,11 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Common.WindowsDesktop" Version="2.4.2" />
|
||||
<PackageReference Include="Common.WindowsDesktop" Version="2.4.3" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="10.0.10" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.10" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.10" />
|
||||
<PackageReference Include="OxyPlot.Wpf" Version="2.2.0" />
|
||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="10.0.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="10.0.1" />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Common.NETCore.Timing;
|
||||
using Common.WindowsDesktop.Consts;
|
||||
using FASS.Simulator.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
@@ -237,7 +238,7 @@ namespace FASS.Simulator.Models.Message
|
||||
}
|
||||
|
||||
var pending = Math.Max(0, Volatile.Read(ref _pendingCount));
|
||||
var notice = $"[ {DateTime.Now.ToString(TimestampFormat)} ]=>[ {_resumeNoticeLabel}:暂停期间丢弃 {dropped} 条日志,待显示日志 {pending} 条 ]";
|
||||
var notice = $"[ {Clock.Now.ToString(TimestampFormat)} ]=>[ {_resumeNoticeLabel}:暂停期间丢弃 {dropped} 条日志,待显示日志 {pending} 条 ]";
|
||||
if (_resumeNoticeIncludeDisplayedStats)
|
||||
{
|
||||
var displayed = _dispatcher.CheckAccess() ? _target.Count : _dispatcher.Invoke(() => _target.Count);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using Common.NETCore.Timing;
|
||||
|
||||
namespace FASS.Simulator.Models
|
||||
{
|
||||
public enum SimulatorSessionType
|
||||
@@ -43,7 +45,7 @@ namespace FASS.Simulator.Models
|
||||
|
||||
public SimulatorRuntimeSnapshot GetSnapshot()
|
||||
{
|
||||
var nowTicks = DateTime.UtcNow.Ticks;
|
||||
var nowTicks = Clock.UtcNow.Ticks;
|
||||
var nextRefreshUtcTicks = Volatile.Read(ref _nextRefreshUtcTicks);
|
||||
if (nowTicks < nextRefreshUtcTicks)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Common.NETCore.Timing;
|
||||
using Quartz;
|
||||
|
||||
namespace FASS.Simulator.Services.CronTasks.Jobs
|
||||
@@ -14,7 +15,7 @@ namespace FASS.Simulator.Services.CronTasks.Jobs
|
||||
|
||||
public Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
Logger.LogInformation("当前时间:[{DateTimeNow}]", DateTime.Now);
|
||||
Logger.LogInformation("当前时间:[{DateTimeNow}]", Clock.Now);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Common.NETCore.Timing;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace FASS.Simulator.Services.Sessions
|
||||
@@ -85,7 +86,7 @@ namespace FASS.Simulator.Services.Sessions
|
||||
var interval = NormalizeTick(_tickProvider());
|
||||
await Task.Delay(interval, cancellationToken);
|
||||
|
||||
var utcNow = DateTime.UtcNow;
|
||||
var utcNow = Clock.UtcNow;
|
||||
foreach (var session in worker.Sessions.Keys)
|
||||
{
|
||||
if (session.SessionIsClosed)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Common.NETCore.Timing;
|
||||
using Common.WindowsDesktop.Consts;
|
||||
using Common.WindowsDesktop.Enums;
|
||||
using FASS.Simulator.Models.Message;
|
||||
@@ -117,7 +118,7 @@ namespace FASS.Simulator.Utility
|
||||
|
||||
private static Task AddMessageInternal(string message, Brush brush, Action<MessageItem> action, bool includeTimestamp)
|
||||
{
|
||||
var text = includeTimestamp ? $"[ {DateTime.Now.ToString(TimestampFormat)} ]=>[ {message} ]" : message;
|
||||
var text = includeTimestamp ? $"[ {Clock.Now.ToString(TimestampFormat)} ]=>[ {message} ]" : message;
|
||||
action(new MessageItem(text, brush));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Common.NETCore.Extensions;
|
||||
using Common.NETCore.Helpers;
|
||||
using Common.NETCore.Timing;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using FASS.Extend.Car.Fairyland.Pcb;
|
||||
using FASS.Simulator.Models;
|
||||
@@ -82,8 +83,8 @@ namespace FASS.Simulator.ViewModels.Pages.Car.Fairyland.Pcb
|
||||
FullMode = BoundedChannelFullMode.DropWrite,
|
||||
AllowSynchronousContinuations = false
|
||||
});
|
||||
_nextKeepaliveUtc = DateTime.UtcNow;
|
||||
_nextReconnectUtc = DateTime.UtcNow;
|
||||
_nextKeepaliveUtc = Clock.UtcNow;
|
||||
_nextReconnectUtc = Clock.UtcNow;
|
||||
}
|
||||
|
||||
public int SessionShardKey => Model?.Car ?? 0;
|
||||
@@ -635,13 +636,13 @@ namespace FASS.Simulator.ViewModels.Pages.Car.Fairyland.Pcb
|
||||
|
||||
if (command.Command != SessionCommand.Receive)
|
||||
{
|
||||
HandleCommand(command, DateTime.UtcNow);
|
||||
HandleCommand(command, Clock.UtcNow);
|
||||
return true;
|
||||
}
|
||||
|
||||
var dropped = Interlocked.Increment(ref _commandDropCount);
|
||||
_runtimeTuning.RecordCommandDrop(SimulatorSessionType.Pcb);
|
||||
var nowUtcTicks = DateTime.UtcNow.Ticks;
|
||||
var nowUtcTicks = Clock.UtcNow.Ticks;
|
||||
var intervalTicks = TimeSpan.FromMilliseconds(_runtimeTuning.GetSnapshot().CommandDropLogIntervalMilliseconds).Ticks;
|
||||
var lastUtcTicks = Volatile.Read(ref _lastCommandDropLogUtcTicks);
|
||||
if (nowUtcTicks - lastUtcTicks >= intervalTicks &&
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Common.NETCore.Extensions;
|
||||
using Common.NETCore.Helpers;
|
||||
using Common.NETCore.Timing;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using FASS.Extend.Car.Fairyland.Plc;
|
||||
using FASS.Simulator.Models;
|
||||
@@ -80,7 +81,7 @@ namespace FASS.Simulator.ViewModels.Pages.Car.Fairyland.Plc
|
||||
FullMode = BoundedChannelFullMode.DropWrite,
|
||||
AllowSynchronousContinuations = false
|
||||
});
|
||||
_nextReconnectUtc = DateTime.UtcNow;
|
||||
_nextReconnectUtc = Clock.UtcNow;
|
||||
}
|
||||
|
||||
public int SessionShardKey => Model?.Car ?? 0;
|
||||
@@ -630,13 +631,13 @@ namespace FASS.Simulator.ViewModels.Pages.Car.Fairyland.Plc
|
||||
|
||||
if (command.Command != SessionCommand.Receive)
|
||||
{
|
||||
HandleCommand(command, DateTime.UtcNow);
|
||||
HandleCommand(command, Clock.UtcNow);
|
||||
return true;
|
||||
}
|
||||
|
||||
var dropped = Interlocked.Increment(ref _commandDropCount);
|
||||
_runtimeTuning.RecordCommandDrop(SimulatorSessionType.Plc);
|
||||
var nowUtcTicks = DateTime.UtcNow.Ticks;
|
||||
var nowUtcTicks = Clock.UtcNow.Ticks;
|
||||
var intervalTicks = TimeSpan.FromMilliseconds(_runtimeTuning.GetSnapshot().CommandDropLogIntervalMilliseconds).Ticks;
|
||||
var lastUtcTicks = Volatile.Read(ref _lastCommandDropLogUtcTicks);
|
||||
if (nowUtcTicks - lastUtcTicks >= intervalTicks &&
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<CETCompat>false</CETCompat>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
<AssemblyName>FASS.Api</AssemblyName>
|
||||
<ApplicationIcon>Resources\App.ico</ApplicationIcon>
|
||||
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
|
||||
@@ -13,12 +13,12 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Grpc.AspNetCore" Version="2.80.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.9" />
|
||||
<PackageReference Include="MiniExcel" Version="1.44.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.10" />
|
||||
<PackageReference Include="MiniExcel" Version="1.45.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.119.4" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.1" />
|
||||
<PackageReference Include="SkiaSharp" Version="4.150.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -671,6 +671,16 @@
|
||||
return typeof mapItem === 'function' ? items.map(mapItem) : items;
|
||||
}
|
||||
|
||||
function updateTableRowCells(row, item, selectors) {
|
||||
const columnSelectors = Array.isArray(selectors) ? selectors : [];
|
||||
for (let i = 0; i < columnSelectors.length; i++) {
|
||||
page.updateTableCell(row, i, columnSelectors[i](item));
|
||||
}
|
||||
while (row.children.length > columnSelectors.length) {
|
||||
row.removeChild(row.lastChild);
|
||||
}
|
||||
}
|
||||
|
||||
function cloneCar(source) {
|
||||
return {
|
||||
code: String(source?.code ?? ''),
|
||||
@@ -856,7 +866,7 @@
|
||||
}
|
||||
|
||||
function updateCarRow(row, car) {
|
||||
page.updateTableRowCells(row, car, carColumnSelectors);
|
||||
updateTableRowCells(row, car, carColumnSelectors);
|
||||
}
|
||||
|
||||
function renderCars() {
|
||||
@@ -916,7 +926,7 @@
|
||||
}
|
||||
|
||||
function updateAlarmRow(row, alarm) {
|
||||
page.updateTableRowCells(row, alarm, alarmColumnSelectors);
|
||||
updateTableRowCells(row, alarm, alarmColumnSelectors);
|
||||
}
|
||||
|
||||
function renderAlarms() {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<CETCompat>false</CETCompat>
|
||||
<Version>2.4.2</Version>
|
||||
<Version>2.4.3</Version>
|
||||
<AssemblyName>FASS.Mvc</AssemblyName>
|
||||
<ApplicationIcon>Resources\App.ico</ApplicationIcon>
|
||||
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
|
||||
@@ -13,10 +13,10 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Grpc.AspNetCore" Version="2.80.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.9" />
|
||||
<PackageReference Include="MiniExcel" Version="1.44.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.10" />
|
||||
<PackageReference Include="MiniExcel" Version="1.45.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.119.4" />
|
||||
<PackageReference Include="SkiaSharp" Version="4.150.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -744,6 +744,7 @@ button:active {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
touch-action: none;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
background: var(--canvas-bg);
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user