public IAsyncDisposable RegisterForUpdates(string installDirectory, string profileId, IPEndPoint localEndpoint, IPEndPoint steamEndpoint, Action <IAsyncDisposable, ServerStatusUpdate> updateCallback)
        {
            var registration = new ServerStatusUpdateRegistration
            {
                AsmId            = Config.Default.ASMUniqueKey,
                InstallDirectory = installDirectory,
                ProfileId        = profileId,
                LocalEndpoint    = localEndpoint,
                SteamEndpoint    = steamEndpoint,
                UpdateCallback   = updateCallback,
            };

            registration.UnregisterAction = async() =>
            {
                var tcs = new TaskCompletionSource <bool>();
                _eventQueue.Post(() =>
                {
                    if (_serverRegistrations.Contains(registration))
                    {
                        Logger.Debug("Removing registration for L:{0} S:{1}", registration.LocalEndpoint, registration.SteamEndpoint);
                        _serverRegistrations.Remove(registration);
                    }
                    tcs.TrySetResult(true);
                    return(Task.FromResult(true));
                });

                await tcs.Task;
            };

            _eventQueue.Post(() =>
            {
                if (!_serverRegistrations.Contains(registration))
                {
                    Logger.Debug("Adding registration for L:{0} S:{1}", registration.LocalEndpoint, registration.SteamEndpoint);
                    _serverRegistrations.Add(registration);

                    var registrationKey = registration.SteamEndpoint.ToString();
                    _lastExternalCallQuery[registrationKey]   = DateTime.MinValue;
                    _lastExternalStatusQuery[registrationKey] = DateTime.MinValue;
                }
                return(Task.FromResult(true));
            }
                             );

            return(registration);
        }
 private void PostServerStatusUpdate(ServerStatusUpdateRegistration registration, StatusCallback 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);
     });
 }
        public IAsyncDisposable RegisterForUpdates(string installDirectory, IPEndPoint localEndpoint, IPEndPoint steamEndpoint, Action <IAsyncDisposable, ServerStatusUpdate> updateCallback)
        {
            var registration = new ServerStatusUpdateRegistration
            {
                InstallDirectory = installDirectory,
                LocalEndpoint    = localEndpoint,
                SteamEndpoint    = steamEndpoint,
                UpdateCallback   = updateCallback
            };

            registration.UnregisterAction = async() =>
            {
                var tcs = new TaskCompletionSource <bool>();
                eventQueue.Post(() =>
                {
                    if (serverRegistrations.Contains(registration))
                    {
                        logger.Debug("Removing registration for L:{0} S:{1}", registration.LocalEndpoint, registration.SteamEndpoint);
                        serverRegistrations.Remove(registration);
                    }
                    tcs.TrySetResult(true);
                    return(Task.FromResult(true));
                });

                await tcs.Task;
            };

            eventQueue.Post(() =>
            {
                if (!serverRegistrations.Contains(registration))
                {
                    logger.Debug("Adding registration for L:{0} S:{1}", registration.LocalEndpoint, registration.SteamEndpoint);
                    serverRegistrations.Add(registration);
                }
                return(Task.FromResult(true));
            }
                            );

            return(registration);
        }
        private async Task <ServerStatusUpdate> GenerateServerStatusUpdateAsync(ServerStatusUpdateRegistration registration)
        {
            var registrationKey = registration.SteamEndpoint.ToString();

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

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

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

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

            case ServerProcessStatus.Running:
                break;

            default:
                Debugger.Break();
                break;
            }

            var currentStatus = ServerStatus.Initializing;

            //
            // If the process was running do we then perform network checks.
            //
            Logger.Debug("Checking server local status at {0}", registration.LocalEndpoint);

            // get the server information direct from the server using local connection.
            ReadOnlyCollection <Player> players;
            var localInfo = GetLocalNetworkStatus(registration.LocalEndpoint, out players);

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

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

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

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

                        _lastExternalStatusQuery[registrationKey] = DateTime.Now;
                    }
                }

                //var lastExternalCallQuery = _lastExternalCallQuery.ContainsKey(registrationKey) ? _lastExternalCallQuery[registrationKey] : DateTime.MinValue;
                //if (lastExternalCallQuery == DateTime.MinValue)
                //{
                //    // perform a server call to the web api.
                //    var uri = new Uri(string.Format(Config.Default.ServerCallUrlFormat, Config.Default.ServerManagerCode, registration.SteamEndpoint.Address, registration.SteamEndpoint.Port, Config.Default.ServerManagerUniqueKey, registration.ProfileId));
                //    await NetworkUtils.PerformServerCallToAPI(uri, registration.SteamEndpoint);

                //    _lastExternalCallQuery[registrationKey] = DateTime.Now;
                //}

                // check if the server returned the information.
                if (serverStatus)
                {
                    currentStatus = ServerStatus.Published;
                }
                else
                {
                    Logger.Debug("No public status returned for {0}", registration.SteamEndpoint);
                }
            }

            var statusUpdate = new ServerStatusUpdate
            {
                Process    = process,
                Status     = currentStatus,
                ServerInfo = localInfo,
                Players    = players
            };

            return(await Task.FromResult(statusUpdate));
        }
        private static ServerProcessStatus GetServerProcessStatus(ServerStatusUpdateRegistration updateContext, out Process serverProcess)
        {
            serverProcess = null;
            if (String.IsNullOrWhiteSpace(updateContext.InstallDirectory))
            {
                return(ServerProcessStatus.NotInstalled);
            }

            var serverExePath = Path.Combine(updateContext.InstallDirectory, Config.Default.ServerBinaryRelativePath, Config.Default.ServerExe);

            if (!File.Exists(serverExePath))
            {
                return(ServerProcessStatus.NotInstalled);
            }

            //
            // The server appears to be installed, now determine if it is running or stopped.
            //
            try
            {
                foreach (var process in Process.GetProcessesByName(Config.Default.ServerProcessName))
                {
                    var commandLine = ProcessUtils.GetCommandLineForProcess(process.Id)?.ToLower();

                    if (commandLine != null && commandLine.Contains(updateContext.InstallDirectory.ToLower()) && commandLine.Contains(Config.Default.ServerExe.ToLower()))
                    {
                        // Does this match our server exe and port?
                        var serverArgMatch = String.Format(Config.Default.ServerCommandLineArgsMatchFormat, updateContext.LocalEndpoint.Port).ToLower();
                        if (commandLine.Contains(serverArgMatch))
                        {
                            // Was an IP set on it?
                            var anyIpArgMatch = String.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, String.Empty).ToLower();
                            if (commandLine.Contains(anyIpArgMatch))
                            {
                                // If we have a specific IP, check for it.
                                var ipArgMatch = String.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, updateContext.LocalEndpoint.Address.ToString()).ToLower();
                                if (!commandLine.Contains(ipArgMatch))
                                {
                                    // Specific IP set didn't match
                                    continue;
                                }

                                // Specific IP matched
                            }

                            // Either specific IP matched or no specific IP was set and we will claim this is ours.

                            process.EnableRaisingEvents = true;
                            if (process.HasExited)
                            {
                                return(ServerProcessStatus.Stopped);
                            }

                            serverProcess = process;
                            return(ServerProcessStatus.Running);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Debug("Exception while checking process status: {0}\n{1}", ex.Message, ex.StackTrace);
            }

            return(ServerProcessStatus.Stopped);
        }
        private static async Task <ServerStatusUpdate> GenerateServerStatusUpdateAsync(ServerStatusUpdateRegistration registration)
        {
            //
            // First check the process status
            //
            Process process;
            var     processStatus = GetServerProcessStatus(registration, out process);

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

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

            case ServerProcessStatus.Running:
                break;

            default:
                Debugger.Break();
                break;
            }

            ServerStatus currentStatus = ServerStatus.Initializing;
            //
            // If the process was running do we then perform network checks.
            //
            ServerInfo localInfo;
            ReadOnlyCollection <Player> players;

            localInfo = GetLocalNetworkStatus(registration.LocalEndpoint, out players);

            if (localInfo != null)
            {
                currentStatus = ServerStatus.Running;

                //
                // Now that it's running, we can check the publication status.
                //
                logger.Debug("Checking server public status at {0}", registration.SteamEndpoint);
                var serverInfo = await NetworkUtils.GetServerNetworkInfo(registration.SteamEndpoint);

                if (serverInfo != null)
                {
                    currentStatus = ServerStatus.Published;
                }
                else
                {
                    logger.Debug("No public status returned for {0}", registration.SteamEndpoint);
                }
            }

            var statusUpdate = new ServerStatusUpdate
            {
                Process    = process,
                Status     = currentStatus,
                ServerInfo = localInfo,
                Players    = players
            };

            return(await Task.FromResult(statusUpdate));
        }