refactor: remove proxy API (#1596)

This commit is contained in:
Levi authored and GitHub committed 2026-10-21 22:48:17 +08:00
1 parent 47cafb7575
commit 4214765d39
98 files changed
+5958 -1225

No files matched your search

+13 -5
View File
@@ -208,11 +208,6 @@ Future<void> login(LoginReq loginReq) {
return _parse<void>(() => _request('api/web/login', method: 'POST', data: loginReq.toJson()), null);
}
Future<Response<String>> proxyRequest<T>(String uri, {dynamic data, Options? options}) async {
initDefault();
return _transport!.proxyRequest(uri, data: data, options: options);
}
String join(String path) {
initDefault();
return _transport!.join(path);
@@ -226,3 +221,16 @@ Future<dynamic> forward(
}) async {
return _request(path, method: method, data: data, queryParameters: queryParameters);
}
Future<void> triggerProtocolJob(String protocol, String name) => _parse<void>(
() => _request(
'api/v1/protocols/${Uri.encodeComponent(protocol)}/jobs/${Uri.encodeComponent(name)}/trigger',
method: 'POST',
),
null,
);
Future<List<String>> getMirrorCandidates(String provider, String url) => _parse(
() => _request('api/v1/mirrors/${Uri.encodeComponent(provider)}/candidates', method: 'POST', data: {'url': url}),
(json) => List<String>.from(json['urls'] as List),
);
+30 -45
View File
@@ -1,27 +1,18 @@
import 'dart:convert';
import 'package:dio/dio.dart';
import 'api.dart';
import 'model/store_extension.dart';
class GopeedSiteApi {
GopeedSiteApi._();
GopeedSiteApi({Dio? client})
: _client =
client ??
Dio(BaseOptions(connectTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(seconds: 10)));
static final instance = GopeedSiteApi._();
static const _host = 'gopeed.com';
static final instance = GopeedSiteApi();
final Dio _client;
final _storePages = <String, ({StoreExtensionPage page, DateTime expires})>{};
final _storeRequests = <String, Future<StoreExtensionPage>>{};
Future<List<dynamic>> getReleases({int perPage = 10}) async {
final json = await _getJson('/api/releases', queryParameters: {'per_page': perPage.clamp(1, 100).toString()});
if (json is! List<dynamic>) {
throw const FormatException('Invalid releases response');
}
return json;
}
Future<StoreExtensionPage> getExtensions({
int page = 1,
int limit = 20,
@@ -31,14 +22,14 @@ class GopeedSiteApi {
bool forceRefresh = false,
}) async {
final params = {
'view': 'summary',
'page': page.toString(),
'limit': limit.clamp(1, 100).toString(),
'sort': sort.name,
'order': order.name,
'view': 'summary',
if (query != null && query.trim().isNotEmpty) 'q': query.trim(),
};
final key = Uri.https(_host, '/api/extensions', params).toString();
final key = Uri(queryParameters: params).toString();
final now = DateTime.now();
_storePages.removeWhere((_, entry) => !now.isBefore(entry.expires));
final cached = _storePages[key];
@@ -58,40 +49,34 @@ class GopeedSiteApi {
}
Future<StoreExtensionPage> _fetchStorePage(Map<String, String> params) async {
final json = await _getJson('/api/extensions', queryParameters: params);
return StoreExtensionPage.fromJson(json as Map<String, dynamic>);
final response = await _client.get<Map<String, dynamic>>(
'https://gopeed.com/api/extensions',
queryParameters: params,
);
return StoreExtensionPage.fromJson(response.data!);
}
Future<StoreExtension> getExtension(String id, {String? version}) async {
final json = await _getJsonUri(
Uri(
scheme: 'https',
host: _host,
pathSegments: ['api', 'extensions', id],
queryParameters: {if (version != null && version.isNotEmpty) 'version': version},
),
final uri = Uri(
scheme: 'https',
host: 'gopeed.com',
pathSegments: ['api', 'extensions', id],
queryParameters: {'version': ?version},
);
return StoreExtension.fromJson(json as Map<String, dynamic>);
final response = await _client.get<Map<String, dynamic>>(uri.toString());
return StoreExtension.fromJson(response.data!);
}
Future<dynamic> getReleases() async {
final response = await _client.get<dynamic>(
'https://gopeed.com/api/releases',
queryParameters: {'per_page': 10},
options: Options(followRedirects: false),
);
return response.data;
}
Future<void> reportExtensionInstall(String id) async {
final uri = Uri.https(_host, '/api/extensions/install');
await proxyRequest(
uri.toString(),
data: {'id': id},
options: Options(method: 'POST', contentType: Headers.jsonContentType),
);
}
Future<dynamic> _getJson(String path, {Map<String, String>? queryParameters}) {
return _getJsonUri(Uri.https(_host, path, queryParameters));
}
Future<dynamic> _getJsonUri(Uri uri) async {
final Response<String> response = await proxyRequest(uri.toString());
if (response.data == null || response.data!.isEmpty) {
throw Exception('Empty response from $uri');
}
return jsonDecode(response.data!);
await _client.post<void>('https://gopeed.com/api/extensions/install', data: {'id': id});
}
}
+43 -26
View File
@@ -8,6 +8,7 @@ class DownloaderConfig {
int maxRunning;
ProtocolConfig protocolConfig = ProtocolConfig();
ExtraConfig extra = ExtraConfig();
GithubMirrorConfig githubMirror = GithubMirrorConfig();
ProxyConfig proxy = ProxyConfig();
WebhookConfig webhook = WebhookConfig();
ScriptConfig script = ScriptConfig();
@@ -98,10 +99,43 @@ class HttpConfig {
Map<String, dynamic> toJson() => _$HttpConfigToJson(this);
}
DateTime? _trackerUpdateTimeFromJson(String? value) =>
value == null || value.startsWith('0001-') ? null : DateTime.parse(value);
@JsonSerializable()
class TrackerSubscriptionStatus {
final bool success;
final int trackerCount;
final DateTime lastFetchTime;
TrackerSubscriptionStatus({required this.success, required this.trackerCount, required this.lastFetchTime});
factory TrackerSubscriptionStatus.fromJson(Map<String, dynamic> json) => _$TrackerSubscriptionStatusFromJson(json);
Map<String, dynamic> toJson() => _$TrackerSubscriptionStatusToJson(this);
}
@JsonSerializable(explicitToJson: true)
class BtState {
Map<String, List<String>> trackerSources;
Map<String, TrackerSubscriptionStatus> trackerSubscriptionStatuses;
@JsonKey(fromJson: _trackerUpdateTimeFromJson)
DateTime? lastTrackerUpdateTime;
BtState({this.trackerSources = const {}, this.trackerSubscriptionStatuses = const {}, this.lastTrackerUpdateTime});
factory BtState.fromJson(Map<String, dynamic>? json) => json == null ? BtState() : _$BtStateFromJson(json);
Map<String, dynamic> toJson() => _$BtStateToJson(this);
}
@JsonSerializable(explicitToJson: true)
class BtConfig {
BtState state = BtState();
List<String> trackerSubscribeUrls;
bool autoUpdateTrackers;
List<String> customTrackers;
int listenPort;
List<String> trackers;
bool seedKeep;
double seedRatio;
int seedTime;
@@ -109,8 +143,10 @@ class BtConfig {
bool disablePex;
BtConfig({
this.trackerSubscribeUrls = const [],
this.autoUpdateTrackers = true,
this.customTrackers = const [],
this.listenPort = 0,
this.trackers = const [],
this.seedKeep = false,
this.seedRatio = 0,
this.seedTime = 0,
@@ -158,9 +194,6 @@ class ExtraConfig {
String analyticsClientId;
List<DownloadCategory> downloadCategories;
ExtraConfigBt bt = ExtraConfigBt();
ExtraConfigGithubMirror githubMirror = ExtraConfigGithubMirror();
ExtraConfig({
this.themeMode = '',
this.themeColor = 'green',
@@ -271,22 +304,6 @@ class ProxyConfig {
Map<String, dynamic> toJson() => _$ProxyConfigToJson(this);
}
@JsonSerializable()
class ExtraConfigBt {
List<String> trackerSubscribeUrls = [];
List<String> subscribeTrackers = [];
bool autoUpdateTrackers = true;
DateTime? lastTrackerUpdateTime;
List<String> customTrackers = [];
ExtraConfigBt();
factory ExtraConfigBt.fromJson(Map<String, dynamic> json) => _$ExtraConfigBtFromJson(json);
Map<String, dynamic> toJson() => _$ExtraConfigBtToJson(this);
}
enum GithubMirrorType { jsdelivr, ghProxy }
@JsonSerializable()
@@ -304,16 +321,16 @@ class GithubMirror {
}
@JsonSerializable(explicitToJson: true)
class ExtraConfigGithubMirror {
class GithubMirrorConfig {
bool enabled;
List<GithubMirror> mirrors;
ExtraConfigGithubMirror({this.enabled = true, this.mirrors = const []});
GithubMirrorConfig({this.enabled = true, this.mirrors = const []});
factory ExtraConfigGithubMirror.fromJson(Map<String, dynamic>? json) =>
json == null ? ExtraConfigGithubMirror() : _$ExtraConfigGithubMirrorFromJson(json);
factory GithubMirrorConfig.fromJson(Map<String, dynamic>? json) =>
json == null ? GithubMirrorConfig() : _$GithubMirrorConfigFromJson(json);
Map<String, dynamic> toJson() => _$ExtraConfigGithubMirrorToJson(this);
Map<String, dynamic> toJson() => _$GithubMirrorConfigToJson(this);
}
@JsonSerializable()
@@ -15,6 +15,7 @@ DownloaderConfig _$DownloaderConfigFromJson(Map<String, dynamic> json) =>
)
..protocolConfig = ProtocolConfig.fromJson(json['protocolConfig'] as Map<String, dynamic>?)
..extra = ExtraConfig.fromJson(json['extra'] as Map<String, dynamic>?)
..githubMirror = GithubMirrorConfig.fromJson(json['githubMirror'] as Map<String, dynamic>?)
..proxy = ProxyConfig.fromJson(json['proxy'] as Map<String, dynamic>)
..webhook = WebhookConfig.fromJson(json['webhook'] as Map<String, dynamic>?)
..script = ScriptConfig.fromJson(json['script'] as Map<String, dynamic>?)
@@ -27,6 +28,7 @@ Map<String, dynamic> _$DownloaderConfigToJson(DownloaderConfig instance) => <Str
'maxRunning': instance.maxRunning,
'protocolConfig': instance.protocolConfig.toJson(),
'extra': instance.extra.toJson(),
'githubMirror': instance.githubMirror.toJson(),
'proxy': instance.proxy.toJson(),
'webhook': instance.webhook.toJson(),
'script': instance.script.toJson(),
@@ -92,19 +94,56 @@ Map<String, dynamic> _$HttpConfigToJson(HttpConfig instance) => <String, dynamic
'useServerCtime': instance.useServerCtime,
};
TrackerSubscriptionStatus _$TrackerSubscriptionStatusFromJson(Map<String, dynamic> json) => TrackerSubscriptionStatus(
success: json['success'] as bool,
trackerCount: (json['trackerCount'] as num).toInt(),
lastFetchTime: DateTime.parse(json['lastFetchTime'] as String),
);
Map<String, dynamic> _$TrackerSubscriptionStatusToJson(TrackerSubscriptionStatus instance) => <String, dynamic>{
'success': instance.success,
'trackerCount': instance.trackerCount,
'lastFetchTime': instance.lastFetchTime.toIso8601String(),
};
BtState _$BtStateFromJson(Map<String, dynamic> json) => BtState(
trackerSources:
(json['trackerSources'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, (e as List<dynamic>).map((e) => e as String).toList()),
) ??
const {},
trackerSubscriptionStatuses:
(json['trackerSubscriptionStatuses'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, TrackerSubscriptionStatus.fromJson(e as Map<String, dynamic>)),
) ??
const {},
lastTrackerUpdateTime: _trackerUpdateTimeFromJson(json['lastTrackerUpdateTime'] as String?),
);
Map<String, dynamic> _$BtStateToJson(BtState instance) => <String, dynamic>{
'trackerSources': instance.trackerSources,
'trackerSubscriptionStatuses': instance.trackerSubscriptionStatuses.map((k, e) => MapEntry(k, e.toJson())),
'lastTrackerUpdateTime': ?instance.lastTrackerUpdateTime?.toIso8601String(),
};
BtConfig _$BtConfigFromJson(Map<String, dynamic> json) => BtConfig(
trackerSubscribeUrls: (json['trackerSubscribeUrls'] as List<dynamic>?)?.map((e) => e as String).toList() ?? const [],
autoUpdateTrackers: json['autoUpdateTrackers'] as bool? ?? true,
customTrackers: (json['customTrackers'] as List<dynamic>?)?.map((e) => e as String).toList() ?? const [],
listenPort: (json['listenPort'] as num?)?.toInt() ?? 0,
trackers: (json['trackers'] as List<dynamic>?)?.map((e) => e as String).toList() ?? const [],
seedKeep: json['seedKeep'] as bool? ?? false,
seedRatio: (json['seedRatio'] as num?)?.toDouble() ?? 0,
seedTime: (json['seedTime'] as num?)?.toInt() ?? 0,
disableDht: json['disableDht'] as bool? ?? false,
disablePex: json['disablePex'] as bool? ?? false,
);
)..state = BtState.fromJson(json['state'] as Map<String, dynamic>?);
Map<String, dynamic> _$BtConfigToJson(BtConfig instance) => <String, dynamic>{
'state': instance.state.toJson(),
'trackerSubscribeUrls': instance.trackerSubscribeUrls,
'autoUpdateTrackers': instance.autoUpdateTrackers,
'customTrackers': instance.customTrackers,
'listenPort': instance.listenPort,
'trackers': instance.trackers,
'seedKeep': instance.seedKeep,
'seedRatio': instance.seedRatio,
'seedTime': instance.seedTime,
@@ -128,37 +167,31 @@ Map<String, dynamic> _$Ed2kConfigToJson(Ed2kConfig instance) => <String, dynamic
'nodesDat': instance.nodesDat,
};
ExtraConfig _$ExtraConfigFromJson(Map<String, dynamic> json) =>
ExtraConfig(
themeMode: json['themeMode'] as String? ?? '',
themeColor: json['themeColor'] as String? ?? 'green',
locale: json['locale'] as String? ?? '',
lastDeleteTaskKeep: json['lastDeleteTaskKeep'] as bool? ?? false,
defaultDirectDownload: json['defaultDirectDownload'] as bool? ?? false,
defaultBtClient: json['defaultBtClient'] as bool? ?? true,
notifyWhenNewVersion: json['notifyWhenNewVersion'] as bool? ?? true,
desktopNotification: json['desktopNotification'] as bool? ?? true,
backgroundLocationKeepAlive: json['backgroundLocationKeepAlive'] as bool? ?? false,
backgroundContinuedProcessing:
json['backgroundContinuedProcessing']
as bool? ??
false,
windowState: json['windowState'] == null
? null
: WindowStateConfig.fromJson(json['windowState'] as Map<String, dynamic>?),
bookmarks: (json['bookmarks'] as Map<String, dynamic>?)?.map((k, e) => MapEntry(k, e as String)) ?? const {},
createHistory: (json['createHistory'] as List<dynamic>?)?.map((e) => e as String).toList() ?? const [],
runAsMenubarApp: json['runAsMenubarApp'] as bool? ?? false,
analyticsEnabled: json['analyticsEnabled'] as bool? ?? true,
analyticsClientId: json['analyticsClientId'] as String? ?? '',
downloadCategories:
(json['downloadCategories'] as List<dynamic>?)
?.map((e) => DownloadCategory.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
)
..bt = ExtraConfigBt.fromJson(json['bt'] as Map<String, dynamic>)
..githubMirror = ExtraConfigGithubMirror.fromJson(json['githubMirror'] as Map<String, dynamic>?);
ExtraConfig _$ExtraConfigFromJson(Map<String, dynamic> json) => ExtraConfig(
themeMode: json['themeMode'] as String? ?? '',
themeColor: json['themeColor'] as String? ?? 'green',
locale: json['locale'] as String? ?? '',
lastDeleteTaskKeep: json['lastDeleteTaskKeep'] as bool? ?? false,
defaultDirectDownload: json['defaultDirectDownload'] as bool? ?? false,
defaultBtClient: json['defaultBtClient'] as bool? ?? true,
notifyWhenNewVersion: json['notifyWhenNewVersion'] as bool? ?? true,
desktopNotification: json['desktopNotification'] as bool? ?? true,
backgroundLocationKeepAlive: json['backgroundLocationKeepAlive'] as bool? ?? false,
backgroundContinuedProcessing: json['backgroundContinuedProcessing'] as bool? ?? false,
windowState: json['windowState'] == null
? null
: WindowStateConfig.fromJson(json['windowState'] as Map<String, dynamic>?),
bookmarks: (json['bookmarks'] as Map<String, dynamic>?)?.map((k, e) => MapEntry(k, e as String)) ?? const {},
createHistory: (json['createHistory'] as List<dynamic>?)?.map((e) => e as String).toList() ?? const [],
runAsMenubarApp: json['runAsMenubarApp'] as bool? ?? false,
analyticsEnabled: json['analyticsEnabled'] as bool? ?? true,
analyticsClientId: json['analyticsClientId'] as String? ?? '',
downloadCategories:
(json['downloadCategories'] as List<dynamic>?)
?.map((e) => DownloadCategory.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
);
Map<String, dynamic> _$ExtraConfigToJson(ExtraConfig instance) => <String, dynamic>{
'themeMode': instance.themeMode,
@@ -170,8 +203,7 @@ Map<String, dynamic> _$ExtraConfigToJson(ExtraConfig instance) => <String, dynam
'notifyWhenNewVersion': instance.notifyWhenNewVersion,
'desktopNotification': instance.desktopNotification,
'backgroundLocationKeepAlive': instance.backgroundLocationKeepAlive,
'backgroundContinuedProcessing':
instance.backgroundContinuedProcessing,
'backgroundContinuedProcessing': instance.backgroundContinuedProcessing,
'windowState': instance.windowState.toJson(),
'bookmarks': instance.bookmarks,
'createHistory': instance.createHistory,
@@ -179,8 +211,6 @@ Map<String, dynamic> _$ExtraConfigToJson(ExtraConfig instance) => <String, dynam
'analyticsEnabled': instance.analyticsEnabled,
'analyticsClientId': instance.analyticsClientId,
'downloadCategories': instance.downloadCategories.map((e) => e.toJson()).toList(),
'bt': instance.bt.toJson(),
'githubMirror': instance.githubMirror.toJson(),
};
WindowStateConfig _$WindowStateConfigFromJson(Map<String, dynamic> json) => WindowStateConfig(
@@ -249,23 +279,6 @@ Map<String, dynamic> _$ProxyConfigToJson(ProxyConfig instance) => <String, dynam
'pwd': instance.pwd,
};
ExtraConfigBt _$ExtraConfigBtFromJson(Map<String, dynamic> json) => ExtraConfigBt()
..trackerSubscribeUrls = (json['trackerSubscribeUrls'] as List<dynamic>).map((e) => e as String).toList()
..subscribeTrackers = (json['subscribeTrackers'] as List<dynamic>).map((e) => e as String).toList()
..autoUpdateTrackers = json['autoUpdateTrackers'] as bool
..lastTrackerUpdateTime = json['lastTrackerUpdateTime'] == null
? null
: DateTime.parse(json['lastTrackerUpdateTime'] as String)
..customTrackers = (json['customTrackers'] as List<dynamic>).map((e) => e as String).toList();
Map<String, dynamic> _$ExtraConfigBtToJson(ExtraConfigBt instance) => <String, dynamic>{
'trackerSubscribeUrls': instance.trackerSubscribeUrls,
'subscribeTrackers': instance.subscribeTrackers,
'autoUpdateTrackers': instance.autoUpdateTrackers,
'lastTrackerUpdateTime': ?instance.lastTrackerUpdateTime?.toIso8601String(),
'customTrackers': instance.customTrackers,
};
GithubMirror _$GithubMirrorFromJson(Map<String, dynamic> json) => GithubMirror(
type: $enumDecode(_$GithubMirrorTypeEnumMap, json['type']),
url: json['url'] as String,
@@ -282,14 +295,14 @@ Map<String, dynamic> _$GithubMirrorToJson(GithubMirror instance) => <String, dyn
const _$GithubMirrorTypeEnumMap = {GithubMirrorType.jsdelivr: 'jsdelivr', GithubMirrorType.ghProxy: 'ghProxy'};
ExtraConfigGithubMirror _$ExtraConfigGithubMirrorFromJson(Map<String, dynamic> json) => ExtraConfigGithubMirror(
GithubMirrorConfig _$GithubMirrorConfigFromJson(Map<String, dynamic> json) => GithubMirrorConfig(
enabled: json['enabled'] as bool? ?? true,
mirrors:
(json['mirrors'] as List<dynamic>?)?.map((e) => GithubMirror.fromJson(e as Map<String, dynamic>)).toList() ??
const [],
);
Map<String, dynamic> _$ExtraConfigGithubMirrorToJson(ExtraConfigGithubMirror instance) => <String, dynamic>{
Map<String, dynamic> _$GithubMirrorConfigToJson(GithubMirrorConfig instance) => <String, dynamic>{
'enabled': instance.enabled,
'mirrors': instance.mirrors.map((e) => e.toJson()).toList(),
};