初始化提交
This commit is contained in:
+28
@@ -0,0 +1,28 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'kr_outbound_item.dart';
|
||||
|
||||
/// 表示服务器分组的模型类
|
||||
class KRGroupOutboundList {
|
||||
final String tag; // 标签
|
||||
String icon = ""; // 图标
|
||||
final List<KROutboundItem> outboundList; // 出站项列表
|
||||
|
||||
/// 构造函数,初始化标签和出站项列表
|
||||
KRGroupOutboundList({
|
||||
required this.tag,
|
||||
required this.outboundList,
|
||||
});
|
||||
}
|
||||
|
||||
class KRCountryOutboundList {
|
||||
|
||||
final String country;
|
||||
final List<KROutboundItem> outboundList;
|
||||
//// 是否展开
|
||||
RxBool isExpand = false.obs;
|
||||
KRCountryOutboundList({
|
||||
required this.country,
|
||||
required this.outboundList,
|
||||
});
|
||||
}
|
||||
Executable
+207
@@ -0,0 +1,207 @@
|
||||
import 'dart:convert';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:kaer_with_panels/app/modules/kr_main/views/kr_main_view.dart';
|
||||
|
||||
import '../response/kr_node_list.dart';
|
||||
|
||||
/// 表示出站项的模型类
|
||||
class KROutboundItem {
|
||||
String id = ""; // 标签
|
||||
String tag = ""; // 标签
|
||||
String serverAddr = ""; // 服务器地址
|
||||
|
||||
/// 初始化配置
|
||||
Map<String, dynamic> config = {}; // 配置项
|
||||
|
||||
String city = ""; // 城市
|
||||
String country = ""; // 国家
|
||||
|
||||
double latitude = 0.0;
|
||||
double longitude = 0.0;
|
||||
String protocol = "";
|
||||
|
||||
/// 延迟
|
||||
RxInt urlTestDelay = 0.obs;
|
||||
|
||||
/// URL
|
||||
String url = "";
|
||||
|
||||
/// 服务器类型
|
||||
|
||||
/// 构造函数,接受 KrNodeListItem 对象并初始化 KROutboundItem
|
||||
KROutboundItem(KrNodeListItem nodeListItem) {
|
||||
id = nodeListItem.id.toString();
|
||||
protocol = nodeListItem.protocol;
|
||||
latitude = nodeListItem.latitude;
|
||||
longitude = nodeListItem.longitude;
|
||||
|
||||
tag = nodeListItem.name; // 设置标签
|
||||
serverAddr = nodeListItem.serverAddr; // 设置服务器地址
|
||||
// 将 config 字符串转换为 Map<String, dynamic>
|
||||
city = nodeListItem.city; // 设置城市
|
||||
country = nodeListItem.country; // 设置国家
|
||||
|
||||
final json = jsonDecode(nodeListItem.config);
|
||||
switch (nodeListItem.protocol) {
|
||||
case "vless":
|
||||
final securityConfig =
|
||||
json["security_config"] as Map<String, dynamic>? ?? {};
|
||||
|
||||
// 智能设置 server_name
|
||||
String serverName = securityConfig["sni"] ?? "";
|
||||
if (serverName.isEmpty) {
|
||||
serverName = nodeListItem.serverAddr;
|
||||
}
|
||||
|
||||
config = {
|
||||
"type": "vless",
|
||||
"tag": nodeListItem.name,
|
||||
"server": nodeListItem.serverAddr,
|
||||
"server_port": json["port"],
|
||||
"uuid": nodeListItem.uuid,
|
||||
if (json["flow"] != null && json["flow"] != "none")
|
||||
"flow": json["flow"],
|
||||
if (json["transport"] != null && json["transport"] != "tcp")
|
||||
"transport": _buildTransport(json),
|
||||
"tls": {
|
||||
"enabled": json["security"] == "tls",
|
||||
"server_name": serverName,
|
||||
"insecure": securityConfig["allow_insecure"] ?? false,
|
||||
"utls": {
|
||||
"enabled": true,
|
||||
"fingerprint": securityConfig["fingerprint"] ?? "chrome"
|
||||
}
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "vmess":
|
||||
final securityConfig =
|
||||
json["security_config"] as Map<String, dynamic>? ?? {};
|
||||
|
||||
// 智能设置 server_name
|
||||
String serverName = securityConfig["sni"] ?? "";
|
||||
if (serverName.isEmpty) {
|
||||
serverName = nodeListItem.serverAddr;
|
||||
}
|
||||
|
||||
config = {
|
||||
"type": "vmess",
|
||||
"tag": nodeListItem.name,
|
||||
"server": nodeListItem.serverAddr,
|
||||
"server_port": json["port"],
|
||||
"uuid": nodeListItem.uuid,
|
||||
"alter_id": 0,
|
||||
"security": "auto",
|
||||
if (json["transport"] != null && json["transport"] != "tcp")
|
||||
"transport": _buildTransport(json),
|
||||
"tls": {
|
||||
"enabled": json["security"] == "tls",
|
||||
"server_name": serverName,
|
||||
"insecure": securityConfig["allow_insecure"] ?? false,
|
||||
"utls": {"enabled": true, "fingerprint": "chrome"}
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "shadowsocks":
|
||||
config = {
|
||||
"type": "shadowsocks",
|
||||
"tag": nodeListItem.name,
|
||||
"server": nodeListItem.serverAddr,
|
||||
"server_port": json["port"],
|
||||
"method": json["method"],
|
||||
"password": nodeListItem.uuid
|
||||
};
|
||||
break;
|
||||
case "hysteria2":
|
||||
final securityConfig =
|
||||
json["security_config"] as Map<String, dynamic>? ?? {};
|
||||
config = {
|
||||
"type": "hysteria2",
|
||||
"tag": nodeListItem.name,
|
||||
"server": nodeListItem.serverAddr,
|
||||
"server_port": json["port"],
|
||||
"password": nodeListItem.uuid,
|
||||
"up_mbps": 100,
|
||||
"down_mbps": 100,
|
||||
"obfs": {
|
||||
"type": "salamander",
|
||||
"password": json["obfs_password"] ?? nodeListItem.uuid
|
||||
},
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": securityConfig["sni"] ?? "",
|
||||
"insecure": securityConfig["allow_insecure"] ?? false,
|
||||
"alpn": ["h3"]
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "trojan":
|
||||
final securityConfig =
|
||||
json["security_config"] as Map<String, dynamic>? ?? {};
|
||||
|
||||
// 智能设置 server_name
|
||||
String serverName = securityConfig["sni"] ?? "";
|
||||
if (serverName.isEmpty) {
|
||||
// 如果没有配置 SNI,使用服务器地址
|
||||
serverName = nodeListItem.serverAddr;
|
||||
}
|
||||
|
||||
config = {
|
||||
"type": "trojan",
|
||||
"tag": nodeListItem.name,
|
||||
"server": nodeListItem.serverAddr,
|
||||
"server_port": json["port"],
|
||||
"password": nodeListItem.uuid,
|
||||
"tls": {
|
||||
"enabled": json["security"] == "tls",
|
||||
"server_name": serverName,
|
||||
"insecure": securityConfig["allow_insecure"] ?? false,
|
||||
"utls": {"enabled": true, "fingerprint": "chrome"}
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查 relayNode 是否为 JSON 字符串并解析
|
||||
if (nodeListItem.relayNode.isNotEmpty && nodeListItem.relayMode != "none") {
|
||||
final relayNodeJson = jsonDecode(nodeListItem.relayNode);
|
||||
if (relayNodeJson is List && nodeListItem.relayMode != "none") {
|
||||
// 随机选择一个元素
|
||||
final randomNode = (relayNodeJson..shuffle()).first;
|
||||
config["server"] = randomNode["host"]; // 提取 host
|
||||
config["server_port"] = randomNode["port"]; // 提取 port
|
||||
}
|
||||
}
|
||||
// 解析配置
|
||||
}
|
||||
|
||||
/// 构建传输配置
|
||||
Map<String, dynamic> _buildTransport(Map<String, dynamic> json) {
|
||||
final transportType = json["transport"] as String?;
|
||||
final transportConfig =
|
||||
json["transport_config"] as Map<String, dynamic>? ?? {};
|
||||
|
||||
switch (transportType) {
|
||||
case "ws":
|
||||
return {
|
||||
"type": "ws",
|
||||
"path": transportConfig["path"] ?? "/",
|
||||
if (transportConfig["host"] != null)
|
||||
"headers": {"Host": transportConfig["host"]}
|
||||
};
|
||||
case "grpc":
|
||||
return {
|
||||
"type": "grpc",
|
||||
"service_name": transportConfig["service_name"] ?? ""
|
||||
};
|
||||
case "http":
|
||||
return {
|
||||
"type": "http",
|
||||
"host": [transportConfig["host"] ?? ""],
|
||||
"path": transportConfig["path"] ?? "/"
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
import '../response/kr_node_group_list.dart';
|
||||
import 'kr_group_outbound_list.dart';
|
||||
|
||||
import '../response/kr_node_list.dart';
|
||||
import 'kr_outbound_item.dart';
|
||||
|
||||
/// 表示出站项列表的模型类
|
||||
class KrOutboundsList {
|
||||
|
||||
|
||||
|
||||
/// 服务器分组
|
||||
final List<KRGroupOutboundList> groupOutboundList = []; // 存储服务器分组的列表
|
||||
|
||||
/// 国家分组,包含所有国家
|
||||
final List<KRCountryOutboundList> countryOutboundList = []; // 存储国家分组的列表
|
||||
|
||||
/// 全部列表
|
||||
final List<KROutboundItem> allList = []; // 存储国家分组的列表
|
||||
|
||||
// 配置json
|
||||
final List<Map<String,dynamic>> configJsonList = [];
|
||||
|
||||
/// 标签列表
|
||||
final Map<String,KROutboundItem> keyList = {}; // 存储国家分组的列表
|
||||
|
||||
|
||||
/// 处理出站项并将其分组
|
||||
/// [list] 是要处理的出站项列表
|
||||
void processOutboundItems(List<KrNodeListItem> list,List<KRNodeGroupListItem> groupList) {
|
||||
final Map<String, List<KROutboundItem>> tagGroups = {};
|
||||
final Map<String, List<KROutboundItem>> countryGroups = {};
|
||||
|
||||
// 用于追踪已使用的标签
|
||||
final Map<String, int> tagCounter = {};
|
||||
|
||||
for (var element in list) {
|
||||
// 生成唯一标签
|
||||
var baseName = element.name;
|
||||
if (tagCounter.containsKey(baseName)) {
|
||||
tagCounter[baseName] = tagCounter[baseName]! + 1;
|
||||
element.name = "${baseName}_${tagCounter[baseName]}";
|
||||
} else {
|
||||
tagCounter[baseName] = 0;
|
||||
}
|
||||
|
||||
final KROutboundItem item = KROutboundItem(element);
|
||||
allList.add(item);
|
||||
|
||||
// 根据标签分组出站项
|
||||
for (var tag in element.tags) {
|
||||
tagGroups.putIfAbsent(tag, () => []);
|
||||
tagGroups[tag]?.add(item);
|
||||
}
|
||||
|
||||
// 根据国家分组出站项
|
||||
countryGroups.putIfAbsent(element.country, () => []);
|
||||
countryGroups[element.country]?.add(item);
|
||||
|
||||
configJsonList.add(item.config);
|
||||
keyList[item.tag] = item;
|
||||
}
|
||||
|
||||
// 将标签分组转换为 KRGroupOutboundList 并添加到 groupOutboundList
|
||||
for (var tag in tagGroups.keys) {
|
||||
final item = KRGroupOutboundList(
|
||||
tag: tag, outboundList: tagGroups[tag]!);
|
||||
|
||||
for (var group in groupList) {
|
||||
if (item.tag == group.name) {
|
||||
item.icon = group.icon;
|
||||
break;
|
||||
}
|
||||
}
|
||||
groupOutboundList.add(item); // 添加标签分组到列表
|
||||
}
|
||||
|
||||
// 将国家分组转换为 KRCountryOutboundList 并添加到 countryOutboundList
|
||||
for (var country in countryGroups.keys) {
|
||||
countryOutboundList.add(KRCountryOutboundList(
|
||||
country: country,
|
||||
outboundList: countryGroups[country]!)); // 添加国家分组到列表
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user