Compare commits
10 Commits
49b6f79545
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 011dfdffc6 | |||
| eca7510eb8 | |||
| 05fc2496d7 | |||
| 0f913ee940 | |||
| 730044f0b7 | |||
| cb2f5732eb | |||
| e44a7672d5 | |||
| 84c6d72faf | |||
| 0ee01bc313 | |||
| 14b0a44117 |
@@ -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 CONCURRENT_ACTIVE = parseInt(process.env.CONCURRENT_ACTIVE || "50", 10)
|
||||||
const TOKEN_TTL_SECONDS = parseInt(process.env.TOKEN_TTL_SECONDS || `${15 * 60}`, 10)
|
const TOKEN_TTL_SECONDS = parseInt(process.env.TOKEN_TTL_SECONDS || `${15 * 60}`, 10)
|
||||||
|
|
||||||
// MySQL kapcsolat
|
// MySQL kapcsolat - minden híváskor új connection
|
||||||
let db = null
|
|
||||||
|
|
||||||
async function getDbConnection() {
|
async function getDbConnection() {
|
||||||
if (!db && process.env.MYSQL_HOST) {
|
if (!process.env.MYSQL_HOST) return null
|
||||||
db = await mysql.createConnection({
|
try {
|
||||||
|
const connection = await mysql.createConnection({
|
||||||
host: process.env.MYSQL_HOST,
|
host: process.env.MYSQL_HOST,
|
||||||
user: process.env.MYSQL_USER,
|
user: process.env.MYSQL_USER,
|
||||||
password: process.env.MYSQL_PASSWORD,
|
password: process.env.MYSQL_PASSWORD,
|
||||||
database: process.env.MYSQL_DATABASE,
|
database: process.env.MYSQL_DATABASE,
|
||||||
})
|
})
|
||||||
|
return connection
|
||||||
|
} catch (error) {
|
||||||
|
console.error('MySQL connection error:', error)
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
return db
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureEvent(eventId) {
|
function ensureEvent(eventId) {
|
||||||
@@ -61,12 +63,17 @@ async function evaluateQueue(eventId, io) {
|
|||||||
const next = ev.queue.shift()
|
const next = ev.queue.shift()
|
||||||
if (!next) break
|
if (!next) break
|
||||||
|
|
||||||
// sign token
|
// Get database time for consistency
|
||||||
const expiresAt = new Date(Date.now() + TOKEN_TTL_SECONDS * 1000)
|
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", {
|
const token = jwt.sign({ sid: next, eventId }, process.env.JWT_SECRET || "dev-secret", {
|
||||||
expiresIn: TOKEN_TTL_SECONDS,
|
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)
|
ev.active.add(next)
|
||||||
|
|
||||||
// Save to database
|
// Save to database
|
||||||
@@ -87,14 +94,32 @@ async function evaluateQueue(eventId, io) {
|
|||||||
// Check for expired tokens in database and notify clients
|
// Check for expired tokens in database and notify clients
|
||||||
if (connection) {
|
if (connection) {
|
||||||
try {
|
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(
|
const [expiredSessions] = await connection.execute(
|
||||||
'SELECT socket_id FROM active_sessions WHERE event_id = ? AND expires_at < NOW()',
|
'SELECT socket_id FROM active_sessions WHERE event_id = ? AND expires_at < NOW()',
|
||||||
[eventId]
|
[eventId]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (expiredSessions.length > 0) {
|
||||||
|
console.log(`Found ${expiredSessions.length} expired sessions for event ${eventId}`)
|
||||||
|
}
|
||||||
|
|
||||||
for (const session of expiredSessions) {
|
for (const session of expiredSessions) {
|
||||||
const sid = session.socket_id
|
const sid = session.socket_id
|
||||||
if (ev.active.has(sid)) {
|
if (ev.active.has(sid)) {
|
||||||
|
console.log(`Sending token_expired to ${sid.substring(0, 8)}`)
|
||||||
ev.active.delete(sid)
|
ev.active.delete(sid)
|
||||||
io.to(sid).emit("token_expired")
|
io.to(sid).emit("token_expired")
|
||||||
}
|
}
|
||||||
@@ -102,6 +127,7 @@ async function evaluateQueue(eventId, io) {
|
|||||||
|
|
||||||
// Clean up expired sessions from database
|
// Clean up expired sessions from database
|
||||||
if (expiredSessions.length > 0) {
|
if (expiredSessions.length > 0) {
|
||||||
|
console.log(`Cleaning up ${expiredSessions.length} expired sessions for event ${eventId}`);
|
||||||
await connection.execute(
|
await connection.execute(
|
||||||
'DELETE FROM active_sessions WHERE event_id = ? AND expires_at < NOW()',
|
'DELETE FROM active_sessions WHERE event_id = ? AND expires_at < NOW()',
|
||||||
[eventId]
|
[eventId]
|
||||||
@@ -136,6 +162,15 @@ async function evaluateQueue(eventId, io) {
|
|||||||
// If queue no longer needed, clear it
|
// If queue no longer needed, clear it
|
||||||
if (ev.sockets.size < QUEUE_THRESHOLD) ev.queueOn = false
|
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
|
// broadcast
|
||||||
broadcastUpdate(eventId, io)
|
broadcastUpdate(eventId, io)
|
||||||
}
|
}
|
||||||
@@ -163,6 +198,18 @@ export async function GET(req) {
|
|||||||
|
|
||||||
global.io = io
|
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
|
// Periodikus token ellenőrzés minden 5 másodpercben
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
for (const eventId of Object.keys(events)) {
|
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 queue is NOT active and user doesn't have access, grant it immediately
|
||||||
if (!ev.queueOn && !ev.active.has(socket.id)) {
|
if (!ev.queueOn && !ev.active.has(socket.id)) {
|
||||||
console.log(`Granting immediate access to ${socket.id} (under threshold)`)
|
console.log(`Granting immediate access to ${socket.id.substring(0, 8)} (under threshold)`)
|
||||||
const expiresAt = new Date(Date.now() + TOKEN_TTL_SECONDS * 1000)
|
|
||||||
|
// 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", {
|
const token = jwt.sign({ sid: socket.id, eventId }, process.env.JWT_SECRET || "dev-secret", {
|
||||||
expiresIn: TOKEN_TTL_SECONDS,
|
expiresIn: TOKEN_TTL_SECONDS,
|
||||||
})
|
})
|
||||||
@@ -263,6 +317,15 @@ export async function GET(req) {
|
|||||||
position: pos === -1 ? null : pos + 1,
|
position: pos === -1 ? null : pos + 1,
|
||||||
estimatedWait: pos === -1 ? null : (ev.active.size + pos) * TOKEN_TTL_SECONDS,
|
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", () => {
|
socket.on("disconnect", () => {
|
||||||
|
|||||||
@@ -15,6 +15,21 @@ export default function EventPage() {
|
|||||||
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
|
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 [connected, setConnected] = useState(false);
|
||||||
const [position, setPosition] = useState<number | null>(null);
|
const [position, setPosition] = useState<number | null>(null);
|
||||||
const [estimatedWait, setEstimatedWait] = useState<number | null>(null);
|
const [estimatedWait, setEstimatedWait] = useState<number | null>(null);
|
||||||
@@ -67,7 +82,8 @@ export default function EventPage() {
|
|||||||
.then(({ io }) => {
|
.then(({ io }) => {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
const socketPort = process.env.NEXT_PUBLIC_SOCKET_PORT || "4000";
|
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
|
autoConnect: true
|
||||||
});
|
});
|
||||||
socketRef.current = socket;
|
socketRef.current = socket;
|
||||||
@@ -91,8 +107,18 @@ export default function EventPage() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on("granted", (data: any) => {
|
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);
|
setHasAccess(true);
|
||||||
setTokenExpiry(data.expiresAt ? Date.parse(data.expiresAt) : Date.now() + 15 * 60 * 1000);
|
setTokenExpiry(expiryTime);
|
||||||
try {
|
try {
|
||||||
localStorage.setItem("event_token", data.token);
|
localStorage.setItem("event_token", data.token);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
@@ -105,11 +131,11 @@ export default function EventPage() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on("token_expired", () => {
|
socket.on("token_expired", () => {
|
||||||
setHasAccess(false);
|
console.log("Token expired received from server");
|
||||||
setTokenExpiry(null);
|
clearAllTokenState();
|
||||||
localStorage.removeItem("event_token");
|
setTimeout(() => {
|
||||||
// Redirect to homepage
|
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
@@ -122,17 +148,10 @@ export default function EventPage() {
|
|||||||
};
|
};
|
||||||
}, [eventId, loading]);
|
}, [eventId, loading]);
|
||||||
|
|
||||||
// Check for existing token on page load
|
// Check for existing token on page load and clear everything
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
try {
|
console.log('Page loaded, clearing any existing token state');
|
||||||
const existingToken = localStorage.getItem("event_token");
|
clearAllTokenState();
|
||||||
if (existingToken) {
|
|
||||||
console.log('Found existing token, clearing it');
|
|
||||||
localStorage.removeItem("event_token");
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log('localStorage access error:', e);
|
|
||||||
}
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Token expiry timer - ellenőrzés minden másodpercben
|
// Token expiry timer - ellenőrzés minden másodpercben
|
||||||
@@ -143,15 +162,11 @@ export default function EventPage() {
|
|||||||
const msLeft = tokenExpiry - Date.now();
|
const msLeft = tokenExpiry - Date.now();
|
||||||
console.log('Token check - ms left:', msLeft);
|
console.log('Token check - ms left:', msLeft);
|
||||||
if (msLeft <= 0) {
|
if (msLeft <= 0) {
|
||||||
console.log('Token expired, redirecting to homepage');
|
console.log('Token expired locally, redirecting to homepage');
|
||||||
setHasAccess(false);
|
clearAllTokenState();
|
||||||
setTokenExpiry(null);
|
setTimeout(() => {
|
||||||
localStorage.removeItem("event_token");
|
|
||||||
// Disconnect socket and redirect to homepage
|
|
||||||
if (socketRef.current) {
|
|
||||||
socketRef.current.disconnect();
|
|
||||||
}
|
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
|
}, 100);
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
return () => clearInterval(id);
|
return () => clearInterval(id);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
/* config options here */
|
allowedDevOrigins: ["10.20.0.188"]
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|||||||
Reference in New Issue
Block a user