Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ jobs:
strategy:
matrix:
node-version:
- 10
- 12
- 14
- 16
- 18
os:
- macos-latest
- ubuntu-latest
Expand Down
80 changes: 39 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ After registering this plugin, you can choose on which routes the WS server will

const fastify = require('fastify')()
fastify.register(require('@fastify/websocket'))

fastify.get('/', { websocket: true }, (connection /* SocketStream */, req /* FastifyRequest */) => {
connection.socket.on('message', message => {
// message.toString() === 'hi from client'
connection.socket.send('hi from server')
fastify.register(async function (fastify) {
fastify.get('/', { websocket: true }, (connection /* SocketStream */, req /* FastifyRequest */) => {
connection.socket.on('message', message => {
// message.toString() === 'hi from client'
connection.socket.send('hi from server')
})
})
})

Expand All @@ -62,18 +63,19 @@ fastify.register(require('@fastify/websocket'), {
options: { maxPayload: 1048576 }
})


fastify.get('/*', { websocket: true }, (connection /* SocketStream */, req /* FastifyRequest */) => {
connection.socket.on('message', message => {
// message.toString() === 'hi from client'
connection.socket.send('hi from wildcard route')
fastify.register(async function (fastify) {
fastify.get('/*', { websocket: true }, (connection /* SocketStream */, req /* FastifyRequest */) => {
connection.socket.on('message', message => {
// message.toString() === 'hi from client'
connection.socket.send('hi from wildcard route')
})
})
})

fastify.get('/', { websocket: true }, (connection /* SocketStream */, req /* FastifyRequest */) => {
connection.socket.on('message', message => {
// message.toString() === 'hi from client'
connection.socket.send('hi from server')
fastify.get('/', { websocket: true }, (connection /* SocketStream */, req /* FastifyRequest */) => {
connection.socket.on('message', message => {
// message.toString() === 'hi from client'
connection.socket.send('hi from server')
})
})
})

Expand Down Expand Up @@ -127,11 +129,10 @@ This plugin uses the same router as the `fastify` instance, this has a few impli
- When using `@fastify/websocket`, it needs to be registered before all routes in order to be able to intercept websocket connections to existing routes and close the connection on non-websocket routes.

```js
'use strict'

const fastify = require('fastify')()
import Fastify from 'fastify'

fastify.register(require('@fastify/websocket'))
const fastify = Fastify()
await fastify.register(require('@fastify/websocket'))

fastify.get('/', { websocket: true }, function wsHandler (connection, req) {
// bound to fastify server
Expand All @@ -143,12 +144,7 @@ fastify.get('/', { websocket: true }, function wsHandler (connection, req) {
})
})

fastify.listen(3000, err => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
await fastify.listen(3000)
```

If you need to handle both HTTP requests and incoming socket connections on the same route, you can still do it using the [full declaration syntax](https://www.fastify.io/docs/latest/Routes/#full-declaration), adding a `wsHandler` property.
Expand All @@ -167,22 +163,24 @@ fastify.register(require('@fastify/websocket'), {
options: { maxPayload: 1048576 }
})

fastify.route({
method: 'GET',
url: '/hello',
handler: (req, reply) => {
// this will handle http requests
reply.send({ hello: 'world' })
},
wsHandler: (conn, req) => {
// this will handle websockets connections
conn.setEncoding('utf8')
conn.write('hello client')

conn.once('data', chunk => {
conn.end()
})
}
fastify.register(async function () {
fastify.route({
method: 'GET',
url: '/hello',
handler: (req, reply) => {
// this will handle http requests
reply.send({ hello: 'world' })
},
wsHandler: (conn, req) => {
// this will handle websockets connections
conn.setEncoding('utf8')
conn.write('hello client')

conn.once('data', chunk => {
conn.end()
})
}
})
})

fastify.listen(3000, err => {
Expand Down
6 changes: 3 additions & 3 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="node" />
import { IncomingMessage, ServerResponse, Server } from 'http';
import { FastifyRequest, FastifyPluginCallback, RawServerBase, RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RequestGenericInterface, ContextConfigDefault, FastifyInstance } from 'fastify';
import { FastifyRequest, FastifyPluginCallback, RawServerBase, RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RequestGenericInterface, ContextConfigDefault, FastifyInstance} from 'fastify';
import * as fastify from 'fastify';
import * as WebSocket from 'ws';
import { Duplex, DuplexOptions } from 'stream';
Expand All @@ -18,8 +18,8 @@ declare module 'fastify' {
websocket?: boolean;
}

interface FastifyInstance<RawServer, RawRequest, RawReply> {
get: RouteShorthandMethod<RawServer, RawRequest, RawReply>
interface FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider> {
get: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider>,
websocketServer: WebSocket.Server,
}

Expand Down
9 changes: 6 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ function fastifyWebsocket (fastify, opts, next) {
})

fastify.addHook('onError', (request, reply, error, done) => {
/* istanbul ignore next */
if (request.raw[kWs]) {
// Hijack reply to prevent fastify from sending the error after onError hooks are done running
reply.hijack()
Expand All @@ -98,15 +99,17 @@ function fastifyWebsocket (fastify, opts, next) {
let handler = routeOptions.handler

if (routeOptions.websocket || routeOptions.wsHandler) {
if (routeOptions.method !== 'GET') {
if (routeOptions.method === 'HEAD') {
return
} else if (routeOptions.method !== 'GET') {
throw new Error('websocket handler can only be declared in GET method')
}

isWebsocketRoute = true

if (routeOptions.websocket) {
wsHandler = routeOptions.handler
handler = function (request, reply) {
handler = function (_, reply) {
reply.code(404).send()
}
}
Expand Down Expand Up @@ -171,7 +174,7 @@ function fastifyWebsocket (fastify, opts, next) {
connection.socket.close()
}

function defaultErrorHandler (error, conn, request, reply) {
function defaultErrorHandler (error, conn, request) {
// Before destroying the connection, we attach an error listener.
// Since we already handled the error, adding this listener prevents the ws
// library from emitting the error and causing an uncaughtException
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"homepage": "https://github.com/fastify/fastify-websocket#readme",
"devDependencies": {
"@types/ws": "^8.2.2",
"fastify": "^3.25.3",
"fastify": "^4.0.0-rc.2",
"pre-commit": "^1.2.2",
"snazzy": "^9.0.0",
"split2": "^4.1.0",
Expand Down
Loading