public ConnectWindowGenTwo() { ConnectWindowGenTwo.log.Trace("ConnectWindowGenTwo"); this.InitializeComponent(); this.connectModel = new ControlConnectModel(this); this.connectModel.addControlConnectCallback(this); this.socketModel = new SocketModel(this); this.addSocketCallback(); this.initView(); ConnectWindowGenTwo.log.Trace("ip == " + ConfigureUtil.AdapterIP()); ConnectWindowGenTwo.log.Trace("type = " + ConfigureUtil.getClientType()); NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(ConnectWindowGenTwo.AddressChangedCallback); Console.WriteLine("Listening for address changes. Press any key to exit."); }
//Init ======================= Init: private async Task <ConfigureUtil> init(Action <ConfigureUtil> configure) { this.runtimeLog = new LogDispatcher(this.Clock); lock (lockRunning) { if (__running__) { return(null); } __running__ = true; } this.AddSingletonDependency(this, typeof(ICreateInstanceActorForScene)); //Get configuration from the user: var config = new ConfigureUtil(); configure(config); config.Sanitize(); //Add this director to the static list of running directors: lockDirectors.EnterWriteLock(); try { if (directors.ContainsKey(config.DirectorName)) { throw new ApplicationException($"There is already a running director with the name '{config.DirectorName}'"); } directors[config.DirectorName] = this; } finally { lockDirectors.ExitWriteLock(); } //Get an instance of the start up log, or throw an exception: var log = new LogDispatcherForActor(new LogDispatcher(this.Clock), "Before Start"); Actor startUpLogAsActor; { var startUpLogInstantiator = new ActinInstantiator(config.StartUpLogType); if (!startUpLogInstantiator.Build((t) => { throw new ApplicationException($"{config.StartUpLogType.Name} is being used as the 'StartUp' Log, and must not have any dependencies."); })) { throw new ApplicationException($"{config.StartUpLogType.Name} is being used as the 'StartUp' Log, and must not have any dependencies."); } lock (lockInstantiators) { instantiators[config.StartUpLogType] = startUpLogInstantiator; } var startUpLog = startUpLogInstantiator.GetSingletonInstance(this) as IActinLogger; if (startUpLog == null) { throw new ApplicationException("The 'StartUp' Log must implement IActinLogger."); } startUpLogAsActor = startUpLog as Actor; log.AddDestination(startUpLog); if (startUpLog is ActinStandardLogger && !string.IsNullOrWhiteSpace(config.StandardLogOutputFolder)) { var standardLogger = startUpLog as ActinStandardLogger; standardLogger.SetClock(this.Clock); standardLogger.SetLogFolderPath(config.StandardLogOutputFolder); } } try { //Do manual user start up: log.Info("Director Initializing"); await config.RunBeforeStart(new ActorUtil(null, this.Clock) { Log = log, }); //Do automated DI startup: foreach (var a in config.AssembliesToCheckForDI) { try { foreach (var t in a.GetTypes()) { if (t.HasAttribute <SingletonAttribute>() || t.HasAttribute <InstanceAttribute>()) { lock (lockInstantiators) { if (!instantiators.ContainsKey(t)) { //If it's already contained, then it was manually added as a Singleton dependency. //We can't add it again, as when manually added, a singleton instance was provided. instantiators[t] = new ActinInstantiator(t); } } } } } catch (Exception ex) { var msg = $"Actin Failed in assembly {a.FullName}. Inner Exception: {ex.Message}"; log.Error(msg, ex); await runStartUpLog(); throw new Exception(msg, ex); } } lock (lockInstantiators) { //At this point, we should only have manually added singletons, and attribute marked Singleton or Instance classes. var rootableInstantiators = instantiators.Values.ToList(); rootableInstantiators = rootableInstantiators.Where(config.RootActorFilter).ToList(); var skipped = new List <ActinInstantiator>(); foreach (var instantiator in rootableInstantiators) { try { var skippedBecauseConcreteLineageRequired = !instantiator.Build(t => { if (!this.instantiators.TryGetValue(t, out var dependencyInstantiator)) { dependencyInstantiator = new ActinInstantiator(t); this.instantiators[t] = dependencyInstantiator; } return(dependencyInstantiator); }); if (skippedBecauseConcreteLineageRequired) { skipped.Add(instantiator); } } catch (Exception ex) { throw new ApplicationException($"Failed to build rootable type {instantiator.Type.Name}: {ex.Message}", ex); } } var skippedAndNeverBuilt = skipped.Where(x => !x.WasBuilt).ToList(); if (skippedAndNeverBuilt.Any()) { throw new AggregateException(skippedAndNeverBuilt.Select( x => new ApplicationException($"{x.Type.Name} has a concrete [Parent] or [Sibling], but its parent was not found in the dependency chain." + "Most likely you forgot to mark the parent class with a [Singleton] or [Instance] attribute." + "If the Parent is a Scene, or not always available, then you must instead use [FlexibleParent] or [FlexibleSibling]." + "Note that the flexible attributes do not do type checking on start-up."))); } foreach (var singletonInstantiator in rootableInstantiators.Where(x => x.IsRootSingleton)) { var singleton = singletonInstantiator.GetSingletonInstance(this); } } if (!TryGetSingleton(config.RuntimeLogType, out var rtLog)) { throw new ApplicationException($"Actin failed to get a singleton instance of the 'Runtime' log. Ensure you've marked {config.RuntimeLogType.Name} with the Singleton attribute, or manually added it to the Director as a singleton."); } var rtLogAsIActinLogger = rtLog as IActinLogger; if (rtLogAsIActinLogger == null) { throw new ApplicationException($"{config.RuntimeLogType} must implement IActinLogger, as it is being used as the 'Runtime' Log."); } runtimeLog.AddDestination(rtLogAsIActinLogger); await config.RunAfterStart(new ActorUtil(null, this.Clock) { Log = new LogDispatcherForActor(runtimeLog, "After Start"), }); return(config); } catch (Exception ex) when(logFailedStartup(ex)) { //Exception is always unhandled, this is a nicer way to ensure logging before the exception propagates. return(null); } bool logFailedStartup(Exception ex) { log.Log(new ActinLog { Time = Clock.Now, Location = "StartUp", UserMessage = "Actin failed to start.", Details = ex?.ToString(), Type = LogType.Error, }); runStartUpLog().Wait(); return(false); } async Task runStartUpLog() { try { if (startUpLogAsActor != null) { var disposeHandle = await startUpLogAsActor.Init(() => new DispatchData { MainLog = new ConsoleLogger(), }); if (disposeHandle != null) { lock (lockDisposeHandles) { disposeHandles.Add(disposeHandle); } } await startUpLogAsActor.Run(() => new DispatchData { MainLog = new ConsoleLogger(), }); } } catch { //Nowhere to put this if the log is failing. } } }
//Main Loop ======================= Main Loop: async Task runMainLoop(ConfigureUtil config) { var poolCopy = new List <Actor_SansType>(); void safeLog(string location, Exception ex) { try { runtimeLog.Error(location, "Main Loop", ex); } catch { } } runtimeLog.Info("DirectorLoopStarted"); bool readkeyFailed = false; while (Running) { try { try { if (!readkeyFailed && Environment.UserInteractive) { if (Console.KeyAvailable) { var key = Console.ReadKey(true).Key; if (key == ConsoleKey.Q || key == ConsoleKey.Escape) { this.Dispose(); await Task.Delay(5000); //Simulate the time we normally get for shutdown. } } } } catch (Exception ex) { readkeyFailed = true; safeLog("User Interactive Check", ex); } try { poolCopy.Clear(); lock (lockProcessPool) { poolCopy.AddRange(processPool); } } catch (Exception ex) { safeLog("Process Pool Copy", ex); } try { var shouldRemove = poolCopy.Where(x => x.ShouldBeRemovedFromPool).ToList(); if (shouldRemove.Count > 0) { lock (lockProcessPool) { processPool.RemoveAll(x => shouldRemove.Contains(x)); poolCopy.Clear(); poolCopy.AddRange(processPool); } } } catch (Exception ex) { safeLog("Process Pool Pruning", ex); } List <ActorDisposeHandle> handles = null; lock (lockDisposeHandles) { handles = disposeHandles; } try { var remainingHandles = new List <ActorDisposeHandle>(); if (handles != null) { foreach (var handle in handles) { if (handle.MustDispose) { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed handle.DisposeProcess(getCurrentDispatchData); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } else { remainingHandles.Add(handle); } } lock (lockDisposeHandles) { if (disposeHandles != null) { disposeHandles = remainingHandles; } } } } catch (Exception ex) { safeLog("Dispose Processes", ex); } try { List <object> newDependencies = null; lock (lockNewlyRegisteredDependencies) { if (newlyRegisteredDependencies.Count > 0) { newDependencies = newlyRegisteredDependencies.ToList(); newlyRegisteredDependencies.Clear(); } } if (newDependencies != null) { foreach (var newDependency in newDependencies) { try { if (newDependency is Actor_SansType) { var process = newDependency as Actor_SansType; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed process.Init(getCurrentDispatchData).ContinueWith(async task => { #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed if (task.Status == TaskStatus.RanToCompletion) { if (task.Result != null) { var handle = task.Result; var mustDisposeNow = false; lock (lockDisposeHandles) { if (disposeHandles != null) { lock (lockProcessPool) { processPool.Add(process); } disposeHandles.Add(handle); } else { //Means that the whole application has been disposed. mustDisposeNow = true; } } if (mustDisposeNow) { await handle.DisposeProcess(getCurrentDispatchData); } } } }); } else if (newDependency is IOnInit) { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed (newDependency as IOnInit).OnInit(new ActorUtil(newDependency as Actor_SansType, this.Clock)); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } } catch (Exception ex) { safeLog("Initializing Dependency", ex); } } } } catch (Exception ex) { safeLog("Initializing Dependencies", ex); } try { foreach (var process in poolCopy) { try { if (process.ShouldBeRunNow(process.IgnoreSimulatedTime? DateTimeOffset.Now : Clock.Now)) { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed process.Run(getCurrentDispatchData); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } } catch (Exception ex) { safeLog("Running Process", ex); } } } catch (Exception ex) { safeLog("Running All Processes", ex); } await Task.Delay(new TimeSpan(0, 0, 0, 0, config.RunLoopIntervalMs)); } catch (Exception ex) { safeLog("main while", ex); } } }
/// <summary> /// Get setting path. /// </summary> /// <returns>Setting path</returns> public static string GetPath(string fileName) { return(ConfigureUtil.GetAppCurrentDirectory().AddDelimiter() + fileName); }
/// <summary> /// Get setting path. /// </summary> /// <returns>Setting path</returns> public static string GetPath() { return(ConfigureUtil.GetAppCurrentDirectory().AddDelimiter() + Constants.SettingFileName); }