websockets implemented

This commit is contained in:
Torsten Schulz
2024-12-04 19:08:26 +01:00
parent d46a51db38
commit 069c97fa90
64 changed files with 2488 additions and 562 deletions

View File

@@ -1,22 +1,28 @@
import crypto from 'crypto';
const algorithm = 'aes-256-ecb';
const algorithm = 'aes-256-ecb';
const key = crypto.scryptSync(process.env.SECRET_KEY, 'salt', 32);
export const generateIv = () => {
return crypto.randomBytes(16);
return crypto.randomBytes(16).toString('base64');
};
export const encrypt = (text) => {
const cipher = crypto.createCipheriv(algorithm, key, null);
let encrypted = cipher.update(text, 'utf8', 'hex');
const cipher = crypto.createCipheriv(algorithm, key, null);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
};
export const decrypt = (text) => {
const decipher = crypto.createDecipheriv(algorithm, key, null);
let decrypted = decipher.update(text, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
try {
const decipher = crypto.createDecipheriv(algorithm, key, null);
let decrypted = decipher.update(text, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
} catch (error) {
console.log(error);
return null;
}
};

View File

@@ -0,0 +1,81 @@
import RegionData from "../../models/falukant/data/region.js";
import RegionType from "../../models/falukant/type/region.js";
const regionTypes = [];
const regionTypeTrs = [
"country",
"duchy",
"markgravate",
"shire",
"county",
"city"
];
const regions = [
{ labelTr: "falukant", regionType: "country", parentTr: null },
{ labelTr: "duchy1", regionType: "duchy", parentTr: "falukant" },
{ labelTr: "markgravate", regionType: "markgravate", parentTr: "duchy1" },
{ labelTr: "shire1", regionType: "shire", parentTr: "markgravate" },
{ labelTr: "county1", regionType: "county", parentTr: "shire1" },
{ labelTr: "town1", regionType: "city", parentTr: "county1" },
{ labelTr: "town2", regionType: "city", parentTr: "county1" },
{ labelTr: "town3", regionType: "city", parentTr: "county1" },
{ labelTr: "town4", regionType: "city", parentTr: "county1" },
];
// Step 1: Initialize region types
export const initializeFalukantTypes = async () => {
await initializeFalukantTypeRegions();
}
const initializeFalukantTypeRegions = async () => {
for (const regionType of regionTypeTrs) {
const [regionTypeRecord] = await RegionType.findOrCreate({
where: { labelTr: regionType },
defaults: {
parentId: regionTypes[regionTypes.length - 1]?.id
}
});
regionTypes.push(regionTypeRecord);
}
};
// Utility: Find region type object by region type
const findRegionTypeObjectByRegionType = async (regionType) => {
return regionTypes.find(region => region.labelTr === regionType) || null;
};
// Utility: Find region object by label
const findRegionObjectByLabelTr = async (labelTr) => {
return await RegionData.findOne({ where: { name: labelTr } });
};
// Step 2: Initialize regions
export const initializeFalukantRegions = async () => {
for (const region of regions) {
const regionType = await findRegionTypeObjectByRegionType(region.regionType);
if (!regionType) {
console.error(`Region type not found for: ${region.regionType}`);
continue;
}
const parentRegion = region.parentTr
? await findRegionObjectByLabelTr(region.parentTr)
: null;
if (region.parentTr && !parentRegion) {
console.error(`Parent region not found for: ${region.parentTr}`);
continue;
}
console.log('Creating/Fetching Region:', region.labelTr, 'Type:', regionType.labelTr, 'Parent:', parentRegion?.name);
await RegionData.findOrCreate({
where: { name: region.labelTr },
defaults: {
regionTypeId: regionType.id,
parentId: parentRegion?.id || null
}
});
}
};

View File

@@ -0,0 +1,8 @@
import { initializeFalukantTypes, initializeFalukantRegions } from './falukant/initializeFalukantTypes.js';
const initializeFalukant = async () => {
await initializeFalukantTypes();
await initializeFalukantRegions();
}
export default initializeFalukant;

View File

@@ -153,7 +153,7 @@ const initializeTypes = async () => {
};
for (const key of Object.keys(interestsList)) {
try {
try {
const value = interestsList[key];
const [item, created] = await Interest.findOrCreate({
where: { name: key },

View File

@@ -16,38 +16,54 @@ redisClient.connect().catch(console.error);
const setUserSession = async (userId, sessionData) => {
try {
await redisClient.hSet(`user:${userId}`, sessionData);
await redisClient.sendCommand(['JSON.SET', `user:${userId}`, '.', JSON.stringify(sessionData)]);
console.log(userId, sessionData);
const sessionDataStr = await redisClient.sendCommand(['JSON.GET', `user:${userId}`]);
console.log(sessionDataStr);
} catch (error) {
console.error('Fehler beim Setzen der Benutzersitzung:', error);
}
};
};
const deleteUserSession = async (userId) => {
try {
await redisClient.del(`user:${userId}`);
const result = await redisClient.del(`user:${userId}`);
if (result === 1) {
console.log(`Benutzersitzung für Benutzer ${userId} erfolgreich gelöscht.`);
} else {
console.warn(`Benutzersitzung für Benutzer ${userId} war nicht vorhanden.`);
}
} catch (error) {
console.error('Fehler beim Löschen der Benutzersitzung:', error);
}
};
const convertToOriginalType = (value) => {
if (value === 'true') return true;
if (value === 'false') return false;
if (!isNaN(value) && value.trim() !== '') return Number(value);
return value;
};
const getUserSession = async (userId) => {
try {
return await redisClient.hGetAll(`user:${userId}`);
const sessionData = await redisClient.sendCommand(['JSON.GET', `user:${userId}`]);
return JSON.parse(sessionData);
} catch (error) {
console.error('Fehler beim Abrufen der Benutzersitzung:', error);
return null;
}
};
const updateUserTimestamp = async (hashedId) => {
const updateUserTimestamp = async (userId) => {
try {
const userKey = `user:${hashedId}`;
const userKey = `user:${userId}`;
const userExists = await redisClient.exists(userKey);
if (userExists) {
await redisClient.hSet(userKey, 'timestamp', Date.now());
console.log(`Zeitstempel für Benutzer ${hashedId} aktualisiert.`);
} else {
console.warn(`Benutzer mit der hashedId ${hashedId} wurde nicht gefunden.`);
const sessionDataString = await redisClient.sendCommand(['JSON.GET', `user:${userId}`]);
const sessionData = JSON.parse(sessionDataString);
sessionData.timestamp = Date.now();
await redisClient.sendCommand(['JSON.SET', `user:${userId}`, '.', JSON.stringify(sessionData)]);
}
} catch (error) {
console.error('Fehler beim Aktualisieren des Zeitstempels:', error);
@@ -58,17 +74,29 @@ const cleanupExpiredSessions = async () => {
try {
const keys = await redisClient.keys('user:*');
const now = Date.now();
for (const key of keys) {
const session = await redisClient.hGetAll(key);
if (session.timestamp && now - parseInt(session.timestamp) > EXPIRATION_TIME) {
const userId = key.split(':')[1];
await redisClient.del(key);
await User.update({ authCode: '' }, { where: { hashedId: userId } });
console.log(`Abgelaufene Sitzung für Benutzer ${userId} gelöscht.`);
try {
const sessionStr = await redisClient.sendCommand(['JSON.GET', key]);
if (sessionStr) {
const session = JSON.parse(sessionStr);
if (session.timestamp && now - parseInt(session.timestamp) > EXPIRATION_TIME) {
const userId = key.split(':')[1];
await redisClient.del(key);
await User.update({ authCode: '' }, { where: { hashedId: userId } });
console.log(`Abgelaufene Sitzung für Benutzer ${userId} mit RedisJSON gelöscht.`);
}
}
} catch (error) {
if (error.message.includes('WRONGTYPE')) {
console.warn(`Schlüssel ${key} ist kein JSON-Objekt, wird übersprungen.`);
} else {
console.error(`Fehler beim Bereinigen für Schlüssel ${key}:`, error);
}
}
}
} catch (error) {
console.error('Fehler beim Bereinigen abgelaufener Sitzungen:', error);
console.error('Fehler beim Bereinigen abgelaufener Sitzungen mit RedisJSON:', error);
}
};

View File

@@ -17,6 +17,8 @@ const createSchemas = async () => {
await sequelize.query('CREATE SCHEMA IF NOT EXISTS type');
await sequelize.query('CREATE SCHEMA IF NOT EXISTS service');
await sequelize.query('CREATE SCHEMA IF NOT EXISTS forum');
await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_data');
await sequelize.query('CREATE SCHEMA IF NOT EXISTS falukant_type');
};
const initializeDatabase = async () => {

73
backend/utils/socket.js Normal file
View File

@@ -0,0 +1,73 @@
import { Server } from 'socket.io';
import BaseService from '../services/BaseService.js';
const baseService = new BaseService();
let io;
const userSockets = {};
export function setupWebSocket(server) {
io = new Server(server, {
cors: {
origin: '*',
},
});
io.on('connection', (socket) => {
socket.on('setUserId', (userId) => {
if (userId) {
socket.userId = userId;
userSockets[userId] = socket.id;
}
});
socket.on('disconnect', () => {
if (socket.userId) {
delete userSockets[socket.userId];
}
});
});
}
export function getIo() {
if (!io) {
throw new Error('Socket.io ist nicht initialisiert!');
}
return io;
}
export function getUserSockets() {
return userSockets;
}
export async function notifyUser(recipientHashedUserId, event, data) {
const io = getIo();
const userSockets = getUserSockets();
try {
const recipientUser = await baseService.getUserByHashedId(recipientHashedUserId);
if (recipientUser) {
const socketId = userSockets[recipientUser.hashedId];
if (socketId) {
io.to(socketId).emit(event, data);
}
} else {
console.log(`Benutzer mit gehashter ID ${recipientHashedUserId} nicht gefunden.`);
}
} catch (err) {
console.error('Fehler beim Senden der Benachrichtigung:', err);
}
}
export async function notifyAllUsers(event, data) {
const io = getIo();
const userSockets = getUserSockets();
try {
for (const [userId, socketId] of Object.entries(userSockets)) {
io.to(socketId).emit(event, data);
console.log(`Benachrichtigung an Benutzer mit ID ${userId} gesendet.`);
}
} catch (err) {
console.error('Fehler beim Senden der Benachrichtigung an alle Benutzer:', err);
}
}

View File

@@ -5,6 +5,7 @@ import initializeTypes from './initializeTypes.js';
import initializeSettings from './initializeSettings.js';
import initializeUserRights from './initializeUserRights.js';
import initializeImageTypes from './initializeImageTypes.js';
import initializeFalukant from './initializeFalukant.js';
import setupAssociations from '../models/associations.js';
import models from '../models/index.js';
import { createTriggers } from '../models/trigger.js';
@@ -13,32 +14,35 @@ import initializeForum from './initializeForum.js';
const syncDatabase = async () => {
try {
console.log("Initializing database schemas...");
await initializeDatabase(); // Stellt sicher, dass alle Schemas erstellt sind
await initializeDatabase();
console.log("Synchronizing models...");
await syncModels(models); // Modelle synchronisieren
await syncModels(models);
console.log("Setting up associations...");
setupAssociations(); // Assoziationen definieren
setupAssociations();
console.log("Creating triggers...");
await createTriggers(); // Trigger erstellen
await createTriggers();
console.log("Initializing settings...");
await initializeSettings(); // Einstellungsdaten initialisieren
await initializeSettings();
console.log("Initializing types...");
await initializeTypes(); // Typen initialisieren
await initializeTypes();
console.log("Initializing user rights...");
await initializeUserRights(); // Benutzerrechte initialisieren
await initializeUserRights();
console.log("Initializing image types...");
await initializeImageTypes(); // Bildtypen initialisieren
await initializeImageTypes();
console.log("Initializing forums...");
await initializeForum(); // Foren initialisieren
await initializeForum();
console.log("Initializing Falukant...");
await initializeFalukant();
console.log('Database synchronization complete.');
} catch (error) {
console.error('Unable to synchronize the database:', error);