private async Task <Intersection> ReadIntersectionMetaAndSubscribeAsync(TLCFIClientSession session, TLCFIClientConfig config, TLCFIClientStateManager stateManager, CancellationToken token) { ObjectMeta intersectionMeta = null; ObjectData intersectionState = null; var iref = new ObjectReference { Ids = new[] { config.RemoteIntersectionId }, Type = TLCObjectType.Intersection }; try { _logger.Info("Getting Intersection META data for intersection with id {0}", config.RemoteIntersectionId); intersectionMeta = await session.TLCProxy.ReadMetaAsync(iref, token); } catch (JsonRpcException e) { _logger.LogRpcException(e); } if (intersectionMeta == null || intersectionMeta.Meta.Length != 1) { var exmes = $"Error reading META of Intersection: received {intersectionMeta?.Meta.Length ?? 0} objects, expected 1"; _logger.Warn(exmes); throw new InvalidMetaReceivedException(exmes); } _logger.Info("Succesfully obtained Intersection META data"); var intersectionData = (Intersection)intersectionMeta.Meta[0]; stateManager.InternalIntersections.Add(intersectionData); try { intersectionState = await session.TLCProxy.SubscribeAsync(iref, token); } catch (JsonRpcException e) { _logger.LogRpcException(e); } if (intersectionState == null || intersectionState.Data.Length != 1) { var exmes = $"Error reading STATE of Intersection: received {intersectionState?.Data.Length ?? 0} objects, expected 1"; _logger.Warn(exmes); throw new InvalidMetaReceivedException(exmes); } var ins = (Intersection)intersectionState.Data[0]; var sins = stateManager.InternalIntersections.First(x => x.Id == intersectionState.Objects.Ids[0]); // Copy state sins.StateTicks = ins.StateTicks; sins.State = ins.State; session.State.IntersectionControl = sins.State == IntersectionControlState.Control; return(intersectionData); }
private async Task ReadFacilitiesMetaAsync(TLCFIClientSession session, TLCFIClientConfig config, TLCFIClientStateManager stateManager, CancellationToken token) { try { if (_facilitiesRef != null) { ObjectMeta facilitiesMeta = null; try { _logger.Info("Getting TLCFacilities META data"); facilitiesMeta = await session.TLCProxy.ReadMetaAsync(_facilitiesRef, token); } catch (JsonRpcException e) { _logger.LogRpcException(e); } if (facilitiesMeta != null && facilitiesMeta.Meta.Length == 1) { _logger.Info("Succesfully obtained TLCFacilities META data"); var facilitiesData = (TLCFacilities)facilitiesMeta.Meta[0]; stateManager.Facilities = facilitiesData; if (!facilitiesData.Intersections.Contains(config.RemoteIntersectionId)) { _logger.Error("Intersection with id {0} not found in TLCFacilities META data", config.RemoteIntersectionId); throw new TLCObjectNotFoundException(config.RemoteIntersectionId, TLCObjectType.Intersection); } } else { _logger.Fatal("Error reading META of TLCFacilities: received {0} objects, expected 1", facilitiesMeta?.Meta.Length ?? 0); throw new ArgumentOutOfRangeException(); } } else { _logger.Error( "Error reading META of TLCFacilities: reference to facilities is null; was Register() succesfully called?"); throw new NullReferenceException(); } } catch (Exception e) { _logger.Error(e, "Error reading META of TLCFacilities, canceling session; "); throw new TLCFISessionException("Error reading META of TLCFacilities, canceling session"); } }
public async Task InitializeSession(TLCFIClientSession session, TLCFIClientConfig config, TLCFIClientStateManager stateManager, CancellationToken token) { if (config == null) { throw new NullReferenceException("Config is null, has SetConfig been called first?"); } try { var sessionId = await RegisterAsync(session, config, token); if (!session.State.Registered) { throw new TLCFISessionException("Registering with TLC failed"); } ApplicationRegistered?.Invoke(this, EventArgs.Empty); session.StartAliveTimers(); await GetSessionDataAsync(sessionId, session, config, stateManager, token); if (stateManager == null) { return; } await ReadFacilitiesMetaAsync(session, config, stateManager, token); Intersection inter = null; if (!config.UseIdsFromTLCForSubscription) { inter = await ReadIntersectionMetaAndSubscribeAsync(session, config, stateManager, token); } var refs = CollectAllRefs(stateManager.Facilities, inter, config); CheckMetaData(stateManager.Facilities, inter, config); await ReadAllObjectsMetaAsync(refs, session, config, stateManager, token); await SubscribeAllObjectsAsync(refs, session, stateManager, token); ApplicationConfigured?.Invoke(this, EventArgs.Empty); await SetInitialControlState(session, stateManager); _logger.Info("Client configured succesfully. Now ready to request control."); } catch (TLCFISessionException e) { _logger.Fatal(e, "Error initializing session. " + (e.Fatal ? "(FATAL!): " : ": ")); throw new TLCFISessionException("Error initializing session. " + (e.Fatal ? "(FATAL!) " : ""), e.Fatal); } }
private async Task SetInitialControlState(TLCFIClientSession session, TLCFIClientStateManager stateManager) { _logger.Info("Setting initial application session state in TLC (with ControlState.Offline) if needed"); try { if (stateManager.ControlSession.ReqControlState != ControlState.Offline) { await session.SetReqControlStateAsync(ControlState.Offline); } session.State.Configured = true; _logger.Debug("Succesfully set initial application session state in TLC"); } catch (JsonRpcException e) { _logger.LogRpcException(e); throw new TLCFISessionException("Error while setting initial application control state in TLCFacilities."); } }
private async Task <string> RegisterAsync(TLCFIClientSession session, TLCFIClientConfig config, CancellationToken token) { _logger.Info("Registering with TLC."); try { // Register with TLC var rr = new RegistrationRequest { Username = config.Username, Password = config.Password, Version = TLCFIDataProvider.Default.ProtocolVersion, Type = ApplicationType.Control }; try { rr.Uri = !string.IsNullOrWhiteSpace(config.IveraUri) ? new Uri(config.IveraUri) : new Uri("http://10.0.0.0:12345"); } catch (Exception e) { _logger.Error(e, "Error configuring IVERA uri; reverting to default [http://10.0.0.0:12345]. Exception: "); } var reply = await session.TLCProxy.RegisterAsync(rr, token); _facilitiesRef = reply?.Facilities ?? throw new RegistrationFailedException("Received null as a reply to RegisterAsync()."); session.State.Registered = true; _logger.Info("Registered succesful."); return(reply.Sessionid); } catch (JsonRpcException e) { session.State.Registered = false; _logger.LogRpcException(e); return(null); } catch (Exception e) { session.State.Registered = false; _logger.Info(e, "Register failed with non-jsonrpc error: "); return(null); } }
private async Task SubscribeAllObjectsAsync(IEnumerable <ObjectReference> refs, TLCFIClientSession session, TLCFIClientStateManager stateManager, CancellationToken token) { try { var getstatetasks = (from objref in refs where objref.Ids.Length > 0 select session.TLCProxy.SubscribeAsync(objref, token)).Cast <Task>() .ToList(); await Task.WhenAll(getstatetasks.ToArray()); foreach (var t in getstatetasks) { using (var task = t as Task <ObjectData>) { if (task == null) { continue; } var data = task.Result; switch (data.Objects.Type) { case TLCObjectType.SignalGroup: for (var i = 0; i < data.Data.Length; ++i) { var sg = (SignalGroup)data.Data[i]; var ssg = stateManager.InternalSignalGroups.First(x => x.Id == data.Objects.Ids[i]); if (ssg == null) { throw new NullReferenceException(); } // copy state ssg.StateTicks = sg.StateTicks; ssg.State = sg.State; ssg.Predictions = sg.Predictions; } break; case TLCObjectType.Detector: for (var i = 0; i < data.Data.Length; ++i) { var d = (Detector)data.Data[i]; var sd = stateManager.InternalDetectors.First(x => x.Id == data.Objects.Ids[i]); if (sd == null) { throw new NullReferenceException(); } // copy state sd.StateTicks = d.StateTicks; sd.State = d.State; sd.FaultState = d.FaultState; sd.Swico = d.Swico; } break; case TLCObjectType.Input: for (var i = 0; i < data.Data.Length; ++i) { var ip = (Input)data.Data[i]; var sip = stateManager.InternalInputs.First(x => x.Id == data.Objects.Ids[i]); if (sip == null) { throw new NullReferenceException(); } // copy state sip.StateTicks = ip.StateTicks; sip.State = ip.State; sip.FaultState = ip.FaultState; sip.Swico = ip.Swico; } break; case TLCObjectType.Output: for (var i = 0; i < data.Data.Length; ++i) { var op = (Output)data.Data[i]; var sop = stateManager.InternalOutputs.First(x => x.Id == data.Objects.Ids[i]); if (sop == null) { throw new NullReferenceException(); } // copy state sop.StateTicks = op.StateTicks; sop.State = op.State; sop.FaultState = op.FaultState; } break; case TLCObjectType.Intersection: for (var i = 0; i < data.Data.Length; ++i) { var ins = (Intersection)data.Data[i]; var sins = stateManager.InternalIntersections.First(x => x.Id == data.Objects.Ids[i]); if (sins == null) { throw new NullReferenceException(); } // copy state sins.StateTicks = ins.StateTicks; sins.State = ins.State; session.State.IntersectionControl = sins.State == IntersectionControlState.Control; } break; case TLCObjectType.SpecialVehicleEventGenerator: if (data.Data.Length == 1) { var spv = (SpecialVehicleEventGenerator)data.Data[0]; var sspv = stateManager.SpvhGenerator; if (spv == null) { throw new NullReferenceException(); } // copy state sspv.FaultState = spv.FaultState; } break; case TLCObjectType.Variable: for (var i = 0; i < data.Data.Length; ++i) { var v = (Variable)data.Data[i]; var sv = stateManager.InternalVariables.First(x => x.Id == data.Objects.Ids[i]); if (sv == null) { throw new NullReferenceException(); } // copy state sv.Lifetime = v.Lifetime; sv.Value = v.Value; } break; case TLCObjectType.Session: // Already subscribed in Register() case TLCObjectType.TLCFacilities: // This object does not have a state throw new NotSupportedException(); default: throw new ArgumentOutOfRangeException(); } } } _logger.Info("Succesfully initialized TLC state in CLA"); } catch (JsonRpcException e) { _logger.LogRpcException(e); throw new TLCFISessionException("Error while subscribing to objects in TLCFacilities."); } catch (Exception e) { _logger.Error(e, "Error while obtaining objects from TLC"); throw new TLCFISessionException("Error while subscribing to objects in TLCFacilities."); } }
private async Task ReadAllObjectsMetaAsync(IEnumerable <ObjectReference> refs, TLCFIClientSession session, TLCFIClientConfig config, TLCFIClientStateManager stateManager, CancellationToken token) { if (!session.State.Registered) { _logger.Warn( "Error configuring application: not authorized with TLC; were Register() and ReadFacilitiesMeta() called?"); throw new TLCFISessionException("Client is authorized with TLC; were Register() and ReadFacilitiesMeta() called?"); } try { var getmetatasks = (from objref in refs where objref.Ids.Length > 0 select session.TLCProxy.ReadMetaAsync(objref, token)).Cast <Task>() .ToList(); await Task.WhenAll(getmetatasks.ToArray()); foreach (var t in getmetatasks) { using (var task = t as Task <ObjectMeta>) { if (task == null) { continue; } var meta = task.Result; switch (meta.Objects.Type) { case TLCObjectType.SignalGroup: foreach (SignalGroup sg in meta.Meta) { stateManager.InternalSignalGroups.Add(sg); } break; case TLCObjectType.Detector: foreach (Detector d in meta.Meta) { stateManager.InternalDetectors.Add(d); } break; case TLCObjectType.Input: foreach (Input ip in meta.Meta) { stateManager.InternalInputs.Add(ip); } break; case TLCObjectType.Output: foreach (Output op in meta.Meta) { stateManager.InternalOutputs.Add(op); } break; case TLCObjectType.SpecialVehicleEventGenerator: stateManager.SpvhGenerator = (SpecialVehicleEventGenerator)meta.Meta[0]; break; case TLCObjectType.Variable: foreach (Variable op in meta.Meta) { stateManager.InternalVariables.Add(op); } break; case TLCObjectType.Session: // Special kind of object; gets initialized in Register() case TLCObjectType.TLCFacilities: // Got initialized in ReadFacilitiesMeta() case TLCObjectType.Intersection: // Got initialized in ReadFacilitiesMeta() throw new NotSupportedException(); default: throw new ArgumentOutOfRangeException(); } } } } catch (JsonRpcException e) { _logger.LogRpcException(e); throw new TLCFISessionException("Error reading META from TLCFacilities."); } catch (Exception e) { _logger.Error(e, "Error while reading META data for all objects from TLC"); throw new TLCFISessionException("Error reading META from TLCFacilities."); } try { stateManager.Initialize(config.RemoteIntersectionId); // Check and init } catch (DuplicateNameException) { throw new TLCFISessionException("Error checking META data from TLCFacilities (FATAL!)", true); } }
private async Task <TLCFIClientStateManager> GetSessionDataAsync(string sessionId, TLCFIClientSession session, TLCFIClientConfig config, TLCFIClientStateManager stateManager, CancellationToken token) { _logger.Info("Obtaining session data and subscribing to session."); try { // Read meta for session var sref = new ObjectReference() { Ids = new[] { sessionId }, Type = TLCObjectType.Session }; var meta = await session.TLCProxy.ReadMetaAsync(sref, token); token.ThrowIfCancellationRequested(); if (meta == null || meta.Meta.Length != 1) { throw new InvalidMetaReceivedException("Incorrect response while reading session META. Meta received: " + meta); } // Check and store data, set state for session, and subscribe to session updates stateManager.Session = (TLCSessionBase)meta.Meta[0]; ValueChecker.CheckValidObjectId(stateManager.Session.Id); switch (config.ApplicationType) { case ApplicationType.Consumer: case ApplicationType.Provider: break; case ApplicationType.Control: if (stateManager.Session is ControlApplication ct) { // Start with Error state: either the TLC will set it to Offline, or we will in SetInitialControlState ct.ReqControlState = ControlState.Error; ct.StartCapability = config.StartCapability; ct.EndCapability = config.EndCapability; ct.ReqIntersection = config.RemoteIntersectionId; } break; default: throw new ArgumentOutOfRangeException(); } if (stateManager.Session.SessionType != config.ApplicationType) { throw new InvalidTLCObjectTypeException($"Type of Session (ApplicationType) incorrect. Expected {config.ApplicationType.ToString()}, got {stateManager.Session.SessionType.ToString()}"); } var data = await session.TLCProxy.SubscribeAsync(sref, token); token.ThrowIfCancellationRequested(); if (data == null || data.Data.Length != 1) { throw new InvalidStateReceivedException("Incorrect response while reading session STATE. State received: " + data); } ApplicationRegistered?.Invoke(this, EventArgs.Empty); _logger.Info("Succesfully got session meta and state: registered properly."); return(stateManager); } catch (JsonRpcException e) { session.State.Registered = false; _logger.LogRpcException(e); } catch (Exception e) { session.State.Registered = false; _logger.Info(e, "Register failed with non-jsonrpc error."); } return(null); }