private async Task DoLocalUpdate()
        {
            try
            {
                foreach (var registration in this._serverRegistrations)
                {
                    ServerStatusUpdate statusUpdate = new ServerStatusUpdate();
                    try
                    {
                        Logger.Info($"{nameof(DoLocalUpdate)} Start: {registration.LocalEndpoint}");
                        statusUpdate = await GenerateServerStatusUpdateAsync(registration);

                        PostServerStatusUpdate(registration, registration.UpdateCallback, statusUpdate);
                    }
                    catch (Exception ex)
                    {
                        // We don't want to stop other registration queries or break the ActionBlock
                        Logger.Error($"{nameof(DoLocalUpdate)} - Exception in local update. {ex.Message}\r\n{ex.StackTrace}");
                        Debugger.Break();
                    }
                    finally
                    {
                        Logger.Info($"{nameof(DoLocalUpdate)} End: {registration.LocalEndpoint}: {statusUpdate.Status}");
                    }
                }
            }
            finally
            {
                Task.Delay(Config.Default.ServerStatusWatcher_LocalStatusQueryDelay).ContinueWith(_ => _eventQueue.Post(DoLocalUpdate)).DoNotWait();
            }
        }
        private async Task <ServerStatusUpdate> GenerateServerStatusUpdateAsync(ServerStatusUpdateRegistration registration)
        {
            var registrationKey = registration.SteamEndpoint.ToString();

            //
            // First check the process status
            //
            var processStatus = GetServerProcessStatus(registration, out Process process);

            switch (processStatus)
            {
            case ServerProcessStatus.NotInstalled:
                return(new ServerStatusUpdate {
                    Status = WatcherServerStatus.NotInstalled
                });

            case ServerProcessStatus.Stopped:
                return(new ServerStatusUpdate {
                    Status = WatcherServerStatus.Stopped
                });

            case ServerProcessStatus.Unknown:
                return(new ServerStatusUpdate {
                    Status = WatcherServerStatus.Unknown
                });

            case ServerProcessStatus.Running:
                break;

            default:
                Debugger.Break();
                break;
            }

            var currentStatus = WatcherServerStatus.Initializing;

            //
            // If the process was running do we then perform network checks.
            //
            Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server local network status at {registration.LocalEndpoint}");

            // get the server information direct from the server using local connection.
            GetLocalNetworkStatus(registration.GameFile, registration.LocalEndpoint, out QueryMaster.ServerInfo localInfo, out int onlinePlayerCount);

            if (localInfo != null)
            {
                currentStatus = WatcherServerStatus.RunningLocalCheck;

                //
                // Now that it's running, we can check the publication status.
                //
                Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server public status direct at {registration.SteamEndpoint}");

                // get the server information direct from the server using public connection.
                var serverStatus = CheckServerStatusDirect(registration.SteamEndpoint);
                // check if the server returned the information.
                if (!serverStatus)
                {
                    // server did not return any information
                    var nextExternalStatusQuery = _nextExternalStatusQuery.ContainsKey(registrationKey) ? _nextExternalStatusQuery[registrationKey] : DateTime.MinValue;
                    if (DateTime.Now >= nextExternalStatusQuery)
                    {
                        currentStatus = WatcherServerStatus.RunningExternalCheck;

                        if (!string.IsNullOrWhiteSpace(Config.Default.ServerStatusUrlFormat))
                        {
                            Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server public status via api at {registration.SteamEndpoint}");

                            // get the server information direct from the server using external connection.
                            var uri = new Uri(string.Format(Config.Default.ServerStatusUrlFormat, Config.Default.ServerManagerCode, App.Instance.Version, registration.SteamEndpoint.Address, registration.SteamEndpoint.Port));
                            serverStatus = await NetworkUtils.CheckServerStatusViaAPI(uri, registration.SteamEndpoint);
                        }

                        _nextExternalStatusQuery[registrationKey] = DateTime.Now.AddMilliseconds(Config.Default.ServerStatusWatcher_RemoteStatusQueryDelay);
                    }
                }

                // check if the server returned the information.
                if (serverStatus)
                {
                    currentStatus = WatcherServerStatus.Published;
                }
            }

            var statusUpdate = new ServerStatusUpdate
            {
                Process           = process,
                Status            = currentStatus,
                ServerInfo        = localInfo,
                OnlinePlayerCount = onlinePlayerCount,
            };

            return(await Task.FromResult(statusUpdate));
        }
 private void PostServerStatusUpdate(ServerStatusUpdateRegistration registration, Action <IAsyncDisposable, ServerStatusUpdate> callback, ServerStatusUpdate statusUpdate)
 {
     _eventQueue.Post(() =>
     {
         if (this._serverRegistrations.Contains(registration))
         {
             try
             {
                 callback(registration, statusUpdate);
             }
             catch (Exception ex)
             {
                 DebugUtils.WriteFormatThreadSafeAsync("Exception during local status update callback: {0}\n{1}", ex.Message, ex.StackTrace).DoNotWait();
             }
         }
         return(TaskUtils.FinishedTask);
     });
 }