Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: add server-sent events support #1613

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
29 changes: 28 additions & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import { Low } from 'lowdb'
import { json } from 'milliparsec'
import sirv from 'sirv'

import { Data, isItem, Service } from './service.js'
import { Data, isItem, Item, Service } from './service.js'

const __dirname = dirname(fileURLToPath(import.meta.url))
const isProduction = process.env['NODE_ENV'] === 'production'

export type AppOptions = {
logger?: boolean
static?: string[]
chunk?: number
}

const eta = new Eta({
Expand Down Expand Up @@ -75,6 +76,32 @@ export function createApp(db: Low<Data>, options: AppOptions = {}) {
next?.()
})

app.get('/sse/:name', (req, res) => {
res.header('Content-Type', 'text/event-stream');
const { name = '' } = req.params

const interval = 200;

const data = service.find(name) as Item[];
if (!data.length) {
return res.sendStatus(404)
}

for (let i = 0; i < data.length; i += options.chunk!) {
setTimeout(() => {
const payload = JSON.stringify(data.slice(i, options.chunk! + i))
res.write(`data: ${payload}\n\n`);
res.flushHeaders();

if (i >= data.length) {
res.end();
}
}, i * interval);
}

return;
})

app.get('/:name/:id', (req, res, next) => {
const { name = '', id = '' } = req.params
res.locals['data'] = service.findById(name, id, req.query)
Expand Down
11 changes: 9 additions & 2 deletions src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Options:
-p, --port <port> Port (default: 3000)
-h, --host <host> Host (default: localhost)
-s, --static <dir> Static files directory (multiple allowed)
--chunk <size> Server-sent events chunk size (default: 2)
--help Show this message
--version Show version number
`)
Expand All @@ -33,6 +34,7 @@ function args(): {
port: number
host: string
static: string[]
chunk: number
} {
try {
const { values, positionals } = parseArgs({
Expand All @@ -53,6 +55,10 @@ function args(): {
multiple: true,
default: [],
},
chunk: {
type: 'string',
default: '2'
},
help: {
type: 'boolean',
},
Expand Down Expand Up @@ -100,6 +106,7 @@ function args(): {
port: parseInt(values.port as string),
host: values.host as string,
static: values.static as string[],
chunk: parseInt(values.chunk as string),
}
} catch (e) {
if ((e as NodeJS.ErrnoException).code === 'ERR_PARSE_ARGS_UNKNOWN_OPTION') {
Expand All @@ -112,7 +119,7 @@ function args(): {
}
}

const { file, port, host, static: staticArr } = args()
const { file, port, host, static: staticArr, chunk } = args()

if (!existsSync(file)) {
console.log(chalk.red(`File ${file} not found`))
Expand Down Expand Up @@ -140,7 +147,7 @@ const db = new Low<Data>(observer, {})
await db.read()

// Create app
const app = createApp(db, { logger: false, static: staticArr })
const app = createApp(db, { logger: false, static: staticArr, chunk })

function logRoutes(data: Data) {
console.log(chalk.bold('Endpoints:'))
Expand Down