diff --git a/.github/workflows/build-installer.yml b/.github/workflows/build-installer.yml index 1efa046..d1b71e5 100644 --- a/.github/workflows/build-installer.yml +++ b/.github/workflows/build-installer.yml @@ -38,7 +38,7 @@ jobs: - name: Test run: dotnet test --no-restore --verbosity normal Lanpartyseating.Desktop.Tests --configuration Release - name: Build - run: dotnet build LanpartySeating.Desktop.Installer/LanpartySeating.Desktop.Installer.wixproj --configuration Release --property:Version=1.0.21 /p:InstallerPlatform=${{ matrix.arch }} + run: dotnet build LanpartySeating.Desktop.Installer/LanpartySeating.Desktop.Installer.wixproj --configuration Release --property:Version=1.0.22 /p:InstallerPlatform=${{ matrix.arch }} - name: Upload artifact uses: actions/upload-artifact@v3 with: diff --git a/LanpartySeating.Desktop.Installer/Lanpartyseating.Desktop.Installer.wxs b/LanpartySeating.Desktop.Installer/Lanpartyseating.Desktop.Installer.wxs index d58f54d..764c795 100644 --- a/LanpartySeating.Desktop.Installer/Lanpartyseating.Desktop.Installer.wxs +++ b/LanpartySeating.Desktop.Installer/Lanpartyseating.Desktop.Installer.wxs @@ -35,26 +35,12 @@ - + - - - - - - + + + + diff --git a/Lanpartyseating.Desktop.Tests/UtilsTests.cs b/Lanpartyseating.Desktop.Tests/UtilsTests.cs index 0f725b3..a452d96 100644 --- a/Lanpartyseating.Desktop.Tests/UtilsTests.cs +++ b/Lanpartyseating.Desktop.Tests/UtilsTests.cs @@ -1,11 +1,13 @@ using Lanpartyseating.Desktop.Business; +using Lanpartyseating.Desktop.Config; +using Microsoft.Extensions.Options; namespace Lanpartyseating.Desktop.Tests; public class UtilsTests { - private readonly Utils _utils = new(); - + private readonly Utils _utils = new(Options.Create(new DebugOptions())); + [Theory] [InlineData("LAN-GAMING-01", 1, true)] [InlineData("LAN-GAMING-01", 2, false)] @@ -19,4 +21,23 @@ public void Test_When_ForThisStationCalled_Then_MatchingStationNumberAndHostname // Assert Assert.Equal(expectedResult, result); } + + [Theory] + [InlineData("LAN-GAMING-01", 1, true)] + [InlineData("LAN-GAMING-01", 2, true)] + [InlineData("LAN-GAMING-1", 1, true)] + [InlineData("LAN-GAMING-70", 70, true)] + public void Test_When_ForThisStationCalled_And_ReactToAllStationsEnabled_Then_ReturnTrue(string hostname, int stationNumber, bool expectedResult) + { + // Create servicecollection with debug options true + var utils = new Utils(Options.Create(new DebugOptions { ReactToAllStations = true })); + + // Act + var result = utils.ForThisStation(stationNumber, hostname); + + // Assert + Assert.Equal(expectedResult, result); + } + + } \ No newline at end of file diff --git a/Lanpartyseating.Desktop.sln.DotSettings.user b/Lanpartyseating.Desktop.sln.DotSettings.user index a612518..e107ede 100644 --- a/Lanpartyseating.Desktop.sln.DotSettings.user +++ b/Lanpartyseating.Desktop.sln.DotSettings.user @@ -1,11 +1,6 @@  - <SessionState ContinuousTestingMode="0" IsActive="True" Name="Test_When_ForThisStationCalled_Then_MatchingStationNumberAndHostnameReturnTrue" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <SessionState ContinuousTestingMode="0" IsActive="True" Name="UtilsTests" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <TestAncestor> - <TestId>xUnit::8B549C98-F78C-422A-8C26-E1D7A0881CAD::net8.0-windows::Lanpartyseating.Desktop.Tests.UtilsTests.Test_When_ForThisStationCalled_Then_MatchingStationNumberAndHostnameReturnTrue</TestId> - </TestAncestor> -</SessionState> - <SessionState ContinuousTestingMode="0" Name="Test_When_ForThisStationCalled_Then_MatchingStationNumberAndHostnameReturnTrue #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> - <TestAncestor> - <TestId>xUnit::8B549C98-F78C-422A-8C26-E1D7A0881CAD::net8.0-windows::Lanpartyseating.Desktop.Tests.UtilsTests.Test_When_ForThisStationCalled_Then_MatchingStationNumberAndHostnameReturnTrue</TestId> + <TestId>xUnit::8B549C98-F78C-422A-8C26-E1D7A0881CAD::net8.0-windows::Lanpartyseating.Desktop.Tests.UtilsTests</TestId> </TestAncestor> </SessionState> \ No newline at end of file diff --git a/Lanpartyseating.Desktop/Business/Callbacks.cs b/Lanpartyseating.Desktop/Business/Callbacks.cs index 9819aae..7cd6aaa 100644 --- a/Lanpartyseating.Desktop/Business/Callbacks.cs +++ b/Lanpartyseating.Desktop/Business/Callbacks.cs @@ -1,10 +1,5 @@ -using System.Diagnostics; -using System.Runtime.InteropServices; -using Lanpartyseating.Desktop.Config; -using Lanpartyseating.Desktop.Contracts; +using Lanpartyseating.Desktop.Contracts; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.Win32; using Message = Phoenix.Message; namespace Lanpartyseating.Desktop.Business; @@ -13,23 +8,28 @@ public class Callbacks { private readonly ILogger _logger; private readonly Utils _utils; - private readonly SeatingOptions _options; + private readonly ISessionManager _sessionManager; + private readonly Timekeeper _timekeeper; - public Callbacks(ILogger logger, IOptions options, Utils utils) + public Callbacks(ILogger logger, + Utils utils, + ISessionManager sessionManager, + Timekeeper timekeeper) { _logger = logger; _utils = utils; - _options = options.Value; + _sessionManager = sessionManager; + _timekeeper = timekeeper; } public void NewReservation(Message payload) { - var payloadObject = payload.Payload.Unbox(); + var newReservation = payload.Payload.Unbox(); - _logger.LogInformation($"New reservation created for station #{payloadObject.StationNumber}"); - if (!_utils.ForThisStation(payloadObject.StationNumber, Environment.MachineName)) return; + _logger.LogInformation($"New reservation created for station #{newReservation.StationNumber}"); + if (!_utils.ForThisStation(newReservation.StationNumber, Environment.MachineName)) return; - _utils.LoginInteractiveSession(_options.GamerAccountUsername, _options.GamerAccountPassword); + _timekeeper.StartSession(newReservation.Start, newReservation.End); } public void TournamentStart(Message payload) @@ -39,7 +39,7 @@ public void TournamentStart(Message payload) _logger.LogInformation($"Tournament started for station #{payloadObject.StationNumber}"); if (!_utils.ForThisStation(payloadObject.StationNumber, Environment.MachineName)) return; - _utils.LoginInteractiveSession(_options.TournamentAccountUsername, _options.TournamentAccountPassword); + _sessionManager.SignInTournamentAccount(); } public void CancelReservation(Message payload) @@ -49,6 +49,16 @@ public void CancelReservation(Message payload) _logger.LogInformation($"Reservation cancelled for station #{payloadObject.StationNumber}"); if (!_utils.ForThisStation(payloadObject.StationNumber, Environment.MachineName)) return; - _utils.LogoffInteractiveSession(); + _timekeeper.EndSession(); + } + + public void ExtendReservation(Message payload) + { + var extendReservation = payload.Payload.Unbox(); + + _logger.LogInformation($"Reservation extended for station #{extendReservation.StationNumber}"); + if (!_utils.ForThisStation(extendReservation.StationNumber, Environment.MachineName)) return; + + _timekeeper.ExtendSession(extendReservation.End); } } \ No newline at end of file diff --git a/Lanpartyseating.Desktop/Business/DummySessionManager.cs b/Lanpartyseating.Desktop/Business/DummySessionManager.cs new file mode 100644 index 0000000..8102da6 --- /dev/null +++ b/Lanpartyseating.Desktop/Business/DummySessionManager.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.Logging; + +namespace Lanpartyseating.Desktop.Business; + +public class DummySessionManager : ISessionManager +{ + private readonly ILogger _logger; + + public DummySessionManager(ILogger logger) + { + _logger = logger; + _logger.LogInformation("The dummy session manager is in use"); + } + + public void SignInGamerAccount() + { + _logger.LogInformation("The client would have logged in an interactive session for the gamer account now"); + } + + public void SignInTournamentAccount() + { + _logger.LogInformation("The client would have logged in an interactive session for the tournament account now"); + } + + public void SignOut() + { + _logger.LogInformation("The client would have logged out an the current interactive session now"); + } +} \ No newline at end of file diff --git a/Lanpartyseating.Desktop/Business/ISessionManager.cs b/Lanpartyseating.Desktop/Business/ISessionManager.cs new file mode 100644 index 0000000..f3ba091 --- /dev/null +++ b/Lanpartyseating.Desktop/Business/ISessionManager.cs @@ -0,0 +1,8 @@ +namespace Lanpartyseating.Desktop.Business; + +public interface ISessionManager +{ + public void SignInGamerAccount(); + public void SignInTournamentAccount(); + public void SignOut(); +} \ No newline at end of file diff --git a/Lanpartyseating.Desktop/Business/PhoenixChannelReactorService.cs b/Lanpartyseating.Desktop/Business/PhoenixChannelReactorService.cs index 86d2bd1..8c4bdf6 100644 --- a/Lanpartyseating.Desktop/Business/PhoenixChannelReactorService.cs +++ b/Lanpartyseating.Desktop/Business/PhoenixChannelReactorService.cs @@ -20,6 +20,7 @@ public PhoenixChannelReactorService(IOptions options, Callbacks _desktopChannel.On("new_reservation", callbacks.NewReservation); _desktopChannel.On("cancel_reservation", callbacks.CancelReservation); _desktopChannel.On("tournament_start", callbacks.TournamentStart); + _desktopChannel.On("extend_reservation", callbacks.ExtendReservation); } public void Connect() diff --git a/Lanpartyseating.Desktop/Business/Timekeeper.cs b/Lanpartyseating.Desktop/Business/Timekeeper.cs new file mode 100644 index 0000000..03ba27d --- /dev/null +++ b/Lanpartyseating.Desktop/Business/Timekeeper.cs @@ -0,0 +1,99 @@ +using Microsoft.Extensions.Logging; + +namespace Lanpartyseating.Desktop.Business; + +using System; +using System.Threading; + +public class Timekeeper : IDisposable +{ + private readonly ILogger _logger; + private readonly ISessionManager _sessionManager; + private Timer _timer; + private DateTimeOffset _sessionEndTime; + private readonly object _lock = new(); + + public Timekeeper(ILogger logger, ISessionManager sessionManager) + { + _logger = logger; + _sessionManager = sessionManager; + _timer = new Timer(SessionEnded, null, Timeout.Infinite, Timeout.Infinite); + } + + public void StartSession(DateTimeOffset startTime, DateTimeOffset endTime) + { + lock (_lock) + { + if (endTime <= startTime) + { + throw new ArgumentException("End time must be later than start time."); + } + + if (endTime <= DateTimeOffset.UtcNow) + { + throw new ArgumentException("End time must be in the future."); + } + + _sessionEndTime = endTime; + var duration = endTime - DateTimeOffset.UtcNow; + + // If the start time is in the future, delay the timer start + if (startTime > DateTimeOffset.UtcNow) + { + _timer.Change(startTime - DateTimeOffset.UtcNow, Timeout.InfiniteTimeSpan); + } + else + { + _timer.Change(duration, Timeout.InfiniteTimeSpan); + } + + _logger.LogInformation($"Session started. Will end at {endTime}."); + _sessionManager.SignInGamerAccount(); + } + } + + public void ExtendSession(DateTimeOffset newEndTime) + { + lock (_lock) + { + if (newEndTime <= DateTimeOffset.UtcNow) + { + throw new ArgumentException("New end time must be in the future."); + } + + if (newEndTime > _sessionEndTime) + { + _sessionEndTime = newEndTime; + var duration = newEndTime - DateTimeOffset.UtcNow; + _timer.Change(duration, Timeout.InfiniteTimeSpan); + _logger.LogInformation($"Session extended. New end time: {newEndTime}."); + } + else + { + _logger.LogInformation("New end time must be later than the current end time."); + } + } + } + + public void EndSession() + { + lock (_lock) + { + _timer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); + _sessionEndTime = DateTimeOffset.MinValue; + _logger.LogInformation("Session forcibly ended."); + _sessionManager.SignOut(); + } + } + + private void SessionEnded(object state) + { + _logger.LogInformation("Session ended."); + _sessionManager.SignOut(); + } + + public void Dispose() + { + _timer?.Dispose(); + } +} \ No newline at end of file diff --git a/Lanpartyseating.Desktop/Business/Utils.cs b/Lanpartyseating.Desktop/Business/Utils.cs index 687b002..d84978b 100644 --- a/Lanpartyseating.Desktop/Business/Utils.cs +++ b/Lanpartyseating.Desktop/Business/Utils.cs @@ -1,56 +1,29 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Text.RegularExpressions; +using Lanpartyseating.Desktop.Config; +using Microsoft.Extensions.Options; using Microsoft.Win32; namespace Lanpartyseating.Desktop.Business; public class Utils { - - [DllImport("wtsapi32.dll", SetLastError = true)] - [return:MarshalAs(UnmanagedType.Bool)] - private static extern bool WTSLogoffSession(IntPtr hServer, int sessionId, bool bWait); + private readonly IOptions _debugOptions; - [DllImport("Kernel32.dll", SetLastError = true)] - [return:MarshalAs(UnmanagedType.U4)] - private static extern int WTSGetActiveConsoleSessionId(); - - public void LoginInteractiveSession(string username, string password) + public Utils(IOptions debugOptions) { - var winlogonRegPath = @"Software\Microsoft\Windows NT\CurrentVersion\Winlogon"; - - // Enable autologon - Registry.SetValue($@"HKEY_LOCAL_MACHINE\{winlogonRegPath}", "AutoAdminLogon", 1, RegistryValueKind.DWord); - - // Don't autologon as soon as the session is logged out - Registry.SetValue($@"HKEY_LOCAL_MACHINE\{winlogonRegPath}", "ForceAutoLogon", 0, RegistryValueKind.DWord); - - // Set autologon username - Registry.SetValue($@"HKEY_LOCAL_MACHINE\{winlogonRegPath}", "DefaultUserName", username, RegistryValueKind.String); - - // Set autologon password - Registry.SetValue($@"HKEY_LOCAL_MACHINE\{winlogonRegPath}", "DefaultPassword", password, RegistryValueKind.String); - - // Trigger autologon on next winlogon start - Registry.LocalMachine.DeleteSubKeyTree($@"{winlogonRegPath}\AutoLogonChecked", false); - - // Kill winlogon - var processes = Process.GetProcessesByName("winlogon"); - foreach (var process in processes) - { - process.Kill(); - } + _debugOptions = debugOptions; } - public void LogoffInteractiveSession() - { - var sessionId = WTSGetActiveConsoleSessionId(); - WTSLogoffSession(IntPtr.Zero, sessionId, false); - } public bool ForThisStation(int stationNumber, string hostname) { + if (_debugOptions.Value.ReactToAllStations) + { + return true; + } + var regex = new Regex(@"^LAN-GAMING-(\d+)$"); var match = regex.Match(hostname); if (!match.Success) diff --git a/Lanpartyseating.Desktop/Business/WindowsSessionManager.cs b/Lanpartyseating.Desktop/Business/WindowsSessionManager.cs new file mode 100644 index 0000000..1a4f7fb --- /dev/null +++ b/Lanpartyseating.Desktop/Business/WindowsSessionManager.cs @@ -0,0 +1,72 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; +using Lanpartyseating.Desktop.Config; +using Microsoft.Extensions.Options; +using Microsoft.Win32; + +namespace Lanpartyseating.Desktop.Business; + +public class WindowsSessionManager : ISessionManager +{ + private readonly SeatingOptions _options; + + public WindowsSessionManager(IOptions options) + { + _options = options.Value; + } + public void SignInGamerAccount() + { + LoginInteractiveSession(_options.GamerAccountUsername, _options.GamerAccountPassword); + } + + public void SignInTournamentAccount() + { + LoginInteractiveSession(_options.TournamentAccountUsername, _options.TournamentAccountPassword); + } + + public void SignOut() + { + LogoffInteractiveSession(); + } + + [DllImport("wtsapi32.dll", SetLastError = true)] + [return:MarshalAs(UnmanagedType.Bool)] + private static extern bool WTSLogoffSession(IntPtr hServer, int sessionId, bool bWait); + + [DllImport("Kernel32.dll", SetLastError = true)] + [return:MarshalAs(UnmanagedType.U4)] + private static extern int WTSGetActiveConsoleSessionId(); + + internal void LoginInteractiveSession(string username, string password) + { + var winlogonRegPath = @"Software\Microsoft\Windows NT\CurrentVersion\Winlogon"; + + // Enable autologon + Registry.SetValue($@"HKEY_LOCAL_MACHINE\{winlogonRegPath}", "AutoAdminLogon", 1, RegistryValueKind.DWord); + + // Don't autologon as soon as the session is logged out + Registry.SetValue($@"HKEY_LOCAL_MACHINE\{winlogonRegPath}", "ForceAutoLogon", 0, RegistryValueKind.DWord); + + // Set autologon username + Registry.SetValue($@"HKEY_LOCAL_MACHINE\{winlogonRegPath}", "DefaultUserName", username, RegistryValueKind.String); + + // Set autologon password + Registry.SetValue($@"HKEY_LOCAL_MACHINE\{winlogonRegPath}", "DefaultPassword", password, RegistryValueKind.String); + + // Trigger autologon on next winlogon start + Registry.LocalMachine.DeleteSubKeyTree($@"{winlogonRegPath}\AutoLogonChecked", false); + + // Kill winlogon + var processes = Process.GetProcessesByName("winlogon"); + foreach (var process in processes) + { + process.Kill(); + } + } + + internal void LogoffInteractiveSession() + { + var sessionId = WTSGetActiveConsoleSessionId(); + WTSLogoffSession(IntPtr.Zero, sessionId, false); + } +} \ No newline at end of file diff --git a/Lanpartyseating.Desktop/Config/DebugOptions.cs b/Lanpartyseating.Desktop/Config/DebugOptions.cs new file mode 100644 index 0000000..d83e885 --- /dev/null +++ b/Lanpartyseating.Desktop/Config/DebugOptions.cs @@ -0,0 +1,7 @@ +namespace Lanpartyseating.Desktop.Config; + +public class DebugOptions +{ + public bool ReactToAllStations { get; set; } + public bool UseDummySessionManager { get; set; } +} \ No newline at end of file diff --git a/Lanpartyseating.Desktop/Config/SeatingOptions.cs b/Lanpartyseating.Desktop/Config/SeatingOptions.cs index 0d49e31..b2c4b32 100644 --- a/Lanpartyseating.Desktop/Config/SeatingOptions.cs +++ b/Lanpartyseating.Desktop/Config/SeatingOptions.cs @@ -1,10 +1,17 @@ -namespace Lanpartyseating.Desktop.Config; +using System.ComponentModel.DataAnnotations; + +namespace Lanpartyseating.Desktop.Config; public class SeatingOptions { - public string WebsocketEndpoint { get; set; } - public string GamerAccountUsername { get; set; } - public string GamerAccountPassword { get; set; } - public string TournamentAccountUsername { get; set; } - public string TournamentAccountPassword { get; set; } + [Required] + public required string WebsocketEndpoint { get; set; } + [Required] + public required string GamerAccountUsername { get; set; } + [Required(AllowEmptyStrings = true)] + public required string GamerAccountPassword { get; set; } + [Required] + public required string TournamentAccountUsername { get; set; } + [Required(AllowEmptyStrings = true)] + public required string TournamentAccountPassword { get; set; } } \ No newline at end of file diff --git a/Lanpartyseating.Desktop/Contracts/ExtendReservation.cs b/Lanpartyseating.Desktop/Contracts/ExtendReservation.cs new file mode 100644 index 0000000..1b781cd --- /dev/null +++ b/Lanpartyseating.Desktop/Contracts/ExtendReservation.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Lanpartyseating.Desktop.Contracts; + +public class ExtendReservation +{ + [JsonProperty("station_number")] + public int StationNumber { get; init; } + [JsonProperty("start_date")] + public DateTimeOffset Start { get; init; } + [JsonProperty("end_date")] + public DateTimeOffset End { get; init; } +} \ No newline at end of file diff --git a/Lanpartyseating.Desktop/Contracts/NewReservation.cs b/Lanpartyseating.Desktop/Contracts/NewReservation.cs index f4b55a8..a904fdb 100644 --- a/Lanpartyseating.Desktop/Contracts/NewReservation.cs +++ b/Lanpartyseating.Desktop/Contracts/NewReservation.cs @@ -6,4 +6,8 @@ public class NewReservation { [JsonProperty("station_number")] public int StationNumber { get; init; } + [JsonProperty("start_date")] + public DateTimeOffset Start { get; init; } + [JsonProperty("end_date")] + public DateTimeOffset End { get; init; } } \ No newline at end of file diff --git a/Lanpartyseating.Desktop/Lanpartyseating.Desktop.csproj b/Lanpartyseating.Desktop/Lanpartyseating.Desktop.csproj index 6a4b6cb..c431dd6 100644 --- a/Lanpartyseating.Desktop/Lanpartyseating.Desktop.csproj +++ b/Lanpartyseating.Desktop/Lanpartyseating.Desktop.csproj @@ -10,6 +10,7 @@ + @@ -19,7 +20,7 @@ - + Always diff --git a/Lanpartyseating.Desktop/Program.cs b/Lanpartyseating.Desktop/Program.cs index 898b0c7..66e36c6 100644 --- a/Lanpartyseating.Desktop/Program.cs +++ b/Lanpartyseating.Desktop/Program.cs @@ -4,6 +4,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; + namespace Lanpartyseating.Desktop; [UsedImplicitly] @@ -26,10 +28,22 @@ static void Main(string[] args) options.ServiceName = "Lanparty Seating"; }); services.AddOptions() + .ValidateDataAnnotations() .BindConfiguration("Seating"); + services.AddOptions() + .BindConfiguration("Debug"); services.AddSingleton(); services.AddSingleton(); + if (services.BuildServiceProvider().GetRequiredService>().Value.UseDummySessionManager) + { + services.AddSingleton(); + } + else + { + services.AddSingleton(); + } services.AddSingleton(); + services.AddSingleton(); services.AddHostedService(); }) .Build(); diff --git a/Lanpartyseating.Desktop/appsettings.Development.json b/Lanpartyseating.Desktop/appsettings.Development.json index b62a5a6..31e0e5e 100644 --- a/Lanpartyseating.Desktop/appsettings.Development.json +++ b/Lanpartyseating.Desktop/appsettings.Development.json @@ -5,6 +5,10 @@ "Microsoft.Hosting.Lifetime": "Information" } }, + "Debug": { + "ReactToAllStations": true, + "UseDummySessionManager": true + }, "Seating": { "WebsocketEndpoint": "ws://localhost:4000/desktop", "GamerAccountUsername": "gamer", diff --git a/Lanpartyseating.Desktop/appsettings.json b/Lanpartyseating.Desktop/appsettings.Production.json similarity index 100% rename from Lanpartyseating.Desktop/appsettings.json rename to Lanpartyseating.Desktop/appsettings.Production.json diff --git a/README.md b/README.md index 0402e53..35ede5b 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Lanpartyseating.Desktop is designed to evolve over time. ## Features -The core features planned for Lanpartyseating.Desktop include: +The core features of Lanpartyseating.Desktop include: 1. **Automatic User Login/Logout:** The client will automatically log users in at the start of gaming sessions and log them out at the end, simplifying the user experience and improving security. @@ -34,15 +34,20 @@ executable or in the `C:\ProgramData\Lanparty Seating` directory. The following settings are available: -| Setting | Description | -|------------------------------|----------------------------------------------------------------| -| `Seating.WebsocketEndpoint` | The `lanparty-seating` WebSocket endpoint to connect to. | -| `Seating.GamerUsername` | The username of the gamer account to use for automatic login. | -| `Seating.GamerPassword` | The password of the gamer account to use for automatic login. | -| `Seating.TournamentUsername` | The username of the tournament account to use for tournaments. | -| `Seating.TournamentPassword` | The password of the tournament account to use for tournaments. | +> [!WARNING] +> The `Debug` settings should only be used to facilitate development of the software. Enabling them in production will cause the software to malfunction. -An example configuration file can be found in the repo at `Lanpartyseating.Desktop/appsettings.json`. +| Setting | Description | +|-------------------------------------|--------------------------------------------------------------------------------------------------------------| +| `Debug.ReactToAllStations` | Set to `true` to process stations events regardless of if they are destined for the current station. | +| `Debug.UseDummySessionManager` | Set to `true` to simply log descriptive messages instead of logging in and out of windows sessions for real. | +| `Seating.WebsocketEndpoint` | The `lanparty-seating` WebSocket endpoint to connect to. | +| `Seating.GamerAccountUsername` | The username of the gamer account to use for automatic login. | +| `Seating.GamerAccountPassword` | The password of the gamer account to use for automatic login. | +| `Seating.TournamentAccountUsername` | The username of the tournament account to use for tournaments. | +| `Seating.TournamentAccountPassword` | The password of the tournament account to use for tournaments. | + +An example configuration file can be found in the repo at `Lanpartyseating.Desktop/appsettings.Production.json`. ### Phoenix.Channel