modernirc
Version:
IRC library for creating modern IRC bots
81 lines (72 loc) • 2.3 kB
JavaScript
/**
* API for Webapp controller
*
* It answers HTTP requests to control the data from and to the bot.
* In order to achieve that, the bot must be able to send its details to the API.
*/
import http from 'node:http'
import { URL } from 'node:url'
import qs from 'node:querystring'
import { workerData } from 'node:worker_threads'
import routes from './routes.js'
import { createLogger } from '../log.js'
/**
* HTTP API request handler
* @param logger {object} Logger
* @param req {import('node:http').IncomingMessage}
* @param res {import('node:http').ServerResponse}
* @returns {Promise<*>}
*/
async function handler(logger, req, res) {
req._url = URL.parse(req.url, `https://${req.headers.host}`)
if (['post', 'put', 'patch'].includes(req.method.toLowerCase())) {
req.body = await new Promise((resolve, reject) => {
let data = ''
req.on('data', (chunk) => {
data += chunk.toString()
}).on('end', () => {
if (req.headers['content-type']?.startsWith('application/json')) {
return resolve(JSON.parse(data))
}
if (req.headers['content-type']?.startsWith('application/x-www-form-urlencoded')) {
return resolve(qs.parse(data))
}
return resolve(data)
}).on('error', reject)
})
} else {
req.body = null
}
req.logger = logger
const key = req.headers['x-key']
if (!key || key !== workerData.opts.auth.key) {
res.writeHead(403)
return res.end('Forbidden Access')
}
const eligibleRoute = routes.find((route) => {
return route.path === req._url.pathname && req.method.toLowerCase() === route.method
})
if (!eligibleRoute) {
res.writeHead(404)
return res.end('Not Found')
}
const result = await eligibleRoute.handler(req)
const resultData = JSON.stringify(result.data)
res.writeHead(result.statusCode, {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(resultData),
})
return res.end(resultData)
}
function main() {
const logger = createLogger({
...workerData.logger,
name: 'api',
})
const srv = http.createServer((req, res) => handler(logger, req, res))
const port = workerData.opts.listen?.port ?? 9999
srv.listen(port, () => {
logger.info(`listening on port ${port}`)
})
}
main()