import 'dart:convert'; import 'package:shelf/shelf.dart'; import 'package:shelf_router/shelf_router.dart'; import 'package:waylume_server/wireguard/peers.dart'; import 'package:waylume_server/wireguard/utils.dart'; import 'package:waylume_server/core/utils.dart'; import 'package:waylume_server/services/vpn_session_service.dart'; class PeerRoutes { Router get router { final router = Router(); router.get('/peers', _getPeers); router.post('/peer', _createPeer); router.delete('/peer/', _deletePeer); router.get('/peer//config', _getPeerConfig); router.patch('/peer//speed-limit', _setSpeedLimit); router.patch('/peer//data-cap', _setDataCap); return router; } Future _getPeers(Request request) async { try { final statusParam = request.url.queryParameters['status']?.toUpperCase(); List> peers; if (statusParam == 'DEAD') { peers = await VpnSessionService.getInactivePeers(); } else if (statusParam == 'ALIVE') { final allPeers = await VpnSessionService.getAllLocalPeers(); peers = allPeers.where((peer) => peer['status'] == 'ALIVE').toList(); } else { // No filter or invalid filter - return all peers peers = await VpnSessionService.getAllLocalPeers(); } return Response.ok( jsonEncode({ 'success': true, 'peers': peers, 'total_count': peers.length, 'filter': statusParam, }), headers: {'Content-Type': 'application/json'}, ); } catch (e) { return Response.internalServerError( body: jsonEncode({ 'success': false, 'error': e.toString(), }), headers: {'Content-Type': 'application/json'}, ); } } Future _createPeer(Request request) async { try { final peer = await createPeer(); final geoData = await getGeolocationData(); String serverEndpoint = '${geoData.ip}:51820'; String serverPublicKey = await getServerPublicKey(); final responseData = { 'peer': { 'ip': peer.ip, 'privateKey': peer.privateKey, 'publicKey': peer.publicKey, }, 'server': { 'publicKey': serverPublicKey, 'endpoint': serverEndpoint, }, 'success': true, }; return Response.ok( jsonEncode(responseData), headers: {'Content-Type': 'application/json'}, ); } catch (e) { return Response.internalServerError( body: jsonEncode({ 'success': false, 'error': e.toString(), }), headers: {'Content-Type': 'application/json'}, ); } } Future _deletePeer(Request request) async { try { final publicKey = request.params['publicKey']; if (publicKey == null || publicKey.isEmpty) { return Response.badRequest( body: jsonEncode({ 'success': false, 'error': 'publicKey parameter is required', }), headers: {'Content-Type': 'application/json'}, ); } final success = await deletePeer(publicKey); return Response.ok( jsonEncode({ 'success': success, 'message': success ? 'Peer deleted successfully' : 'Failed to delete peer', }), headers: {'Content-Type': 'application/json'}, ); } catch (e) { return Response.internalServerError( body: jsonEncode({ 'success': false, 'error': e.toString(), }), headers: {'Content-Type': 'application/json'}, ); } } Future _getPeerConfig(Request request) async { try { final publicKey = request.params['publicKey']; if (publicKey == null || publicKey.isEmpty) { return Response.badRequest( body: jsonEncode({ 'success': false, 'error': 'publicKey parameter is required', }), headers: {'Content-Type': 'application/json'}, ); } return Response.notFound( jsonEncode({ 'success': false, 'error': 'Config retrieval not implemented - peer info not stored', }), headers: {'Content-Type': 'application/json'}, ); } catch (e) { return Response.internalServerError( body: jsonEncode({ 'success': false, 'error': e.toString(), }), headers: {'Content-Type': 'application/json'}, ); } } Future _setSpeedLimit(Request request) async { try { final publicKey = request.params['publicKey']; final body = await request.readAsString(); final data = jsonDecode(body) as Map; final bytesPerSecond = data['bytesPerSecond'] as int?; if (publicKey == null || publicKey.isEmpty) { return Response.badRequest( body: jsonEncode({ 'success': false, 'error': 'publicKey parameter is required', }), headers: {'Content-Type': 'application/json'}, ); } if (bytesPerSecond == null) { return Response.badRequest( body: jsonEncode({ 'success': false, 'error': 'bytesPerSecond parameter is required', }), headers: {'Content-Type': 'application/json'}, ); } await setSpeedLimit(publicKey, bytesPerSecond); return Response.ok( jsonEncode({ 'success': true, 'message': 'Speed limit set successfully', }), headers: {'Content-Type': 'application/json'}, ); } catch (e) { return Response.internalServerError( body: jsonEncode({ 'success': false, 'error': e.toString(), }), headers: {'Content-Type': 'application/json'}, ); } } Future _setDataCap(Request request) async { try { final publicKey = request.params['publicKey']; final body = await request.readAsString(); final data = jsonDecode(body) as Map; final quotaBytes = data['quotaBytes'] as int?; if (publicKey == null || publicKey.isEmpty) { return Response.badRequest( body: jsonEncode({ 'success': false, 'error': 'publicKey parameter is required', }), headers: {'Content-Type': 'application/json'}, ); } if (quotaBytes == null) { return Response.badRequest( body: jsonEncode({ 'success': false, 'error': 'quotaBytes parameter is required', }), headers: {'Content-Type': 'application/json'}, ); } await setDataCap(publicKey, quotaBytes); return Response.ok( jsonEncode({ 'success': true, 'message': 'Data cap set successfully', }), headers: {'Content-Type': 'application/json'}, ); } catch (e) { return Response.internalServerError( body: jsonEncode({ 'success': false, 'error': e.toString(), }), headers: {'Content-Type': 'application/json'}, ); } } }