@@ -930,7 +930,7 @@ async function handleImageEdit(
930930}
931931
932932// ─── Server ──────────────────────────────────────────────────────────────────
933- /** The port the gateway actually bound. Falls back off GATEWAY_PORT when it's taken (a 2nd Off Grid
933+ /** The port the gateway actually bound. Falls back off GATEWAY_PORT when it's taken (a 2nd Off Grid AI Desktop
934934 * instance); consumers (setup health ping, the Gateway UI) must read this LIVE value. */
935935let boundGatewayPort = GATEWAY_PORT
936936export function getGatewayPort ( ) : number {
@@ -1220,15 +1220,39 @@ export async function startModelServer(port = GATEWAY_PORT): Promise<void> {
12201220 server . headersTimeout = 0 // no cap on time-to-headers
12211221 server . keepAliveTimeout = 60_000
12221222
1223- server . on ( 'error' , ( e ) => console . error ( '[model-server]' , e ) )
12241223 // The gateway has no authentication. Bind the socket itself to loopback so no
12251224 // route can become LAN-accessible through a missing per-handler authorization check.
1226- server . listen ( boundGatewayPort , GATEWAY_HOST , ( ) => {
1227- console . log (
1228- `[model-server] multimodal gateway at http://${ GATEWAY_HOST } :${ boundGatewayPort } /v1`
1229- )
1230- } )
1231- startingGateway = false
1225+ // Resolve only AFTER the socket actually binds; a bind failure must reject and clear state so
1226+ // callers (which .catch it) can surface the failure and a later restart can retry — rather than a
1227+ // resolved promise leaving a dead `server` set forever and IPC reporting a false success.
1228+ const listening = server
1229+ try {
1230+ await new Promise < void > ( ( resolve , reject ) => {
1231+ const onError = ( e : Error ) : void => {
1232+ listening . removeListener ( 'listening' , onListening )
1233+ reject ( e )
1234+ }
1235+ const onListening = ( ) : void => {
1236+ listening . removeListener ( 'error' , onError )
1237+ // Hand ongoing runtime errors to the logger now that startup succeeded.
1238+ listening . on ( 'error' , ( e ) => console . error ( '[model-server]' , e ) )
1239+ console . log (
1240+ `[model-server] multimodal gateway at http://${ GATEWAY_HOST } :${ boundGatewayPort } /v1`
1241+ )
1242+ resolve ( )
1243+ }
1244+ listening . once ( 'error' , onError )
1245+ listening . once ( 'listening' , onListening )
1246+ listening . listen ( boundGatewayPort , GATEWAY_HOST )
1247+ } )
1248+ } catch ( e ) {
1249+ // Bind failed — drop the dead server and reset so a retry starts clean.
1250+ server = null
1251+ boundGatewayPort = GATEWAY_PORT
1252+ throw e
1253+ } finally {
1254+ startingGateway = false
1255+ }
12321256}
12331257
12341258export function stopModelServer ( ) : void {
0 commit comments