diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.FakePlcV2/FakePlc.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.FakePlcV2/FakePlc.cs deleted file mode 100644 index 4e55877e..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.FakePlcV2/FakePlc.cs +++ /dev/null @@ -1,356 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Buffers.Binary; -using System.IO; -using System.Net; -using System.Net.NetworkInformation; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using GeothermalResearchInstitute.PlcV2; -using GeothermalResearchInstitute.v2; -using Google.Protobuf; - -namespace GeothermalResearchInstitute.FakePlcV2 -{ - public class FakePlc : IDisposable - { - private TcpClient client; - private CancellationTokenSource cancellationTokenSource; - private Task backgroundTask; - private bool disposedValue = false; - - public FakePlc(byte[] id) - { - this.Mac = new PhysicalAddress(id); - } - - ~FakePlc() - { - this.Dispose(false); - } - - public PhysicalAddress Mac { get; } - - public Metric Metric { get; } = new Metric - { - OutputWaterCelsiusDegree = 11F, - InputWaterCelsiusDegree = 13F, - HeaterOutputWaterCelsiusDegree = 17F, - EnvironmentCelsiusDegree = 19F, - OutputWaterPressureMeter = 23F, - InputWaterPressureMeter = 29F, - HeaterPowerKilowatt = 31F, - WaterPumpFlowRateCubicMeterPerHour = 37F, - }; - - public Switch Switch { get; } = new Switch - { - DevicePowerOn = true, - ExhausterPowerOn = true, - HeaterAutoOn = true, - HeaterPowerOn = true, - HeaterFanOn = true, - HeaterCompressorOn = true, - HeaterFourWayReversingOn = true, - }; - - public WorkingMode WorkingMode { get; } = new WorkingMode - { - DeviceWorkingMode = DeviceWorkingMode.TemperatureDetermination, - DeviceFlowRateControlMode = DeviceFlowRateControlMode.VariableFrequency, - WaterPumpWorkingMode = WaterPumpWorkingMode.FixedFlowRate, - }; - - public RunningParameter RunningParameter { get; } = new RunningParameter - { - SummerHeaterCelsiusDegree = 11F, - WinterHeaterCelsiusDegree = 13F, - ColdPowerKilowatt = 17F, - WarmPowerKilowatt = 19F, - WaterPumpFlowRateCubicMeterPerHour = 23F, - WaterPumpFrequencyHertz = 29F, - }; - - public Alarm Alarm { get; } = new Alarm - { - LowFlowRate = false, - HighHeaterPressure = false, - LowHeaterPressure = false, - NoPower = false, - HeaterOverloadedBroken = false, - ElectricalHeaterBroken = false, - }; - - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - public async Task StartAsync(IPAddress address, int port) - { - this.client = new TcpClient(); - await this.client.ConnectAsync(address, port).ConfigureAwait(false); - - this.cancellationTokenSource = new CancellationTokenSource(); - this.backgroundTask = Task.Factory.StartNew( - this.BackgroundTaskEntryPoint, - this.cancellationTokenSource.Token, - TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, - TaskScheduler.Default); - } - - public async Task StopAsync() - { - if (this.client == null) - { - return; - } - - this.cancellationTokenSource.Cancel(); - await this.backgroundTask.ConfigureAwait(false); - this.client.Close(); - - this.backgroundTask.Dispose(); - this.backgroundTask = null; - this.cancellationTokenSource.Dispose(); - this.cancellationTokenSource = null; - this.client.Dispose(); - this.client = null; - } - - protected virtual void Dispose(bool disposing) - { - if (!this.disposedValue) - { - if (disposing) - { - if (this.backgroundTask != null) - { - this.StopAsync().GetAwaiter().GetResult(); - } - } - - this.disposedValue = true; - } - } - - private void BackgroundTaskEntryPoint() - { - using var reader = new BinaryReader(this.client.GetStream(), Encoding.ASCII, true); - while (!this.cancellationTokenSource.IsCancellationRequested) - { - byte[] header = reader.ReadBytes(20); - ushort contentLength = BinaryPrimitives.ReadUInt16BigEndian(header.AsSpan(0x12, 2)); - byte[] content = contentLength == 0 ? Array.Empty() : reader.ReadBytes(contentLength); - - var messageType = (PlcMessageType)BinaryPrimitives.ReadUInt16BigEndian(header.AsSpan(0x06, 2)); - PlcFrame responseFrame; - switch (messageType) - { - case PlcMessageType.ConnectRequest: - responseFrame = PlcFrame.Create( - PlcMessageType.ConnectResponse, - ByteString.CopyFrom(this.Mac.GetAddressBytes())); - break; - case PlcMessageType.GetMetricRequest: - responseFrame = this.CreateGetMetricResponse(); - break; - case PlcMessageType.GetSwitchRequest: - responseFrame = this.CreateGetSwitchResponseFrame(); - break; - case PlcMessageType.UpdateSwitchRequest: - this.UpdateSwitch(content); - responseFrame = this.CreateGetSwitchResponseFrame(); - break; - case PlcMessageType.GetWorkingModeRequest: - responseFrame = this.CreateGetWorkingModeResponseFrame(); - break; - case PlcMessageType.UpdateWorkingModeRequest: - this.UpdateWorkingMode(content); - responseFrame = this.CreateGetWorkingModeResponseFrame(); - break; - case PlcMessageType.GetRunningParameterRequest: - responseFrame = this.CreateGetRunningParameterResponseFrame(); - break; - case PlcMessageType.UpdateRunningParameterRequest: - this.UpdateRunningParameter(content); - responseFrame = this.CreateGetRunningParameterResponseFrame(); - break; - case PlcMessageType.GetAlarmRequest: - responseFrame = this.CreateGetAlarmResponseFrame(); - break; - default: - responseFrame = null; - break; - } - - if (responseFrame == null) - { - continue; - } - - responseFrame.FrameHeader.SequenceNumber = - BinaryPrimitives.ReadUInt32BigEndian(header.AsSpan(0x08, 4)); - responseFrame.WriteTo(this.client.GetStream()); - } - } - - private void UpdateSwitch(ReadOnlySpan content) - { - if ((content[0] & 0x10) != 0) - { - this.Switch.DevicePowerOn = (content[0] & 0x01) == 1; - } - - if ((content[1] & 0x10) != 0) - { - this.Switch.ExhausterPowerOn = (content[1] & 0x01) == 1; - } - - if ((content[2] & 0x10) != 0) - { - this.Switch.HeaterAutoOn = (content[2] & 0x01) == 1; - } - - if ((content[3] & 0x10) != 0) - { - this.Switch.HeaterPowerOn = (content[3] & 0x01) == 1; - } - - if ((content[4] & 0x10) != 0) - { - this.Switch.HeaterFanOn = (content[4] & 0x01) == 1; - } - - if ((content[5] & 0x10) != 0) - { - this.Switch.HeaterCompressorOn = (content[5] & 0x01) == 1; - } - - if ((content[6] & 0x10) != 0) - { - this.Switch.HeaterFourWayReversingOn = (content[6] & 0x01) == 1; - } - } - - private void UpdateWorkingMode(byte[] content) - { - if (content[0] != 0) - { - this.WorkingMode.DeviceWorkingMode = (DeviceWorkingMode)content[0]; - } - - if (content[1] != 0) - { - this.WorkingMode.DeviceFlowRateControlMode = (DeviceFlowRateControlMode)content[1]; - } - - if (content[2] != 0) - { - this.WorkingMode.WaterPumpWorkingMode = (WaterPumpWorkingMode)content[2]; - } - } - - private void UpdateRunningParameter(byte[] content) - { - this.RunningParameter.SummerHeaterCelsiusDegree = BitConverter.ToSingle(content.AsSpan(0, 4)); - this.RunningParameter.WinterHeaterCelsiusDegree = BitConverter.ToSingle(content.AsSpan(4, 4)); - this.RunningParameter.ColdPowerKilowatt = BitConverter.ToSingle(content.AsSpan(8, 4)); - this.RunningParameter.WarmPowerKilowatt = BitConverter.ToSingle(content.AsSpan(12, 4)); - this.RunningParameter.WaterPumpFlowRateCubicMeterPerHour = BitConverter.ToSingle(content.AsSpan(16, 4)); - this.RunningParameter.WaterPumpFrequencyHertz = BitConverter.ToSingle(content.AsSpan(20, 4)); - } - - private PlcFrame CreateGetMetricResponse() - { - byte[] responseContent = new byte[0x20]; - using (var writer = new BinaryWriter(new MemoryStream(responseContent))) - { - writer.Write(this.Metric.OutputWaterCelsiusDegree); - writer.Write(this.Metric.InputWaterCelsiusDegree); - writer.Write(this.Metric.HeaterOutputWaterCelsiusDegree); - writer.Write(this.Metric.EnvironmentCelsiusDegree); - writer.Write(this.Metric.OutputWaterPressureMeter); - writer.Write(this.Metric.InputWaterPressureMeter); - writer.Write(this.Metric.HeaterPowerKilowatt); - writer.Write(this.Metric.WaterPumpFlowRateCubicMeterPerHour); - } - - return PlcFrame.Create( - PlcMessageType.GetMetricResponse, - ByteString.CopyFrom(responseContent)); - } - - private PlcFrame CreateGetSwitchResponseFrame() - { - byte[] responseContent = new byte[0x07]; - responseContent[0] = (byte)(this.Switch.DevicePowerOn ? 0x01 : 0x00); - responseContent[1] = (byte)(this.Switch.ExhausterPowerOn ? 0x01 : 0x00); - responseContent[2] = (byte)(this.Switch.HeaterAutoOn ? 0x01 : 0x00); - responseContent[3] = (byte)(this.Switch.HeaterPowerOn ? 0x01 : 0x00); - responseContent[4] = (byte)(this.Switch.HeaterFanOn ? 0x01 : 0x00); - responseContent[5] = (byte)(this.Switch.HeaterCompressorOn ? 0x01 : 0x00); - responseContent[6] = (byte)(this.Switch.HeaterFourWayReversingOn ? 0x01 : 0x00); - - return PlcFrame.Create( - PlcMessageType.GetSwitchResponse, - ByteString.CopyFrom(responseContent)); - } - - private PlcFrame CreateGetWorkingModeResponseFrame() - { - byte[] responseContent = new byte[0x03]; - responseContent[0] = (byte)this.WorkingMode.DeviceWorkingMode; - responseContent[1] = (byte)this.WorkingMode.DeviceFlowRateControlMode; - responseContent[2] = (byte)this.WorkingMode.WaterPumpWorkingMode; - - return PlcFrame.Create( - PlcMessageType.GetWorkingModeResponse, - ByteString.CopyFrom(responseContent)); - } - - private PlcFrame CreateGetRunningParameterResponseFrame() - { - byte[] responseContent = new byte[0x18]; - using (var writer = new BinaryWriter(new MemoryStream(responseContent))) - { - writer.Write(this.RunningParameter.SummerHeaterCelsiusDegree); - writer.Write(this.RunningParameter.WinterHeaterCelsiusDegree); - writer.Write(this.RunningParameter.ColdPowerKilowatt); - writer.Write(this.RunningParameter.WarmPowerKilowatt); - writer.Write(this.RunningParameter.WaterPumpFlowRateCubicMeterPerHour); - writer.Write(this.RunningParameter.WaterPumpFrequencyHertz); - } - - return PlcFrame.Create( - PlcMessageType.GetRunningParameterResponse, - ByteString.CopyFrom(responseContent)); - } - - private PlcFrame CreateGetAlarmResponseFrame() - { - byte[] responseContent = new byte[0x0A]; - responseContent[0] = (byte)(this.Alarm.LowFlowRate ? 0x01 : 0x00); - responseContent[1] = (byte)(this.Alarm.HighHeaterPressure ? 0x01 : 0x00); - responseContent[2] = (byte)(this.Alarm.LowHeaterPressure ? 0x01 : 0x00); - responseContent[3] = (byte)(this.Alarm.NoPower ? 0x01 : 0x00); - responseContent[4] = (byte)(this.Alarm.HeaterOverloadedBroken ? 0x01 : 0x00); - responseContent[5] = (byte)(this.Alarm.ElectricalHeaterBroken ? 0x01 : 0x00); - responseContent[6] = (byte)(this.Alarm.NoWater ? 0x01 : 0x00); - responseContent[7] = (byte)(this.Alarm.HighVoltage ? 0x01 : 0x00); - responseContent[8] = (byte)(this.Alarm.LowVoltage ? 0x01 : 0x00); - responseContent[9] = (byte)(this.Alarm.EmergencyStopped ? 0x01 : 0x00); - - return PlcFrame.Create( - PlcMessageType.GetAlarmResponse, - ByteString.CopyFrom(responseContent)); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.FakePlcV2/GeothermalResearchInstitute.FakePlcV2.csproj b/GeothermalResearchInstitute/GeothermalResearchInstitute.FakePlcV2/GeothermalResearchInstitute.FakePlcV2.csproj deleted file mode 100644 index d67eef1f..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.FakePlcV2/GeothermalResearchInstitute.FakePlcV2.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - Exe - $(CurrentTargetFramework) - - win-x64 - true - False - False - False - - - - - - - diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.FakePlcV2/Program.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.FakePlcV2/Program.cs deleted file mode 100644 index e614db6d..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.FakePlcV2/Program.cs +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Net; -using System.Net.NetworkInformation; -using System.Threading.Tasks; - -namespace GeothermalResearchInstitute.FakePlcV2 -{ - internal class Program - { - internal static async Task Main() - { - using var plc = new FakePlc(PhysicalAddress.Parse("10BF4879B2A4").GetAddressBytes()); - await plc.StartAsync(IPAddress.Loopback, 8889).ConfigureAwait(false); - Console.ReadKey(); - await plc.StopAsync().ConfigureAwait(false); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.FakePlcV2/packages.lock.json b/GeothermalResearchInstitute/GeothermalResearchInstitute.FakePlcV2/packages.lock.json deleted file mode 100644 index 65cb1867..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.FakePlcV2/packages.lock.json +++ /dev/null @@ -1,195 +0,0 @@ -{ - "version": 2, - "dependencies": { - "net6.0": { - "DotNet.ReproducibleBuilds": { - "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==", - "dependencies": { - "Microsoft.SourceLink.AzureRepos.Git": "1.1.1", - "Microsoft.SourceLink.Bitbucket.Git": "1.1.1", - "Microsoft.SourceLink.GitHub": "1.1.1", - "Microsoft.SourceLink.GitLab": "1.1.1" - } - }, - "Microsoft.CodeAnalysis.BannedApiAnalyzers": { - "type": "Direct", - "requested": "[3.3.3, )", - "resolved": "3.3.3", - "contentHash": "vvz3XCHVrd/Ks4xPoutLmL/T2+8JcOk/OMs3ngwQqnzokQCGEDsY+WjK/txCsDWU29sX3fGzH/FnYwNV93O1mA==" - }, - "Microsoft.CodeAnalysis.NetAnalyzers": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "cjG06LMeOADNUeCUaklOfVgrnVkLy80H5PVll4QHDUXv+C+6G9rHczrNdWjfb3xKv3Ts9s4UsP6J2ZWe52Gz4Q==" - }, - "Microsoft.NETFramework.ReferenceAssemblies": { - "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", - "dependencies": { - "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3" - } - }, - "Microsoft.SourceLink.GitHub": { - "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Nerdbank.GitVersioning": { - "type": "Direct", - "requested": "[3.5.113, )", - "resolved": "3.5.113", - "contentHash": "4fBSMkqhi410qlkjPm+Mxfk8iO3C7dmgdVS7ljsfVO21WEzZCHP1VCOqB6rlOPfPidR/oxX+/Do/I7meCAz+Jg==" - }, - "StyleCop.Analyzers": { - "type": "Direct", - "requested": "[1.2.0-beta.435, )", - "resolved": "1.2.0-beta.435", - "contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==", - "dependencies": { - "StyleCop.Analyzers.Unstable": "1.2.0.435" - } - }, - "Grpc.Core.Api": { - "type": "Transitive", - "resolved": "2.46.3", - "contentHash": "uy1oe5baVa4V+C8ZyMiA8xYdNIx5A3PiacQL0f1zWDjF2z64Cb1MMXXRTs3GX+jeKpoK/RtOZg8UnJSm2KC/pQ==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" - }, - "Microsoft.NETFramework.ReferenceAssemblies.net461": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==" - }, - "Microsoft.SourceLink.AzureRepos.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Bitbucket.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==" - }, - "Microsoft.SourceLink.GitLab": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "StyleCop.Analyzers.Unstable": { - "type": "Transitive", - "resolved": "1.2.0.435", - "contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg==" - }, - "crc32c.net": { - "type": "Project" - }, - "geothermalresearchinstitute.grpc": { - "type": "Project", - "dependencies": { - "Google.Protobuf": "[3.21.6, )", - "Grpc": "[2.46.3, )" - } - }, - "geothermalresearchinstitute.plcv2": { - "type": "Project", - "dependencies": { - "Crc32C.NET": "[1.0.0, )", - "GeothermalResearchInstitute.Grpc": "[1.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[6.0.0, )", - "System.Memory": "[4.5.5, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" - } - }, - "Google.Protobuf": { - "type": "CentralTransitive", - "requested": "[3.21.6, )", - "resolved": "3.21.6", - "contentHash": "HSYHFnfuTu/O4Ijy0mCW9zxLI8MJfCZJ10dk3JGPrkLaRR4LsiPKzZrrnapf2G0tP2yRMkHCl+2LKLTXqGBn2A==" - }, - "Grpc": { - "type": "CentralTransitive", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "79TsAcLBVl5J7AmtnV+GmgkhWlpK3D9JYJDhYxZGO0DKukbyrRxxcbaFlRZ84WGwTAW8LezrInUYgfiJi3zGVg==", - "dependencies": { - "Grpc.Core": "2.46.3" - } - }, - "Grpc.Core": { - "type": "CentralTransitive", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "lu7KP7BVWdvFXWbn/IFYHBQCpMohJwbLM1aL+nu2C0pY2CdS0idaUNAJNC2nZ60fXfqoxnSiERrIU6rC474oTw==", - "dependencies": { - "Grpc.Core.Api": "2.46.3", - "System.Memory": "4.5.3" - } - }, - "Microsoft.Extensions.Logging.Abstractions": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA==" - }, - "System.Memory": { - "type": "CentralTransitive", - "requested": "[4.5.5, )", - "resolved": "4.5.5", - "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" - } - }, - "net6.0/win-x64": { - "Grpc.Core": { - "type": "CentralTransitive", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "lu7KP7BVWdvFXWbn/IFYHBQCpMohJwbLM1aL+nu2C0pY2CdS0idaUNAJNC2nZ60fXfqoxnSiERrIU6rC474oTw==", - "dependencies": { - "Grpc.Core.Api": "2.46.3", - "System.Memory": "4.5.3" - } - } - } - } -} \ No newline at end of file diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Grpc/GeothermalResearchInstitute.Grpc.csproj b/GeothermalResearchInstitute/GeothermalResearchInstitute.Grpc/GeothermalResearchInstitute.Grpc.csproj deleted file mode 100644 index 436acde9..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Grpc/GeothermalResearchInstitute.Grpc.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - $(CurrentTargetFramework) - - - - - - - - - - - - - - - diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Grpc/packages.lock.json b/GeothermalResearchInstitute/GeothermalResearchInstitute.Grpc/packages.lock.json deleted file mode 100644 index f9021b20..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Grpc/packages.lock.json +++ /dev/null @@ -1,157 +0,0 @@ -{ - "version": 2, - "dependencies": { - "net6.0": { - "DotNet.ReproducibleBuilds": { - "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==", - "dependencies": { - "Microsoft.SourceLink.AzureRepos.Git": "1.1.1", - "Microsoft.SourceLink.Bitbucket.Git": "1.1.1", - "Microsoft.SourceLink.GitHub": "1.1.1", - "Microsoft.SourceLink.GitLab": "1.1.1" - } - }, - "Google.Protobuf": { - "type": "Direct", - "requested": "[3.21.6, )", - "resolved": "3.21.6", - "contentHash": "HSYHFnfuTu/O4Ijy0mCW9zxLI8MJfCZJ10dk3JGPrkLaRR4LsiPKzZrrnapf2G0tP2yRMkHCl+2LKLTXqGBn2A==" - }, - "Grpc": { - "type": "Direct", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "79TsAcLBVl5J7AmtnV+GmgkhWlpK3D9JYJDhYxZGO0DKukbyrRxxcbaFlRZ84WGwTAW8LezrInUYgfiJi3zGVg==", - "dependencies": { - "Grpc.Core": "2.46.3" - } - }, - "Grpc.Tools": { - "type": "Direct", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "giDUsniVGpakcqR9UjkzUEfOFQLffg96uV/hYhP6Iht4/ila5vSGRWYfeuN2yei933KRXTqjCW+8RvcMONRSHA==" - }, - "Microsoft.CodeAnalysis.BannedApiAnalyzers": { - "type": "Direct", - "requested": "[3.3.3, )", - "resolved": "3.3.3", - "contentHash": "vvz3XCHVrd/Ks4xPoutLmL/T2+8JcOk/OMs3ngwQqnzokQCGEDsY+WjK/txCsDWU29sX3fGzH/FnYwNV93O1mA==" - }, - "Microsoft.CodeAnalysis.NetAnalyzers": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "cjG06LMeOADNUeCUaklOfVgrnVkLy80H5PVll4QHDUXv+C+6G9rHczrNdWjfb3xKv3Ts9s4UsP6J2ZWe52Gz4Q==" - }, - "Microsoft.NETFramework.ReferenceAssemblies": { - "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", - "dependencies": { - "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3" - } - }, - "Microsoft.SourceLink.GitHub": { - "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Nerdbank.GitVersioning": { - "type": "Direct", - "requested": "[3.5.113, )", - "resolved": "3.5.113", - "contentHash": "4fBSMkqhi410qlkjPm+Mxfk8iO3C7dmgdVS7ljsfVO21WEzZCHP1VCOqB6rlOPfPidR/oxX+/Do/I7meCAz+Jg==" - }, - "StyleCop.Analyzers": { - "type": "Direct", - "requested": "[1.2.0-beta.435, )", - "resolved": "1.2.0-beta.435", - "contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==", - "dependencies": { - "StyleCop.Analyzers.Unstable": "1.2.0.435" - } - }, - "Grpc.Core.Api": { - "type": "Transitive", - "resolved": "2.46.3", - "contentHash": "uy1oe5baVa4V+C8ZyMiA8xYdNIx5A3PiacQL0f1zWDjF2z64Cb1MMXXRTs3GX+jeKpoK/RtOZg8UnJSm2KC/pQ==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" - }, - "Microsoft.NETFramework.ReferenceAssemblies.net461": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==" - }, - "Microsoft.SourceLink.AzureRepos.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Bitbucket.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==" - }, - "Microsoft.SourceLink.GitLab": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "StyleCop.Analyzers.Unstable": { - "type": "Transitive", - "resolved": "1.2.0.435", - "contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg==" - }, - "Grpc.Core": { - "type": "CentralTransitive", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "lu7KP7BVWdvFXWbn/IFYHBQCpMohJwbLM1aL+nu2C0pY2CdS0idaUNAJNC2nZ60fXfqoxnSiERrIU6rC474oTw==", - "dependencies": { - "Grpc.Core.Api": "2.46.3", - "System.Memory": "4.5.3" - } - }, - "System.Memory": { - "type": "CentralTransitive", - "requested": "[4.5.5, )", - "resolved": "4.5.5", - "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" - } - } - } -} \ No newline at end of file diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/FrameHeader.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/FrameHeader.cs deleted file mode 100644 index c49ad0fa..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/FrameHeader.cs +++ /dev/null @@ -1,123 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Buffers.Binary; -using System.Text.Json; -using System.Threading.Tasks; -using Overby.Extensions.AsyncBinaryReaderWriter; - -namespace GeothermalResearchInstitute.Plc -{ - internal class FrameHeader - { - public FrameHeader( - byte version, - byte type, - byte sequenceNumber, - uint streamId, - ushort contentOffset, - ushort contentLength, - uint contentChecksum) - { - this.Version = version; - this.Type = type; - this.SequenceNumber = sequenceNumber; - this.StreamId = streamId; - this.ContentOffset = contentOffset; - this.ContentLength = contentLength; - this.ContentChecksum = contentChecksum; - } - - public byte Version { get; } - - public byte Type { get; } - - public byte SequenceNumber { get; } - - public uint StreamId { get; } - - public ushort ContentOffset { get; } - - public ushort ContentLength { get; } - - public uint ContentChecksum { get; } - - public static FrameHeader Parse(ReadOnlySpan buffer) - { - return new FrameHeader( - version: buffer[4], - type: buffer[5], - sequenceNumber: buffer[6], - streamId: BinaryPrimitives.ReadUInt32BigEndian(buffer.Slice(8, 4)), - contentOffset: BinaryPrimitives.ReadUInt16BigEndian(buffer.Slice(12, 2)), - contentLength: BinaryPrimitives.ReadUInt16BigEndian(buffer.Slice(14, 2)), - contentChecksum: BinaryPrimitives.ReadUInt32BigEndian(buffer.Slice(16, 4))); - } - - public void WriteTo(Span buffer) - { - // Write magic signature. - buffer[0] = (byte)'D'; - buffer[1] = (byte)'R'; - buffer[2] = (byte)'Y'; - buffer[3] = 0; - - // Write version, type, sequence number. - buffer[4] = this.Version; - buffer[5] = this.Type; - buffer[6] = this.SequenceNumber; - buffer[7] = 0; - - // Write stream id. - BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(8, 4), this.StreamId); - - // Write content offset & size. - BinaryPrimitives.WriteUInt16BigEndian(buffer.Slice(12, 2), this.ContentOffset); - BinaryPrimitives.WriteUInt16BigEndian(buffer.Slice(14, 2), this.ContentLength); - - // Write content checksum. - BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(16, 4), this.ContentChecksum); - } - - public async Task WriteTo(AsyncBinaryWriter binaryWriter) - { - // Write magic signature. - await binaryWriter.WriteAsync((byte)'D').ConfigureAwait(false); - await binaryWriter.WriteAsync((byte)'R').ConfigureAwait(false); - await binaryWriter.WriteAsync((byte)'Y').ConfigureAwait(false); - await binaryWriter.WriteAsync((byte)0).ConfigureAwait(false); - - // Write version, type, sequence number. - await binaryWriter.WriteAsync((byte)this.Version).ConfigureAwait(false); - await binaryWriter.WriteAsync((byte)this.Type).ConfigureAwait(false); - await binaryWriter.WriteAsync((byte)this.SequenceNumber).ConfigureAwait(false); - await binaryWriter.WriteAsync((byte)0).ConfigureAwait(false); - - // Write stream id. - await binaryWriter - .WriteAsync(BinaryPrimitives.ReverseEndianness((uint)this.StreamId)) - .ConfigureAwait(false); - - // Write content offset & size. - await binaryWriter - .WriteAsync(BinaryPrimitives.ReverseEndianness((ushort)this.ContentOffset)) - .ConfigureAwait(false); - await binaryWriter - .WriteAsync(BinaryPrimitives.ReverseEndianness((ushort)this.ContentLength)) - .ConfigureAwait(false); - - // Write content checksum. - await binaryWriter - .WriteAsync(BinaryPrimitives.ReverseEndianness((uint)this.ContentChecksum)) - .ConfigureAwait(false); - } - - public override string ToString() - { - return JsonSerializer.Serialize(this); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/GeothermalResearchInstitute.Plc.csproj b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/GeothermalResearchInstitute.Plc.csproj deleted file mode 100644 index bf98a9d4..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/GeothermalResearchInstitute.Plc.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - $(CurrentTargetFramework) - - - - - - - - - - - - - - - diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/HexUtils.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/HexUtils.cs deleted file mode 100644 index 861c09e5..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/HexUtils.cs +++ /dev/null @@ -1,143 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Text; - -namespace GeothermalResearchInstitute.Plc -{ - internal class HexUtils - { - private readonly ReadOnlyMemory bytes; - private readonly int bytesPerLine; - private readonly bool showHeader; - private readonly bool showOffset; - private readonly bool showAscii; - - private readonly StringBuilder sb = new StringBuilder(); - - private int index; - - private HexUtils( - ReadOnlyMemory bytes, - int bytesPerLine, - bool showHeader, - bool showOffset, - bool showAscii) - { - this.bytes = bytes; - this.bytesPerLine = bytesPerLine; - this.showHeader = showHeader; - this.showOffset = showOffset; - this.showAscii = showAscii; - } - - public static string Dump( - ReadOnlyMemory bytes, - int bytesPerLine = 16, - bool showHeader = true, - bool showOffset = true, - bool showAscii = true) - { - return new HexUtils(bytes, bytesPerLine, showHeader, showOffset, showAscii).Dump(); - } - - private static string Translate(byte b) - { - return b < 32 ? "." : Encoding.ASCII.GetString(new[] { b }); - } - - private string Dump() - { - if (this.showHeader) - { - this.WriteHeader(); - } - - this.WriteBody(); - return this.sb.ToString(); - } - - private void WriteHeader() - { - if (this.showOffset) - { - this.sb.Append("Offset(h) "); - } - - for (int i = 0; i < this.bytesPerLine; i++) - { - this.sb.Append($"{i & 0xFF:X2}"); - if (i + 1 < this.bytesPerLine) - { - this.sb.Append(' '); - } - } - - this.sb.AppendLine(); - } - - private void WriteBody() - { - while (this.index < this.bytes.Length) - { - if (this.index % this.bytesPerLine == 0) - { - if (this.index > 0) - { - if (this.showAscii) - { - this.WriteAscii(); - } - - this.sb.AppendLine(); - } - - if (this.showOffset) - { - this.WriteOffset(); - } - } - - this.WriteByte(); - if (this.index % this.bytesPerLine != 0 && this.index < this.bytes.Length) - { - this.sb.Append(' '); - } - } - - if (this.showAscii) - { - this.WriteAscii(); - } - } - - private void WriteOffset() - { - this.sb.Append($"{this.index:X8} "); - } - - private void WriteByte() - { - this.sb.Append($"{this.bytes.Span[this.index]:X2}"); - this.index++; - } - - private void WriteAscii() - { - int backtrack = ((this.index - 1) / this.bytesPerLine) * this.bytesPerLine; - int length = this.index - backtrack; - - // This is to fill up last string of the dump if it's shorter than _bytesPerLine - this.sb.Append(new string(' ', (this.bytesPerLine - length) * 3)); - - this.sb.Append(" "); - for (int i = 0; i < length; i++) - { - this.sb.Append(Translate(this.bytes.Span[backtrack + i])); - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClient.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClient.cs deleted file mode 100644 index e8c4528f..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClient.cs +++ /dev/null @@ -1,224 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; -using System.Threading.Tasks.Dataflow; -using GeothermalResearchInstitute.v2; -using Google.Protobuf; -using Grpc.Core; -using Microsoft.Extensions.Logging; - -namespace GeothermalResearchInstitute.Plc -{ - public partial class PlcClient : IDisposable - { - private readonly ILogger logger; - private readonly TcpClient client; - private readonly ConcurrentDictionary receivingContexts = - new ConcurrentDictionary(); - - private volatile bool started = false; - private volatile bool stopped = false; - private ManualResetEvent stoppedEvent; - private EndPoint remoteEndPoint; - private BufferBlock requestQueue; - private int counter; - private Task backgroundSendingTask; - private Task backgroundReceivingTask; - private Task backgroundDeadlineCollectionTask; - - private bool disposedValue = false; - - public PlcClient(ILogger logger, TcpClient client) - { - this.logger = logger; - this.client = client; - this.ConnectionClosed += async (_, __) => - { - await this.StopAsync().ConfigureAwait(false); - }; - } - - public event EventHandler ConnectionClosed; - - public EndPoint RemoteEndPoint => this.remoteEndPoint; - - public Task StartAsync() - { - if (this.started) - { - return Task.CompletedTask; - } - - if (!this.client.Connected) - { - return Task.FromException(new InvalidOperationException("Client disconnected")); - } - - this.remoteEndPoint = this.client.Client?.RemoteEndPoint; - this.stoppedEvent = new ManualResetEvent(false); - this.requestQueue = new BufferBlock(new DataflowBlockOptions - { - BoundedCapacity = 20, - EnsureOrdered = false, - TaskScheduler = TaskScheduler.Default, - }); - this.counter = 0; - - this.backgroundSendingTask = Task.Factory.StartNew( - this.BackgroundSendingTaskEntryPoint, - Task.Factory.CancellationToken, - TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, - TaskScheduler.Default); - this.backgroundReceivingTask = Task.Factory.StartNew( - this.BackgroundReceivingTaskEntryPoint, - Task.Factory.CancellationToken, - TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, - TaskScheduler.Default); - this.backgroundDeadlineCollectionTask = Task.Factory.StartNew( - this.BackgroundDeadlineCollectionTaskEntryPoint, - Task.Factory.CancellationToken, - TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, - TaskScheduler.Default); - - this.started = true; - return Task.CompletedTask; - } - - public async Task StopAsync() - { - if (this.started && !this.stopped) - { - this.stoppedEvent.Set(); - this.requestQueue.Complete(); - - await this.backgroundSendingTask.ConfigureAwait(false); - await this.backgroundReceivingTask.ConfigureAwait(false); - - this.stopped = true; - } - } - - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (this.disposedValue) - { - return; - } - - if (disposing) - { - if (this.started) - { - if (!this.stopped) - { - this.StopAsync().GetAwaiter().GetResult(); - } - - this.stoppedEvent.Dispose(); - this.backgroundSendingTask.Dispose(); - this.backgroundReceivingTask.Dispose(); - this.client.Dispose(); - } - } - - this.disposedValue = true; - } - - private async Task InvokeAsync( - string path, - TRequest request, - MessageParser responseParser, - DateTime? deadline = null, - CancellationToken cancellationToken = default) - where TRequest : IMessage - where TResponse : IMessage - { - var promise = new TaskCompletionSource(); - - await this.requestQueue - .SendAsync( - new RequestContext - { - Path = path, - Message = request, - Deadline = deadline, - CancellationToken = cancellationToken, - TaskCompletionSource = promise, - }, - cancellationToken) - .ConfigureAwait(false); - return await promise.Task - .ContinueWith( - future => - { - if (future.IsFaulted) - { - throw new RpcException(new Status( - StatusCode.Internal, future.Exception.ToString())); - } - - if (future.IsCanceled) - { - throw new RpcException(Status.DefaultCancelled); - } - - UnifiedFrameContent frame = future.Result; - if (frame.Header.Status == 0) - { - return responseParser.ParseFrom(frame.Payload); - } - else - { - throw new RpcException(new Status( - (StatusCode)frame.Header.Status, - frame.Header.StatusMessage)); - } - }, - cancellationToken, - TaskContinuationOptions.DenyChildAttach, - TaskScheduler.Default) - .ConfigureAwait(false); - } - - private void BackgroundDeadlineCollectionTaskEntryPoint() - { - while (!this.stoppedEvent.WaitOne(100)) - { - DateTime now = DateTime.Now; - foreach (KeyValuePair p in this.receivingContexts) - { - if (p.Value.CancellationToken.IsCancellationRequested - || now > p.Value.Deadline) - { - if (this.receivingContexts.TryRemove(p.Key, out var _)) - { - p.Value.TaskCompletionSource.SetResult(new UnifiedFrameContent - { - Header = new Header - { - Status = (int)StatusCode.DeadlineExceeded, - StatusMessage = "Didn't receive message before deadline", - }, - }); - } - } - } - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClientApi.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClientApi.cs deleted file mode 100644 index 69e96a26..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClientApi.cs +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Threading; -using System.Threading.Tasks; -using GeothermalResearchInstitute.v2; - -namespace GeothermalResearchInstitute.Plc -{ - public partial class PlcClient - { - public Task TestAsync( - TestRequest request, - DateTime? deadline = null, - CancellationToken cancellationToken = default) - { - return this.InvokeAsync( - "/bjdire.v2.DeviceService/Test", - request, - TestResponse.Parser, - deadline, - cancellationToken); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClientReceiving.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClientReceiving.cs deleted file mode 100644 index 4eae4fb6..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClientReceiving.cs +++ /dev/null @@ -1,122 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.IO; -using System.Text; -using System.Threading.Tasks; -using GeothermalResearchInstitute.v2; -using Microsoft.Extensions.Logging; -using Overby.Extensions.AsyncBinaryReaderWriter; - -namespace GeothermalResearchInstitute.Plc -{ - public partial class PlcClient - { - private async void BackgroundReceivingTaskEntryPoint() - { - try - { - using var binaryReader = new AsyncBinaryReader(this.client.GetStream(), Encoding.ASCII, true); - - while (!this.stoppedEvent.WaitOne(1000)) - { - await this.DrainReceivingContexts(binaryReader).ConfigureAwait(false); - } - - await this.DrainReceivingContexts(binaryReader).ConfigureAwait(false); - } - catch (IOException e) - { - this.logger.LogError(e, "Error when receiving data from {0}", this.remoteEndPoint); - this.client.Close(); - this.ConnectionClosed?.Invoke(this, new EventArgs()); - } - } - - private async Task DrainReceivingContexts(AsyncBinaryReader binaryReader) - { - while (!(this.receivingContexts.IsEmpty && this.requestQueue.Count == 0)) - { - byte[] frameHeaderBytes = await binaryReader.ReadBytesAsync(20).ConfigureAwait(false); - if (frameHeaderBytes.Length < 20) - { - throw new IOException("Socket closed during reading."); - } - - var frameHeader = FrameHeader.Parse(frameHeaderBytes); - if (frameHeader.ContentOffset != 20) - { - this.logger.LogCritical( - "Invalid frame header with unexpected content offset, expected=20 actual={0}", - frameHeader.ContentOffset); - throw new InvalidDataException("Invalid frame header"); - } - - if (frameHeader.Version != 1) - { - this.logger.LogWarning( - "Invalid frame header with unexpected version {0}", - frameHeader.Version); - throw new InvalidDataException("Invalid frame header"); - } - - byte[] framePayloadBytes = await binaryReader - .ReadBytesAsync(frameHeader.ContentLength) - .ConfigureAwait(false); - if (framePayloadBytes.Length < frameHeader.ContentLength) - { - throw new IOException("Socket closed during reading."); - } - - if (this.logger.IsEnabled(LogLevel.Debug)) - { - var buffer = new byte[frameHeaderBytes.Length + framePayloadBytes.Length]; - Buffer.BlockCopy(frameHeaderBytes, 0, buffer, 0, frameHeaderBytes.Length); - Buffer.BlockCopy(framePayloadBytes, 0, buffer, frameHeaderBytes.Length, framePayloadBytes.Length); - - this.logger.LogDebug( - "Received streamId={0}:" + Environment.NewLine + "{1}", - frameHeader.StreamId, - HexUtils.Dump(buffer.AsMemory())); - } - - if (this.receivingContexts.TryRemove((int)frameHeader.StreamId, out RequestContext requestContext)) - { - this.Process(requestContext, frameHeader, framePayloadBytes); - } - else - { - this.logger.LogWarning("Dropped a frame with unexpected streamId {0}", frameHeader.StreamId); - } - } - } - - private void Process(RequestContext requestContext, FrameHeader frameHeader, byte[] framePayloadBytes) - { - if (frameHeader.Type != 2) - { - this.logger.LogWarning("Dropped a frame with unexpected type {0}", frameHeader.Type); - requestContext.TaskCompletionSource.SetException(new InvalidDataException("Invalid data received")); - return; - } - - var expectedChecksum = Crc32C.Crc32CAlgorithm.Compute(framePayloadBytes); - if (frameHeader.ContentChecksum != expectedChecksum) - { - this.logger.LogWarning( - "Dropped a frame with unexpected checksum {0}(expected {1})", - frameHeader.ContentChecksum, - expectedChecksum); - requestContext.TaskCompletionSource.SetException(new InvalidDataException("Invalid data received")); - return; - } - - // TODO(zhangshuai.ustc): check deadline. - var unifiedFrameContent = UnifiedFrameContent.Parser.ParseFrom(framePayloadBytes); - requestContext.TaskCompletionSource.SetResult(unifiedFrameContent); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClientRequestContext.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClientRequestContext.cs deleted file mode 100644 index 9f2ba6e9..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClientRequestContext.cs +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Threading; -using System.Threading.Tasks; -using GeothermalResearchInstitute.v2; -using Google.Protobuf; - -namespace GeothermalResearchInstitute.Plc -{ - public partial class PlcClient - { - private class RequestContext - { - public string Path { get; set; } - - public IMessage Message { get; set; } - - public DateTime? Deadline { get; set; } - - public CancellationToken CancellationToken { get; set; } - - public TaskCompletionSource TaskCompletionSource { get; set; } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClientSending.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClientSending.cs deleted file mode 100644 index 269cd95a..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/PlcClientSending.cs +++ /dev/null @@ -1,135 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.IO; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Threading.Tasks.Dataflow; -using GeothermalResearchInstitute.v2; -using Google.Protobuf; -using Grpc.Core; -using Microsoft.Extensions.Logging; -using Overby.Extensions.AsyncBinaryReaderWriter; - -namespace GeothermalResearchInstitute.Plc -{ - public partial class PlcClient - { - private static async Task WriteFrame( - AsyncBinaryWriter writer, - byte type, - byte seqNum, - int streamId, - byte[] contents) - { - uint contentChecksum = 0; - - // TODO(zhangshuai.ustc): Support other platform - if (Environment.OSVersion.Platform == PlatformID.Win32NT - || Environment.OSVersion.Platform == PlatformID.Win32Windows) - { - contentChecksum = Crc32C.Crc32CAlgorithm.Compute(contents); - } - - var frameHeader = new FrameHeader( - version: 1, - type: type, - sequenceNumber: seqNum, - streamId: (uint)streamId, - contentOffset: 20, - contentLength: (ushort)contents.Length, - contentChecksum: contentChecksum); - await frameHeader.WriteTo(writer).ConfigureAwait(false); - await writer.WriteAsync(contents).ConfigureAwait(false); - } - - private async void BackgroundSendingTaskEntryPoint() - { - try - { - using var binaryWriter = new AsyncBinaryWriter(this.client.GetStream(), Encoding.ASCII, true); - while (await this.requestQueue - .OutputAvailableAsync() - .ConfigureAwait(false)) - { - await this.DrainSendingRequestContexts(binaryWriter).ConfigureAwait(false); - } - } - catch (IOException e) - { - this.logger.LogError(e, "Error when receiving data from {0}", this.client.Client.RemoteEndPoint); - this.client.Close(); - this.ConnectionClosed?.Invoke(this, new EventArgs()); - } - } - - private async Task DrainSendingRequestContexts(AsyncBinaryWriter binaryWriter) - { - while (this.requestQueue.TryReceive(out RequestContext requestContext)) - { - if (requestContext.CancellationToken.IsCancellationRequested - || DateTime.Now > requestContext.Deadline) - { - requestContext.TaskCompletionSource.SetResult(new UnifiedFrameContent - { - Header = new Header - { - Status = (int)StatusCode.DeadlineExceeded, - StatusMessage = Status.DefaultCancelled.Detail, - }, - }); - } - - var unifiedFrameContent = new UnifiedFrameContent() - { - Header = new Header() - { - Path = requestContext.Path, - }, - Payload = requestContext.Message.ToByteString(), - }; - int streamId = Interlocked.Increment(ref this.counter); - await this.WriteUnifiedFrameContent(binaryWriter, streamId, unifiedFrameContent) - .ConfigureAwait(false); - if (!this.receivingContexts.TryAdd(streamId, requestContext)) - { - throw new InvalidOperationException("Impossible"); - } - - this.logger.LogDebug("Request recorded as streamId={0}: {1}", streamId, requestContext.Message); - } - } - - private async Task WriteUnifiedFrameContent( - AsyncBinaryWriter writer, - int streamId, - UnifiedFrameContent unifiedFrameContent) - { - if (this.logger.IsEnabled(LogLevel.Debug)) - { - using var memoryStream = new MemoryStream(); - using var memoryWriter = new AsyncBinaryWriter(memoryStream, Encoding.ASCII, false); - - await WriteFrame(memoryWriter, 2, 0, streamId, unifiedFrameContent.ToByteArray()) - .ConfigureAwait(false); - byte[] sendingBytes = memoryStream.ToArray(); - - this.logger.LogDebug( - "Sending to {0} with streamId={1}:" + Environment.NewLine + "{2}", - unifiedFrameContent.Header.Path, - streamId, - HexUtils.Dump(new ReadOnlyMemory(sendingBytes))); - await writer.WriteAsync(sendingBytes).ConfigureAwait(false); - } - else - { - await WriteFrame(writer, 2, 0, streamId, unifiedFrameContent.ToByteArray()) - .ConfigureAwait(false); - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/packages.lock.json b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/packages.lock.json deleted file mode 100644 index aeedc35d..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcClient/packages.lock.json +++ /dev/null @@ -1,202 +0,0 @@ -{ - "version": 2, - "dependencies": { - "net6.0": { - "DotNet.ReproducibleBuilds": { - "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==", - "dependencies": { - "Microsoft.SourceLink.AzureRepos.Git": "1.1.1", - "Microsoft.SourceLink.Bitbucket.Git": "1.1.1", - "Microsoft.SourceLink.GitHub": "1.1.1", - "Microsoft.SourceLink.GitLab": "1.1.1" - } - }, - "Microsoft.CodeAnalysis.BannedApiAnalyzers": { - "type": "Direct", - "requested": "[3.3.3, )", - "resolved": "3.3.3", - "contentHash": "vvz3XCHVrd/Ks4xPoutLmL/T2+8JcOk/OMs3ngwQqnzokQCGEDsY+WjK/txCsDWU29sX3fGzH/FnYwNV93O1mA==" - }, - "Microsoft.CodeAnalysis.NetAnalyzers": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "cjG06LMeOADNUeCUaklOfVgrnVkLy80H5PVll4QHDUXv+C+6G9rHczrNdWjfb3xKv3Ts9s4UsP6J2ZWe52Gz4Q==" - }, - "Microsoft.Extensions.Logging.Abstractions": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA==" - }, - "Microsoft.NETFramework.ReferenceAssemblies": { - "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", - "dependencies": { - "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3" - } - }, - "Microsoft.SourceLink.GitHub": { - "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Nerdbank.GitVersioning": { - "type": "Direct", - "requested": "[3.5.113, )", - "resolved": "3.5.113", - "contentHash": "4fBSMkqhi410qlkjPm+Mxfk8iO3C7dmgdVS7ljsfVO21WEzZCHP1VCOqB6rlOPfPidR/oxX+/Do/I7meCAz+Jg==" - }, - "Overby.Extensions.AsyncBinaryReaderWriter": { - "type": "Direct", - "requested": "[1.0.39, )", - "resolved": "1.0.39", - "contentHash": "/4AdpYC4rgMOfmNjvU4kdEEqiEd3DfVWDbbzTIf3LoAbZ6GE46mM5FvmvQR2kYuMvEfqZo1mp1Rl1SAmjgXfrQ==" - }, - "StyleCop.Analyzers": { - "type": "Direct", - "requested": "[1.2.0-beta.435, )", - "resolved": "1.2.0-beta.435", - "contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==", - "dependencies": { - "StyleCop.Analyzers.Unstable": "1.2.0.435" - } - }, - "System.Text.Json": { - "type": "Direct", - "requested": "[6.0.6, )", - "resolved": "6.0.6", - "contentHash": "GZ+62pLOr544jwSvyXv5ezSfzlFBTjLuPhgOS2dnKuknAA8dPNUGXLKTHf9XdsudU9JpbtweXnE4oEiKEB2T1Q==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Encodings.Web": "6.0.0" - } - }, - "System.Threading.Tasks.Dataflow": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" - }, - "Grpc.Core.Api": { - "type": "Transitive", - "resolved": "2.46.3", - "contentHash": "uy1oe5baVa4V+C8ZyMiA8xYdNIx5A3PiacQL0f1zWDjF2z64Cb1MMXXRTs3GX+jeKpoK/RtOZg8UnJSm2KC/pQ==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" - }, - "Microsoft.NETFramework.ReferenceAssemblies.net461": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==" - }, - "Microsoft.SourceLink.AzureRepos.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Bitbucket.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==" - }, - "Microsoft.SourceLink.GitLab": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "StyleCop.Analyzers.Unstable": { - "type": "Transitive", - "resolved": "1.2.0.435", - "contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg==" - }, - "System.Runtime.CompilerServices.Unsafe": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" - }, - "System.Text.Encodings.Web": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "crc32c.net": { - "type": "Project" - }, - "geothermalresearchinstitute.grpc": { - "type": "Project", - "dependencies": { - "Google.Protobuf": "[3.21.6, )", - "Grpc": "[2.46.3, )" - } - }, - "Google.Protobuf": { - "type": "CentralTransitive", - "requested": "[3.21.6, )", - "resolved": "3.21.6", - "contentHash": "HSYHFnfuTu/O4Ijy0mCW9zxLI8MJfCZJ10dk3JGPrkLaRR4LsiPKzZrrnapf2G0tP2yRMkHCl+2LKLTXqGBn2A==" - }, - "Grpc": { - "type": "CentralTransitive", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "79TsAcLBVl5J7AmtnV+GmgkhWlpK3D9JYJDhYxZGO0DKukbyrRxxcbaFlRZ84WGwTAW8LezrInUYgfiJi3zGVg==", - "dependencies": { - "Grpc.Core": "2.46.3" - } - }, - "Grpc.Core": { - "type": "CentralTransitive", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "lu7KP7BVWdvFXWbn/IFYHBQCpMohJwbLM1aL+nu2C0pY2CdS0idaUNAJNC2nZ60fXfqoxnSiERrIU6rC474oTw==", - "dependencies": { - "Grpc.Core.Api": "2.46.3", - "System.Memory": "4.5.3" - } - }, - "System.Memory": { - "type": "CentralTransitive", - "requested": "[4.5.5, )", - "resolved": "4.5.5", - "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" - } - } - } -} \ No newline at end of file diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/GeothermalResearchInstitute.PlcV2.csproj b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/GeothermalResearchInstitute.PlcV2.csproj deleted file mode 100644 index 5585b5a0..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/GeothermalResearchInstitute.PlcV2.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - $(CurrentTargetFramework) - - - - - - - - - - - - - - diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/HexUtils.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/HexUtils.cs deleted file mode 100644 index a95dc0dd..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/HexUtils.cs +++ /dev/null @@ -1,143 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Text; - -namespace GeothermalResearchInstitute.PlcV2 -{ - internal class HexUtils - { - private readonly ReadOnlyMemory bytes; - private readonly int bytesPerLine; - private readonly bool showHeader; - private readonly bool showOffset; - private readonly bool showAscii; - - private readonly StringBuilder sb = new StringBuilder(); - - private int index; - - private HexUtils( - ReadOnlyMemory bytes, - int bytesPerLine, - bool showHeader, - bool showOffset, - bool showAscii) - { - this.bytes = bytes; - this.bytesPerLine = bytesPerLine; - this.showHeader = showHeader; - this.showOffset = showOffset; - this.showAscii = showAscii; - } - - public static string Dump( - ReadOnlyMemory bytes, - int bytesPerLine = 16, - bool showHeader = true, - bool showOffset = true, - bool showAscii = true) - { - return new HexUtils(bytes, bytesPerLine, showHeader, showOffset, showAscii).Dump(); - } - - private static string Translate(byte b) - { - return b < 32 ? "." : Encoding.ASCII.GetString(new[] { b }); - } - - private string Dump() - { - if (this.showHeader) - { - this.WriteHeader(); - } - - this.WriteBody(); - return this.sb.ToString(); - } - - private void WriteHeader() - { - if (this.showOffset) - { - this.sb.Append("Offset(h) "); - } - - for (int i = 0; i < this.bytesPerLine; i++) - { - this.sb.Append($"{i & 0xFF:X2}"); - if (i + 1 < this.bytesPerLine) - { - this.sb.Append(' '); - } - } - - this.sb.AppendLine(); - } - - private void WriteBody() - { - while (this.index < this.bytes.Length) - { - if (this.index % this.bytesPerLine == 0) - { - if (this.index > 0) - { - if (this.showAscii) - { - this.WriteAscii(); - } - - this.sb.AppendLine(); - } - - if (this.showOffset) - { - this.WriteOffset(); - } - } - - this.WriteByte(); - if (this.index % this.bytesPerLine != 0 && this.index < this.bytes.Length) - { - this.sb.Append(' '); - } - } - - if (this.showAscii) - { - this.WriteAscii(); - } - } - - private void WriteOffset() - { - this.sb.Append($"{this.index:X8} "); - } - - private void WriteByte() - { - this.sb.Append($"{this.bytes.Span[this.index]:X2}"); - this.index++; - } - - private void WriteAscii() - { - int backtrack = ((this.index - 1) / this.bytesPerLine) * this.bytesPerLine; - int length = this.index - backtrack; - - // This is to fill up last string of the dump if it's shorter than _bytesPerLine - this.sb.Append(new string(' ', (this.bytesPerLine - length) * 3)); - - this.sb.Append(" "); - for (int i = 0; i < length; i++) - { - this.sb.Append(Translate(this.bytes.Span[backtrack + i])); - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClient.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClient.cs deleted file mode 100644 index 5feb17d2..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClient.cs +++ /dev/null @@ -1,130 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.Concurrent; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; -using System.Threading.Tasks.Dataflow; -using Microsoft.Extensions.Logging; - -namespace GeothermalResearchInstitute.PlcV2 -{ - public partial class PlcClient : IDisposable - { - private readonly ILogger logger; - - private readonly TcpClient tcpClient; - - private readonly BufferBlock requestContextSendingBufferBlock = - new BufferBlock(new DataflowBlockOptions - { - BoundedCapacity = 100, - EnsureOrdered = false, - TaskScheduler = TaskScheduler.Default, - }); - - private readonly Task sendingBackgroundTask; - private readonly Task receivingBackgroundTask; - private readonly Task deadlineBackgroundTask; - private readonly SemaphoreSlim mutex = new SemaphoreSlim(1); - private readonly CancellationTokenSource closingCancellationTokenSource = new CancellationTokenSource(); - - private readonly ConcurrentDictionary requestContextReceivingDictionary = - new ConcurrentDictionary(); - - private int sequenceNumberGenerator = 0; - private bool disposedValue = false; - - public PlcClient(ILogger logger, TcpClient tcpClient) - { - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.tcpClient = tcpClient ?? throw new ArgumentNullException(nameof(tcpClient)); - this.RemoteEndPoint = tcpClient.Client.RemoteEndPoint; - - this.sendingBackgroundTask = Task.Factory.StartNew( - this.SendingBackgroundTaskEntryPoint, - CancellationToken.None, - TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, - TaskScheduler.Default); - this.receivingBackgroundTask = Task.Factory.StartNew( - this.ReceivingBackgroundTaskEntryPoint, - CancellationToken.None, - TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, - TaskScheduler.Default); - this.deadlineBackgroundTask = Task.Factory.StartNew( - this.DeadlineBackgroundTaskEntryPoint, - CancellationToken.None, - TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, - TaskScheduler.Default); - } - - ~PlcClient() - { - this.Dispose(false); - } - - public event EventHandler OnClosed; - - public event EventHandler OnDebugSending; - - public event EventHandler OnDebugReceiving; - - public EndPoint RemoteEndPoint { get; } - - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - public async Task Close() - { - await this.mutex.WaitAsync().ConfigureAwait(false); - try - { - if (!this.closingCancellationTokenSource.IsCancellationRequested) - { - this.closingCancellationTokenSource.Cancel(); - this.requestContextSendingBufferBlock.Complete(); - - await this.sendingBackgroundTask.ConfigureAwait(false); - await this.receivingBackgroundTask.ConfigureAwait(false); - await this.deadlineBackgroundTask.ConfigureAwait(false); - - this.tcpClient.Close(); - this.OnClosed?.Invoke(this, EventArgs.Empty); - } - } - finally - { - this.mutex.Release(); - } - } - - protected virtual void Dispose(bool disposing) - { - if (!this.disposedValue) - { - if (disposing) - { - this.Close().GetAwaiter().GetResult(); - - this.sendingBackgroundTask.Dispose(); - this.receivingBackgroundTask.Dispose(); - this.deadlineBackgroundTask.Dispose(); - - this.tcpClient.Dispose(); - this.closingCancellationTokenSource.Dispose(); - this.mutex.Dispose(); - } - - this.disposedValue = true; - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClientApi.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClientApi.cs deleted file mode 100644 index b84ce081..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClientApi.cs +++ /dev/null @@ -1,454 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Buffers.Binary; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using System.Threading.Tasks.Dataflow; -using GeothermalResearchInstitute.v2; -using Google.Protobuf; -using Google.Protobuf.WellKnownTypes; -using Grpc.Core; - -namespace GeothermalResearchInstitute.PlcV2 -{ - public partial class PlcClient - { - public async Task ConnectAsync(ConnectRequest request, DateTime? deadline) - { - if (request is null) - { - throw new ArgumentNullException(nameof(request)); - } - - PlcFrame response = await this.InvokeAsync( - PlcFrame.Create(PlcMessageType.ConnectRequest, ByteString.Empty), - deadline) - .ConfigureAwait(false); - if (response.FrameHeader.MessageType != PlcMessageType.ConnectResponse) - { - throw new InvalidDataException( - "Response message type mismatch: " + response.FrameHeader.MessageType); - } - - return new ConnectResponse - { - Id = response.FrameBody, - }; - } - - public async Task GetMetricAsync(GetMetricRequest request, DateTime? deadline) - { - if (request is null) - { - throw new ArgumentNullException(nameof(request)); - } - - PlcFrame response = await this.InvokeAsync( - PlcFrame.Create(PlcMessageType.GetMetricRequest, ByteString.Empty), - deadline) - .ConfigureAwait(false); - if (response.FrameHeader.MessageType != PlcMessageType.GetMetricResponse) - { - throw new InvalidDataException( - "Response message type mismatch: " + response.FrameHeader.MessageType); - } - - using var reader = new BinaryReader(new MemoryStream(response.FrameBody.ToByteArray())); - return new Metric - { - CreateTime = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow), - OutputWaterCelsiusDegree = reader.ReadSingle(), - InputWaterCelsiusDegree = reader.ReadSingle(), - HeaterOutputWaterCelsiusDegree = reader.ReadSingle(), - EnvironmentCelsiusDegree = reader.ReadSingle(), - OutputWaterPressureMeter = reader.ReadSingle(), - InputWaterPressureMeter = reader.ReadSingle(), - HeaterPowerKilowatt = reader.ReadSingle(), - WaterPumpFlowRateCubicMeterPerHour = reader.ReadSingle(), - }; - } - - public async Task GetSwitchAsync(GetSwitchRequest request, DateTime? deadline) - { - if (request is null) - { - throw new ArgumentNullException(nameof(request)); - } - - PlcFrame response = await this.InvokeAsync( - PlcFrame.Create(PlcMessageType.GetSwitchRequest, ByteString.Empty), - deadline) - .ConfigureAwait(false); - if (response.FrameHeader.MessageType != PlcMessageType.GetSwitchResponse) - { - throw new InvalidDataException( - "Response message type mismatch: " + response.FrameHeader.MessageType); - } - - using var reader = new BinaryReader(new MemoryStream(response.FrameBody.ToByteArray())); - return new Switch - { - DevicePowerOn = reader.ReadByte() != 0, - ExhausterPowerOn = reader.ReadByte() != 0, - HeaterAutoOn = reader.ReadByte() != 0, - HeaterPowerOn = reader.ReadByte() != 0, - HeaterFanOn = reader.ReadByte() != 0, - HeaterCompressorOn = reader.ReadByte() != 0, - HeaterFourWayReversingOn = reader.ReadByte() != 0, - }; - } - - public async Task UpdateSwitchAsync(UpdateSwitchRequest request, DateTime? deadline) - { - if (request is null) - { - throw new ArgumentNullException(nameof(request)); - } - - if (request.UpdateMask.Paths.Count != 1) - { - throw new ArgumentException("Update not exact 1 field", nameof(request)); - } - - byte[] bytes = new byte[0x07]; - switch (request.UpdateMask.Paths.Single()) - { - case "device_power_on": - bytes[0] = (byte)(0x10 | (request.Switch.DevicePowerOn ? 1 : 0)); - break; - case "exhauster_power_on": - bytes[1] = (byte)(0x10 | (request.Switch.ExhausterPowerOn ? 1 : 0)); - break; - case "heater_auto_on": - bytes[2] = (byte)(0x10 | (request.Switch.HeaterAutoOn ? 1 : 0)); - break; - case "heater_power_on": - bytes[3] = (byte)(0x10 | (request.Switch.HeaterPowerOn ? 1 : 0)); - break; - case "heater_fan_on": - bytes[4] = (byte)(0x10 | (request.Switch.HeaterFanOn ? 1 : 0)); - break; - case "heater_compressor_on": - bytes[5] = (byte)(0x10 | (request.Switch.HeaterCompressorOn ? 1 : 0)); - break; - case "heater_four_way_reversing_on": - bytes[6] = (byte)(0x10 | (request.Switch.HeaterFourWayReversingOn ? 1 : 0)); - break; - default: - throw new InvalidDataException("Unrecognized update mask " + request.UpdateMask.Paths.Single()); - } - - PlcFrame response = await this.InvokeAsync( - PlcFrame.Create(PlcMessageType.UpdateSwitchRequest, ByteString.CopyFrom(bytes)), - deadline) - .ConfigureAwait(false); - if (response.FrameHeader.MessageType != PlcMessageType.GetSwitchResponse) - { - throw new InvalidDataException( - "Response message type mismatch: " + response.FrameHeader.MessageType); - } - - using var reader = new BinaryReader(new MemoryStream(response.FrameBody.ToByteArray())); - return new Switch - { - DevicePowerOn = reader.ReadByte() != 0, - ExhausterPowerOn = reader.ReadByte() != 0, - HeaterAutoOn = reader.ReadByte() != 0, - HeaterPowerOn = reader.ReadByte() != 0, - HeaterFanOn = reader.ReadByte() != 0, - HeaterCompressorOn = reader.ReadByte() != 0, - HeaterFourWayReversingOn = reader.ReadByte() != 0, - }; - } - - public async Task GetWorkingModeAsync(GetWorkingModeRequest request, DateTime? deadline) - { - if (request is null) - { - throw new ArgumentNullException(nameof(request)); - } - - PlcFrame response = await this.InvokeAsync( - PlcFrame.Create(PlcMessageType.GetWorkingModeRequest, ByteString.Empty), - deadline) - .ConfigureAwait(false); - if (response.FrameHeader.MessageType != PlcMessageType.GetWorkingModeResponse) - { - throw new InvalidDataException( - "Response message type mismatch: " + response.FrameHeader.MessageType); - } - - using var reader = new BinaryReader(new MemoryStream(response.FrameBody.ToByteArray())); - return new WorkingMode - { - DeviceWorkingMode = (DeviceWorkingMode)reader.ReadByte(), - DeviceFlowRateControlMode = (DeviceFlowRateControlMode)reader.ReadByte(), - WaterPumpWorkingMode = (WaterPumpWorkingMode)reader.ReadByte(), - }; - } - - public async Task UpdateWorkingModeAsync(UpdateWorkingModeRequest request, DateTime? deadline) - { - if (request is null) - { - throw new ArgumentNullException(nameof(request)); - } - - byte[] bytes = new byte[0x03]; - foreach (string path in request.UpdateMask.Paths) - { - switch (path) - { - case "device_working_mode": - bytes[0] = (byte)request.WorkingMode.DeviceWorkingMode; - break; - case "device_flow_rate_control_mode": - bytes[1] = (byte)request.WorkingMode.DeviceFlowRateControlMode; - break; - case "water_pump_working_mode": - bytes[2] = (byte)request.WorkingMode.WaterPumpWorkingMode; - break; - default: - throw new InvalidDataException("Unrecognized update mask " + path); - } - } - - PlcFrame response = await this.InvokeAsync( - PlcFrame.Create(PlcMessageType.UpdateWorkingModeRequest, ByteString.CopyFrom(bytes)), - deadline) - .ConfigureAwait(false); - if (response.FrameHeader.MessageType != PlcMessageType.GetWorkingModeResponse) - { - throw new InvalidDataException( - "Response message type mismatch: " + response.FrameHeader.MessageType); - } - - using var reader = new BinaryReader(new MemoryStream(response.FrameBody.ToByteArray())); - return new WorkingMode - { - DeviceWorkingMode = (DeviceWorkingMode)reader.ReadByte(), - DeviceFlowRateControlMode = (DeviceFlowRateControlMode)reader.ReadByte(), - WaterPumpWorkingMode = (WaterPumpWorkingMode)reader.ReadByte(), - }; - } - - public async Task GetAlarmAsync(GetAlarmRequest request, DateTime? deadline) - { - if (request is null) - { - throw new ArgumentNullException(nameof(request)); - } - - PlcFrame response = await this.InvokeAsync( - PlcFrame.Create(PlcMessageType.GetAlarmRequest, ByteString.Empty), - deadline) - .ConfigureAwait(false); - if (response.FrameHeader.MessageType != PlcMessageType.GetAlarmResponse) - { - throw new InvalidDataException( - "Response message type mismatch: " + response.FrameHeader.MessageType); - } - - using var reader = new BinaryReader(new MemoryStream(response.FrameBody.ToByteArray())); - return new Alarm - { - CreateTime = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow), - LowFlowRate = reader.ReadByte() != 0, - HighHeaterPressure = reader.ReadByte() != 0, - LowHeaterPressure = reader.ReadByte() != 0, - NoPower = reader.ReadByte() != 0, - HeaterOverloadedBroken = reader.ReadByte() != 0, - ElectricalHeaterBroken = reader.ReadByte() != 0, - NoWater = reader.ReadByte() == 0, - HighVoltage = reader.ReadByte() == 0, - LowVoltage = reader.ReadByte() == 0, - EmergencyStopped = reader.ReadByte() == 0, - }; - } - - public async Task GetRunningParameterAsync( - GetRunningParameterRequest request, - DateTime? deadline) - { - if (request is null) - { - throw new ArgumentNullException(nameof(request)); - } - - PlcFrame response = await this.InvokeAsync( - PlcFrame.Create(PlcMessageType.GetRunningParameterRequest, ByteString.Empty), - deadline) - .ConfigureAwait(false); - if (response.FrameHeader.MessageType != PlcMessageType.GetRunningParameterResponse) - { - throw new InvalidDataException( - "Response message type mismatch: " + response.FrameHeader.MessageType); - } - - using var reader = new BinaryReader(new MemoryStream(response.FrameBody.ToByteArray())); - return new RunningParameter - { - SummerHeaterCelsiusDegree = reader.ReadSingle(), - WinterHeaterCelsiusDegree = reader.ReadSingle(), - ColdPowerKilowatt = reader.ReadSingle(), - WarmPowerKilowatt = reader.ReadSingle(), - WaterPumpFlowRateCubicMeterPerHour = reader.ReadSingle(), - WaterPumpFrequencyHertz = reader.ReadSingle(), - }; - } - - public async Task UpdateRunningParameterAsync( - UpdateRunningParameterRequest request, - DateTime? deadline) - { - if (request is null) - { - throw new ArgumentNullException(nameof(request)); - } - - if (request.UpdateMask == null) - { - request.UpdateMask = FieldMask.FromFieldNumbers( - RunningParameter.Descriptor.Fields.InFieldNumberOrder().Select(f => f.FieldNumber)); - } - - byte[] bytes = new byte[0x18]; - for (int i = 0; i < 0x18; i++) - { - bytes[i] = 0xFF; - } - - foreach (string path in request.UpdateMask.Paths) - { - switch (path) - { - case "summer_heater_celsius_degree": - if (!TryWriteBytes( - bytes.AsSpan(0, 4), - request.RunningParameter.SummerHeaterCelsiusDegree)) - { - throw new InvalidOperationException(); - } - - break; - case "winter_heater_celsius_degree": - if (!TryWriteBytes( - bytes.AsSpan(4, 4), - request.RunningParameter.WinterHeaterCelsiusDegree)) - { - throw new InvalidOperationException(); - } - - break; - case "cold_power_kilowatt": - if (!TryWriteBytes( - bytes.AsSpan(8, 4), - request.RunningParameter.ColdPowerKilowatt)) - { - throw new InvalidOperationException(); - } - - break; - case "warm_power_kilowatt": - if (!TryWriteBytes( - bytes.AsSpan(12, 4), - request.RunningParameter.WarmPowerKilowatt)) - { - throw new InvalidOperationException(); - } - - break; - case "water_pump_flow_rate_cubic_meter_per_hour": - if (!TryWriteBytes( - bytes.AsSpan(16, 4), - request.RunningParameter.WaterPumpFlowRateCubicMeterPerHour)) - { - throw new InvalidOperationException(); - } - - break; - case "water_pump_frequency_hertz": - if (!TryWriteBytes( - bytes.AsSpan(20, 4), - request.RunningParameter.WaterPumpFrequencyHertz)) - { - throw new InvalidOperationException(); - } - - break; - default: - throw new InvalidDataException("Unrecognized update mask " + path); - } - } - - PlcFrame response = await this.InvokeAsync( - PlcFrame.Create(PlcMessageType.UpdateRunningParameterRequest, ByteString.CopyFrom(bytes)), - deadline) - .ConfigureAwait(false); - if (response.FrameHeader.MessageType != PlcMessageType.GetRunningParameterResponse) - { - throw new InvalidDataException( - "Response message type mismatch: " + response.FrameHeader.MessageType); - } - - using var reader = new BinaryReader(new MemoryStream(response.FrameBody.ToByteArray())); - return new RunningParameter - { - SummerHeaterCelsiusDegree = reader.ReadSingle(), - WinterHeaterCelsiusDegree = reader.ReadSingle(), - ColdPowerKilowatt = reader.ReadSingle(), - WarmPowerKilowatt = reader.ReadSingle(), - WaterPumpFlowRateCubicMeterPerHour = reader.ReadSingle(), - WaterPumpFrequencyHertz = reader.ReadSingle(), - }; - } - - private static bool TryWriteBytes(Span destination, float value) - { -#if NET48 - if (destination.Length < sizeof(float)) - { - return false; - } - - byte[] bytes = BitConverter.GetBytes(value); - destination[0] = bytes[0]; - destination[1] = bytes[1]; - destination[2] = bytes[2]; - destination[3] = bytes[3]; - - return true; -#else - return BitConverter.TryWriteBytes(destination, value); -#endif - } - - private Task InvokeAsync(PlcFrame request, DateTime? deadline) - { - if (this.closingCancellationTokenSource.IsCancellationRequested) - { - return Task.FromException(new RpcException(Status.DefaultCancelled)); - } - - var promise = new TaskCompletionSource(); - bool accepted = this.requestContextSendingBufferBlock.Post(new PlcRequestContext - { - TaskCompletionSource = promise, - RequestFrame = request, - Deadline = deadline, - }); - - if (!accepted) - { - promise.SetException(new RpcException(Status.DefaultCancelled)); - } - - return promise.Task; - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClientDeadline.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClientDeadline.cs deleted file mode 100644 index e828cfa9..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClientDeadline.cs +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.Generic; -using System.Threading; -using Grpc.Core; -using Microsoft.Extensions.Logging; - -namespace GeothermalResearchInstitute.PlcV2 -{ - public partial class PlcClient - { - private void DeadlineBackgroundTaskEntryPoint() - { - CancellationToken closingCancellationToken = this.closingCancellationTokenSource.Token; - while (!closingCancellationToken.WaitHandle.WaitOne(300)) - { - DateTime now = DateTime.UtcNow; - foreach (KeyValuePair entry in this.requestContextReceivingDictionary) - { - if (entry.Value.Deadline < now) - { - if (this.requestContextReceivingDictionary.TryRemove( - entry.Key, - out PlcRequestContext requestContext)) - { - this.logger.LogWarning( - "Request {0} to {1} exceed deadline, deadline={2:u}, now1={3:u}, now2={4:u}", - entry.Key, - this.RemoteEndPoint, - entry.Value.Deadline, - now, - DateTime.UtcNow); - requestContext.TaskCompletionSource.TrySetException(new RpcException(new Status( - StatusCode.DeadlineExceeded, string.Empty))); - } - } - } - } - - foreach (KeyValuePair entry in this.requestContextReceivingDictionary) - { - if (this.requestContextReceivingDictionary.TryRemove(entry.Key, out PlcRequestContext requestContext)) - { - requestContext.TaskCompletionSource.TrySetException(new RpcException(Status.DefaultCancelled)); - } - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClientReceiving.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClientReceiving.cs deleted file mode 100644 index 12aafd57..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClientReceiving.cs +++ /dev/null @@ -1,99 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.IO; -using System.Text; -using System.Threading; -using Google.Protobuf; -using Grpc.Core; -using Microsoft.Extensions.Logging; - -namespace GeothermalResearchInstitute.PlcV2 -{ - public partial class PlcClient - { - private void ReceivingBackgroundTaskEntryPoint() - { - CancellationToken closingCancellationToken = this.closingCancellationTokenSource.Token; - using var reader = new BinaryReader(this.tcpClient.GetStream(), Encoding.ASCII, true); - try - { - while (!closingCancellationToken.IsCancellationRequested) - { - byte[] headerBytes = reader.ReadBytes(20); - if (headerBytes.Length != 20) - { - throw new IOException("Failed to read frame header"); - } - - var header = PlcFrameHeader.Parse(headerBytes); - if (header.ContentOffset != 20) - { - throw new InvalidDataException("Content offset is not 20"); - } - - byte[] bodyBytes = reader.ReadBytes(header.ContentLength); - if (bodyBytes.Length != header.ContentLength) - { - throw new IOException("Failed to read frame body"); - } - - if (this.logger.IsEnabled(LogLevel.Debug)) - { - byte[] buffer = new byte[headerBytes.Length + bodyBytes.Length]; - Buffer.BlockCopy(headerBytes, 0, buffer, 0, headerBytes.Length); - Buffer.BlockCopy(bodyBytes, 0, buffer, headerBytes.Length, bodyBytes.Length); - - this.logger.LogDebug( - "Received {0} from {1}{2}{3}", - header.SequenceNumber, - this.RemoteEndPoint, - Environment.NewLine, - HexUtils.Dump(buffer)); - this.OnDebugReceiving?.Invoke(this, buffer); - } - - if (this.requestContextReceivingDictionary.TryRemove( - (int)header.SequenceNumber, - out PlcRequestContext requestContext)) - { - if (header.Crc32cChecksum != 0 - && header.Crc32cChecksum != Crc32C.Crc32CAlgorithm.Compute(bodyBytes)) - { - this.logger.LogWarning( - "Received frame crc32c checksum mismatch from {0}", - this.RemoteEndPoint); - requestContext.TaskCompletionSource.TrySetException(new RpcException( - new Status(StatusCode.Internal, "Data transfer error, checksum mismatch."))); - } - else - { - requestContext.TaskCompletionSource.TrySetResult(new PlcFrame - { - FrameHeader = header, - FrameBody = ByteString.CopyFrom(bodyBytes), - }); - } - } - else - { - this.logger.LogWarning("Received unknown sequence number from {0}", this.RemoteEndPoint); - } - } - } - catch (IOException e) - { - this.logger.LogError(e, "Failed to receiving from {0}", this.RemoteEndPoint); - this.Close().ConfigureAwait(false).GetAwaiter().GetResult(); - } - catch (InvalidDataException e) - { - this.logger.LogError(e, "Received invalid data from {0}", this.RemoteEndPoint); - this.Close().ConfigureAwait(false).GetAwaiter().GetResult(); - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClientSending.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClientSending.cs deleted file mode 100644 index 14f844e5..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcClientSending.cs +++ /dev/null @@ -1,82 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks.Dataflow; -using Grpc.Core; -using Microsoft.Extensions.Logging; - -namespace GeothermalResearchInstitute.PlcV2 -{ - public partial class PlcClient - { - private async void SendingBackgroundTaskEntryPoint() - { - try - { - while (await this.requestContextSendingBufferBlock - .OutputAvailableAsync() - .ConfigureAwait(false)) - { - DateTime utcNow = DateTime.UtcNow; - while (this.requestContextSendingBufferBlock.TryReceive(out PlcRequestContext requestContext)) - { - this.ProcessRequest(utcNow, requestContext); - } - } - } - catch (IOException e) - { - this.logger.LogError(e, "Failed to send message to {0}", this.RemoteEndPoint); - this.Close().ConfigureAwait(false).GetAwaiter().GetResult(); - } - } - - private void ProcessRequest(DateTime utcNow, PlcRequestContext requestContext) - { - if (requestContext.Deadline?.ToUniversalTime() < utcNow) - { - this.logger.LogDebug( - "Request deadline exceeded, deadline={0:u}, now1={1:u}, now2={2:u}", - requestContext.Deadline, - utcNow, - DateTime.UtcNow); - requestContext.TaskCompletionSource.SetException(new RpcException( - new Status(StatusCode.DeadlineExceeded, string.Empty))); - return; - } - - int sequenceNumber = Interlocked.Increment(ref this.sequenceNumberGenerator); - requestContext.RequestFrame.FrameHeader.SequenceNumber = (uint)sequenceNumber; - - if (!this.requestContextReceivingDictionary.TryAdd(sequenceNumber, requestContext)) - { - throw new InvalidOperationException(); // Should not happen. - } - - if (this.logger.IsEnabled(LogLevel.Debug)) - { - using var stream = new MemoryStream(); - requestContext.RequestFrame.WriteTo(stream); - this.logger.LogDebug( - "Sending {0} to {1}{2}{3}", - sequenceNumber, - this.RemoteEndPoint, - Environment.NewLine, - HexUtils.Dump(stream.ToArray())); - this.OnDebugSending?.Invoke(this, stream.ToArray()); - - stream.Seek(0, SeekOrigin.Begin); - stream.CopyTo(this.tcpClient.GetStream()); - } - else - { - requestContext.RequestFrame.WriteTo(this.tcpClient.GetStream()); - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcFrame.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcFrame.cs deleted file mode 100644 index c3eb303f..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcFrame.cs +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System.IO; -using Google.Protobuf; - -namespace GeothermalResearchInstitute.PlcV2 -{ - public class PlcFrame - { - public PlcFrameHeader FrameHeader { get; set; } - - public ByteString FrameBody { get; set; } - - public static PlcFrame Create(PlcMessageType messageType, ByteString messageBody) - { - if (messageBody is null) - { - throw new System.ArgumentNullException(nameof(messageBody)); - } - - return new PlcFrame - { - FrameHeader = new PlcFrameHeader - { - MessageType = messageType, - }, - FrameBody = messageBody, - }; - } - - public void WriteTo(Stream outputStream) - { - this.FrameHeader.Crc32cChecksum = this.FrameBody.IsEmpty - ? 0 - : Crc32C.Crc32CAlgorithm.Compute(this.FrameBody.ToByteArray()); - this.FrameHeader.ContentOffset = 0x14; - this.FrameHeader.ContentLength = (ushort)this.FrameBody.Length; - - this.FrameHeader.WriteTo(outputStream); - this.FrameBody.WriteTo(outputStream); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcFrameHeader.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcFrameHeader.cs deleted file mode 100644 index 28d20517..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcFrameHeader.cs +++ /dev/null @@ -1,69 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Buffers.Binary; -using System.IO; -using System.Text; - -namespace GeothermalResearchInstitute.PlcV2 -{ - public class PlcFrameHeader - { - public PlcMessageType MessageType { get; set; } - - public uint SequenceNumber { get; set; } - - public uint Crc32cChecksum { get; set; } - - public ushort ContentOffset { get; set; } - - public ushort ContentLength { get; set; } - - public static PlcFrameHeader Parse(ReadOnlySpan bytes) - { - if (bytes.Length != 20) - { - throw new ArgumentException("Header must has 20 bytes", nameof(bytes)); - } - - byte version = bytes[0x04]; - if (version != 0x02) - { - throw new InvalidDataException("Header version must be 2, but " + version + " received."); - } - - return new PlcFrameHeader - { - MessageType = (PlcMessageType)BinaryPrimitives.ReadUInt16BigEndian(bytes.Slice(0x06, 2)), - SequenceNumber = BinaryPrimitives.ReadUInt32BigEndian(bytes.Slice(0x08, 4)), - Crc32cChecksum = BinaryPrimitives.ReadUInt32BigEndian(bytes.Slice(0x0C, 4)), - ContentOffset = BinaryPrimitives.ReadUInt16BigEndian(bytes.Slice(0x10, 2)), - ContentLength = BinaryPrimitives.ReadUInt16BigEndian(bytes.Slice(0x12, 2)), - }; - } - - public void WriteTo(Stream outputStream) - { - using var writer = new BinaryWriter(outputStream, Encoding.ASCII, true); - - writer.Write('D'); - writer.Write('R'); - writer.Write('Y'); - writer.Write((byte)0x00); - - writer.Write((byte)0x02); - writer.Write((byte)0x00); - writer.Write(BinaryPrimitives.ReverseEndianness((ushort)this.MessageType)); - - writer.Write(BinaryPrimitives.ReverseEndianness(this.SequenceNumber)); - - writer.Write(BinaryPrimitives.ReverseEndianness(this.Crc32cChecksum)); - - writer.Write(BinaryPrimitives.ReverseEndianness(this.ContentOffset)); - writer.Write(BinaryPrimitives.ReverseEndianness(this.ContentLength)); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcMessageType.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcMessageType.cs deleted file mode 100644 index 3a1a2f10..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcMessageType.cs +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System.Diagnostics.CodeAnalysis; - -namespace GeothermalResearchInstitute.PlcV2 -{ - [SuppressMessage("Design", "CA1028:枚举存储应为 Int32", Justification = "业务需求")] - public enum PlcMessageType : ushort - { - ConnectRequest = 0x0100, - ConnectResponse = 0x0101, - GetMetricRequest = 0x0200, - GetMetricResponse = 0x0201, - GetSwitchRequest = 0x0300, - GetSwitchResponse = 0x0301, - UpdateSwitchRequest = 0x0400, - GetRunningParameterRequest = 0x0500, - GetRunningParameterResponse = 0x0501, - UpdateRunningParameterRequest = 0x0600, - GetWorkingModeRequest = 0x0700, - GetWorkingModeResponse = 0x0701, - UpdateWorkingModeRequest = 0x0800, - GetAlarmRequest = 0x0900, - GetAlarmResponse = 0x0901, - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcRequestContext.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcRequestContext.cs deleted file mode 100644 index cd8cd3a1..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcRequestContext.cs +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Threading.Tasks; - -namespace GeothermalResearchInstitute.PlcV2 -{ - public class PlcRequestContext - { - public TaskCompletionSource TaskCompletionSource { get; set; } - - public PlcFrame RequestFrame { get; set; } - - public DateTime? Deadline { get; set; } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcServer.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcServer.cs deleted file mode 100644 index 733719b3..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/PlcServer.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Net; -using System.Net.Sockets; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; - -namespace GeothermalResearchInstitute.PlcV2 -{ - public class PlcServer - { - private readonly ILoggerFactory loggerFactory; - private readonly TcpListener tcpListener; - - public PlcServer(ILoggerFactory loggerFactory, IPAddress ipAddress, int port) - { - this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); - this.tcpListener = new TcpListener(ipAddress, port); - } - - public EndPoint LocalEndPoint => this.tcpListener.LocalEndpoint; - - public void Start() - { - this.tcpListener.Start(20); - } - - public void Stop() - { - this.tcpListener.Stop(); - } - - public async Task AcceptAsync() - { - TcpClient tcpClient = await this.tcpListener - .AcceptTcpClientAsync() - .ConfigureAwait(false); - return new PlcClient(this.loggerFactory.CreateLogger(), tcpClient); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/packages.lock.json b/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/packages.lock.json deleted file mode 100644 index a13e89c0..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.PlcV2/packages.lock.json +++ /dev/null @@ -1,173 +0,0 @@ -{ - "version": 2, - "dependencies": { - "net6.0": { - "DotNet.ReproducibleBuilds": { - "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==", - "dependencies": { - "Microsoft.SourceLink.AzureRepos.Git": "1.1.1", - "Microsoft.SourceLink.Bitbucket.Git": "1.1.1", - "Microsoft.SourceLink.GitHub": "1.1.1", - "Microsoft.SourceLink.GitLab": "1.1.1" - } - }, - "Microsoft.CodeAnalysis.BannedApiAnalyzers": { - "type": "Direct", - "requested": "[3.3.3, )", - "resolved": "3.3.3", - "contentHash": "vvz3XCHVrd/Ks4xPoutLmL/T2+8JcOk/OMs3ngwQqnzokQCGEDsY+WjK/txCsDWU29sX3fGzH/FnYwNV93O1mA==" - }, - "Microsoft.CodeAnalysis.NetAnalyzers": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "cjG06LMeOADNUeCUaklOfVgrnVkLy80H5PVll4QHDUXv+C+6G9rHczrNdWjfb3xKv3Ts9s4UsP6J2ZWe52Gz4Q==" - }, - "Microsoft.Extensions.Logging.Abstractions": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA==" - }, - "Microsoft.NETFramework.ReferenceAssemblies": { - "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", - "dependencies": { - "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3" - } - }, - "Microsoft.SourceLink.GitHub": { - "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Nerdbank.GitVersioning": { - "type": "Direct", - "requested": "[3.5.113, )", - "resolved": "3.5.113", - "contentHash": "4fBSMkqhi410qlkjPm+Mxfk8iO3C7dmgdVS7ljsfVO21WEzZCHP1VCOqB6rlOPfPidR/oxX+/Do/I7meCAz+Jg==" - }, - "StyleCop.Analyzers": { - "type": "Direct", - "requested": "[1.2.0-beta.435, )", - "resolved": "1.2.0-beta.435", - "contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==", - "dependencies": { - "StyleCop.Analyzers.Unstable": "1.2.0.435" - } - }, - "System.Memory": { - "type": "Direct", - "requested": "[4.5.5, )", - "resolved": "4.5.5", - "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" - }, - "System.Threading.Tasks.Dataflow": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" - }, - "Grpc.Core.Api": { - "type": "Transitive", - "resolved": "2.46.3", - "contentHash": "uy1oe5baVa4V+C8ZyMiA8xYdNIx5A3PiacQL0f1zWDjF2z64Cb1MMXXRTs3GX+jeKpoK/RtOZg8UnJSm2KC/pQ==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" - }, - "Microsoft.NETFramework.ReferenceAssemblies.net461": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==" - }, - "Microsoft.SourceLink.AzureRepos.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Bitbucket.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==" - }, - "Microsoft.SourceLink.GitLab": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "StyleCop.Analyzers.Unstable": { - "type": "Transitive", - "resolved": "1.2.0.435", - "contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg==" - }, - "crc32c.net": { - "type": "Project" - }, - "geothermalresearchinstitute.grpc": { - "type": "Project", - "dependencies": { - "Google.Protobuf": "[3.21.6, )", - "Grpc": "[2.46.3, )" - } - }, - "Google.Protobuf": { - "type": "CentralTransitive", - "requested": "[3.21.6, )", - "resolved": "3.21.6", - "contentHash": "HSYHFnfuTu/O4Ijy0mCW9zxLI8MJfCZJ10dk3JGPrkLaRR4LsiPKzZrrnapf2G0tP2yRMkHCl+2LKLTXqGBn2A==" - }, - "Grpc": { - "type": "CentralTransitive", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "79TsAcLBVl5J7AmtnV+GmgkhWlpK3D9JYJDhYxZGO0DKukbyrRxxcbaFlRZ84WGwTAW8LezrInUYgfiJi3zGVg==", - "dependencies": { - "Grpc.Core": "2.46.3" - } - }, - "Grpc.Core": { - "type": "CentralTransitive", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "lu7KP7BVWdvFXWbn/IFYHBQCpMohJwbLM1aL+nu2C0pY2CdS0idaUNAJNC2nZ60fXfqoxnSiERrIU6rC474oTw==", - "dependencies": { - "Grpc.Core.Api": "2.46.3", - "System.Memory": "4.5.3" - } - } - } - } -} \ No newline at end of file diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/FakeDevicesHostedService.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/FakeDevicesHostedService.cs deleted file mode 100644 index c056a8b2..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/FakeDevicesHostedService.cs +++ /dev/null @@ -1,76 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using GeothermalResearchInstitute.FakePlcV2; -using GeothermalResearchInstitute.ServerConsole.Options; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; - -namespace GeothermalResearchInstitute.ServerConsole -{ - [SuppressMessage("Microsoft.Performance", "CA1812", Justification = "Instantiated with reflection.")] - internal class FakeDevicesHostedService : IHostedService, IDisposable - { - private readonly IOptions coreOptions; - private readonly FakePlc[] fakePlcList; - private bool disposedValue = false; - - public FakeDevicesHostedService( - IOptions coreOptions, - IOptions deviceOptions) - { - this.coreOptions = coreOptions; - this.fakePlcList = deviceOptions.Value.Devices - .Select(d => new FakePlc(d.ComputeIdBinary())) - .Take(coreOptions.Value.MaxFakeDeviceNum) - .ToArray(); - } - - public async Task StartAsync(CancellationToken cancellationToken) - { - int port = this.coreOptions.Value.TcpPort; - foreach (FakePlc plc in this.fakePlcList) - { - await plc.StartAsync(IPAddress.Loopback, port).ConfigureAwait(false); - } - } - - public async Task StopAsync(CancellationToken cancellationToken) - { - foreach (FakePlc plc in this.fakePlcList) - { - await plc.StopAsync().ConfigureAwait(false); - } - } - - public void Dispose() - { - this.Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (!this.disposedValue) - { - if (disposing) - { - foreach (FakePlc plc in this.fakePlcList) - { - plc.StopAsync().ConfigureAwait(false).GetAwaiter().GetResult(); - plc.Dispose(); - } - } - - this.disposedValue = true; - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/GeothermalResearchInstitute.ServerConsole.csproj b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/GeothermalResearchInstitute.ServerConsole.csproj deleted file mode 100644 index 9723a7ad..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/GeothermalResearchInstitute.ServerConsole.csproj +++ /dev/null @@ -1,80 +0,0 @@ - - - - - Exe - $(CurrentTargetFramework) - - win-x64 - true - False - False - False - - $(BaseArtifactsPath)\GeothermalResearchInstitute.ServerConsole - $(DefaultArtifactsFileMatch) *.ini *.sqlite - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - true - - - PreserveNewest - true - - - - - - - - - - PreserveNewest - true - - - PreserveNewest - true - - - - - - - Always - true - - - - diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/GrpcHostedService.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/GrpcHostedService.cs deleted file mode 100644 index bdf6fc7c..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/GrpcHostedService.cs +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Grpc.Core; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace GeothermalResearchInstitute.ServerConsole -{ - public class GrpcHostedService : IHostedService - { - private readonly ILogger logger; - private readonly Server server; - - public GrpcHostedService(ILogger logger, Server server) - { - this.logger = logger; - this.server = server; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - if (cancellationToken.IsCancellationRequested) - { - return Task.FromCanceled(cancellationToken); - } - - this.server.Start(); - if (this.logger.IsEnabled(LogLevel.Information)) - { - this.logger.LogInformation( - "gRPC services are listening on {0}", - string.Join(",", this.server.Ports.Select(p => $"{p.Host}:{p.BoundPort}"))); - } - - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - this.logger.LogInformation("Killing gRPC server..."); - return this.server.KillAsync(); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/GrpcServices/DeviceServiceImpl.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/GrpcServices/DeviceServiceImpl.cs deleted file mode 100644 index 8c9b969b..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/GrpcServices/DeviceServiceImpl.cs +++ /dev/null @@ -1,562 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using GeothermalResearchInstitute.PlcV2; -using GeothermalResearchInstitute.ServerConsole.Models; -using GeothermalResearchInstitute.ServerConsole.Options; -using GeothermalResearchInstitute.ServerConsole.Utils; -using GeothermalResearchInstitute.v2; -using Google.Protobuf; -using Grpc.Core; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using GrpcAlarm = GeothermalResearchInstitute.v2.Alarm; -using GrpcAlarmChange = GeothermalResearchInstitute.v2.AlarmChange; -using GrpcMetric = GeothermalResearchInstitute.v2.Metric; -using ModelAlarm = GeothermalResearchInstitute.ServerConsole.Models.Alarm; -using ModelAlarmChange = GeothermalResearchInstitute.ServerConsole.Models.AlarmChange; -using ModelMetric = GeothermalResearchInstitute.ServerConsole.Models.Metric; - -namespace GeothermalResearchInstitute.ServerConsole.GrpcServices -{ - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Design", "CA1062:验证公共方法的参数", Justification = "由Grpc框架保证.")] - public class DeviceServiceImpl : DeviceService.DeviceServiceBase, IDisposable - { - private readonly ILogger logger; - private readonly IServiceProvider serviceProvider; - private readonly PlcManager plcManager; - private readonly Timer askAlarmTimer; - private readonly Timer askMetricTimer; - private bool disposedValue = false; - - public DeviceServiceImpl( - ILogger logger, - IOptions tasksOptions, - IServiceProvider serviceProvider, - PlcManager plcManager) - { - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); - this.plcManager = plcManager ?? throw new ArgumentNullException(nameof(plcManager)); - this.askAlarmTimer = new Timer( - this.AskPersistDeviceAlarm, - null, - TimeSpan.FromMilliseconds(tasksOptions.Value.CollectAlarmIntervalMillis), - TimeSpan.FromMilliseconds(tasksOptions.Value.CollectAlarmIntervalMillis)); - this.askMetricTimer = new Timer( - this.AskPersistDeviceMetric, - null, - TimeSpan.FromMilliseconds(tasksOptions.Value.CollectMetricIntervalMillis), - TimeSpan.FromMilliseconds(tasksOptions.Value.CollectMetricIntervalMillis)); - - IOptionsSnapshot coreOptions = - this.serviceProvider.GetRequiredService>(); - this.logger.LogInformation("CoreOptions: {0}", coreOptions.Value); - this.logger.LogInformation("TasksOptions: {0}", tasksOptions.Value); - - if (this.logger.IsEnabled(LogLevel.Debug)) - { - IOptionsSnapshot deviceOptions = this.serviceProvider.GetRequiredService>(); - foreach (DeviceOptionsEntry d in deviceOptions.Value.Devices) - { - this.logger.LogDebug( - "{0}={1}", - string.Join(string.Empty, d.ComputeIdBinary().Select(b => b.ToString("X2", CultureInfo.InvariantCulture))), - d.Name); - } - - IOptionsSnapshot authenticationOptions = this.serviceProvider.GetRequiredService>(); - foreach (Credential c in authenticationOptions.Value.Credentials) - { - this.logger.LogDebug(c.ToString()); - } - } - } - - ~DeviceServiceImpl() - { - this.Dispose(false); - } - - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - public override Task Authenticate( - AuthenticateRequest request, ServerCallContext context) - { - IOptionsSnapshot authenticationOptions = this.serviceProvider.GetRequiredService>(); - Credential credential = authenticationOptions.Value.Credentials.SingleOrDefault( - c => string.Equals(c.Username, request.Username, StringComparison.Ordinal) && - string.Equals(c.Password, request.Password, StringComparison.Ordinal)); - if (credential == null) - { - throw new RpcException(new Status(StatusCode.Unauthenticated, "Invalid username or password.")); - } - else - { - return Task.FromResult(new AuthenticateResponse() - { - Nickname = credential.Nickname, - Role = credential.Role, - }); - } - } - - public override Task Test(TestRequest request, ServerCallContext context) - { - throw new RpcException(new Status(StatusCode.Unimplemented, "Not supported.")); - } - - public override Task Connect(ConnectRequest request, ServerCallContext context) - { - throw new RpcException(new Status(StatusCode.Unimplemented, "Not supported.")); - } - - public override Task ListDevices(ListDevicesRequest request, ServerCallContext context) - { - IOptionsSnapshot deviceOptions = - this.serviceProvider.GetRequiredService>(); - - var response = new ListDevicesResponse(); - response.Devices.Add( - from d in deviceOptions.Value.Devices - let id = ByteString.CopyFrom(d.ComputeIdBinary()) - join e in this.plcManager.PlcDictionary.AsEnumerable() - on id equals e.Key into g - from e in g.DefaultIfEmpty() - select new Device - { - Id = id, - Name = d.Name, - Ipv4Address = e.Value == null - ? ByteString.Empty - : ByteString.CopyFrom(((IPEndPoint)e.Value.RemoteEndPoint).Address.GetAddressBytes()), - Status = e.Value == null - ? DeviceStatus.Disconnected - : DeviceStatus.Healthy, - }); - - return Task.FromResult(response); - } - - public override Task GetMetric(GetMetricRequest request, ServerCallContext context) - { - return this.Invoke( - (client, request, deadline) => client.GetMetricAsync(request, deadline), - request.DeviceId, - request, - context); - } - - public override Task GetSwitch(GetSwitchRequest request, ServerCallContext context) - { - return this.Invoke( - (client, request, deadline) => client.GetSwitchAsync(request, deadline), - request.DeviceId, - request, - context); - } - - public override Task UpdateSwitch(UpdateSwitchRequest request, ServerCallContext context) - { - return this.Invoke( - (client, request, deadline) => client.UpdateSwitchAsync(request, deadline), - request.DeviceId, - request, - context); - } - - public override Task ListMetrics(ListMetricsRequest request, ServerCallContext context) - { - string id = BitConverter.ToString(request.DeviceId.ToByteArray()); - - DateTimeOffset endDateTime; - if (string.IsNullOrEmpty(request.PageToken)) - { - endDateTime = request.EndTime?.ToDateTimeOffset() ?? DateTimeOffset.UtcNow; - } - else - { - endDateTime = DateTimeOffset.Parse(request.PageToken, CultureInfo.InvariantCulture); - } - - endDateTime = endDateTime.ToUniversalTime(); - DateTimeOffset? startDateTime = request.StartTime?.ToDateTimeOffset().ToUniversalTime(); - - var response = new ListMetricsResponse(); - using (BjdireContext db = this.serviceProvider.GetRequiredService()) - { - var metrics = (from m in db.Metrics - where m.DeviceId == id - && (startDateTime == null || startDateTime <= m.Timestamp) - && m.Timestamp <= endDateTime - orderby m.Timestamp descending - select m) - .Take(request.PageSize) - .ToList(); - response.Metrics.AddRange(metrics.Select(metric => - { - var m = new GrpcMetric(); - m.AssignFrom(metric); - return m; - })); - - if (metrics.Count == request.PageSize && metrics.Last().Timestamp > startDateTime) - { - response.NextPageToken = metrics.Last().Timestamp - .ToUniversalTime() - .ToString(CultureInfo.InvariantCulture); - } - } - - return Task.FromResult(response); - } - - public override Task GetWorkingMode(GetWorkingModeRequest request, ServerCallContext context) - { - return this.Invoke( - (client, request, deadline) => client.GetWorkingModeAsync(request, deadline), - request.DeviceId, - request, - context); - } - - public override Task UpdateWorkingMode( - UpdateWorkingModeRequest request, - ServerCallContext context) - { - return this.Invoke( - (client, request, deadline) => client.UpdateWorkingModeAsync(request, deadline), - request.DeviceId, - request, - context); - } - - public override Task GetRunningParameter( - GetRunningParameterRequest request, - ServerCallContext context) - { - return this.Invoke( - (client, request, deadline) => client.GetRunningParameterAsync(request, deadline), - request.DeviceId, - request, - context); - } - - public override Task UpdateRunningParameter( - UpdateRunningParameterRequest request, - ServerCallContext context) - { - return this.Invoke( - (client, request, deadline) => client.UpdateRunningParameterAsync(request, deadline), - request.DeviceId, - request, - context); - } - - public override Task GetAlarm(GetAlarmRequest request, ServerCallContext context) - { - return this.Invoke( - (client, request, deadline) => client.GetAlarmAsync(request, deadline), - request.DeviceId, - request, - context); - } - - public override Task ListAlarmChanges( - ListAlarmChangesRequest request, - ServerCallContext context) - { - string id = BitConverter.ToString(request.DeviceId.ToByteArray()); - - DateTimeOffset endDateTime; - if (string.IsNullOrEmpty(request.PageToken)) - { - endDateTime = request.EndTime?.ToDateTimeOffset() ?? DateTimeOffset.UtcNow; - } - else - { - endDateTime = DateTimeOffset.Parse(request.PageToken, CultureInfo.InvariantCulture); - } - - endDateTime = endDateTime.ToUniversalTime(); - DateTimeOffset? startDateTime = request.StartTime?.ToDateTimeOffset().ToUniversalTime(); - - var response = new ListAlarmChangesResponse(); - using (BjdireContext db = this.serviceProvider.GetRequiredService()) - { - var alarmChanges = (from m in db.AlarmChanges - where m.DeviceId == id - && (startDateTime == null || startDateTime <= m.Timestamp) - && m.Timestamp <= endDateTime - orderby m.Timestamp descending - select m) - .Take(request.PageSize) - .ToList(); - response.AlarmChanges.AddRange(alarmChanges.Select(alarmChange => - { - var m = new GrpcAlarmChange(); - m.AssignFrom(alarmChange); - return m; - })); - - if (alarmChanges.Count == request.PageSize && alarmChanges.Last().Timestamp > startDateTime) - { - response.NextPageToken = alarmChanges.Last().Timestamp - .ToUniversalTime() - .ToString(CultureInfo.InvariantCulture); - } - } - - return Task.FromResult(response); - } - - protected virtual void Dispose(bool disposing) - { - if (!this.disposedValue) - { - if (disposing) - { - this.askAlarmTimer.Dispose(); - this.askMetricTimer.Dispose(); - } - - this.disposedValue = true; - } - } - - private static IEnumerable ComputeAlarmChanges( - string deviceId, - ModelAlarm lastKnownAlarm, - ModelAlarm currentAlarm) - { - if (lastKnownAlarm.LowFlowRate != currentAlarm.LowFlowRate) - { - yield return new ModelAlarmChange - { - DeviceId = deviceId, - Timestamp = currentAlarm.Timestamp, - Type = AlarmType.LowFlowRate, - Direction = currentAlarm.LowFlowRate - ? AlarmChangeDirection.Appearance - : AlarmChangeDirection.Disappearance, - }; - } - - if (lastKnownAlarm.HighHeaterPressure != currentAlarm.HighHeaterPressure) - { - yield return new ModelAlarmChange - { - DeviceId = deviceId, - Timestamp = currentAlarm.Timestamp, - Type = AlarmType.HighHeaterPressure, - Direction = currentAlarm.HighHeaterPressure - ? AlarmChangeDirection.Appearance - : AlarmChangeDirection.Disappearance, - }; - } - - if (lastKnownAlarm.LowHeaterPressure != currentAlarm.LowHeaterPressure) - { - yield return new ModelAlarmChange - { - DeviceId = deviceId, - Timestamp = currentAlarm.Timestamp, - Type = AlarmType.LowHeaterPressure, - Direction = currentAlarm.LowHeaterPressure - ? AlarmChangeDirection.Appearance - : AlarmChangeDirection.Disappearance, - }; - } - - if (lastKnownAlarm.NoPower != currentAlarm.NoPower) - { - yield return new ModelAlarmChange - { - DeviceId = deviceId, - Timestamp = currentAlarm.Timestamp, - Type = AlarmType.NoPower, - Direction = currentAlarm.NoPower - ? AlarmChangeDirection.Appearance - : AlarmChangeDirection.Disappearance, - }; - } - - if (lastKnownAlarm.HeaterOverloadedBroken != currentAlarm.HeaterOverloadedBroken) - { - yield return new ModelAlarmChange - { - DeviceId = deviceId, - Timestamp = currentAlarm.Timestamp, - Type = AlarmType.HeaterOverloadedBroken, - Direction = currentAlarm.HeaterOverloadedBroken - ? AlarmChangeDirection.Appearance - : AlarmChangeDirection.Disappearance, - }; - } - - if (lastKnownAlarm.ElectricalHeaterBroken != currentAlarm.ElectricalHeaterBroken) - { - yield return new ModelAlarmChange - { - DeviceId = deviceId, - Timestamp = currentAlarm.Timestamp, - Type = AlarmType.ElectricalHeaterBroken, - Direction = currentAlarm.ElectricalHeaterBroken - ? AlarmChangeDirection.Appearance - : AlarmChangeDirection.Disappearance, - }; - } - } - - private Task Invoke( - Func> stub, - ByteString deviceId, - TRequest request, - ServerCallContext context) - { - if (deviceId.IsEmpty) - { - throw new RpcException(new Status(StatusCode.InvalidArgument, "Must specify device_id.")); - } - - if (this.plcManager.PlcDictionary.TryGetValue(deviceId, out PlcClient client)) - { - return stub.Invoke(client, request, context.Deadline); - } - else - { - throw new RpcException(new Status(StatusCode.NotFound, "Device is currently offline.")); - } - } - - private async void AskPersistDeviceAlarm(object state) - { - IOptionsSnapshot coreOptions = - this.serviceProvider.GetRequiredService>(); - IOptionsSnapshot deviceOptions = - this.serviceProvider.GetRequiredService>(); - - using BjdireContext db = this.serviceProvider.GetRequiredService(); - - foreach (DeviceOptionsEntry d in deviceOptions.Value.Devices) - { - try - { - byte[] id = d.ComputeIdBinary(); - string deviceId = BitConverter.ToString(id); - if (this.plcManager.PlcDictionary.TryGetValue(ByteString.CopyFrom(id), out PlcClient client)) - { - this.logger.LogInformation("Ask alarm for {0}({1})", d.Id, d.Name); - - GrpcAlarm alarm = await client - .GetAlarmAsync( - new GetAlarmRequest(), - DateTime.UtcNow.AddMilliseconds( - coreOptions.Value.DefaultReadTimeoutMillis)) - .ConfigureAwait(false); - - var m = new ModelAlarm - { - DeviceId = deviceId, - }; - alarm.AssignTo(m); - - ModelAlarm lastKnownAlarmInfo = ( - from mm in db.Alarms - where mm.DeviceId == deviceId - orderby mm.Timestamp descending - select mm) - .FirstOrDefault(); - - if (lastKnownAlarmInfo == null) - { - lastKnownAlarmInfo = new ModelAlarm(); - } - - db.AlarmChanges.AddRange(ComputeAlarmChanges(deviceId, lastKnownAlarmInfo, m)); - - db.Alarms.Add(m); - } - else - { - this.logger.LogWarning( - "Failed to ask alarm for {0}({1}), currently offline.", - d.Id, - d.Name); - } - } - catch (RpcException e) - { - this.logger.LogWarning(e, "Failed to ask alarm for {0}({1})", d.Id, d.Name); - } - } - - db.SaveChanges(); - } - - private async void AskPersistDeviceMetric(object state) - { - IOptionsSnapshot coreOptions = - this.serviceProvider.GetRequiredService>(); - IOptionsSnapshot deviceOptions = - this.serviceProvider.GetRequiredService>(); - - using BjdireContext db = this.serviceProvider.GetRequiredService(); - - foreach (DeviceOptionsEntry d in deviceOptions.Value.Devices) - { - try - { - byte[] id = d.ComputeIdBinary(); - if (this.plcManager.PlcDictionary.TryGetValue(ByteString.CopyFrom(id), out PlcClient client)) - { - this.logger.LogInformation("Ask metric for {0}({1})", d.Id, d.Name); - - GrpcMetric metric = await client - .GetMetricAsync( - new GetMetricRequest(), - DateTime.UtcNow.AddMilliseconds( - coreOptions.Value.DefaultReadTimeoutMillis)) - .ConfigureAwait(false); - - var m = new ModelMetric - { - DeviceId = BitConverter.ToString(id), - }; - metric.AssignTo(m); - - db.Metrics.Add(m); - } - else - { - this.logger.LogWarning( - "Failed to ask metric for {0}({1}), currently offline.", - d.Id, - d.Name); - } - } - catch (RpcException e) - { - this.logger.LogWarning(e, "Failed to ask metric for {0}({1})", d.Id, d.Name); - } - } - - db.SaveChanges(); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/20191214052037_InitialCreate.Designer.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/20191214052037_InitialCreate.Designer.cs deleted file mode 100644 index 744990ed..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/20191214052037_InitialCreate.Designer.cs +++ /dev/null @@ -1,109 +0,0 @@ -// -using GeothermalResearchInstitute.ServerConsole.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace GeothermalResearchInstitute.ServerConsole.Migrations -{ - [DbContext(typeof(BjdireContext))] - [Migration("20191214052037_InitialCreate")] - partial class InitialCreate - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "3.1.0"); - - modelBuilder.Entity("GeothermalResearchInstitute.ServerConsole.Models.Alarm", b => - { - b.Property("DeviceId") - .HasColumnType("TEXT"); - - b.Property("Timestamp") - .HasColumnType("INTEGER"); - - b.Property("ElectricalHeaterBroken") - .HasColumnType("INTEGER"); - - b.Property("HeaterOverloadedBroken") - .HasColumnType("INTEGER"); - - b.Property("HighHeaterPressure") - .HasColumnType("INTEGER"); - - b.Property("LowFlowRate") - .HasColumnType("INTEGER"); - - b.Property("LowHeaterPressure") - .HasColumnType("INTEGER"); - - b.Property("NoPower") - .HasColumnType("INTEGER"); - - b.HasKey("DeviceId", "Timestamp"); - - b.ToTable("Alarms"); - }); - - modelBuilder.Entity("GeothermalResearchInstitute.ServerConsole.Models.AlarmChange", b => - { - b.Property("DeviceId") - .HasColumnType("TEXT"); - - b.Property("Timestamp") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.Property("Direction") - .HasColumnType("INTEGER"); - - b.HasKey("DeviceId", "Timestamp", "Type"); - - b.ToTable("AlarmChanges"); - }); - - modelBuilder.Entity("GeothermalResearchInstitute.ServerConsole.Models.Metric", b => - { - b.Property("DeviceId") - .HasColumnType("TEXT"); - - b.Property("Timestamp") - .HasColumnType("INTEGER"); - - b.Property("EnvironmentCelsiusDegree") - .HasColumnType("REAL"); - - b.Property("HeaterOutputWaterCelsiusDegree") - .HasColumnType("REAL"); - - b.Property("HeaterPowerKilowatt") - .HasColumnType("REAL"); - - b.Property("InputWaterCelsiusDegree") - .HasColumnType("REAL"); - - b.Property("InputWaterPressureMeter") - .HasColumnType("REAL"); - - b.Property("OutputWaterCelsiusDegree") - .HasColumnType("REAL"); - - b.Property("OutputWaterPressureMeter") - .HasColumnType("REAL"); - - b.Property("WaterPumpFlowRateCubicMeterPerHour") - .HasColumnType("REAL"); - - b.HasKey("DeviceId", "Timestamp"); - - b.ToTable("Metrics"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/20191214052037_InitialCreate.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/20191214052037_InitialCreate.cs deleted file mode 100644 index f2f37c3d..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/20191214052037_InitialCreate.cs +++ /dev/null @@ -1,89 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using Microsoft.EntityFrameworkCore.Migrations; - -namespace GeothermalResearchInstitute.ServerConsole.Migrations -{ - public partial class InitialCreate : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - if (migrationBuilder is null) - { - throw new System.ArgumentNullException(nameof(migrationBuilder)); - } - - migrationBuilder.CreateTable( - name: "AlarmChanges", - columns: table => new - { - DeviceId = table.Column(nullable: false), - Timestamp = table.Column(nullable: false), - Type = table.Column(nullable: false), - Direction = table.Column(nullable: false), - }, - constraints: table => - { - table.PrimaryKey("PK_AlarmChanges", x => new { x.DeviceId, x.Timestamp, x.Type }); - }); - - migrationBuilder.CreateTable( - name: "Alarms", - columns: table => new - { - DeviceId = table.Column(nullable: false), - Timestamp = table.Column(nullable: false), - LowFlowRate = table.Column(nullable: false), - HighHeaterPressure = table.Column(nullable: false), - LowHeaterPressure = table.Column(nullable: false), - NoPower = table.Column(nullable: false), - HeaterOverloadedBroken = table.Column(nullable: false), - ElectricalHeaterBroken = table.Column(nullable: false), - }, - constraints: table => - { - table.PrimaryKey("PK_Alarms", x => new { x.DeviceId, x.Timestamp }); - }); - - migrationBuilder.CreateTable( - name: "Metrics", - columns: table => new - { - DeviceId = table.Column(nullable: false), - Timestamp = table.Column(nullable: false), - OutputWaterCelsiusDegree = table.Column(nullable: false), - InputWaterCelsiusDegree = table.Column(nullable: false), - HeaterOutputWaterCelsiusDegree = table.Column(nullable: false), - EnvironmentCelsiusDegree = table.Column(nullable: false), - OutputWaterPressureMeter = table.Column(nullable: false), - InputWaterPressureMeter = table.Column(nullable: false), - HeaterPowerKilowatt = table.Column(nullable: false), - WaterPumpFlowRateCubicMeterPerHour = table.Column(nullable: false), - }, - constraints: table => - { - table.PrimaryKey("PK_Metrics", x => new { x.DeviceId, x.Timestamp }); - }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - if (migrationBuilder is null) - { - throw new System.ArgumentNullException(nameof(migrationBuilder)); - } - - migrationBuilder.DropTable( - name: "AlarmChanges"); - - migrationBuilder.DropTable( - name: "Alarms"); - - migrationBuilder.DropTable( - name: "Metrics"); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/20191215142314_Add4MoreAlarmTypes.Designer.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/20191215142314_Add4MoreAlarmTypes.Designer.cs deleted file mode 100644 index 323dbf66..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/20191215142314_Add4MoreAlarmTypes.Designer.cs +++ /dev/null @@ -1,121 +0,0 @@ -// -using GeothermalResearchInstitute.ServerConsole.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace GeothermalResearchInstitute.ServerConsole.Migrations -{ - [DbContext(typeof(BjdireContext))] - [Migration("20191215142314_Add4MoreAlarmTypes")] - partial class Add4MoreAlarmTypes - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "3.1.0"); - - modelBuilder.Entity("GeothermalResearchInstitute.ServerConsole.Models.Alarm", b => - { - b.Property("DeviceId") - .HasColumnType("TEXT"); - - b.Property("Timestamp") - .HasColumnType("INTEGER"); - - b.Property("ElectricalHeaterBroken") - .HasColumnType("INTEGER"); - - b.Property("EmergencyStopped") - .HasColumnType("INTEGER"); - - b.Property("HeaterOverloadedBroken") - .HasColumnType("INTEGER"); - - b.Property("HighHeaterPressure") - .HasColumnType("INTEGER"); - - b.Property("HighVoltage") - .HasColumnType("INTEGER"); - - b.Property("LowFlowRate") - .HasColumnType("INTEGER"); - - b.Property("LowHeaterPressure") - .HasColumnType("INTEGER"); - - b.Property("LowVoltage") - .HasColumnType("INTEGER"); - - b.Property("NoPower") - .HasColumnType("INTEGER"); - - b.Property("NoWater") - .HasColumnType("INTEGER"); - - b.HasKey("DeviceId", "Timestamp"); - - b.ToTable("Alarms"); - }); - - modelBuilder.Entity("GeothermalResearchInstitute.ServerConsole.Models.AlarmChange", b => - { - b.Property("DeviceId") - .HasColumnType("TEXT"); - - b.Property("Timestamp") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.Property("Direction") - .HasColumnType("INTEGER"); - - b.HasKey("DeviceId", "Timestamp", "Type"); - - b.ToTable("AlarmChanges"); - }); - - modelBuilder.Entity("GeothermalResearchInstitute.ServerConsole.Models.Metric", b => - { - b.Property("DeviceId") - .HasColumnType("TEXT"); - - b.Property("Timestamp") - .HasColumnType("INTEGER"); - - b.Property("EnvironmentCelsiusDegree") - .HasColumnType("REAL"); - - b.Property("HeaterOutputWaterCelsiusDegree") - .HasColumnType("REAL"); - - b.Property("HeaterPowerKilowatt") - .HasColumnType("REAL"); - - b.Property("InputWaterCelsiusDegree") - .HasColumnType("REAL"); - - b.Property("InputWaterPressureMeter") - .HasColumnType("REAL"); - - b.Property("OutputWaterCelsiusDegree") - .HasColumnType("REAL"); - - b.Property("OutputWaterPressureMeter") - .HasColumnType("REAL"); - - b.Property("WaterPumpFlowRateCubicMeterPerHour") - .HasColumnType("REAL"); - - b.HasKey("DeviceId", "Timestamp"); - - b.ToTable("Metrics"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/20191215142314_Add4MoreAlarmTypes.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/20191215142314_Add4MoreAlarmTypes.cs deleted file mode 100644 index 232ba886..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/20191215142314_Add4MoreAlarmTypes.cs +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using Microsoft.EntityFrameworkCore.Migrations; - -namespace GeothermalResearchInstitute.ServerConsole.Migrations -{ - public partial class Add4MoreAlarmTypes : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - if (migrationBuilder is null) - { - throw new System.ArgumentNullException(nameof(migrationBuilder)); - } - - migrationBuilder.AddColumn( - name: "EmergencyStopped", - table: "Alarms", - nullable: false, - defaultValue: false); - - migrationBuilder.AddColumn( - name: "HighVoltage", - table: "Alarms", - nullable: false, - defaultValue: false); - - migrationBuilder.AddColumn( - name: "LowVoltage", - table: "Alarms", - nullable: false, - defaultValue: false); - - migrationBuilder.AddColumn( - name: "NoWater", - table: "Alarms", - nullable: false, - defaultValue: false); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - if (migrationBuilder is null) - { - throw new System.ArgumentNullException(nameof(migrationBuilder)); - } - - migrationBuilder.DropColumn( - name: "EmergencyStopped", - table: "Alarms"); - - migrationBuilder.DropColumn( - name: "HighVoltage", - table: "Alarms"); - - migrationBuilder.DropColumn( - name: "LowVoltage", - table: "Alarms"); - - migrationBuilder.DropColumn( - name: "NoWater", - table: "Alarms"); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/BjdireContextModelSnapshot.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/BjdireContextModelSnapshot.cs deleted file mode 100644 index 8c146bbc..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Migrations/BjdireContextModelSnapshot.cs +++ /dev/null @@ -1,119 +0,0 @@ -// -using GeothermalResearchInstitute.ServerConsole.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace GeothermalResearchInstitute.ServerConsole.Migrations -{ - [DbContext(typeof(BjdireContext))] - partial class BjdireContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "3.1.0"); - - modelBuilder.Entity("GeothermalResearchInstitute.ServerConsole.Models.Alarm", b => - { - b.Property("DeviceId") - .HasColumnType("TEXT"); - - b.Property("Timestamp") - .HasColumnType("INTEGER"); - - b.Property("ElectricalHeaterBroken") - .HasColumnType("INTEGER"); - - b.Property("EmergencyStopped") - .HasColumnType("INTEGER"); - - b.Property("HeaterOverloadedBroken") - .HasColumnType("INTEGER"); - - b.Property("HighHeaterPressure") - .HasColumnType("INTEGER"); - - b.Property("HighVoltage") - .HasColumnType("INTEGER"); - - b.Property("LowFlowRate") - .HasColumnType("INTEGER"); - - b.Property("LowHeaterPressure") - .HasColumnType("INTEGER"); - - b.Property("LowVoltage") - .HasColumnType("INTEGER"); - - b.Property("NoPower") - .HasColumnType("INTEGER"); - - b.Property("NoWater") - .HasColumnType("INTEGER"); - - b.HasKey("DeviceId", "Timestamp"); - - b.ToTable("Alarms"); - }); - - modelBuilder.Entity("GeothermalResearchInstitute.ServerConsole.Models.AlarmChange", b => - { - b.Property("DeviceId") - .HasColumnType("TEXT"); - - b.Property("Timestamp") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.Property("Direction") - .HasColumnType("INTEGER"); - - b.HasKey("DeviceId", "Timestamp", "Type"); - - b.ToTable("AlarmChanges"); - }); - - modelBuilder.Entity("GeothermalResearchInstitute.ServerConsole.Models.Metric", b => - { - b.Property("DeviceId") - .HasColumnType("TEXT"); - - b.Property("Timestamp") - .HasColumnType("INTEGER"); - - b.Property("EnvironmentCelsiusDegree") - .HasColumnType("REAL"); - - b.Property("HeaterOutputWaterCelsiusDegree") - .HasColumnType("REAL"); - - b.Property("HeaterPowerKilowatt") - .HasColumnType("REAL"); - - b.Property("InputWaterCelsiusDegree") - .HasColumnType("REAL"); - - b.Property("InputWaterPressureMeter") - .HasColumnType("REAL"); - - b.Property("OutputWaterCelsiusDegree") - .HasColumnType("REAL"); - - b.Property("OutputWaterPressureMeter") - .HasColumnType("REAL"); - - b.Property("WaterPumpFlowRateCubicMeterPerHour") - .HasColumnType("REAL"); - - b.HasKey("DeviceId", "Timestamp"); - - b.ToTable("Metrics"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/Alarm.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/Alarm.cs deleted file mode 100644 index 37effab9..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/Alarm.cs +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; - -namespace GeothermalResearchInstitute.ServerConsole.Models -{ - public class Alarm - { - public string DeviceId { get; set; } - - public DateTimeOffset Timestamp { get; set; } - - // 流量低 - public bool LowFlowRate { get; set; } - - // 热泵压力高 - public bool HighHeaterPressure { get; set; } - - // 热泵压力低 - public bool LowHeaterPressure { get; set; } - - // 电源断相或相序错 - public bool NoPower { get; set; } - - // 热泵过载故障(热继电器) - public bool HeaterOverloadedBroken { get; set; } - - // 电加热器故障 - public bool ElectricalHeaterBroken { get; set; } - - // 系统缺水故障 - public bool NoWater { get; set; } - - // 电源电压过高 - public bool HighVoltage { get; set; } - - // 电源电压过低 - public bool LowVoltage { get; set; } - - // 急停开关被按下 - public bool EmergencyStopped { get; set; } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/AlarmChange.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/AlarmChange.cs deleted file mode 100644 index 8a7c357b..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/AlarmChange.cs +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using GeothermalResearchInstitute.v2; - -namespace GeothermalResearchInstitute.ServerConsole.Models -{ - public class AlarmChange - { - public string DeviceId { get; set; } - - public DateTimeOffset Timestamp { get; set; } - - public AlarmType Type { get; set; } - - public AlarmChangeDirection Direction { get; set; } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/BjdireContext.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/BjdireContext.cs deleted file mode 100644 index a0d713fe..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/BjdireContext.cs +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using GeothermalResearchInstitute.v2; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace GeothermalResearchInstitute.ServerConsole.Models -{ - public class BjdireContext : DbContext - { - public BjdireContext(DbContextOptions options) - : base(options) - { - } - - public DbSet Alarms { get; set; } - - public DbSet AlarmChanges { get; set; } - - public DbSet Metrics { get; set; } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - if (modelBuilder is null) - { - throw new ArgumentNullException(nameof(modelBuilder)); - } - - modelBuilder.Entity() - .HasKey(m => new { m.DeviceId, m.Timestamp }); - modelBuilder.Entity() - .HasKey(m => new { m.DeviceId, m.Timestamp, m.Type }); - modelBuilder.Entity() - .Property(m => m.Type) - .HasConversion(new EnumToNumberConverter()); - modelBuilder.Entity() - .Property(m => m.Direction) - .HasConversion(new EnumToNumberConverter()); - modelBuilder.Entity() - .HasKey(m => new { m.DeviceId, m.Timestamp }); - - if (this.Database.ProviderName == "Microsoft.EntityFrameworkCore.Sqlite") - { - // SQLite does not have proper support for DateTimeOffset via Entity Framework Core, see the limitations - // here: https://docs.microsoft.com/en-us/ef/core/providers/sqlite/limitations#query-limitations - // To work around this, when the SQLite database provider is used, all model properties of type DateTimeOffset - // use the DateTimeOffsetToBinaryConverter - // Based on: https://github.com/aspnet/EntityFrameworkCore/issues/10784#issuecomment-415769754 - // This only supports millisecond precision, but should be sufficient for most use cases. - foreach (IMutableEntityType entityType in modelBuilder.Model.GetEntityTypes()) - { - IEnumerable properties = entityType.ClrType.GetProperties() - .Where(p => p.PropertyType == typeof(DateTimeOffset)); - foreach (PropertyInfo property in properties) - { - modelBuilder - .Entity(entityType.Name) - .Property(property.Name) - .HasConversion(new DateTimeOffsetToBinaryConverter()); - } - } - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/BjdireContextFactory.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/BjdireContextFactory.cs deleted file mode 100644 index 11c8a72e..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/BjdireContextFactory.cs +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Design; - -namespace GeothermalResearchInstitute.ServerConsole.Models -{ - public class BjdireContextFactory : IDesignTimeDbContextFactory - { - public BjdireContext CreateDbContext(string[] args) - { - var builder = new DbContextOptionsBuilder(); - Program.DbContextOptionsBuilderAction.Invoke(builder); - return new BjdireContext(builder.Options); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/Metric.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/Metric.cs deleted file mode 100644 index fe4d6fae..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Models/Metric.cs +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; - -namespace GeothermalResearchInstitute.ServerConsole.Models -{ - public class Metric - { - public string DeviceId { get; set; } - - public DateTimeOffset Timestamp { get; set; } - - // 出水温度 - public float OutputWaterCelsiusDegree { get; set; } - - // 回水温度 - public float InputWaterCelsiusDegree { get; set; } - - // 加热器出水温度 - public float HeaterOutputWaterCelsiusDegree { get; set; } - - // 环境温度 - public float EnvironmentCelsiusDegree { get; set; } - - // 出水压力 - public float OutputWaterPressureMeter { get; set; } - - // 回水压力 - public float InputWaterPressureMeter { get; set; } - - // 加热器加热功率 - public float HeaterPowerKilowatt { get; set; } - - // 流量 - public float WaterPumpFlowRateCubicMeterPerHour { get; set; } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/AuthenticationOptions.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/AuthenticationOptions.cs deleted file mode 100644 index eb07b98f..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/AuthenticationOptions.cs +++ /dev/null @@ -1,16 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System.Collections.Generic; - -namespace GeothermalResearchInstitute.ServerConsole.Options -{ - public class AuthenticationOptions - { - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Usage", "CA2227:集合属性应为只读", Justification = "Sets with reflection.")] - public ICollection Credentials { get; set; } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/CoreOptions.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/CoreOptions.cs deleted file mode 100644 index 93a65a29..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/CoreOptions.cs +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System.Text.Json; - -namespace GeothermalResearchInstitute.ServerConsole.Options -{ - public class CoreOptions - { - public int GrpcPort { get; set; } - - public int TcpPort { get; set; } - - public int DefaultReadTimeoutMillis { get; set; } - - public int MaxFakeDeviceNum { get; set; } - - public override string ToString() - { - return JsonSerializer.Serialize(this); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/Credential.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/Credential.cs deleted file mode 100644 index dd14be0a..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/Credential.cs +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using GeothermalResearchInstitute.v2; - -namespace GeothermalResearchInstitute.ServerConsole.Options -{ - public class Credential - { - public string Nickname { get; set; } - - public string Username { get; set; } - - public string Password { get; set; } - - public UserRole Role { get; set; } - - public override string ToString() - { - return this.Nickname + "(" + this.Username + ":" + this.Role + ")"; - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/DeviceOptions.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/DeviceOptions.cs deleted file mode 100644 index ef61f971..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/DeviceOptions.cs +++ /dev/null @@ -1,16 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System.Collections.Generic; - -namespace GeothermalResearchInstitute.ServerConsole.Options -{ - public class DeviceOptions - { - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Usage", "CA2227:集合属性应为只读", Justification = "Sets with reflection.")] - public ICollection Devices { get; set; } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/DeviceOptionsEntry.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/DeviceOptionsEntry.cs deleted file mode 100644 index 5b7f6842..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/DeviceOptionsEntry.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Net.NetworkInformation; - -namespace GeothermalResearchInstitute.ServerConsole.Options -{ - public class DeviceOptionsEntry - { - public string Id { get; set; } - - public string Name { get; set; } - - public byte[] ComputeIdBinary() - { - return PhysicalAddress - .Parse(this.Id -#if NET48 - .Replace(":", null) - .Replace("-", null)) -#else - .Replace(":", null, StringComparison.Ordinal) - .Replace("-", null, StringComparison.Ordinal)) -#endif - .GetAddressBytes(); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/TasksOptions.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/TasksOptions.cs deleted file mode 100644 index 5d80bdea..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Options/TasksOptions.cs +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System.Text.Json; - -namespace GeothermalResearchInstitute.ServerConsole.Options -{ - public class TasksOptions - { - public int CollectAlarmIntervalMillis { get; set; } - - public int CollectMetricIntervalMillis { get; set; } - - public override string ToString() - { - return JsonSerializer.Serialize(this); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/PlcHostedService.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/PlcHostedService.cs deleted file mode 100644 index b7053dec..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/PlcHostedService.cs +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; - -namespace GeothermalResearchInstitute.ServerConsole -{ - public class PlcHostedService : IHostedService - { - private readonly PlcManager plcManager; - - public PlcHostedService(PlcManager plcManager) - { - this.plcManager = plcManager ?? throw new ArgumentNullException(nameof(plcManager)); - } - - public Task StartAsync(CancellationToken cancellationToken) - { - return this.plcManager.StartAsync(cancellationToken); - } - - public Task StopAsync(CancellationToken cancellationToken) - { - return this.plcManager.StopAsync(); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/PlcManager.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/PlcManager.cs deleted file mode 100644 index 5a4df582..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/PlcManager.cs +++ /dev/null @@ -1,154 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; -using GeothermalResearchInstitute.PlcV2; -using GeothermalResearchInstitute.v2; -using Google.Protobuf; -using Grpc.Core; -using Microsoft.Extensions.Logging; - -namespace GeothermalResearchInstitute.ServerConsole -{ - [SuppressMessage( - "Design", - "CA1001:具有可释放字段的类型应该是可释放的", - Justification = "Disposed in StopAsync, ensured by framework.")] - public class PlcManager - { - private readonly ILogger logger; - private readonly PlcServer plcServer; - private CancellationTokenSource cancellationTokenSource; - private Task backgroundTask; - - public PlcManager(ILogger logger, PlcServer plcServer) - { - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.plcServer = plcServer ?? throw new ArgumentNullException(nameof(plcServer)); - } - - public ConcurrentDictionary PlcDictionary { get; } = - new ConcurrentDictionary(); - - public Task StartAsync(CancellationToken cancellationToken) - { - if (cancellationToken.IsCancellationRequested) - { - return Task.FromCanceled(cancellationToken); - } - - this.plcServer.Start(); - this.logger.LogInformation("PLC server is listening on {0}", this.plcServer.LocalEndPoint); - - this.PlcDictionary.Clear(); - this.cancellationTokenSource = new CancellationTokenSource(); - this.backgroundTask = Task.Factory.StartNew( - this.BackgroundTaskEntryPoint, - this.cancellationTokenSource.Token, - TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach, - TaskScheduler.Default); - - return Task.CompletedTask; - } - - public async Task StopAsync() - { - this.cancellationTokenSource.Cancel(); - await this.backgroundTask.ConfigureAwait(false); - - foreach (ByteString id in this.PlcDictionary.Keys) - { - if (this.PlcDictionary.TryRemove(id, out PlcClient client)) - { - await client.Close().ConfigureAwait(false); - client.Dispose(); - } - } - - this.plcServer.Stop(); - - this.cancellationTokenSource.Dispose(); - this.cancellationTokenSource = null; - this.backgroundTask.Dispose(); - this.backgroundTask = null; - } - - private async void BackgroundTaskEntryPoint() - { - while (!this.cancellationTokenSource.IsCancellationRequested) - { - PlcClient client = null; - try - { - client = await this.plcServer.AcceptAsync().ConfigureAwait(false); - this.logger.LogInformation("TCP connection established from {0}", client.RemoteEndPoint); - } - catch (SocketException e) - { - this.logger.LogError(e, "Failed to TCP accept PLC."); - continue; - } - catch (ObjectDisposedException) - { - // Ignore it. - break; - } - - ConnectResponse response; - try - { - response = await client - .ConnectAsync(new ConnectRequest(), DateTime.UtcNow.AddSeconds(10)) - .ConfigureAwait(false); - this.logger.LogInformation( - "ConnectResponse received from newly PLC {0}: {1}", - client.RemoteEndPoint, - response); - } - catch (RpcException e) - { - this.logger.LogWarning( - e, - "Failed to send ConnectRequest to newly PLC {0}, hang up.", - client.RemoteEndPoint); - await client.Close().ConfigureAwait(false); - client.Dispose(); - continue; - } - - client.OnClosed += (sender, args) => - { - this.logger.LogInformation( - "Client(MAC={0}, EndPoint={1}) disconnected.", - BitConverter.ToString(response.Id.ToByteArray()), - client.RemoteEndPoint); - this.PlcDictionary.TryRemove(response.Id, out PlcClient _); - }; - - if (this.PlcDictionary.TryAdd(response.Id, client)) - { - this.logger.LogInformation( - "Client(MAC={0}, EndPoint={1}) connected.", - BitConverter.ToString(response.Id.ToByteArray()), - client.RemoteEndPoint); - } - else - { - this.logger.LogWarning( - "Failed to add the client(MAC={0}, EndPoint={1}) into dictionary.", - BitConverter.ToString(response.Id.ToByteArray()), - client.RemoteEndPoint); - await client.Close().ConfigureAwait(false); - client.Dispose(); - } - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Program.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Program.cs deleted file mode 100644 index 36b36739..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Program.cs +++ /dev/null @@ -1,147 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Net; -using GeothermalResearchInstitute.PlcV2; -using GeothermalResearchInstitute.ServerConsole.GrpcServices; -using GeothermalResearchInstitute.ServerConsole.Models; -using GeothermalResearchInstitute.ServerConsole.Options; -using GeothermalResearchInstitute.v2; -using Grpc.Core; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Serilog; - -namespace GeothermalResearchInstitute.ServerConsole -{ - internal class Program - { - internal static readonly Action DbContextOptionsBuilderAction = - builder => builder.UseSqlite("Data Source=bjdire.sqlite;"); - - private static void Main(string[] args) - { - IHost host = new HostBuilder() - .ConfigureHostConfiguration(builder => builder - .SetBasePath(Environment.CurrentDirectory) - .AddIniFile("appsettings.ini", optional: false, reloadOnChange: true) - .AddCommandLine(args)) - .ConfigureAppConfiguration((context, builder) => - { - IHostEnvironment env = context.HostingEnvironment; - builder - .SetBasePath(Environment.CurrentDirectory) - .AddIniFile("appsettings.ini", optional: false, reloadOnChange: true) - .AddIniFile($"appsettings.{env.EnvironmentName}.ini", optional: false, reloadOnChange: true) - .AddCommandLine(args); - }) - .ConfigureLogging((context, builder) => - { - IHostEnvironment env = context.HostingEnvironment; - if (env.IsDevelopment() || env.IsStaging()) - { - builder.AddDebug(); - } - - Log.Logger = new LoggerConfiguration() - .ReadFrom.Configuration(context.Configuration) - .CreateLogger(); - builder.AddSerilog(dispose: true); - - builder.AddConfiguration(context.Configuration.GetSection("Logging")); - }) - .ConfigureServices((context, builder) => - { - IHostEnvironment env = context.HostingEnvironment; - IConfiguration config = context.Configuration; - - // Configuration options. - builder.Configure(config); - builder.Configure(config.GetSection("core")); - builder.Configure(config); - builder.Configure(config.GetSection("tasks")); - - // Database. - if (env.IsDevelopment()) - { - // TODO(zhangshuai.ustc): Add fake data. - builder.AddDbContext( - options => options.UseInMemoryDatabase("bjdire"), - ServiceLifetime.Transient, - ServiceLifetime.Transient); - } - else - { - builder.AddDbContext( - DbContextOptionsBuilderAction, - ServiceLifetime.Transient, - ServiceLifetime.Transient); - } - - // PLC server. - builder.AddSingleton(provider => new PlcServer( - provider.GetRequiredService(), - IPAddress.Any, - provider.GetRequiredService>().Value.TcpPort)); - builder.AddSingleton(); - - // gRPC services. - builder.AddSingleton(serviceProvider => - { - return new HCOONa.MicrosoftExtensions.Logging.GrpcAdapater.GrpcLogger( - serviceProvider.GetRequiredService(), - serviceProvider.GetRequiredService>()); - }); - builder.AddSingleton(); - builder.AddSingleton(serviceProvider => - { - GrpcEnvironment.SetLogger(serviceProvider.GetRequiredService()); - return new Server - { - Services = - { - DeviceService.BindService(serviceProvider.GetRequiredService()), - }, - Ports = - { - new ServerPort( - "0.0.0.0", - serviceProvider.GetRequiredService>().Value.GrpcPort, - ServerCredentials.Insecure), - }, - }; - }); - - builder.AddHostedService(); - builder.AddHostedService(); - -#if DEBUG - if (env.IsDevelopment()) - { - builder.AddHostedService(); - } -#endif - }) - .UseConsoleLifetime() - .Build(); - - ILogger programLogger = host.Services.GetRequiredService>(); - AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => - { - programLogger.LogCritical("Global unhandled exception occurred!", (Exception)e.ExceptionObject); - }; - - using (host) - { - host.Run(); - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Properties/launchSettings.json b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Properties/launchSettings.json deleted file mode 100644 index a1a400f7..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "GeothermalResearchInstitute.ServerConsole": { - "commandName": "Project", - "commandLineArgs": "--Environment=Development" - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Utils/ConvertUtils.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Utils/ConvertUtils.cs deleted file mode 100644 index ed73dc53..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/Utils/ConvertUtils.cs +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using Google.Protobuf.WellKnownTypes; -using GrpcAlarm = GeothermalResearchInstitute.v2.Alarm; -using GrpcAlarmChange = GeothermalResearchInstitute.v2.AlarmChange; -using GrpcMetric = GeothermalResearchInstitute.v2.Metric; -using ModelAlarm = GeothermalResearchInstitute.ServerConsole.Models.Alarm; -using ModelAlarmChange = GeothermalResearchInstitute.ServerConsole.Models.AlarmChange; -using ModelMetric = GeothermalResearchInstitute.ServerConsole.Models.Metric; - -namespace GeothermalResearchInstitute.ServerConsole.Utils -{ - internal static class ConvertUtils - { - public static GrpcAlarm AssignFrom(this GrpcAlarm gAlarm, ModelAlarm alarm) - { - gAlarm.CreateTime = Timestamp.FromDateTimeOffset(alarm.Timestamp); - gAlarm.LowFlowRate = alarm.LowFlowRate; - gAlarm.HighHeaterPressure = alarm.HighHeaterPressure; - gAlarm.LowHeaterPressure = alarm.LowHeaterPressure; - gAlarm.NoPower = alarm.NoPower; - gAlarm.HeaterOverloadedBroken = alarm.HeaterOverloadedBroken; - gAlarm.ElectricalHeaterBroken = alarm.ElectricalHeaterBroken; - return gAlarm; - } - - public static GrpcAlarm AssignTo(this GrpcAlarm gAlarm, ModelAlarm alarm) - { - alarm.Timestamp = gAlarm.CreateTime.ToDateTimeOffset(); - alarm.LowFlowRate = gAlarm.LowFlowRate; - alarm.HighHeaterPressure = gAlarm.HighHeaterPressure; - alarm.LowHeaterPressure = gAlarm.LowHeaterPressure; - alarm.NoPower = gAlarm.NoPower; - alarm.HeaterOverloadedBroken = gAlarm.HeaterOverloadedBroken; - alarm.ElectricalHeaterBroken = gAlarm.ElectricalHeaterBroken; - return gAlarm; - } - - public static GrpcAlarmChange AssignFrom(this GrpcAlarmChange gAlarmChange, ModelAlarmChange alarmChange) - { - gAlarmChange.CreateTime = Timestamp.FromDateTimeOffset(alarmChange.Timestamp); - gAlarmChange.AlarmType = alarmChange.Type; - gAlarmChange.AlarmChangeDirection = alarmChange.Direction; - return gAlarmChange; - } - - public static GrpcMetric AssignFrom(this GrpcMetric gMetric, ModelMetric metric) - { - gMetric.CreateTime = Timestamp.FromDateTimeOffset(metric.Timestamp); - gMetric.OutputWaterCelsiusDegree = metric.OutputWaterCelsiusDegree; - gMetric.InputWaterCelsiusDegree = metric.InputWaterCelsiusDegree; - gMetric.HeaterOutputWaterCelsiusDegree = metric.HeaterOutputWaterCelsiusDegree; - gMetric.EnvironmentCelsiusDegree = metric.EnvironmentCelsiusDegree; - gMetric.OutputWaterPressureMeter = metric.OutputWaterPressureMeter; - gMetric.InputWaterPressureMeter = metric.InputWaterPressureMeter; - gMetric.HeaterPowerKilowatt = metric.HeaterPowerKilowatt; - gMetric.WaterPumpFlowRateCubicMeterPerHour = metric.WaterPumpFlowRateCubicMeterPerHour; - return gMetric; - } - - public static GrpcMetric AssignTo(this GrpcMetric gMetric, ModelMetric metric) - { - metric.Timestamp = gMetric.CreateTime.ToDateTimeOffset(); - metric.OutputWaterCelsiusDegree = gMetric.OutputWaterCelsiusDegree; - metric.InputWaterCelsiusDegree = gMetric.InputWaterCelsiusDegree; - metric.HeaterOutputWaterCelsiusDegree = gMetric.HeaterOutputWaterCelsiusDegree; - metric.EnvironmentCelsiusDegree = gMetric.EnvironmentCelsiusDegree; - metric.OutputWaterPressureMeter = gMetric.OutputWaterPressureMeter; - metric.InputWaterPressureMeter = gMetric.InputWaterPressureMeter; - metric.HeaterPowerKilowatt = gMetric.HeaterPowerKilowatt; - metric.WaterPumpFlowRateCubicMeterPerHour = gMetric.WaterPumpFlowRateCubicMeterPerHour; - return gMetric; - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/appsettings.Development.ini b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/appsettings.Development.ini deleted file mode 100644 index e5c40612..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/appsettings.Development.ini +++ /dev/null @@ -1,29 +0,0 @@ -[core] -MaxFakeDeviceNum = 1 - -[tasks] -; 5 seconds -CollectMetricIntervalMillis = 5000 - -[credentials] -0:nickname = 开发用户0 -0:username = user -0:password = user -0:role = User -1:nickname = 开发管理员1 -1:username = admin -1:password = admin -1:role = Administrator - -[devices] -0:id = 10:BF:48:79:B2:A4 -0:name = 开发设备0 -1:id = BC:96:80:E6:70:16 -1:name = 开发设备1 - -[Logging:LogLevel] -Default = Debug - -[Serilog] -MinimumLevel:Default = Debug -WriteTo:Async:Args:configure:0:Args:rollOnFileSizeLimit = false diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/appsettings.Production.ini b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/appsettings.Production.ini deleted file mode 100644 index c0985c2f..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/appsettings.Production.ini +++ /dev/null @@ -1,25 +0,0 @@ -[core] - -[credentials] -; 增减用户无需重启服务 -; 用户昵称,将在上位机界面显示 -0:nickname = 刘冰 -; 用户名 -0:username = liubing -; 密码 -0:password = liubing123 -; 身份,管理员(Administrator),用户(User) -0:role = Administrator - -[devices] -; 增减设备无需重启服务 -; 设备 MAC 地址 -0:id = 10:BF:48:79:B2:A4 -; 设备名称,将在上位机界面显示 -0:name = 开发设备0 - -[Logging:LogLevel] -Default = Information - -[Serilog] -MinimumLevel:Default = Information diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/appsettings.Staging.ini b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/appsettings.Staging.ini deleted file mode 100644 index c737aa5f..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/appsettings.Staging.ini +++ /dev/null @@ -1,28 +0,0 @@ -[core] -MaxFakeDeviceNum = 1 - -[tasks] -; 5 seconds -CollectMetricIntervalMillis = 5000 - -[credentials] -0:nickname = 开发用户0 -0:username = user -0:password = user -0:role = User -1:nickname = 开发管理员1 -1:username = admin -1:password = admin -1:role = Administrator - -[devices] -0:id = 10:BF:48:79:B2:A4 -0:name = 开发设备0 -1:id = BC:96:80:E6:70:16 -1:name = 开发设备1 - -[Logging:LogLevel] -Default = Debug - -[Serilog] -MinimumLevel:Default = Debug diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/appsettings.ini b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/appsettings.ini deleted file mode 100644 index c4461d86..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/appsettings.ini +++ /dev/null @@ -1,34 +0,0 @@ -[core] -GrpcPort = 8888 -TcpPort = 8889 - -; 5 seconds -DefaultReadTimeoutMillis = 5000 - -[tasks] -; 1 minute -CollectAlarmIntervalMillis = 60000 - -; 10 minutes -CollectMetricIntervalMillis = 600000 - -[credentials] - -[devices] - -[Serilog] -Using:0 = Serilog.Sinks.Console -MinimumLevel:Default = Debug -MinimumLevel:Override:Microsoft.EntityFrameworkCore = Information -MinimumLevel:Override:Microsoft.EntityFrameworkCore.Infrastructure = Warning -WriteTo:0:Name = Console -WriteTo:0:Args:outputTemplate = {Timestamp:yyyy-MM-ddTHH:mm:ss.fffzzz} {ThreadId} {Level} {SourceContext} {Message:l}{NewLine}{Exception} -Enrich:0 = FromLogContext -Enrich:1 = WithThreadId -WriteTo:Async:Name = Async -WriteTo:Async:Args:configure:0:Name = File -WriteTo:Async:Args:configure:0:Args:path = log.txt -WriteTo:Async:Args:configure:0:Args:outputTemplate = {Timestamp:yyyy-MM-ddTHH:mm:ss.fffzzz} {ThreadId} {Level} {SourceContext} {Message:l}{NewLine}{Exception} -WriteTo:Async:Args:configure:0:Args:rollOnFileSizeLimit = true -WriteTo:Async:Args:configure:0:Args:fileSizeLimitBytes = 104857600 -WriteTo:Async:Args:configure:0:Args:retainedFileCountLimit = 5 diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/bjdire.sqlite b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/bjdire.sqlite deleted file mode 100644 index e234fbb2..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/bjdire.sqlite +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dca11ebff6fa896f7ab5cd900ce2bbcd6d4599435e2d5800f19266bd75d3191f -size 36864 diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/packages.lock.json b/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/packages.lock.json deleted file mode 100644 index 346de03c..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.ServerConsole/packages.lock.json +++ /dev/null @@ -1,771 +0,0 @@ -{ - "version": 2, - "dependencies": { - "net6.0": { - "DotNet.ReproducibleBuilds": { - "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==", - "dependencies": { - "Microsoft.SourceLink.AzureRepos.Git": "1.1.1", - "Microsoft.SourceLink.Bitbucket.Git": "1.1.1", - "Microsoft.SourceLink.GitHub": "1.1.1", - "Microsoft.SourceLink.GitLab": "1.1.1" - } - }, - "Microsoft.CodeAnalysis.BannedApiAnalyzers": { - "type": "Direct", - "requested": "[3.3.3, )", - "resolved": "3.3.3", - "contentHash": "vvz3XCHVrd/Ks4xPoutLmL/T2+8JcOk/OMs3ngwQqnzokQCGEDsY+WjK/txCsDWU29sX3fGzH/FnYwNV93O1mA==" - }, - "Microsoft.CodeAnalysis.NetAnalyzers": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "cjG06LMeOADNUeCUaklOfVgrnVkLy80H5PVll4QHDUXv+C+6G9rHczrNdWjfb3xKv3Ts9s4UsP6J2ZWe52Gz4Q==" - }, - "Microsoft.EntityFrameworkCore.Design": { - "type": "Direct", - "requested": "[6.0.9, )", - "resolved": "6.0.9", - "contentHash": "F+1dYjaxMG181+seb2xK4uLU1UoTR0UZRcfYzSQFfVFwAyWtCp3uooNorWYE3BnJAHNEVJgsGmlfYAEGsrewqg==", - "dependencies": { - "Humanizer.Core": "2.8.26", - "Microsoft.EntityFrameworkCore.Relational": "6.0.9" - } - }, - "Microsoft.EntityFrameworkCore.InMemory": { - "type": "Direct", - "requested": "[6.0.9, )", - "resolved": "6.0.9", - "contentHash": "uQWxbNXOSvvQWgcDRTIfP6xC6NvyH/B8TlhCumzrPOy681LOS9RAoMPTlClboE3NyK5ptfzZhkO2vRTki0lFFw==", - "dependencies": { - "Microsoft.EntityFrameworkCore": "6.0.9" - } - }, - "Microsoft.EntityFrameworkCore.Sqlite": { - "type": "Direct", - "requested": "[6.0.9, )", - "resolved": "6.0.9", - "contentHash": "kaAUWwv967c1pZUD1xQ4+XYGaRfIxqaRjVE8sv8ZSG+FXdqz7wYT9GB/1Sv2j0hgqknOpTrUu4x5O6RVyhPjEA==", - "dependencies": { - "Microsoft.EntityFrameworkCore.Sqlite.Core": "6.0.9", - "SQLitePCLRaw.bundle_e_sqlite3": "2.0.6" - } - }, - "Microsoft.Extensions.Configuration.CommandLine": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "3nL1qCkZ1Oxx14ZTzgo4MmlO7tso7F+TtMZAY2jUAtTLyAcDp+EDjk3RqafoKiNaePyPvvlleEcBxh3b2Hzl1g==", - "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration.Ini": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "4p1kPxibT+RNlj91k9SfvtNIUALqru9xmh+XT7Pfw80WAufCmgj3F81hpXZ4YOcFFphBSw1a+n8NZQooWxCHWQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0" - } - }, - "Microsoft.Extensions.DependencyInjection": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "Microsoft.Extensions.Hosting": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "M8VzD0ni5VarIRT8njnwK4K2WSAo0kZH4Zc3mKcSGkP4CjDZ91T9ZEFmmwhmo4z7x8AFq+tW0WFi9wX+K2cxkQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Configuration.Binder": "6.0.0", - "Microsoft.Extensions.Configuration.CommandLine": "6.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "6.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "6.0.0", - "Microsoft.Extensions.Configuration.Json": "6.0.0", - "Microsoft.Extensions.Configuration.UserSecrets": "6.0.0", - "Microsoft.Extensions.DependencyInjection": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Physical": "6.0.0", - "Microsoft.Extensions.Hosting.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging.Configuration": "6.0.0", - "Microsoft.Extensions.Logging.Console": "6.0.0", - "Microsoft.Extensions.Logging.Debug": "6.0.0", - "Microsoft.Extensions.Logging.EventLog": "6.0.0", - "Microsoft.Extensions.Logging.EventSource": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0" - } - }, - "Microsoft.Extensions.Logging": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "System.Diagnostics.DiagnosticSource": "6.0.0" - } - }, - "Microsoft.Extensions.Logging.Configuration": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "ZDskjagmBAbv+K8rYW9VhjPplhbOE63xUD0DiuydZJwt15dRyoqicYklLd86zzeintUc7AptDkHn+YhhYkYo8A==", - "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Configuration.Binder": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "6.0.0" - } - }, - "Microsoft.Extensions.Logging.Debug": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "M9g/JixseSZATJE9tcMn9uzoD4+DbSglivFqVx8YkRJ7VVPmnvCEbOZ0AAaxsL1EKyI4cz07DXOOJExxNsUOHw==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0" - } - }, - "Microsoft.Extensions.Options.ConfigurationExtensions": { - "type": "Direct", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "bXWINbTn0vC0FYc9GaQTISbxhQLAMrvtbuvD9N6JelEaIS/Pr62wUCinrq5bf1WRBGczt1v4wDhxFtVFNcMdUQ==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Configuration.Binder": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.NETFramework.ReferenceAssemblies": { - "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", - "dependencies": { - "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3" - } - }, - "Microsoft.SourceLink.GitHub": { - "type": "Direct", - "requested": "[1.1.1, )", - "resolved": "1.1.1", - "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Nerdbank.GitVersioning": { - "type": "Direct", - "requested": "[3.5.113, )", - "resolved": "3.5.113", - "contentHash": "4fBSMkqhi410qlkjPm+Mxfk8iO3C7dmgdVS7ljsfVO21WEzZCHP1VCOqB6rlOPfPidR/oxX+/Do/I7meCAz+Jg==" - }, - "Serilog": { - "type": "Direct", - "requested": "[2.12.0, )", - "resolved": "2.12.0", - "contentHash": "xaiJLIdu6rYMKfQMYUZgTy8YK7SMZjB4Yk50C/u//Z4OsvxkUfSPJy4nknfvwAC34yr13q7kcyh4grbwhSxyZg==" - }, - "Serilog.Enrichers.Thread": { - "type": "Direct", - "requested": "[3.1.0, )", - "resolved": "3.1.0", - "contentHash": "85lWsGRJpRxvKT6j/H67no55SUBsBIvp556TKuBTGhjtoPeq+L7j/sDWbgAtvT0p7u7/phJyX6j35PQ4Vtqw0g==", - "dependencies": { - "Serilog": "2.3.0" - } - }, - "Serilog.Extensions.Logging": { - "type": "Direct", - "requested": "[3.1.0, )", - "resolved": "3.1.0", - "contentHash": "IWfem7wfrFbB3iw1OikqPFNPEzfayvDuN4WP7Ue1AVFskalMByeWk3QbtUXQR34SBkv1EbZ3AySHda/ErDgpcg==", - "dependencies": { - "Microsoft.Extensions.Logging": "2.0.0", - "Serilog": "2.9.0" - } - }, - "Serilog.Settings.Configuration": { - "type": "Direct", - "requested": "[3.4.0, )", - "resolved": "3.4.0", - "contentHash": "ULloXSiapTb3zOWodC0G4WRDQzA5RjMEfZNZzOZpH8kC3t/lrISLblklIpKC44CX0sMDF40MnJwTIQ3pFQFs4g==", - "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "2.0.0", - "Microsoft.Extensions.DependencyModel": "3.0.0", - "Serilog": "2.10.0" - } - }, - "Serilog.Sinks.Async": { - "type": "Direct", - "requested": "[1.5.0, )", - "resolved": "1.5.0", - "contentHash": "csHYIqAwI4Gy9oAhXYRwxGrQEAtBg3Ep7WaCzsnA1cZuBZjVAU0n7hWaJhItjO7hbLHh/9gRVxALCUB4Dv+gZw==", - "dependencies": { - "Serilog": "2.9.0" - } - }, - "Serilog.Sinks.Console": { - "type": "Direct", - "requested": "[4.1.0, )", - "resolved": "4.1.0", - "contentHash": "K6N5q+5fetjnJPvCmkWOpJ/V8IEIoMIB1s86OzBrbxwTyHxdx3pmz4H+8+O/Dc/ftUX12DM1aynx/dDowkwzqg==", - "dependencies": { - "Serilog": "2.10.0" - } - }, - "Serilog.Sinks.File": { - "type": "Direct", - "requested": "[5.0.0, )", - "resolved": "5.0.0", - "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==", - "dependencies": { - "Serilog": "2.10.0" - } - }, - "StyleCop.Analyzers": { - "type": "Direct", - "requested": "[1.2.0-beta.435, )", - "resolved": "1.2.0-beta.435", - "contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==", - "dependencies": { - "StyleCop.Analyzers.Unstable": "1.2.0.435" - } - }, - "Grpc.Core.Api": { - "type": "Transitive", - "resolved": "2.46.3", - "contentHash": "uy1oe5baVa4V+C8ZyMiA8xYdNIx5A3PiacQL0f1zWDjF2z64Cb1MMXXRTs3GX+jeKpoK/RtOZg8UnJSm2KC/pQ==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, - "Humanizer.Core": { - "type": "Transitive", - "resolved": "2.8.26", - "contentHash": "OiKusGL20vby4uDEswj2IgkdchC1yQ6rwbIkZDVBPIR6al2b7n3pC91elBul9q33KaBgRKhbZH3+2Ur4fnWx2A==" - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" - }, - "Microsoft.Data.Sqlite.Core": { - "type": "Transitive", - "resolved": "6.0.9", - "contentHash": "vH2Mul/lTqCYIaLDl1ICvv8LrDl1870s7erbRjyWdMNWIzL05I+k6osKifzQpqFNkhAApjU3GgEYHuw1XZBoxA==", - "dependencies": { - "SQLitePCLRaw.core": "2.0.6" - } - }, - "Microsoft.EntityFrameworkCore": { - "type": "Transitive", - "resolved": "6.0.9", - "contentHash": "3QxYF6TR14O3cSZitdzM10Smsw+hweLXyB45PN4ZVjrX4GqzUoGZ0ZC06r0ST7O7SgYxNjxw34ay5XXbBTX86A==", - "dependencies": { - "Microsoft.EntityFrameworkCore.Abstractions": "6.0.9", - "Microsoft.EntityFrameworkCore.Analyzers": "6.0.9", - "Microsoft.Extensions.Caching.Memory": "6.0.1", - "Microsoft.Extensions.DependencyInjection": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "System.Collections.Immutable": "6.0.0", - "System.Diagnostics.DiagnosticSource": "6.0.0" - } - }, - "Microsoft.EntityFrameworkCore.Abstractions": { - "type": "Transitive", - "resolved": "6.0.9", - "contentHash": "XglcSAr6EtjqJpI0DjMMDWkq3l5zG45hRHgrodZFMxNxE7KettJ+X8Em39Aaa0XQwH2P+NHVyK+xhtPX8ogdEA==" - }, - "Microsoft.EntityFrameworkCore.Analyzers": { - "type": "Transitive", - "resolved": "6.0.9", - "contentHash": "rNIx4fr7KWH4ypghhI+78PhCUYBHdjVbQ3yKvj/KmUIe4d9pysHXT3lF9TuReVdMDsn5mEx+3Yez8s80J4/JLA==" - }, - "Microsoft.EntityFrameworkCore.Relational": { - "type": "Transitive", - "resolved": "6.0.9", - "contentHash": "LAZHEvlgSg6OUzLUH3BoVneYrQj7cQqwwFnzSfwVGNjQvj5RRh7Vz0eSXLKfQD4xv5QuSm3l+MzFMZC1NBPQHw==", - "dependencies": { - "Microsoft.EntityFrameworkCore": "6.0.9", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0" - } - }, - "Microsoft.EntityFrameworkCore.Sqlite.Core": { - "type": "Transitive", - "resolved": "6.0.9", - "contentHash": "yo2m2Tvi0f8SQPBaFTmmO2P+sLNl5Zz23JsV7J85N4AFXyDMvCiS0eza/90HgJ/RgrGssEIC2jvaABRreRKl/g==", - "dependencies": { - "Microsoft.Data.Sqlite.Core": "6.0.9", - "Microsoft.EntityFrameworkCore.Relational": "6.0.9", - "Microsoft.Extensions.DependencyModel": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "tq2wXyh3fL17EMF2bXgRhU7JrbO3on93MRKYxzz4JzzvuGSA1l0W3GI9/tl8EO89TH+KWEymP7bcFway6z9fXg==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration.Abstractions": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==", - "dependencies": { - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration.FileExtensions": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "V4Dth2cYMZpw3HhGw9XUDIijpI6gN+22LDt0AhufIgOppCUfpWX4483OmN+dFXRJkJLc8Tv0Q8QK+1ingT2+KQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Physical": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration.Json": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "GJGery6QytCzS/BxJ96klgG9in3uH26KcUBbiVG/coNDXCRq6LGVVlUT4vXq34KPuM+R2av+LeYdX9h4IZOCUg==", - "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", - "System.Text.Json": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration.UserSecrets": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "lB0Hb2V4+RUHy+LjEcqEr4EcV4RWc9EnjAV2GdtWQEdljQX+R4hGREftI7sInU9okP93pDrJiaj6QUJ6ZsslOA==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Configuration.Json": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Physical": "6.0.0" - } - }, - "Microsoft.Extensions.DependencyInjection.Abstractions": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg==" - }, - "Microsoft.Extensions.DependencyModel": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "TD5QHg98m3+QhgEV1YVoNMl5KtBw/4rjfxLHO0e/YV9bPUBDKntApP4xdrVtGgCeQZHVfC2EXIGsdpRNrr87Pg==", - "dependencies": { - "System.Buffers": "4.5.1", - "System.Memory": "4.5.4", - "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Encodings.Web": "6.0.0", - "System.Text.Json": "6.0.0" - } - }, - "Microsoft.Extensions.FileProviders.Physical": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "QvkL7l0nM8udt3gfyu0Vw8bbCXblxaKOl7c2oBfgGy4LCURRaL9XWZX1FWJrQc43oMokVneVxH38iz+bY1sbhg==", - "dependencies": { - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", - "Microsoft.Extensions.FileSystemGlobbing": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.FileSystemGlobbing": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "ip8jnL1aPiaPeKINCqaTEbvBFDmVx9dXQEBZ2HOBRXPD1eabGNqP/bKlsIcp7U2lGxiXd5xIhoFcmY8nM4Hdiw==" - }, - "Microsoft.Extensions.Hosting.Abstractions": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "GcT5l2CYXL6Sa27KCSh0TixsRfADUgth+ojQSD5EkzisZxmGFh7CwzkcYuGwvmXLjr27uWRNrJ2vuuEjMhU05Q==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0" - } - }, - "Microsoft.Extensions.Logging.EventLog": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "rlo0RxlMd0WtLG3CHI0qOTp6fFn7MvQjlrCjucA31RqmiMFCZkF8CHNbe8O7tbBIyyoLGWB1he9CbaA5iyHthg==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "System.Diagnostics.EventLog": "6.0.0" - } - }, - "Microsoft.Extensions.Logging.EventSource": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "BeDyyqt7nkm/nr+Gdk+L8n1tUT/u33VkbXAOesgYSNsxDM9hJ1NOBGoZfj9rCbeD2+9myElI6JOVVFmnzgeWQA==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0", - "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Json": "6.0.0" - } - }, - "Microsoft.Extensions.Primitives": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "Microsoft.NETFramework.ReferenceAssemblies.net461": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==" - }, - "Microsoft.SourceLink.AzureRepos.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Bitbucket.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==" - }, - "Microsoft.SourceLink.GitLab": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "SQLitePCLRaw.bundle_e_sqlite3": { - "type": "Transitive", - "resolved": "2.0.6", - "contentHash": "zssYqiaucyGArZfg74rJuzK0ewgZiidsRVrZTmP7JLNvK806gXg6PGA46XzoJGpNPPA5uRcumwvVp6YTYxtQ5w==", - "dependencies": { - "SQLitePCLRaw.core": "2.0.6", - "SQLitePCLRaw.lib.e_sqlite3": "2.0.6", - "SQLitePCLRaw.provider.e_sqlite3": "2.0.6" - } - }, - "SQLitePCLRaw.core": { - "type": "Transitive", - "resolved": "2.0.6", - "contentHash": "Vh8n0dTvwXkCGur2WqQTITvk4BUO8i8h9ucSx3wwuaej3s2S6ZC0R7vqCTf9TfS/I4QkXO6g3W2YQIRFkOcijA==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, - "SQLitePCLRaw.lib.e_sqlite3": { - "type": "Transitive", - "resolved": "2.0.6", - "contentHash": "xlstskMKalKQl0H2uLNe0viBM6fvAGLWqKZUQ3twX5y1tSOZKe0+EbXopQKYdbjJytNGI6y5WSKjpI+kVr2Ckg==" - }, - "SQLitePCLRaw.provider.e_sqlite3": { - "type": "Transitive", - "resolved": "2.0.6", - "contentHash": "peXLJbhU+0clVBIPirihM1NoTBqw8ouBpcUsVMlcZ4k6fcL2hwgkctVB2Nt5VsbnOJcPspQL5xQK7QvLpxkMgg==", - "dependencies": { - "SQLitePCLRaw.core": "2.0.6" - } - }, - "StyleCop.Analyzers.Unstable": { - "type": "Transitive", - "resolved": "1.2.0.435", - "contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg==" - }, - "System.Buffers": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" - }, - "System.Diagnostics.DiagnosticSource": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "frQDfv0rl209cKm1lnwTgFPzNigy2EKk1BS3uAvHvlBVKe5cymGyHO+Sj+NLv5VF/AhHsqPIUUwya5oV4CHMUw==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "System.Diagnostics.EventLog": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==" - }, - "System.Runtime.CompilerServices.Unsafe": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" - }, - "System.Text.Encodings.Web": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "crc32c.net": { - "type": "Project" - }, - "geothermalresearchinstitute.fakeplcv2": { - "type": "Project", - "dependencies": { - "GeothermalResearchInstitute.PlcV2": "[1.0.0, )" - } - }, - "geothermalresearchinstitute.grpc": { - "type": "Project", - "dependencies": { - "Google.Protobuf": "[3.21.6, )", - "Grpc": "[2.46.3, )" - } - }, - "geothermalresearchinstitute.plcv2": { - "type": "Project", - "dependencies": { - "Crc32C.NET": "[1.0.0, )", - "GeothermalResearchInstitute.Grpc": "[1.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[6.0.0, )", - "System.Memory": "[4.5.5, )", - "System.Threading.Tasks.Dataflow": "[6.0.0, )" - } - }, - "hcoona.microsoftextensions.logging.grpcadapter": { - "type": "Project", - "dependencies": { - "Grpc.Core": "[2.46.3, )", - "Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )" - } - }, - "Google.Protobuf": { - "type": "CentralTransitive", - "requested": "[3.21.6, )", - "resolved": "3.21.6", - "contentHash": "HSYHFnfuTu/O4Ijy0mCW9zxLI8MJfCZJ10dk3JGPrkLaRR4LsiPKzZrrnapf2G0tP2yRMkHCl+2LKLTXqGBn2A==" - }, - "Grpc": { - "type": "CentralTransitive", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "79TsAcLBVl5J7AmtnV+GmgkhWlpK3D9JYJDhYxZGO0DKukbyrRxxcbaFlRZ84WGwTAW8LezrInUYgfiJi3zGVg==", - "dependencies": { - "Grpc.Core": "2.46.3" - } - }, - "Grpc.Core": { - "type": "CentralTransitive", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "lu7KP7BVWdvFXWbn/IFYHBQCpMohJwbLM1aL+nu2C0pY2CdS0idaUNAJNC2nZ60fXfqoxnSiERrIU6rC474oTw==", - "dependencies": { - "Grpc.Core.Api": "2.46.3", - "System.Memory": "4.5.3" - } - }, - "Microsoft.Extensions.Caching.Abstractions": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "bcz5sSFJbganH0+YrfvIjJDIcKNW7TL07C4d1eTmXy/wOt52iz4LVogJb6pazs7W0+74j0YpXFErvp++Aq5Bsw==", - "dependencies": { - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.Caching.Memory": { - "type": "CentralTransitive", - "requested": "[6.0.1, )", - "resolved": "6.0.1", - "contentHash": "B4y+Cev05eMcjf1na0v9gza6GUtahXbtY1JCypIgx3B4Ea/KAgsWyXEmW4q6zMbmTMtKzmPVk09rvFJirvMwTg==", - "dependencies": { - "Microsoft.Extensions.Caching.Abstractions": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration.Binder": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "b3ErKzND8LIC7o08QAVlKfaEIYEvLJbtmVbFZVBRXeu9YkKfSSzLZfR1SUfQPBIy9mKLhEtJgGYImkcMNaKE0A==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration.EnvironmentVariables": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "DjYkzqvhiHCq38LW71PcIxXk6nhtV6VySP9yDcSO0goPl7YCU1VG1f2Wbgy58lkA10pWkjHCblZPUyboCB93ZA==", - "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0" - } - }, - "Microsoft.Extensions.FileProviders.Abstractions": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "0pd4/fho0gC12rQswaGQxbU34jOS1TPS8lZPpkFCH68ppQjHNHYle9iRuHeev1LhrJ94YPvzcRd8UmIuFk23Qw==", - "dependencies": { - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.Logging.Abstractions": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA==" - }, - "Microsoft.Extensions.Logging.Console": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "gsqKzOEdsvq28QiXFxagmn1oRB9GeI5GgYCkoybZtQA0IUb7QPwf1WmN3AwJeNIsadTvIFQCiVK0OVIgKfOBGg==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging.Configuration": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "System.Text.Json": "6.0.0" - } - }, - "Microsoft.Extensions.Options": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "System.Collections.Immutable": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "l4zZJ1WU2hqpQQHXz1rvC3etVZN+2DLmQMO79FhOTZHMn8tDRr+WU287sbomD0BETlmKDn0ygUgVy9k5xkkJdA==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "System.Memory": { - "type": "CentralTransitive", - "requested": "[4.5.5, )", - "resolved": "4.5.5", - "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" - }, - "System.Text.Json": { - "type": "CentralTransitive", - "requested": "[6.0.6, )", - "resolved": "6.0.6", - "contentHash": "GZ+62pLOr544jwSvyXv5ezSfzlFBTjLuPhgOS2dnKuknAA8dPNUGXLKTHf9XdsudU9JpbtweXnE4oEiKEB2T1Q==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Encodings.Web": "6.0.0" - } - }, - "System.Threading.Tasks.Dataflow": { - "type": "CentralTransitive", - "requested": "[6.0.0, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" - } - }, - "net6.0/win-x64": { - "SQLitePCLRaw.lib.e_sqlite3": { - "type": "Transitive", - "resolved": "2.0.6", - "contentHash": "xlstskMKalKQl0H2uLNe0viBM6fvAGLWqKZUQ3twX5y1tSOZKe0+EbXopQKYdbjJytNGI6y5WSKjpI+kVr2Ckg==" - }, - "System.Diagnostics.EventLog": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==" - }, - "System.Text.Encodings.Web": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "Grpc.Core": { - "type": "CentralTransitive", - "requested": "[2.46.3, )", - "resolved": "2.46.3", - "contentHash": "lu7KP7BVWdvFXWbn/IFYHBQCpMohJwbLM1aL+nu2C0pY2CdS0idaUNAJNC2nZ60fXfqoxnSiERrIU6rC474oTw==", - "dependencies": { - "Grpc.Core.Api": "2.46.3", - "System.Memory": "4.5.3" - } - } - } - } -} \ No newline at end of file diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/App.xaml b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/App.xaml deleted file mode 100644 index a4b93dfb..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/App.xaml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/App.xaml.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/App.xaml.cs deleted file mode 100644 index 3412bcda..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/App.xaml.cs +++ /dev/null @@ -1,172 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Threading.Tasks; -using System.Windows; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Modules; -using GeothermalResearchInstitute.Wpf.Options; -using GeothermalResearchInstitute.Wpf.ViewModels; -using GeothermalResearchInstitute.Wpf.Views; -using Grpc.Core; -using HCOONa.MicrosoftExtensions.Logging.GrpcAdapater; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Prism.Ioc; -using Prism.Modularity; -using Prism.Unity; -using Prism.Unity.Ioc; -using Serilog; -using Unity; -using Unity.Microsoft.DependencyInjection; - -namespace GeothermalResearchInstitute.Wpf -{ - public partial class App : PrismApplication - { - private IUnityContainer UnityContainer { get; set; } - - private IHost Host { get; set; } - - protected override void OnStartup(StartupEventArgs e) - { - this.SetupExceptionHandling(); - - this.UnityContainer = new UnityContainer(); - - this.Host = new HostBuilder() - .UseServiceProviderFactory(new ServiceProviderFactory(this.UnityContainer)) - .ConfigureHostConfiguration(builder => builder - .SetBasePath(Environment.CurrentDirectory) - .AddIniFile("appsettings.ini", optional: false, reloadOnChange: true) - .AddCommandLine(e.Args)) - .ConfigureAppConfiguration((context, builder) => - { - IHostEnvironment env = context.HostingEnvironment; - builder - .SetBasePath(Environment.CurrentDirectory) - .AddIniFile("appsettings.ini", optional: false, reloadOnChange: true) - .AddIniFile($"appsettings.{env.EnvironmentName}.ini", optional: false, reloadOnChange: true) - .AddCommandLine(e.Args); - }) - .ConfigureLogging((context, builder) => - { - IHostEnvironment env = context.HostingEnvironment; - if (env.IsDevelopment() || env.IsStaging()) - { - builder.AddDebug(); - } - - Log.Logger = new LoggerConfiguration() - .ReadFrom.Configuration(context.Configuration) - .CreateLogger(); - builder.AddSerilog(dispose: true); - - builder.AddConfiguration(context.Configuration.GetSection("Logging")); - }) - .ConfigureServices((context, builder) => - { - IHostEnvironment env = context.HostingEnvironment; - IConfiguration config = context.Configuration; - - builder.Configure(config.GetSection("core")); - - builder.AddSingleton(serviceProvider => - { - return new GrpcLogger( - serviceProvider.GetRequiredService(), - serviceProvider.GetRequiredService>()); - }); - - if (env.IsDevelopment()) - { -#if DEBUG - builder.AddSingleton< - DeviceService.DeviceServiceClient, - FakeClients.FakeDeviceServiceClient>(); -#endif - } - else - { - builder.AddSingleton(provider => - { - IOptions coreOptions = - provider.GetRequiredService>(); - return new Channel( - coreOptions.Value.ServerGrpcAddress, - coreOptions.Value.ServerGrpcPort, - ChannelCredentials.Insecure); - }); - builder.AddSingleton(provider => - new DeviceService.DeviceServiceClient(provider.GetRequiredService())); - } - }) - .Build(); - - base.OnStartup(e); - } - - protected override Window CreateShell() - { - return this.Container.Resolve(); - } - - protected override IContainerExtension CreateContainerExtension() - { - return new UnityContainerExtension(this.Host.Services.GetRequiredService()); - } - - protected override void RegisterTypes(IContainerRegistry containerRegistry) - { - containerRegistry.RegisterInstance(new ViewModelContext - { - Principal = null, - UserBarVisibility = Visibility.Visible, - BannerVisibility = Visibility.Collapsed, - NavigateBackTarget = null, - }); - } - - protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) - { - base.ConfigureModuleCatalog(moduleCatalog); - moduleCatalog - .AddModule() - .AddModule() - .AddModule() - .AddModule() - .AddModule() - .AddModule(); - } - - protected override void OnExit(ExitEventArgs e) - { - this.Host.Dispose(); - - base.OnExit(e); - } - - private static void MessageBoxShowException(Exception e, string caption) - { - MessageBox.Show(e.ToString(), caption, MessageBoxButton.OK, MessageBoxImage.Error); - } - - private void SetupExceptionHandling() - { - AppDomain.CurrentDomain.UnhandledException += (s, e) => - MessageBoxShowException((Exception)e.ExceptionObject, "AppDomain.CurrentDomain.UnhandledException"); - - this.Dispatcher.UnhandledException += (s, e) => - MessageBoxShowException(e.Exception, "Application.Current.DispatcherUnhandledException"); - - TaskScheduler.UnobservedTaskException += (s, e) => - MessageBoxShowException(e.Exception, "TaskScheduler.UnobservedTaskException"); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Common/Constants.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Common/Constants.cs deleted file mode 100644 index 425f7235..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Common/Constants.cs +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -namespace GeothermalResearchInstitute.Wpf.Common -{ - public static class Constants - { - public static string BannerRegion { get; } = nameof(BannerRegion); - - public static string UserBarRegion { get; } = nameof(UserBarRegion); - - public static string ContentRegion { get; } = nameof(ContentRegion); - - public static string UserRoleOperator { get; } = "Operator"; - - public static string UserRoleAdministrator { get; } = "Administrator"; - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Common/ProtoUtils.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Common/ProtoUtils.cs deleted file mode 100644 index 9e15909e..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Common/ProtoUtils.cs +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Common; - -namespace GeothermalResearchInstitute.Wpf.Common -{ - public static class ProtoUtils - { - public static string ConvertToString(UserRole role) => role switch - { - UserRole.Administrator => Constants.UserRoleAdministrator, - UserRole.User => Constants.UserRoleOperator, - _ => throw new ArgumentOutOfRangeException(nameof(role)), - }; - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Common/RandomUtils.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Common/RandomUtils.cs deleted file mode 100644 index 8cb62c52..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Common/RandomUtils.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Threading; - -namespace GeothermalResearchInstitute.Wpf.Common -{ - public static class RandomUtils - { - private static readonly ThreadLocal ThreadLocalRandom = new ThreadLocal(() => new Random()); - - public static double NextDouble() - { - return ThreadLocalRandom.Value.NextDouble(); - } - - public static double NextDouble(double startInclusive, double endExclusive) - { - return startInclusive + (ThreadLocalRandom.Value.NextDouble() * (endExclusive - startInclusive)); - } - - public static float NextFloat(float startInclusive, float endExclusive) - => (float)NextDouble(startInclusive, endExclusive); - - public static int Next(int startInclusive, int endExclusive) => - ThreadLocalRandom.Value.Next(startInclusive, endExclusive); - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Common/RpcExceptionUtil.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Common/RpcExceptionUtil.cs deleted file mode 100644 index 054fcd20..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Common/RpcExceptionUtil.cs +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System.Windows; -using Grpc.Core; - -namespace GeothermalResearchInstitute.Wpf.Common -{ - internal static class RpcExceptionUtil - { - public static void ShowMessageBox(this RpcException e) - { - string text = e.StatusCode switch - { - StatusCode.DeadlineExceeded => "网络连接错误,请检查到服务器的连接是否正常", - StatusCode.Unavailable => "网络连接错误,请检查到服务器的连接是否正常", - StatusCode.Unauthenticated => "用户名或密码错误", - _ => "其他未知错误:\n" + e.ToString(), - }; - - MessageBox.Show(text, "远程连接错误", MessageBoxButton.OK, MessageBoxImage.Error); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Events/PrincipalUpdatedEvent.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Events/PrincipalUpdatedEvent.cs deleted file mode 100644 index 0401f76a..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Events/PrincipalUpdatedEvent.cs +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using Prism.Events; - -namespace GeothermalResearchInstitute.Wpf.Events -{ - public class PrincipalUpdatedEvent : PubSubEvent - { - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/FakeClients/FakeDeviceServiceClient.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/FakeClients/FakeDeviceServiceClient.cs deleted file mode 100644 index a0cebffd..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/FakeClients/FakeDeviceServiceClient.cs +++ /dev/null @@ -1,407 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Threading; -using System.Threading.Tasks; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Common; -using Google.Protobuf; -using Google.Protobuf.WellKnownTypes; -using Grpc.Core; -using Grpc.Core.Testing; - -namespace GeothermalResearchInstitute.Wpf.FakeClients -{ - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Design", "CA1062:验证公共方法的参数", Justification = "Guaranteed by framework.")] - public class FakeDeviceServiceClient : DeviceService.DeviceServiceClient - { - public static readonly ByteString Id1 = ByteString.CopyFrom(new byte[] { 0x10, 0xBF, 0x48, 0x79, 0xB2, 0xA4 }); - public static readonly ByteString Id2 = ByteString.CopyFrom(new byte[] { 0xBC, 0x96, 0x80, 0xE6, 0x70, 0x16 }); - public static readonly ByteString Id3 = ByteString.CopyFrom(new byte[] { 0xBC, 0x96, 0x80, 0xE6, 0x70, 0x17 }); - - public static readonly Dictionary Devices = new Dictionary - { - { - Id1, - new Device - { - Id = Id1, - Ipv4Address = ByteString.CopyFromUtf8("10.0.0.1"), - Name = "测试设备1", - Status = DeviceStatus.Healthy, - } - }, - { - Id2, - new Device - { - Id = Id2, - Ipv4Address = ByteString.CopyFromUtf8("10.0.0.2"), - Name = "测试设备2", - Status = DeviceStatus.Unhealthy, - } - }, - { - Id3, - new Device - { - Id = Id3, - Ipv4Address = ByteString.CopyFromUtf8("10.0.0.3"), - Name = "测试设备3", - Status = DeviceStatus.Disconnected, - } - }, - }; - - private static readonly Dictionary WorkingModes = new Dictionary - { - { - Id1, - new WorkingMode - { - DeviceWorkingMode = DeviceWorkingMode.SummerSituation, - DeviceFlowRateControlMode = DeviceFlowRateControlMode.VariableFrequency, - WaterPumpWorkingMode = WaterPumpWorkingMode.FixedFrequency, - } - }, - { - Id2, - new WorkingMode - { - DeviceWorkingMode = DeviceWorkingMode.WinterSituation, - DeviceFlowRateControlMode = DeviceFlowRateControlMode.VariableFrequency, - WaterPumpWorkingMode = WaterPumpWorkingMode.FixedFrequency, - } - }, - { - Id3, - new WorkingMode - { - DeviceWorkingMode = DeviceWorkingMode.TemperatureDetermination, - DeviceFlowRateControlMode = DeviceFlowRateControlMode.VariableFrequency, - WaterPumpWorkingMode = WaterPumpWorkingMode.FixedFrequency, - } - }, - }; - - private static readonly Dictionary RunningParameters = new Dictionary - { - { - Id1, - new RunningParameter - { - SummerHeaterCelsiusDegree = 13.7F, - WinterHeaterCelsiusDegree = 8.4F, - ColdPowerKilowatt = 4F, - WarmPowerKilowatt = 8F, - WaterPumpFlowRateCubicMeterPerHour = 28.4F, - WaterPumpFrequencyHertz = 20.8F, - } - }, - }; - - private static readonly Dictionary Switches = new Dictionary - { - { - Id1, - new Switch - { - DevicePowerOn = true, - ExhausterPowerOn = true, - HeaterPowerOn = true, - HeaterFourWayReversingOn = true, - HeaterFanOn = true, - HeaterCompressorOn = true, - HeaterAutoOn = true, - } - }, - { - Id2, - new Switch - { - DevicePowerOn = true, - ExhausterPowerOn = true, - HeaterPowerOn = true, - HeaterFourWayReversingOn = true, - HeaterFanOn = false, - HeaterCompressorOn = true, - HeaterAutoOn = true, - } - }, - }; - - public override AsyncUnaryCall AuthenticateAsync( - AuthenticateRequest request, - Metadata headers = null, - DateTime? deadline = null, - CancellationToken cancellationToken = default) - { - if (request.Username == "user" && request.Password == "user") - { - return TestCalls.AsyncUnaryCall( - Task.FromResult( - new AuthenticateResponse() - { - Nickname = "用户1", - Role = UserRole.User, - }), - Task.FromResult(new Metadata()), - () => Status.DefaultSuccess, - () => new Metadata(), - () => { }); - } - else if (request.Username == "admin" && request.Password == "admin") - { - return TestCalls.AsyncUnaryCall( - Task.FromResult( - new AuthenticateResponse() - { - Nickname = "管理员1", - Role = UserRole.Administrator, - }), - Task.FromResult(new Metadata()), - () => Status.DefaultSuccess, - () => new Metadata(), - () => { }); - } - else - { - var status = new Status(StatusCode.Unauthenticated, "Invalid username or password."); - return TestCalls.AsyncUnaryCall( - Task.FromException(new RpcException(status)), - Task.FromResult(new Metadata()), - () => status, - () => new Metadata(), - () => { }); - } - } - - public override AsyncUnaryCall ListDevicesAsync(ListDevicesRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default) - { - var response = new ListDevicesResponse(); - response.Devices.Add(Devices.Values); - return TestCalls.AsyncUnaryCall( - Task.FromResult(response), - Task.FromResult(new Metadata()), - () => Status.DefaultSuccess, - () => new Metadata(), - () => { }); - } - - public override AsyncUnaryCall GetWorkingModeAsync(GetWorkingModeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default) - { - return TestCalls.AsyncUnaryCall( - Task.FromResult(WorkingModes[request.DeviceId]), - Task.FromResult(new Metadata()), - () => Status.DefaultSuccess, - () => new Metadata(), - () => { }); - } - - public override AsyncUnaryCall UpdateWorkingModeAsync(UpdateWorkingModeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default) - { - WorkingMode workingMode = WorkingModes[request.DeviceId]; - if (request.UpdateMask == null) - { - workingMode.MergeFrom(request.WorkingMode); - } - else - { - request.UpdateMask.Merge(request.WorkingMode, workingMode); - } - - return TestCalls.AsyncUnaryCall( - Task.FromResult(workingMode), - Task.FromResult(new Metadata()), - () => Status.DefaultSuccess, - () => new Metadata(), - () => { }); - } - - public override AsyncUnaryCall GetRunningParameterAsync(GetRunningParameterRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default) - { - return TestCalls.AsyncUnaryCall( - Task.FromResult(RunningParameters[request.DeviceId]), - Task.FromResult(new Metadata()), - () => Status.DefaultSuccess, - () => new Metadata(), - () => { }); - } - - public override AsyncUnaryCall UpdateRunningParameterAsync(UpdateRunningParameterRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default) - { - RunningParameter runningParameter = RunningParameters[request.DeviceId]; - if (request.UpdateMask == null) - { - runningParameter.MergeFrom(request.RunningParameter); - } - else - { - request.UpdateMask.Merge(request.RunningParameter, runningParameter); - } - - return TestCalls.AsyncUnaryCall( - Task.FromResult(runningParameter), - Task.FromResult(new Metadata()), - () => Status.DefaultSuccess, - () => new Metadata(), - () => { }); - } - - public override AsyncUnaryCall ListMetricsAsync(ListMetricsRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default) - { - DateTimeOffset endDateTime; - if (string.IsNullOrEmpty(request.PageToken)) - { - endDateTime = request.EndTime?.ToDateTimeOffset() ?? DateTimeOffset.UtcNow; - } - else - { - endDateTime = DateTimeOffset.Parse(request.PageToken, CultureInfo.InvariantCulture); - } - - endDateTime = endDateTime.ToUniversalTime(); - var startDateTime = request.StartTime?.ToDateTime(); - - var metrics = new List(request.PageSize); - for (int i = 0; i < request.PageSize; i++) - { - endDateTime = endDateTime.Subtract(TimeSpan.FromSeconds(5)); - if (startDateTime.HasValue && startDateTime > endDateTime) - { - break; - } - - metrics.Add(new Metric - { - CreateTime = Timestamp.FromDateTimeOffset(endDateTime), - InputWaterCelsiusDegree = RandomUtils.NextFloat(10, 20), - OutputWaterCelsiusDegree = RandomUtils.NextFloat(10, 20), - HeaterOutputWaterCelsiusDegree = RandomUtils.NextFloat(10, 20), - EnvironmentCelsiusDegree = RandomUtils.NextFloat(10, 20), - HeaterPowerKilowatt = RandomUtils.NextFloat(0, 12), - WaterPumpFlowRateCubicMeterPerHour = RandomUtils.NextFloat(1, 3), - }); - } - - var response = new ListMetricsResponse - { - NextPageToken = endDateTime.ToUniversalTime().ToString(CultureInfo.InvariantCulture), - }; - response.Metrics.AddRange(metrics); - - return TestCalls.AsyncUnaryCall( - Task.FromResult(response), - Task.FromResult(new Metadata()), - () => Status.DefaultSuccess, - () => new Metadata(), - () => { }); - } - - public override AsyncUnaryCall GetMetricAsync(GetMetricRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default) - { - return TestCalls.AsyncUnaryCall( - Task.FromResult(new Metric - { - InputWaterCelsiusDegree = RandomUtils.NextFloat(10, 20), - OutputWaterCelsiusDegree = RandomUtils.NextFloat(10, 20), - HeaterOutputWaterCelsiusDegree = RandomUtils.NextFloat(10, 20), - EnvironmentCelsiusDegree = RandomUtils.NextFloat(10, 20), - HeaterPowerKilowatt = RandomUtils.NextFloat(0, 12), - WaterPumpFlowRateCubicMeterPerHour = RandomUtils.NextFloat(1, 3), - }), - Task.FromResult(new Metadata()), - () => Status.DefaultSuccess, - () => new Metadata(), - () => { }); - } - - public override AsyncUnaryCall GetSwitchAsync(GetSwitchRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default) - { - Switch switchInfo = Switches[request.DeviceId]; - - return TestCalls.AsyncUnaryCall( - Task.FromResult(switchInfo.Clone()), - Task.FromResult(new Metadata()), - () => Status.DefaultSuccess, - () => new Metadata(), - () => { }); - } - - public override AsyncUnaryCall UpdateSwitchAsync(UpdateSwitchRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default) - { - Switch switchInfo = Switches[request.DeviceId] ?? new Switch(); - - if (request.UpdateMask == null) - { - switchInfo.MergeFrom(request.Switch); - } - else - { - request.UpdateMask.Merge(request.Switch, switchInfo); - } - - Switches[request.DeviceId] = switchInfo; - - return TestCalls.AsyncUnaryCall( - Task.FromResult(switchInfo.Clone()), - Task.FromResult(new Metadata()), - () => Status.DefaultSuccess, - () => new Metadata(), - () => { }); - } - - public override AsyncUnaryCall ListAlarmChangesAsync(ListAlarmChangesRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default) - { - DateTimeOffset endDateTime; - if (string.IsNullOrEmpty(request.PageToken)) - { - endDateTime = request.EndTime?.ToDateTimeOffset() ?? DateTimeOffset.UtcNow; - } - else - { - endDateTime = DateTimeOffset.Parse(request.PageToken, CultureInfo.InvariantCulture); - } - - endDateTime = endDateTime.ToUniversalTime(); - var startDateTime = request.StartTime?.ToDateTime(); - - var alarmChanges = new List(request.PageSize); - for (int i = 0; i < request.PageSize; i++) - { - endDateTime = endDateTime.Subtract(TimeSpan.FromSeconds(5)); - if (startDateTime.HasValue && startDateTime > endDateTime) - { - break; - } - - alarmChanges.Add(new AlarmChange - { - CreateTime = Timestamp.FromDateTimeOffset(endDateTime), - AlarmType = (AlarmType)RandomUtils.Next(1, 7), - AlarmChangeDirection = (AlarmChangeDirection)RandomUtils.Next(1, 3), - }); - } - - var response = new ListAlarmChangesResponse - { - NextPageToken = endDateTime.ToUniversalTime().ToString(CultureInfo.InvariantCulture), - }; - - response.AlarmChanges.AddRange(alarmChanges); - - return TestCalls.AsyncUnaryCall( - Task.FromResult(response), - Task.FromResult(new Metadata()), - () => Status.DefaultSuccess, - () => new Metadata(), - () => { }); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/GeothermalResearchInstitute.Wpf.csproj b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/GeothermalResearchInstitute.Wpf.csproj deleted file mode 100644 index 2d3115a8..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/GeothermalResearchInstitute.Wpf.csproj +++ /dev/null @@ -1,89 +0,0 @@ - - - - - WinExe - $(CurrentWpfTargetFramework) - true - - win-x64 - true - False - False - False - - Full - True - - $(BaseArtifactsPath)\GeothermalResearchInstitute.Wpf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - true - - - PreserveNewest - true - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - true - - - PreserveNewest - true - - - diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/BannerModule.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/BannerModule.cs deleted file mode 100644 index 3cb3c60a..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/BannerModule.cs +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Views; -using Prism.Ioc; -using Prism.Modularity; -using Prism.Regions; - -namespace GeothermalResearchInstitute.Wpf.Modules -{ - public class BannerModule : IModule - { - public void OnInitialized(IContainerProvider containerProvider) - { - containerProvider.Resolve() - .RegisterViewWithRegion(Constants.BannerRegion, typeof(BannerView)); - } - - public void RegisterTypes(IContainerRegistry containerRegistry) - { - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/DeviceListModule.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/DeviceListModule.cs deleted file mode 100644 index 2774c04c..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/DeviceListModule.cs +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using GeothermalResearchInstitute.Wpf.Views; -using Prism.Ioc; -using Prism.Modularity; - -namespace GeothermalResearchInstitute.Wpf.Modules -{ - public class DeviceListModule : IModule - { - public void OnInitialized(IContainerProvider containerProvider) - { - } - - public void RegisterTypes(IContainerRegistry containerRegistry) - { - containerRegistry.RegisterForNavigation(); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/LoginModule.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/LoginModule.cs deleted file mode 100644 index 68a5ce59..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/LoginModule.cs +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using GeothermalResearchInstitute.Wpf.Views; -using Prism.Ioc; -using Prism.Modularity; - -namespace GeothermalResearchInstitute.Wpf.Modules -{ - public class LoginModule : IModule - { - public void OnInitialized(IContainerProvider containerProvider) - { - } - - public void RegisterTypes(IContainerRegistry containerRegistry) - { - containerRegistry.RegisterForNavigation(); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/NavigationModule.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/NavigationModule.cs deleted file mode 100644 index a3073418..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/NavigationModule.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using GeothermalResearchInstitute.Wpf.Views; -using Prism.Ioc; -using Prism.Modularity; - -namespace GeothermalResearchInstitute.Wpf.Modules -{ - public class NavigationModule : IModule - { - public void OnInitialized(IContainerProvider containerProvider) - { - } - - public void RegisterTypes(IContainerRegistry containerRegistry) - { - containerRegistry.RegisterForNavigation(); - containerRegistry.RegisterForNavigation(); - containerRegistry.RegisterForNavigation(); - containerRegistry.RegisterForNavigation(); - containerRegistry.RegisterForNavigation(); - containerRegistry.RegisterForNavigation(); - containerRegistry.RegisterForNavigation(); - containerRegistry.RegisterForNavigation(); - containerRegistry.RegisterForNavigation(); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/UserBarModule.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/UserBarModule.cs deleted file mode 100644 index a0c9b1bc..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/UserBarModule.cs +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Views; -using Prism.Ioc; -using Prism.Modularity; -using Prism.Regions; - -namespace GeothermalResearchInstitute.Wpf.Modules -{ - public class UserBarModule : IModule - { - public void OnInitialized(IContainerProvider containerProvider) - { - containerProvider.Resolve() - .RegisterViewWithRegion(Constants.UserBarRegion, typeof(UserBarView)); - } - - public void RegisterTypes(IContainerRegistry containerRegistry) - { - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/WelcomeModule.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/WelcomeModule.cs deleted file mode 100644 index ce1d24ab..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Modules/WelcomeModule.cs +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Views; -using Prism.Ioc; -using Prism.Modularity; -using Prism.Regions; - -namespace GeothermalResearchInstitute.Wpf.Modules -{ - public class WelcomeModule : IModule - { - public void OnInitialized(IContainerProvider containerProvider) - { - containerProvider.Resolve() - .RegisterViewWithRegion(Constants.ContentRegion, typeof(WelcomeView)); - } - - public void RegisterTypes(IContainerRegistry containerRegistry) - { - containerRegistry.RegisterForNavigation(); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Options/CoreOptions.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Options/CoreOptions.cs deleted file mode 100644 index 9e7d8934..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Options/CoreOptions.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System.Text.Json; - -namespace GeothermalResearchInstitute.Wpf.Options -{ - public class CoreOptions - { - public string ServerGrpcAddress { get; set; } - - public int ServerGrpcPort { get; set; } - - public int DefaultReadTimeoutMillis { get; set; } - - public int DefaultWriteTimeoutMillis { get; set; } - - public int DefaultPageSize { get; set; } = 50; - - public int DefaultRefreshIntervalMillis { get; set; } = 1000; - - public int MaxErrorToleranceNum { get; set; } = 5; - - public override string ToString() - { - return JsonSerializer.Serialize(this); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Properties/launchSettings.json b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Properties/launchSettings.json deleted file mode 100644 index 2d19c171..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "GeothermalResearchInstitute.Wpf": { - "commandName": "Project", - "commandLineArgs": "--Environment=Development" - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/DefaultStyle.xaml b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/DefaultStyle.xaml deleted file mode 100644 index 21fd98f4..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/DefaultStyle.xaml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/Strings.xaml b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/Strings.xaml deleted file mode 100644 index 5e505f26..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/Strings.xaml +++ /dev/null @@ -1,17 +0,0 @@ - - 浅层地温能测试仪远程监控系统 - - - 匿名用户 - 无权限 - 操作员 - 管理员 - - - 用户登录 - 用户注销 - 进入系统 - 联系我们 - diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/device.png b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/device.png deleted file mode 100644 index d155bd3e..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/device.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2e8c39a9d8ec41f0e4d198540704771b2d90ace032ee70365047733b705348bd -size 867272 diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/fan-new.png b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/fan-new.png deleted file mode 100644 index cc44b163..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/fan-new.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1e3a32efc5ded35a8da13b7e6ddda4f39f24952f6c8f3cf92c5616135bb9d7ce -size 12932 diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/left-arrow.png b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/left-arrow.png deleted file mode 100644 index 40822ed7..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/left-arrow.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:911d2919df01b19be9e13f0a355c2e9e16bf1ce6bd4a39eaa8a9ea5eb681ff87 -size 867272 diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/logo.png b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/logo.png deleted file mode 100644 index c0a1838b..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/logo.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:54938f1220f75a19bc5f38715566010e0efd35be8de4917fa88d08a9ea95a809 -size 52282 diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/right-arrow.png b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/right-arrow.png deleted file mode 100644 index 4a0261eb..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Resources/right-arrow.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:93890c5b33d94a955c3e5a9f694b0ea4b30fc752f0930fb45a8ecdd8218d3e71 -size 867272 diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/BannerViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/BannerViewModel.cs deleted file mode 100644 index 2fa0f182..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/BannerViewModel.cs +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Globalization; -using GeothermalResearchInstitute.Wpf.Common; -using Prism.Commands; -using Prism.Mvvm; -using Prism.Regions; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Microsoft.Performance", "CA1822", Justification = "ViewModel")] - public class BannerViewModel : BindableBase - { - private readonly IRegionManager regionManager; - private ViewModelContext viewModelContext; - - public BannerViewModel(IRegionManager regionManager) - { - this.regionManager = regionManager ?? throw new ArgumentNullException(nameof(regionManager)); - this.NavigateBackCommand = new DelegateCommand(this.ExecuteNavigateBackCommand); - - var dispatcherTimer = new System.Windows.Threading.DispatcherTimer(); - dispatcherTimer.Tick += this.DispatcherTimer_Tick; - dispatcherTimer.Interval = TimeSpan.FromSeconds(1); - dispatcherTimer.Start(); - } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set - { - this.SetProperty(ref this.viewModelContext, value); - this.viewModelContext.PropertyChanged += this.ViewModelContext_PropertyChanged; - } - } - - public string Title => this.ViewModelContext?.Title; - - public string CurrentLocalDateTimeString => DateTime.Now.ToString(CultureInfo.CurrentCulture); - - public DelegateCommand NavigateBackCommand { get; } - - private void ExecuteNavigateBackCommand() - { - this.regionManager.RequestNavigate(Constants.ContentRegion, this.ViewModelContext.NavigateBackTarget); - } - - private void DispatcherTimer_Tick(object sender, EventArgs e) - { - this.RaisePropertyChanged(nameof(this.CurrentLocalDateTimeString)); - } - - private void ViewModelContext_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) - { - this.RaisePropertyChanged(e.PropertyName); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceAlarmHistoryViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceAlarmHistoryViewModel.cs deleted file mode 100644 index 4ce2c9b0..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceAlarmHistoryViewModel.cs +++ /dev/null @@ -1,79 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.ObjectModel; -using System.Threading.Tasks; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Options; -using Grpc.Core; -using Microsoft.Extensions.Options; -using Prism.Mvvm; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - public class DeviceAlarmHistoryViewModel : BindableBase - { - private readonly IOptions coreOptions; - private readonly DeviceService.DeviceServiceClient client; - private ViewModelContext viewModelContext; - private string nextPageToken = null; - private bool noMore = false; - - public DeviceAlarmHistoryViewModel( - IOptions coreOptions, - DeviceService.DeviceServiceClient client) - { - this.coreOptions = coreOptions ?? throw new ArgumentNullException(nameof(coreOptions)); - this.client = client ?? throw new ArgumentNullException(nameof(client)); - } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set => this.SetProperty(ref this.viewModelContext, value); - } - - public ObservableCollection AlarmChanges { get; } = new ObservableCollection(); - - public async Task LoadAsync() - { - if (this.noMore) - { - return; - } - - var request = new ListAlarmChangesRequest - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - PageSize = this.coreOptions.Value.DefaultPageSize, - }; - - if (!string.IsNullOrEmpty(this.nextPageToken)) - { - request.PageToken = this.nextPageToken; - } - - try - { - ListAlarmChangesResponse response = await this.client.ListAlarmChangesAsync( - request, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultReadTimeoutMillis)); - this.AlarmChanges.AddRange(response.AlarmChanges); - this.nextPageToken = response.NextPageToken; - } - catch (RpcException e) - { - e.ShowMessageBox(); - } - - if (string.IsNullOrEmpty(this.nextPageToken)) - { - this.noMore = true; - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceControlViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceControlViewModel.cs deleted file mode 100644 index 90f376de..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceControlViewModel.cs +++ /dev/null @@ -1,220 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Threading.Tasks; -using System.Windows.Threading; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Options; -using Google.Protobuf.WellKnownTypes; -using Grpc.Core; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Prism.Commands; -using Prism.Mvvm; -using Prism.Regions; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - public class DeviceControlViewModel : BindableBase, IRegionMemberLifetime, INavigationAware - { - private readonly ILogger logger; - private readonly IOptions coreOptions; - private readonly DeviceService.DeviceServiceClient client; - private readonly DispatcherTimer timer; - private ViewModelContext viewModelContext; - private Switch deviceSwitch; - private Metric metric; - - public DeviceControlViewModel( - ILogger logger, - IOptions coreOptions, - DeviceService.DeviceServiceClient client) - { - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.coreOptions = coreOptions ?? throw new ArgumentNullException(nameof(coreOptions)); - this.client = client ?? throw new ArgumentNullException(nameof(client)); - - this.timer = new DispatcherTimer( - TimeSpan.FromMilliseconds(this.coreOptions.Value.DefaultRefreshIntervalMillis), - DispatcherPriority.DataBind, - this.Timer_Tick, - Dispatcher.CurrentDispatcher); - - this.SwitchOnClickCommand = new DelegateCommand(this.ExecuteSwitchOnClickCommand); - this.SwitchOffClickCommand = new DelegateCommand(this.ExecuteSwitchOffClickCommand); - } - - public DelegateCommand SwitchOnClickCommand { get; } - - public DelegateCommand SwitchOffClickCommand { get; } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set => this.SetProperty(ref this.viewModelContext, value); - } - - public Switch Switch - { - get => this.deviceSwitch; - set => this.SetProperty(ref this.deviceSwitch, value); - } - - public Metric Metric - { - get => this.metric ?? new Metric(); - set - { - this.SetProperty(ref this.metric, value); - this.RaisePropertyChanged(nameof(this.WaterPump)); - this.RaisePropertyChanged(nameof(this.HeaterWaterTemperature)); - } - } - - public bool HeaterWaterTemperature - { - get => this.Metric.HeaterOutputWaterCelsiusDegree - this.Metric.InputWaterCelsiusDegree > 0; - } - - public bool WaterPump - { - get => this.Metric.WaterPumpFlowRateCubicMeterPerHour > 0; - } - - public bool KeepAlive => false; - - public bool IsNavigationTarget(NavigationContext navigationContext) => false; - - public void OnNavigatedFrom(NavigationContext navigationContext) - { - this.timer.Stop(); - } - - public void OnNavigatedTo(NavigationContext navigationContext) - { - this.timer.Start(); - } - - public async Task LoadMetricAsync() - { - try - { - this.Metric = await this.client.GetMetricAsync( - new GetMetricRequest() - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - }, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultReadTimeoutMillis)); - } - catch (RpcException e) - { - this.logger.LogError( - e, - "Failed to get switch for device {0}", - this.ViewModelContext.SelectedDevice.Id); - } - } - - public async Task LoadSwitchAsync() - { - try - { - Switch response = await this.client.GetSwitchAsync( - new GetSwitchRequest() - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - }, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultReadTimeoutMillis)); - this.Switch = response; - } - catch (RpcException e) - { - this.logger.LogError( - e, - "Failed to get switch for device {0}", - this.ViewModelContext.SelectedDevice.Id); - } - } - - private async void Timer_Tick(object sender, EventArgs e) - { - await this.LoadMetricAsync().ConfigureAwait(true); - } - - private async void ExecuteSwitchOnClickCommand(string fieldMask) - { - var updatingMask = FieldMask.FromString(fieldMask); - var updatingSwitch = new Switch(); - Switch.Descriptor.FindFieldByName(fieldMask).Accessor.SetValue(updatingSwitch, true); - DateTime now = DateTime.UtcNow; - DateTime deadline = now.AddMilliseconds(this.coreOptions.Value.DefaultWriteTimeoutMillis); - try - { - this.Switch = await this.client.UpdateSwitchAsync( - new UpdateSwitchRequest() - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - Switch = updatingSwitch, - UpdateMask = updatingMask, - }, - deadline: deadline); - } - catch (RpcException e) - { - if (e.StatusCode == StatusCode.DeadlineExceeded) - { - this.logger.LogDebug( - "Request deadline exceeded, send_time={0:u}, deadline={1:u}, now={2:u}", - now, - deadline, - DateTime.UtcNow); - e.ShowMessageBox(); - } - else - { - e.ShowMessageBox(); - } - } - } - - private async void ExecuteSwitchOffClickCommand(string fieldMask) - { - var updatingMask = FieldMask.FromString(fieldMask); - var updatingSwitch = new Switch(); - Switch.Descriptor.FindFieldByName(fieldMask).Accessor.SetValue(updatingSwitch, false); - DateTime now = DateTime.UtcNow; - DateTime deadline = now.AddMilliseconds(this.coreOptions.Value.DefaultWriteTimeoutMillis); - try - { - this.Switch = await this.client.UpdateSwitchAsync( - new UpdateSwitchRequest() - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - Switch = updatingSwitch, - UpdateMask = updatingMask, - }, - deadline: deadline); - } - catch (RpcException e) - { - if (e.StatusCode == StatusCode.DeadlineExceeded) - { - this.logger.LogDebug( - "Request deadline exceeded, send_time={0:u}, deadline={1:u}, now={2:u}", - now, - deadline, - DateTime.UtcNow); - e.ShowMessageBox(); - } - else - { - e.ShowMessageBox(); - } - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceListViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceListViewModel.cs deleted file mode 100644 index 8e0907d6..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceListViewModel.cs +++ /dev/null @@ -1,95 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.ObjectModel; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Options; -using GeothermalResearchInstitute.Wpf.Views; -using Grpc.Core; -using Microsoft.Extensions.Options; -using Prism.Commands; -using Prism.Mvvm; -using Prism.Regions; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - public class DeviceListViewModel : BindableBase - { - private readonly IOptions coreOptions; - private readonly IRegionManager regionManager; - private readonly DeviceService.DeviceServiceClient client; - private ViewModelContext viewModelContext; - - public DeviceListViewModel( - IOptions coreOptions, - IRegionManager regionManager, - DeviceService.DeviceServiceClient client) - { - this.coreOptions = coreOptions ?? throw new ArgumentNullException(nameof(coreOptions)); - this.regionManager = regionManager ?? throw new ArgumentNullException(nameof(regionManager)); - this.client = client ?? throw new ArgumentNullException(nameof(client)); - - this.ConfirmCommand = new DelegateCommand(this.ExecuteConfirmCommand); - } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set - { - this.SetProperty(ref this.viewModelContext, value); - this.viewModelContext.PropertyChanged += (s, e) => - { - this.RaisePropertyChanged(e.PropertyName); - }; - } - } - - public ObservableCollection Devices { get; } = new ObservableCollection(); - - public Device SelectedDevice - { - get => this.ViewModelContext?.SelectedDevice; - set => this.ViewModelContext.SelectedDevice = value; - } - - public DelegateCommand ConfirmCommand { get; } - - public async Task LoadDevicesAsync() - { - try - { - ListDevicesResponse response = await this.client.ListDevicesAsync( - new ListDevicesRequest(), - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultReadTimeoutMillis)); - this.Devices.Clear(); - this.Devices.AddRange(response.Devices); - this.SelectedDevice = this.Devices.FirstOrDefault(); - } - catch (RpcException e) - { - e.ShowMessageBox(); - } - } - - private void ExecuteConfirmCommand() - { - if (this.SelectedDevice == null) - { - MessageBox.Show("必须选择一个设备才能继续"); - } - else - { - this.regionManager.RequestNavigate(Constants.ContentRegion, nameof(NavigationView)); - this.ViewModelContext.NavigateBackTarget = nameof(WelcomeView); - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceMetricBoardViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceMetricBoardViewModel.cs deleted file mode 100644 index 2f3d1e03..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceMetricBoardViewModel.cs +++ /dev/null @@ -1,131 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Windows.Threading; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Options; -using Grpc.Core; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Prism.Mvvm; -using Prism.Regions; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Performance", "CA1822", Justification = "ViewModel.")] - public class DeviceMetricBoardViewModel : BindableBase, IRegionMemberLifetime, INavigationAware - { - private readonly ILogger logger; - private readonly IOptions coreOptions; - private readonly DeviceService.DeviceServiceClient client; - private readonly DispatcherTimer timer; - private ViewModelContext viewModelContext; - private Metric metric; - - public DeviceMetricBoardViewModel( - ILogger logger, - IOptions coreOptions, - DeviceService.DeviceServiceClient client) - { - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.coreOptions = coreOptions ?? throw new ArgumentNullException(nameof(coreOptions)); - this.client = client ?? throw new ArgumentNullException(nameof(client)); - - this.timer = new DispatcherTimer( - TimeSpan.FromMilliseconds(this.coreOptions.Value.DefaultRefreshIntervalMillis), - DispatcherPriority.DataBind, - this.Timer_Tick, - Dispatcher.CurrentDispatcher); - } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set => this.SetProperty(ref this.viewModelContext, value); - } - - public bool KeepAlive => false; - - public Metric Metric - { - get => this.metric; - set - { - this.SetProperty(ref this.metric, value); - this.RaisePropertyChanged(nameof(this.HeaterPowerKilowatt)); - this.RaisePropertyChanged(nameof(this.OutputWaterPressureMeter)); - this.RaisePropertyChanged(nameof(this.OutputWaterCelsiusDegree)); - this.RaisePropertyChanged(nameof(this.WaterPumpFlowRateCubicMeterPerHour)); - this.RaisePropertyChanged(nameof(this.GroundHeatExchangeKilowatt)); - this.RaisePropertyChanged(nameof(this.InputWaterPressureMeter)); - this.RaisePropertyChanged(nameof(this.InputWaterCelsiusDegree)); - this.RaisePropertyChanged(nameof(this.EnvironmentCelsiusDegree)); - this.RaisePropertyChanged(nameof(this.CompressorHeatExchangeKilowatt)); - this.RaisePropertyChanged(nameof(this.DeltaWaterPressureMeter)); - this.RaisePropertyChanged(nameof(this.HeaterOutputWaterCelsiusDegree)); - } - } - - public float HeaterPowerKilowatt => this.Metric?.HeaterPowerKilowatt ?? 0; - - public float OutputWaterPressureMeter => this.Metric?.OutputWaterPressureMeter ?? 0; - - public float OutputWaterCelsiusDegree => this.Metric?.OutputWaterCelsiusDegree ?? 0; - - public float WaterPumpFlowRateCubicMeterPerHour => this.Metric?.WaterPumpFlowRateCubicMeterPerHour ?? 0; - - public float GroundHeatExchangeKilowatt => - 1.167F * this.WaterPumpFlowRateCubicMeterPerHour * Math.Abs( - this.InputWaterCelsiusDegree - this.OutputWaterCelsiusDegree); - - public float InputWaterPressureMeter => this.Metric?.InputWaterPressureMeter ?? 0; - - public float InputWaterCelsiusDegree => this.Metric?.InputWaterCelsiusDegree ?? 0; - - public float EnvironmentCelsiusDegree => this.Metric?.EnvironmentCelsiusDegree ?? 0; - - public float CompressorHeatExchangeKilowatt => - 1.167F * this.WaterPumpFlowRateCubicMeterPerHour * Math.Abs( - this.OutputWaterCelsiusDegree - this.HeaterOutputWaterCelsiusDegree); - - public float DeltaWaterPressureMeter => Math.Abs(this.InputWaterPressureMeter - this.OutputWaterPressureMeter); - - public float HeaterOutputWaterCelsiusDegree => this.Metric?.HeaterOutputWaterCelsiusDegree ?? 0; - - public bool IsNavigationTarget(NavigationContext navigationContext) => false; - - public void OnNavigatedFrom(NavigationContext navigationContext) - { - this.timer.Stop(); - } - - public void OnNavigatedTo(NavigationContext navigationContext) - { - this.timer.Start(); - } - - private async void Timer_Tick(object sender, EventArgs e) - { - try - { - this.Metric = await this.client.GetMetricAsync( - new GetMetricRequest - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - }, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultReadTimeoutMillis)); - } - catch (RpcException ex) - { - this.logger.LogError( - ex, - "Failed to get metrics for device {0}", - this.ViewModelContext.SelectedDevice.Id); - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceMetricHistoryExportViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceMetricHistoryExportViewModel.cs deleted file mode 100644 index d190a244..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceMetricHistoryExportViewModel.cs +++ /dev/null @@ -1,204 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Options; -using Google.Protobuf.WellKnownTypes; -using Grpc.Core; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.Win32; -using Prism.Commands; -using Prism.Mvvm; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Performance", "CA1822", Justification = "ViewModel.")] - public class DeviceMetricHistoryExportViewModel : BindableBase - { - private readonly ILogger logger; - private readonly IOptions coreOptions; - private readonly DeviceService.DeviceServiceClient client; - private ViewModelContext viewModelContext; - private DateTime startDateTime = DateTime.Now.Subtract(TimeSpan.FromDays(1)); - private DateTime endDateTime = DateTime.Now; - private int intervalMinutes = 10; - - public DeviceMetricHistoryExportViewModel( - ILogger logger, - IOptions coreOptions, - DeviceService.DeviceServiceClient client) - { - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.coreOptions = coreOptions ?? throw new ArgumentNullException(nameof(coreOptions)); - this.client = client ?? throw new ArgumentNullException(nameof(client)); - - this.ExportCommand = new DelegateCommand(this.ExecuteExport, this.CanExport); - } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set => this.SetProperty(ref this.viewModelContext, value); - } - - public DateTime StartDateTime - { - get => this.startDateTime; - set - { - this.SetProperty(ref this.startDateTime, value); - this.ExportCommand.RaiseCanExecuteChanged(); - } - } - - public DateTime EndDateTime - { - get => this.endDateTime; - set - { - this.SetProperty(ref this.endDateTime, value); - this.ExportCommand.RaiseCanExecuteChanged(); - } - } - - public int IntervalMinutes - { - get => this.intervalMinutes; - set => this.SetProperty(ref this.intervalMinutes, value); - } - - public DelegateCommand ExportCommand { get; } - - private bool CanExport() => this.StartDateTime < this.EndDateTime; - - private async void ExecuteExport() - { - int errorCounter = 0; - var metrics = new List(); - string nextPageToken = null; - while (true) - { - var request = new ListMetricsRequest - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - StartTime = Timestamp.FromDateTime(this.StartDateTime.ToUniversalTime()), - EndTime = Timestamp.FromDateTime(this.EndDateTime.ToUniversalTime()), - PageSize = this.coreOptions.Value.DefaultPageSize, - }; - - if (nextPageToken != null) - { - request.PageToken = nextPageToken; - } - - ListMetricsResponse response; - try - { - response = await this.client.ListMetricsAsync( - request, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultReadTimeoutMillis)); - } - catch (RpcException e) - { - this.logger.LogError( - e, - "Failed to list metrics for device {0}", - this.ViewModelContext.SelectedDevice.Id); - errorCounter++; - if (errorCounter < this.coreOptions.Value.MaxErrorToleranceNum) - { - continue; - } - else - { - e.ShowMessageBox(); - return; - } - } - - nextPageToken = response.NextPageToken; - - if (response.Metrics.Count == 0) - { - break; - } - - if (response.Metrics.Any(m => m.CreateTime.ToDateTimeOffset() < this.StartDateTime)) - { - metrics.AddRange(response.Metrics.Where( - m => m.CreateTime.ToDateTimeOffset() >= this.StartDateTime)); - break; - } - else - { - metrics.AddRange(response.Metrics); - } - - if (string.IsNullOrEmpty(nextPageToken)) - { - break; - } - } - - var saveFileDialog = new SaveFileDialog - { - Filter = "逗号分隔文件(*.csv)|*.csv", - AddExtension = true, - }; - - if (saveFileDialog.ShowDialog() == true) - { - using var sw = new StreamWriter( - File.Open(saveFileDialog.FileName, FileMode.Create, FileAccess.Write, FileShare.Read), - Encoding.UTF8); - - await sw - .WriteLineAsync( - "采集时间," - + "出水温度(摄氏度),回水温度(摄氏度),加热器出水温度(摄氏度)," - + "环境温度(摄氏度),出水压力(米),回水压力(米)," - + "加热器功率(千瓦),水泵流量(立方米/小时)") - .ConfigureAwait(true); - - var metricInterval = TimeSpan.FromMinutes(this.IntervalMinutes); - - // Notice that the metrics is ordered by create_time descending. - DateTimeOffset lastKnownMetricCreateTime = DateTimeOffset.MaxValue; - - foreach (Metric m in metrics) - { - DateTimeOffset createTimeThreshold = lastKnownMetricCreateTime - .Subtract(TimeSpan.FromSeconds(metricInterval.TotalSeconds * 0.9)); - - var createTime = m.CreateTime.ToDateTimeOffset(); - if (createTimeThreshold < createTime) - { - continue; - } - - await sw - .WriteLineAsync( - $"{createTime.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)}," - + $"{m.OutputWaterCelsiusDegree:F2},{m.InputWaterCelsiusDegree:F2}," - + $"{m.HeaterOutputWaterCelsiusDegree:F2},{m.EnvironmentCelsiusDegree:F2}," - + $"{m.OutputWaterPressureMeter:F2},{m.InputWaterPressureMeter:F2}," - + $"{m.HeaterPowerKilowatt:F2},{m.WaterPumpFlowRateCubicMeterPerHour:F2}") - .ConfigureAwait(true); - - lastKnownMetricCreateTime = createTime; - } - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceMetricHistoryPlotViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceMetricHistoryPlotViewModel.cs deleted file mode 100644 index 22dcf168..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceMetricHistoryPlotViewModel.cs +++ /dev/null @@ -1,258 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Options; -using Google.Protobuf.WellKnownTypes; -using Grpc.Core; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.Win32; -using OxyPlot; -using OxyPlot.Axes; -using OxyPlot.Series; -using Prism.Commands; -using Prism.Mvvm; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Performance", "CA1822", Justification = "ViewModel.")] - public class DeviceMetricHistoryPlotViewModel : BindableBase - { - private static readonly List MetricFieldDescriptorViewModels = - new List - { - new MetricFieldDescriptorViewModel( - "出水温度", - 0, - 50, - Metric.Descriptor.FindFieldByNumber(Metric.OutputWaterCelsiusDegreeFieldNumber).Accessor), - new MetricFieldDescriptorViewModel( - "回水温度", - 0, - 50, - Metric.Descriptor.FindFieldByNumber(Metric.InputWaterCelsiusDegreeFieldNumber).Accessor), - new MetricFieldDescriptorViewModel( - "环境温度", - 0, - 50, - Metric.Descriptor.FindFieldByNumber(Metric.EnvironmentCelsiusDegreeFieldNumber).Accessor), - new MetricFieldDescriptorViewModel( - "加热器功率", - 0, - 15, - Metric.Descriptor.FindFieldByNumber(Metric.HeaterPowerKilowattFieldNumber).Accessor), - new MetricFieldDescriptorViewModel( - "流量", - 0, - 4, - Metric.Descriptor.FindFieldByNumber(Metric.WaterPumpFlowRateCubicMeterPerHourFieldNumber).Accessor), - }; - - private readonly ILogger logger; - private readonly IOptions coreOptions; - private readonly DeviceService.DeviceServiceClient client; - - private ViewModelContext viewModelContext; - - private DateTime startDateTime = DateTime.Now.Subtract(TimeSpan.FromDays(1)); - private DateTime endDateTime = DateTime.Now; - private int intervalMinutes = 10; - private MetricFieldDescriptorViewModel selectedMetricField; - - private PlotModel plotModel = new PlotModel - { - Title = "点击确定生成折线图", - }; - - public DeviceMetricHistoryPlotViewModel( - ILogger logger, - IOptions coreOptions, - DeviceService.DeviceServiceClient client) - { - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.coreOptions = coreOptions ?? throw new ArgumentNullException(nameof(coreOptions)); - this.client = client ?? throw new ArgumentNullException(nameof(client)); - - this.PlotCommand = new DelegateCommand(this.ExecutePlot, this.CanPlot); - } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set => this.SetProperty(ref this.viewModelContext, value); - } - - public DateTime StartDateTime - { - get => this.startDateTime; - set - { - this.SetProperty(ref this.startDateTime, value); - this.PlotCommand.RaiseCanExecuteChanged(); - } - } - - public DateTime EndDateTime - { - get => this.endDateTime; - set - { - this.SetProperty(ref this.endDateTime, value); - this.PlotCommand.RaiseCanExecuteChanged(); - } - } - - public int IntervalMinutes - { - get => this.intervalMinutes; - set => this.SetProperty(ref this.intervalMinutes, value); - } - - public ObservableCollection MetricFields { get; } = - new ObservableCollection(MetricFieldDescriptorViewModels); - - public MetricFieldDescriptorViewModel SelectedMetricField - { - get => this.selectedMetricField; - set => this.SetProperty(ref this.selectedMetricField, value); - } - - public PlotModel PlotModel - { - get => this.plotModel; - set => this.SetProperty(ref this.plotModel, value); - } - - public DelegateCommand PlotCommand { get; } - - private bool CanPlot() => this.StartDateTime < this.EndDateTime; - - private async void ExecutePlot() - { - int errorCounter = 0; - var metrics = new List(); - string nextPageToken = null; - while (true) - { - var request = new ListMetricsRequest - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - StartTime = Timestamp.FromDateTime(this.StartDateTime.ToUniversalTime()), - EndTime = Timestamp.FromDateTime(this.EndDateTime.ToUniversalTime()), - PageSize = this.coreOptions.Value.DefaultPageSize, - }; - - if (nextPageToken != null) - { - request.PageToken = nextPageToken; - } - - ListMetricsResponse response; - try - { - response = await this.client.ListMetricsAsync( - request, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultReadTimeoutMillis)); - } - catch (RpcException e) - { - this.logger.LogError( - e, - "Failed to list metrics for device {0}", - this.ViewModelContext.SelectedDevice.Id); - errorCounter++; - if (errorCounter < this.coreOptions.Value.MaxErrorToleranceNum) - { - continue; - } - else - { - e.ShowMessageBox(); - return; - } - } - - nextPageToken = response.NextPageToken; - - if (response.Metrics.Count == 0) - { - break; - } - - if (response.Metrics.Any(m => m.CreateTime.ToDateTimeOffset() < this.StartDateTime)) - { - metrics.AddRange(response.Metrics.Where( - m => m.CreateTime.ToDateTimeOffset() >= this.StartDateTime)); - break; - } - else - { - metrics.AddRange(response.Metrics); - } - - if (string.IsNullOrEmpty(nextPageToken)) - { - break; - } - } - - var tmp = new PlotModel { Title = this.SelectedMetricField.DisplayName + "历史数据折线图" }; - tmp.Axes.Add(new DateTimeAxis - { - Position = AxisPosition.Bottom, - Minimum = DateTimeAxis.ToDouble(this.StartDateTime.ToLocalTime()), - Maximum = DateTimeAxis.ToDouble(this.EndDateTime.ToLocalTime()), - StringFormat = "yyyy-MM-dd\nHH:mm:ss", - }); - tmp.Axes.Add(new LinearAxis - { - Position = AxisPosition.Left, - Minimum = this.SelectedMetricField.Minimum, - Maximum = this.SelectedMetricField.Maximum, - }); - - var series = new LineSeries(); - - DateTimeOffset startDateTime = metrics.LastOrDefault()?.CreateTime.ToDateTimeOffset() - ?? this.StartDateTime; - var metricInterval = TimeSpan.FromMinutes(this.IntervalMinutes); - - // Notice that the metrics is ordered by create_time descending. - DateTimeOffset lastKnownMetricCreateTime = DateTimeOffset.MaxValue; - - foreach (Metric m in metrics) - { - DateTimeOffset createTimeThreshold = lastKnownMetricCreateTime - .Subtract(TimeSpan.FromSeconds(metricInterval.TotalSeconds * 0.9)); - - var createTime = m.CreateTime.ToDateTimeOffset(); - if (createTimeThreshold < createTime) - { - continue; - } - - series.Points.Add(DateTimeAxis.CreateDataPoint( - m.CreateTime.ToDateTime().ToLocalTime(), - (float)this.SelectedMetricField.Accessor.GetValue(m))); - - lastKnownMetricCreateTime = createTime; - } - - tmp.Series.Add(series); - - this.PlotModel = tmp; - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceMetricHistoryViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceMetricHistoryViewModel.cs deleted file mode 100644 index 5ef173c3..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceMetricHistoryViewModel.cs +++ /dev/null @@ -1,79 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.ObjectModel; -using System.Threading.Tasks; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Options; -using Grpc.Core; -using Microsoft.Extensions.Options; -using Prism.Mvvm; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - public class DeviceMetricHistoryViewModel : BindableBase - { - private readonly IOptions coreOptions; - private readonly DeviceService.DeviceServiceClient client; - private ViewModelContext viewModelContext; - private string nextPageToken = null; - private bool noMore = false; - - public DeviceMetricHistoryViewModel( - IOptions coreOptions, - DeviceService.DeviceServiceClient client) - { - this.coreOptions = coreOptions ?? throw new ArgumentNullException(nameof(coreOptions)); - this.client = client ?? throw new ArgumentNullException(nameof(client)); - } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set => this.SetProperty(ref this.viewModelContext, value); - } - - public ObservableCollection Metrics { get; } = new ObservableCollection(); - - public async Task LoadAsync() - { - if (this.noMore) - { - return; - } - - var request = new ListMetricsRequest - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - PageSize = this.coreOptions.Value.DefaultPageSize, - }; - - if (!string.IsNullOrEmpty(this.nextPageToken)) - { - request.PageToken = this.nextPageToken; - } - - try - { - ListMetricsResponse response = await this.client.ListMetricsAsync( - request, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultReadTimeoutMillis)); - this.Metrics.AddRange(response.Metrics); - this.nextPageToken = response.NextPageToken; - } - catch (RpcException e) - { - e.ShowMessageBox(); - } - - if (string.IsNullOrEmpty(this.nextPageToken)) - { - this.noMore = true; - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceRunningParameterViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceRunningParameterViewModel.cs deleted file mode 100644 index effe2f9e..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceRunningParameterViewModel.cs +++ /dev/null @@ -1,302 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using System.Windows; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Options; -using Google.Protobuf.WellKnownTypes; -using Grpc.Core; -using Microsoft.Extensions.Options; -using Prism.Commands; -using Prism.Mvvm; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Performance", "CA1822", Justification = "ViewModel.")] - public class DeviceRunningParameterViewModel : BindableBase - { - private static readonly DeviceFlowRateControlMode[] CandidateDeviceFlowRateControlModes = new[] - { - DeviceFlowRateControlMode.VariableFrequency, - DeviceFlowRateControlMode.WorkFrequency, - }; - - private static readonly WaterPumpWorkingMode[] CandidateWaterPumpWorkingModes = new[] - { - WaterPumpWorkingMode.FixedFlowRate, - WaterPumpWorkingMode.FixedFrequency, - }; - - private readonly IOptions coreOptions; - private readonly DeviceService.DeviceServiceClient client; - private ViewModelContext viewModelContext; - private WorkingMode currentWorkingMode; - private WorkingMode updatingWorkingMode; - private RunningParameter currentRunningParameter; - private RunningParameter updatingRunningParameter; - - public DeviceRunningParameterViewModel( - IOptions coreOptions, - DeviceService.DeviceServiceClient client) - { - this.coreOptions = coreOptions ?? throw new ArgumentNullException(nameof(coreOptions)); - this.client = client ?? throw new ArgumentNullException(nameof(client)); - - this.UpdateCommand = new DelegateCommand(this.ExecuteUpdateCommand); - } - - public ICollection DeviceFlowRateControlModes => - CandidateDeviceFlowRateControlModes; - - public ICollection WaterPumpWorkingModes => - CandidateWaterPumpWorkingModes; - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set => this.SetProperty(ref this.viewModelContext, value); - } - - public RunningParameter CurrentRunningParameter - { - get => this.currentRunningParameter; - set - { - this.SetProperty(ref this.currentRunningParameter, value); - this.UpdatingRunningParameter = value?.Clone(); - - this.RaisePropertyChanged(nameof(this.CurrentSummerHeaterCelsiusDegree)); - this.RaisePropertyChanged(nameof(this.CurrentWinterHeaterCelsiusDegree)); - this.RaisePropertyChanged(nameof(this.CurrentColdPowerKilowatt)); - this.RaisePropertyChanged(nameof(this.CurrentWarmPowerKilowatt)); - this.RaisePropertyChanged(nameof(this.CurrentWaterPumpFlowRateCubicMeterPerHour)); - this.RaisePropertyChanged(nameof(this.CurrentWaterPumpFrequencyHertz)); - } - } - - public RunningParameter UpdatingRunningParameter - { - get => this.updatingRunningParameter ?? this.CurrentRunningParameter; - set - { - this.SetProperty(ref this.updatingRunningParameter, value); - - this.RaisePropertyChanged(nameof(this.UpdatingSummerHeaterCelsiusDegree)); - this.RaisePropertyChanged(nameof(this.UpdatingWinterHeaterCelsiusDegree)); - this.RaisePropertyChanged(nameof(this.UpdatingColdPowerKilowatt)); - this.RaisePropertyChanged(nameof(this.UpdatingWarmPowerKilowatt)); - this.RaisePropertyChanged(nameof(this.UpdatingWaterPumpFlowRateCubicMeterPerHour)); - this.RaisePropertyChanged(nameof(this.UpdatingWaterPumpFrequencyHertz)); - } - } - - public WorkingMode CurrentWorkingMode - { - get => this.currentWorkingMode; - set - { - this.SetProperty(ref this.currentWorkingMode, value); - this.UpdatingWorkingMode = value?.Clone(); - - this.RaisePropertyChanged(nameof(this.CurrentFlowRateControlMode)); - this.RaisePropertyChanged(nameof(this.CurrentWaterPumpWorkingMode)); - this.RaisePropertyChanged(nameof(this.CurrentWaterPumpFlowRateCubicMeterPerHourVisibility)); - this.RaisePropertyChanged(nameof(this.CurrentWaterPumpFrequencyHertzVisibility)); - } - } - - public WorkingMode UpdatingWorkingMode - { - get => this.updatingWorkingMode ?? this.CurrentWorkingMode; - set - { - this.SetProperty(ref this.updatingWorkingMode, value); - - this.RaisePropertyChanged(nameof(this.UpdatingFlowRateControlMode)); - this.RaisePropertyChanged(nameof(this.UpdatingWaterPumpWorkingMode)); - } - } - - public float CurrentSummerHeaterCelsiusDegree => - this.CurrentRunningParameter?.SummerHeaterCelsiusDegree ?? 0; - - public float UpdatingSummerHeaterCelsiusDegree - { - get => this.UpdatingRunningParameter?.SummerHeaterCelsiusDegree ?? 0; - set - { - this.UpdatingRunningParameter.SummerHeaterCelsiusDegree = value; - this.RaisePropertyChanged(); - } - } - - public float CurrentWinterHeaterCelsiusDegree => - this.CurrentRunningParameter?.WinterHeaterCelsiusDegree ?? 0; - - public float UpdatingWinterHeaterCelsiusDegree - { - get => this.UpdatingRunningParameter?.WinterHeaterCelsiusDegree ?? 0; - set - { - this.UpdatingRunningParameter.WinterHeaterCelsiusDegree = value; - this.RaisePropertyChanged(); - } - } - - public float CurrentColdPowerKilowatt => - this.CurrentRunningParameter?.ColdPowerKilowatt ?? 0; - - public float UpdatingColdPowerKilowatt - { - get => this.UpdatingRunningParameter?.ColdPowerKilowatt ?? 0; - set - { - this.UpdatingRunningParameter.ColdPowerKilowatt = value; - this.RaisePropertyChanged(); - } - } - - public float CurrentWarmPowerKilowatt => - this.CurrentRunningParameter?.WarmPowerKilowatt ?? 0; - - public float UpdatingWarmPowerKilowatt - { - get => this.UpdatingRunningParameter?.WarmPowerKilowatt ?? 0; - set - { - this.UpdatingRunningParameter.WarmPowerKilowatt = value; - this.RaisePropertyChanged(); - } - } - - public float CurrentWaterPumpFlowRateCubicMeterPerHour => - this.CurrentRunningParameter?.WaterPumpFlowRateCubicMeterPerHour ?? 0; - - public float UpdatingWaterPumpFlowRateCubicMeterPerHour - { - get => this.UpdatingRunningParameter?.WaterPumpFlowRateCubicMeterPerHour ?? 0; - set - { - this.UpdatingRunningParameter.WaterPumpFlowRateCubicMeterPerHour = value; - this.RaisePropertyChanged(); - } - } - - public float CurrentWaterPumpFrequencyHertz => - this.CurrentRunningParameter?.WaterPumpFrequencyHertz ?? 0; - - public float UpdatingWaterPumpFrequencyHertz - { - get => this.UpdatingRunningParameter?.WaterPumpFrequencyHertz ?? 0; - set - { - this.UpdatingRunningParameter.WaterPumpFrequencyHertz = value; - this.RaisePropertyChanged(); - } - } - - public DeviceFlowRateControlMode CurrentFlowRateControlMode => - this.CurrentWorkingMode?.DeviceFlowRateControlMode ?? DeviceFlowRateControlMode.VariableFrequency; - - public DeviceFlowRateControlMode UpdatingFlowRateControlMode - { - get => this.UpdatingWorkingMode?.DeviceFlowRateControlMode ?? DeviceFlowRateControlMode.VariableFrequency; - set - { - this.UpdatingWorkingMode.DeviceFlowRateControlMode = value; - this.RaisePropertyChanged(); - } - } - - public WaterPumpWorkingMode CurrentWaterPumpWorkingMode => - this.CurrentWorkingMode?.WaterPumpWorkingMode ?? WaterPumpWorkingMode.FixedFlowRate; - - public WaterPumpWorkingMode UpdatingWaterPumpWorkingMode - { - get => this.UpdatingWorkingMode?.WaterPumpWorkingMode ?? WaterPumpWorkingMode.FixedFlowRate; - set - { - this.UpdatingWorkingMode.WaterPumpWorkingMode = value; - this.RaisePropertyChanged(); - } - } - - public Visibility CurrentWaterPumpFlowRateCubicMeterPerHourVisibility => - this.CurrentWaterPumpWorkingMode == WaterPumpWorkingMode.FixedFlowRate - ? Visibility.Visible - : Visibility.Collapsed; - - public Visibility CurrentWaterPumpFrequencyHertzVisibility => - this.CurrentWaterPumpWorkingMode == WaterPumpWorkingMode.FixedFrequency - ? Visibility.Visible - : Visibility.Collapsed; - - public DelegateCommand UpdateCommand { get; } - - public async Task LoadAsync() - { - try - { - this.CurrentRunningParameter = await this.client.GetRunningParameterAsync( - new GetRunningParameterRequest - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - }, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultReadTimeoutMillis)); - this.UpdatingRunningParameter = this.CurrentRunningParameter.Clone(); - - this.CurrentWorkingMode = await this.client.GetWorkingModeAsync( - new GetWorkingModeRequest - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - }, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultReadTimeoutMillis)); - this.UpdatingWorkingMode = this.CurrentWorkingMode.Clone(); - } - catch (RpcException e) - { - e.ShowMessageBox(); - } - } - - private async void ExecuteUpdateCommand() - { - try - { - this.CurrentRunningParameter = await this.client.UpdateRunningParameterAsync( - new UpdateRunningParameterRequest - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - RunningParameter = this.UpdatingRunningParameter, - }, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultWriteTimeoutMillis)); - this.UpdatingRunningParameter = this.CurrentRunningParameter.Clone(); - - this.CurrentWorkingMode = await this.client.UpdateWorkingModeAsync( - new UpdateWorkingModeRequest - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - WorkingMode = this.UpdatingWorkingMode, - UpdateMask = FieldMask.FromStringEnumerable(new[] - { - "device_flow_rate_control_mode", - "water_pump_working_mode", - }), - }, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultWriteTimeoutMillis)); - this.UpdatingWorkingMode = this.CurrentWorkingMode.Clone(); - } - catch (RpcException e) - { - e.ShowMessageBox(); - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceWorkingModeViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceWorkingModeViewModel.cs deleted file mode 100644 index 9958cb37..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/DeviceWorkingModeViewModel.cs +++ /dev/null @@ -1,130 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Options; -using Google.Protobuf.WellKnownTypes; -using Grpc.Core; -using Microsoft.Extensions.Options; -using Prism.Commands; -using Prism.Mvvm; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Performance", "CA1822", Justification = "ViewModel.")] - public class DeviceWorkingModeViewModel : BindableBase - { - private static readonly DeviceWorkingMode[] CandidateDeviceWorkingModes = new[] - { - DeviceWorkingMode.TemperatureDetermination, - DeviceWorkingMode.FixedWarmPower, - DeviceWorkingMode.FixedColdPower, - DeviceWorkingMode.SummerSituation, - DeviceWorkingMode.WinterSituation, - }; - - private readonly IOptions coreOptions; - private readonly DeviceService.DeviceServiceClient client; - private ViewModelContext viewModelContext; - private WorkingMode currentWorkingMode; - private DeviceWorkingMode selectedWorkingMode; - - public DeviceWorkingModeViewModel( - IOptions coreOptions, - DeviceService.DeviceServiceClient client) - { - this.coreOptions = coreOptions ?? throw new ArgumentNullException(nameof(coreOptions)); - this.client = client ?? throw new ArgumentNullException(nameof(client)); - this.UpdateDeviceWorkingModeCommand = new DelegateCommand( - this.ExecuteUpdateDeviceWorkingModeCommand, this.CanUpdateDeviceWorkingModeCommand); - } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set => this.SetProperty(ref this.viewModelContext, value); - } - - public ICollection DeviceWorkingModes => CandidateDeviceWorkingModes; - - public WorkingMode CurrentWorkingMode - { - get => this.currentWorkingMode; - set - { - this.SetProperty(ref this.currentWorkingMode, value); - this.RaisePropertyChanged(nameof(this.CurrentDeviceWorkingMode)); - this.RaisePropertyChanged(nameof(this.SelectedDeviceWorkingMode)); - this.UpdateDeviceWorkingModeCommand.RaiseCanExecuteChanged(); - } - } - - public DeviceWorkingMode CurrentDeviceWorkingMode - { - get => this.CurrentWorkingMode?.DeviceWorkingMode ?? DeviceWorkingMode.TemperatureDetermination; - } - - public DeviceWorkingMode SelectedDeviceWorkingMode - { - get => this.selectedWorkingMode == DeviceWorkingMode.Unspecified - ? this.CurrentDeviceWorkingMode - : this.selectedWorkingMode; - set - { - this.SetProperty(ref this.selectedWorkingMode, value); - this.UpdateDeviceWorkingModeCommand.RaiseCanExecuteChanged(); - } - } - - public DelegateCommand UpdateDeviceWorkingModeCommand { get; } - - public async Task LoadWorkingMode() - { - try - { - this.CurrentWorkingMode = await this.client.GetWorkingModeAsync( - new GetWorkingModeRequest - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - }, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultReadTimeoutMillis)); - } - catch (RpcException e) - { - e.ShowMessageBox(); - } - } - - private bool CanUpdateDeviceWorkingModeCommand() => this.selectedWorkingMode != DeviceWorkingMode.Unspecified; - - private async void ExecuteUpdateDeviceWorkingModeCommand() - { - try - { - this.CurrentWorkingMode = await this.client.UpdateWorkingModeAsync( - new UpdateWorkingModeRequest - { - DeviceId = this.ViewModelContext.SelectedDevice.Id, - WorkingMode = new WorkingMode - { - DeviceWorkingMode = this.SelectedDeviceWorkingMode, - }, - UpdateMask = FieldMask.FromString("device_working_mode"), - }, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultWriteTimeoutMillis)); - this.SelectedDeviceWorkingMode = DeviceWorkingMode.Unspecified; - } - catch (RpcException e) - { - e.ShowMessageBox(); - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/LoginViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/LoginViewModel.cs deleted file mode 100644 index bafaf6cf..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/LoginViewModel.cs +++ /dev/null @@ -1,100 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.ComponentModel.DataAnnotations; -using System.Security.Principal; -using System.Windows.Controls; -using GeothermalResearchInstitute.v2; -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Options; -using Grpc.Core; -using Microsoft.Extensions.Options; -using Prism.Commands; -using Prism.Regions; -using Prism.Validation; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - public class LoginViewModel : ValidatableBindableBase, IRegionMemberLifetime - { - private readonly IOptions coreOptions; - private readonly IRegionManager regionManager; - private readonly DeviceService.DeviceServiceClient client; - private ViewModelContext viewModelContext; - private string username = string.Empty; - private string password = string.Empty; - - public LoginViewModel( - IOptions coreOptions, - IRegionManager regionManager, - DeviceService.DeviceServiceClient client) - { - this.coreOptions = coreOptions ?? throw new ArgumentNullException(nameof(coreOptions)); - this.regionManager = regionManager ?? throw new ArgumentNullException(nameof(regionManager)); - this.client = client ?? throw new ArgumentNullException(nameof(client)); - - this.LoginCommand = new DelegateCommand(this.ExecuteLoginCommand); - this.NavigateBackCommand = new DelegateCommand(this.ExecuteNavigateBackCommand); - } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set => this.SetProperty(ref this.viewModelContext, value); - } - - [Required] - [StringLength(48, MinimumLength = 3)] - public string Username - { - get => this.username; - set => this.SetProperty(ref this.username, value); - } - - [Required] - [StringLength(48, MinimumLength = 3)] - public string Password - { - get => this.password; - set => this.SetProperty(ref this.password, value); - } - - public DelegateCommand LoginCommand { get; } - - public DelegateCommand NavigateBackCommand { get; } - - public bool KeepAlive => false; - - private async void ExecuteLoginCommand(PasswordBox passwordBox) - { - this.Password = passwordBox.Password; // Use SecuredPassword in the future. - - try - { - AuthenticateResponse response = await this.client.AuthenticateAsync( - new AuthenticateRequest - { - Username = this.Username, - Password = this.Password, - }, - deadline: DateTime.UtcNow.AddMilliseconds(this.coreOptions.Value.DefaultReadTimeoutMillis)); - this.ViewModelContext.Principal = new GenericPrincipal( - new GenericIdentity(response.Nickname, "Remote"), - new[] { ProtoUtils.ConvertToString(response.Role) }); - this.ExecuteNavigateBackCommand(); - } - catch (RpcException e) - { - e.ShowMessageBox(); - } - } - - private void ExecuteNavigateBackCommand() - { - this.regionManager.RequestNavigate(Constants.ContentRegion, this.ViewModelContext.NavigateBackTarget); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/MainWindowViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/MainWindowViewModel.cs deleted file mode 100644 index b30a0743..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/MainWindowViewModel.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System.ComponentModel; -using System.Windows; -using Prism.Mvvm; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - public class MainWindowViewModel : BindableBase - { - private ViewModelContext viewModelContext; - - public MainWindowViewModel(ViewModelContext viewModelContext) - { - this.ViewModelContext = viewModelContext ?? throw new System.ArgumentNullException(nameof(viewModelContext)); - this.ViewModelContext.PropertyChanged += this.ViewModelContext_PropertyChanged; - } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set => this.SetProperty(ref this.viewModelContext, value); - } - - public Visibility UserBarVisibility - { - get => this.ViewModelContext.UserBarVisibility; - set => this.ViewModelContext.UserBarVisibility = value; - } - - public Visibility BannerVisibility - { - get => this.ViewModelContext.BannerVisibility; - set => this.ViewModelContext.BannerVisibility = value; - } - - private void ViewModelContext_PropertyChanged(object sender, PropertyChangedEventArgs e) - { - this.RaisePropertyChanged(e.PropertyName); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/MetricFieldDescriptorViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/MetricFieldDescriptorViewModel.cs deleted file mode 100644 index d86e8dec..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/MetricFieldDescriptorViewModel.cs +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using Google.Protobuf.Reflection; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - public class MetricFieldDescriptorViewModel - { - public MetricFieldDescriptorViewModel( - string displayName, - double minimum, - double maximum, - IFieldAccessor accessor) - { - this.DisplayName = displayName; - this.Minimum = minimum; - this.Maximum = maximum; - this.Accessor = accessor; - } - - public string DisplayName { get; } - - public double Minimum { get; } - - public double Maximum { get; } - - public IFieldAccessor Accessor { get; } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/NavigationViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/NavigationViewModel.cs deleted file mode 100644 index cf482928..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/NavigationViewModel.cs +++ /dev/null @@ -1,164 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.IO; -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Views; -using Microsoft.Extensions.Logging; -using Prism.Commands; -using Prism.Mvvm; -using Prism.Regions; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - public class NavigationViewModel : BindableBase - { - private readonly ILogger logger; - private readonly IRegionManager regionManager; - private ViewModelContext viewModelContext; - - public NavigationViewModel(ILogger logger, IRegionManager regionManager) - { - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.regionManager = regionManager ?? throw new ArgumentNullException(nameof(regionManager)); - - this.NavigateToDeviceControlView = - new DelegateCommand(this.ExecuteNavigateToDeviceControlView, this.CanNavigateToDeviceControlView); - this.NavigateToDeviceWorkingModeView = - new DelegateCommand(this.ExecuteNavigateToDeviceWorkingModeView, this.CanNavigateToDeviceWorkingModeView); - this.NavigateToDeviceRunningParameterView = - new DelegateCommand(this.ExecuteNavigateToDeviceRunningParameterView, this.CanNavigateToDeviceRunningParameterView); - this.NavigateToDeviceMetricHistoryView = - new DelegateCommand(this.ExecuteNavigateToDeviceMetricHistoryView); - this.NavigateToDeviceMetricBoardView = - new DelegateCommand(this.ExecuteNavigateToDeviceMetricBoardView, this.CanNavigateToDeviceMetricBoardView); - this.NavigateToDeviceMetricHistoryExportView = - new DelegateCommand(this.ExecuteNavigateToDeviceMetricHistoryExportView); - this.NavigateToDeviceMetricHistoryPlotView = - new DelegateCommand(this.ExecuteNavigateToDeviceMetricHistoryPlotView); - this.NavigateToDeviceAlarmHistoryView = this.NavigateToDeviceAlarmHistoryView = - new DelegateCommand(this.ExecuteNavigateToDeviceAlarmHistoryView); - } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set - { - this.SetProperty(ref this.viewModelContext, value); - this.RaiseCommandsCanExecuteChanged(); - this.viewModelContext.PropertyChanged += (s, e) => - { - if (e.PropertyName == nameof(this.ViewModelContext.SelectedDevice)) - { - this.RaiseCommandsCanExecuteChanged(); - } - }; - } - } - - public DelegateCommand NavigateToDeviceControlView { get; } - - public DelegateCommand NavigateToDeviceWorkingModeView { get; } - - public DelegateCommand NavigateToDeviceRunningParameterView { get; } - - public DelegateCommand NavigateToDeviceMetricHistoryView { get; } - - public DelegateCommand NavigateToDeviceMetricBoardView { get; } - - public DelegateCommand NavigateToDeviceMetricHistoryExportView { get; } - - public DelegateCommand NavigateToDeviceMetricHistoryPlotView { get; } - - public DelegateCommand NavigateToDeviceAlarmHistoryView { get; } - - private bool IsDeviceConnected => - this.ViewModelContext?.SelectedDevice?.Status == v2.DeviceStatus.Healthy - || this.ViewModelContext?.SelectedDevice?.Status == v2.DeviceStatus.Unhealthy; - - private void RaiseCommandsCanExecuteChanged() - { - this.NavigateToDeviceControlView.RaiseCanExecuteChanged(); - this.NavigateToDeviceWorkingModeView.RaiseCanExecuteChanged(); - this.NavigateToDeviceRunningParameterView.RaiseCanExecuteChanged(); - this.NavigateToDeviceMetricBoardView.RaiseCanExecuteChanged(); - this.NavigateToDeviceAlarmHistoryView.RaiseCanExecuteChanged(); - } - - private bool CanNavigateToDeviceControlView() => this.IsDeviceConnected; - - private void ExecuteNavigateToDeviceControlView() - { - this.regionManager.RequestNavigate(Constants.ContentRegion, nameof(DeviceControlView)); - this.ViewModelContext.NavigateBackTarget = nameof(NavigationView); - } - - private bool CanNavigateToDeviceWorkingModeView() => this.IsDeviceConnected; - - private void ExecuteNavigateToDeviceWorkingModeView() - { - this.regionManager.RequestNavigate(Constants.ContentRegion, nameof(DeviceWorkingModeView)); - this.ViewModelContext.NavigateBackTarget = nameof(NavigationView); - } - - private bool CanNavigateToDeviceRunningParameterView() => this.IsDeviceConnected; - - private void ExecuteNavigateToDeviceRunningParameterView() - { - this.regionManager.RequestNavigate(Constants.ContentRegion, nameof(DeviceRunningParameterView)); - this.ViewModelContext.NavigateBackTarget = nameof(NavigationView); - } - - private void ExecuteNavigateToDeviceMetricHistoryView() - { - this.regionManager.RequestNavigate(Constants.ContentRegion, nameof(DeviceMetricHistoryView)); - this.ViewModelContext.NavigateBackTarget = nameof(NavigationView); - } - - private bool CanNavigateToDeviceMetricBoardView() => this.IsDeviceConnected; - - private void ExecuteNavigateToDeviceMetricBoardView() - { - this.regionManager.RequestNavigate(Constants.ContentRegion, nameof(DeviceMetricBoardView)); - this.ViewModelContext.NavigateBackTarget = nameof(NavigationView); - } - - private void ExecuteNavigateToDeviceMetricHistoryExportView() - { - try - { - this.regionManager.RequestNavigate(Constants.ContentRegion, nameof(DeviceMetricHistoryExportView)); - this.ViewModelContext.NavigateBackTarget = nameof(NavigationView); - } - catch (IOException e) - { - this.logger.LogError(e, "Failed to navigate to device metric history export view."); - } - } - - private void ExecuteNavigateToDeviceMetricHistoryPlotView() - { - try - { - this.regionManager.RequestNavigate(Constants.ContentRegion, nameof(DeviceMetricHistoryPlotView)); - this.ViewModelContext.NavigateBackTarget = nameof(NavigationView); - } - catch (IOException e) - { - this.logger.LogError(e, "Failed to navigate to device metric history plot view."); - } - } - - private bool CanNavigateToDeviceAlarmHistoryView() => this.IsDeviceConnected; - - private void ExecuteNavigateToDeviceAlarmHistoryView() - { - this.regionManager.RequestNavigate(Constants.ContentRegion, nameof(DeviceAlarmHistoryView)); - this.ViewModelContext.NavigateBackTarget = nameof(NavigationView); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/UserBarViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/UserBarViewModel.cs deleted file mode 100644 index f37eb407..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/UserBarViewModel.cs +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System.Windows; -using GeothermalResearchInstitute.Wpf.Common; -using Prism.Mvvm; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Microsoft.Performance", "CA1822", Justification = "ViewModel")] - public class UserBarViewModel : BindableBase - { - private ViewModelContext viewModelContext; - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set - { - this.SetProperty(ref this.viewModelContext, value); - this.viewModelContext.PropertyChanged += this.ViewModelContext_PropertyChanged; - } - } - - public string DisplayName - { - get - { - string name = this.ViewModelContext?.Principal?.Identity.Name; - if (string.IsNullOrEmpty(name)) - { - return (string)Application.Current.FindResource("AnonymousUserName"); - } - else - { - return name; - } - } - } - - public string Role - { - get - { - if (this.ViewModelContext?.Principal?.IsInRole(Constants.UserRoleOperator) == true) - { - return (string)Application.Current.FindResource("OperatorUserRole"); - } - else if (this.ViewModelContext?.Principal?.IsInRole(Constants.UserRoleAdministrator) == true) - { - return (string)Application.Current.FindResource("AdministratorUserRole"); - } - else - { - return (string)Application.Current.FindResource("AnonymousUserRole"); - } - } - } - - public string DeviceName => this.ViewModelContext?.SelectedDevice?.Name ?? "无"; - - private void ViewModelContext_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(this.ViewModelContext.Principal)) - { - this.RaisePropertyChanged(nameof(this.DisplayName)); - this.RaisePropertyChanged(nameof(this.Role)); - } - else if (e.PropertyName == nameof(this.ViewModelContext.SelectedDevice)) - { - this.RaisePropertyChanged(nameof(this.DeviceName)); - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/ViewModelContext.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/ViewModelContext.cs deleted file mode 100644 index a5b97970..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/ViewModelContext.cs +++ /dev/null @@ -1,58 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System.Security.Principal; -using System.Windows; -using GeothermalResearchInstitute.v2; -using Prism.Mvvm; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - public class ViewModelContext : BindableBase - { - private IPrincipal principal; - private Visibility userBarVisibility; - private Visibility bannerVisibility; - private string title; - private string navigateBackTarget; - private Device selectedDevice; - - public IPrincipal Principal - { - get => this.principal; - set => this.SetProperty(ref this.principal, value); - } - - public Visibility UserBarVisibility - { - get => this.userBarVisibility; - set => this.SetProperty(ref this.userBarVisibility, value); - } - - public Visibility BannerVisibility - { - get => this.bannerVisibility; - set => this.SetProperty(ref this.bannerVisibility, value); - } - - public string Title - { - get => this.title; - set => this.SetProperty(ref this.title, value); - } - - public string NavigateBackTarget - { - get => this.navigateBackTarget; - set => this.SetProperty(ref this.navigateBackTarget, value); - } - - public Device SelectedDevice - { - get => this.selectedDevice; - set => this.SetProperty(ref this.selectedDevice, value); - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/WelcomeViewModel.cs b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/WelcomeViewModel.cs deleted file mode 100644 index c32363ff..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/ViewModels/WelcomeViewModel.cs +++ /dev/null @@ -1,105 +0,0 @@ -// -// Copyright Shuai Zhang. All rights reserved. -// Licensed under the GPLv3 license. See LICENSE file in the project root for full license information. -// - -using System; -using System.ComponentModel; -using System.Linq; -using GeothermalResearchInstitute.Wpf.Common; -using GeothermalResearchInstitute.Wpf.Options; -using GeothermalResearchInstitute.Wpf.Views; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Prism.Commands; -using Prism.Mvvm; -using Prism.Regions; - -namespace GeothermalResearchInstitute.Wpf.ViewModels -{ - public class WelcomeViewModel : BindableBase - { - private readonly ILogger logger; - private readonly IOptions coreOptions; - private readonly IRegionManager regionManager; - private ViewModelContext viewModelContext; - - public WelcomeViewModel( - ILogger logger, - IOptions coreOptions, - IRegionManager regionManager) - { - this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.coreOptions = coreOptions ?? throw new ArgumentNullException(nameof(coreOptions)); - this.regionManager = regionManager ?? throw new ArgumentNullException(nameof(regionManager)); - - this.NavigateToLoginViewCommand = new DelegateCommand(this.ExecuteNavigateToLoginView); - this.LogoutCommand = new DelegateCommand(this.ExecuteLogout, this.CanExecuteLogout); - this.NavigateToNavigationViewCommand = new DelegateCommand( - this.ExecuteNavigateToNavigationView, this.CanExecuteNavigateToNavigationView); - this.NavigateToContactViewCommand = new DelegateCommand( - this.ExecuteNavigateToContactView); - - this.logger.LogInformation("CoreOptions: {0}", this.coreOptions.Value); - } - - public ViewModelContext ViewModelContext - { - get => this.viewModelContext; - set - { - this.SetProperty(ref this.viewModelContext, value); - this.viewModelContext.PropertyChanged += this.ViewModelContext_PropertyChanged; - } - } - - public DelegateCommand NavigateToLoginViewCommand { get; } - - public DelegateCommand LogoutCommand { get; } - - public DelegateCommand NavigateToNavigationViewCommand { get; } - - public DelegateCommand NavigateToContactViewCommand { get; } - - private bool IsAuthenticated => this.ViewModelContext?.Principal?.Identity.IsAuthenticated == true; - - private void ExecuteNavigateToLoginView() - { - this.regionManager.RequestNavigate(Constants.ContentRegion, nameof(LoginView)); - this.ViewModelContext.NavigateBackTarget = nameof(WelcomeView); - } - - private bool CanExecuteLogout() => this.IsAuthenticated; - - private void ExecuteLogout() - { - this.ViewModelContext.Principal = null; - } - - private bool CanExecuteNavigateToNavigationView() => this.IsAuthenticated; - - private void ExecuteNavigateToNavigationView() - { - this.regionManager.RequestNavigate(Constants.ContentRegion, nameof(DeviceListView)); - this.ViewModelContext.NavigateBackTarget = nameof(WelcomeView); - } - - private void ExecuteNavigateToContactView() - { -#if DEBUG - this.ViewModelContext.SelectedDevice = FakeClients.FakeDeviceServiceClient.Devices.Values.First(); - this.regionManager.RequestNavigate(Constants.ContentRegion, nameof(DeviceMetricHistoryPlotView)); - this.ViewModelContext.NavigateBackTarget = nameof(WelcomeView); -#endif - } - - private void ViewModelContext_PropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(this.ViewModelContext.Principal)) - { - this.LogoutCommand.RaiseCanExecuteChanged(); - this.NavigateToNavigationViewCommand.RaiseCanExecuteChanged(); - } - } - } -} diff --git a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Views/BannerView.xaml b/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Views/BannerView.xaml deleted file mode 100644 index 9bd1c6fa..00000000 --- a/GeothermalResearchInstitute/GeothermalResearchInstitute.Wpf/Views/BannerView.xaml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - -