/// <summary> /// Produces a DOT GraphViz graph. /// </summary> /// <returns>DOT GraphViz text.</returns> public string WriteMap(ISchematic <TState, TInput> schematic) { var lines = new List <string>(); var actionLines = new List <string>(); foreach (var state in schematic.States.Values) { var source = state.Value; lines.AddRange(state.Transitions.Values .Select(transition => GetTransitionRepresentation( source.ToString(), transition.Input.ToString(), transition.ResultantState.ToString(), transition.Precondition?.Description))); if (state.Action != null) { actionLines.Add($" {state.Value} -> \"{state.Action.Description ?? state.Action.ConnectorKey.Identifier}\"" + " [label=\"executes\" style=dotted];"); } } if (actionLines.Count > 0) { lines.Add(" node [shape=box];"); lines.AddRange(actionLines); } return($"digraph {{\r\n{ string.Join("\r\n\t", lines) }\r\n}}"); }
public Task <IEnumerable <IStateMachine <TState, TInput> > > BulkCreateMachinesAsync( ISchematic <TState, TInput> schematic, IEnumerable <IDictionary <string, string> > metadata, CancellationToken cancellationToken = default) { return(BulkCreateMachinesAsync(schematic.Clone(), metadata, cancellationToken)); }
public async Task InvokeAsync <TPayload>( ISchematic <TState, TInput> schematic, IStateMachine <TState, TInput> machine, Status <TState> status, InputParameters <TInput, TPayload> inputParameters, IReadOnlyDictionary <string, string> connectorSettings, CancellationToken cancellationToken = default) { var configuration = _configurations.FindConfiguration(schematic, status); var messageBytes = CreateMessageBytes( schematic, machine, status, inputParameters, connectorSettings, cancellationToken); var queueClient = new QueueClient( new ServiceBusConnectionStringBuilder(configuration.ConnectionString), ReceiveMode.PeekLock, RetryPolicy.Default); await queueClient.SendAsync(new Message(messageBytes)); }
public Task <bool> ValidateAsync <TPayload>( ISchematic <TypeState, TypeState> schematic, IStateMachine <TypeState, TypeState> machine, Status <TypeState> status, InputParameters <TypeState, TPayload> inputParameters, IReadOnlyDictionary <string, string> connectorSettings, CancellationToken cancellationToken = default) { TSignal signal = default; if (inputParameters != null) { if (!(inputParameters.Payload is TSignal castedSignal)) { throw new ArgumentException( $"Type mismatch for converting to signal: " + $"{typeof(TSignal)} from {typeof(TPayload)}", nameof(inputParameters.Payload)); } signal = castedSignal; } return(ValidateAsync( new ConnectorContext { Schematic = new NaturalSchematic(schematic), Machine = new NaturalStateMachine(machine), Status = status, Settings = connectorSettings }, signal, cancellationToken)); }
public static Schematic <TState, TInput> Clone <TState, TInput>(this ISchematic <TState, TInput> schematic) => new Schematic <TState, TInput>( schematic.SchematicName, schematic.InitialState, schematic.StateConflictRetryCount, schematic.States.Values .Select(Clone) .ToArray());
public Task InvokeAsync <TPayload>( ISchematic <TState, TInput> schematic, IStateMachine <TState, TInput> machine, Status <TState> status, InputParameters <TInput, TPayload> inputParameters, IReadOnlyDictionary <string, string> connectorSettings, CancellationToken cancellationToken = default) { var configuration = _logConfigurations.FindConfiguration(schematic, status); string messageFormat = null; connectorSettings?.TryGetValue("messageFormat", out messageFormat); const string machineEnteredStateMessage = "Machine {machineId} entered state: {state}."; messageFormat = messageFormat ?? machineEnteredStateMessage; var logLevel = MapLogLevel(configuration.LogLevel); object input = null; object payload = null; if (inputParameters != null) { input = inputParameters.Input; payload = inputParameters.Payload; } var logParameters = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase) { [nameof(schematic.SchematicName)] = schematic.SchematicName, [nameof(machine.MachineId)] = machine.MachineId, [nameof(status.State)] = status.State, [nameof(inputParameters.Input)] = input, [nameof(inputParameters.Payload)] = payload }; // Get the distinct set of matches including casing. var matches = _messageFormatTokensRegex .Matches(messageFormat).Cast <Match>() .Select(match => match.Value) .ToList(); var parameters = matches.Select(match => { logParameters.TryGetValue(match, out var value); return(value); }).ToArray(); Logger.LogFormat(logLevel, messageFormat, parameters); #if NET45 return(Task.FromResult(0)); #else return(Task.CompletedTask); #endif }
public Task Given_a_Schematic_with_an_initial_state_INITIALSTATE(string schematicName, TState initialState) { CurrentSchematic = CurrentHost.Agent() .CreateSchematic <TState, TInput>(schematicName) .WithState(initialState, state => state .AsInitialState()) .Build(); return(Task.CompletedTask); }
/// <summary> /// Generates nodes for all components, one node connects all terminals (components) that have the same position or that /// are connected through wire(s) /// </summary> /// <param name="schematic"></param> /// <returns></returns> public static List <INode> Generate(ISchematic schematic) { // Generate nodes located on the same position var nodes = GenerateSamePositionNodes(new List <IBaseComponent>(schematic.Components)); // Merge them based on the wire connections nodes = MergeNodesConnectedByWires(nodes, new List <IWire>(schematic.Wires)); return(nodes); }
public async Task Given_a_Machine_exists_with_MachineId_MACHINEID(ISchematic <TState, TInput> schematic, string machineId) { CurrentMachine = await CurrentHost.Agent() .GetStateEngine <TState, TInput>() .CreateMachineAsync(schematic, machineId, new Dictionary <string, string> { ["Key1"] = "Value1", ["Key2"] = "Value2" }); }
public async Task When_a_Machine_is_created_from_a_Schematic(ISchematic <TState, TInput> schematic) { try { CurrentMachine = await CurrentHost.Agent() .GetStateEngine <TState, TInput>() .CreateMachineAsync(schematic); } catch (Exception ex) { CurrentException = ex; } }
public Task InvokeAsync <TPayload>( ISchematic <string, string> schematic, IStateMachine <string, string> machine, Status <string> status, InputParameters <string, TPayload> inputParameters, IReadOnlyDictionary <string, string> connectorSettings, CancellationToken cancellationToken = default) { // Processing var engine = Agent.GetStateEngine <string, string>(); return(Task.CompletedTask); }
public async Task When_a_Machine_is_created_from_a_Schematic_with_a_predefined_MachineId( ISchematic <TState, TInput> schematic, string machineId) { try { CurrentMachine = await CurrentHost.Agent() .GetStateEngine <TState, TInput>() .CreateMachineAsync(schematic, machineId); } catch (Exception ex) { CurrentException = ex; } }
public async Task InvokeAsync <TPayload>( ISchematic <string, string> schematic, IStateMachine <string, string> machine, Status <string> status, InputParameters <string, TPayload> inputParameters, IReadOnlyDictionary <string, string> connectorSettings, CancellationToken cancellationToken = default) { // Processing // Move next await Task.WhenAll( machine.SendAsync("Continue", cancellationToken), machine.SendAsync("Complete", cancellationToken)); }
protected override Task OnMachineCreatedAsync <TState, TInput>( ISchematic <TState, TInput> schematic, MachineCreationEventData <TState> machineCreationEventData) { Logger.LogFormat( _loggingLevel, "Machine {machineId} created in state {state} with commit number of {commitNumber}.", machineCreationEventData.InitialStatus.MachineId, machineCreationEventData.InitialStatus.State, machineCreationEventData.InitialStatus.CommitNumber); #if NET45 return(Task.FromResult(0)); #else return(Task.CompletedTask); #endif }
public static TConfiguration FindConfiguration <TConfiguration, TState, TInput>( this IEnumerable <TConfiguration> configurations, ISchematic <TState, TInput> schematic, Status <TState> status) where TConfiguration : IConnectorConfiguration { var connectorKey = schematic.FindConnectorKey(status.State); var configuration = configurations.SingleOrDefault(c => c.Identifier == connectorKey.Identifier); if (configuration == null) { throw new ConnectorConfigurationNotFoundException <TState, TInput>(schematic, status, connectorKey); } return(configuration); }
public async Task When_a_Machine_is_created_from_a_Schematic(ISchematic <TState, TInput> schematic) { try { CurrentMachine = await CurrentHost.Agent() .GetStateEngine <TState, TInput>() .CreateMachineAsync(schematic, new Dictionary <string, string> { ["Key1"] = "Value1", ["Key2"] = "Value2" }); } catch (Exception ex) { CurrentException = ex; } }
private void NotifyBulkOnMachineCreated( ISchematic <TState, TInput> schematic, IEnumerable <MachineStatus <TState, TInput> > machineStatuses) { #pragma warning disable 4014 Task.Run(async() => await Task.WhenAll( _listeners.Select(listener => listener.MachineCreatedAsync( schematic, machineStatuses.Select(status => new MachineCreationEventData <TState>( initialStatus: status, metadata: new ReadOnlyDictionary <string, string>( status.Metadata ?? new Dictionary <string, string>(0)) )).ToList()))), CancellationToken.None); #pragma warning restore 4014 }
internal REstateMachine( IConnectorResolver <TState, TInput> connectorResolver, IRepositoryContextFactory <TState, TInput> repositoryContextFactory, ICartographer <TState, TInput> cartographer, IEnumerable <IEventListener> listeners, string machineId, ISchematic <TState, TInput> schematic, IReadOnlyDictionary <string, string> metadata) { _connectorResolver = connectorResolver; _repositoryContextFactory = repositoryContextFactory; _listeners = listeners.ToList(); MachineId = machineId; CachedValues = new Lazy <Task <(ISchematic <TState, TInput> schematic, IReadOnlyDictionary <string, string> metadata)> >( () => Task.FromResult((schematic, metadata))); }
internal REstateMachine( IConnectorResolver <TState, TInput> connectorResolver, IRepositoryContextFactory <TState, TInput> repositoryContextFactory, ICartographer <TState, TInput> cartographer, IEnumerable <IEventListener> listeners, string machineId, ISchematic <TState, TInput> schematic, IReadOnlyDictionary <string, string> metadata) { _connectorResolver = connectorResolver; _repositoryContextFactory = repositoryContextFactory; _metadata = metadata; _listeners = listeners.ToList(); MachineId = machineId; Schematic = schematic; }
public virtual byte[] CreateMessageBytes <TPayload>( ISchematic <TState, TInput> schematic, IStateMachine <TState, TInput> machine, Status <TState> status, InputParameters <TInput, TPayload> inputParameters, IReadOnlyDictionary <string, string> connectorSettings, CancellationToken cancellationToken = default) { var message = new QueueMessage <TState, TInput, TPayload> { State = status.State, CommitNumber = status.CommitNumber, MachineId = status.MachineId, UpdatedTime = status.UpdatedTime, Input = inputParameters.Input, Payload = inputParameters.Payload }; return(LZ4MessagePackSerializer.Serialize(message, MessagePack.Resolvers.ContractlessStandardResolver.Instance)); }
public IStateMachine <TState, TInput> ConstructFromSchematic( string machineId, ISchematic <TState, TInput> schematic, IReadOnlyDictionary <string, string> metadata) { if (schematic == null) { throw new ArgumentNullException(nameof(schematic)); } var restateMachine = new REstateMachine <TState, TInput>( _connectorResolver, _repositoryContextFactory, _cartographer, _listeners, machineId, schematic, metadata); return(restateMachine); }
public async Task <ISchematic <TState, TInput> > GetSchematicAsync(CancellationToken cancellationToken = default) { if (_machineSchematic != null) { return(_machineSchematic); } var response = await _stateMachineService .WithCancellationToken(cancellationToken) .GetMachineSchematicAsync(new GetMachineSchematicRequest { MachineId = MachineId }); _machineSchematic = MessagePackSerializer .Deserialize <Schematic <TState, TInput> >( response.SchematicBytes, ContractlessStandardResolver.Instance); return(_machineSchematic); }
protected override Task OnTransitionAsync <TState, TInput, TPayload>( ISchematic <TState, TInput> schematic, Status <TState> status, IReadOnlyDictionary <string, string> metadata, TInput input, TPayload payload) { Logger.LogFormat( _loggingLevel, "Machine {machineId} transitioned to {state} with input {input}.", status.MachineId, status.State, input, payload, status.CommitNumber); #if NET45 return(Task.FromResult(0)); #else return(Task.CompletedTask); #endif }
/// <summary> /// Measured time, invokes simulation completed event and logs simulation completed event. /// Simulation completed message: "Calculated *simulation name* simulation in *measured time*ms". /// </summary> /// <param name="schematic">Schematic for which to perform the simulation</param> /// <param name="simulationLogic">Action that is responsible for performing and saving simulation results</param> /// <param name="simulationName">Name to use in simulation ended message</param> /// <param name="simulationType">Type of the simulation, for simulation ended event purposes</param> private void SimulationRunWrapper(ISchematic schematic, Action <AdmittanceMatrixFactory> simulationLogic, string simulationName, SimulationType simulationType) { // Create a stopwatch to measure the duration of simulation Stopwatch watch = new Stopwatch(); // Start measuring time watch.Start(); // Create an admittance matrix factory and use it to invoke passed simulation logic simulationLogic(new AdmittanceMatrixFactory(schematic)); // Stop time measurement watch.Stop(); // Invoke simulation completed event SimulationCompleted?.Invoke(this, new SimulationCompletedEventArgs(simulationType)); // Log the simulation time IoC.Log("Completed " + simulationName + $" in {watch.ElapsedMilliseconds}ms", InfoLoggerMessageDuration.Short); }
private async Task InvokeAction( ISchematic <TState, TInput> schematic, Status <TState> status, IStateMachine <TState, TInput> machine, CancellationToken cancellationToken) { var initialAction = schematic.States[schematic.InitialState].Action; if (initialAction == null) { return; } var connector = ConnectorResolver.ResolveAction(initialAction.ConnectorKey); await connector.InvokeAsync <object>( schematic, machine, status, null, initialAction.Settings, cancellationToken); }
/// <summary> /// Performs a full ACDC simulation with <see cref="IOpAmp"/> adjustment - every <see cref="IOpAmp"/> is operating in either active or /// saturated state so that its output voltage does not exceed its supply voltages. /// </summary> /// <param name="schematic"></param> public void ACDCFullCycleWithOpAmpAdjustment(ISchematic schematic) => SimulationRunWrapper(schematic, (x) => FullCycleLogicWithOpAmpAdjustment(x, true), "ACDC Cycle with op-amp adjustment", SimulationType.AC);
/// <summary> /// Performs an AC cycle simulation - simulation is running for one full period of lowest frequency source in the <paramref name="schematic"/> /// </summary> /// <param name="schematic"></param> public void ACFullCycleWithoutOpAmpAdjustment(ISchematic schematic) => SimulationRunWrapper(schematic, (x) => FullCycleWithoutOpAmpAdjustment(x, false), "AC cycle without op-amp adjustment", SimulationType.AC);
/// <summary> /// Performs a DC bias simulation of the circuit. /// </summary> /// <param name="schematic"></param> public void DCBias(ISchematic schematic) => SimulationRunWrapper(schematic, DCBiasLogic, "DC bias", SimulationType.DC);
public Task <ISchematic <TState, TInput> > StoreSchematicAsync( ISchematic <TState, TInput> schematic, CancellationToken cancellationToken = default) => StoreSchematicAsync(schematic.Clone(), cancellationToken);
public Task <IStateMachine <TState, TInput> > CreateMachineAsync( ISchematic <TState, TInput> schematic, string machineId, IDictionary <string, string> metadata = null, CancellationToken cancellationToken = default) => CreateMachineAsync(schematic.Clone(), machineId, metadata, cancellationToken);