fastify-uws
Version:
A performant HTTP and WebSocket server for Fastify with uWebSockets.
106 lines (105 loc) • 3.44 kB
JavaScript
import f from "uWebSockets.js";
import v from "node:dns/promises";
import { METHODS as L } from "node:http";
import { EventEmitter as N } from "eventemitter3";
import H from "ipaddr.js";
import { ERR_SERVER_DESTROYED as I, ERR_SOCKET_BAD_PORT as y, ERR_ENOTFOUND as O, ERR_INVALID_METHOD as C, ERR_ADDRINUSE as M } from "./errors.js";
import { HTTPSocket as P } from "./http-socket.js";
import { Request as x } from "./request.js";
import { Response as b } from "./response.js";
import { kHandler as R, kHttps as w, kWs as r, kAddress as s, kListenSocket as l, kApp as g, kClosed as d, kListenAll as A, kListening as a, kListen as S, kClientError as V } from "./symbols.js";
function q(n) {
return n.http2 && n.https ? f.SSLApp({
key_file_name: n.https.key.toString("utf-8"),
cert_file_name: n.https.cert.toString("utf-8")
}) : f.App();
}
const U = new Map(L.map((n) => [n.toLowerCase(), n])), c = {};
class X extends N {
[R];
timeout;
[w];
[r];
[s];
[l];
[g];
[d];
[A];
[a];
constructor(t, e = {}) {
super();
const { http2: o = !1, https: u = null, connectionTimeout: p = 0 } = e;
this[R] = t, this.timeout = p, this[w] = u, this[r] = null, this[s] = null, this[l] = null, this[g] = q({ http2: o, https: u }), this[d] = !1;
}
get encrypted() {
return !!this[w];
}
get listening() {
return this[a];
}
setTimeout(t) {
this.timeout = t;
}
address() {
return this[s];
}
listen(t, e) {
t?.signal && t.signal.addEventListener("abort", () => {
this.close();
}), this[S](t).then(() => {
e?.(), this[a] = !0, this.emit("listening");
}).catch((o) => {
this[s] = null, process.nextTick(() => this.emit("error", o));
});
}
closeIdleConnections() {
this.close();
}
close(t = () => {
}) {
if (this[s] = null, this[a] = !1, this[d]) return t();
const e = this[s]?.port;
if (e !== void 0 && c[e] === this && delete c[e], this[s] = null, this[d] = !0, this[l] && (f.us_listen_socket_close(this[l]), this[l] = null), this[r])
for (const o of this[r].connections)
o.close();
process.nextTick(() => {
this.emit("close"), t();
});
}
ref() {
}
unref() {
}
async [S]({ port: t, host: e }) {
if (this[d]) throw new I();
if (t != null && Number.isNaN(Number(t)))
throw new y(t);
t = t == null ? 0 : Number(t);
const o = await v.lookup(e);
if (this[s] = {
...o,
port: t
}, this[s].address.startsWith("[")) throw new O(this[s].address);
const u = H.parse(this[s].address);
this[s].family = u.kind() === "ipv6" ? "IPv6" : "IPv4";
const p = u.toNormalizedString(), E = this[g], T = (k, m) => {
const h = U.get(m.getMethod()), i = new P(this, k, h === "GET" || h === "HEAD");
if (!h) {
i[V] = !0, this.emit("clientError", new C(), i);
return;
}
const _ = new x(m, i, h), D = new b(i);
_.headers.upgrade && this.emit("upgrade", _, i), this[R](_, D);
};
return E.any("/*", T), t !== 0 && c[t] && (this[r] = c[t][r]), this[r] && this[r].addServer(this), new Promise((k, m) => {
const h = (i) => {
if (!i) return m(new M(this[s].address, t));
this[l] = i, t = this[s].port = f.us_socket_local_port(i), c[t] || (c[t] = this), k();
};
this[A] = e === "localhost", this[A] ? E.listen(t, h) : E.listen(p, t, h);
});
}
}
export {
X as Server
};