public IAsyncDisposable RegisterForUpdates(string installDirectory, string profileId, string gameFile, IPEndPoint localEndpoint, IPEndPoint steamEndpoint, Action <IAsyncDisposable, ServerStatusUpdate> updateCallback) { var registration = new ServerStatusUpdateRegistration { InstallDirectory = installDirectory, ProfileId = profileId, GameFile = gameFile, LocalEndpoint = localEndpoint, SteamEndpoint = steamEndpoint, UpdateCallback = updateCallback, }; registration.UnregisterAction = async() => { var tcs = new TaskCompletionSource <bool>(); _eventQueue.Post(() => { if (_serverRegistrations.Contains(registration)) { Logger.Debug($"{nameof(RegisterForUpdates)} Removing registration for L:{registration.LocalEndpoint} S:{registration.SteamEndpoint}"); _serverRegistrations.Remove(registration); } tcs.TrySetResult(true); return(Task.FromResult(true)); }); await tcs.Task; }; _eventQueue.Post(() => { if (!_serverRegistrations.Contains(registration)) { Logger.Debug($"{nameof(RegisterForUpdates)} Adding registration for L:{registration.LocalEndpoint} S:{registration.SteamEndpoint}"); _serverRegistrations.Add(registration); var registrationKey = registration.SteamEndpoint.ToString(); _nextExternalStatusQuery[registrationKey] = DateTime.MinValue; } return(Task.FromResult(true)); } ); return(registration); }
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); }); }
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.ServerExeFile); 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.ServerExeFile.ToLower())) { // Does this match our server exe and port? var serverArgMatch = String.Format(Config.Default.ServerCommandLineArgsPortMatchFormat, 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.Error($"{nameof(GetServerProcessStatus)}. {ex.Message}\r\n{ex.StackTrace}"); } return(ServerProcessStatus.Stopped); }
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)); }