arblant
Railynx / lib / app / probe_engine.dart
probe_engine.dart75 lines · 2.0 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
import '../engine/vless_parser.dart';
import '../engine/vless_scanner.dart';

/// The network side of the app, behind an interface so widget tests can
/// replace it with a fake. [RealProbeEngine] is the only production code.
abstract class ProbeEngine {
  Future<List<ScanResult>> scan({
    required String subnetPrefix,
    required String domain,
    required String uuid,
    required String path,
    required int port,
    required void Function(int completed, int total, ScanResult result) onProgress,
    required bool Function() shouldStop,
    ScanAbort? abort,
  });

  Future<Map<String, ScanResult>> testIps({
    required List<String> ips,
    required VlessConfig config,
  });
}

class RealProbeEngine implements ProbeEngine {
  static const int testConcurrency = 8;

  @override
  Future<List<ScanResult>> scan({
    required String subnetPrefix,
    required String domain,
    required String uuid,
    required String path,
    required int port,
    required void Function(int completed, int total, ScanResult result) onProgress,
    required bool Function() shouldStop,
    ScanAbort? abort,
  }) {
    return scanSubnet(
      subnetPrefix: subnetPrefix,
      domain: domain,
      uuid: uuid,
      path: path,
      port: port,
      onProgress: onProgress,
      shouldStop: shouldStop,
      abort: abort,
    );
  }

  @override
  Future<Map<String, ScanResult>> testIps({
    required List<String> ips,
    required VlessConfig config,
  }) async {
    final out = <String, ScanResult>{};
    final queue = List<String>.of(ips);
    Future<void> worker() async {
      while (queue.isNotEmpty) {
        final ip = queue.removeAt(0);
        out[ip] = await testIpRealDelay(
          ip,
          config.domain,
          config.uuid,
          path: config.path.isEmpty ? '/' : config.path,
          port: config.port,
          doubleCheck: true,
        );
      }
    }

    final workers = ips.length < testConcurrency ? ips.length : testConcurrency;
    await Future.wait(<Future<void>>[for (var i = 0; i < workers; i++) worker()]);
    return out;
  }
}