desktop-service-sync.mjs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. import { join, resolve } from 'node:path'
  2. import { homedir } from 'node:os'
  3. import { createHash } from 'node:crypto'
  4. import { mkdirSync } from 'node:fs'
  5. import { LaunchAgentService, synchronizeDesktop, stopDesktopService } from './lib/service-update.mjs'
  6. import { migrateManagedDataHome } from './lib/managed-data-migration.mjs'
  7. // Losing the App's progress pipe must not interrupt a durable service transaction.
  8. process.stdout.on('error', error => { if (!['EPIPE', 'EIO'].includes(error.code)) process.exitCode = 1 })
  9. let input = ''
  10. for await (const bytes of process.stdin) { input += bytes; if (input.length > 32768) throw new Error('同步参数过大') }
  11. try {
  12. const options = JSON.parse(input)
  13. const home = resolve(options.home), port = Number(options.port)
  14. if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error('本机服务端口无效')
  15. if (options.action === 'migrate') {
  16. if (!options.fixture) await migrateManagedDataHome({ home, port, onProgress: message => process.stdout.write(JSON.stringify({ message }) + '\n') })
  17. process.stdout.write(JSON.stringify({ result: { action: 'migrated' } }) + '\n')
  18. process.exit(0)
  19. }
  20. mkdirSync(home, { recursive: true, mode: 0o700 })
  21. // Fixture mode isolates *all* service/update state, including launchd labels.
  22. const fixture = options.fixture === true
  23. const releaseRoot = fixture ? join(home, 'updates', 'fixture-releases') : join(homedir(), '.local', 'share', 'hermes-yaoyao')
  24. const label = fixture ? `cn.samien.yaoyao.sync-test.${createHash('sha256').update(home).digest('hex').slice(0, 16)}` : 'com.samien.hermes-yaoyao'
  25. const driver = new LaunchAgentService({ home, port, releaseRoot, label,
  26. plistPath: fixture ? join(home, 'updates', 'fixture-service.plist') : undefined,
  27. environment: options.environment,
  28. })
  29. if(options.action!==undefined&&!['sync','stop'].includes(options.action))throw new Error('本机服务操作无效')
  30. const onProgress = message => process.stdout.write(JSON.stringify({ message }) + '\n')
  31. const result = options.action==='stop'
  32. ? await stopDesktopService({home,driver,onProgress})
  33. : await synchronizeDesktop({ home, runtimeRoot: resolve(options.runtimeRoot), releaseRoot, driver, onProgress })
  34. const current = result.current
  35. process.stdout.write(JSON.stringify({ result: { action: result.action, current: current && {
  36. version: current.version, commit: current.commit, buildNumber: current.buildNumber, artifactDigest: current.artifactDigest,
  37. } } }) + '\n')
  38. } catch (error) {
  39. process.stdout.write(JSON.stringify({ error: error.message, code: error.code }) + '\n'); process.exitCode = 1
  40. }