Remove deprecated scripts for adding head-matter to wt_config.xml, including Python and Bash implementations, to streamline configuration management.
This commit is contained in:
865
server/broadcast.js
Normal file
865
server/broadcast.js
Normal file
@@ -0,0 +1,865 @@
|
||||
import crypto from 'crypto';
|
||||
import { readFileSync, writeFileSync, appendFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import axios from 'axios';
|
||||
|
||||
const TIMEOUT_SECONDS = 1800; // 30 Minuten
|
||||
|
||||
class Client {
|
||||
constructor(sessionId) {
|
||||
this.sessionId = sessionId;
|
||||
this.gender = '';
|
||||
this.country = '';
|
||||
this.isoCountryCode = '';
|
||||
this.userName = '';
|
||||
this.age = 0;
|
||||
this.conversations = {};
|
||||
this.lastActivity = new Date();
|
||||
this.loginTimeStamp = new Date();
|
||||
this.blockedUsers = new Set();
|
||||
this.socket = null; // Socket.IO Socket-Objekt
|
||||
}
|
||||
|
||||
setActivity() {
|
||||
this.lastActivity = new Date();
|
||||
}
|
||||
|
||||
activitiesTimedOut() {
|
||||
const secondsSinceActivity = (new Date() - this.lastActivity) / 1000;
|
||||
return secondsSinceActivity > TIMEOUT_SECONDS;
|
||||
}
|
||||
|
||||
remainingSecondsToTimeout() {
|
||||
const secondsSinceActivity = (new Date() - this.lastActivity) / 1000;
|
||||
return Math.max(0, TIMEOUT_SECONDS - secondsSinceActivity);
|
||||
}
|
||||
|
||||
currentlyLoggedInSeconds() {
|
||||
return Math.floor((new Date() - this.loginTimeStamp) / 1000);
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
sessionId: this.sessionId,
|
||||
userName: this.userName,
|
||||
gender: this.gender,
|
||||
country: this.country,
|
||||
isoCountryCode: this.isoCountryCode,
|
||||
age: this.age
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let clients = new Map();
|
||||
let conversations = new Map(); // Key: "user1:user2" (alphabetisch sortiert)
|
||||
|
||||
// Map: Socket-ID -> Express-Session-ID (für Session-Wiederherstellung)
|
||||
let socketToSessionMap = new Map();
|
||||
|
||||
// Exportiere clients Map für Zugriff von außen
|
||||
export function getClientsMap() {
|
||||
return clients;
|
||||
}
|
||||
|
||||
// Exportiere Funktion zum Abrufen der Session-ID für einen Socket
|
||||
export function getSessionIdForSocket(socketId) {
|
||||
return socketToSessionMap.get(socketId);
|
||||
}
|
||||
|
||||
function extractSessionId(handshakeOrRequest) {
|
||||
// Unterstützt sowohl Socket.IO handshake als auch Express request
|
||||
const cookies = handshakeOrRequest.headers?.cookie || handshakeOrRequest.cookies || '';
|
||||
|
||||
console.log('extractSessionId - Cookies:', cookies);
|
||||
|
||||
const sessionMatch = cookies.match(/connect\.sid=([^;]+)/);
|
||||
if (sessionMatch) {
|
||||
let sessionId = sessionMatch[1];
|
||||
|
||||
console.log('extractSessionId - Gefundenes Cookie:', sessionId);
|
||||
|
||||
// Express-Session speichert die Session-ID als signierten Wert: s:xxxxx.signature
|
||||
// Die tatsächliche Session-ID ist nur xxxxx
|
||||
if (sessionId.startsWith('s:')) {
|
||||
const parts = sessionId.split('.');
|
||||
if (parts.length > 0) {
|
||||
sessionId = parts[0].substring(2); // Entferne 's:' Präfix
|
||||
console.log('extractSessionId - Bereinigte Session-ID:', sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
console.log('extractSessionId - Kein connect.sid Cookie gefunden');
|
||||
// Fallback: Generiere temporäre UUID
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
|
||||
// Exportiere Funktion zum Prüfen des Session-Status
|
||||
export function getSessionStatus(req) {
|
||||
// Verwende req.sessionID von Express-Session
|
||||
const sessionId = req.sessionID || extractSessionId(req);
|
||||
|
||||
if (!sessionId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const client = clients.get(sessionId);
|
||||
|
||||
if (!client || !client.userName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
sessionId: client.sessionId,
|
||||
userName: client.userName,
|
||||
gender: client.gender,
|
||||
age: client.age,
|
||||
country: client.country,
|
||||
isoCountryCode: client.isoCountryCode
|
||||
};
|
||||
}
|
||||
|
||||
function getConversationKey(user1, user2) {
|
||||
return [user1, user2].sort().join(':');
|
||||
}
|
||||
|
||||
function logClientLogin(client) {
|
||||
try {
|
||||
const logPath = join(process.cwd(), 'logs', 'logins.log');
|
||||
const logEntry = `${new Date().toISOString()},${client.userName},${client.country},${client.age},${client.gender}\n`;
|
||||
appendFileSync(logPath, logEntry, 'utf-8');
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Loggen des Logins:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function checkAndLogStart() {
|
||||
try {
|
||||
const logPath = join(process.cwd(), 'logs', 'starts.log');
|
||||
const logEntry = `${new Date().toISOString()}\n`;
|
||||
appendFileSync(logPath, logEntry, 'utf-8');
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Loggen des Starts:', error);
|
||||
}
|
||||
}
|
||||
|
||||
export function setupBroadcast(io) {
|
||||
// Länderliste beim Start laden
|
||||
let countriesMap = {};
|
||||
|
||||
async function downloadCountries() {
|
||||
try {
|
||||
const response = await axios.get('https://pkgstore.datahub.io/core/country-list/data_csv/data/d7c9d7cfb42cb69f4422dec222dbbaa8/data_csv.csv');
|
||||
const lines = response.data.split('\n');
|
||||
countriesMap = {};
|
||||
|
||||
// Parse CSV-Zeile mit Berücksichtigung von Anführungszeichen
|
||||
const parseCSVLine = (line) => {
|
||||
const result = [];
|
||||
let current = '';
|
||||
let inQuotes = false;
|
||||
|
||||
for (let i = 0; i < line.length; i++) {
|
||||
const char = line[i];
|
||||
if (char === '"') {
|
||||
// Ignoriere Anführungszeichen, sie werden nicht zum Wert hinzugefügt
|
||||
inQuotes = !inQuotes;
|
||||
} else if (char === ',' && !inQuotes) {
|
||||
result.push(current.trim());
|
||||
current = '';
|
||||
} else {
|
||||
current += char;
|
||||
}
|
||||
}
|
||||
result.push(current.trim());
|
||||
return result;
|
||||
};
|
||||
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (!line) continue;
|
||||
|
||||
const [name, code] = parseCSVLine(line);
|
||||
if (name && code) {
|
||||
// Entferne alle Anführungszeichen (auch am Anfang/Ende)
|
||||
const cleanName = name.replace(/^["']+|["']+$/g, '').replace(/["']/g, '').trim();
|
||||
const cleanCode = code.replace(/^["']+|["']+$/g, '').replace(/["']/g, '').trim();
|
||||
if (cleanName && cleanCode) {
|
||||
countriesMap[cleanName] = cleanCode.toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Länderliste geladen: ${Object.keys(countriesMap).length} Länder`);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Länderliste:', error);
|
||||
}
|
||||
}
|
||||
|
||||
downloadCountries();
|
||||
setInterval(downloadCountries, 24 * 60 * 60 * 1000); // Täglich aktualisieren
|
||||
|
||||
// Socket.IO-Verbindungshandler
|
||||
io.on('connection', (socket) => {
|
||||
const request = socket.handshake;
|
||||
|
||||
// Versuche Session-ID aus Cookie zu extrahieren
|
||||
let sessionId = extractSessionId(request);
|
||||
|
||||
console.log('Socket.IO Connect - Session-ID (aus Cookie):', sessionId);
|
||||
console.log('Socket.IO Connect - Cookie:', request.headers?.cookie);
|
||||
|
||||
// Wenn keine gültige Session-ID gefunden wurde, generiere eine temporäre UUID
|
||||
// Diese wird beim Login durch die Express-Session-ID ersetzt (siehe handleLogin)
|
||||
if (!sessionId || sessionId.length < 10 || !sessionId.match(/^[a-zA-Z0-9_-]+$/)) {
|
||||
sessionId = crypto.randomUUID();
|
||||
console.log('Socket.IO Connect - Keine gültige Session-ID gefunden, verwende temporäre UUID:', sessionId);
|
||||
socket.data.temporarySessionId = true; // Markiere als temporär
|
||||
}
|
||||
|
||||
// Speichere Socket-ID mit Session-ID
|
||||
socket.data.sessionId = sessionId;
|
||||
|
||||
let client = clients.get(sessionId);
|
||||
if (!client) {
|
||||
console.log('Socket.IO Connect - Neuer Client erstellt für Session-ID:', sessionId);
|
||||
client = new Client(sessionId);
|
||||
clients.set(sessionId, client);
|
||||
} else {
|
||||
console.log('Socket.IO Connect - Bestehender Client gefunden für Session-ID:', sessionId, 'User:', client.userName);
|
||||
}
|
||||
|
||||
// Speichere Socket mit Session-ID
|
||||
client.socket = socket;
|
||||
|
||||
// Bestätigung an Client senden, inklusive Benutzerdaten falls bereits eingeloggt
|
||||
const connectedData = { sessionId };
|
||||
if (client.userName) {
|
||||
connectedData.user = {
|
||||
userName: client.userName,
|
||||
gender: client.gender,
|
||||
age: client.age,
|
||||
country: client.country,
|
||||
isoCountryCode: client.isoCountryCode
|
||||
};
|
||||
connectedData.loggedIn = true;
|
||||
}
|
||||
socket.emit('connected', connectedData);
|
||||
|
||||
socket.on('disconnect', (reason) => {
|
||||
const client = clients.get(sessionId);
|
||||
if (client) {
|
||||
// Setze Socket auf null, damit keine Nachrichten mehr an diesen Client gesendet werden
|
||||
// ABER: Lösche den Client NICHT, damit die Session beim Reload wiederhergestellt werden kann
|
||||
client.socket = null;
|
||||
|
||||
// Aktualisiere Benutzerliste, damit andere Clients sehen, dass dieser Benutzer offline ist
|
||||
if (client.userName) {
|
||||
broadcastUserList();
|
||||
}
|
||||
// Client bleibt in der Map, damit Session-Wiederherstellung funktioniert
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('error', (error) => {
|
||||
console.error('Socket.IO-Fehler:', error);
|
||||
});
|
||||
|
||||
// Socket.IO Event-Handler: Setze Express-Session-ID
|
||||
socket.on('setSessionId', (data) => {
|
||||
const { expressSessionId } = data;
|
||||
if (expressSessionId) {
|
||||
console.log('setSessionId - Express-Session-ID erhalten:', expressSessionId);
|
||||
const currentSessionId = socket.data.sessionId;
|
||||
|
||||
if (currentSessionId !== expressSessionId) {
|
||||
console.log('setSessionId - Aktualisiere Session-ID von', currentSessionId, 'zu', expressSessionId);
|
||||
|
||||
// Prüfe, ob bereits ein Client mit dieser Session-ID existiert
|
||||
let existingClient = clients.get(expressSessionId);
|
||||
|
||||
// Wenn kein Client mit dieser Session-ID gefunden wurde, prüfe ob ein Client mit dem aktuellen Socket existiert
|
||||
// und bereits eingeloggt ist (für Session-Wiederherstellung nach Reload)
|
||||
if (!existingClient) {
|
||||
const currentClient = clients.get(currentSessionId);
|
||||
if (currentClient && currentClient.userName) {
|
||||
console.log('setSessionId - Client mit Session-ID', currentSessionId, 'ist bereits eingeloggt:', currentClient.userName);
|
||||
// Verwende bestehenden Client und aktualisiere nur die Session-ID
|
||||
existingClient = currentClient;
|
||||
clients.delete(currentSessionId);
|
||||
clients.set(expressSessionId, existingClient);
|
||||
existingClient.sessionId = expressSessionId;
|
||||
} else {
|
||||
// Wenn kein Client mit der aktuellen Session-ID gefunden wurde, suche nach einem Client,
|
||||
// der bereits eingeloggt ist und keinen aktiven Socket hat (für Session-Wiederherstellung)
|
||||
// Dies ist ein Fallback für den Fall, dass die Session-ID beim Reload geändert wurde
|
||||
for (const [sid, c] of clients.entries()) {
|
||||
if (c.userName && (!c.socket || !c.socket.connected)) {
|
||||
console.log('setSessionId - Gefundener Client ohne aktiven Socket:', sid, c.userName);
|
||||
// Verwende diesen Client und aktualisiere die Session-ID
|
||||
existingClient = c;
|
||||
clients.delete(sid);
|
||||
clients.set(expressSessionId, existingClient);
|
||||
existingClient.sessionId = expressSessionId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (existingClient) {
|
||||
// Verwende bestehenden Client
|
||||
console.log('setSessionId - Verwende bestehenden Client, User:', existingClient.userName || 'nicht eingeloggt');
|
||||
existingClient.socket = socket;
|
||||
socket.data.sessionId = expressSessionId;
|
||||
|
||||
// Entferne alten Client, falls unterschiedlich
|
||||
if (currentSessionId !== expressSessionId && clients.has(currentSessionId)) {
|
||||
clients.delete(currentSessionId);
|
||||
}
|
||||
|
||||
// Sende Login-Status zurück, falls bereits eingeloggt
|
||||
if (existingClient.userName) {
|
||||
console.log('setSessionId - Sende Login-Status zurück für User:', existingClient.userName);
|
||||
socket.emit('connected', {
|
||||
sessionId: expressSessionId,
|
||||
loggedIn: true,
|
||||
user: existingClient.toJSON()
|
||||
});
|
||||
|
||||
// Aktualisiere Userliste für alle Clients, damit der wiederhergestellte Client die Liste erhält
|
||||
broadcastUserList();
|
||||
}
|
||||
} else {
|
||||
// Erstelle neuen Client mit Express-Session-ID
|
||||
console.log('setSessionId - Erstelle neuen Client');
|
||||
const newClient = new Client(expressSessionId);
|
||||
newClient.socket = socket;
|
||||
clients.set(expressSessionId, newClient);
|
||||
socket.data.sessionId = expressSessionId;
|
||||
|
||||
// Entferne alten Client
|
||||
if (clients.has(currentSessionId)) {
|
||||
clients.delete(currentSessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Socket.IO Event-Handler
|
||||
// WICHTIG: Hole den Client immer dynamisch basierend auf socket.data.sessionId,
|
||||
// da sich die Session-ID nach setSessionId ändern kann
|
||||
socket.on('login', async (data) => {
|
||||
try {
|
||||
const currentClient = clients.get(socket.data.sessionId);
|
||||
if (!currentClient) {
|
||||
socket.emit('error', { message: 'Client nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
currentClient.setActivity();
|
||||
await handleLogin(socket, currentClient, data);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Verarbeiten der Login-Nachricht:', error);
|
||||
socket.emit('error', { message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('message', async (data) => {
|
||||
try {
|
||||
const currentClient = clients.get(socket.data.sessionId);
|
||||
if (!currentClient) {
|
||||
socket.emit('error', { message: 'Client nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
currentClient.setActivity();
|
||||
handleMessage(socket, currentClient, data);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Verarbeiten der Message-Nachricht:', error);
|
||||
socket.emit('error', { message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('requestConversation', async (data) => {
|
||||
try {
|
||||
const currentClient = clients.get(socket.data.sessionId);
|
||||
if (!currentClient) {
|
||||
socket.emit('error', { message: 'Client nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
currentClient.setActivity();
|
||||
handleRequestConversation(socket, currentClient, data);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Verarbeiten der RequestConversation-Nachricht:', error);
|
||||
socket.emit('error', { message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('userSearch', async (data) => {
|
||||
try {
|
||||
const currentClient = clients.get(socket.data.sessionId);
|
||||
if (!currentClient) {
|
||||
socket.emit('error', { message: 'Client nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
currentClient.setActivity();
|
||||
handleUserSearch(socket, currentClient, data);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Verarbeiten der UserSearch-Nachricht:', error);
|
||||
socket.emit('error', { message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('requestHistory', async () => {
|
||||
try {
|
||||
const currentClient = clients.get(socket.data.sessionId);
|
||||
if (!currentClient) {
|
||||
socket.emit('error', { message: 'Client nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
currentClient.setActivity();
|
||||
handleRequestHistory(socket, currentClient);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Verarbeiten der RequestHistory-Nachricht:', error);
|
||||
socket.emit('error', { message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('requestOpenConversations', async () => {
|
||||
try {
|
||||
const currentClient = clients.get(socket.data.sessionId);
|
||||
if (!currentClient) {
|
||||
socket.emit('error', { message: 'Client nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
currentClient.setActivity();
|
||||
handleRequestOpenConversations(socket, currentClient);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Verarbeiten der RequestOpenConversations-Nachricht:', error);
|
||||
socket.emit('error', { message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('blockUser', async (data) => {
|
||||
try {
|
||||
const currentClient = clients.get(socket.data.sessionId);
|
||||
if (!currentClient) {
|
||||
socket.emit('error', { message: 'Client nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
currentClient.setActivity();
|
||||
handleBlockUser(socket, currentClient, data);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Verarbeiten der BlockUser-Nachricht:', error);
|
||||
socket.emit('error', { message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('unblockUser', async (data) => {
|
||||
try {
|
||||
const currentClient = clients.get(socket.data.sessionId);
|
||||
if (!currentClient) {
|
||||
socket.emit('error', { message: 'Client nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
currentClient.setActivity();
|
||||
handleUnblockUser(socket, currentClient, data);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Verarbeiten der UnblockUser-Nachricht:', error);
|
||||
socket.emit('error', { message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
async function handleLogin(socket, client, data) {
|
||||
const { userName, gender, age, country, expressSessionId } = data;
|
||||
|
||||
// Validierung
|
||||
if (!userName || userName.trim().length < 3) {
|
||||
socket.emit('error', { message: 'Benutzername muss mindestens 3 Zeichen lang sein' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Wenn eine Express-Session-ID übergeben wurde, verwende diese statt der Socket-ID
|
||||
if (expressSessionId) {
|
||||
console.log('handleLogin - Express-Session-ID erhalten:', expressSessionId);
|
||||
|
||||
// Entferne alten Client mit temporärer Socket-ID, falls vorhanden
|
||||
const oldSessionId = socket.data.sessionId;
|
||||
if (oldSessionId && oldSessionId !== expressSessionId && clients.has(oldSessionId)) {
|
||||
console.log('handleLogin - Entferne alten Client mit Session-ID:', oldSessionId);
|
||||
clients.delete(oldSessionId);
|
||||
}
|
||||
|
||||
// Prüfe, ob bereits ein Client mit dieser Session-ID existiert
|
||||
let existingClient = clients.get(expressSessionId);
|
||||
if (existingClient) {
|
||||
// Verwende bestehenden Client
|
||||
console.log('handleLogin - Verwende bestehenden Client mit Session-ID:', expressSessionId);
|
||||
client = existingClient;
|
||||
// Aktualisiere Socket-Verbindung
|
||||
client.socket = socket;
|
||||
socket.data.sessionId = expressSessionId;
|
||||
} else {
|
||||
// Erstelle neuen Client mit Express-Session-ID
|
||||
console.log('handleLogin - Erstelle neuen Client mit Session-ID:', expressSessionId);
|
||||
client = new Client(expressSessionId);
|
||||
clients.set(expressSessionId, client);
|
||||
client.socket = socket;
|
||||
socket.data.sessionId = expressSessionId;
|
||||
}
|
||||
} else {
|
||||
console.log('handleLogin - Keine Express-Session-ID erhalten, verwende Socket-ID');
|
||||
}
|
||||
|
||||
// Prüfe, ob Name bereits verwendet wird
|
||||
for (const [sid, c] of clients.entries()) {
|
||||
if (c.userName === userName && sid !== client.sessionId) {
|
||||
socket.emit('error', { message: 'Dieser Benutzername ist bereits vergeben' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
client.userName = userName.trim();
|
||||
client.gender = gender;
|
||||
client.age = age;
|
||||
client.country = country;
|
||||
|
||||
// ISO-Code aus Länderliste ermitteln
|
||||
client.isoCountryCode = countriesMap[country] || 'unknown';
|
||||
|
||||
client.loginTimeStamp = new Date();
|
||||
client.setActivity();
|
||||
|
||||
// Stelle sicher, dass der Socket gesetzt ist
|
||||
if (!client.socket) {
|
||||
console.log('handleLogin - WARNUNG: Socket nicht gesetzt, setze ihn jetzt');
|
||||
client.socket = socket;
|
||||
}
|
||||
|
||||
console.log('handleLogin - Client nach Login:', {
|
||||
sessionId: client.sessionId,
|
||||
userName: client.userName,
|
||||
hasSocket: !!client.socket,
|
||||
socketConnected: client.socket ? client.socket.connected : false
|
||||
});
|
||||
|
||||
logClientLogin(client);
|
||||
checkAndLogStart();
|
||||
|
||||
// Benutzerliste an alle senden
|
||||
broadcastUserList();
|
||||
|
||||
// Aktualisiere ungelesene Nachrichten für den neuen Benutzer
|
||||
updateUnreadCount(client);
|
||||
|
||||
console.log('handleLogin - Sende loginSuccess an Socket');
|
||||
socket.emit('loginSuccess', {
|
||||
sessionId: client.sessionId,
|
||||
user: client.toJSON()
|
||||
});
|
||||
}
|
||||
|
||||
function handleMessage(socket, client, data) {
|
||||
if (!client.userName) {
|
||||
socket.emit('error', { message: 'Nicht eingeloggt' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { toUserName, message, messageId, isImage, imageType } = data;
|
||||
|
||||
if (!toUserName) {
|
||||
socket.emit('error', { message: 'Empfänger fehlt' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Finde Empfänger
|
||||
let receiver = null;
|
||||
for (const [sid, c] of clients.entries()) {
|
||||
if (c.userName === toUserName) {
|
||||
receiver = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!receiver) {
|
||||
socket.emit('error', { message: 'Benutzer nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Prüfe, ob Empfänger noch verbunden ist
|
||||
if (!receiver.socket || !receiver.socket.connected) {
|
||||
// Empfänger ist nicht mehr verbunden, entferne ihn aus der Liste
|
||||
clients.delete(receiver.sessionId);
|
||||
broadcastUserList();
|
||||
socket.emit('error', { message: 'Benutzer nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Prüfe Blockierung
|
||||
if (receiver.blockedUsers.has(client.userName)) {
|
||||
socket.emit('error', { message: 'Du wurdest von diesem Benutzer blockiert' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Speichere Nachricht in Konversation
|
||||
const convKey = getConversationKey(client.userName, toUserName);
|
||||
if (!conversations.has(convKey)) {
|
||||
conversations.set(convKey, []);
|
||||
}
|
||||
|
||||
const conversation = conversations.get(convKey);
|
||||
conversation.push({
|
||||
from: client.userName,
|
||||
to: toUserName,
|
||||
message,
|
||||
messageId,
|
||||
timestamp: new Date().toISOString(),
|
||||
read: false,
|
||||
isImage: isImage || false,
|
||||
imageType: imageType || null
|
||||
});
|
||||
|
||||
// Sende an Empfänger (wenn online)
|
||||
receiver.socket.emit('message', {
|
||||
from: client.userName,
|
||||
message,
|
||||
messageId,
|
||||
timestamp: new Date().toISOString(),
|
||||
isImage: isImage || false,
|
||||
imageType: imageType || null
|
||||
});
|
||||
|
||||
// Bestätigung an Absender
|
||||
socket.emit('messageSent', {
|
||||
messageId,
|
||||
to: toUserName
|
||||
});
|
||||
|
||||
// Aktualisiere ungelesene Nachrichten für den Empfänger
|
||||
updateUnreadCount(receiver);
|
||||
}
|
||||
|
||||
function handleRequestConversation(socket, client, data) {
|
||||
if (!client.userName) {
|
||||
socket.emit('error', { message: 'Nicht eingeloggt' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { withUserName } = data;
|
||||
const convKey = getConversationKey(client.userName, withUserName);
|
||||
const conversation = conversations.get(convKey) || [];
|
||||
|
||||
// Markiere alle Nachrichten von diesem Benutzer als gelesen
|
||||
for (const msg of conversation) {
|
||||
if (msg.to === client.userName && msg.from === withUserName) {
|
||||
msg.read = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Aktualisiere ungelesene Nachrichten nach dem Markieren als gelesen
|
||||
updateUnreadCount(client);
|
||||
|
||||
socket.emit('conversation', {
|
||||
with: withUserName,
|
||||
messages: conversation.map(msg => ({
|
||||
from: msg.from,
|
||||
message: msg.message,
|
||||
timestamp: msg.timestamp,
|
||||
isImage: msg.isImage || false,
|
||||
imageType: msg.imageType || null
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
function handleUserSearch(socket, client, data) {
|
||||
if (!client.userName) {
|
||||
socket.emit('error', { message: 'Nicht eingeloggt' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { nameIncludes, minAge, maxAge, countries, genders } = data;
|
||||
|
||||
const results = [];
|
||||
for (const [sid, c] of clients.entries()) {
|
||||
if (!c.userName || c.userName === client.userName) continue;
|
||||
|
||||
// Name-Filter
|
||||
if (nameIncludes && !c.userName.toLowerCase().includes(nameIncludes.toLowerCase())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Alter-Filter
|
||||
if (minAge && c.age < minAge) continue;
|
||||
if (maxAge && c.age > maxAge) continue;
|
||||
|
||||
// Länder-Filter
|
||||
if (countries && countries.length > 0 && !countries.includes(c.country)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Geschlecht-Filter
|
||||
if (genders && genders.length > 0 && !genders.includes(c.gender)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.push(c.toJSON());
|
||||
}
|
||||
|
||||
socket.emit('searchResults', {
|
||||
results
|
||||
});
|
||||
}
|
||||
|
||||
function handleRequestHistory(socket, client) {
|
||||
if (!client.userName) {
|
||||
socket.emit('error', { message: 'Nicht eingeloggt' });
|
||||
return;
|
||||
}
|
||||
|
||||
const history = [];
|
||||
for (const [convKey, messages] of conversations.entries()) {
|
||||
const [user1, user2] = convKey.split(':');
|
||||
if (user1 === client.userName || user2 === client.userName) {
|
||||
const otherUser = user1 === client.userName ? user2 : user1;
|
||||
history.push({
|
||||
userName: otherUser,
|
||||
lastMessage: messages.length > 0 ? messages[messages.length - 1] : null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit('historyResults', {
|
||||
results: history
|
||||
});
|
||||
}
|
||||
|
||||
function handleRequestOpenConversations(socket, client) {
|
||||
if (!client.userName) {
|
||||
socket.emit('error', { message: 'Nicht eingeloggt' });
|
||||
return;
|
||||
}
|
||||
|
||||
const inbox = [];
|
||||
for (const [convKey, messages] of conversations.entries()) {
|
||||
const [user1, user2] = convKey.split(':');
|
||||
if (user1 === client.userName || user2 === client.userName) {
|
||||
const otherUser = user1 === client.userName ? user2 : user1;
|
||||
const unreadCount = messages.filter(m =>
|
||||
m.to === client.userName && !m.read
|
||||
).length;
|
||||
|
||||
if (unreadCount > 0) {
|
||||
inbox.push({
|
||||
userName: otherUser,
|
||||
unreadCount
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
socket.emit('inboxResults', {
|
||||
results: inbox
|
||||
});
|
||||
}
|
||||
|
||||
function handleBlockUser(socket, client, data) {
|
||||
if (!client.userName) {
|
||||
socket.emit('error', { message: 'Nicht eingeloggt' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { userName } = data;
|
||||
client.blockedUsers.add(userName);
|
||||
|
||||
socket.emit('userBlocked', {
|
||||
userName
|
||||
});
|
||||
}
|
||||
|
||||
function handleUnblockUser(socket, client, data) {
|
||||
if (!client.userName) {
|
||||
socket.emit('error', { message: 'Nicht eingeloggt' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { userName } = data;
|
||||
client.blockedUsers.delete(userName);
|
||||
|
||||
socket.emit('userUnblocked', {
|
||||
userName
|
||||
});
|
||||
}
|
||||
|
||||
function updateUnreadCount(client) {
|
||||
if (!client.userName || !client.socket || !client.socket.connected) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Zähle Personen mit ungelesenen Nachrichten für diesen Benutzer
|
||||
let unreadPersons = 0;
|
||||
for (const [convKey, messages] of conversations.entries()) {
|
||||
const [user1, user2] = convKey.split(':');
|
||||
if (user1 === client.userName || user2 === client.userName) {
|
||||
const unreadCount = messages.filter(m =>
|
||||
m.to === client.userName && !m.read
|
||||
).length;
|
||||
if (unreadCount > 0) {
|
||||
unreadPersons++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sende Update an Client
|
||||
client.socket.emit('unreadChats', {
|
||||
count: unreadPersons
|
||||
});
|
||||
}
|
||||
|
||||
function broadcastUserList() {
|
||||
// Filtere nur eingeloggte Benutzer mit aktiver Verbindung
|
||||
const userList = Array.from(clients.values())
|
||||
.filter(c => {
|
||||
const hasUserName = !!c.userName;
|
||||
const hasSocket = !!c.socket;
|
||||
const isConnected = c.socket && c.socket.connected;
|
||||
if (hasUserName && (!hasSocket || !isConnected)) {
|
||||
console.log('broadcastUserList - Client ohne Socket oder nicht verbunden:', c.userName, 'socket:', hasSocket, 'connected:', isConnected);
|
||||
}
|
||||
return hasUserName && hasSocket && isConnected;
|
||||
})
|
||||
.map(c => c.toJSON());
|
||||
|
||||
console.log('broadcastUserList - Sende Userliste mit', userList.length, 'Benutzern:', userList.map(u => u.userName));
|
||||
|
||||
// Sende an alle verbundenen Clients
|
||||
io.emit('userList', {
|
||||
users: userList
|
||||
});
|
||||
}
|
||||
|
||||
function broadcastToUser(userName, data) {
|
||||
// Finde den Client mit diesem Benutzernamen und sende die Nachricht
|
||||
for (const [sid, c] of clients.entries()) {
|
||||
if (c.userName === userName && c.socket) {
|
||||
c.socket.emit(data.type, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Timeout-Check alle 60 Sekunden
|
||||
setInterval(() => {
|
||||
for (const [sid, client] of clients.entries()) {
|
||||
if (client.activitiesTimedOut()) {
|
||||
console.log(`Client ${client.userName} hat Timeout erreicht`);
|
||||
clients.delete(sid);
|
||||
broadcastUserList();
|
||||
}
|
||||
}
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
130
server/index.js
Normal file
130
server/index.js
Normal file
@@ -0,0 +1,130 @@
|
||||
import express from 'express';
|
||||
import { createServer } from 'http';
|
||||
import { Server as SocketIOServer } from 'socket.io';
|
||||
import cookieParser from 'cookie-parser';
|
||||
import session from 'express-session';
|
||||
import cors from 'cors';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
import { setupBroadcast } from './broadcast.js';
|
||||
import { setupRoutes } from './routes.js';
|
||||
import { setupSEORoutes } from './routes-seo.js';
|
||||
import { setupSEORoutes } from './routes-seo.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const app = express();
|
||||
const server = createServer(app);
|
||||
|
||||
// Umgebungsvariablen
|
||||
const NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
const PORT = process.env.PORT || (NODE_ENV === 'production' ? 4000 : 3300);
|
||||
const IS_PRODUCTION = NODE_ENV === 'production';
|
||||
|
||||
// CORS-Origins konfigurieren
|
||||
const allowedOrigins = IS_PRODUCTION
|
||||
? ['https://ypchat.net', 'https://www.ypchat.net']
|
||||
: ['http://localhost:5175', 'http://127.0.0.1:5175'];
|
||||
|
||||
// Socket.IO auf dem gleichen HTTP-Server wie Express
|
||||
const io = new SocketIOServer(server, {
|
||||
cors: {
|
||||
origin: allowedOrigins,
|
||||
credentials: true,
|
||||
methods: ['GET', 'POST']
|
||||
},
|
||||
transports: ['websocket', 'polling'],
|
||||
allowEIO3: true
|
||||
});
|
||||
|
||||
console.log('Socket.IO Server initialisiert auf Express-Server');
|
||||
console.log('Umgebung:', NODE_ENV);
|
||||
console.log('CORS erlaubt für:', allowedOrigins);
|
||||
|
||||
// CORS-Konfiguration
|
||||
app.use(cors({
|
||||
origin: (origin, callback) => {
|
||||
// Erlaube Requests ohne Origin (z.B. Postman, mobile Apps)
|
||||
if (!origin) return callback(null, true);
|
||||
|
||||
if (allowedOrigins.includes(origin) || !IS_PRODUCTION) {
|
||||
callback(null, true);
|
||||
} else {
|
||||
callback(new Error('Nicht erlaubt durch CORS'));
|
||||
}
|
||||
},
|
||||
credentials: true,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization']
|
||||
}));
|
||||
|
||||
// Middleware
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(cookieParser());
|
||||
|
||||
// Session-Konfiguration
|
||||
const sessionSecret = process.env.SESSION_SECRET || 'singlechat-secret-key-change-in-production';
|
||||
app.use(session({
|
||||
secret: sessionSecret,
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
cookie: {
|
||||
secure: IS_PRODUCTION, // true für HTTPS in Production
|
||||
httpOnly: true,
|
||||
maxAge: 24 * 60 * 60 * 1000, // 24 Stunden
|
||||
sameSite: IS_PRODUCTION ? 'lax' : false // Lax für HTTPS, false für Development
|
||||
}
|
||||
}));
|
||||
|
||||
// Trust Proxy für Apache Reverse Proxy (muss vor Routes stehen)
|
||||
if (IS_PRODUCTION) {
|
||||
app.set('trust proxy', 1); // Vertraue dem ersten Proxy (Apache)
|
||||
}
|
||||
|
||||
// Statische Dateien aus docroot
|
||||
app.use('/static', express.static(join(__dirname, '../docroot')));
|
||||
|
||||
// SEO-Routes (robots.txt, sitemap.xml, Pre-Rendering)
|
||||
// Müssen vor anderen Routes stehen, damit sie nicht vom SPA-Fallback abgefangen werden
|
||||
setupSEORoutes(app, __dirname);
|
||||
|
||||
// API Routes (müssen vor SPA-Fallback stehen)
|
||||
setupRoutes(app, __dirname);
|
||||
|
||||
// Socket.IO-Handling
|
||||
setupBroadcast(io);
|
||||
|
||||
// In Production: Serviere auch die gebauten Client-Dateien
|
||||
// SPA-Fallback muss nach allen anderen Routen stehen
|
||||
if (IS_PRODUCTION) {
|
||||
const distPath = join(__dirname, '../docroot/dist');
|
||||
app.use(express.static(distPath));
|
||||
// Fallback für Vue Router (SPA) - muss am Ende stehen
|
||||
app.get('*', (req, res) => {
|
||||
// Überspringe SEO-Routes in Production (werden bereits von setupSEORoutes behandelt)
|
||||
if (IS_PRODUCTION && (req.path === '/' || req.path === '/partners')) {
|
||||
return; // Route wurde bereits behandelt
|
||||
}
|
||||
// Nur für nicht-API und nicht-static Requests
|
||||
if (!req.path.startsWith('/api') && !req.path.startsWith('/static') && req.path !== '/robots.txt' && req.path !== '/sitemap.xml') {
|
||||
res.sendFile(join(distPath, 'index.html'));
|
||||
} else {
|
||||
res.status(404).send('Not found');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Server starten
|
||||
const HOST = '127.0.0.1'; // Nur localhost, da Apache als Reverse Proxy fungiert
|
||||
|
||||
server.listen(PORT, HOST, () => {
|
||||
console.log(`Server läuft auf http://${HOST}:${PORT}`);
|
||||
console.log(`Umgebung: ${NODE_ENV}`);
|
||||
console.log(`CORS erlaubt für: ${allowedOrigins.join(', ')}`);
|
||||
if (IS_PRODUCTION) {
|
||||
console.log('Production-Modus: HTTPS über Apache Reverse Proxy');
|
||||
}
|
||||
});
|
||||
|
||||
126
server/routes-seo.js
Normal file
126
server/routes-seo.js
Normal file
@@ -0,0 +1,126 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
// SEO-Meta-Daten für verschiedene Routen
|
||||
const seoData = {
|
||||
'/': {
|
||||
title: 'SingleChat - Chat, Single-Chat und Bildaustausch',
|
||||
description: 'Willkommen auf SingleChat - deine erste Adresse für Chat, Single-Chat und Bildaustausch. Chatte mit Menschen aus aller Welt, finde neue Kontakte und teile Erinnerungen sicher und komfortabel.',
|
||||
keywords: 'Chat, Single-Chat, Bildaustausch, Online-Chat, Singles, Kontakte, Community',
|
||||
ogTitle: 'SingleChat - Chat, Single-Chat und Bildaustausch',
|
||||
ogDescription: 'Willkommen auf SingleChat - deine erste Adresse für Chat, Single-Chat und Bildaustausch.',
|
||||
ogType: 'website',
|
||||
ogUrl: 'https://ypchat.net/',
|
||||
ogImage: 'https://ypchat.net/static/favicon.png'
|
||||
},
|
||||
'/partners': {
|
||||
title: 'Partner - SingleChat',
|
||||
description: 'Unsere Partner und befreundete Seiten. Entdecke weitere interessante Angebote und Communities.',
|
||||
keywords: 'Partner, Links, befreundete Seiten, Community',
|
||||
ogTitle: 'Partner - SingleChat',
|
||||
ogDescription: 'Unsere Partner und befreundete Seiten.',
|
||||
ogType: 'website',
|
||||
ogUrl: 'https://ypchat.net/partners',
|
||||
ogImage: 'https://ypchat.net/static/favicon.png'
|
||||
}
|
||||
};
|
||||
|
||||
// HTML-Template für Pre-Rendering
|
||||
function generateHTML(route, meta) {
|
||||
const baseHTML = `<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<!-- SEO Meta Tags -->
|
||||
<title>${meta.title}</title>
|
||||
<meta name="description" content="${meta.description}">
|
||||
<meta name="keywords" content="${meta.keywords}">
|
||||
<meta name="robots" content="index, follow">
|
||||
|
||||
<!-- Open Graph Tags -->
|
||||
<meta property="og:title" content="${meta.ogTitle}">
|
||||
<meta property="og:description" content="${meta.ogDescription}">
|
||||
<meta property="og:type" content="${meta.ogType}">
|
||||
<meta property="og:url" content="${meta.ogUrl}">
|
||||
<meta property="og:image" content="${meta.ogImage}">
|
||||
|
||||
<!-- Twitter Card -->
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="${meta.ogTitle}">
|
||||
<meta name="twitter:description" content="${meta.ogDescription}">
|
||||
<meta name="twitter:image" content="${meta.ogImage}">
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href="${meta.ogUrl}">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="/static/favicon.png">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
return baseHTML;
|
||||
}
|
||||
|
||||
export function setupSEORoutes(app, __dirname) {
|
||||
// Pre-Rendering für SEO-relevante Routen (nur in Production)
|
||||
// In Development wird die normale index.html verwendet
|
||||
const IS_PRODUCTION = process.env.NODE_ENV === 'production';
|
||||
|
||||
if (IS_PRODUCTION) {
|
||||
// Pre-Rendering für Hauptseite
|
||||
app.get('/', (req, res) => {
|
||||
const meta = seoData['/'];
|
||||
const html = generateHTML('/', meta);
|
||||
res.send(html);
|
||||
});
|
||||
|
||||
// Pre-Rendering für Partners-Seite
|
||||
app.get('/partners', (req, res) => {
|
||||
const meta = seoData['/partners'];
|
||||
const html = generateHTML('/partners', meta);
|
||||
res.send(html);
|
||||
});
|
||||
}
|
||||
|
||||
// robots.txt
|
||||
app.get('/robots.txt', (req, res) => {
|
||||
const robotsTxt = `User-agent: *
|
||||
Allow: /
|
||||
Allow: /partners
|
||||
Disallow: /api/
|
||||
Disallow: /static/logs/
|
||||
|
||||
Sitemap: https://ypchat.net/sitemap.xml
|
||||
`;
|
||||
res.type('text/plain');
|
||||
res.send(robotsTxt);
|
||||
});
|
||||
|
||||
// sitemap.xml
|
||||
app.get('/sitemap.xml', (req, res) => {
|
||||
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://ypchat.net/</loc>
|
||||
<lastmod>${new Date().toISOString().split('T')[0]}</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
<priority>1.0</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://ypchat.net/partners</loc>
|
||||
<lastmod>${new Date().toISOString().split('T')[0]}</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.8</priority>
|
||||
</url>
|
||||
</urlset>`;
|
||||
res.type('application/xml');
|
||||
res.send(sitemap);
|
||||
});
|
||||
}
|
||||
|
||||
160
server/routes.js
Normal file
160
server/routes.js
Normal file
@@ -0,0 +1,160 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { parse } from 'csv-parse/sync';
|
||||
|
||||
import axios from 'axios';
|
||||
import { getSessionStatus, getClientsMap, getSessionIdForSocket } from './broadcast.js';
|
||||
|
||||
export function setupRoutes(app, __dirname) {
|
||||
// Health-Check-Endpoint
|
||||
app.get('/api/health', (req, res) => {
|
||||
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
||||
});
|
||||
|
||||
// Session-Status-Endpoint
|
||||
app.get('/api/session', (req, res) => {
|
||||
try {
|
||||
const sessionId = req.sessionID;
|
||||
console.log('Session-Check - SessionID:', sessionId);
|
||||
console.log('Session-Check - Alle Clients:', Array.from(getClientsMap().keys()));
|
||||
|
||||
// Prüfe zuerst in der clients Map
|
||||
const clientsMap = getClientsMap();
|
||||
let client = clientsMap.get(sessionId);
|
||||
|
||||
// Wenn kein Client mit dieser Session-ID gefunden wurde, aber es gibt Clients,
|
||||
// die bereits eingeloggt sind, könnte es sein, dass die Session-ID beim Reload geändert wurde.
|
||||
// In diesem Fall sollten wir den Client mit der Express-Session-ID verknüpfen.
|
||||
// Aber wir können nicht sicher sein, welcher Client zu welcher Session gehört,
|
||||
// daher geben wir einfach die Session-ID zurück und lassen den Client beim setSessionId
|
||||
// den richtigen Client finden.
|
||||
|
||||
if (client && client.userName) {
|
||||
console.log('Session-Check - Client gefunden:', client.userName);
|
||||
res.json({
|
||||
loggedIn: true,
|
||||
sessionId: sessionId, // Wichtig: Sende Session-ID zurück
|
||||
user: {
|
||||
sessionId: client.sessionId,
|
||||
userName: client.userName,
|
||||
gender: client.gender,
|
||||
age: client.age,
|
||||
country: client.country,
|
||||
isoCountryCode: client.isoCountryCode
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('Session-Check - Kein Client gefunden für SessionID:', sessionId);
|
||||
// Prüfe auch alle Clients, um zu sehen, ob es ein Mismatch gibt
|
||||
for (const [sid, c] of clientsMap.entries()) {
|
||||
if (c.userName) {
|
||||
console.log('Session-Check - Gefundener Client:', sid, c.userName);
|
||||
}
|
||||
}
|
||||
// Sende Session-ID zurück, auch wenn nicht eingeloggt (für Login)
|
||||
res.json({ loggedIn: false, sessionId: sessionId });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Prüfen der Session:', error);
|
||||
res.json({ loggedIn: false });
|
||||
}
|
||||
});
|
||||
|
||||
// Länderliste-Endpoint
|
||||
app.get('/api/countries', async (req, res) => {
|
||||
try {
|
||||
// Versuche zuerst, die CSV-Datei zu laden
|
||||
const csvPath = join(__dirname, '../docroot/countries.csv');
|
||||
let countries = {};
|
||||
|
||||
try {
|
||||
const fileContent = readFileSync(csvPath, 'utf-8');
|
||||
const records = parse(fileContent, {
|
||||
columns: true,
|
||||
skip_empty_lines: true,
|
||||
quote: '"',
|
||||
trim: true,
|
||||
relax_quotes: true,
|
||||
relax_column_count: true
|
||||
});
|
||||
|
||||
records.forEach(record => {
|
||||
if (record.Name && record.Code) {
|
||||
// Entferne alle Anführungszeichen (auch am Anfang/Ende)
|
||||
const name = record.Name.replace(/^["']+|["']+$/g, '').replace(/["']/g, '').trim();
|
||||
const code = record.Code.replace(/^["']+|["']+$/g, '').replace(/["']/g, '').trim();
|
||||
if (name && code) {
|
||||
countries[name] = code.toLowerCase();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (fileError) {
|
||||
// Wenn die Datei nicht existiert, lade von der URL
|
||||
console.log('CSV-Datei nicht gefunden, lade von URL...');
|
||||
const response = await axios.get('https://pkgstore.datahub.io/core/country-list/data_csv/data/d7c9d7cfb42cb69f4422dec222dbbaa8/data_csv.csv');
|
||||
const lines = response.data.split('\n');
|
||||
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (!line) continue;
|
||||
|
||||
// Parse CSV-Zeile mit Berücksichtigung von Anführungszeichen
|
||||
const parseCSVLine = (line) => {
|
||||
const result = [];
|
||||
let current = '';
|
||||
let inQuotes = false;
|
||||
|
||||
for (let i = 0; i < line.length; i++) {
|
||||
const char = line[i];
|
||||
if (char === '"') {
|
||||
// Ignoriere Anführungszeichen, sie werden nicht zum Wert hinzugefügt
|
||||
inQuotes = !inQuotes;
|
||||
} else if (char === ',' && !inQuotes) {
|
||||
result.push(current.trim());
|
||||
current = '';
|
||||
} else {
|
||||
current += char;
|
||||
}
|
||||
}
|
||||
result.push(current.trim());
|
||||
return result;
|
||||
};
|
||||
|
||||
const [name, code] = parseCSVLine(line);
|
||||
if (name && code) {
|
||||
// Entferne alle Anführungszeichen (auch am Anfang/Ende)
|
||||
const cleanName = name.replace(/^["']+|["']+$/g, '').replace(/["']/g, '').trim();
|
||||
const cleanCode = code.replace(/^["']+|["']+$/g, '').replace(/["']/g, '').trim();
|
||||
if (cleanName && cleanCode) {
|
||||
countries[cleanName] = cleanCode.toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.json(countries);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Länderliste:', error);
|
||||
res.status(500).json({ error: 'Fehler beim Laden der Länderliste' });
|
||||
}
|
||||
});
|
||||
|
||||
// Partners-Links
|
||||
app.get('/api/partners', (req, res) => {
|
||||
try {
|
||||
const csvPath = join(__dirname, '../docroot/links.csv');
|
||||
const fileContent = readFileSync(csvPath, 'utf-8');
|
||||
const records = parse(fileContent, {
|
||||
columns: true,
|
||||
skip_empty_lines: true,
|
||||
quote: '"'
|
||||
});
|
||||
|
||||
res.json(records);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Partner-Links:', error);
|
||||
res.status(500).json({ error: 'Fehler beim Laden der Partner-Links' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user