Files
SpineParticlesWeb/scripts/verify-spine-connector.mjs
2026-09-05 16:20:23 +08:00

69 lines
3.2 KiB
JavaScript

import { mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
const root = new URL('../', import.meta.url)
const connectorUrl = process.env.SPINE_CONNECTOR_URL || 'http://127.0.0.1:27843'
const origin = process.env.SPINE_CONNECTOR_TEST_ORIGIN || 'http://127.0.0.1:5173'
const imagePath = new URL('public/images/star.png', root)
const healthResponse = await fetch(`${connectorUrl}/v1/health`, { headers: { Origin: origin } })
if (!healthResponse.ok) throw new Error(`连接器健康检查失败:HTTP ${healthResponse.status}`)
const health = await healthResponse.json()
if (!health.authorized) throw new Error('测试来源没有获得连接器授权')
if (!health.spineFound) throw new Error('连接器没有找到本机 Spine')
const skeletonJson = JSON.stringify({
skeleton: { spine: '4.2', images: './images/', fps: 30 },
bones: [{ name: 'root' }, { name: 'particle', parent: 'root' }],
slots: [{ name: 'particle', bone: 'particle', attachment: 'star' }],
skins: [{ name: 'default', attachments: { particle: { star: { path: 'star', width: 64, height: 64 } } } }],
animations: { animation: {} },
})
const image = await readFile(imagePath)
const payload = {
schemaVersion: 1,
projectName: 'Spine粒子连接器测试',
spineVersion: JSON.parse(skeletonJson).skeleton.spine,
skeletonJson,
images: [{ path: 'star.png', dataBase64: image.toString('base64') }],
}
const response = await fetch(`${connectorUrl}/v1/convert`, {
method: 'POST',
headers: { Origin: origin, 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
})
if (!response.ok) throw new Error(`转换失败:${await response.text()}`)
const temp = await mkdtemp(join(tmpdir(), 'spine-connector-verify-'))
const output = join(temp, 'SpineParticleConnectorTest.zip')
try {
const archive = Buffer.from(await response.arrayBuffer())
await writeFile(output, archive)
const info = await stat(output)
if (!info.isFile() || info.size === 0 || archive.readUInt32LE(0) !== 0x04034b50) throw new Error('连接器返回的不是有效 ZIP')
const entries = []
let offset = 0
while (offset + 30 <= archive.length && archive.readUInt32LE(offset) === 0x04034b50) {
const size = archive.readUInt32LE(offset + 18)
const nameLength = archive.readUInt16LE(offset + 26)
const extraLength = archive.readUInt16LE(offset + 28)
const name = archive.subarray(offset + 30, offset + 30 + nameLength).toString('utf8')
entries.push({ name, size })
offset += 30 + nameLength + extraLength + size
}
if (!entries.some((entry) => entry.name.endsWith('.spine') && entry.size > 0)) throw new Error('ZIP 中缺少 .spine 工程')
if (!entries.some((entry) => entry.name === 'images/star.png' && entry.size === image.length)) throw new Error('ZIP 中缺少 images/star.png')
console.log(JSON.stringify({
connectorVersion: health.connectorVersion,
requestedSpineVersion: payload.spineVersion,
actualSpineVersion: response.headers.get('x-spine-editor-version'),
encodedFileName: response.headers.get('x-spine-file-name'),
imageCount: payload.images.length,
archiveBytes: info.size,
entries,
}, null, 2))
} finally {
await rm(temp, { recursive: true, force: true })
}