Files
kingchenc c193ccedd2 Refactor: Consolidate helpers, standardize JSON library, and improve code organization
Summary
  - Introduced centralized helper classes to eliminate code duplication and improve maintainability
  - Standardized JSON serialization from Newtonsoft.Json to System.Text.Json
  - Refactored large methods into focused, testable units
  - Added pre-compiled regex patterns for better performance

New Helper Classes

  | File | Purpose |
  |------|---------|
  | Helpers/Core/Constants.cs | Centralized magic strings, error codes, ports, app identifiers |
  | Helpers/Core/UrlHelper.cs | URL normalization (NormalizeServerUrl, CombineUrl, IsValidHttpUrl) |
  | Helpers/Core/PlatformService.cs | Cross-platform OS detection and platform-specific operations |
  | Helpers/Core/RegexPatterns.cs | Pre-compiled regex patterns for version parsing, Tizen capabilities, HTML, etc. |
  | Helpers/Core/JsonSerializerOptionsProvider.cs | Centralized JsonSerializerOptions configurations |

Key Changes

TizenInstallerService Refactoring
  Split 215-line InstallPackageAsync into focused methods:
  - PrepareDeviceAsync() – Device preparation and diagnostics
  - GetDeviceInfoAsync() – Device information collection
  - HandleCertificateAsync() – Certificate handling logic
  - ApplyConfigurationAsync() – Configuration application
  - HandleInstallationResultAsync() – Result processing

JSON Library Migration
  Migrated from Newtonsoft.Json to System.Text.Json:
  - Models/GitHubRelease.cs
  - Helpers/Core/AddLatestRelease.cs
  - Helpers/API/TizenApiClient.cs
  - Services/SamsungLoginService.cs
  - Services/TizenInstallerService.cs
  - ViewModels/MainWindowViewModel.cs

Code Quality Improvements
  - Replaced 13× duplicate TrimEnd('/') calls with UrlHelper
  - Unified OS detection via PlatformService (previously mixed OperatingSystem.* and RuntimeInformation.*)
  - Used Random.Shared instead of new Random() for thread safety
  - Eliminated magic strings/numbers via Constants class
2026-01-11 22:32:13 +01:00

103 lines
3.1 KiB
C#

using Fleck;
using Jellyfin2Samsung.Helpers.Core;
using Jellyfin2Samsung.Models;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Jellyfin2Samsung.Services
{
public class TvLogService
{
private WebSocketServer? _server;
private IWebSocketConnection? _connection;
private CancellationTokenSource? _cts;
public void StartLogServer(
int port,
Action<string> onMessage,
Action<TvLogConnectionStatus> onStatusChanged)
{
_cts?.Cancel();
_cts = new CancellationTokenSource();
try
{
FleckLog.Level = LogLevel.Warn;
FleckLog.LogAction = (level, msg, ex) =>
onMessage($"[Fleck {level}] {msg} {ex}\n");
_server = new WebSocketServer($"ws://0.0.0.0:{port}");
_server.Start(socket =>
{
socket.OnOpen = () =>
{
_connection = socket;
onStatusChanged(TvLogConnectionStatus.Connected);
onMessage("[Connected to TV]\n");
};
socket.OnClose = () =>
{
_connection = null;
onStatusChanged(TvLogConnectionStatus.Listening);
onMessage("[TV disconnected]\n");
};
socket.OnMessage = msg =>
{
onMessage(msg + "\n");
};
});
onStatusChanged(TvLogConnectionStatus.Listening);
onMessage($"[Listening on ws://0.0.0.0:{port}]\n");
_ = MonitorForConnectionsAsync(
port,
onMessage,
onStatusChanged,
_cts.Token);
}
catch (Exception ex)
{
onStatusChanged(TvLogConnectionStatus.Stopped);
onMessage($"[Failed to start server: {ex}]\n");
}
}
public void Stop()
{
_cts?.Cancel();
_cts = null;
_server?.Dispose();
_server = null;
_connection = null;
}
private async Task MonitorForConnectionsAsync(
int port,
Action<string> onMessage,
Action<TvLogConnectionStatus> onStatusChanged,
CancellationToken token)
{
try
{
await Task.Delay(TimeSpan.FromSeconds(Constants.Defaults.WebSocketMonitorDelaySeconds), token);
if (_connection != null || token.IsCancellationRequested)
return;
onStatusChanged(TvLogConnectionStatus.NoConnections);
onMessage(
"[No incoming connections detected]\n" +
"If the TV cannot connect, your firewall may be blocking this port.\n\n" +
PlatformService.GetFirewallHelpText(port));
}
catch (TaskCanceledException) { }
}
}
}