import 'dart:io'; import 'dart:developer' as developer; import 'package:path_provider/path_provider.dart'; import 'package:dio/dio.dart'; import 'auth_service.dart'; import '../models/peer_info.dart'; /// ZeroTier服务状态详情 class ZerotierStatus { final String address; final String version; final bool online; final int primaryPort; final List listeningOn; ZerotierStatus({ required this.address, required this.version, required this.online, required this.primaryPort, required this.listeningOn, }); /// 从JSON创建状态对象 factory ZerotierStatus.fromJson(Map json) { // 提取监听地址列表 List listeningAddresses = []; if (json['config'] != null && json['config']['settings'] != null && json['config']['settings']['listeningOn'] != null) { listeningAddresses = List.from(json['config']['settings']['listeningOn']); } // 提取主端口 int port = 0; if (json['config'] != null && json['config']['settings'] != null && json['config']['settings']['primaryPort'] != null) { port = json['config']['settings']['primaryPort']; } return ZerotierStatus( address: json['address'] ?? '', version: json['version'] ?? '', online: json['online'] ?? false, primaryPort: port, listeningOn: listeningAddresses, ); } } /// ZeroTier服务,提供所有ZeroTier相关功能 class ZerotierService { final AuthService _authService = AuthService(); // 内部成员变量,存储最后一次加载的数据 List _networkList = []; List _peersList = []; ZerotierStatus? _statusInfo; // 表示ZeroTier服务是否正在运行 bool runningStatus = false; // 允许外部访问最新数据的getter方法 List get networkList => _networkList; List get peersList => _peersList; ZerotierStatus? get statusInfo => _statusInfo; /// 向ZeroTier服务发送命令 Future zerotierCommand(String command) async { try { final path = (await getApplicationDocumentsDirectory()).path; final file = File('$path/run/pipe'); if (!await file.exists()) { developer.log('未找到ZeroTier命令管道: ${file.path}'); runningStatus = false; // 特定错误,表示Magisk模块未运行 throw const FileSystemException('MODULE_NOT_RUNNING'); } await file.writeAsString(command); developer.log('已发送ZeroTier命令: $command'); return true; } on FileSystemException catch (e) { if (e.message == 'MODULE_NOT_RUNNING') { developer.log('ZeroTier Magisk模块未运行'); } else { developer.log('未找到ZeroTier命令管道,服务可能未运行'); } runningStatus = false; return false; } catch (e) { developer.log('发送ZeroTier命令失败', error: e.toString()); return false; } } /// 加载网络列表 Future?> loadNetwork() async { developer.log('开始加载网络列表'); try { final client = await _authService.client; // 使用相对路径,基础URL已在客户端中配置 final resp = await client.get('/network'); if (resp.statusCode != 200) { throw HttpException('加载网络列表失败: ${resp.statusCode}'); } final body = resp.data; _networkList = List.from(body.map((u) => u['id'])); developer.log('成功加载网络列表: ${_networkList.length} 个网络'); return _networkList; } on DioException catch (e) { if (e.type == DioExceptionType.connectionTimeout || e.type == DioExceptionType.connectionError) { developer.log('无法连接到ZeroTier服务:服务可能未运行'); } else { developer.log('加载网络列表失败', error: e.toString()); } _networkList = []; return null; } on SocketException { developer.log('无法连接到ZeroTier服务:服务可能未运行'); _networkList = []; return null; } catch (e) { developer.log('加载网络列表失败', error: e.toString()); _networkList = []; return null; } } /// 离开指定网络 Future leaveNetwork(String id) async { try { final client = await _authService.client; // 使用相对路径 final resp = await client.delete('/network/$id'); final success = resp.statusCode == 200; if (success) { developer.log('成功离开网络: $id'); } else { developer.log('离开网络失败: $id, 状态码: ${resp.statusCode}'); } return success; } on DioException catch (e) { if (e.type == DioExceptionType.connectionTimeout || e.type == DioExceptionType.connectionError) { developer.log('无法连接到ZeroTier服务:服务可能未运行'); // 更新运行状态 runningStatus = false; } else { developer.log('离开网络错误', error: e.toString()); } return false; } on SocketException { developer.log('无法连接到ZeroTier服务:服务可能未运行'); // 更新运行状态 runningStatus = false; return false; } catch (e) { developer.log('离开网络错误', error: e.toString()); return false; } } /// 加入指定网络 Future joinNetwork(String id) async { try { if (id.isEmpty) { developer.log('无法加入空网络ID'); return false; } final client = await _authService.client; // 使用相对路径 final resp = await client.put('/network/$id'); final success = resp.statusCode == 200; if (success) { developer.log('成功加入网络: $id'); } else { developer.log('加入网络失败: $id, 状态码: ${resp.statusCode}'); } return success; } on DioException catch (e) { if (e.type == DioExceptionType.connectionTimeout || e.type == DioExceptionType.connectionError) { developer.log('无法连接到ZeroTier服务:服务可能未运行'); // 更新运行状态 runningStatus = false; } else { developer.log('加入网络错误', error: e.toString()); } return false; } on SocketException { developer.log('无法连接到ZeroTier服务:服务可能未运行'); // 更新运行状态 runningStatus = false; return false; } catch (e) { developer.log('加入网络错误', error: e.toString()); return false; } } /// 加载 Peer 列表 Future?> loadPeers() async { developer.log('开始加载 Peer 列表'); try { final client = await _authService.client; final resp = await client.get('/peer'); if (resp.statusCode != 200) { throw HttpException('加载 Peer 列表失败: ${resp.statusCode}'); } final List rawPeers = resp.data; _peersList = rawPeers .map((p) => PeerInfo.fromJson(p as Map)) .toList(); // Sort the list (PLANETs first, then LEAFs by address) _peersList.sort(); developer.log('成功加载 Peer 列表: ${_peersList.length} 个 Peers'); return _peersList; } on DioException catch (e) { if (e.type == DioExceptionType.connectionTimeout || e.type == DioExceptionType.connectionError) { developer.log('无法连接到ZeroTier服务:服务可能未运行'); } else { developer.log('加载 Peer 列表 Dio 错误', error: e.toString(), stackTrace: e.stackTrace); } _peersList = []; return null; } on SocketException { developer.log('无法连接到ZeroTier服务:服务可能未运行'); _peersList = []; return null; } catch (e, s) { developer.log('加载 Peer 列表失败', error: e.toString(), stackTrace: s); _peersList = []; return null; } } /// 加载ZeroTier服务状态 Future loadStatus() async { developer.log('检查ZeroTier服务状态'); Map? statusData; try { // 尝试获取状态信息 final client = await _authService.client; final response = await client.get('/status'); if (response.statusCode == 200) { statusData = response.data; developer.log('已获取ZeroTier状态信息'); } else { developer.log('获取ZeroTier状态信息失败: ${response.statusCode}'); statusData = null; } } on DioException catch (e) { if (e.type == DioExceptionType.connectionTimeout || e.type == DioExceptionType.connectionError) { developer.log('无法连接到ZeroTier服务:服务可能未运行'); } else { developer.log('获取ZeroTier状态信息错误', error: e.toString()); } statusData = null; } on SocketException { developer.log('无法连接到ZeroTier服务:服务可能未运行'); statusData = null; } catch (e) { developer.log('检查ZeroTier状态错误', error: e.toString()); statusData = null; } // 根据获取的状态信息更新运行状态和详情 if (statusData != null) { runningStatus = true; _statusInfo = ZerotierStatus.fromJson(statusData); developer.log('ZeroTier服务状态: 运行中'); developer.log('已加载ZeroTier详细状态信息'); return _statusInfo; } else { runningStatus = false; _statusInfo = null; developer.log('ZeroTier服务状态: 未运行'); return null; } } /// 释放资源 void dispose() { _authService.dispose(); } }