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 rules = []; //单例 static RequestRewrites? _instance; static Future get instance async { if (_instance == null) { var config = await _loadRequestRewriteConfig(); _instance = RequestRewrites.fromJson(config); } return _instance!; } //加载配置 RequestRewrites.fromJson(Map? map) { reload(map); } //重新加载配置 reload(Map? 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 reloadRequestRewrite() async { var config = await _loadRequestRewriteConfig(); reload(config); } /// 加载请求重写配置文件 static Future?> _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 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 indexes) { for (var i in indexes) { rules.removeAt(i); } } toJson() { return { 'enabled': enabled, 'rules': rules.map((e) => e.toJson()).toList(), }; } /// 保存请求重写配置文件 Future 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 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, }; } }