Skip to content

Commit

Permalink
refactor!: improve types and api
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Feb 25, 2024
1 parent ced76fa commit 2ebacd3
Show file tree
Hide file tree
Showing 19 changed files with 339 additions and 326 deletions.
4 changes: 2 additions & 2 deletions examples/h3/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { createApp } from "h3";
import { defineWebSocketHooks } from "crossws";
import { defineHooks } from "crossws";

export const app = createApp();

// Listhen automatically sets up integration!
// Learn more: https://crossws.unjs.io

export const websocket = defineWebSocketHooks({
export const websocket = defineHooks({
open(peer) {
console.log("[ws] open", peer);
},
Expand Down
19 changes: 8 additions & 11 deletions playground/_shared.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import {
CrossWSOptions,
WebSocketAdapter,
defineWebSocketHooks,
} from "../src/index.ts";
import { ResolveHooks, Adapter, defineHooks } from "../src/index.ts";

export const getIndexHTML = () =>
fetch(
"https://raw.githubusercontent.com/unjs/crossws/main/examples/h3/public/index.html",
).then((res) => res.text());

export function createDemo<T extends WebSocketAdapter>(
export function createDemo<T extends Adapter<any, any>>(
adapter: T,
opts?: Parameters<T>[1],
options?: Parameters<T>[0],
): ReturnType<T> {
const hooks = defineWebSocketHooks({
const hooks = defineHooks({
$(name, peer, ...args) {
console.log(
`$ ${peer} ${name} (${args.map((arg) => stringify(arg)).join(", ")})`,
Expand All @@ -39,7 +35,7 @@ export function createDemo<T extends WebSocketAdapter>(
},
});

const resolve: CrossWSOptions["resolve"] = (info) => {
const resolve: ResolveHooks = (info) => {
return {
open: (peer) => {
peer.send({
Expand All @@ -51,9 +47,10 @@ export function createDemo<T extends WebSocketAdapter>(
};
};

return adapter(hooks, {
return adapter({
...options,
hooks,
resolve,
...opts,
});
}

Expand Down
2 changes: 1 addition & 1 deletion playground/bun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Bun.serve({
if (await handleUpgrade(req, server)) {
return;
}
return new Response(await getIndexHTML({ name: "bun" }), {
return new Response(await getIndexHTML(), {
headers: { "Content-Type": "text/html" },
});
},
Expand Down
2 changes: 1 addition & 1 deletion playground/cloudflare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default {
return handleUpgrade(request, env, context);
}

return new Response(await getIndexHTML({ name: "cloudflare" }), {
return new Response(await getIndexHTML(), {
headers: { "content-type": "text/html" },
});
},
Expand Down
6 changes: 1 addition & 5 deletions playground/deno.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,14 @@ import type * as _Deno from "../types/lib.deno.d.ts";

import { createDemo, getIndexHTML } from "./_shared.ts";

declare global {
const Deno: typeof import("@deno/types").Deno;
}

const adapter = createDemo(denoAdapter);

Deno.serve({ port: 3001 }, async (req) => {
if (req.headers.get("upgrade") === "websocket") {
return adapter.handleUpgrade(req);
}

return new Response(await getIndexHTML({ name: "deno" }), {
return new Response(await getIndexHTML(), {
headers: { "Content-Type": "text/html" },
});
});
16 changes: 13 additions & 3 deletions playground/uws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,19 @@ const adapter = createDemo(uwsAdapter);
const app = App().ws("/*", adapter.websocket);

app.get("/*", async (res, req) => {
res.writeStatus("200 OK");
res.writeHeader("Content-Type", "text/html");
res.end(await getIndexHTML({ name: "node-uws" }));
let aborted = false;
res.onAborted(() => {
aborted = true;
});
const html = await getIndexHTML();
if (aborted) {
return;
}
res.cork(() => {
res.writeStatus("200 OK");
res.writeHeader("Content-Type", "text/html");
res.end(html);
});
});

app.listen(3001, () => {
Expand Down
12 changes: 0 additions & 12 deletions src/adapter.ts

This file was deleted.

65 changes: 32 additions & 33 deletions src/adapters/bun.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
// https://bun.sh/docs/api/websockets

import type { WebSocketHandler, ServerWebSocket, Server } from "bun";

import { WSMessage } from "../message";
import { WSPeer } from "../peer";
import { defineWebSocketAdapter } from "../adapter";
import { CrossWSOptions, createCrossWS } from "../crossws";
import { Message } from "../message";
import { Peer } from "../peer";
import { AdapterOptions, defineWebSocketAdapter } from "../types";
import { createCrossWS } from "../crossws";
import { toBufferLike } from "../_utils";

export interface AdapterOptions extends CrossWSOptions {}
export interface BunAdapter {
websocket: WebSocketHandler<ContextData>;
handleUpgrade(req: Request, server: Server): Promise<boolean>;
}

export interface BunOptions extends AdapterOptions {}

type ContextData = {
_peer?: WSPeer;
_peer?: Peer;
req?: Request;
server?: Server;
};

export interface Adapter {
websocket: WebSocketHandler<ContextData>;
handleUpgrade(req: Request, server: Server): Promise<boolean>;
}

export default defineWebSocketAdapter<Adapter, AdapterOptions>(
(hooks, options = {}) => {
const crossws = createCrossWS(hooks, options);
export default defineWebSocketAdapter<BunAdapter, BunOptions>(
(options = {}) => {
const crossws = createCrossWS(options);

const getWSPeer = (ws: ServerWebSocket<ContextData>) => {
const getPeer = (ws: ServerWebSocket<ContextData>) => {
if (ws.data?._peer) {
return ws.data._peer;
}
const peer = new BunWSPeer({ bun: { ws } });
const peer = new BunPeer({ bun: { ws } });
ws.data = ws.data || {};
ws.data._peer = peer;
return peer;
Expand All @@ -48,38 +47,38 @@ export default defineWebSocketAdapter<Adapter, AdapterOptions>(
},
websocket: {
message: (ws, message) => {
const peer = getWSPeer(ws);
crossws.$("bun:message", peer, ws, message);
crossws.message(peer, new WSMessage(message));
const peer = getPeer(ws);
crossws.$callHook("bun:message", peer, ws, message);
crossws.callHook("message", peer, new Message(message));
},
open: (ws) => {
const peer = getWSPeer(ws);
crossws.$("bun:open", peer, ws);
crossws.open(peer);
const peer = getPeer(ws);
crossws.$callHook("bun:open", peer, ws);
crossws.callHook("open", peer);
},
close: (ws) => {
const peer = getWSPeer(ws);
crossws.$("bun:close", peer, ws);
crossws.close(peer, {});
const peer = getPeer(ws);
crossws.$callHook("bun:close", peer, ws);
crossws.callHook("close", peer, {});
},
drain: (ws) => {
const peer = getWSPeer(ws);
crossws.$("bun:drain", peer);
const peer = getPeer(ws);
crossws.$callHook("bun:drain", peer);
},
ping(ws, data) {
const peer = getWSPeer(ws);
crossws.$("bun:ping", peer, ws, data);
const peer = getPeer(ws);
crossws.$callHook("bun:ping", peer, ws, data);
},
pong(ws, data) {
const peer = getWSPeer(ws);
crossws.$("bun:pong", peer, ws, data);
const peer = getPeer(ws);
crossws.$callHook("bun:pong", peer, ws, data);
},
},
};
},
);

class BunWSPeer extends WSPeer<{
class BunPeer extends Peer<{
bun: { ws: ServerWebSocket<ContextData> };
}> {
get id() {
Expand Down
43 changes: 23 additions & 20 deletions src/adapters/cloudflare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,31 @@

import type * as _cf from "@cloudflare/workers-types";

import { WSPeer } from "../peer";
import { defineWebSocketAdapter } from "../adapter.js";
import { WSMessage } from "../message";
import { WebSocketError } from "../error";
import { CrossWSOptions, createCrossWS } from "../crossws";
import { Peer } from "../peer";
import { AdapterOptions, defineWebSocketAdapter } from "../types.js";
import { Message } from "../message";
import { WSError } from "../error";
import { createCrossWS } from "../crossws";
import { toBufferLike } from "../_utils";

type Env = Record<string, any>;

declare const WebSocketPair: typeof _cf.WebSocketPair;
declare const Response: typeof _cf.Response;

export interface AdapterOptions extends CrossWSOptions {}

export interface Adapter {
export interface CloudflareAdapter {
handleUpgrade(
req: _cf.Request,
env: Env,
context: _cf.ExecutionContext,
): Promise<_cf.Response>;
}

export default defineWebSocketAdapter<Adapter, AdapterOptions>(
(hooks, options = {}) => {
const crossws = createCrossWS(hooks, options);
export interface CloudflareOptions extends AdapterOptions {}

export default defineWebSocketAdapter<CloudflareAdapter, CloudflareOptions>(
(options = {}) => {
const crossws = createCrossWS(options);

const handleUpgrade = async (
req: _cf.Request,
Expand All @@ -44,22 +44,25 @@ export default defineWebSocketAdapter<Adapter, AdapterOptions>(
const { headers } = await crossws.upgrade(peer);

server.accept();
crossws.$("cloudflare:accept", peer);
crossws.open(peer);
crossws.$callHook("cloudflare:accept", peer);
crossws.callHook("open", peer);

server.addEventListener("message", (event) => {
crossws.$("cloudflare:message", peer, event);
crossws.message(peer, new WSMessage(event.data));
crossws.$callHook("cloudflare:message", peer, event);
crossws.callHook("message", peer, new Message(event.data));
});

server.addEventListener("error", (event) => {
crossws.$("cloudflare:error", peer, event);
crossws.error(peer, new WebSocketError(event.error));
crossws.$callHook("cloudflare:error", peer, event);
crossws.callHook("error", peer, new WSError(event.error));
});

server.addEventListener("close", (event) => {
crossws.$("cloudflare:close", peer, event);
crossws.close(peer, { code: event.code, reason: event.reason });
crossws.$callHook("cloudflare:close", peer, event);
crossws.callHook("close", peer, {
code: event.code,
reason: event.reason,
});
});

// eslint-disable-next-line unicorn/no-null
Expand All @@ -76,7 +79,7 @@ export default defineWebSocketAdapter<Adapter, AdapterOptions>(
},
);

class CloudflarePeer extends WSPeer<{
class CloudflarePeer extends Peer<{
cloudflare: {
client: _cf.WebSocket;
server: _cf.WebSocket;
Expand Down
Loading

0 comments on commit 2ebacd3

Please sign in to comment.