import { app, net } from 'electron' import type { LicenseSession, VersionInfo, } from '../../src/shared/types' import { buildDesktopRequestHeaders } from './server-api-headers' interface ApiResult { code: string msg: string data: T } export interface DevicePayload { deviceId: string deviceName: string osName: string osVersion: string appVersion: string } export class ServerApiError extends Error { constructor( public readonly code: string, message: string, ) { super(message) this.name = 'ServerApiError' } } const DEFAULT_API_BASE_URL = 'https://apimall.v2.jxxyk.com/api' export class DesktopServerApi { private readonly baseUrl: string constructor(baseUrl = process.env.IMAGE_TOOL_API_BASE_URL || DEFAULT_API_BASE_URL) { this.baseUrl = this.validateBaseUrl(baseUrl) } activate(activationCode: string, device: DevicePayload): Promise { return this.post('/desktop/activate', { activationCode, ...device, }) } login(token: string, device: DevicePayload): Promise { return this.post('/desktop/login', { token, ...device, }) } checkVersion(currentVersion: string): Promise { return this.post('/desktop/version/check', { currentVersion, platform: 'windows', }) } private async post(pathname: string, body: unknown): Promise { const controller = new AbortController() const timeout = setTimeout(() => controller.abort(), 15_000) try { const response = await net.fetch(`${this.baseUrl}${pathname}`, { method: 'POST', headers: buildDesktopRequestHeaders(app.getVersion()), body: JSON.stringify(body), signal: controller.signal, }) if (!response.ok) { throw new ServerApiError(String(response.status), `授权服务暂时不可用(${response.status})`) } const result = (await response.json()) as ApiResult if (result.code !== '0') { throw new ServerApiError(result.code, result.msg || '授权校验失败') } return result.data } catch (error) { if (error instanceof ServerApiError) { throw error } if (error instanceof Error && error.name === 'AbortError') { throw new ServerApiError('NETWORK_TIMEOUT', '连接授权服务超时,请检查网络后重试') } throw new ServerApiError('NETWORK_ERROR', '无法连接授权服务,请检查网络后重试') } finally { clearTimeout(timeout) } } private validateBaseUrl(value: string): string { const url = new URL(value.trim()) const localDevelopment = url.protocol === 'http:' && ['127.0.0.1', 'localhost'].includes(url.hostname) if (url.protocol !== 'https:' && !(localDevelopment && !app.isPackaged)) { throw new Error('生产授权服务必须使用 HTTPS') } return url.toString().replace(/\/$/, '') } }