ConfigService.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import { ServerConfig, ConnectionTestResult, ConfigValidation } from '../types';
  2. import { createStorageAdapter } from '../storage';
  3. import { ping } from '../../../API/serverConfigPing';
  4. /**
  5. * 默认服务器配置
  6. */
  7. export const DEFAULT_SERVER_CONFIG: ServerConfig = {
  8. ip: '127.0.0.1',
  9. apiPort: 80,
  10. mqttPort: 8083,
  11. };
  12. export class ConfigService {
  13. private static instance: ConfigService;
  14. private storage = createStorageAdapter();
  15. private readonly CONFIG_KEY = 'serverConfig';
  16. private constructor() {}
  17. static getInstance(): ConfigService {
  18. if (!ConfigService.instance) {
  19. ConfigService.instance = new ConfigService();
  20. }
  21. return ConfigService.instance;
  22. }
  23. /**
  24. * 获取默认配置
  25. */
  26. getDefaultConfig(): ServerConfig {
  27. return DEFAULT_SERVER_CONFIG;
  28. }
  29. /**
  30. * 获取服务器配置
  31. */
  32. async getServerConfig(): Promise<ServerConfig> {
  33. try {
  34. const configJson = await this.storage.getItem(this.CONFIG_KEY);
  35. if (configJson) {
  36. return JSON.parse(configJson);
  37. }
  38. } catch (error) {
  39. console.error('读取配置失败:', error);
  40. }
  41. return this.getDefaultConfig();
  42. }
  43. /**
  44. * 保存服务器配置
  45. */
  46. async saveServerConfig(config: ServerConfig): Promise<void> {
  47. await this.storage.setItem(
  48. this.CONFIG_KEY,
  49. JSON.stringify(config)
  50. );
  51. }
  52. /**
  53. * 验证 URL 格式
  54. */
  55. validateUrl(url: string): ConfigValidation {
  56. const errors: string[] = [];
  57. if (!url || url.trim() === '') {
  58. errors.push('地址不能为空');
  59. return { valid: false, errors };
  60. }
  61. try {
  62. const parsed = new URL(url);
  63. // 只允许 http 和 https
  64. if (!['http:', 'https:'].includes(parsed.protocol)) {
  65. errors.push('只支持 HTTP 和 HTTPS 协议');
  66. }
  67. // 检查端口范围
  68. if (parsed.port) {
  69. const port = parseInt(parsed.port);
  70. if (port < 1 || port > 65535) {
  71. errors.push('端口号必须在 1-65535 之间');
  72. }
  73. }
  74. } catch (e) {
  75. errors.push('URL 格式不正确');
  76. }
  77. return {
  78. valid: errors.length === 0,
  79. errors,
  80. };
  81. }
  82. /**
  83. * 验证 MQTT URL 格式
  84. */
  85. validateMqttUrl(url: string): ConfigValidation {
  86. const errors: string[] = [];
  87. if (!url || url.trim() === '') {
  88. errors.push('MQTT 地址不能为空');
  89. return { valid: false, errors };
  90. }
  91. try {
  92. const parsed = new URL(url);
  93. // 只允许 ws 和 wss
  94. if (!['ws:', 'wss:'].includes(parsed.protocol)) {
  95. errors.push('只支持 WS 和 WSS 协议');
  96. }
  97. } catch (e) {
  98. errors.push('MQTT URL 格式不正确');
  99. }
  100. return {
  101. valid: errors.length === 0,
  102. errors,
  103. };
  104. }
  105. /**
  106. * 测试连接 - 连续检测 10 次,每隔 1 秒
  107. */
  108. async testConnection(
  109. onProgress?: (progress: { current: number; total: number }) => void
  110. ): Promise<ConnectionTestResult> {
  111. // 连续检测 10 次
  112. for (let i = 0; i < 10; i++) {
  113. // 更新进度
  114. onProgress?.({ current: i + 1, total: 10 });
  115. try {
  116. console.log(`检测服务器连接 (${i + 1}/10)...`);
  117. const response = await ping();
  118. // 检查响应
  119. if (response.code === '0x000000' && response.data === 'pong') {
  120. return {
  121. success: true,
  122. message: `连接成功 (第 ${i + 1} 次检测)`,
  123. };
  124. } else {
  125. console.warn(`检测失败 (${i + 1}/10): 服务器响应异常 - ${response.description}`);
  126. }
  127. } catch (error: any) {
  128. console.warn(`检测失败 (${i + 1}/10):`, error.message);
  129. }
  130. // 等待 1 秒后进行下一次检测(最后一次不需要等待)
  131. if (i < 9) {
  132. await new Promise(resolve => setTimeout(resolve, 1000));
  133. }
  134. }
  135. // 所有检测都失败
  136. return {
  137. success: false,
  138. message: '连接失败,所有 10 次检测均未成功',
  139. };
  140. }
  141. /**
  142. * 清除配置
  143. */
  144. async clearConfig(): Promise<void> {
  145. await this.storage.removeItem(this.CONFIG_KEY);
  146. }
  147. }
  148. export default ConfigService.getInstance();