Compare commits

...

10 Commits

3 changed files with 115 additions and 37 deletions

View File

@@ -9,19 +9,21 @@ const QUEUE_THRESHOLD = parseInt(process.env.QUEUE_THRESHOLD || "100", 10)
const CONCURRENT_ACTIVE = parseInt(process.env.CONCURRENT_ACTIVE || "50", 10)
const TOKEN_TTL_SECONDS = parseInt(process.env.TOKEN_TTL_SECONDS || `${15 * 60}`, 10)
// MySQL kapcsolat
let db = null
// MySQL kapcsolat - minden híváskor új connection
async function getDbConnection() {
if (!db && process.env.MYSQL_HOST) {
db = await mysql.createConnection({
if (!process.env.MYSQL_HOST) return null
try {
const connection = await mysql.createConnection({
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
})
return connection
} catch (error) {
console.error('MySQL connection error:', error)
return null
}
return db
}
function ensureEvent(eventId) {
@@ -61,12 +63,17 @@ async function evaluateQueue(eventId, io) {
const next = ev.queue.shift()
if (!next) break
// sign token
const expiresAt = new Date(Date.now() + TOKEN_TTL_SECONDS * 1000)
// Get database time for consistency
const [timeRows] = await connection.execute('SELECT NOW() as db_time')
const dbTime = new Date(timeRows[0].db_time)
const expiresAt = new Date(dbTime.getTime() + TOKEN_TTL_SECONDS * 1000)
const token = jwt.sign({ sid: next, eventId }, process.env.JWT_SECRET || "dev-secret", {
expiresIn: TOKEN_TTL_SECONDS,
})
console.log(`Creating queued token for ${next.substring(0, 8)}: DB time ${dbTime.toISOString()}, expires at ${expiresAt.toISOString()}, TTL: ${TOKEN_TTL_SECONDS}s`)
ev.active.add(next)
// Save to database
@@ -87,14 +94,32 @@ async function evaluateQueue(eventId, io) {
// Check for expired tokens in database and notify clients
if (connection) {
try {
// Debug: check current time vs stored times
const [allSessions] = await connection.execute(
'SELECT socket_id, expires_at, NOW() as server_time FROM active_sessions WHERE event_id = ?',
[eventId]
)
console.log(`Event ${eventId} - Current sessions:`, allSessions.map(s => ({
socket: s.socket_id.substring(0, 8),
expires: s.expires_at,
server_time: s.server_time,
expired: new Date(s.expires_at) < new Date(s.server_time)
})))
const [expiredSessions] = await connection.execute(
'SELECT socket_id FROM active_sessions WHERE event_id = ? AND expires_at < NOW()',
[eventId]
)
if (expiredSessions.length > 0) {
console.log(`Found ${expiredSessions.length} expired sessions for event ${eventId}`)
}
for (const session of expiredSessions) {
const sid = session.socket_id
if (ev.active.has(sid)) {
console.log(`Sending token_expired to ${sid.substring(0, 8)}`)
ev.active.delete(sid)
io.to(sid).emit("token_expired")
}
@@ -102,6 +127,7 @@ async function evaluateQueue(eventId, io) {
// Clean up expired sessions from database
if (expiredSessions.length > 0) {
console.log(`Cleaning up ${expiredSessions.length} expired sessions for event ${eventId}`);
await connection.execute(
'DELETE FROM active_sessions WHERE event_id = ? AND expires_at < NOW()',
[eventId]
@@ -136,6 +162,15 @@ async function evaluateQueue(eventId, io) {
// If queue no longer needed, clear it
if (ev.sockets.size < QUEUE_THRESHOLD) ev.queueOn = false
// Close database connection
if (connection) {
try {
await connection.end()
} catch (error) {
console.error('Error closing DB connection:', error)
}
}
// broadcast
broadcastUpdate(eventId, io)
}
@@ -163,6 +198,18 @@ export async function GET(req) {
global.io = io
// Clean up all expired sessions on server start
const startupConnection = await getDbConnection()
if (startupConnection) {
try {
const [result] = await startupConnection.execute('DELETE FROM active_sessions WHERE expires_at < NOW()')
console.log(`Server startup: Cleaned ${result.affectedRows} expired sessions`)
await startupConnection.end()
} catch (error) {
console.error('Cleanup error on startup:', error)
}
}
// Periodikus token ellenőrzés minden 5 másodpercben
setInterval(async () => {
for (const eventId of Object.keys(events)) {
@@ -230,8 +277,15 @@ export async function GET(req) {
// If queue is NOT active and user doesn't have access, grant it immediately
if (!ev.queueOn && !ev.active.has(socket.id)) {
console.log(`Granting immediate access to ${socket.id} (under threshold)`)
const expiresAt = new Date(Date.now() + TOKEN_TTL_SECONDS * 1000)
console.log(`Granting immediate access to ${socket.id.substring(0, 8)} (under threshold)`)
// Get server time from database to ensure consistency
const [timeRows] = await connection.execute('SELECT NOW() as db_time')
const dbTime = new Date(timeRows[0].db_time)
const expiresAt = new Date(dbTime.getTime() + TOKEN_TTL_SECONDS * 1000)
console.log(`DB time: ${dbTime.toISOString()}, Token expires: ${expiresAt.toISOString()}, TTL: ${TOKEN_TTL_SECONDS}s`)
const token = jwt.sign({ sid: socket.id, eventId }, process.env.JWT_SECRET || "dev-secret", {
expiresIn: TOKEN_TTL_SECONDS,
})
@@ -263,6 +317,15 @@ export async function GET(req) {
position: pos === -1 ? null : pos + 1,
estimatedWait: pos === -1 ? null : (ev.active.size + pos) * TOKEN_TTL_SECONDS,
})
// Close database connection
if (connection) {
try {
await connection.end()
} catch (error) {
console.error('Error closing DB connection:', error)
}
}
})
socket.on("disconnect", () => {

View File

@@ -15,6 +15,21 @@ export default function EventPage() {
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
};
// Function to clear all token and queue state
const clearAllTokenState = () => {
console.log("Clearing all token state");
setHasAccess(false);
setTokenExpiry(null);
setPosition(null);
setEstimatedWait(null);
try {
localStorage.removeItem("event_token");
} catch (e) {}
if (socketRef.current) {
socketRef.current.disconnect();
}
};
const [connected, setConnected] = useState(false);
const [position, setPosition] = useState<number | null>(null);
const [estimatedWait, setEstimatedWait] = useState<number | null>(null);
@@ -67,7 +82,8 @@ export default function EventPage() {
.then(({ io }) => {
if (!mounted) return;
const socketPort = process.env.NEXT_PUBLIC_SOCKET_PORT || "4000";
const socket = io(`http://10.20.0.188:${socketPort}`, {
const socketHost = process.env.NEXT_PUBLIC_SOCKET_HOST || window.location.hostname;
const socket = io(`http://${socketHost}:${socketPort}`, {
autoConnect: true
});
socketRef.current = socket;
@@ -91,8 +107,18 @@ export default function EventPage() {
});
socket.on("granted", (data: any) => {
console.log("Granted event received:", data);
const expiryTime = data.expiresAt ? Date.parse(data.expiresAt) : Date.now() + 15 * 60 * 1000;
console.log("Setting token expiry:", {
raw: data.expiresAt,
parsed: new Date(expiryTime),
now: new Date(),
diffMs: expiryTime - Date.now(),
diffMin: Math.round((expiryTime - Date.now()) / 60000)
});
setHasAccess(true);
setTokenExpiry(data.expiresAt ? Date.parse(data.expiresAt) : Date.now() + 15 * 60 * 1000);
setTokenExpiry(expiryTime);
try {
localStorage.setItem("event_token", data.token);
} catch (e) {}
@@ -105,11 +131,11 @@ export default function EventPage() {
});
socket.on("token_expired", () => {
setHasAccess(false);
setTokenExpiry(null);
localStorage.removeItem("event_token");
// Redirect to homepage
window.location.href = "/";
console.log("Token expired received from server");
clearAllTokenState();
setTimeout(() => {
window.location.href = "/";
}, 100);
});
})
.catch(error => {
@@ -122,17 +148,10 @@ export default function EventPage() {
};
}, [eventId, loading]);
// Check for existing token on page load
// Check for existing token on page load and clear everything
useEffect(() => {
try {
const existingToken = localStorage.getItem("event_token");
if (existingToken) {
console.log('Found existing token, clearing it');
localStorage.removeItem("event_token");
}
} catch (e) {
console.log('localStorage access error:', e);
}
console.log('Page loaded, clearing any existing token state');
clearAllTokenState();
}, []);
// Token expiry timer - ellenőrzés minden másodpercben
@@ -143,15 +162,11 @@ export default function EventPage() {
const msLeft = tokenExpiry - Date.now();
console.log('Token check - ms left:', msLeft);
if (msLeft <= 0) {
console.log('Token expired, redirecting to homepage');
setHasAccess(false);
setTokenExpiry(null);
localStorage.removeItem("event_token");
// Disconnect socket and redirect to homepage
if (socketRef.current) {
socketRef.current.disconnect();
}
window.location.href = "/";
console.log('Token expired locally, redirecting to homepage');
clearAllTokenState();
setTimeout(() => {
window.location.href = "/";
}, 100);
}
}, 1000);
return () => clearInterval(id);

View File

@@ -1,7 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
allowedDevOrigins: ["10.20.0.188"]
};
export default nextConfig;