app.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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.ceil(Math.random() * maxRows)
  8. const parseQueries = (i) => Math.min(Math.max(parseInt(i, 10) || 1, 1), maxQuery)
  9. const escapeHTMLRules = { '&': '&#38;', '<': '&#60;', '>': '&#62;', '"': '&#34;', "'": '&#39;', '/': '&#47;' }
  10. const unsafeHTMLMatcher = /[&<>"'\/]/g
  11. const escapeHTMLCode = (text) => text ? text.replace(unsafeHTMLMatcher, function (m) { return escapeHTMLRules[m] || m; }) : ''
  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. next()
  20. })
  21. app.get('/plaintext', (_request, response) => {
  22. response.atomic(() => {
  23. response
  24. .type('text')
  25. .send('Hello, World!')
  26. })
  27. })
  28. app.get('/json', (_request, response) => {
  29. response.json({ message: 'Hello, World!' })
  30. })
  31. if (db) {
  32. // populate cache
  33. (async () => {
  34. const worlds = await db.getAllWorlds()
  35. for (let i = 0; i < worlds.length; i++) {
  36. cache.set(worlds[i].id, worlds[i])
  37. }
  38. })()
  39. app.get('/db', async (_request, response) => {
  40. try {
  41. const world = await db.find(generateRandomNumber())
  42. response.json(world)
  43. } catch (error) {
  44. throw error
  45. }
  46. })
  47. app.get('/queries', async (request, response) => {
  48. try {
  49. const queries = parseQueries(request.query.queries)
  50. const worldPromises = []
  51. for (let i = 0; i < queries; i++) {
  52. worldPromises.push(db.find(generateRandomNumber()))
  53. }
  54. const worlds = await Promise.all(worldPromises)
  55. response.json(worlds)
  56. } catch (error) {
  57. throw error
  58. }
  59. })
  60. app.get('/updates', async (request, response) => {
  61. try {
  62. const queries = parseQueries(request.query.queries)
  63. const worldPromises = []
  64. for (let i = 0; i < queries; i++) {
  65. worldPromises.push(db.find(generateRandomNumber()))
  66. }
  67. const worlds = await Promise.all(worldPromises)
  68. const updatedWorlds = await Promise.all(worlds.map(async (world) => {
  69. world.randomNumber = generateRandomNumber()
  70. await db.update(world)
  71. return world
  72. }))
  73. response.json(updatedWorlds)
  74. } catch (error) {
  75. throw error
  76. }
  77. })
  78. app.get('/fortunes', async (_request, response) => {
  79. try {
  80. const fortunes = await db.fortunes()
  81. fortunes.push({ id: 0, message: 'Additional fortune added at request time.' })
  82. fortunes.sort((a, b) => a.message.localeCompare(b.message))
  83. let i = 0, html = '<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>'
  84. for (; i < fortunes.length; i++) html += `<tr><td>${fortunes[i].id}</td><td>${escapeHTMLCode(fortunes[i].message)}</td></tr>`
  85. html += '</table></body></html>'
  86. response.atomic(() => {
  87. response
  88. // .type('html')
  89. .header('Content-Type', 'text/html; charset=utf-8')
  90. .send(html)
  91. })
  92. } catch (error) {
  93. throw error
  94. }
  95. })
  96. app.get('/cached-worlds', async (request, response) => {
  97. try {
  98. const count = parseQueries(request.query.count)
  99. const worlds = []
  100. for (let i = 0; i < count; i++) {
  101. worlds[i] = cache.get(generateRandomNumber())
  102. }
  103. response.json(worlds)
  104. } catch (error) {
  105. throw error
  106. }
  107. })
  108. }
  109. app.listen(8080).then(() => {
  110. console.log(`${isWorker ? `${cluster.worker.id}: ` : ''}Successfully bound to http://0.0.0.0:8080`)
  111. })