Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions FluxRoute.AI/Models/StrategyGenome.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ public sealed class StrategyGenome
public string? DesyncFooling { get; set; }
public string? FakeResend { get; set; }

public string? WarpConfig { get; set; }
public int? MTU { get; set; }
public bool GoolEnabled { get; set; }
public bool PsiphonEnabled { get; set; }
public string? PsiphonCountry { get; set; }
public bool ScanEnabled { get; set; }
public string? Reserved { get; set; }

public List<string> ExtraArgs { get; set; } = [];

public string DisplayName { get; set; } = "";
Expand Down Expand Up @@ -90,6 +98,13 @@ public EngineProfile ToEngineProfile(int socksPort = 1080)
DesyncAnyProtocol = DesyncAnyProtocol,
DesyncFooling = DesyncFooling,
FakeResend = FakeResend,
WarpConfig = WarpConfig,
MTU = MTU,
GoolEnabled = GoolEnabled,
PsiphonEnabled = PsiphonEnabled,
PsiphonCountry = PsiphonCountry,
ScanEnabled = ScanEnabled,
Reserved = Reserved,
ExtraArgs = [..ExtraArgs],
};
}
Expand Down
72 changes: 66 additions & 6 deletions FluxRoute.AI/Services/AiOrchestratorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public sealed class AiOrchestratorService : IDisposable
private CancellationTokenSource? _cts;
private int _consecutiveFailures;
private int _probeCountSinceEvolve;
private int _probeCountSinceMtuTune;
private DateTimeOffset _lastEvolutionUtc = DateTimeOffset.MinValue;
private volatile bool _networkDirty;
private StrategyGenome? _currentGenome;
Expand Down Expand Up @@ -280,11 +281,26 @@ private async Task RunCycleAsync(CancellationToken ct)
var targets = BuildTargets();
var result = await _probeService.ProbeCurrentAsync(active, targets, ct: ct).ConfigureAwait(false);

// If Warp is enabled in current run mode, check it too
var runMode = _engineManager.RunMode;
if (runMode == DpiRunMode.Warp || runMode == DpiRunMode.WarpZapret || runMode == DpiRunMode.WarpByeDpi)
{
var warpCheck = await _connectivity.CheckWarpAsync(ct).ConfigureAwait(false);
result.Checks.Add(warpCheck);
// Re-calculate score with warp check
result.Score = ProfileScoringService.Calculate(result.ProcessStarted, result.ProcessStable, result.Checks, true);
}

var failedKeys = result.FailedChecks.Select(x => x.Key).ToList();
var avgLat = result.Checks.Where(x => x.ElapsedMs.HasValue).Select(x => x.ElapsedMs!.Value).DefaultIfEmpty(0)
.Average();

var engineName = _currentGenome.EngineType == DpiEngineType.ByeDpi ? "byedpi" : "zapret";
var engineName = _currentGenome.EngineType switch
{
DpiEngineType.ByeDpi => "byedpi",
DpiEngineType.Warp => "warp",
_ => "zapret"
};
var failureSig = !result.ProcessStable
? $"{engineName}_failed"
: result.Score < (int)Math.Round(FailThreshold * 100)
Expand Down Expand Up @@ -343,6 +359,10 @@ private async Task RunCycleAsync(CancellationToken ct)
_probeCountSinceEvolve++;
await MaybeEvolveAsync(fp, ct).ConfigureAwait(false);

_probeCountSinceMtuTune++;
if (_currentGenome?.EngineType == DpiEngineType.Warp)
await MaybeTuneMtuAsync(fp, ct).ConfigureAwait(false);

if (result.IsWorking(FailThreshold))
return;

Expand Down Expand Up @@ -521,6 +541,32 @@ private async Task MaybeEvolveAsync(NetworkFingerprint fp, CancellationToken ct)
Notify("ИИ: эволюция не дала новой стратегии (мало вариантов в пуле или нет родителей).");
}

private async Task MaybeTuneMtuAsync(NetworkFingerprint fp, CancellationToken ct)
{
if (_probeCountSinceMtuTune < 5) return;
_probeCountSinceMtuTune = 0;

var current = _currentGenome;
if (current == null || current.EngineType != DpiEngineType.Warp) return;

var lastOutcomes = _history.LoadFor(current.Id, fp.Hash).TakeLast(5).ToList();
if (lastOutcomes.Count < 5) return;

var avgScore = lastOutcomes.Average(o => o.Score);
if (avgScore < 80)
{
var oldMtu = current.MTU ?? 1280;
var newMtu = oldMtu - 20;
if (newMtu < 1200) newMtu = 1420; // reset to high

Notify($"ИИ: Авто-подбор MTU для Warp: {oldMtu} -> {newMtu} (avg score: {avgScore:F1}%)");
current.MTU = newMtu;
_registry.Upsert(current);
_registry.Save();
await ApplyGenomeAsync(current, fp, ct, switched: false).ConfigureAwait(false);
}
}

public async Task EvolveNowAsync(CancellationToken ct = default)
{
SyncBuiltins();
Expand All @@ -539,8 +585,11 @@ private List<StrategyGenome> GenePool()
var all = _registry.GetActiveGenomes();
return ai.EngineMode switch
{
1 => all.Where(g => g.EngineType == DpiEngineType.ByeDpi).ToList(),
2 => all.Where(g => g.EngineType is DpiEngineType.Zapret or DpiEngineType.ByeDpi).ToList(),
(int)DpiEngineMode.ByeDpi => all.Where(g => g.EngineType == DpiEngineType.ByeDpi).ToList(),
(int)DpiEngineMode.Warp => all.Where(g => g.EngineType == DpiEngineType.Warp).ToList(),
(int)DpiEngineMode.Hybrid => all.Where(g => g.EngineType is DpiEngineType.Zapret or DpiEngineType.ByeDpi).ToList(),
(int)DpiEngineMode.WarpZapret => all.Where(g => g.EngineType is DpiEngineType.Warp or DpiEngineType.Zapret).ToList(),
(int)DpiEngineMode.WarpByeDpi => all.Where(g => g.EngineType is DpiEngineType.Warp or DpiEngineType.ByeDpi).ToList(),
_ => all.Where(g => g.EngineType == DpiEngineType.Zapret).ToList(),
};
}
Expand Down Expand Up @@ -602,7 +651,13 @@ private async Task<bool> TryProbeAndPersistGenomeAsync(StrategyGenome g, Network
StopAfterProbe = false,
};

var socksPort = g.EngineType == DpiEngineType.ByeDpi ? g.ToEngineProfile().SocksPort : (int?)null;
var socksPort = g.EngineType switch
{
DpiEngineType.ByeDpi => g.ToEngineProfile().SocksPort,
DpiEngineType.Warp => 8086,
_ => (int?)null
};

if (socksPort is not null)
{
probeOptions = new ProfileProbeOptions
Expand All @@ -615,15 +670,20 @@ private async Task<bool> TryProbeAndPersistGenomeAsync(StrategyGenome g, Network
UseCurlForHttp = probeOptions.UseCurlForHttp,
MaxParallelChecks = probeOptions.MaxParallelChecks,
Socks5Endpoint = $"127.0.0.1:{socksPort}",
ProcessName = "ciadpi",
ProcessName = g.EngineType == DpiEngineType.Warp ? "warp-plus" : "ciadpi",
};
}
var result = await _probeService.ProbeCurrentAsync(testProfile, targets, probeOptions, ct).ConfigureAwait(false);
var failedKeys = result.FailedChecks.Select(x => x.Key).ToList();
var avgLat = result.Checks.Where(x => x.ElapsedMs.HasValue).Select(x => x.ElapsedMs!.Value).DefaultIfEmpty(0)
.Average();

var engineName = g.EngineType == DpiEngineType.ByeDpi ? "byedpi" : "zapret";
var engineName = g.EngineType switch
{
DpiEngineType.ByeDpi => "byedpi",
DpiEngineType.Warp => "warp",
_ => "zapret"
};
var failureSig = !result.ProcessStable
? $"{engineName}_failed"
: result.Score < (int)Math.Round(FailThreshold * 100)
Expand Down
21 changes: 21 additions & 0 deletions FluxRoute.AI/Services/BatMaterializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,31 @@ public string WriteProfile(StrategyGenome g)

if (g.EngineType == DpiEngineType.ByeDpi)
return WriteByeDpiBat(g, engineDir);
if (g.EngineType == DpiEngineType.Warp)
return WriteWarpBat(g, engineDir);

return WriteZapretBat(g, engineDir);
}

private string WriteWarpBat(StrategyGenome g, string engineDir)
{
var warpDir = Path.Combine(engineDir, "warp");
Directory.CreateDirectory(warpDir);

var sb = new StringBuilder();
sb.AppendLine("@echo off");
sb.AppendLine($"cd /d \"{warpDir}\"");
sb.AppendLine("start /min \"\" warp-plus.exe -b 127.0.0.1:8086");
sb.AppendLine("exit");

var dir = Path.Combine(engineDir, "ai-evolved");
Directory.CreateDirectory(dir);
var safeName = SanitizeFileName(g.DisplayName);
var path = Path.Combine(dir, $"{safeName}.bat");
File.WriteAllText(path, sb.ToString(), new UTF8Encoding(false));
return path;
}

private string WriteByeDpiBat(StrategyGenome g, string engineDir)
{
var byedpiDir = Path.Combine(engineDir, "byedpi");
Expand Down
46 changes: 45 additions & 1 deletion FluxRoute.AI/Services/StrategyEvolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public sealed class StrategyEvolver
private static readonly string[] SemanticMarkers = ["host", "endhost", "midsld", "sniext", "endsld"];
private static readonly string[] DesyncModes = ["split", "fake", "fakesplit", "disorder", "fakedisorder", "multidisorder", "multisplit"];
private static readonly string[] FakeTlsMods = ["orig", "rand", "rndsni", "dupsid", "padencap"];
private static readonly DpiEngineType[] EngineTypes = [DpiEngineType.Zapret, DpiEngineType.ByeDpi];
private static readonly DpiEngineType[] EngineTypes = [DpiEngineType.Zapret, DpiEngineType.ByeDpi, DpiEngineType.Warp];
private static readonly string[] SplitPosCandidates = ["1", "2", "3", "7", "10", "1+s", "2+s", "3+s", "host", "midsld", "sniext"];
private static readonly string[] DisorderPosCandidates = ["1", "3", "5", "1+s", "3+s"];
private static readonly string[] FakePosCandidates = ["-1", "3", "7", "10"];
Expand All @@ -18,6 +18,7 @@ public sealed class StrategyEvolver
private static readonly string[] ModHttpCandidates = ["hcsmix", "dcsmix", "rmspace", "hcsmix,dcsmix", "hcsmix,rmspace"];
private static readonly string[] FoolingCandidates = ["md5sig", "badseq", "datanoack", "hopbyhop", "hopbyhop2", "badsum"];
private static readonly string[] AnyProtocolCandidates = ["0", "1"];
private static readonly string[] PsiphonCountries = ["AT", "AU", "BE", "BG", "CA", "CH", "CZ", "DE", "DK", "EE", "ES", "FI", "FR", "GB", "HR", "HU", "IE", "IN", "IT", "JP", "LV", "NL", "NO", "PL", "PT", "RO", "RS", "SE", "SG", "SK", "US"];

private readonly AiStrategyRegistry _registry;
private readonly AiHistoryStore _history;
Expand Down Expand Up @@ -197,6 +198,13 @@ private StrategyGenome Crossover(StrategyGenome a, StrategyGenome b)
DesyncAnyProtocol = RngPickNullableRef(a.DesyncAnyProtocol, b.DesyncAnyProtocol),
DesyncFooling = RngPickNullableRef(a.DesyncFooling, b.DesyncFooling),
FakeResend = RngPickNullableRef(a.FakeResend, b.FakeResend),
WarpConfig = RngPickNullableRef(a.WarpConfig, b.WarpConfig),
MTU = RngPickNullableStruct(a.MTU, b.MTU),
GoolEnabled = RngPickBool(a.GoolEnabled, b.GoolEnabled),
PsiphonEnabled = RngPickBool(a.PsiphonEnabled, b.PsiphonEnabled),
PsiphonCountry = RngPickNullableRef(a.PsiphonCountry, b.PsiphonCountry),
ScanEnabled = RngPickBool(a.ScanEnabled, b.ScanEnabled),
Reserved = RngPickNullableRef(a.Reserved, b.Reserved),
ExtraArgs = RngPickList(a.ExtraArgs, b.ExtraArgs),
ParentIds = [a.Id, b.Id],
};
Expand Down Expand Up @@ -230,6 +238,10 @@ private void Mutate(StrategyGenome g)
{
MutateByeDpi(g, roll);
}
else if (g.EngineType == DpiEngineType.Warp)
{
MutateWarp(g, roll);
}
else
{
MutateZapret(g, roll);
Expand Down Expand Up @@ -280,6 +292,38 @@ private void MutateZapret(StrategyGenome g, int roll)
}
}

private void MutateWarp(StrategyGenome g, int roll)
{
switch (roll)
{
case 0:
g.EngineType = DpiEngineType.Zapret;
break;
case 1:
g.EngineType = DpiEngineType.ByeDpi;
break;
case 2:
g.MTU = (g.MTU ?? 1280) + (_rng.Next(3) - 1) * 20;
g.MTU = Math.Clamp(g.MTU.Value, 1200, 1500);
break;
case 3:
g.GoolEnabled = !g.GoolEnabled;
break;
case 4:
g.PsiphonEnabled = !g.PsiphonEnabled;
if (g.PsiphonEnabled) g.PsiphonCountry = PsiphonCountries[_rng.Next(PsiphonCountries.Length)];
break;
case 5:
g.ScanEnabled = !g.ScanEnabled;
break;
case 6:
g.Reserved = $"{_rng.Next(256)},{_rng.Next(256)},{_rng.Next(256)}";
break;
default:
break;
}
}

private void MutateByeDpi(StrategyGenome g, int roll)
{
switch (roll)
Expand Down
8 changes: 8 additions & 0 deletions FluxRoute.AI/Services/StrategyGenomeValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public static bool IsValid(StrategyGenome g)
{
if (g.EngineType == DpiEngineType.ByeDpi)
return IsValidByeDpi(g);
if (g.EngineType == DpiEngineType.Warp)
return IsValidWarp(g);
return IsValidZapret(g);
}

Expand All @@ -26,6 +28,12 @@ private static bool IsValidZapret(StrategyGenome g)
return true;
}

private static bool IsValidWarp(StrategyGenome g)
{
// Warp strategies are valid if they are just Warp engine type for now
return g.EngineType == DpiEngineType.Warp;
}

private static bool IsValidByeDpi(StrategyGenome g)
{
if (string.IsNullOrWhiteSpace(g.DisorderPos) &&
Expand Down
2 changes: 1 addition & 1 deletion FluxRoute.Core.Tests/ProfileParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public void ProfileProbeResult_FailedChecks_OnlyReturnsFailed()
{
var result = new ProfileProbeResult
{
Checks = new[]
Checks = new List<CheckResult>
{
new CheckResult { Key = "A", Ok = true },
new CheckResult { Key = "B", Ok = false },
Expand Down
8 changes: 6 additions & 2 deletions FluxRoute.Core/Models/DpiEngineType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ public enum DpiEngineType
{
Zapret,
ByeDpi,
GoodbyeDpi
GoodbyeDpi,
Warp
}

public enum DpiEngineMode
{
Zapret = 0,
ByeDpi = 1,
Hybrid = 2
Warp = 2,
Hybrid = 3,
WarpZapret = 4,
WarpByeDpi = 5
}
8 changes: 8 additions & 0 deletions FluxRoute.Core/Models/EngineProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,13 @@ public sealed class EngineProfile
public string? DesyncFooling { get; set; }
public string? FakeResend { get; set; }

public string? WarpConfig { get; set; }
public int? MTU { get; set; }
public bool GoolEnabled { get; set; }
public bool PsiphonEnabled { get; set; }
public string? PsiphonCountry { get; set; }
public bool ScanEnabled { get; set; }
public string? Reserved { get; set; }

public List<string> ExtraArgs { get; set; } = [];
}
6 changes: 3 additions & 3 deletions FluxRoute.Core/Models/ProfileProbeResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ public sealed class ProfileProbeResult
public bool ProcessStarted { get; init; }
public bool ProcessStable { get; init; }
public IReadOnlyList<int> ProcessIds { get; init; } = Array.Empty<int>();
public IReadOnlyList<CheckResult> Checks { get; init; } = Array.Empty<CheckResult>();
public double SuccessRate { get; init; }
public int Score { get; init; }
public List<CheckResult> Checks { get; set; } = new();
public double SuccessRate { get; set; }
public int Score { get; set; }
public TimeSpan Duration { get; init; }
public string Summary { get; init; } = "";

Expand Down
Loading
Loading