diff --git a/mod.ts b/mod.ts index 018c92a..edb0f38 100644 --- a/mod.ts +++ b/mod.ts @@ -1,3 +1,4 @@ // Copyright 2020 the oak authors. All rights reserved. MIT license. export { responseTimeHeader } from "./observability/response_time_header.ts"; +export { WebSocketMiddleware } from "./websocket/enable_websockets.ts"; \ No newline at end of file diff --git a/websocket/README.md b/websocket/README.md new file mode 100644 index 0000000..b7c127c --- /dev/null +++ b/websocket/README.md @@ -0,0 +1,49 @@ +The following is a re-implementation of the example server in [std/ws](https://deno.land/std@0.76.0/ws): + +```ts +import { WebSocketMiddleware } from "https://deno.land/x/oak-middleware/mod.ts"; +import { Application } from "https://deno.land/x/oak/mod.ts"; +import { + isWebSocketCloseEvent, + isWebSocketPingEvent, + WebSocket, +} from "https://deno.land/std@0.76.0/ws/mod.ts"; + +async function handleWs(sock: WebSocket) { + console.log("socket connected!"); + try { + for await (const ev of sock) { + if (typeof ev === "string") { + // text message. + console.log("ws:Text", ev); + await sock.send(ev); + } else if (ev instanceof Uint8Array) { + // binary message. + console.log("ws:Binary", ev); + } else if (isWebSocketPingEvent(ev)) { + const [, body] = ev; + // ping. + console.log("ws:Ping", body); + } else if (isWebSocketCloseEvent(ev)) { + // close. + const { code, reason } = ev; + console.log("ws:Close", code, reason); + } + } + } catch (err) { + console.error(`failed to receive frame: ${err}`); + + if (!sock.isClosed) { + await sock.close(1000).catch(console.error); + } + } +} + +const app = new App(); +app.use(WebSocketMiddleware(handleWs)); + +// other middleware + +await app.listen(":80"); + +``` \ No newline at end of file diff --git a/websocket/enable_websockets.ts b/websocket/enable_websockets.ts new file mode 100644 index 0000000..9675e2a --- /dev/null +++ b/websocket/enable_websockets.ts @@ -0,0 +1,14 @@ +import type { Middleware, Context } from "https://deno.land/x/oak@v6.3.1/mod.ts"; +import { WebSocket, acceptable } from 'https://deno.land/std@0.76.0/ws/mod.ts' +export type WebSocketHandler = (socket: WebSocket, url: URL, headers: Headers) => Promise; + +export function WebSocketMiddleware(handler: WebSocketHandler){ + return async function real_middleware(ctx: Context, next: () => Promise) { + if(acceptable(ctx.request)) { + let ws = await ctx.upgrade(); + await handler(ws, ctx.request.url, ctx.request.headers); + } else { + return await next(); + } + }; +} \ No newline at end of file