run-process.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #!/usr/bin/env node
  2. /**
  3. * run-process.js
  4. * 接收两个参数:ip 数组 (JSON)、脚本名
  5. * 异步根据每个 ip 执行脚本;执行前先 adb connect 该设备,确保连接成功再跑流程。
  6. *
  7. * 调用示例:node run-process.js '["192.168.2.5","192.168.2.6"]' 'RedNoteAIThumbsUp'
  8. */
  9. const path = require('path')
  10. const fs = require('fs')
  11. const { execSync } = require('child_process')
  12. const projectRoot = path.resolve(path.join(__dirname, '..'))
  13. const staticRoot = process.env.STATIC_ROOT ? path.resolve(process.env.STATIC_ROOT) : path.join(projectRoot, 'static')
  14. const config = require(path.join(projectRoot, 'configs', 'config.js'))
  15. const adbPath = config.adbPath?.path
  16. ? path.resolve(projectRoot, config.adbPath.path)
  17. : path.join(projectRoot, 'lib', 'scrcpy-adb', 'adb.exe')
  18. const ADB_PORT = 5555
  19. const ipListJson = process.argv[2]
  20. const scriptName = process.argv[3]
  21. if (!scriptName) {
  22. process.stderr.write('run-process: missing scriptName\n')
  23. process.exit(1)
  24. }
  25. const folderPath = path.resolve(path.join(staticRoot, 'process', scriptName))
  26. function writeLog(folderPath, message) {
  27. const logFile = path.join(folderPath, 'log.txt')
  28. if (!fs.existsSync(folderPath)) fs.mkdirSync(folderPath, { recursive: true })
  29. const ts = new Date().toISOString().replace('T', ' ').slice(0, 19)
  30. fs.appendFileSync(logFile, `[${ts}] ${message}\n`)
  31. }
  32. try {
  33. writeLog(folderPath, `[run-process] start scriptName=${scriptName} folderPath=${folderPath}`)
  34. } catch (e) {
  35. process.stderr.write(`run-process: writeLog failed ${e.message}\n`)
  36. }
  37. let ipList
  38. try {
  39. ipList = JSON.parse(ipListJson || '[]')
  40. } catch (e) {
  41. writeLog(folderPath, `[错误] 解析 IP 列表失败: ${e.message}`)
  42. process.exit(1)
  43. }
  44. let shouldStop = false
  45. let actions
  46. try {
  47. const { parseWorkflow } = require('./ef-compiler/ef-compiler.js')
  48. actions = parseWorkflow(JSON.parse(fs.readFileSync(path.join(folderPath, 'process.json'), 'utf8'))).actions
  49. } catch (e) {
  50. writeLog(folderPath, `[错误] 加载 process.json 失败: ${e.message}`)
  51. process.exit(1)
  52. }
  53. const { executeActionSequence } = require('./ef-compiler/ef-compiler.js')
  54. const resolution = { width: 1080, height: 1920 }
  55. /** 对指定 IP 执行 adb connect,确保设备在列表中后再跑流程 */
  56. function ensureDeviceConnected(ip, port) {
  57. const out = execSync(`"${adbPath}" connect ${ip}:${port}`, { encoding: 'utf-8' }).trim()
  58. return out.includes('connected') || out.includes('already connected')
  59. }
  60. /** 启动执行:遍历 ip 列表并异步执行脚本;任一台失败则停止全部并返回失败设备 IP */
  61. async function start() {
  62. if (!ipList || ipList.length === 0) {
  63. writeLog(folderPath, '[run-process] 无设备,退出')
  64. process.stdout.write(JSON.stringify({ success: true, results: [] }) + '\n')
  65. process.exit(0)
  66. }
  67. writeLog(folderPath, `[run-process] 开始执行 ${ipList.length} 台设备: ${ipList.join(', ')}`)
  68. let failedIp = null
  69. const runOne = async (ip) => {
  70. if (shouldStop) return { ip, success: false, stopped: true }
  71. const connected = ensureDeviceConnected(ip, ADB_PORT)
  72. if (!connected) {
  73. writeLog(folderPath, `[run-process] ${ip}:${ADB_PORT} 连接未就绪,跳过`)
  74. return { ip, success: false }
  75. }
  76. const result = await executeActionSequence(actions, `${ip}:${ADB_PORT}`, folderPath, resolution, 1000, null, () => shouldStop)
  77. if (!result.success) {
  78. if (!failedIp) { failedIp = ip; shouldStop = true }
  79. }
  80. return { ip, success: result.success }
  81. }
  82. const results = await Promise.all(ipList.map(ip => runOne(ip)))
  83. const output = failedIp
  84. ? { success: false, failedIp, results }
  85. : { success: true, results }
  86. process.stdout.write(JSON.stringify(output) + '\n')
  87. process.exit(failedIp ? 1 : 0)
  88. }
  89. /** 停止执行(SIGTERM/SIGINT 时调用) */
  90. function stop() {
  91. shouldStop = true
  92. }
  93. process.on('SIGTERM', () => { stop(); process.exit(130) })
  94. process.on('SIGINT', () => { stop(); process.exit(130) })
  95. start()