diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceReportRespDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceReportRespDTO.java index 423868ca..85c8972a 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceReportRespDTO.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceReportRespDTO.java @@ -19,7 +19,7 @@ public class DeviceReportRespDTO { @Schema(description = "固件版本信息") private Firmware firmware; - + @Schema(description = "WebSocket配置") private Websocket websocket; @@ -66,12 +66,14 @@ public class DeviceReportRespDTO { @Schema(description = "时区偏移量,单位为分钟") private Integer timezone_offset; } - + @Getter @Setter public static class Websocket { @Schema(description = "WebSocket服务器地址") private String url; + @Schema(description = "WebSocket 认证 token") + private String token; } @Getter diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java index a79d1f2e..5c3f854d 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java @@ -169,6 +169,7 @@ public class DeviceServiceImpl extends BaseServiceImpl DeviceReportRespDTO.Websocket websocket = new DeviceReportRespDTO.Websocket(); // 从系统参数获取WebSocket URL,如果未配置则使用默认值 String wsUrl = sysParamsService.getValue(Constant.SERVER_WEBSOCKET, true); + websocket.setToken(""); if (StringUtils.isBlank(wsUrl) || wsUrl.equals("null")) { log.error("WebSocket地址未配置,请登录智控台,在参数管理找到【server.websocket】配置"); wsUrl = "ws://xiaozhi.server.com:8000/xiaozhi/v1/"; diff --git a/main/xiaozhi-server/test/js/xiaoZhiConnect.js b/main/xiaozhi-server/test/js/xiaoZhiConnect.js index 606d615b..d8fbe7a3 100644 --- a/main/xiaozhi-server/test/js/xiaoZhiConnect.js +++ b/main/xiaozhi-server/test/js/xiaoZhiConnect.js @@ -1,24 +1,50 @@ +import { otaStatusStyle } from './document.js'; import { log } from './utils/logger.js'; -import { otaStatusStyle } from './document.js' // WebSocket 连接 -export async function webSocketConnect(otaUrl,wsUrl,config){ - if (!validateWsUrl(wsUrl)) { - return; // 直接返回,不再往下执行 - } +export async function webSocketConnect(otaUrl, config) { if (!validateConfig(config)) { return; } - const ok = await sendOTA(otaUrl, config); - if (!ok) return; - // 使用自定义WebSocket实现以添加认证头信息 - let connUrl = new URL(wsUrl); - // 添加认证参数 + // 发送OTA请求并获取返回的websocket信息 + const otaResult = await sendOTA(otaUrl, config); + if (!otaResult) { + log('无法从OTA服务器获取信息', 'error'); + return; + } + + // 从OTA响应中提取websocket信息 + const { websocket } = otaResult; + if (!websocket || !websocket.url) { + log('OTA响应中缺少websocket信息', 'error'); + return; + } + + // 使用OTA返回的websocket URL + let connUrl = new URL(websocket.url); + + // 添加token参数(从OTA响应中获取) + if (websocket.token) { + if (websocket.token.startsWith("Bearer ")) { + connUrl.searchParams.append('authorization', websocket.token); + } else { + connUrl.searchParams.append('authorization', 'Bearer ' + websocket.token); + } + } + + // 添加认证参数(保持原有逻辑) connUrl.searchParams.append('device-id', config.deviceId); connUrl.searchParams.append('client-id', config.clientId); - log(`正在连接: ${connUrl.toString()}`, 'info'); + + const wsurl = connUrl.toString() + + log(`正在连接: ${wsurl}`, 'info'); + + if (wsurl) { + document.getElementById('serverUrl').value = wsurl; + } return new WebSocket(connUrl.toString()); } @@ -37,7 +63,7 @@ function validateConfig(config) { } // 判断wsUrl路径是否存在错误 -function validateWsUrl(wsUrl){ +function validateWsUrl(wsUrl) { if (wsUrl === '') return false; // 检查URL格式 if (!wsUrl.startsWith('ws://') && !wsUrl.startsWith('wss://')) { @@ -48,7 +74,7 @@ function validateWsUrl(wsUrl){ } -// OTA发送请求,验证状态 +// OTA发送请求,验证状态,并返回响应数据 async function sendOTA(otaUrl, config) { try { const res = await fetch(otaUrl, { @@ -90,14 +116,9 @@ async function sendOTA(otaUrl, config) { const result = await res.json(); otaStatusStyle(true) - return true; // 成功 + return result; // 返回完整的响应数据 } catch (err) { otaStatusStyle(false) - return false; // 失败 + return null; // 失败返回null } -} - - - - - +} \ No newline at end of file diff --git a/main/xiaozhi-server/test/test_page.html b/main/xiaozhi-server/test/test_page.html index 547f2b31..879d627b 100644 --- a/main/xiaozhi-server/test/test_page.html +++ b/main/xiaozhi-server/test/test_page.html @@ -133,10 +133,8 @@
- + -
@@ -714,7 +712,7 @@ localStorage.setItem('wsUrl', url); try { - const ws = await webSocketConnect(otaUrl, url, config) + const ws = await webSocketConnect(otaUrl, config) if (ws === undefined) { return } @@ -756,7 +754,7 @@ messageInput.disabled = true; sendTextButton.disabled = true; recordButton.disabled = true; - stopButton.disabled = true; + // stopButton.disabled = true; }; websocket.onerror = (error) => { @@ -1009,7 +1007,6 @@ // 初始化事件监听器 function initEventListeners() { connectButton.addEventListener('click', connectToServer); - document.getElementById('authTestButton').addEventListener('click', testAuthentication); // 设备配置面板折叠/展开 const toggleButton = document.getElementById('toggleConfig'); @@ -1049,11 +1046,6 @@ document.getElementById('otaUrl').value = savedOtaUrl; } - const savedWsUrl = localStorage.getItem('wsUrl'); - if (savedWsUrl) { - document.getElementById('serverUrl').value = savedWsUrl; - } - // 切换面板显示 toggleButton.addEventListener('click', () => { const isExpanded = configPanel.classList.contains('expanded'); @@ -1091,107 +1083,6 @@ window.addEventListener('resize', initVisualizer); } - // 测试认证 - async function testAuthentication() { - log('开始测试认证...', 'info'); - - const config = getConfig(); - - // 显示服务器配置 - log('-------- 服务器认证配置检查 --------', 'info'); - log('请确认config.yaml中的auth配置:', 'info'); - log('1. server.auth.enabled 为 false 或服务器已正确配置认证', 'info'); - log('2. 如果启用了认证,请确认使用了正确的token', 'info'); - log(`3. 或者在allowed_devices中添加了测试设备MAC:${config.deviceMac}`, 'info'); - - const serverUrl = serverUrlInput.value.trim(); - if (!serverUrl) { - log('请输入服务器地址', 'error'); - return; - } - - // 测试连接 - log('尝试不同认证参数的连接:', 'info'); - - // 测试1: 无参数连接 - try { - log('测试1: 尝试无参数连接...', 'info'); - const ws1 = new WebSocket(serverUrl); - - ws1.onopen = () => { - log('测试1成功: 无参数可连接,服务器可能没有启用认证', 'success'); - ws1.close(); - }; - - ws1.onerror = (error) => { - log('测试1失败: 无参数连接被拒绝,服务器可能启用了认证', 'error'); - }; - - // 5秒后关闭测试连接 - setTimeout(() => { - if (ws1.readyState === WebSocket.CONNECTING || ws1.readyState === WebSocket.OPEN) { - ws1.close(); - } - }, 5000); - } catch (error) { - log(`测试1出错: ${error.message}`, 'error'); - } - - // 测试2: 带参数连接 - setTimeout(async () => { - try { - log('测试2: 尝试带token参数连接...', 'info'); - - let url = new URL(serverUrl); - url.searchParams.append('token', config.token); - url.searchParams.append('device_id', config.deviceId); - url.searchParams.append('device_mac', config.deviceMac); - - const ws2 = new WebSocket(url.toString()); - - ws2.onopen = () => { - log('测试2成功: 带token参数可连接', 'success'); - - // 尝试发送hello消息 - const helloMsg = { - type: 'hello', - device_id: config.deviceId, - device_mac: config.deviceMac, - token: config.token - }; - - ws2.send(JSON.stringify(helloMsg)); - log('已发送hello测试消息', 'info'); - - // 监听响应 - ws2.onmessage = (event) => { - try { - const response = JSON.parse(event.data); - if (response.type === 'hello' && response.session_id) { - log(`测试完全成功! 收到hello响应,会话ID: ${response.session_id}`, 'success'); - ws2.close(); - } - } catch (e) { - log(`收到非JSON响应: ${event.data}`, 'info'); - } - }; - - // 5秒后关闭 - setTimeout(() => ws2.close(), 5000); - }; - - ws2.onerror = (error) => { - log('测试2失败: 带token参数连接被拒绝', 'error'); - log('请检查token是否正确,或服务器是否接受URL参数认证', 'error'); - }; - } catch (error) { - log(`测试2出错: ${error.message}`, 'error'); - } - }, 6000); - - log('认证测试已启动,请查看测试结果...', 'info'); - } - // 帮助函数:ArrayBuffer转Base64 function arrayBufferToBase64(buffer) { let binary = '';