Skip to content

Commit

Permalink
add types (#4)
Browse files Browse the repository at this point in the history
* add types and refactor fastify plugin
  • Loading branch information
tinchoz49 authored Nov 5, 2023
1 parent d0c4305 commit f88642c
Show file tree
Hide file tree
Showing 23 changed files with 924 additions and 68 deletions.
38 changes: 24 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ $ npm install @geut/fastify-uws

```javascript
import fastify from 'fastify'
import { serverFactory, fastifyUws, getUws } from '@geut/fastify-uws'
import { serverFactory, getUws, WebSocketStream } from '@geut/fastify-uws'

import fastifyUwsPlugin from '@geut/fastify-uws/plugin'

const app = fastify({
serverFactory
})

await app.register(fastifyUws)
await app.register(fastifyUwsPlugin)

app.addHook('onReady', async () => {
// access to uws app
Expand All @@ -39,24 +41,32 @@ app.websocketServer.on('close', ws => {
})

app
.get('/', {
ws: {
.route({
method: 'GET',
url: '/',
handler (req, reply) {
return 'hello from http endpoint'
},
uws: {
// cache subscription topics to produce less memory allocations
topics: [
'home/sensors/ligth',
'home/sensors/temp'
]
},
uwsHandler (conn) {
conn.subscribe('home/sensors/temp')
conn.on('message', (message) => {
conn.publish('home/sensors/temp', 'random message')
})
conn.send(JSON.stringify({ hello: 'world' }))
}
},
async (req, reply) => {
if (!reply.ws) {
return 'hello from http endpoint'
}

reply.subscribe('home/sensors/temp')
reply.on('message', (message) => {
reply.publish('home/sensors/temp', 'random message')
})
.get('/stream', { uws: true }, (conn) => {
const stream = new WebSocketStream(conn)
stream.on('data', data => {
console.log('stream data from /stream')
})
reply.send(JSON.stringify({ hello: 'world' }))
})
.listen({
port: 3000
Expand Down
58 changes: 58 additions & 0 deletions example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import fastify from 'fastify'
import { serverFactory, getUws, WebSocketStream } from './src/server.js'

import fastifyUwsPlugin from './src/plugin.js'

const app = fastify({
serverFactory
})

await app.register(fastifyUwsPlugin)

app.addHook('onReady', async () => {
// access to uws app
// eslint-disable-next-line no-unused-vars
const uwsApp = getUws(app)
})

app.websocketServer.on('open', ws => {
console.log('OPEN')
})

app.websocketServer.on('close', ws => {
console.log('CLOSE')
})

app
.route({
method: 'GET',
url: '/',
handler (req, reply) {
return 'hello from http endpoint'
},
uws: {
// cache subscription topics to produce less memory allocations
topics: [
'home/sensors/ligth',
'home/sensors/temp'
]
},
uwsHandler (conn) {
conn.subscribe('home/sensors/temp')
conn.on('message', (message) => {
conn.publish('home/sensors/temp', 'random message')
})
conn.send(JSON.stringify({ hello: 'world' }))
}
})
.get('/stream', { uws: true }, (conn) => {
const stream = new WebSocketStream(conn)
stream.on('data', data => {
console.log('stream data from /stream')
})
})
.listen({
port: 3000
}, (err) => {
err && console.error(err)
})
34 changes: 23 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,57 @@
"version": "1.1.0",
"description": "uWebSockets.js for fastify",
"type": "module",
"main": "./dist/index.cjs",
"exports": {
".": {
"require": "./dist/index.cjs",
"import": "./src/index.js"
"types": "./types/server.d.ts",
"import": "./src/server.js",
"require": "./src/server.cjs"
},
"./plugin": {
"types": "./types/plugin.d.ts",
"import": "./src/plugin.js",
"require": "./src/plugin.cjs"
},
"./package.json": "./package.json"
},
"workspaces": [
"tests/fastify/module"
],
"files": [
"types",
"dist",
"src"
],
"scripts": {
"start": "node index.js",
"build": "tsup src/index.js",
"build": "rm -rf dist && tsup src/server.js src/plugin.js --splitting",
"test": "uvu --ignore tests/fastify",
"posttest": "npm run lint",
"posttest": "npm run lint && tsc",
"lint": "standard",
"prepublishOnly": "npm test && npm run build"
"prepublishOnly": "npm test && npm run build",
"types": "node scripts/generate-dts.js"
},
"dependencies": {
"fastify-plugin": "^4.2.1",
"fastify-plugin": "^4.5.1",
"fastq": "^1.13.0",
"ipaddr.js": "^2.0.1",
"nanoerror": "^1.2.1",
"nanoerror": "^2.0.0",
"streamx": "^2.12.5",
"tempy": "^1.0.1",
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.25.0"
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.33.0"
},
"devDependencies": {
"fastify": "^4.6.0",
"@types/events": "^3.0.2",
"@types/node": "^20.8.10",
"@types/streamx": "^2.9.3",
"execa": "^8.0.1",
"fastify": "^4.24.3",
"require-inject": "^1.4.4",
"simple-get": "^4.0.1",
"standard": "^17.0.0",
"tap": "^16.3.0",
"tsup": "^6.2.3",
"tsup": "^7.2.0",
"typescript": "^5.2.2",
"uvu": "^0.5.3",
"ws": "^8.9.0"
},
Expand Down
19 changes: 19 additions & 0 deletions scripts/generate-dts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as fs from 'node:fs'
import { $ } from 'execa'

await $`tsc src/server.js src/plugin.js --declaration --allowJs --emitDeclarationOnly --outDir types`

const types = fs.readFileSync('types/plugin.d.ts', 'utf-8')
fs.writeFileSync(
'types/plugin.d.ts',
types + 'import "./fastify-overload.d.ts"'
)

// for some reason tsc exclude uwebsocket.js module
for (const file of ['server.d.ts', 'websocket-server.d.ts']) {
const types = fs.readFileSync(`types/${file}`, 'utf-8')
fs.writeFileSync(
`types/${file}`,
types + 'import uws from "uWebSockets.js"'
)
}
6 changes: 6 additions & 0 deletions src/http-socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const toHex = (buf, start, end) => buf.slice(start, end).toString('hex')

const noop = () => {}

/**
* @this {HTTPSocket}
*/
function onAbort () {
this.aborted = true
this.emit('aborted')
Expand All @@ -44,6 +47,9 @@ function onTimeout () {
}
}

/**
* @this {HTTPSocket}
*/
function onWrite (data, cb) {
const res = this[kRes]

Expand Down
53 changes: 38 additions & 15 deletions src/plugin.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
// this plugin is inspired by https://github.com/fastify/fastify-websocket
/**
* @template T
* @typedef {import('fastify').FastifyPluginCallback<T>} FastifyPluginCallback */

import fp from 'fastify-plugin'
/** @typedef {import('./websocket-server.js').WSOptions} WSOptions */

/** @typedef {import('./request.js').Request} Request */

import fp from 'fastify-plugin'
import { WebSocketServer, WebSocket } from './websocket-server.js'

import {
kWs,
kRes
} from './symbols.js'

function defaultErrorHandler (err, request) {
/**
* @this {import('fastify').FastifyInstance}
* @param {Error} err
* @param {WebSocket} conn
* @param {import('fastify').FastifyRequest} request
*/
function defaultErrorHandler (err, conn, request) {
request.log.error(err)
request.raw.destroy(err)
}

function fastifyUws (fastify, opts = {}, next) {
/** @type {FastifyPluginCallback<{ errorHandler?: typeof defaultErrorHandler } & WSOptions>} */
function fastifyUws (fastify, opts, next) {
const { server } = fastify
const { errorHandler = defaultErrorHandler, options } = opts
const { errorHandler = defaultErrorHandler, ...options } = opts || {}

if (errorHandler && typeof errorHandler !== 'function') {
return next(new Error('invalid errorHandler function'))
Expand All @@ -27,11 +39,19 @@ function fastifyUws (fastify, opts = {}, next) {
fastify.decorate('websocketServer', websocketServer)

fastify.addHook('onRoute', routeOptions => {
const isWebSocket = !!routeOptions.ws
if (!isWebSocket || routeOptions.method === 'HEAD' || routeOptions.method === 'OPTIONS') return
const isWebSocket = !!routeOptions.uws || routeOptions.uwsHandler
if (!isWebSocket || routeOptions.method !== 'GET') return

const wsOptions = typeof routeOptions.uws === 'object' ? routeOptions.uws : {}

let httpHandler, uwsHandler
if (routeOptions.uwsHandler) {
httpHandler = routeOptions.handler
uwsHandler = routeOptions.uwsHandler
} else {
uwsHandler = routeOptions.handler
}

const wsOptions = typeof routeOptions.ws === 'object' ? routeOptions.ws : {}
const handler = routeOptions.handler
const namespace = Buffer.from(routeOptions.url)

const topics = {}
Expand All @@ -42,7 +62,7 @@ function fastifyUws (fastify, opts = {}, next) {
}

routeOptions.handler = function (request, reply) {
const requestRaw = request.raw
const requestRaw = /** @type {Request} */(/** @type {unknown} */(request.raw))
if (requestRaw[kWs]) {
reply.hijack()
const uRes = requestRaw.socket[kRes]
Expand All @@ -51,6 +71,8 @@ function fastifyUws (fastify, opts = {}, next) {
uRes.upgrade({
req: requestRaw,
handler: (ws) => {
request.uws = true

const conn = new WebSocket(namespace, ws, topics)
let result
try {
Expand All @@ -67,13 +89,13 @@ function fastifyUws (fastify, opts = {}, next) {
conn.end()
})

result = handler.call(this, request, conn)
result = uwsHandler.call(this, conn, request)
} catch (err) {
return errorHandler.call(this, err, request, conn)
return errorHandler.call(this, err, conn, request)
}

if (result && typeof result.catch === 'function') {
result.catch(err => errorHandler.call(this, err, request, conn))
result.catch(err => errorHandler.call(this, err, conn, request))
}
}
},
Expand All @@ -82,15 +104,16 @@ function fastifyUws (fastify, opts = {}, next) {
requestRaw.headers['sec-websocket-extensions'],
requestRaw[kWs])
} else {
return handler.call(this, request, reply)
return httpHandler.call(this, request, reply)
}
}
})

next()
}

/** @type {typeof fastifyUws} */
export default fp(fastifyUws, {
fastify: '>= 4.0.0',
name: '@fastify/websocket'
name: 'fastify-uws'
})
1 change: 0 additions & 1 deletion src/response.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import { STATUS_CODES } from 'http'

import { Writable } from 'streamx'
Expand Down
Loading

0 comments on commit f88642c

Please sign in to comment.