@@ -58,6 +58,7 @@ private static string ResolveDataDir()
5858 private static readonly string BridgesDir = Path . Combine ( DataDir , "bridges" ) ;
5959 private static readonly string ModeFile = Path . Combine ( DataDir , "mode.txt" ) ;
6060 private static readonly string StrategyFile = Path . Combine ( DataDir , "strategy.txt" ) ;
61+ private static readonly string LastSuccessFile = Path . Combine ( DataDir , "last-success.txt" ) ;
6162 private static readonly string ConfluxSetsFile = Path . Combine ( DataDir , "conflux-sets.txt" ) ;
6263 private static readonly string ConfluxLegsFile = Path . Combine ( DataDir , "conflux-legs.txt" ) ;
6364 private static readonly string ConfluxLinkedSetsFile = Path . Combine ( DataDir , "conflux-linked-sets.txt" ) ;
@@ -166,8 +167,8 @@ private static int DefaultStrategy()
166167 private const int InternetOptionSettingsChanged = 39 ;
167168 private const int InternetOptionRefresh = 37 ;
168169
169- private static readonly string [ ] ModeNames = { "vanilla" , "obfs4" , "webtunnel" , "snowflake" , "direct" } ;
170- private static readonly string [ ] BridgeFiles = { "vanilla_tested.txt" , "obfs4_tested.txt" , "webtunnel_tested.txt" , "snowflake_tested.txt" , "" } ;
170+ private static readonly string [ ] ModeNames = { "vanilla" , "obfs4" , "webtunnel" , "snowflake" , "direct" , "memory" } ;
171+ private static readonly string [ ] BridgeFiles = { "vanilla_tested.txt" , "obfs4_tested.txt" , "webtunnel_tested.txt" , "snowflake_tested.txt" , "" , "" } ;
171172 private static readonly string [ ] AllBridgeFiles = { "obfs4_tested.txt" , "webtunnel_tested.txt" , "vanilla_tested.txt" , "snowflake_tested.txt" } ;
172173 private const string BridgesBaseUrl =
173174 "https://raw.githubusercontent.com/Delta-Kronecker/Tor-Bridges-Collector/refs/heads/main/bridge" ;
@@ -499,6 +500,40 @@ private static void WriteStrategyFile(int strategy)
499500 catch { }
500501 }
501502
503+ private static void WriteLastSuccessCache ( int mode , int strategy )
504+ {
505+ try
506+ {
507+ if ( mode < 0 || mode >= ModeNames . Length ) return ;
508+ if ( strategy < 0 || strategy >= StrategyNames . Length ) return ;
509+ string content = "mode=" + ModeNames [ mode ] + "\r \n strategy=" + StrategyNames [ strategy ] ;
510+ File . WriteAllText ( LastSuccessFile , content , new UTF8Encoding ( false ) ) ;
511+ }
512+ catch { }
513+ }
514+
515+ private static bool ReadLastSuccessCache ( out int mode , out int strategy )
516+ {
517+ mode = - 1 ;
518+ strategy = - 1 ;
519+ try
520+ {
521+ if ( ! File . Exists ( LastSuccessFile ) ) return false ;
522+ string [ ] lines = File . ReadAllLines ( LastSuccessFile ) ;
523+ string modeName = null , stratName = null ;
524+ foreach ( string line in lines )
525+ {
526+ string t = line . Trim ( ) ;
527+ if ( t . StartsWith ( "mode=" ) ) modeName = t . Substring ( 5 ) . Trim ( ) ;
528+ else if ( t . StartsWith ( "strategy=" ) ) stratName = t . Substring ( 9 ) . Trim ( ) ;
529+ }
530+ if ( modeName != null ) mode = ParseMode ( modeName ) ;
531+ if ( stratName != null ) strategy = ParseStrategy ( stratName ) ;
532+ return mode >= 0 ;
533+ }
534+ catch { return false ; }
535+ }
536+
502537 // When the lowlatency preset is chosen, steer the conflux set policy
503538 // toward latency: fastest-set selection, a tight best-% filter and the
504539 // slow-set skip. Choosing any OTHER preset restores the throughput
@@ -745,13 +780,14 @@ private static int ShowMenu()
745780 Console . WriteLine ( " 3) WebTunnel" ) ;
746781 Console . WriteLine ( " 4) Snowflake" ) ;
747782 Console . WriteLine ( " 5) Direct Tor" ) ;
748- Console . Write ( " Choose 1-5 (Enter = " + ModeNames [ last >= 0 ? last : 0 ] + "): " ) ;
783+ Console . WriteLine ( " 6) Memory (last successful)" ) ;
784+ Console . Write ( " Choose 1-6 (Enter = " + ModeNames [ last >= 0 ? last : 0 ] + "): " ) ;
749785 string input ;
750786 try { input = Console . ReadLine ( ) ; }
751787 catch { return - 1 ; }
752788 if ( string . IsNullOrWhiteSpace ( input ) ) return last >= 0 ? last : 0 ;
753789 int n ;
754- if ( int . TryParse ( input . Trim ( ) , out n ) && n >= 1 && n <= 5 ) return n - 1 ;
790+ if ( int . TryParse ( input . Trim ( ) , out n ) && n >= 1 && n <= 6 ) return n - 1 ;
755791 int m = ParseMode ( input . Trim ( ) ) ;
756792 if ( m >= 0 ) return m ;
757793 Console . WriteLine ( " Invalid choice, try again." ) ;
@@ -3452,6 +3488,22 @@ private static int RunTorSession(int mode, int strategy,
34523488 mode = ReadLastMode ( ) ;
34533489 if ( mode < 0 ) mode = 1 ; // obfs4 — only used when the race is off
34543490 }
3491+ if ( mode == 5 ) // memory
3492+ {
3493+ int cachedMode , cachedStrategy ;
3494+ if ( ReadLastSuccessCache ( out cachedMode , out cachedStrategy ) )
3495+ {
3496+ mode = cachedMode ;
3497+ if ( strategy < 0 ) strategy = cachedStrategy ;
3498+ Console . WriteLine ( " [memory] reconnecting with: " + ModeNames [ mode ] + " / " + StrategyNames [ strategy ] ) ;
3499+ }
3500+ else
3501+ {
3502+ Console . WriteLine ( " [memory] no successful connection cached yet." ) ;
3503+ WaitForKey ( ) ;
3504+ return menuReturn ? 2 : 1 ;
3505+ }
3506+ }
34553507 if ( genOnly )
34563508 {
34573509 if ( ! WriteTorrc ( mode , strategy ) ) { WaitForKey ( ) ; return 1 ; }
@@ -3523,6 +3575,7 @@ private static int RunTorSession(int mode, int strategy,
35233575 Console . WriteLine ( "Bootstrapped 100% - Tor is UP (auto-restart " + attempt + ")." ) ;
35243576 Console . WriteLine ( ) ;
35253577 }
3578+ WriteLastSuccessCache ( mode , strategy ) ;
35263579
35273580 if ( bootstrapOnly )
35283581 {
0 commit comments