WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s

This commit is contained in:
yawan
2026-09-22 16:19:06 +08:00
commit f7fc992f57
3929 changed files with 1006607 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
const fs = require('node:fs')
const path = require('node:path')
const { execFile } = require('node:child_process')
const { promisify } = require('node:util')
const execute = promisify(execFile)
const directory = path.resolve(__dirname, '../../acceptance')
const startedAt = new Date().toISOString()
const reportPath = path.join(directory, `public-latency-${startedAt.replace(/[:.]/g, '-')}.json`)
const report = { started_at: startedAt, samples: [], summaries: [] }
const headerNames = ['cache-control', 'cf-cache-status', 'cf-ray', 'age', 'etag', 'last-modified', 'content-type', 'content-encoding', 'content-length', 'vary', 'server']
const measurementFormat = '\n__BEGIN__%{json}__HEADERS__%{header_json}__END__\n'
function decode(output, label, url) {
return [...output.matchAll(/__BEGIN__([\s\S]*?)__HEADERS__([\s\S]*?)__END__/g)].map((match, index) => {
const measurement = JSON.parse(match[1])
const headers = JSON.parse(match[2])
const ms = (value) => Math.round(value * 1000000) / 1000
return {
label, url, connection_sequence: index + 1,
status: measurement.http_code, exit_code: measurement.exitcode,
http_version: measurement.http_version, new_connections: measurement.num_connects,
remote_ip: measurement.remote_ip, downloaded_bytes: measurement.size_download,
dns_ms: ms(measurement.time_namelookup),
connect_ms: ms(measurement.time_connect), tls_ms: ms(measurement.time_appconnect),
ttfb_ms: ms(measurement.time_starttransfer), total_ms: ms(measurement.time_total),
wait_after_request_ready_ms: ms(measurement.time_starttransfer - measurement.time_pretransfer),
headers: Object.fromEntries(headerNames.filter(name => headers[name]).map(name => [name, headers[name]])),
}
})
}
async function measure(label, url, family, repetitions = 1) {
const args = ['--silent', '--show-error', '--compressed', '--connect-timeout', '8', '--max-time', '15', '--write-out', measurementFormat]
if (family) args.push(family)
for (let index = 0; index < repetitions; index++) args.push('--output', '/dev/null', url)
let result
try { result = await execute('curl', args, { maxBuffer: 1024 * 1024 }) }
catch (error) { result = error }
const samples = decode(result.stdout || '', label, url)
if (!samples.length) samples.push({ label, url, failed: true, exit_code: result.code || 1 })
report.samples.push(...samples)
console.log(JSON.stringify({ label, samples: samples.map(sample => ({ status: sample.status, ttfb_ms: sample.ttfb_ms, total_ms: sample.total_ms, exit_code: sample.exit_code })) }))
}
async function tunnelMetrics() {
try {
const response = await fetch('http://127.0.0.1:20241/metrics', { signal: AbortSignal.timeout(3000) })
const lines = (await response.text()).split('\n')
return lines.filter(line => /^cloudflared_tunnel_(?:ha_connections|request_errors|total_requests|server_locations)/.test(line))
} catch { return ['metrics_unavailable'] }
}
function summarize() {
for (const label of new Set(report.samples.map(sample => sample.label))) {
const samples = report.samples.filter(sample => sample.label === label && sample.exit_code === 0)
const median = key => {
const values = samples.map(sample => sample[key]).sort((a, b) => a - b)
const middle = Math.floor(values.length / 2)
return values.length ? (values.length % 2 ? values[middle] : (values[middle - 1] + values[middle]) / 2) : null
}
report.summaries.push({ label, successful_samples: samples.length,
dns_median_ms: median('dns_ms'), connect_median_ms: median('connect_ms'), tls_median_ms: median('tls_ms'),
ttfb_median_ms: median('ttfb_ms'), total_median_ms: median('total_ms'), wait_median_ms: median('wait_after_request_ready_ms'),
cache_states: [...new Set(samples.flatMap(sample => sample.headers?.['cf-cache-status'] || []))],
edge_locations: [...new Set(samples.flatMap(sample => sample.headers?.['cf-ray']?.map(ray => ray.split('-').at(-1)) || []))],
})
}
}
async function main() {
report.tunnel_before = await tunnelMetrics()
const targets = [
['html', '/login'],
['small_static', '/assets/favicon-bEsoBimf.ico'],
['api_guard', '/api/v1/auth/me'],
]
for (let round = 0; round < 3; round++) {
for (const [name, resource] of targets) {
await measure(`origin_${name}`, `http://127.0.0.1:18088${resource}`)
await measure(`public_ipv4_${name}`, `https://agent.pducv.cn${resource}`, '--ipv4')
await measure(`public_ipv6_${name}`, `https://agent.pducv.cn${resource}`, '--ipv6')
}
await measure('backend_health', 'http://127.0.0.1:18080/health')
}
for (const [label, family] of [['ipv4', '--ipv4'], ['ipv6', '--ipv6']]) {
await measure(`public_${label}_warm_html`, 'https://agent.pducv.cn/login', family, 3)
await measure(`public_${label}_config`, 'https://agent.pducv.cn/config.js', family)
await measure(`public_${label}_icons`, 'https://agent.pducv.cn/tdesign-icons/0.4.1/fonts/index.js', family)
}
await measure('origin_config', 'http://127.0.0.1:18088/config.js')
await measure('origin_icons', 'http://127.0.0.1:18088/tdesign-icons/0.4.1/fonts/index.js')
report.tunnel_after = await tunnelMetrics()
}
main().catch(error => { report.error = error.name; process.exitCode = 1 }).finally(() => {
report.completed_at = new Date().toISOString()
summarize()
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2) + '\n', { flag: 'wx' })
console.log(JSON.stringify({ report: reportPath, summaries: report.summaries, error: report.error }))
})