// 切換 Node-RED 舊版「羽球報名」流程的開關(同一個 bot 只能有一個 polling 端) // // node scripts/nodered-switch.mjs pause # 停用 bd_tab、bot 設定改 send-only → 讓本專案接手 // node scripts/nodered-switch.mjs resume # 還原 Node-RED polling(本專案要先停) // node scripts/nodered-switch.mjs status // // 用 Node-RED admin API(http://:1880/flows),deploy type = nodes(只重啟有變動的節點)。 import 'dotenv/config' const BASE = (process.env.NODERED_URL || 'http://192.168.5.45:1880').replace(/\/$/, '') const TAB_ID = process.env.NODERED_BD_TAB || 'bd_tab' const BOT_CONFIG_ID = process.env.NODERED_BD_BOT || 'tgbot_bd_config' const mode = process.argv[2] if (!['pause', 'resume', 'status'].includes(mode)) { console.error('用法:node scripts/nodered-switch.mjs pause|resume|status') process.exit(1) } const headers = { 'Node-RED-API-Version': 'v2', 'Content-Type': 'application/json' } const res = await fetch(`${BASE}/flows`, { headers }) if (!res.ok) throw new Error(`GET /flows 失敗:${res.status}`) const { rev, flows } = await res.json() const tab = flows.find((n) => n.id === TAB_ID) const bot = flows.find((n) => n.id === BOT_CONFIG_ID) if (!tab || !bot) throw new Error(`找不到 ${TAB_ID} 或 ${BOT_CONFIG_ID}`) const show = () => console.log(`Node-RED ${BASE}\n ${TAB_ID}: ${tab.disabled ? '停用' : '啟用'}\n ${BOT_CONFIG_ID}.updatemode: ${bot.updatemode}`) if (mode === 'status') { show() process.exit(0) } if (mode === 'pause') { tab.disabled = true bot.updatemode = 'none' } else { tab.disabled = false bot.updatemode = 'polling' } const post = await fetch(`${BASE}/flows`, { method: 'POST', headers: { ...headers, 'Node-RED-Deployment-Type': 'nodes' }, body: JSON.stringify({ rev, flows }), }) if (!post.ok) throw new Error(`POST /flows 失敗:${post.status} ${await post.text()}`) console.log(`✅ 已${mode === 'pause' ? '暫停' : '恢復'} Node-RED 羽球報名流程(rev ${(await post.json()).rev.slice(0, 8)})`) show()