rewrite: Implement TorrentService for managing torrent server lifecycle and configuration

This commit is contained in:
2026-01-03 00:34:41 +00:00
parent 3bd17c4f56
commit 9c9247bf3e
13 changed files with 89 additions and 9 deletions

View File

@@ -14,6 +14,8 @@ const String anilistClientSecret = 'xI8KTZlKm2F3kHXLko1ArQ21bKap4MojgDTk6Ukx';
const String anilistGraphQLEndpoint = 'https://graphql.anilist.co';
// Anizip API configuration
const String anizipBaseEndpoint = 'https://api.ani.zip';
// Torrent API configuration
const String torrentServiceEndpoint = 'http://127.0.0.1:8090';
// Cache configuration
const Set<String> cacheDisabledEndpoints = <String>{
anilistOAuthEndpoint,

View File

@@ -0,0 +1,7 @@
class EmptyApiResponse {
const EmptyApiResponse();
factory EmptyApiResponse.fromJson(Map<String, dynamic> json) {
return const EmptyApiResponse();
}
}

View File

@@ -9,6 +9,7 @@ import 'package:retry/retry.dart';
// Internal dependencies
import 'package:unyo/config/config.dart' as config;
import 'package:unyo/core/di/locator.dart';
import 'package:unyo/core/services/api/http/empty_api_response.dart';
import 'api_response.dart';
import 'http_exception.dart';
@@ -232,6 +233,14 @@ class HttpService {
final status = response.statusCode;
if (status >= 200 && status < 300) {
_logger.d("Response from server is successful with status code $status");
if (response.body.isEmpty) {
_logger.d("Response body is empty, returning empty ApiResponse");
return ApiResponse(
data: fromJson({}),
statusCode: status,
headers: response.headers,
);
}
if (json.decode(response.body) is List<dynamic>) {
final jsonList = json.decode(response.body) as List<dynamic>;
return ApiResponse(

View File

@@ -1,29 +1,37 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:path/path.dart' as path;
import 'package:unyo/config/config.dart' as config;
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:system_info3/system_info3.dart';
import 'package:unyo/core/di/locator.dart';
import 'package:unyo/core/services/api/http/api_response.dart';
import 'package:unyo/core/services/api/http/empty_api_response.dart';
import 'package:unyo/core/services/api/http/http_service.dart';
class TorrentService {
static const String _servicesDir = "services";
static const String _torrServerDir = "torrserver";
static const String _torrentServerName = "torrserver";
static const String _packageAssetsDir = "assets";
final HttpService _httpService = sl<HttpService>();
Process? torrentProcess;
TorrentService() {
initTorrentServer();
}
Future<void> initTorrentServer() async {
await stopServer();
Directory supportDirectory = await getApplicationSupportDirectory();
_loadTorrServerIfNeeded(supportDirectory);
String torrServerPath = await _loadTorrServerIfNeeded(supportDirectory);
_startServer(torrServerPath);
}
Future<void> _loadTorrServerIfNeeded(Directory supportDirectory) async {
Future<String> _loadTorrServerIfNeeded(Directory supportDirectory) async {
String torrentServerPath = path.join(
supportDirectory.path,
_torrServerDir,
_torrentServerName,
_torrentServerName + (Platform.isWindows ? ".exe" : ""),
);
File aniyomiBridgeCore = File(torrentServerPath);
@@ -33,6 +41,10 @@ class TorrentService {
torrentServerPath,
);
}
if (!Platform.isWindows) {
await Process.run('chmod', ['+x', torrentServerPath]);
}
return torrentServerPath;
}
Future<File> _copyAssetToFile(String assetPath, String outPath) async {
@@ -43,4 +55,21 @@ class TorrentService {
await file.writeAsBytes(buffer, flush: true);
return file;
}
Future<void> _startServer(String torrServerPath) async {
torrentProcess = await Process.start(torrServerPath, [], mode: ProcessStartMode.normal);
}
Future<void> stopServer() async {
try {
ApiResponse<EmptyApiResponse> response = await _httpService.get("${config.torrentServiceEndpoint}/shutdown", fromJson: EmptyApiResponse.fromJson);
if (response.statusCode == 200) {
torrentProcess = null;
return;
}
} catch (_) {
}
torrentProcess?.kill();
}
}

View File

@@ -8,7 +8,9 @@
#include <dynamic_color/dynamic_color_plugin.h>
#include <fvp/fvp_plugin.h>
#include <screen_retriever_linux/screen_retriever_linux_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
#include <window_manager/window_manager_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) dynamic_color_registrar =
@@ -17,7 +19,13 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) fvp_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FvpPlugin");
fvp_plugin_register_with_registrar(fvp_registrar);
g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin");
screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
g_autoptr(FlPluginRegistrar) window_manager_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin");
window_manager_plugin_register_with_registrar(window_manager_registrar);
}

View File

@@ -5,7 +5,9 @@
list(APPEND FLUTTER_PLUGIN_LIST
dynamic_color
fvp
screen_retriever_linux
url_launcher_linux
window_manager
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

@@ -9,16 +9,20 @@ import bonsoir_darwin
import dynamic_color
import fvp
import path_provider_foundation
import screen_retriever_macos
import shared_preferences_foundation
import url_launcher_macos
import video_player_avfoundation
import window_manager
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
SwiftBonsoirPlugin.register(with: registry.registrar(forPlugin: "SwiftBonsoirPlugin"))
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
FvpPlugin.register(with: registry.registrar(forPlugin: "FvpPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
}

View File

@@ -15,6 +15,8 @@ PODS:
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- screen_retriever_macos (0.0.1):
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
@@ -23,6 +25,8 @@ PODS:
- video_player_avfoundation (0.0.1):
- Flutter
- FlutterMacOS
- window_manager (0.5.0):
- FlutterMacOS
DEPENDENCIES:
- bonsoir_darwin (from `Flutter/ephemeral/.symlinks/plugins/bonsoir_darwin/darwin`)
@@ -31,9 +35,11 @@ DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`)
- fvp (from `Flutter/ephemeral/.symlinks/plugins/fvp/darwin`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- video_player_avfoundation (from `Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin`)
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
SPEC REPOS:
trunk:
@@ -52,12 +58,16 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/fvp/darwin
path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
screen_retriever_macos:
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos
shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
video_player_avfoundation:
:path: Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin
window_manager:
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
SPEC CHECKSUMS:
bonsoir_darwin: 29c7ccf356646118844721f36e1de4b61f6cbd0e
@@ -67,9 +77,11 @@ SPEC CHECKSUMS:
fvp: ed100b827d10aff53789fb9cb9dfdd85a87d037d
mdk: 622e3452cea55a982c0712ec9ce931d8ec718b22
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
window_manager: b729e31d38fb04905235df9ea896128991cad99e
PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009

View File

@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<false/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.network.server</key>

View File

@@ -3,9 +3,7 @@
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<false/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.network.client</key>

View File

@@ -70,6 +70,7 @@ dependencies:
jwt_decoder: ^2.0.1
k3vinb5_aniyomi_bridge:
path: ../k3vinb5_aniyomi_bridge
window_manager: ^0.5.1
# Dev dependencies
dev_dependencies:
flutter_test:

View File

@@ -9,7 +9,9 @@
#include <bonsoir_windows/bonsoir_windows_plugin_c_api.h>
#include <dynamic_color/dynamic_color_plugin_c_api.h>
#include <fvp/fvp_plugin_c_api.h>
#include <screen_retriever_windows/screen_retriever_windows_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h>
#include <window_manager/window_manager_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
BonsoirWindowsPluginCApiRegisterWithRegistrar(
@@ -18,6 +20,10 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
FvpPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FvpPluginCApi"));
ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
WindowManagerPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("WindowManagerPlugin"));
}

View File

@@ -6,7 +6,9 @@ list(APPEND FLUTTER_PLUGIN_LIST
bonsoir_windows
dynamic_color
fvp
screen_retriever_windows
url_launcher_windows
window_manager
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST