Rename speedKbps and dataCapMB parameters to bytesPerSecond and quotaBytes, respectively, in API and traffic control logic

This commit is contained in:
ImBenji
2025-08-05 13:46:13 +01:00
parent daf67bf516
commit 2d692e0bc0
4 changed files with 123 additions and 31 deletions

View File

@@ -79,10 +79,10 @@ class ApiTester {
print(' IP: $peerIP');
// Test 2: Set speed limit
print('\n📋 TEST 2: Set speed limit (500 kbps)');
e print('\n📋 TEST 2: Set speed limit (62500 bytes/s = 500 kbps)');
final speedResponse = await makeRequest('POST', '/api/peers/speed-limit', {
'publicKey': publicKey,
'speedKbps': 500,
'bytesPerSecond': 62500, // 500 kbps = 500000 bits/s = 62500 bytes/s
});
if (speedResponse['statusCode'] == 200 && speedResponse['body']['success'] == true) {
@@ -92,10 +92,10 @@ class ApiTester {
}
// Test 3: Set data cap
print('\n📋 TEST 3: Set data cap (1024 MB)');
print('\n📋 TEST 3: Set data cap (1073741824 bytes = 1024 MB)');
final dataCapResponse = await makeRequest('POST', '/api/peers/data-cap', {
'publicKey': publicKey,
'dataCapMB': 1024,
'quotaBytes': 1073741824, // 1024 * 1024 * 1024 bytes
});
if (dataCapResponse['statusCode'] == 200 && dataCapResponse['body']['success'] == true) {

View File

@@ -116,7 +116,7 @@ class PeerRoutes {
final body = await request.readAsString();
final data = jsonDecode(body) as Map<String, dynamic>;
final publicKey = data['publicKey'] as String?;
final speedKbps = data['speedKbps'] as int?;
final bytesPerSecond = data['bytesPerSecond'] as int?;
if (publicKey == null) {
return Response.badRequest(
@@ -128,17 +128,17 @@ class PeerRoutes {
);
}
if (speedKbps == null) {
if (bytesPerSecond == null) {
return Response.badRequest(
body: jsonEncode({
'success': false,
'error': 'speedKbps parameter is required',
'error': 'bytesPerSecond parameter is required',
}),
headers: {'Content-Type': 'application/json'},
);
}
await setSpeedLimit(publicKey, speedKbps);
await setSpeedLimit(publicKey, bytesPerSecond);
return Response.ok(
jsonEncode({
@@ -163,7 +163,7 @@ class PeerRoutes {
final body = await request.readAsString();
final data = jsonDecode(body) as Map<String, dynamic>;
final publicKey = data['publicKey'] as String?;
final dataCapMB = data['dataCapMB'] as int?;
final quotaBytes = data['quotaBytes'] as int?;
if (publicKey == null) {
return Response.badRequest(
@@ -175,17 +175,17 @@ class PeerRoutes {
);
}
if (dataCapMB == null) {
if (quotaBytes == null) {
return Response.badRequest(
body: jsonEncode({
'success': false,
'error': 'dataCapMB parameter is required',
'error': 'quotaBytes parameter is required',
}),
headers: {'Content-Type': 'application/json'},
);
}
await setDataCap(publicKey, dataCapMB);
await setDataCap(publicKey, quotaBytes);
return Response.ok(
jsonEncode({

View File

@@ -1,9 +1,10 @@
import 'dart:io';
class TrafficControlService {
static Future<void> setSpeedLimit(String peerIP, int speedKbps) async {
static Future<void> setSpeedLimit(String peerIP, int bytesPerSecond) async {
final mark = _getMarkForIP(peerIP);
print('Setting speed limit for peer $peerIP to ${speedKbps}kbps (mark: $mark)');
final kbps = (bytesPerSecond * 8 / 1000).round(); // Convert bytes/s to kbps
print('Setting speed limit for peer $peerIP to ${bytesPerSecond} bytes/s (${kbps}kbps, mark: $mark)');
try {
// Ensure HTB qdisc exists on wg0
@@ -29,23 +30,55 @@ class TrafficControlService {
}
print('Running iptables MARK commands for $peerIP...');
await _runIptablesCommand(['-I', 'FORWARD', '-s', peerIP, '-j', 'MARK', '--set-mark', mark.toString()]);
await _runIptablesCommand(['-I', 'FORWARD', '-d', peerIP, '-j', 'MARK', '--set-mark', mark.toString()]);
// Mark upload traffic (FROM peer) with uploadMark
await _runIptablesCommand(['-I', 'FORWARD', '-s', peerIP, '-j', 'MARK', '--set-mark', uploadMark.toString()]);
// Mark download traffic (TO peer) with downloadMark
await _runIptablesCommand(['-I', 'FORWARD', '-d', peerIP, '-j', 'MARK', '--set-mark', downloadMark.toString()]);
print('Running tc class add/change command...');
// Create separate classes for upload and download
final uploadMark = mark;
final downloadMark = mark + 1000; // Offset to avoid conflicts
print('Running tc class add/change commands for upload and download...');
// Upload class (traffic FROM peer)
try {
await _runTcCommand(['class', 'add', 'dev', 'wg0', 'parent', '1:1', 'classid', '1:$mark', 'htb', 'rate', '${speedKbps}kbit', 'ceil', '${speedKbps}kbit']);
await _runTcCommand(['class', 'add', 'dev', 'wg0', 'parent', '1:1', 'classid', '1:$uploadMark', 'htb', 'rate', '${kbps}kbit', 'ceil', '${kbps}kbit']);
} catch (e) {
if (e.toString().contains('File exists')) {
print('Class exists, updating with change command...');
await _runTcCommand(['class', 'change', 'dev', 'wg0', 'classid', '1:$mark', 'htb', 'rate', '${speedKbps}kbit', 'ceil', '${speedKbps}kbit']);
print('Upload class exists, updating...');
await _runTcCommand(['class', 'change', 'dev', 'wg0', 'classid', '1:$uploadMark', 'htb', 'rate', '${kbps}kbit', 'ceil', '${kbps}kbit']);
} else {
rethrow;
}
}
print('Running tc filter add command...');
await _runTcCommand(['filter', 'add', 'dev', 'wg0', 'protocol', 'ip', 'parent', '1:', 'prio', '1', 'handle', mark.toString(), 'fw', 'flowid', '1:$mark']);
// Download class (traffic TO peer)
try {
await _runTcCommand(['class', 'add', 'dev', 'wg0', 'parent', '1:1', 'classid', '1:$downloadMark', 'htb', 'rate', '${kbps}kbit', 'ceil', '${kbps}kbit']);
} catch (e) {
if (e.toString().contains('File exists')) {
print('Download class exists, updating...');
await _runTcCommand(['class', 'change', 'dev', 'wg0', 'classid', '1:$downloadMark', 'htb', 'rate', '${kbps}kbit', 'ceil', '${kbps}kbit']);
} else {
rethrow;
}
}
print('Running tc filter add commands...');
// Upload filter
try {
await _runTcCommand(['filter', 'add', 'dev', 'wg0', 'protocol', 'ip', 'parent', '1:', 'prio', '1', 'handle', uploadMark.toString(), 'fw', 'flowid', '1:$uploadMark']);
} catch (e) {
if (!e.toString().contains('File exists')) rethrow;
}
// Download filter
try {
await _runTcCommand(['filter', 'add', 'dev', 'wg0', 'protocol', 'ip', 'parent', '1:', 'prio', '1', 'handle', downloadMark.toString(), 'fw', 'flowid', '1:$downloadMark']);
} catch (e) {
if (!e.toString().contains('File exists')) rethrow;
}
print('Speed limit set successfully for $peerIP');
} catch (e) {
@@ -57,8 +90,8 @@ class TrafficControlService {
}
}
static Future<void> setDataCap(String peerIP, int dataCapMB) async {
final quotaBytes = dataCapMB * 1024 * 1024;
static Future<void> setDataCap(String peerIP, int quotaBytes) async {
print('Setting data cap for peer $peerIP to $quotaBytes bytes');
await _runIptablesCommand(['-I', 'FORWARD', '-s', peerIP, '-m', 'quota', '--quota', quotaBytes.toString(), '-j', 'ACCEPT']);
await _runIptablesCommand(['-I', 'FORWARD', '-d', peerIP, '-m', 'quota', '--quota', quotaBytes.toString(), '-j', 'ACCEPT']);