1010namespace Immutable . Browser . Core
1111{
1212 /// <summary>
13- /// A lightweight HTTP server to serve the GameBridge index.html locally.
14- /// This provides a proper origin (http://localhost:PORT) instead of null origin from file:// URLs.
13+ /// Local HTTP server for index.html to provide a proper origin instead of null from file:// URLs.
1514 /// </summary>
1615 public class GameBridgeServer : IDisposable
1716 {
1817 private const string TAG = "[Game Bridge Server]" ;
19- private const int MIN_PORT = 49152 ;
20- private const int MAX_PORT = 65535 ;
21- private const int MAX_PORT_ATTEMPTS = 100 ;
18+
19+ // Fixed port to maintain consistent origin for localStorage/IndexedDB persistence
20+ private const int PORT = 51990 ;
21+ private static readonly string URL = "http://localhost:" + PORT + "/" ;
2222
2323 private HttpListener ? _listener ;
2424 private Thread ? _listenerThread ;
2525 private byte [ ] ? _indexHtmlContent ;
2626 private readonly CancellationTokenSource _cts = new CancellationTokenSource ( ) ;
2727 private bool _disposed ;
2828
29- public int Port { get ; private set ; }
30-
3129 /// <summary>
3230 /// Creates a new GameBridgeServer instance.
3331 /// </summary>
@@ -40,13 +38,12 @@ public GameBridgeServer(string indexHtmlPath)
4038 if ( ! File . Exists ( indexHtmlPath ) )
4139 throw new FileNotFoundException ( $ "{ TAG } index.html not found: { indexHtmlPath } ") ;
4240
43- // Cache the file content at startup
4441 _indexHtmlContent = File . ReadAllBytes ( indexHtmlPath ) ;
4542 Debug . Log ( $ "{ TAG } Loaded index.html ({ _indexHtmlContent . Length } bytes)") ;
4643 }
4744
4845 /// <summary>
49- /// Starts the HTTP server on an available port .
46+ /// Starts the game bridge server .
5047 /// </summary>
5148 /// <returns>The URL to the index.html file.</returns>
5249 public string Start ( )
@@ -55,15 +52,15 @@ public string Start()
5552 throw new ObjectDisposedException ( nameof ( GameBridgeServer ) ) ;
5653
5754 if ( _listener ? . IsListening == true )
58- return $ "http://localhost: { Port } /" ;
55+ return URL ;
5956
60- Port = FindAvailablePort ( ) ;
57+ EnsurePortAvailable ( ) ;
6158
6259 _listener = new HttpListener ( ) ;
63- _listener . Prefixes . Add ( $ "http://localhost: { Port } /" ) ;
60+ _listener . Prefixes . Add ( URL ) ;
6461 _listener . Start ( ) ;
6562
66- Debug . Log ( $ "{ TAG } Started on http://localhost: { Port } / ") ;
63+ Debug . Log ( $ "{ TAG } Started on { URL } ") ;
6764
6865 _listenerThread = new Thread ( ListenerLoop )
6966 {
@@ -72,7 +69,7 @@ public string Start()
7269 } ;
7370 _listenerThread . Start ( ) ;
7471
75- return $ "http://localhost: { Port } /" ;
72+ return URL ;
7673 }
7774
7875 private void ListenerLoop ( )
@@ -120,16 +117,14 @@ private void HandleRequest(HttpListenerContext context)
120117 }
121118 }
122119
123- private int FindAvailablePort ( )
120+ private void EnsurePortAvailable ( )
124121 {
125- var random = new System . Random ( ) ;
126- for ( int attempt = 0 ; attempt < MAX_PORT_ATTEMPTS ; attempt ++ )
122+ if ( ! IsPortAvailable ( PORT ) )
127123 {
128- int port = random . Next ( MIN_PORT , MAX_PORT ) ;
129- if ( IsPortAvailable ( port ) )
130- return port ;
124+ throw new InvalidOperationException (
125+ $ " { TAG } Port { PORT } is already in use. " +
126+ "Please close any application using this port to ensure localStorage/IndexedDB data persists correctly." ) ;
131127 }
132- throw new InvalidOperationException ( $ "{ TAG } Could not find an available port") ;
133128 }
134129
135130 private bool IsPortAvailable ( int port )
0 commit comments