express: WIP
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
parent
5c1b0ce6ff
commit
d5c43d0624
5 changed files with 175 additions and 17 deletions
3
express/animals.json
Normal file
3
express/animals.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"animals": ["Dog", "Cat", "Elephant", "Lion", "Giraffe"]
|
||||||
|
}
|
|
@ -7,10 +7,15 @@
|
||||||
<body>
|
<body>
|
||||||
<h1>Random Animal Generator</h1>
|
<h1>Random Animal Generator</h1>
|
||||||
<p id="animal-name">Click a button to get a random animal:</p>
|
<p id="animal-name">Click a button to get a random animal:</p>
|
||||||
<button id="button1">Button 1</button>
|
<button id="isCritterButton">Is Critter</button>
|
||||||
<button id="button2">Button 2</button>
|
<button id="isNotCritterButton">Is <b>not</b> Critter</button>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// Function to generate a random session ID
|
||||||
|
function generateSessionId() {
|
||||||
|
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
||||||
|
}
|
||||||
|
|
||||||
// Function to fetch a random animal name from the server
|
// Function to fetch a random animal name from the server
|
||||||
async function getRandomAnimal() {
|
async function getRandomAnimal() {
|
||||||
try {
|
try {
|
||||||
|
@ -22,24 +27,35 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to set or retrieve the session ID cookie
|
||||||
|
function getSessionId() {
|
||||||
|
const sessionId = document.cookie.replace(/(?:(?:^|.*;\s*)sessionId\s*=\s*([^;]*).*$)|^.*$/, '$1');
|
||||||
|
if (!sessionId) {
|
||||||
|
const newSessionId = generateSessionId();
|
||||||
|
document.cookie = `sessionId=${newSessionId}`;
|
||||||
|
return newSessionId;
|
||||||
|
}
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
// Add click event listeners to the buttons
|
// Add click event listeners to the buttons
|
||||||
document.getElementById('button1').addEventListener('click', () => {
|
document.getElementById('isCritterButton').addEventListener('click', () => {
|
||||||
recordButtonClick('Button 1');
|
recordButtonClick('is critter', getSessionId());
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('button2').addEventListener('click', () => {
|
document.getElementById('isNotCritterButton').addEventListener('click', () => {
|
||||||
recordButtonClick('Button 2');
|
recordButtonClick('is not critter', getSessionId());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Function to record button clicks on the server
|
// Function to record button clicks on the server
|
||||||
async function recordButtonClick(buttonName) {
|
async function recordButtonClick(buttonName, sessionId) {
|
||||||
try {
|
try {
|
||||||
await fetch('/recordButtonClick', {
|
await fetch('/recordButtonClick', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ buttonName }),
|
body: JSON.stringify({ buttonName, sessionId }),
|
||||||
});
|
});
|
||||||
getRandomAnimal(); // Load another random animal
|
getRandomAnimal(); // Load another random animal
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
102
express/package-lock.json
generated
102
express/package-lock.json
generated
|
@ -10,9 +10,15 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"express": "^4.18.2"
|
"express": "^4.18.2",
|
||||||
|
"ioredis": "^5.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ioredis/commands": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
|
||||||
|
},
|
||||||
"node_modules/accepts": {
|
"node_modules/accepts": {
|
||||||
"version": "1.3.8",
|
"version": "1.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||||
|
@ -73,6 +79,14 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cluster-key-slot": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/content-disposition": {
|
"node_modules/content-disposition": {
|
||||||
"version": "0.5.4",
|
"version": "0.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||||
|
@ -113,6 +127,14 @@
|
||||||
"ms": "2.0.0"
|
"ms": "2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/denque": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/depd": {
|
"node_modules/depd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
|
@ -350,6 +372,50 @@
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/ioredis": {
|
||||||
|
"version": "5.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz",
|
||||||
|
"integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@ioredis/commands": "^1.1.1",
|
||||||
|
"cluster-key-slot": "^1.1.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"denque": "^2.1.0",
|
||||||
|
"lodash.defaults": "^4.2.0",
|
||||||
|
"lodash.isarguments": "^3.1.0",
|
||||||
|
"redis-errors": "^1.2.0",
|
||||||
|
"redis-parser": "^3.0.0",
|
||||||
|
"standard-as-callback": "^2.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.22.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/ioredis"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ioredis/node_modules/debug": {
|
||||||
|
"version": "4.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ioredis/node_modules/ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
|
},
|
||||||
"node_modules/ipaddr.js": {
|
"node_modules/ipaddr.js": {
|
||||||
"version": "1.9.1",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||||
|
@ -358,6 +424,16 @@
|
||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.defaults": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isarguments": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
|
||||||
|
},
|
||||||
"node_modules/media-typer": {
|
"node_modules/media-typer": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
|
@ -502,6 +578,25 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/redis-errors": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/redis-parser": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
|
||||||
|
"dependencies": {
|
||||||
|
"redis-errors": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/safe-buffer": {
|
"node_modules/safe-buffer": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
@ -586,6 +681,11 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/standard-as-callback": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
|
||||||
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"express": "^4.18.2"
|
"express": "^4.18.2",
|
||||||
|
"ioredis": "^5.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,27 @@
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
const fs = require('fs');
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
|
const Redis = require('ioredis');
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = 3000;
|
const port = 3000;
|
||||||
|
|
||||||
// Dummy database for storing button clicks
|
// Create a Redis Client
|
||||||
const buttonClicks = {
|
const redis = new Redis();
|
||||||
'Button 1': 0,
|
|
||||||
'Button 2': 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
|
|
||||||
|
var animals;
|
||||||
|
// check and load animals into redis
|
||||||
|
fs.readFile("./animals.json", function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
var jsondata = JSON.parse(data);
|
||||||
|
animals = jsondata.animals;
|
||||||
|
//await redis.set('animals', jsondata.animals, 'EX', 3000);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Serve the HTML file
|
// Serve the HTML file
|
||||||
app.get('/', (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
res.sendFile(__dirname + '/index.html');
|
res.sendFile(__dirname + '/index.html');
|
||||||
|
@ -18,20 +29,47 @@ app.get('/', (req, res) => {
|
||||||
|
|
||||||
// Route to get a random animal name
|
// Route to get a random animal name
|
||||||
app.get('/getRandomAnimal', (req, res) => {
|
app.get('/getRandomAnimal', (req, res) => {
|
||||||
const animals = ['Dog', 'Cat', 'Elephant', 'Lion', 'Giraffe'];
|
|
||||||
const randomAnimal = animals[Math.floor(Math.random() * animals.length)];
|
const randomAnimal = animals[Math.floor(Math.random() * animals.length)];
|
||||||
res.json({ animalName: randomAnimal });
|
res.json({ animalName: randomAnimal });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Route to record button clicks
|
// Route to record button clicks
|
||||||
app.post('/recordButtonClick', (req, res) => {
|
app.post('/recordButtonClick', (req, res) => {
|
||||||
const { buttonName } = req.body;
|
try {
|
||||||
|
const { buttonName, sessionId } = req.body;
|
||||||
|
|
||||||
|
// Use a Redis hash to store button clicks associated with session IDs
|
||||||
|
await redis.hincrby('buttonClicks', `${sessionId}:${buttonName}`, 1);
|
||||||
|
|
||||||
|
res.sendStatus(200);
|
||||||
|
|
||||||
if (buttonClicks.hasOwnProperty(buttonName)) {
|
if (buttonClicks.hasOwnProperty(buttonName)) {
|
||||||
buttonClicks[buttonName]++;
|
buttonClicks[buttonName]++;
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
} else {
|
} else {
|
||||||
res.status(400).json({ error: 'Invalid button name' });
|
res.status(400).json({ error: 'Invalid button name' });
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error recording button click:', error);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Route to show the current results
|
||||||
|
app.get('/results', async (req, res) => {
|
||||||
|
try {
|
||||||
|
// Get the current random animal from Redis
|
||||||
|
const randomAnimal = await redis.get('randomAnimal');
|
||||||
|
|
||||||
|
// Get the button click counts from the Redis hash
|
||||||
|
const buttonClicks = await redis.hgetall('buttonClicks');
|
||||||
|
|
||||||
|
res.json({ randomAnimal, buttonClicks });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching results:', error);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue