app.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { Server } from 'hyper-express'
  2. import { LRUCache } from 'lru-cache'
  3. import cluster, { isWorker } from 'node:cluster'
  4. import { maxQuery, maxRows } from './config.js'
  5. const { DATABASE } = process.env
  6. const db = DATABASE ? await import(`./database/${DATABASE}.js`) : null
  7. const generateRandomNumber = () => Math.floor(Math.random() * maxRows) + 1
  8. const parseQueries = (i) => Math.min(parseInt(i) || 1, maxQuery)
  9. const escapeHTMLRules = { '&': '&#38;', '<': '&#60;', '>': '&#62;', '"': '&#34;', "'": '&#39;', '/': '&#47;' }
  10. const unsafeHTMLMatcher = /[&<>"'\/]/g
  11. const escapeHTMLCode = (text) => unsafeHTMLMatcher.test(text) ? text.replace(unsafeHTMLMatcher, function (m) { return escapeHTMLRules[m] || m; }) : text
  12. const cache = new LRUCache({
  13. max: maxRows
  14. })
  15. const app = new Server()
  16. // use middleware to add `Server` into response header
  17. app.use((_request, response, next) => {
  18. response.header('Server', 'hyperexpress')
  19. return next()
  20. })
  21. app.get('/plaintext', (_request, response) => {
  22. response.type('text').send('Hello, World!')
  23. })
  24. app.get('/json', (_request, response) => {
  25. response.json({ message: 'Hello, World!' })
  26. })
  27. if (db) {
  28. app.get('/db', async (_request, response) => {
  29. try {
  30. const world = await db.find(generateRandomNumber())
  31. response.json(world)
  32. } catch (error) {
  33. throw error
  34. }
  35. })
  36. app.get('/queries', async (request, response) => {
  37. try {
  38. const queries = parseQueries(request.query.queries)
  39. const worldPromises = new Array(queries)
  40. for (let i = 0; i < queries; i++) {
  41. worldPromises[i] = db.find(generateRandomNumber())
  42. }
  43. const worlds = await Promise.all(worldPromises);
  44. response.json(worlds)
  45. } catch (error) {
  46. throw error
  47. }
  48. })
  49. app.get('/updates', async (request, response) => {
  50. try {
  51. const queries = parseQueries(request.query.queries)
  52. const worldPromises = new Array(queries)
  53. for (let i = 0; i < queries; i++) {
  54. worldPromises[i] = db.find(generateRandomNumber())
  55. }
  56. const worlds = await Promise.all(worldPromises)
  57. for (let i = 0; i < queries; i++) {
  58. worlds[i].randomNumber = generateRandomNumber()
  59. }
  60. await db.bulkUpdate(worlds)
  61. response.json(worlds)
  62. } catch (error) {
  63. throw error
  64. }
  65. })
  66. app.get('/fortunes', async (_request, response) => {
  67. try {
  68. const fortunes = await db.fortunes()
  69. fortunes.push({ id: 0, message: 'Additional fortune added at request time.' })
  70. fortunes.sort((a, b) => (a.message < b.message) ? -1 : 1)
  71. const n = fortunes.length
  72. let i = 0, html = ''
  73. for (; i < n; i++) html += `<tr><td>${fortunes[i].id}</td><td>${escapeHTMLCode(fortunes[i].message)}</td></tr>`
  74. response
  75. .header('Content-Type', 'text/html; charset=utf-8')
  76. .send(`<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>${html}</table></body></html>`)
  77. } catch (error) {
  78. throw error
  79. }
  80. })
  81. let isCachePopulated = false
  82. app.get('/cached-worlds', async (request, response) => {
  83. try {
  84. if (!isCachePopulated) {
  85. const worlds = await db.getAllWorlds()
  86. for (let i = 0; i < worlds.length; i++) {
  87. cache.set(worlds[i].id, worlds[i])
  88. }
  89. isCachePopulated = true
  90. }
  91. const count = parseQueries(request.query.count)
  92. const worlds = new Array(count)
  93. for (let i = 0; i < count; i++) {
  94. worlds[i] = cache.get(generateRandomNumber())
  95. }
  96. response.json(worlds)
  97. } catch (error) {
  98. throw error
  99. }
  100. })
  101. }
  102. app.listen(8080).then(() => {
  103. console.log(`${isWorker ? `${cluster.worker.id}: ` : ''}Successfully bound to http://0.0.0.0:8080`)
  104. })