public void Execute(IActivityMonitor m, object payload) { using (m.OpenTrace($"Executing {UniqueName}.")) { try { if (PayloadSignature != null) { if (!(payload is SimplePayload simple) || simple.Fields.Count != _parameters.Length - 1) { throw new ArgumentException(nameof(payload)); } var p = new object[_parameters.Length]; p[0] = m; for (int i = 0; i < simple.Fields.Count; ++i) { p[i + 1] = simple.Fields[i].GetValue(); } _method.Invoke(_instance, p); } else { _method.Invoke(_instance, new[] { m }); } } catch (Exception ex) { m.Error(ex); } } }
/// <summary> /// Initialization of the handler: computes the path. /// </summary> /// <param name="monitor"></param> public ValueTask <bool> ActivateAsync(IActivityMonitor monitor) { Throw.CheckNotNullArgument(monitor); using (monitor.OpenTrace($"Initializing BinaryFile handler (MaxCountPerFile = {_file.MaxCountPerFile}).")) { return(ValueTask.FromResult(_file.Initialize(monitor))); } }
/// <summary> /// Initialization of the handler: computes the path. /// </summary> /// <param name="m">The monitor to use.</param> public ValueTask <bool> ActivateAsync(IActivityMonitor m) { using (m.OpenTrace($"Initializing TextFile handler (MaxCountPerFile = {_file.MaxCountPerFile}).")) { _file.Initialize(m); return(ValueTask.FromResult(true)); } }
public static void ReplayLogs(DirectoryInfo directory, bool recurse, Func <MultiLogReader.Monitor, ActivityMonitor> monitorProvider, IActivityMonitor m = null) { var reader = new MultiLogReader(); using (m != null ? m.OpenTrace().Send("Reading files from '{0}' {1}.", directory.FullName, recurse ? "(recursive)" : null) : null) { var files = reader.Add(directory.EnumerateFiles("*.ckmon", recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly).Select(f => f.FullName)); if (files.Count == 0) { if (m != null) { m.Warn().Send("No *.ckmon files found!"); } } else { var monitors = reader.GetActivityMap().Monitors; if (m != null) { m.Trace().Send(String.Join(Environment.NewLine, files)); m.CloseGroup(String.Format("Found {0} file(s) containing {1} monitor(s).", files.Count, monitors.Count)); m.OpenTrace().Send("Extracting entries."); } foreach (var mon in monitors) { var replay = monitorProvider(mon); if (replay == null) { if (m != null) { m.Info().Send("Skipping activity from '{0}'.", mon.MonitorId); } } else { mon.Replay(replay, m); } } } } }
void ReadCurrentSha(IActivityMonitor m) { using (m.OpenTrace("Reading current Sha signatures.")) { foreach (var p in _context.DependencyContext.BuildProjectsInfo.ZeroBuildProjects) { var d = _context.FindDriver(p.Project); Debug.Assert(d != null); _currentShas[p.Index] = d.GitRepository.Head.GetSha(p.Project.SolutionRelativeFolderPath); } } }
public static ValueTask <Task <T?> > SendPacket <T>(IActivityMonitor?m, IOutgoingPacketStore store, OutputPump output, IOutgoingPacket packet) where T : class { IDisposableGroup?group = m?.OpenTrace($"Sending a packet '{packet}'in QoS {packet.Qos}"); return(packet.Qos switch { QualityOfService.AtMostOnce => PublishQoS0 <T>(m, group, output, packet), QualityOfService.AtLeastOnce => StoreAndSend <T>(m, group, output, store, packet, packet.Qos), QualityOfService.ExactlyOnce => StoreAndSend <T>(m, group, output, store, packet, packet.Qos), _ => throw new ArgumentException("Invalid QoS."), });
public void LogErrorAndWarnings(IActivityMonitor monitor) { Throw.CheckNotNullArgument(monitor); using (monitor.OpenTrace($"Collector summary:")) { if (PocoSupport == null) { monitor.Fatal($"Poco support failed!"); } RealObjects.LogErrorAndWarnings(monitor); AutoServices.LogErrorAndWarnings(monitor); } }
/// <summary> /// Registers types from multiple assemblies. /// Only classes and IPoco interfaces are considered. /// Once the first type is registered, no more call to <see cref="SetAutoServiceKind(Type, AutoServiceKind)"/> is allowed. /// </summary> /// <param name="assemblyNames">The assembly names to register.</param> /// <returns>The number of new discovered classes.</returns> public int RegisterAssemblyTypes(IReadOnlyCollection <string> assemblyNames) { if (assemblyNames == null) { throw new ArgumentNullException(nameof(assemblyNames)); } int totalRegistered = 0; using (_monitor.OnError(() => ++ _registerFatalOrErrorCount)) using (_monitor.OpenTrace($"Registering {assemblyNames.Count} assemblies.")) { foreach (var one in assemblyNames) { using (_monitor.OpenTrace($"Registering assembly '{one}'.")) { Assembly?a = null; try { a = Assembly.Load(one); } catch (Exception ex) { _monitor.Error($"Error while loading assembly '{one}'.", ex); } if (a != null) { int nbAlready = _cc.RegisteredTypeCount; _cc.RegisterTypes(a.GetTypes()); int delta = _cc.RegisteredTypeCount - nbAlready; _monitor.CloseGroup($"{delta} types(s) registered."); totalRegistered += delta; } } } } return(totalRegistered); }
public void Setup(IActivityMonitor monitor) { using (monitor.OpenInfo($"Executing {_scripts.Count} script(s) on this Workstation.")) using (var tempPS1 = new TemporaryFile("ps1")) { bool hasError = false; HashSet <EnvVar> currentVariables = null; foreach (var o in _scripts) { if (hasError) { break; } switch (o) { case HashSet <EnvVar> v: currentVariables = v; break; case ScriptLine script: { using (monitor.OpenTrace($"Executing script Type='{script.Type}', WorkingDir='{script.WorkingDir}', Arguments='{script.Arguments}', ContinueOnNonZeroExitCode='{script.ContinueOnNonZeroExitCode}'.")) { monitor.Debug($"With EnvironmentVariables: {currentVariables?.Select( v => v.ToString() ).Concatenate()}."); monitor.Debug(script.Script); var variables = currentVariables?.Select(v => (v.Name, Environment.ExpandEnvironmentVariables(v.Value))).ToList() ?? new List <(string Name, string)>(); variables.Add(("CKLI_WORLD_MAPPING", _fileSystem.Root)); System.IO.File.WriteAllText(tempPS1.Path, script.Script); if (!ProcessRunner.RunPowerShell( monitor, script.WorkingDir, tempPS1.Path, new[] { script.Arguments }, stdErrorLevel: LogLevel.Warn, variables)) { hasError |= !script.ContinueOnNonZeroExitCode; if (!hasError) { monitor.Warn("ContinueOnNonZeroExitCode is true: error is ignored."); } } } break; } } } } }
/// <summary> /// Logs detailed information about discovered items. /// </summary> /// <param name="monitor">Logger (must not be null).</param> public void LogErrorAndWarnings(IActivityMonitor monitor) { if (monitor == null) { throw new ArgumentNullException(nameof(monitor)); } using (monitor.OpenTrace($"Auto Services: {LeafInterfaces.Count} most specialized interfaces and {RootClasses.Count} concrete paths.")) { foreach (var a in ClassAmbiguities) { monitor.Error($"Base class '{a[0].ClassType}' cannot be unified by any of this candidates: '{a.Skip( 1 ).Select( t => t.ClassType.ToCSharpName( false ) ).Concatenate( "', '" )}'."); } RealObjectCollectorResult.CommonLogAndWarings(monitor, AbstractTails); } }
public bool PushLocalArtifacts(IActivityMonitor m, IArtifactRepository target, IEnumerable <ArtifactInstance> artifacts, bool arePublicArtifacts) { bool success = true; foreach (var h in _provider._handlers) { using (m.OpenTrace($"Pushing for type handler '{h}'.")) { if (!h.PushLocalArtifacts(this, m, target, artifacts, arePublicArtifacts)) { m.CloseGroup("Failed."); success = false; } } } return(success); }
public void LogErrorAndWarnings(IActivityMonitor monitor) { if (monitor == null) { throw new ArgumentNullException(nameof(monitor)); } using (monitor.OpenTrace($"Real Objects: {EngineMap.RawMappings.Count} mappings for {_concreteClassesPath.Count} concrete paths.")) { foreach (var a in InterfaceAmbiguities) { monitor.Error($"Interface '{a[0].FullName}' is implemented by more than one concrete classes: {a.Skip( 1 ).Select( t => t.ToCSharpName() ).Concatenate( "', '" )}."); } foreach (var a in ClassAmbiguities) { monitor.Error($"Base class '{a[0].FullName}' has more than one concrete specialization: '{a.Skip( 1 ).Select( t => t.ToCSharpName() ).Concatenate( "', '" )}'."); } CommonLogAndWarings(monitor, AbstractTails); } }
/// <summary> /// Finds from the cache or loads a Xml project file. /// </summary> /// <param name="m">The monitor to use.</param> /// <param name="path">The file path relative to the <see cref="FileSystem"/>.</param> /// <param name="cache">Cache by path.</param> /// <returns>The file or null if unable to load it.</returns> public static MSProjFile FindOrLoadProjectFile( FileSystem fs, IActivityMonitor m, NormalizedPath path, Dictionary <NormalizedPath, MSProjFile> cache) { if (cache.TryGetValue(path, out MSProjFile f)) { return(f); } using (m.OpenTrace($"Loading project file {path}.")) { try { var fP = fs.GetFileInfo(path); if (!fP.Exists) { m.Warn($"Unable to find project file '{path}'. This project is ignored. This may be a case sensivity issue!"); return(null); } XDocument content = fP.ReadAsXDocument(); var imports = new List <Import>(); f = new MSProjFile(path, content, imports); cache[path] = f; var folder = path.RemoveLastPart(); imports.AddRange(content.Root.Descendants("Import") .Where(i => i.Attribute("Sdk") == null) .Select(i => (E: i, P: (string)i.Attribute("Project"))) .Where(i => i.P != null) .Select(i => new Import(i.E, FindOrLoadProjectFile(fs, m, folder.Combine(i.P).ResolveDots(), cache)))); f.Initialize(); return(f); } catch (Exception ex) { m.Error(ex); cache.Remove(path); return(null); } } }
protected override async ValueTask <IOutgoingPacket> DoStorePacket(IActivityMonitor?m, IOutgoingPacket packet) { int packetSize = packet.GetSize(_protocolConfig.ProtocolLevel); m?.Trace($"Renting {packetSize} bytes to persist {packet}."); IMemoryOwner <byte> memOwner = MemoryPool <byte> .Shared.Rent(packetSize); PipeWriter pipe = PipeWriter.Create(memOwner.Memory.AsStream()); // And write their content to this memory. using (m?.OpenTrace($"Serializing {packet} into memory...")) { if (await packet.WriteAsync(_protocolConfig.ProtocolLevel, pipe, default) != WriteResult.Written) { throw new InvalidOperationException("Didn't wrote packet correctly."); } } Memory <byte> slicedMem = memOwner.Memory.Slice(0, packetSize); base[packet.PacketId].Content.Storage = new StoredPacket(slicedMem, memOwner); return(new FromMemoryOutgoingPacket(slicedMem, packet.Qos, packet.PacketId)); }
static void DumpMonitorOutput(IActivityMonitor monitor) { Exception exception1; Exception exception2; try { throw new InvalidOperationException("Exception!"); } catch (Exception e) { exception1 = e; } try { throw new InvalidOperationException("Inception!", exception1); } catch (Exception e) { exception2 = e; } for (int i = 0; i < 5; i++) { using (monitor.OpenTrace().Send("Dump output loop {0}", i)) { for (int j = 0; j < 1000; j++) { monitor.Trace().Send("Trace log! {0}", j); monitor.Info().Send("Info log! {0}", j); monitor.Warn().Send("Warn log! {0}", j); monitor.Error().Send("Error log! {0}", j); monitor.Error().Send("Fatal log! {0}", j); monitor.Error().Send(exception2, "Exception log! {0}", j); } } } }
void LogDemo(IActivityMonitor m) { m.Info("This is an info."); using (m.OpenInfo($"This is an info group.")) { m.Fatal($"Ouch! a faaaaatal."); m.OpenTrace($"A trace"); var group = m.OpenInfo($"This is another group (trace)."); { try { throw new Exception(); } catch (Exception ex) { m.Error("An error occurred.", ex); } } m.CloseGroup("This is a close group."); group.Dispose(); } }
/// <summary> /// Saves this folder, its files and all its subordinated folders, into one or more actual paths on the file system. /// </summary> /// <param name="monitor">The monitor to use.</param> /// <param name="outputPaths">Any number of target directories.</param> /// <returns>True on success, false is an error occurred (the error has been logged).</returns> public bool Save(IActivityMonitor monitor, IReadOnlyCollection <NormalizedPath> outputPaths) { using (monitor.OpenTrace($"Saving {(IsRoot ? $"TypeScript Root folder into {outputPaths.Select( o => o.ToString() ).Concatenate()}" : Name)}.")) { try { var newOnes = IsRoot ? outputPaths : outputPaths.Select(p => p.AppendPart(Name)).ToArray(); if (_firstFile != null) { foreach (var p in newOnes) { Directory.CreateDirectory(p); } var file = _firstFile; while (file != null) { file.Save(monitor, newOnes); file = file._next; } } var folder = _firstChild; while (folder != null) { if (!folder.Save(monitor, newOnes)) { return(false); } folder = folder._next; } return(true); } catch (Exception ex) { monitor.Error(ex); return(false); } } }
PluginCollection <IGitBranchPlugin> DoFindOrCreate(bool ensureFirstLoad, string branchName, IActivityMonitor m = null) { if (String.IsNullOrWhiteSpace(branchName)) { throw new ArgumentNullException(nameof(branchName)); } if (!_branchPlugins.TryGetValue(branchName, out var c) || (ensureFirstLoad && !c.IsFirstLoadDone)) { using (ensureFirstLoad && m != null ? m.OpenTrace($"Initializing plugins for '{_manager.Registry.FolderPath}' branch '{branchName}'.") : null) { try { _manager._plugins.EnsureFirstLoad(); if (c == null) { c = new PluginCollection <IGitBranchPlugin>(_manager, branchName); _branchPlugins.Add(branchName, ensureFirstLoad ? c.EnsureFirstLoad() : c); } else { c.EnsureFirstLoad(); } } catch (Exception ex) { if (m == null) { throw; } m.Error(ex); return(null); } } } return(c); }
/// <summary> /// Gets the information about build projects (see <see cref="Solution.BuildProject"/>) /// and their dependencies. /// </summary> /// <param name="m">The monitor to use.</param> /// <param name="traceGraphDetails">True to trace the details of the input and output (sorted) graphs.</param> /// <returns>The build projects information.</returns> BuildProjectsInfo GetBuildProjectInfo(IActivityMonitor m) { Debug.Assert(!_projects.PureProjectsMode); _projects.PureProjectsMode = true; try { using (m.OpenTrace($"Creating Build Projects information.")) { IDependencySorterResult rBuildProjects = DependencySorter.OrderItems(m, _projects.AllProjectItems.Where(p => p.Project.IsBuildProject), null); if (!rBuildProjects.IsComplete) { rBuildProjects.LogError(m); return(new BuildProjectsInfo(rBuildProjects, null)); } else { var rankedProjects = rBuildProjects.SortedItems .Where(i => i.Item is ProjectItem) .Select(i => (i.Rank, ((ProjectItem)i.Item).Project, DirectDeps: i.Requires .Select(s => s.Item) .OfType <ProjectItem>() .Select(p => p.Project), AllDeps: i.GetAllRequires() .Select(s => s.Item) .OfType <ProjectItem>() .Select(p => p.Project))); var zeroBuildProjects = rankedProjects.Select((p, idx) => new ZeroBuildProjectInfo( idx, p.Rank, p.Project, // UpgradePackages: Among direct dependencies, consider only the // published projects and the ones who are actually referenced // as a package (ignores ProjectReference). p.DirectDeps .Where(d => d.IsPublished && p.Project.PackageReferences.Any(r => d.GeneratedArtifacts .Select(a => a.Artifact) .Contains(r.Target.Artifact))) .ToArray(), // UpgradeZeroProjects: Among direct dependencies, consider all the // published projects, the ones who are actually referenced // as a package AND the ones that are ProjectReference. // ProjectReference MUST be transformed into PackageReference // during ZeroBuild. p.DirectDeps .Where(d => d.IsPublished) .ToArray(), // Dependencies: Considers all the projects. p.AllDeps.ToArray() )) .ToArray(); Debug.Assert(zeroBuildProjects.Select(z => z.Rank).IsSortedLarge()); Debug.Assert(zeroBuildProjects.Select(z => z.Index).IsSortedStrict()); return(new BuildProjectsInfo(rBuildProjects, zeroBuildProjects)); } } } finally { _projects.PureProjectsMode = false; } }
/// <summary> /// Finalizes the code generation. /// </summary> /// <param name="monitor">The monitor to use.</param> /// <returns>True on success, false on error.</returns> public bool FinalizeCodeGeneration(IActivityMonitor monitor) { if (_finalizedCall.HasValue) { return(_finalizedCall.Value); } using (monitor.OpenInfo($"Generating Json serialization with {_map.Count} mappings to {_typeInfos.Count} types.")) { int missingCount = 0; foreach (var t in _typeInfos) { if (t.CodeReader == null || t.CodeWriter == null) { ++missingCount; using (_monitor.OpenTrace($"Missing CodeReader/Writer for '{t.NonNullableJsonName}'. Raising TypeInfoConfigurationRequired.")) { try { TypeInfoConfigurationRequired?.Invoke(this, new TypeInfoConfigurationRequiredEventArg(_monitor, this, t)); } catch (Exception ex) { _monitor.Error($"While raising TypeInfoConfigurationRequired for '{t.NonNullableJsonName}'.", ex); _finalizedCall = false; return(false); } } } } if (missingCount > 0) { // Let the TypeInfo be configured in any order (the event for Z may have configured A and Z together). var missing = _typeInfos.Where(i => i.CodeWriter == null || i.CodeReader == null).ToList(); if (missing.Count > 0) { _monitor.Error($"Missing Json CodeReader/Writer functions for types '{missing.Select( m => m.NonNullableJsonName ).Concatenate( "', '" )}'."); _finalizedCall = false; return(false); } } // Generates the code for "dynamic"/"untyped" object. // Writing must handle the object instance to write. Null reference/value type can be handled immediately (by writing "null"). // When not null, we are dealing only with concrete types here: the object MUST be of an allowed concrete type, an abstraction // that wouldn't be one of the allowed concrete type must NOT be handled! // That's why we can use a direct pattern matching on the object's type for the write method (reference types are ordered from specializations // to generalization) and we use the GenericWriteHandler to remove NRT duplicates. GenerateDynamicWrite(_typeInfos); // Reading must handle the [TypeName,...] array: it needs a lookup from the "type name" to the handler to use: this is the goal of // the _typeReaders dictionary that we initialize here (no concurrency issue, no lock to generate: once built the dictionary will only // be read). GenerateDynamicRead(); using (monitor.OpenTrace("Raising JsonTypeFinalized event.")) { string message = "While raising JsonTypeFinalized."; try { JsonTypeFinalized?.Invoke(this, new EventMonitoredArgs(monitor)); message = "While executing deferred actions to GenerateRead/Write code."; foreach (var a in _finalReadWrite) { a(monitor); } } catch (Exception ex) { _monitor.Error(message, ex); _finalizedCall = false; return(false); } } monitor.CloseGroup("Success."); _finalizedCall = true; return(true); } }
public static void ReplayLogs( DirectoryInfo directory, bool recurse, Func<MultiLogReader.Monitor, ActivityMonitor> monitorProvider, IActivityMonitor m = null ) { var reader = new MultiLogReader(); using( m != null ? m.OpenTrace().Send( "Reading files from '{0}' {1}.", directory.FullName, recurse ? "(recursive)" : null ) : null ) { var files = reader.Add( directory.EnumerateFiles( "*.ckmon", recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly ).Select( f => f.FullName ) ); if( files.Count == 0 ) { if( m != null ) m.Warn().Send( "No *.ckmon files found!" ); } else { var monitors = reader.GetActivityMap().Monitors; if( m != null ) { m.Trace().Send( String.Join( Environment.NewLine, files ) ); m.CloseGroup( String.Format( "Found {0} file(s) containing {1} monitor(s).", files.Count, monitors.Count ) ); m.OpenTrace().Send( "Extracting entries." ); } foreach( var mon in monitors ) { var replay = monitorProvider( mon ); if( replay == null ) { if( m != null ) m.Info().Send( "Skipping activity from '{0}'.", mon.MonitorId ); } else { mon.Replay( replay, m ); } } } } }
/// <summary> /// Runs the builder: publishes the build projects that needs to be. /// This is private: <see cref="EnsureZeroBuildProjects"/> calls it. /// </summary> /// <param name="m">The monitor to use.</param> /// <param name="mustReloadSolutions">True if solutions must be reloaded.</param> /// <returns>True on success, false on error.</returns> bool Run(IActivityMonitor m, IBasicApplicationLifetime appLife, out bool mustReloadSolutions) { Debug.Assert(_mustBuild.Count == ZeroBuildProjects.Count); ReadCurrentSha(m); Debug.Assert(ZeroBuildProjects.Select(p => _context.FindDriver(p.Project)) .All(d => d.GitRepository.CheckCleanCommit(m)), "Repositories are clean."); mustReloadSolutions = false; try { using (m.OpenTrace("Analysing dependencies.")) { foreach (var p in ZeroBuildProjects) { using (m.OpenInfo($"{p} <= {(p.AllDependencies.Any() ? p.AllDependencies.Select( d => d.Name ).Concatenate() : "(no dependency)")}.")) { var driver = _context.FindDriver(p.Project); // Check cache. var currentTreeSha = _currentShas[p.Index]; if (currentTreeSha == null) { throw new Exception($"Unable to get Sha for {p}."); } if (!_sha1Cache.TryGetValue(p.Project.FullFolderPath, out var shaList)) { m.Info($"ReasonToBuild#1: No cached Sha signature found for {p.Project.FullFolderPath}."); } else if (!shaList.Contains(currentTreeSha)) { m.Info($"ReasonToBuild#2: Current Sha signature differs from the cached ones."); } else if (p.AllDependencies.Any(dep => _mustBuild.Contains(dep.FullFolderPath))) { m.Info($"ReasonToBuild#3: Rebuild dependencies are {_mustBuild.Intersect( p.AllDependencies.Select( dep => dep.FullFolderPath.Path ) ).Concatenate()}."); } else if (p.MustPack && !System.IO.File.Exists( System.IO.Path.Combine( _localFeedProvider.ZeroBuild.PhysicalPath, p.Project.SimpleProjectName + ".0.0.0-0.nupkg"))) { m.Info($"ReasonToBuild#4: {p.Project.SimpleProjectName}.0.0.0-0 does not exist in in Zero build feed."); } else if (p.Project.IsBuildProject && !System.IO.File.Exists(_localFeedProvider.GetZeroVersionCodeCakeBuilderExecutablePath(p.Project.Solution.Name))) { m.Info($"ReasonToBuild#5: Published ZeroVersion CodeCakeBuilder is missing."); } else { _mustBuild.Remove(p.Project.FullFolderPath); m.CloseGroup($"Project '{p}' is up to date. Build skipped."); } } if (appLife.StopRequested(m)) { return(false); } } } if (_mustBuild.Count == 0) { m.Info("Nothing to build. Build projects are up-to-date."); mustReloadSolutions = false; } else { mustReloadSolutions = true; using (m.OpenTrace($"Build/Publish {_mustBuild.Count} build projects: {_mustBuild.Concatenate()}")) { foreach (var p in ZeroBuildProjects.Where(p => _mustBuild.Contains(p.Project.FullFolderPath))) { var action = p.MustPack ? "Publishing" : "Building"; using (m.OpenInfo($"{action} {p}.")) { var driver = _context.FindDriver(p.Project); if (!driver.ZeroBuildProject(m, p)) { _sha1Cache.Remove(p.Project.FullFolderPath); m.CloseGroup("Failed."); return(false); } _mustBuild.Remove(p.Project.FullFolderPath); AddCurrentShaToCache(m, p); m.CloseGroup("Success."); } if (appLife.StopRequested(m)) { return(false); } } } } return(true); } finally { if (mustReloadSolutions) { SaveShaCache(m); } Debug.Assert(ZeroBuildProjects.Select(p => _context.FindDriver(p.Project)) .All(d => d.GitRepository.CheckCleanCommit(m)), "Repositories are clean."); } }
/// <inheritdoc/> public async Task <ConnectResult> ConnectAsync(IActivityMonitor?m, MqttClientCredentials?credentials = null, OutgoingLastWill?lastWill = null) { if (IsConnected) { throw new InvalidOperationException("This client is already connected."); } using (m?.OpenTrace("Connecting...")) { try { (IOutgoingPacketStore store, IIncomingPacketStore packetIdStore) = await _config.StoreFactory.CreateAsync(m, _pConfig, _config, _config.ConnectionString, credentials?.CleanSession ?? true); IMqttChannel channel = await _config.ChannelFactory.CreateAsync(m, _config.ConnectionString); ConnectAckReflex connectAckReflex = new(); Task <ConnectResult> connectedTask = connectAckReflex.Task; var output = new OutputPump(this, _pConfig); OutputProcessor outputProcessor; var input = new InputPump(this, channel.DuplexPipe.Input, connectAckReflex.ProcessIncomingPacket); OpenPumps(m, new ClientState(input, output, channel, packetIdStore, store)); ReflexMiddlewareBuilder builder = new ReflexMiddlewareBuilder() .UseMiddleware(new PublishReflex(_config, packetIdStore, OnMessage, output)) .UseMiddleware(new PublishLifecycleReflex(packetIdStore, store, output)) .UseMiddleware(new SubackReflex(store)) .UseMiddleware(new UnsubackReflex(store)); if (_config.KeepAliveSeconds == 0) { outputProcessor = new OutputProcessor(output, channel.DuplexPipe.Output, store); } else { OutputProcessorWithKeepAlive withKeepAlive = new(_config, output, channel.DuplexPipe.Output, store);; outputProcessor = withKeepAlive; _ = builder.UseMiddleware(withKeepAlive); } output.StartPumping(outputProcessor); connectAckReflex.Reflex = builder.Build(InvalidPacket); OutgoingConnect outgoingConnect = new(_pConfig, _config, credentials, lastWill); CancellationTokenSource cts = new(_config.WaitTimeoutMilliseconds); IOutgoingPacket.WriteResult writeConnectResult = await outgoingConnect.WriteAsync(_pConfig.ProtocolLevel, channel.DuplexPipe.Output, cts.Token); if (writeConnectResult != IOutgoingPacket.WriteResult.Written) { _ = await CloseAsync(DisconnectedReason.None); return(new ConnectResult(ConnectError.Timeout)); } Task timeout = _config.DelayHandler.Delay(_config.WaitTimeoutMilliseconds, CloseToken); _ = await Task.WhenAny(connectedTask, timeout); // This following code wouldn't be better with a sort of ... switch/pattern matching ? if (connectedTask.Exception is not null) { m?.Fatal(connectedTask.Exception); _ = await CloseAsync(DisconnectedReason.None); return(new ConnectResult(ConnectError.InternalException)); } if (CloseToken.IsCancellationRequested) { _ = await CloseAsync(DisconnectedReason.None); return(new ConnectResult(ConnectError.RemoteDisconnected)); } if (!connectedTask.IsCompleted) { _ = await CloseAsync(DisconnectedReason.None); return(new ConnectResult(ConnectError.Timeout)); } ConnectResult res = await connectedTask; if (res.ConnectError != ConnectError.Ok) { _ = await CloseAsync(DisconnectedReason.None); return(new ConnectResult(res.ConnectError)); } bool askedCleanSession = credentials?.CleanSession ?? true; if (askedCleanSession && res.SessionState != SessionState.CleanSession) { _ = await CloseAsync(DisconnectedReason.None); return(new ConnectResult(ConnectError.ProtocolError_SessionNotFlushed)); } if (res.SessionState == SessionState.CleanSession) { ValueTask task = packetIdStore.ResetAsync(); await store.ResetAsync(); await task; } else { throw new NotImplementedException(); } return(res); } catch (Exception e) { m?.Error("Error while connecting, closing client.", e); _ = await CloseAsync(DisconnectedReason.None); return(new ConnectResult(ConnectError.InternalException)); } } }
static void DumpMonitorOutput( IActivityMonitor monitor ) { Exception exception1; Exception exception2; try { throw new InvalidOperationException( "Exception!" ); } catch( Exception e ) { exception1 = e; } try { throw new InvalidOperationException( "Inception!", exception1 ); } catch( Exception e ) { exception2 = e; } for( int i = 0; i < 5; i++ ) { using( monitor.OpenTrace().Send( "Dump output loop {0}", i ) ) { for( int j = 0; j < 1000; j++ ) { monitor.Trace().Send( "Trace log! {0}", j ); monitor.Info().Send( "Info log! {0}", j ); monitor.Warn().Send( "Warn log! {0}", j ); monitor.Error().Send( "Error log! {0}", j ); monitor.Error().Send( "Fatal log! {0}", j ); monitor.Error().Send( exception2, "Exception log! {0}", j ); } } } }
bool DoComputeFinalTypeKind(IActivityMonitor m, IAutoServiceKindComputeFacade ctx, AutoServiceKind initial, ref bool success) { Debug.Assert(_rawImpls != null); const AutoServiceKind FrontTypeMask = AutoServiceKind.IsFrontProcessService | AutoServiceKind.IsFrontService; bool isScoped = (initial & AutoServiceKind.IsScoped) != 0; HashSet <Type>?allMarshallableTypes = null; HashSet <Type>?frontMarshallableTypes = null; // If it is [IsMarshallable], the marshaller must handle the marhsalling of any implementations // (this is strange... but who knows?). bool isInterfaceMarshallable = (initial & AutoServiceKind.IsMarshallable) != 0; // If isInterfaceMarshallable is false (regular case), then for this IEnumerable to be marshallable, all its // implementations that are Front services must be marshallable so that it can be resolved as long as its // implementations have been marshalled. // Lets's be optimistic: all implementations that are Front(Process) services (if any) will be marshallable. bool isAutomaticallyMarshallable = true; using (m.OpenTrace($"Computing 'IEnumerable<{EnumeratedType.FullName}>'s final type from {_rawImpls.Count} implementations. Initial: '{initial}'.")) { foreach (var info in _rawImpls) { // RealObject are singleton, are not mashallable and not front process. if (info is RealObjectClassInfo) { continue; } Debug.Assert(info.ServiceClass != null); var impl = info.ServiceClass.MostSpecialized; Debug.Assert(impl != null); // We provide a new empty "cycle detection context" to the class constructors: IEnumerable // of interfaces break potential cycles since they handle their own cycle by resolving to // the "worst" non marshallable IsFrontService|IsScoped. // We consider that if the IEnumerable (or one of its class) cannot be resolved by the DI container, // it's not our problem here. var k = impl.ComputeFinalTypeKind(m, ctx, new Stack <AutoServiceClassInfo>(), ref success); // Check for scope lifetime. if (!isScoped) { if ((k & AutoServiceKind.IsScoped) != 0) { if ((initial & AutoServiceKind.IsSingleton) != 0) { m.Error($"Lifetime error: Type 'IEnumerable<{EnumeratedType.FullName}>' has been registered as a Singleton but implementation '{impl.ClassType}' is Scoped."); success = false; } else { isScoped = true; m.Info($"Type 'IEnumerable<{EnumeratedType.FullName}>' must be Scoped since the implementation '{impl.ClassType}' is Scoped."); } } } // If the implementation is not a front service, we skip it (we don't care of a IsMarshallable only type). if ((k & (AutoServiceKind.IsFrontService | AutoServiceKind.IsFrontProcessService)) == 0) { continue; } var newFinal = _finalKind | (k & AutoServiceKind.IsFrontProcessService | AutoServiceKind.IsFrontService); if (newFinal != _finalKind) { // Upgrades from None, Process to Front... m.Trace($"Type 'IEnumerable<{EnumeratedType.FullName}>' must be {newFinal & FrontTypeMask}, because of (at least) '{impl.ClassType}' implementation."); _finalKind = newFinal; } // If the enumerated Service is marshallable at its level OR it is already known to be NOT automatically marshallable, // we don't have to worry anymore about the subsequent implementations marshalling. if (isInterfaceMarshallable || !isAutomaticallyMarshallable) { continue; } if ((k & AutoServiceKind.IsMarshallable) == 0) { if (success) { m.Warn($"Type 'IEnumerable<{EnumeratedType.FullName}>' is not marshallable and the implementation '{impl.ClassType}' that is a Front service is not marshallable: 'IEnumerable<{EnumeratedType.Name}>' cannot be considered as marshallable."); } isAutomaticallyMarshallable = false; } else { if (allMarshallableTypes == null) { allMarshallableTypes = new HashSet <Type>(); } Debug.Assert(impl.MarshallableTypes != null, "EnsureCtorBinding has been called."); allMarshallableTypes.AddRange(impl.MarshallableTypes); if ((k & AutoServiceKind.IsFrontService) != 0) { if (frontMarshallableTypes == null) { frontMarshallableTypes = new HashSet <Type>(); } Debug.Assert(impl.MarshallableInProcessTypes != null, "EnsureCtorBinding has been called."); frontMarshallableTypes.AddRange(impl.MarshallableInProcessTypes); } } } // Conclude about lifetime. if (!isScoped) { if (success && (initial & AutoServiceKind.IsSingleton) == 0) { m.Info($"Nothing prevents 'IEnumerable<{EnumeratedType.FullName}>' to be considered as a Singleton: this is the most efficient choice."); } _finalKind |= AutoServiceKind.IsSingleton; } else { _finalKind |= AutoServiceKind.IsScoped; } // Conclude about Front aspect. if (isInterfaceMarshallable) { MarshallableTypes = MarshallableInProcessTypes = new[] { EnumeratedType }; Debug.Assert((_finalKind & AutoServiceKind.IsMarshallable) == 0); } else { if (isAutomaticallyMarshallable && allMarshallableTypes != null) { Debug.Assert(allMarshallableTypes.Count > 0); MarshallableTypes = allMarshallableTypes; _finalKind |= AutoServiceKind.IsMarshallable; if (frontMarshallableTypes != null) { MarshallableInProcessTypes = frontMarshallableTypes; } else { MarshallableInProcessTypes = Type.EmptyTypes; } } else { // This service is not a Front service OR it is not automatically marshallable. // We have nothing special to do: the set of Marshallable types is empty (this is not an error). MarshallableTypes = MarshallableInProcessTypes = Type.EmptyTypes; Debug.Assert((_finalKind & AutoServiceKind.IsMarshallable) == 0); } } if (_finalKind != initial) { m.CloseGroup($"Final: {_finalKind}"); } } return(success); }