131 lines
5.4 KiB
JavaScript
131 lines
5.4 KiB
JavaScript
// Helpers for normalizing dashboard state and date values.
|
|
|
|
const { WebSocket } = require('ws');
|
|
|
|
function normalizeClientName(value) {
|
|
return String(value || '').trim();
|
|
}
|
|
|
|
function enrichScreensWithConnections(screens, connectionsBySlug, onboardingNameBySlug, playerUrlsBySlug) {
|
|
return (screens || []).map(function (screen) {
|
|
const connectionState = connectionsBySlug[screen.slug] || { count: 0, connections: [] };
|
|
return Object.assign({}, screen, {
|
|
client_name: onboardingNameBySlug[screen.slug] || null,
|
|
player_connection_count: connectionState.count || 0,
|
|
player_connections: Array.isArray(connectionState.connections) ? connectionState.connections : [],
|
|
player_url: String(playerUrlsBySlug && playerUrlsBySlug[screen.slug] || '').trim() || null
|
|
});
|
|
});
|
|
}
|
|
|
|
function buildClientRows(screens, connectionsBySlug, onboardingNameBySlug, onboardingNameByDeviceId, formatDashboardDate) {
|
|
return (screens || []).flatMap(function (screen) {
|
|
const connectionState = connectionsBySlug[screen.slug] || { count: 0, connections: [] };
|
|
return (connectionState.connections || []).map(function (connection) {
|
|
const deviceId = String(connection.deviceId || '').trim();
|
|
return Object.assign({}, connection, {
|
|
screen_slug: screen.slug,
|
|
screen_name: screen.name,
|
|
client_name: (deviceId && onboardingNameByDeviceId && onboardingNameByDeviceId[deviceId]) || connection.clientName || onboardingNameBySlug[screen.slug] || String(connection.clientId || '').trim() || null,
|
|
playlist_name: screen.playlist_name || null,
|
|
connectedAtLabel: formatDashboardDate(connection.connectedAt),
|
|
lastSeenAtLabel: formatDashboardDate(connection.lastSeenAt),
|
|
player_url: screen.player_url || String(connection.page || '').trim() || null
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function compareScreenNames(left, right) {
|
|
const leftName = String(left && left.name || '').trim();
|
|
const rightName = String(right && right.name || '').trim();
|
|
const nameCompare = leftName.localeCompare(rightName, undefined, { sensitivity: 'base', numeric: true });
|
|
|
|
if (nameCompare !== 0) {
|
|
return nameCompare;
|
|
}
|
|
|
|
return String(left && left.slug || '').localeCompare(String(right && right.slug || ''), undefined, { sensitivity: 'base', numeric: true });
|
|
}
|
|
|
|
function createDashboardStateService(options) {
|
|
const pool = options && options.pool;
|
|
const common = options && options.common;
|
|
const playerSnapshotCache = options && options.playerSnapshotCache;
|
|
const playerSnapshotSockets = options && options.playerSnapshotSockets;
|
|
const ensurePlayerSnapshotSubscription = options && options.ensurePlayerSnapshotSubscription;
|
|
const formatDashboardDate = options && options.formatDashboardDate;
|
|
|
|
if (!pool || !common || !playerSnapshotCache || !playerSnapshotSockets || typeof ensurePlayerSnapshotSubscription !== 'function' || typeof formatDashboardDate !== 'function') {
|
|
throw new Error('createDashboardStateService requires the dashboard dependencies.');
|
|
}
|
|
|
|
async function buildDashboardState() {
|
|
const data = await common.fetchAdminData(pool);
|
|
const screensData = data.screens || [];
|
|
const playerUrlsBySlug = typeof common.fetchScreenPlayerUrls === 'function'
|
|
? await common.fetchScreenPlayerUrls(pool)
|
|
: {};
|
|
screensData.forEach(function (screen) {
|
|
ensurePlayerSnapshotSubscription(screen.slug);
|
|
});
|
|
|
|
const [onboardingRows] = await pool.query(
|
|
`SELECT s.slug, pod.device_id, pod.client_name
|
|
FROM d_onboarding_devices pod
|
|
JOIN d_screens s ON s.id = pod.screen_id
|
|
WHERE pod.client_name IS NOT NULL
|
|
AND TRIM(pod.client_name) <> ''`
|
|
);
|
|
const onboardingNameBySlug = {};
|
|
const onboardingNameByDeviceId = {};
|
|
onboardingRows.forEach(function (row) {
|
|
const clientName = normalizeClientName(row.client_name);
|
|
const slug = normalizeClientName(row.slug);
|
|
const deviceId = normalizeClientName(row.device_id);
|
|
if (slug) {
|
|
onboardingNameBySlug[slug] = clientName;
|
|
}
|
|
if (deviceId) {
|
|
onboardingNameByDeviceId[deviceId] = clientName;
|
|
}
|
|
});
|
|
|
|
const connectionsBySlug = {};
|
|
screensData.forEach(function (screen) {
|
|
const cached = playerSnapshotCache.get(String(screen.slug || '').trim());
|
|
if (cached && Array.isArray(cached.connections)) {
|
|
connectionsBySlug[screen.slug] = cached;
|
|
}
|
|
});
|
|
|
|
const screens = enrichScreensWithConnections(data.screens || [], connectionsBySlug, onboardingNameBySlug, playerUrlsBySlug)
|
|
.map(function (screen) {
|
|
return Object.assign({}, screen, {
|
|
player_url: screen.player_url || null
|
|
});
|
|
})
|
|
.sort(compareScreenNames);
|
|
const clients = buildClientRows(screens, connectionsBySlug, onboardingNameBySlug, onboardingNameByDeviceId, formatDashboardDate);
|
|
const playerServiceConnected = Array.from(playerSnapshotSockets.values()).some(function (socket) {
|
|
return socket && socket.readyState === WebSocket.OPEN;
|
|
});
|
|
|
|
return {
|
|
playlists: data.playlists || [],
|
|
screens: screens,
|
|
clients: clients,
|
|
slides: data.slides || [],
|
|
playerServiceConnected: playerServiceConnected,
|
|
connectedClientsCount: screens.reduce(function (total, screen) {
|
|
return total + Number(screen.player_connection_count || 0);
|
|
}, 0)
|
|
};
|
|
}
|
|
|
|
return {
|
|
buildDashboardState: buildDashboardState
|
|
};
|
|
}
|
|
|
|
module.exports = { createDashboardStateService }; |