|
1 | 1 | import express from "express"; |
| 2 | +import { LRUCache } from 'lru-cache'; |
2 | 3 | import { |
3 | 4 | generateRandomNumber, |
4 | | - getQueriesCount, |
5 | | - handleError, |
| 5 | + parseQueries, |
6 | 6 | escape, |
7 | 7 | jsonSerializer, |
8 | 8 | worldObjectSerializer, |
9 | 9 | worldsObjectSerializer, |
10 | | - sortByMessage, |
11 | | - writeResponse, |
12 | | - headerTypes, |
13 | 10 | GREETING, |
| 11 | + maxRows |
14 | 12 | } from "./utils.mjs"; |
15 | 13 |
|
| 14 | + |
16 | 15 | let db; |
17 | 16 | const { DATABASE } = process.env; |
18 | 17 | if (DATABASE) db = await import(`./database/${DATABASE}.mjs`); |
19 | 18 |
|
| 19 | +const cache = new LRUCache({ |
| 20 | + max: maxRows |
| 21 | +}); |
| 22 | + |
20 | 23 | const extra = { id: 0, message: "Additional fortune added at request time." }; |
21 | 24 |
|
22 | 25 | const app = express(); |
23 | 26 |
|
| 27 | +app.set('x-powered-by', false); |
| 28 | +app.set('etag', false); |
| 29 | + |
24 | 30 | app.get("/plaintext", (req, res) => { |
25 | | - writeResponse(res, GREETING, headerTypes["plain"]); |
| 31 | + res.writeHead(200, { |
| 32 | + "content-type": "text/plain", |
| 33 | + server: "Express", |
| 34 | + }).end(GREETING); |
26 | 35 | }); |
27 | 36 |
|
28 | 37 | app.get("/json", (req, res) => { |
29 | | - writeResponse(res, jsonSerializer({ message: GREETING })); |
| 38 | + res.writeHead(200, { |
| 39 | + "content-type": "application/json", |
| 40 | + server: "Express", |
| 41 | + }).end(jsonSerializer({ message: GREETING })); |
30 | 42 | }); |
31 | 43 |
|
32 | 44 | if (db) { |
33 | 45 | app.get("/db", async (req, res) => { |
34 | | - try { |
35 | | - const row = await db.find(generateRandomNumber()); |
36 | | - writeResponse(res, worldObjectSerializer(row)); |
37 | | - } catch (error) { |
38 | | - handleError(error, res); |
39 | | - } |
| 46 | + const row = await db.find(generateRandomNumber()); |
| 47 | + res.writeHead(200, { |
| 48 | + "content-type": "application/json", |
| 49 | + server: "Express", |
| 50 | + }).end(worldObjectSerializer(row)); |
40 | 51 | }); |
41 | 52 |
|
42 | 53 | app.get("/queries", async (req, res) => { |
43 | | - try { |
44 | | - const queries = getQueriesCount(req); |
45 | | - const worldPromises = new Array(queries); |
46 | | - for (let i = 0; i < queries; i++) { |
47 | | - worldPromises[i] = db.find(generateRandomNumber()); |
48 | | - } |
49 | | - const worlds = await Promise.all(worldPromises); |
50 | | - writeResponse(res, worldsObjectSerializer(worlds)); |
51 | | - } catch (error) { |
52 | | - handleError(error, res); |
| 54 | + const queries = parseQueries(req.query.queries); |
| 55 | + const worldPromises = new Array(queries); |
| 56 | + for (let i = 0; i < queries; i++) { |
| 57 | + worldPromises[i] = db.find(generateRandomNumber()); |
53 | 58 | } |
| 59 | + const worlds = await Promise.all(worldPromises); |
| 60 | + res.writeHead(200, { |
| 61 | + "content-type": "application/json", |
| 62 | + server: "Express", |
| 63 | + }).end(worldsObjectSerializer(worlds)); |
54 | 64 | }); |
55 | 65 |
|
56 | 66 | app.get("/fortunes", async (req, res) => { |
57 | | - try { |
58 | | - const rows = [extra, ...(await db.fortunes())]; |
59 | | - sortByMessage(rows); |
60 | | - const n = rows.length; |
61 | | - let html = "", |
62 | | - i = 0; |
63 | | - for (; i < n; i++) { |
64 | | - html += `<tr><td>${rows[i].id}</td><td>${escape( |
65 | | - rows[i].message |
66 | | - )}</td></tr>`; |
67 | | - } |
68 | | - |
69 | | - writeResponse( |
70 | | - res, |
71 | | - `<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>${html}</table></body></html>`, |
72 | | - headerTypes["html"] |
73 | | - ); |
74 | | - } catch (error) { |
75 | | - handleError(error, res); |
| 67 | + const rows = await db.fortunes(); |
| 68 | + rows.push(extra); |
| 69 | + rows.sort((a, b) => (a.message < b.message) ? -1 : 1); |
| 70 | + const n = rows.length; |
| 71 | + let html = "", |
| 72 | + i = 0; |
| 73 | + for (; i < n; i++) { |
| 74 | + const row = rows[i]; |
| 75 | + html += `<tr><td>${row.id}</td><td>${escape(row.message)}</td></tr>`; |
76 | 76 | } |
| 77 | + res.writeHead(200, { |
| 78 | + "content-type": "text/html; charset=UTF-8", |
| 79 | + server: "Express", |
| 80 | + }).end(`<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>${html}</table></body></html>`); |
77 | 81 | }); |
78 | 82 |
|
79 | 83 | app.get("/updates", async (req, res) => { |
80 | | - try { |
81 | | - const queriesCount = getQueriesCount(req); |
82 | | - const databaseJobs = new Array(queriesCount); |
83 | | - for (let i = 0; i < queriesCount; i++) { |
84 | | - databaseJobs[i] = db.find(generateRandomNumber()); |
85 | | - } |
86 | | - const worldObjects = await Promise.all(databaseJobs); |
| 84 | + const queriesCount = parseQueries(req.query.queries); |
| 85 | + const databaseJobs = new Array(queriesCount); |
| 86 | + for (let i = 0; i < queriesCount; i++) { |
| 87 | + databaseJobs[i] = db.find(generateRandomNumber()); |
| 88 | + } |
| 89 | + const worldObjects = await Promise.all(databaseJobs); |
87 | 90 |
|
88 | | - for (let i = 0; i < queriesCount; i++) { |
89 | | - worldObjects[i].randomNumber = generateRandomNumber(); |
| 91 | + for (let i = 0; i < queriesCount; i++) { |
| 92 | + worldObjects[i].randomNumber = generateRandomNumber(); |
| 93 | + } |
| 94 | + await db.bulkUpdate(worldObjects); |
| 95 | + res.writeHead(200, { |
| 96 | + "content-type": "application/json", |
| 97 | + server: "Express", |
| 98 | + }).end(worldsObjectSerializer(worldObjects)); |
| 99 | + }); |
| 100 | + |
| 101 | + let isCachePopulated = false |
| 102 | + app.get('/cached-worlds', async (req, res) => { |
| 103 | + if (!isCachePopulated) { |
| 104 | + const worlds = await db.getAllWorlds(); |
| 105 | + for (let i = 0; i < worlds.length; i++) { |
| 106 | + cache.set(worlds[i].id, worlds[i]); |
90 | 107 | } |
91 | | - await db.bulkUpdate(worldObjects); |
92 | | - writeResponse(res, JSON.stringify(worldObjects)); |
93 | | - } catch (error) { |
94 | | - handleError(error, res); |
| 108 | + isCachePopulated = true; |
95 | 109 | } |
| 110 | + const count = parseQueries(req.query.count); |
| 111 | + const worlds = new Array(count); |
| 112 | + |
| 113 | + for (let i = 0; i < count; i++) { |
| 114 | + worlds[i] = cache.get(generateRandomNumber()); |
| 115 | + } |
| 116 | + |
| 117 | + res.writeHead(200, { |
| 118 | + "content-type": "application/json", |
| 119 | + server: "Express", |
| 120 | + }).end(worldsObjectSerializer(worlds)); |
96 | 121 | }); |
97 | 122 | } |
98 | 123 |
|
99 | | -app.all("/{*splat}", (req, res) => { |
100 | | - res.status(404).send("Not Found"); |
101 | | -}); |
102 | | - |
103 | 124 | const host = process.env.HOST || "0.0.0.0"; |
104 | 125 | const port = parseInt(process.env.PORT || "8080"); |
105 | 126 | app.listen(port, host, () => { |
|
0 commit comments