express: time and session ID
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
parent
c811d35fa5
commit
44167de812
6 changed files with 1196 additions and 165 deletions
|
@ -4,5 +4,8 @@
|
||||||
- https://github.com/TA3/web-user-behaviour
|
- https://github.com/TA3/web-user-behaviour
|
||||||
- https://www.merriam-webster.com/dictionary/critter
|
- https://www.merriam-webster.com/dictionary/critter
|
||||||
|
|
||||||
|| y/n | time to decide | indecision ||
|
|| critter name | y/n | time to decide | indecision | session_id ||
|
||||||
| | |
|
| | | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
<button id="isNotCritterButton">Is <b>not</b> Critter</button>
|
<button id="isNotCritterButton">Is <b>not</b> Critter</button>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// Initialize session variables
|
||||||
|
let sessionStartTime;
|
||||||
|
let lastButtonClickTime;
|
||||||
|
|
||||||
// Function to generate a random session ID
|
// Function to generate a random session ID
|
||||||
function generateSessionId() {
|
function generateSessionId() {
|
||||||
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
||||||
|
@ -38,6 +42,21 @@
|
||||||
return sessionId;
|
return sessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Function to set session start time
|
||||||
|
function setSessionStartTime() {
|
||||||
|
sessionStartTime = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to calculate and display time difference
|
||||||
|
function displayTimeDifference() {
|
||||||
|
if (sessionStartTime && lastButtonClickTime) {
|
||||||
|
const timeDifference = lastButtonClickTime - sessionStartTime;
|
||||||
|
console.log(`Time since session start: ${timeDifference} milliseconds`);
|
||||||
|
// You can display the time difference on the page as needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add click event listeners to the buttons
|
// Add click event listeners to the buttons
|
||||||
document.getElementById('isCritterButton').addEventListener('click', () => {
|
document.getElementById('isCritterButton').addEventListener('click', () => {
|
||||||
recordButtonClick('is critter', getSessionId());
|
recordButtonClick('is critter', getSessionId());
|
||||||
|
@ -50,21 +69,29 @@
|
||||||
// Function to record button clicks on the server
|
// Function to record button clicks on the server
|
||||||
async function recordButtonClick(buttonName, sessionId) {
|
async function recordButtonClick(buttonName, sessionId) {
|
||||||
try {
|
try {
|
||||||
await fetch('/recordButtonClick', {
|
const currentTime = new Date();
|
||||||
method: 'POST',
|
if (lastButtonClickTime) {
|
||||||
headers: {
|
const timeDifference = currentTime - lastButtonClickTime;
|
||||||
'Content-Type': 'application/json',
|
// Include the time difference in the POST request data
|
||||||
},
|
await fetch('/recordButtonClick', {
|
||||||
body: JSON.stringify({ buttonName, sessionId }),
|
method: 'POST',
|
||||||
});
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ buttonName, sessionId, timeDifference }),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
lastButtonClickTime = currentTime; // Record the timestamp of the button click
|
||||||
|
displayTimeDifference(); // Calculate and display time difference
|
||||||
getRandomAnimal(); // Load another random animal
|
getRandomAnimal(); // Load another random animal
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error recording button click:', error);
|
console.error('Error recording button click:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial random animal load
|
// Initial random animal load and session start time
|
||||||
getRandomAnimal();
|
getRandomAnimal();
|
||||||
|
setSessionStartTime();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
1165
express/package-lock.json
generated
1165
express/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -16,6 +16,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "^1.20.2",
|
"body-parser": "^1.20.2",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"ioredis": "^5.3.2"
|
"sqlite3": "^5.1.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,71 +1,82 @@
|
||||||
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 sqlite3 = require('sqlite3').verbose();
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = 3000;
|
const port = 3000;
|
||||||
|
|
||||||
// Create a Redis Client
|
// Create an SQLite database and initialize tables
|
||||||
const redis = new Redis();
|
const db = new sqlite3.Database('mydb.db', (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Error opening SQLite database:', err.message);
|
||||||
|
} else {
|
||||||
|
console.log('Connected to SQLite database');
|
||||||
|
db.run(`
|
||||||
|
CREATE TABLE IF NOT EXISTS button_clicks (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
session_id TEXT,
|
||||||
|
button_name TEXT,
|
||||||
|
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
time_difference INTEGER -- Add this column for time difference
|
||||||
|
)
|
||||||
|
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
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');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Route to get a random animal name
|
// Route to get a random animal name
|
||||||
app.get('/getRandomAnimal', (req, res) => {
|
app.get('/getRandomAnimal', async (req, res) => {
|
||||||
const randomAnimal = animals[Math.floor(Math.random() * animals.length)];
|
|
||||||
res.json({ animalName: randomAnimal });
|
|
||||||
});
|
|
||||||
|
|
||||||
// Route to record button clicks
|
|
||||||
app.post('/recordButtonClick', (req, res) => {
|
|
||||||
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)) {
|
|
||||||
buttonClicks[buttonName]++;
|
|
||||||
res.sendStatus(200);
|
|
||||||
} else {
|
|
||||||
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 {
|
try {
|
||||||
// Get the current random animal from Redis
|
const animals = ['Dog', 'Cat', 'Elephant', 'Lion', 'Giraffe'];
|
||||||
const randomAnimal = await redis.get('randomAnimal');
|
const randomIndex = Math.floor(Math.random() * animals.length);
|
||||||
|
const randomAnimal = animals[randomIndex];
|
||||||
|
res.json({ animalName: randomAnimal });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching random animal:', error);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Get the button click counts from the Redis hash
|
// Route to record button clicks along with session IDs in SQLite
|
||||||
const buttonClicks = await redis.hgetall('buttonClicks');
|
app.post('/recordButtonClick', (req, res) => {
|
||||||
|
try {
|
||||||
|
const { buttonName, sessionId } = req.body;
|
||||||
|
|
||||||
res.json({ randomAnimal, buttonClicks });
|
db.run('INSERT INTO button_clicks (session_id, button_name) VALUES (?, ?)', [sessionId, buttonName], (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Error recording button click:', err.message);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
} else {
|
||||||
|
res.sendStatus(200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error recording button click:', error);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route to show the current results from SQLite
|
||||||
|
app.get('/results', (req, res) => {
|
||||||
|
try {
|
||||||
|
db.all('SELECT button_name, COUNT(*) as count FROM button_clicks GROUP BY button_name', (err, rows) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Error fetching results:', err.message);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
} else {
|
||||||
|
const results = {};
|
||||||
|
rows.forEach((row) => {
|
||||||
|
results[row.button_name] = row.count;
|
||||||
|
});
|
||||||
|
res.json(results);
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching results:', error);
|
console.error('Error fetching results:', error);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
|
31
index.html
31
index.html
|
@ -1,31 +0,0 @@
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<script src="https://cdn.jsdelivr.net/gh/TA3/web-user-behaviour/userBehaviour.min.js"></script>
|
|
||||||
<script src="https://unpkg.com/htmx.org@1.9.5" integrity="sha384-xcuj3WpfgjlKF+FXhSQFQ0ZNr39ln+hwjN3npfM9VBnUskLolQAcN80McRIVOPuO" crossorigin="anonymous"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
userBehaviour.config( {
|
|
||||||
userInfo: true,
|
|
||||||
clicks: true,
|
|
||||||
mouseMovement: true,
|
|
||||||
mouseMovementInterval: 1,
|
|
||||||
mouseScroll: true,
|
|
||||||
timeCount: true,
|
|
||||||
clearAfterProcess: true,
|
|
||||||
processTime: 15,
|
|
||||||
processData: function(results){
|
|
||||||
console.log(results);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
userBehaviour.start();
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
booger snatch
|
|
||||||
|
|
||||||
<button hx-post="/clicked" hx-trigger="click" hx-target="#parent-div" hx-swap="outerHTML" >is critter</button>
|
|
||||||
<button hx-post="/clicked" hx-trigger="click" hx-target="#parent-div" hx-swap="outerHTML" >is not critter</button>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Loading…
Reference in a new issue