All checks were successful
farmcontrol/farmcontrol-ws/pipeline/head This commit looks good
- Removed unnecessary console logging in the `SocketUser` class for cleaner output. - Updated the `distributeNew` function to accept the entire object instead of just the ID, improving flexibility in handling new entries. - Enhanced the `newAuditLog` and `editAuditLog` functions to filter out excluded models and changes, ensuring sensitive data is not logged. - Introduced new utility functions for omitting specific paths and excluded changes from audit logs, enhancing data privacy and integrity.
378 lines
11 KiB
JavaScript
378 lines
11 KiB
JavaScript
import log4js from 'log4js';
|
|
// Load configuration
|
|
import { loadConfig } from '../config.js';
|
|
import { createAuthMiddleware, KeycloakAuth } from '../auth/auth.js';
|
|
import { generateHostOTP } from '../utils.js';
|
|
import { ActivityManager } from '../activity/activitymanager.js';
|
|
import { UpdateManager } from '../updates/updatemanager.js';
|
|
import { ActionManager } from '../actions/actionmanager.js';
|
|
import { EventManager } from '../events/eventmanager.js';
|
|
import { StatsManager } from '../stats/statsmanager.js';
|
|
import { NotificationManager } from '../notification/notificationmanager.js';
|
|
import { ServerManager } from '../server/servermanager.js';
|
|
import { UserSettingsManager } from '../usersettings/usersettingsmanager.js';
|
|
|
|
const config = loadConfig();
|
|
|
|
const logger = log4js.getLogger('Socket User');
|
|
logger.level = config.server.logLevel;
|
|
|
|
export class SocketUser {
|
|
constructor(socket, socketManager) {
|
|
this.socket = socket;
|
|
this.authenticated = false;
|
|
this.socketId = socket.id;
|
|
this.id = null;
|
|
this.user = null;
|
|
this.socketManager = socketManager;
|
|
this.activityManager = new ActivityManager(this);
|
|
this.trackedActivities = new Set();
|
|
this.updateManager = new UpdateManager(this);
|
|
this.actionManager = new ActionManager(this);
|
|
this.eventManager = new EventManager(this);
|
|
this.statsManager = new StatsManager(this);
|
|
this.notificationManager = new NotificationManager(this);
|
|
this.serverManager = new ServerManager(this);
|
|
this.userSettingsManager = new UserSettingsManager(this);
|
|
this.keycloakAuth = new KeycloakAuth();
|
|
this.setupSocketEventHandlers();
|
|
}
|
|
|
|
setupSocketEventHandlers() {
|
|
this.socket.use(createAuthMiddleware(this));
|
|
this.socket.on('authenticate', this.handleAuthenticateEvent.bind(this));
|
|
this.socket.on('setActivity', this.handleSetActivityEvent.bind(this));
|
|
this.socket.on('clearActivity', this.handleClearActivityEvent.bind(this));
|
|
this.socket.on('getActivities', this.handleGetActivitiesEvent.bind(this));
|
|
this.socket.on(
|
|
'subscribeToObjectActivity',
|
|
this.handleSubscribeToObjectActivityEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'unsubscribeObjectActivity',
|
|
this.handleUnsubscribeObjectActivityEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'subscribeToObjectTypeUpdate',
|
|
this.handleSubscribeToObjectTypeUpdateEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'subscribeToObjectUpdate',
|
|
this.handleSubscribeToObjectUpdateEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'subscribeToObjectEvent',
|
|
this.handleSubscribeToObjectEventEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'unsubscribeObjectTypeUpdate',
|
|
this.handleUnsubscribeToObjectTypeUpdateEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'unsubscribeObjectUpdate',
|
|
this.handleUnsubscribeToObjectUpdateEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'unsubscribeObjectEvent',
|
|
this.handleUnsubscribeObjectEventEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'subscribeToModelStats',
|
|
this.handleSubscribeToStatsEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'unsubscribeModelStats',
|
|
this.handleUnsubscribeToStatsEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'generateHostOtp',
|
|
this.handleGenerateHostOtpEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'getServerVersion',
|
|
this.handleGetServerVersionEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'getUserSettings',
|
|
this.handleGetUserSettingsEvent.bind(this)
|
|
);
|
|
this.socket.on(
|
|
'updateUserSettings',
|
|
this.handleUpdateUserSettingsEvent.bind(this)
|
|
);
|
|
this.socket.on('objectAction', this.handleObjectActionEvent.bind(this));
|
|
this.socket.on('disconnect', this.handleDisconnect.bind(this));
|
|
}
|
|
|
|
async handleAuthenticateEvent(data, callback) {
|
|
const token = data.token || undefined;
|
|
logger.info('Authenticating user with token...');
|
|
if (token) {
|
|
const result = await this.keycloakAuth.verifyToken(token);
|
|
if (result.valid == true) {
|
|
logger.info('User authenticated and valid.');
|
|
|
|
this.user = result.user;
|
|
this.id = this.user._id.toString();
|
|
this.authenticated = true;
|
|
await this.notificationManager.subscribe();
|
|
} else {
|
|
logger.warn('User is not authenticated.');
|
|
}
|
|
callback(result);
|
|
}
|
|
}
|
|
|
|
trackActivity(type, id) {
|
|
this.trackedActivities.add(`${type}|${id}`);
|
|
}
|
|
|
|
untrackActivity(type, id) {
|
|
this.trackedActivities.delete(`${type}|${id}`);
|
|
}
|
|
|
|
async handleSetActivityEvent(data, callback) {
|
|
const respond = result => {
|
|
if (typeof callback === 'function') {
|
|
callback(result);
|
|
} else {
|
|
this.socket.emit('setActivity_result', result);
|
|
}
|
|
};
|
|
|
|
if (!data || !data._id || !data.type || !data.mode) {
|
|
respond({
|
|
success: false,
|
|
error: 'Invalid setActivity event data'
|
|
});
|
|
return;
|
|
}
|
|
data = { ...data, user: this.user._id.toString() };
|
|
try {
|
|
const result = await this.activityManager.setActivity(data);
|
|
if (result?.success === false) {
|
|
respond(result);
|
|
return;
|
|
}
|
|
|
|
this.trackActivity(data.type, data._id);
|
|
respond(result);
|
|
} catch (err) {
|
|
logger.error('Set activity event error:', err);
|
|
respond({
|
|
success: false,
|
|
error: err.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async handleClearActivityEvent(data) {
|
|
if (!data || !data._id || !data.type) {
|
|
this.socket.emit('clearActivity_result', {
|
|
success: false,
|
|
error: 'Invalid clearActivity event data'
|
|
});
|
|
return;
|
|
}
|
|
data = { ...data, user: this.user._id.toString() };
|
|
try {
|
|
await this.activityManager.clearActivity(data);
|
|
this.untrackActivity(data.type, data._id);
|
|
} catch (err) {
|
|
logger.error('Clear activity event error:', err);
|
|
this.socket.emit('clearActivity_result', {
|
|
success: false,
|
|
error: err.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async handleGetActivitiesEvent(data, callback) {
|
|
if (!data || !data._id || !data.type) {
|
|
callback({
|
|
error: 'Invalid getActivities event data'
|
|
});
|
|
return;
|
|
}
|
|
try {
|
|
const activities = await this.activityManager.getObjectActivities(data);
|
|
callback({ activities });
|
|
} catch (err) {
|
|
logger.error('GetActivities event error:', err);
|
|
callback({
|
|
error: err.message
|
|
});
|
|
}
|
|
}
|
|
|
|
async handleSubscribeToObjectActivityEvent(data, callback) {
|
|
if (!data || !data._id || !data.objectType) {
|
|
if (typeof callback === 'function') {
|
|
callback({
|
|
success: false,
|
|
error: 'Invalid subscribeToObjectActivity event data'
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
|
|
const result = await this.activityManager.subscribeToObjectActivity(
|
|
data._id,
|
|
data.objectType
|
|
);
|
|
if (typeof callback === 'function') {
|
|
callback(result);
|
|
}
|
|
}
|
|
|
|
async handleUnsubscribeObjectActivityEvent(data) {
|
|
await this.activityManager.removeObjectActivityListener(
|
|
data._id,
|
|
data.objectType
|
|
);
|
|
}
|
|
|
|
async handleSubscribeToObjectTypeUpdateEvent(data, callback) {
|
|
await this.updateManager.subscribeToObjectNew(data.objectType, data.filter);
|
|
await this.updateManager.subscribeToObjectDelete(
|
|
data.objectType,
|
|
data.filter
|
|
);
|
|
if (typeof callback === 'function') {
|
|
callback({ success: true });
|
|
}
|
|
}
|
|
|
|
async handleSubscribeToObjectUpdateEvent(data, callback) {
|
|
const result = await this.updateManager.subscribeToObjectUpdate(
|
|
data._id,
|
|
data.objectType
|
|
);
|
|
if (typeof callback === 'function') {
|
|
callback(result);
|
|
}
|
|
}
|
|
|
|
async handleSubscribeToObjectEventEvent(data) {
|
|
await this.eventManager.subscribeToObjectEvent(
|
|
data._id,
|
|
data.objectType,
|
|
data.eventType
|
|
);
|
|
}
|
|
|
|
async handleUnsubscribeToObjectTypeUpdateEvent(data) {
|
|
await this.updateManager.removeObjectNewListener(
|
|
data.objectType,
|
|
data.filter
|
|
);
|
|
await this.updateManager.removeObjectDeleteListener(
|
|
data.objectType,
|
|
data.filter
|
|
);
|
|
}
|
|
|
|
async handleUnsubscribeToObjectUpdateEvent(data) {
|
|
await this.updateManager.removeObjectUpdateListener(
|
|
data._id,
|
|
data.objectType
|
|
);
|
|
}
|
|
|
|
async handleUnsubscribeObjectEventEvent(data) {
|
|
await this.eventManager.removeObjectEventsListener(
|
|
data._id,
|
|
data.objectType,
|
|
data.eventType
|
|
);
|
|
}
|
|
|
|
async handleSubscribeToStatsEvent(data) {
|
|
await this.statsManager.subscribeToStats(data.objectType);
|
|
}
|
|
|
|
async handleUnsubscribeToStatsEvent(data) {
|
|
await this.statsManager.removeStatsListener(data.objectType);
|
|
}
|
|
|
|
async handleGenerateHostOtpEvent(data, callback) {
|
|
const result = await generateHostOTP(data._id);
|
|
callback(result);
|
|
}
|
|
|
|
async handleGetServerVersionEvent(data, callback) {
|
|
const responseCallback = typeof callback === 'function' ? callback : data;
|
|
responseCallback(this.serverManager.getServerVersion());
|
|
}
|
|
|
|
async handleGetUserSettingsEvent(data, callback) {
|
|
const responseCallback = typeof callback === 'function' ? callback : data;
|
|
try {
|
|
const settings = await this.userSettingsManager.getUserSettings();
|
|
responseCallback({ success: true, settings });
|
|
} catch (error) {
|
|
logger.error('Get user settings error:', error);
|
|
responseCallback({ success: false, error: error.message });
|
|
}
|
|
}
|
|
|
|
async handleUpdateUserSettingsEvent(data, callback) {
|
|
try {
|
|
const settings = await this.userSettingsManager.updateUserSettings(data);
|
|
if (typeof callback === 'function') {
|
|
callback({ success: true, settings });
|
|
}
|
|
} catch (error) {
|
|
logger.error('Update user settings error:', error);
|
|
if (typeof callback === 'function') {
|
|
callback({ success: false, error: error.message });
|
|
}
|
|
}
|
|
}
|
|
|
|
async handleObjectActionEvent(data, callback) {
|
|
await this.actionManager.sendObjectAction(
|
|
data._id,
|
|
data.objectType,
|
|
data.action,
|
|
callback
|
|
);
|
|
}
|
|
|
|
async handleDisconnect() {
|
|
if (this.user?._id) {
|
|
const userId = this.user._id.toString();
|
|
for (const activityKey of this.trackedActivities) {
|
|
const separatorIndex = activityKey.indexOf('|');
|
|
const type = activityKey.slice(0, separatorIndex);
|
|
const id = activityKey.slice(separatorIndex + 1);
|
|
try {
|
|
await this.activityManager.clearActivity({
|
|
_id: id,
|
|
type,
|
|
user: userId
|
|
});
|
|
} catch (err) {
|
|
logger.error('Error clearing activity on disconnect:', err);
|
|
}
|
|
}
|
|
this.trackedActivities.clear();
|
|
}
|
|
|
|
await this.activityManager.removeAllListeners();
|
|
await this.actionManager.removeAllListeners();
|
|
await this.updateManager.removeAllListeners();
|
|
await this.eventManager.removeAllListeners();
|
|
await this.statsManager.removeAllListeners();
|
|
await this.notificationManager.removeAllListeners();
|
|
if (this.user || this.socket.user) {
|
|
logger.info(
|
|
'External user disconnected:',
|
|
this.user.username || this.socket.user?.username
|
|
);
|
|
} else {
|
|
logger.info('External user disconnected.');
|
|
}
|
|
}
|
|
}
|