69 lines
3.2 KiB
JavaScript
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 })
|
|
}
|