Files
proxypin/lib/network/components/manager/request_rewrite_manager.dart
2025-12-07 01:08:49 +08:00

248 lines
7.2 KiB
Dart

/*
* Copyright 2023 Hongen Wang All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'dart:convert';
import 'dart:io';
import 'package:proxypin/network/components/manager/rewrite_rule.dart';
import 'package:proxypin/network/http/http.dart';
import 'package:proxypin/network/util/file_read.dart';
import 'package:proxypin/network/util/logger.dart';
import 'package:proxypin/network/util/random.dart';
/// @author wanghongen
/// 2023/7/26
/// 请求重写
class RequestRewriteManager {
static String separator = Platform.pathSeparator;
//重写规则
final Map<RequestRewriteRule, List<RewriteItem>> rewriteItemsCache = {};
//单例
static RequestRewriteManager? _instance;
RequestRewriteManager._();
static Future<RequestRewriteManager> get instance async {
if (_instance == null) {
var config = await _loadRequestRewriteConfig();
_instance = RequestRewriteManager._();
await _instance!.reload(config);
}
return _instance!;
}
bool enabled = true;
List<RequestRewriteRule> rules = [];
//重新加载配置
Future<void> reload(Map<String, dynamic>? map) async {
rewriteItemsCache.clear();
if (map == null) {
return;
}
enabled = map['enabled'] == true;
List list = map['rules'] ?? [];
rules.clear();
for (var element in list) {
try {
rules.add(RequestRewriteRule.formJson(element));
} catch (e) {
logger.e('加载请求重写配置失败 $element', error: e);
}
}
}
///重新加载请求重写
Future<void> reloadRequestRewrite() async {
var config = await _loadRequestRewriteConfig();
reload(config);
}
///同步配置
Future<void> syncConfig(Map<String, dynamic>? config) async {
if (config == null) {
return;
}
rewriteItemsCache.clear();
enabled = config['enabled'] == true;
List list = config['rules'] ?? [];
rules.clear();
for (var element in list) {
try {
var rule = RequestRewriteRule.formJson(element);
List list = element['items'] as List;
List<RewriteItem> items = list.map((e) => RewriteItem.fromJson(e)).toList();
await addRule(rule, items);
} catch (e) {
logger.e('加载请求重写配置失败 $element', error: e);
}
}
flushRequestRewriteConfig();
}
/// 加载请求重写配置文件
static Future<Map<String, dynamic>?> _loadRequestRewriteConfig() async {
var home = await FileRead.homeDir();
var file = File('${home.path}${Platform.pathSeparator}request_rewrite.json');
var exits = await file.exists();
if (!exits) {
return null;
}
Map<String, dynamic> config = jsonDecode(await file.readAsString());
logger.i('加载请求重写配置文件 [$file]');
return config;
}
/// 保存请求重写配置文件
Future<void> flushRequestRewriteConfig() async {
var home = await FileRead.homeDir();
var file = File('${home.path}${Platform.pathSeparator}request_rewrite.json');
bool exists = await file.exists();
if (!exists) {
await file.create(recursive: true);
}
var json = jsonEncode(toJson());
logger.i('刷新请求重写配置文件 ${file.path}');
await file.writeAsString(json);
}
///添加规则
Future<void> addRule(RequestRewriteRule rule, List<RewriteItem> items) async {
final home = await FileRead.homeDir();
String rewritePath = "${separator}rewrite$separator${RandomUtil.randomString(16)}.json";
var file = File(home.path + rewritePath);
await file.create(recursive: true);
file.writeAsString(jsonEncode(items.map((e) => e.toJson()).toList()));
rule.rewritePath = rewritePath;
rules.add(rule);
rewriteItemsCache[rule] = items;
}
///更新规则
Future<void> updateRule(int index, RequestRewriteRule rule, List<RewriteItem>? items) async {
rewriteItemsCache.remove(rules[index]);
final home = await FileRead.homeDir();
rule.updatePathReg();
rules[index] = rule;
if (items == null) {
return;
}
bool isExist = rule.rewritePath != null;
if (rule.rewritePath == null) {
String rewritePath = "${separator}rewrite$separator${RandomUtil.randomString(16)}.json";
rule.rewritePath = rewritePath;
}
File file = File(home.path + rule.rewritePath!);
if (!isExist) {
await file.create(recursive: true);
}
await file.writeAsString(jsonEncode(items.map((e) => e.toJson()).toList()));
rewriteItemsCache[rule] = items;
}
Future<void> removeIndex(List<int> indexes) async {
for (var i in indexes) {
var rule = rules.removeAt(i);
rewriteItemsCache.remove(rule); //删除缓存
if (rule.rewritePath != null) {
File home = await FileRead.homeDir();
try {
await File(home.path + rule.rewritePath!).delete();
} catch (e) {
logger.e('删除请求重写配置文件失败 ${home.path + rule.rewritePath!}', error: e);
}
rule.rewritePath = null;
}
}
}
RequestRewriteRule getRequestRewriteRule(HttpRequest request, RuleType type) {
var url = request.domainPath;
for (var rule in rules) {
if (rule.match(url, type: type, method: request.method) && rule.type == type) {
return rule;
}
}
return RequestRewriteRule(type: type, url: url);
}
RequestRewriteRule? getRewriteRule(String? url, List<RuleType> types) {
if (url == null || !enabled) {
return null;
}
for (var rule in rules) {
if (rule.match(url) && types.contains(rule.type)) {
return rule;
}
}
return null;
}
/// 获取重写规则
Future<List<RewriteItem>?> getRewriteItems(RequestRewriteRule rule) async {
if (rewriteItemsCache.containsKey(rule)) {
return rewriteItemsCache[rule]!;
}
if (rule.rewritePath == null) {
return null;
}
final home = await FileRead.homeDir();
List<RewriteItem> items = [];
try {
var json = await File(home.path + rule.rewritePath!).readAsString();
List? list = jsonDecode(json);
list?.forEach((element) => items.add(RewriteItem.fromJson(element)));
rewriteItemsCache[rule] = items;
} catch (e) {
logger.e('加载请求重写配置文件失败 ${home.path + rule.rewritePath!}', error: e);
}
return items;
}
Map<String, Object> toJson() {
return {
'enabled': enabled,
'rules': rules.map((e) => e.toJson()).toList(),
};
}
Future<Map<String, dynamic>> toFullJson() async {
var rulesJson = [];
for (var rule in rules) {
var json = rule.toJson();
json['items'] = await getRewriteItems(rule);
rulesJson.add(json);
}
return {
'enabled': enabled,
'rules': rulesJson,
};
}
}