using System; using System.Collections.Generic; using MultiWheelC.Fleet; using MyParking.Shared; namespace MultiWheelC.Tests { // 为同一测试进程中的各车辆端点提供共享FIFO消息队列。 internal sealed class InMemoryFleetTransportNetwork { private readonly SharedState _sharedState; private readonly HashSet _createdEndpointIds = new HashSet(); public InMemoryFleetTransportNetwork( IReadOnlyList vehicleIds, int leaderVehicleId) { _sharedState = new SharedState( vehicleIds, leaderVehicleId); } public InMemoryFleetTransport CreateEndpoint( int vehicleId) { lock (_sharedState.SyncRoot) { if (!_sharedState.CommandQueues.ContainsKey( vehicleId)) { throw new ArgumentOutOfRangeException( nameof(vehicleId), $"车辆{vehicleId}不属于当前内存车队网络。"); } if (!_createdEndpointIds.Add(vehicleId)) { throw new InvalidOperationException( $"车辆{vehicleId}的内存通信端点已经创建。"); } } return new InMemoryFleetTransport( _sharedState, vehicleId); } internal sealed class SharedState { public SharedState( IReadOnlyList vehicleIds, int leaderVehicleId) { if (vehicleIds == null) { throw new ArgumentNullException( nameof(vehicleIds)); } if (vehicleIds.Count == 0) { throw new ArgumentException( "内存车队网络至少需要一辆车。", nameof(vehicleIds)); } if (leaderVehicleId <= 0) { throw new ArgumentOutOfRangeException( nameof(leaderVehicleId), "主车编号必须大于零。"); } CommandQueues = new Dictionary>(); for (var index = 0; index < vehicleIds.Count; index++) { var vehicleId = vehicleIds[index]; if (vehicleId <= 0) { throw new ArgumentOutOfRangeException( nameof(vehicleIds), $"第{index}辆车的编号必须大于零。"); } if (CommandQueues.ContainsKey(vehicleId)) { throw new ArgumentException( $"内存车队网络包含重复车号{vehicleId}。", nameof(vehicleIds)); } CommandQueues.Add( vehicleId, new Queue()); } if (!CommandQueues.ContainsKey( leaderVehicleId)) { throw new ArgumentException( $"主车{leaderVehicleId}不在车辆列表中。", nameof(leaderVehicleId)); } LeaderVehicleId = leaderVehicleId; } public object SyncRoot { get; } = new object(); public int LeaderVehicleId { get; } public Dictionary> CommandQueues { get; } public Queue ReportQueue { get; } = new Queue(); } } // 单辆模拟车辆持有的通信端点;只负责消息路由,不解释控制语义。 internal sealed class InMemoryFleetTransport : IFleetTransport { private readonly InMemoryFleetTransportNetwork.SharedState _sharedState; private readonly int _localVehicleId; internal InMemoryFleetTransport( InMemoryFleetTransportNetwork.SharedState sharedState, int localVehicleId) { _sharedState = sharedState ?? throw new ArgumentNullException( nameof(sharedState)); _localVehicleId = localVehicleId; } public void SendCommand(FleetCommand command) { if (_localVehicleId != _sharedState.LeaderVehicleId) { throw new InvalidOperationException( "只有主车通信端点可以发送车队命令。"); } lock (_sharedState.SyncRoot) { if (command.TargetVehicleId == FleetProtocol.BroadcastVehicleId) { foreach (var pair in _sharedState.CommandQueues) { // 主车本地命令由运行入口直接执行,不通过通信回环。 if (pair.Key != _localVehicleId) { pair.Value.Enqueue(command); } } return; } if (!_sharedState.CommandQueues.TryGetValue( command.TargetVehicleId, out var queue)) { throw new ArgumentOutOfRangeException( nameof(command), $"目标车辆{command.TargetVehicleId}不存在。"); } queue.Enqueue(command); } } public void SendReport(FleetMemberReport report) { if (report.VehicleId != _localVehicleId) { throw new ArgumentException( $"车辆{_localVehicleId}不能发送属于车辆" + $"{report.VehicleId}的状态报告。", nameof(report)); } lock (_sharedState.SyncRoot) { _sharedState.ReportQueue.Enqueue(report); } } public bool TryReceiveCommand( out FleetCommand command) { lock (_sharedState.SyncRoot) { var queue = _sharedState.CommandQueues[_localVehicleId]; if (queue.Count == 0) { command = default; return false; } command = queue.Dequeue(); return true; } } public bool TryReceiveReport( out FleetMemberReport report) { if (_localVehicleId != _sharedState.LeaderVehicleId) { throw new InvalidOperationException( "只有主车通信端点可以接收成员状态报告。"); } lock (_sharedState.SyncRoot) { if (_sharedState.ReportQueue.Count == 0) { report = default; return false; } report = _sharedState.ReportQueue.Dequeue(); return true; } } } }