@cantoo/capacitor-http-server
Advanced tools
@@ -214,3 +214,4 @@ package com.cantooscribe.httpserver | ||
| // Drain pending requests first so blocked worker threads unblock | ||
| // before we tear down the underlying socket. | ||
| // before we tear down the underlying socket. This just flips latches | ||
| // and returns immediately, so it is safe on the main thread. | ||
| requestBridge.drain( | ||
@@ -226,9 +227,16 @@ HttpRequestBridge.PendingResponse( | ||
| if (srv != null) { | ||
| try { srv.stop() } catch (_: Throwable) {} | ||
| } | ||
| HttpServerService.stop(appContext()) | ||
| cleanupTempDir() | ||
| call.resolve() | ||
| // NanoHTTPD.stop() calls serverThread.join() and waits for every | ||
| // worker thread to return. Running that on Capacitor's default UI | ||
| // thread produces an ANR (and Android then kills the app) as soon | ||
| // as any worker is still finishing the last write. Push the socket | ||
| // teardown onto a background thread and only resolve the promise | ||
| // once everything is actually closed, so a follow-up start() does | ||
| // not collide with the old socket. | ||
| val ctx = appContext() | ||
| Thread({ | ||
| try { srv?.stop() } catch (_: Throwable) {} | ||
| try { HttpServerService.stop(ctx) } catch (_: Throwable) {} | ||
| cleanupTempDir() | ||
| call.resolve() | ||
| }, "HttpServerPlugin-stop").start() | ||
| } | ||
@@ -235,0 +243,0 @@ |
@@ -158,8 +158,21 @@ import Foundation | ||
| server?.removeAllHandlers() | ||
| server?.stop() | ||
| cleanupTempDir() | ||
| endBackgroundTask() | ||
| call.resolve() | ||
| // Do NOT call server?.removeAllHandlers() on a running server: | ||
| // GCDWebServer asserts `_options == nil` inside that method | ||
| // (GWS_DCHECK in GCDWebServer.m), and in Debug builds GWS_DCHECK | ||
| // is `abort()`. That would crash the host app deterministically | ||
| // on every stop(). We don't need it anyway — we drop our only | ||
| // reference to the GCDWebServer instance below and ARC releases | ||
| // it, taking the handlers with it. | ||
| // | ||
| // GCDWebServer.stop() itself waits on an internal semaphore and can | ||
| // block while in-flight requests unwind, so run the teardown on a | ||
| // background queue and only resolve the JS promise once the socket | ||
| // is actually closed; that way a start() issued right after | ||
| // stopServer() cannot race the old socket. | ||
| DispatchQueue.global(qos: .utility).async { [weak self] in | ||
| server?.stop() | ||
| self?.cleanupTempDir() | ||
| self?.endBackgroundTask() | ||
| call.resolve() | ||
| } | ||
| } | ||
@@ -166,0 +179,0 @@ |
+1
-1
| { | ||
| "name": "@cantoo/capacitor-http-server", | ||
| "version": "1.0.4", | ||
| "version": "1.0.5", | ||
| "description": "Capacitor plugin exposing a local HTTP server on iOS and Android with routing delegated to JavaScript.", | ||
@@ -5,0 +5,0 @@ "main": "dist/plugin.cjs.js", |
112813
1.42%