(server: http.Server)
| 249 | * Return a function capable of fully disposing an HTTP server. |
| 250 | */ |
| 251 | export function disposer(server: http.Server): Disposable["dispose"] { |
| 252 | const sockets = new Set<net.Socket>() |
| 253 | let cleanupTimeout: undefined | NodeJS.Timeout |
| 254 | |
| 255 | server.on("connection", (socket) => { |
| 256 | sockets.add(socket) |
| 257 | |
| 258 | socket.on("close", () => { |
| 259 | sockets.delete(socket) |
| 260 | |
| 261 | if (cleanupTimeout && sockets.size === 0) { |
| 262 | clearTimeout(cleanupTimeout) |
| 263 | cleanupTimeout = undefined |
| 264 | } |
| 265 | }) |
| 266 | }) |
| 267 | |
| 268 | return () => { |
| 269 | return new Promise<void>((resolve, reject) => { |
| 270 | // The whole reason we need this disposer is because close will not |
| 271 | // actually close anything; it only prevents future connections then waits |
| 272 | // until everything is closed. |
| 273 | server.close((err) => { |
| 274 | if (err) { |
| 275 | return reject(err) |
| 276 | } |
| 277 | |
| 278 | resolve() |
| 279 | }) |
| 280 | |
| 281 | // If there are sockets remaining we might need to force close them or |
| 282 | // this promise might never resolve. |
| 283 | if (sockets.size > 0) { |
| 284 | // Give sockets a chance to close up shop. |
| 285 | cleanupTimeout = setTimeout(() => { |
| 286 | cleanupTimeout = undefined |
| 287 | |
| 288 | for (const socket of sockets.values()) { |
| 289 | console.warn("a socket was left hanging") |
| 290 | socket.destroy() |
| 291 | } |
| 292 | }, 1000) |
| 293 | } |
| 294 | }) |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | /** |
| 299 | * Get the options for setting a cookie. The options must be identical for |
no test coverage detected