Files
proxypin/lib/network/util/request_rewrite.dart
wanghongenpin ea3828edc6 请求重写
2023-12-01 18:54:12 +08:00

212 lines
5.2 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:network_proxy/network/util/file_read.dart';
import 'package:network_proxy/network/util/logger.dart';
/// @author wanghongen
/// 2023/7/26
/// 请求重写
class RequestRewrites {
bool enabled = true;
List<RequestRewriteRule> rules = [];
//单例
static RequestRewrites? _instance;
static Future<RequestRewrites> get instance async {
if (_instance == null) {
var config = await _loadRequestRewriteConfig();
_instance = RequestRewrites.fromJson(config);
}
return _instance!;
}
//加载配置
RequestRewrites.fromJson(Map<String, dynamic>? map) {
reload(map);
}
//重新加载配置
reload(Map<String, dynamic>? map) {
if (map == null) {
return;
}
enabled = map['enabled'] == true;
List? list = map['rules'];
rules.clear();
list?.forEach((element) {
try {
// body("重写消息体"), 兼容旧版本
if (element['type'] == '重写消息体' && element['requestBody']?.toString().isNotEmpty == true) {
element['type'] = RuleType.requestReplace.name;
rules.add(RequestRewriteRule.formJson(element));
} else if (element['type'] == '重写消息体' && element['responseBody']?.toString().isNotEmpty == true) {
element['type'] = RuleType.responseReplace.name;
rules.add(RequestRewriteRule.formJson(element));
} else {
rules.add(RequestRewriteRule.formJson(element));
}
} catch (e) {
logger.e('加载请求重写配置失败 $element', error: e);
}
});
}
///重新加载请求重写
Future<void> reloadRequestRewrite() async {
var config = await _loadRequestRewriteConfig();
reload(config);
}
/// 加载请求重写配置文件
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;
}
/// 查找重写规则
RequestRewriteRule? findRequestRewrite(String? url, RuleType type) {
if (!enabled || url == null) {
return null;
}
for (var rule in rules) {
if (rule.enabled && rule.urlReg.hasMatch(url) && type == rule.type) {
return rule;
}
}
return null;
}
/// 查找重写规则
String? findResponseReplaceWith(String? url) {
if (!enabled || url == null) {
return null;
}
for (var rule in rules) {
if (rule.enabled && rule.urlReg.hasMatch(url) && rule.type == RuleType.responseReplace) {
return rule.responseBody;
}
}
return null;
}
///添加规则
void addRule(RequestRewriteRule rule) {
rules.removeWhere((it) => it.url == rule.url);
rules.add(rule);
}
removeIndex(List<int> indexes) {
for (var i in indexes) {
rules.removeAt(i);
}
}
toJson() {
return {
'enabled': enabled,
'rules': rules.map((e) => e.toJson()).toList(),
};
}
/// 保存请求重写配置文件
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);
}
}
enum RuleType {
// body("重写消息体"), //OLD VERSION
requestReplace("替换请求"),
responseReplace("替换响应"),
// header("重写Header"),
redirect("重定向");
//名称
final String label;
const RuleType(this.label);
static RuleType fromName(String name) {
return values.firstWhere((element) => element.name == name || element.label == name);
}
}
class RequestRewriteRule {
bool enabled = false;
RuleType type;
String? name;
String url;
//消息体
String? queryParam;
String? requestBody;
String? responseBody;
//重定向
String? redirectUrl;
RegExp urlReg;
RequestRewriteRule(this.enabled,
{this.name,
required this.url,
required this.type,
this.queryParam,
this.requestBody,
this.responseBody,
this.redirectUrl})
: urlReg = RegExp(url.replaceAll("*", ".*"));
/// 从json中创建
factory RequestRewriteRule.formJson(Map<dynamic, dynamic> map) {
return RequestRewriteRule(map['enabled'] == true,
name: map['name'],
url: map['url'] ?? map['domain'] + map['path'],
type: RuleType.fromName(map['type']),
queryParam: map['queryParam'],
requestBody: map['requestBody'],
responseBody: map['responseBody'],
redirectUrl: map['redirectUrl']);
}
void updatePathReg() {
urlReg = RegExp(url.replaceAll("*", ".*"));
}
toJson() {
return {
'name': name,
'enabled': enabled,
'url': url,
'type': type.name,
'queryParam': queryParam,
'requestBody': requestBody,
'responseBody': responseBody,
'redirectUrl': redirectUrl,
};
}
}