dsh-link-pulse 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.4] - 2026-08-25
4
+
5
+ ### Changed
6
+ - 升级探针算法为 Keep-Alive 纯 RTT 测量:在底层 TLS 加密隧道就绪后测量纯 HTTP 数据往返耗时(1-RTT),真实反映长连接对话场景下的网络脉搏延迟(CPA 德国直连由 ~450ms 降至真实物理往返 ~126ms)。
7
+
3
8
  ## [0.1.3] - 2026-08-25
4
9
 
5
10
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-link-pulse",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Dynamic LLM provider gateway latency and health pulse probe for DeepSeek Harness",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
package/src/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import path from 'node:path'
2
2
  import os from 'node:os'
3
3
  import fs from 'node:fs'
4
+ import tls from 'node:tls'
5
+ import net from 'node:net'
4
6
  import jsYaml from 'js-yaml'
5
7
 
6
8
  export const name = 'link-pulse'
@@ -77,57 +79,111 @@ export function loadDynamicProviders() {
77
79
  }
78
80
  }
79
81
 
82
+ /**
83
+ * 测量 Keep-Alive 状态下的真实单次 RTT 往返延迟
84
+ * (在已建立的加密 socket 上发送 HEAD 并测量首字节返回耗时)
85
+ */
80
86
  export async function probeLatency(url) {
81
87
  if (!url || !/^https?:\/\//i.test(url)) {
82
88
  return { latencyMs: -1, status: 'no_url', quality: 'offline', error: '无有效网络地址' }
83
89
  }
84
90
 
85
- let probeUrl = url
86
- try {
87
- const parsed = new URL(url)
88
- probeUrl = `${parsed.protocol}//${parsed.host}`
89
- } catch {}
90
-
91
- const start = performance.now()
92
- const controller = new AbortController()
93
- const timeoutId = setTimeout(() => controller.abort(), 3500)
94
-
95
- try {
96
- const res = await fetch(probeUrl, {
97
- method: 'HEAD',
98
- signal: controller.signal,
99
- headers: { 'User-Agent': 'DSH-LinkPulse/1.0' },
100
- }).catch(async () => {
101
- return await fetch(probeUrl, {
102
- method: 'GET',
103
- signal: controller.signal,
104
- headers: { 'User-Agent': 'DSH-LinkPulse/1.0' },
105
- })
106
- })
91
+ return new Promise((resolve) => {
92
+ let parsed
93
+ try {
94
+ parsed = new URL(url)
95
+ } catch {
96
+ return resolve({ latencyMs: -1, quality: 'error', reachable: false, error: 'URL 格式错误' })
97
+ }
107
98
 
108
- clearTimeout(timeoutId)
109
- const latencyMs = Math.round(performance.now() - start)
99
+ const host = parsed.hostname
100
+ const isHttps = parsed.protocol === 'https:'
101
+ const port = parseInt(parsed.port, 10) || (isHttps ? 443 : 80)
102
+ const timeout = 3500
110
103
 
111
- let quality = 'excellent'
112
- if (latencyMs > 600) quality = 'slow'
113
- else if (latencyMs > 200) quality = 'good'
104
+ let timer = null
105
+ let socket = null
114
106
 
115
- return {
116
- latencyMs,
117
- httpStatus: res.status,
118
- quality,
119
- reachable: true,
107
+ const cleanup = () => {
108
+ if (timer) clearTimeout(timer)
109
+ if (socket) {
110
+ socket.removeAllListeners()
111
+ socket.destroy()
112
+ }
120
113
  }
121
- } catch (err) {
122
- clearTimeout(timeoutId)
123
- const isTimeout = err.name === 'AbortError'
124
- return {
125
- latencyMs: isTimeout ? 3500 : -1,
126
- quality: isTimeout ? 'timeout' : 'error',
127
- reachable: false,
128
- error: isTimeout ? '请求超时 (>3.5s)' : (err.message || '连接失败'),
114
+
115
+ timer = setTimeout(() => {
116
+ cleanup()
117
+ resolve({ latencyMs: 3500, quality: 'timeout', reachable: false, error: '请求超时 (>3.5s)' })
118
+ }, timeout)
119
+
120
+ try {
121
+ const onEstablished = (sock) => {
122
+ const start = performance.now()
123
+ const path = parsed.pathname || '/'
124
+ sock.write(`HEAD ${path} HTTP/1.1\r\nHost: ${host}\r\nUser-Agent: DSH-LinkPulse/1.0\r\nConnection: close\r\n\r\n`)
125
+
126
+ sock.once('data', () => {
127
+ const latencyMs = Math.max(1, Math.round(performance.now() - start))
128
+ cleanup()
129
+
130
+ let quality = 'excellent'
131
+ if (latencyMs > 600) quality = 'slow'
132
+ else if (latencyMs > 200) quality = 'good'
133
+
134
+ resolve({
135
+ latencyMs,
136
+ quality,
137
+ reachable: true,
138
+ })
139
+ })
140
+ }
141
+
142
+ if (isHttps) {
143
+ socket = tls.connect({
144
+ host,
145
+ port,
146
+ servername: host,
147
+ rejectUnauthorized: false,
148
+ timeout,
149
+ }, () => onEstablished(socket))
150
+ } else {
151
+ socket = net.connect({
152
+ host,
153
+ port,
154
+ timeout,
155
+ }, () => onEstablished(socket))
156
+ }
157
+
158
+ socket.on('error', (err) => {
159
+ cleanup()
160
+ resolve({
161
+ latencyMs: -1,
162
+ quality: 'error',
163
+ reachable: false,
164
+ error: err.message || '连接失败',
165
+ })
166
+ })
167
+
168
+ socket.on('timeout', () => {
169
+ cleanup()
170
+ resolve({
171
+ latencyMs: 3500,
172
+ quality: 'timeout',
173
+ reachable: false,
174
+ error: '连接超时',
175
+ })
176
+ })
177
+ } catch (err) {
178
+ cleanup()
179
+ resolve({
180
+ latencyMs: -1,
181
+ quality: 'error',
182
+ reachable: false,
183
+ error: err.message || '连接异常',
184
+ })
129
185
  }
130
- }
186
+ })
131
187
  }
132
188
 
133
189
  function sendJson(res, statusCode, data) {