Skip to content

Instantly share code, notes, and snippets.

@rjrodger
Created August 8, 2023 20:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rjrodger/2de69753bb670316b4395c10bf4cd6b7 to your computer and use it in GitHub Desktop.
Save rjrodger/2de69753bb670316b4395c10bf4cd6b7 to your computer and use it in GitHub Desktop.
Proof of concept REPL for fastify
const Net = require('node:net')
const Repl = require('node:repl')
const Vm = require('node:vm')
const Fastify = require('fastify')({ logger: true })
const Jsonic = require('@jsonic/jsonic-next')
Fastify
.get('/', function handler (request, reply) {
reply.send({ hello: 'world' })
})
.get('/foo', function handler (request, reply) {
reply.send('FOO')
})
.post('/bar', function handler (request, reply) {
reply.send({...request.body, when:Date.now()})
})
.register(function repl(fastify, options, done) {
let server = Net.createServer(function (socket) {
socket.on('error', function (err) {
fastify.err('repl-socket', err)
})
const input = socket
const output = socket
async function evaluate(cmdtext, context, filename, respond) {
cmdtext = cmdtext.trim()
let args = undefined
try {
args = Jsonic(cmdtext)
}
catch(err) {
// Probably JS code
}
let inject = undefined
let out = undefined
if(Array.isArray(args)) {
if('get' === args[0]) {
inject = {
method: 'GET',
url: args[1]
}
}
else if('post' === args[0]) {
inject = {
method: 'POST',
url: args[1],
body: args[2]
}
}
}
try {
if(inject) {
let res = await fastify.inject(inject)
out = {
statusCode: res.statusCode,
body: res.body,
}
}
else {
out = await Vm
.createScript(cmdtext, {
filename,
displayErrors: false,
})
.runInContext(context, {
displayErrors: false,
})
}
respond(undefined, out)
}
catch(err) {
respond(err)
}
}
const repl = Repl.start({
prompt: `fastify-${fastify.version}> `,
socket,
socket,
terminal: false,
useGlobal: false,
eval: evaluate
})
repl
.on('exit', () => {
input.end()
output.end()
})
.on('error', (err) => {
fastify.error('repl', err)
})
Object.assign(repl.context, {
fastify,
inject: async (...args ) => await fastify.inject(...args),
})
})
server
.on('error', function (err) {
fastify.error('repl-server', err)
})
.on('listening', function () {
let address = server.address()
fastify.log.info('REPL listening on ' + address.address + ':' + address.port)
})
.listen(31313, '127.0.0.1')
done()
})
.listen({ port: 3000 }, (err) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
@rjrodger
Copy link
Author

rjrodger commented Aug 8, 2023

This code is MIT licensed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment