mira-app-server
Version:
Mira Server - standalone server application using mira-app-core
411 lines • 15.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DeviceRoutes = void 0;
const express_1 = require("express");
const ws_1 = require("ws");
class DeviceRoutes {
constructor(backend) {
this.backend = backend;
this.router = (0, express_1.Router)();
this.setupRoutes();
}
setupRoutes() {
// 获取所有素材库的设备连接信息
this.router.get('/', this.getAllDevices.bind(this));
// 获取特定素材库的设备连接信息
this.router.get('/library/:libraryId', this.getLibraryDevices.bind(this));
// 广播消息(指定设备或全部)
this.router.post('/broadcast', this.broadcastMessage.bind(this));
// 断开特定设备连接
this.router.post('/disconnect', this.disconnectDevice.bind(this));
this.router.post('/:clientId/disconnect', this.disconnectDeviceByClientId.bind(this));
// 向特定设备发送消息
this.router.post('/send-message', this.sendMessageToDevice.bind(this));
this.router.post('/:clientId/message', this.sendMessageToDeviceByClientId.bind(this));
this.router.post('/:clientId/test', this.sendTestMessageToDevice.bind(this));
this.router.get('/:clientId/messages', this.getDeviceMessages.bind(this));
// 获取设备统计信息
this.router.get('/stats', this.getDeviceStats.bind(this));
}
async broadcastMessage(req, res) {
try {
const { message, title, clientIds } = req.body;
if (!message) {
res.status(400).json({ success: false, error: 'message is required' });
return;
}
const webSocketServer = this.backend.getWebSocketServer();
if (!webSocketServer) {
res.status(500).json({ success: false, error: 'WebSocket server not available' });
return;
}
const payload = {
eventName: 'notification',
data: {
title: title || 'Administrator',
body: message,
timestamp: new Date().toISOString(),
from: 'administrator',
},
};
let sentCount = 0;
if (clientIds && Array.isArray(clientIds) && clientIds.length > 0) {
// 发送给指定设备
for (const clientId of clientIds) {
const found = this.findDeviceClient(clientId);
if (found && found.client.readyState === ws_1.WebSocket.OPEN) {
webSocketServer.sendToWebsocket(found.client, payload);
sentCount++;
}
}
}
else {
// 发送给所有设备
for (const clients of Object.values(webSocketServer.libraryClients)) {
for (const client of clients) {
if (client.readyState === ws_1.WebSocket.OPEN) {
webSocketServer.sendToWebsocket(client, payload);
sentCount++;
}
}
}
}
res.json({
success: true,
data: { sentCount },
timestamp: new Date().toISOString(),
});
}
catch (error) {
console.error('Failed to broadcast message:', error);
res.status(500).json({
success: false,
error: 'Failed to broadcast message',
details: error instanceof Error ? error.message : String(error),
});
}
}
async getAllDevices(req, res) {
try {
const webSocketServer = this.backend.getWebSocketServer();
if (!webSocketServer) {
res.status(500).json({
success: false,
error: 'WebSocket server not available'
});
return;
}
const devices = {};
const libraryClients = webSocketServer.libraryClients;
console.log('[DeviceRoutes] libraryClients keys:', Object.keys(libraryClients), 'total connections:', Object.values(libraryClients).reduce((sum, c) => sum + c.length, 0));
for (const [libraryId, clients] of Object.entries(libraryClients)) {
devices[libraryId] = clients.map(client => this.extractDeviceInfo(client, libraryId));
}
res.json({
success: true,
data: devices,
timestamp: new Date().toISOString()
});
}
catch (error) {
console.error('Failed to get all devices:', error);
res.status(500).json({
success: false,
error: 'Failed to retrieve device information',
details: error instanceof Error ? error.message : String(error)
});
}
}
async getLibraryDevices(req, res) {
try {
const { libraryId } = req.params;
const webSocketServer = this.backend.getWebSocketServer();
if (!webSocketServer) {
res.status(500).json({
success: false,
error: 'WebSocket server not available'
});
return;
}
// 检查素材库是否存在
if (!this.backend.libraries.libraryExists(libraryId)) {
res.status(404).json({
success: false,
error: 'Library not found',
libraryId
});
return;
}
const clients = webSocketServer.libraryClients[libraryId] || [];
const devices = clients.map(client => this.extractDeviceInfo(client, libraryId));
res.json({
success: true,
data: devices,
libraryId,
timestamp: new Date().toISOString()
});
}
catch (error) {
console.error('Failed to get library devices:', error);
res.status(500).json({
success: false,
error: 'Failed to retrieve library devices',
details: error instanceof Error ? error.message : String(error)
});
}
}
async disconnectDevice(req, res) {
try {
const { libraryId, clientId } = req.body;
if (!libraryId || !clientId) {
res.status(400).json({
success: false,
error: 'libraryId and clientId are required'
});
return;
}
const webSocketServer = this.backend.getWebSocketServer();
if (!webSocketServer) {
res.status(500).json({
success: false,
error: 'WebSocket server not available'
});
return;
}
const client = webSocketServer.getWsClientById(libraryId, clientId);
if (!client) {
res.status(404).json({
success: false,
error: 'Device not found',
libraryId,
clientId
});
return;
}
// 发送断开连接消息给客户端
webSocketServer.sendToWebsocket(client, {
eventName: 'admin_disconnect',
data: {
message: 'Connection terminated by administrator',
timestamp: new Date().toISOString()
}
});
// 关闭连接
client.close(1000, 'Disconnected by administrator');
res.json({
success: true,
message: 'Device disconnected successfully',
libraryId,
clientId,
timestamp: new Date().toISOString()
});
}
catch (error) {
console.error('Failed to disconnect device:', error);
res.status(500).json({
success: false,
error: 'Failed to disconnect device',
details: error instanceof Error ? error.message : String(error)
});
}
}
async disconnectDeviceByClientId(req, res) {
const resolved = this.findDeviceClient(req.params.clientId);
if (!resolved) {
res.status(404).json({
success: false,
error: 'Device not found',
clientId: req.params.clientId
});
return;
}
req.body = {
...req.body,
libraryId: resolved.libraryId,
clientId: req.params.clientId
};
await this.disconnectDevice(req, res);
}
async sendMessageToDevice(req, res) {
try {
const { libraryId, clientId, message } = req.body;
if (!libraryId || !clientId || !message) {
res.status(400).json({
success: false,
error: 'libraryId, clientId and message are required'
});
return;
}
const webSocketServer = this.backend.getWebSocketServer();
if (!webSocketServer) {
res.status(500).json({
success: false,
error: 'WebSocket server not available'
});
return;
}
const client = webSocketServer.getWsClientById(libraryId, clientId);
if (!client) {
res.status(404).json({
success: false,
error: 'Device not found',
libraryId,
clientId
});
return;
}
webSocketServer.sendToWebsocket(client, {
eventName: 'admin_message',
data: {
message,
timestamp: new Date().toISOString(),
from: 'administrator'
}
});
res.json({
success: true,
message: 'Message sent successfully',
libraryId,
clientId,
timestamp: new Date().toISOString()
});
}
catch (error) {
console.error('Failed to send message to device:', error);
res.status(500).json({
success: false,
error: 'Failed to send message to device',
details: error instanceof Error ? error.message : String(error)
});
}
}
async sendMessageToDeviceByClientId(req, res) {
const resolved = this.findDeviceClient(req.params.clientId);
if (!resolved) {
res.status(404).json({
success: false,
error: 'Device not found',
clientId: req.params.clientId
});
return;
}
req.body = {
...req.body,
libraryId: resolved.libraryId,
clientId: req.params.clientId,
message: req.body?.message ?? req.body?.content
};
await this.sendMessageToDevice(req, res);
}
async sendTestMessageToDevice(req, res) {
const resolved = this.findDeviceClient(req.params.clientId);
if (!resolved) {
res.status(404).json({
success: false,
error: 'Device not found',
clientId: req.params.clientId
});
return;
}
req.body = {
...req.body,
libraryId: resolved.libraryId,
clientId: req.params.clientId,
message: {
type: 'test',
content: 'Test message from administrator',
timestamp: new Date().toISOString()
}
};
await this.sendMessageToDevice(req, res);
}
async getDeviceMessages(req, res) {
const resolved = this.findDeviceClient(req.params.clientId);
if (!resolved) {
res.status(404).json({
success: false,
error: 'Device not found',
clientId: req.params.clientId
});
return;
}
res.json({
success: true,
data: [],
clientId: req.params.clientId,
libraryId: resolved.libraryId,
timestamp: new Date().toISOString()
});
}
async getDeviceStats(req, res) {
try {
const webSocketServer = this.backend.getWebSocketServer();
if (!webSocketServer) {
res.status(500).json({
success: false,
error: 'WebSocket server not available'
});
return;
}
const libraryClients = webSocketServer.libraryClients;
const stats = {
totalLibraries: Object.keys(libraryClients).length,
totalConnections: 0,
libraryStats: {}
};
for (const [libraryId, clients] of Object.entries(libraryClients)) {
const activeConnections = clients.filter(client => client.readyState === ws_1.WebSocket.OPEN).length;
stats.libraryStats[libraryId] = {
connectionCount: clients.length,
activeConnections
};
stats.totalConnections += clients.length;
}
res.json({
success: true,
data: stats,
timestamp: new Date().toISOString()
});
}
catch (error) {
console.error('Failed to get device stats:', error);
res.status(500).json({
success: false,
error: 'Failed to retrieve device statistics',
details: error instanceof Error ? error.message : String(error)
});
}
}
extractDeviceInfo(client, libraryId) {
const clientData = client;
const userAgent = clientData.requestInfo?.headers?.['user-agent'] || 'Unknown';
const ipAddress = clientData.requestInfo?.remoteAddress || 'Unknown';
return {
clientId: clientData.clientId || 'Unknown',
libraryId,
connectionTime: clientData.connectionTime || new Date().toISOString(),
lastActivity: clientData.lastActivity || new Date().toISOString(),
requestInfo: clientData.requestInfo || {},
status: client.readyState === ws_1.WebSocket.OPEN ? 'connected' : 'disconnected',
userAgent,
ipAddress
};
}
findDeviceClient(clientId) {
const webSocketServer = this.backend.getWebSocketServer();
if (!webSocketServer)
return null;
for (const [libraryId, clients] of Object.entries(webSocketServer.libraryClients)) {
const client = clients.find(item => item.clientId === clientId);
if (client) {
return { libraryId, client };
}
}
return null;
}
getRouter() {
return this.router;
}
}
exports.DeviceRoutes = DeviceRoutes;
//# sourceMappingURL=DeviceRoutes.js.map