import cp from 'child_process'
import path from 'path'
import fs from 'fs'
import JSON5 from 'json5'
import get from 'lodash-es/get.js'
import genPm from 'wsemi/src/genPm.mjs'
import isearr from 'wsemi/src/isearr.mjs'
import isestr from 'wsemi/src/isestr.mjs'
import isbol from 'wsemi/src/isbol.mjs'
import pmSeries from 'wsemi/src/pmSeries.mjs'
import fsIsFile from 'wsemi/src/fsIsFile.mjs'
import fsIsFolder from 'wsemi/src/fsIsFolder.mjs'
import now2str from 'wsemi/src/now2str.mjs'
import now2strp from 'wsemi/src/now2strp.mjs'
import strright from 'wsemi/src/strright.mjs'
import o2j from 'wsemi/src/o2j.mjs'
import fsCreateFolder from 'wsemi/src/fsCreateFolder.mjs'
import execProcess from 'wsemi/src/execProcess.mjs'
let logFd = '' //若由排程呼叫且不給logFd絕對路徑時, 預設是位於C:\Windows\system32
let logWhenSuccess = false
let logWhenError = true
async function readSetting(fpSetting) {
//check
if (!fsIsFile(fpSetting)) {
return Promise.reject('input path is not file')
}
//read and parse
let r = null
try {
//readFileSync
let c = fs.readFileSync(fpSetting, 'utf8')
//parse
r = JSON5.parse(c)
}
catch (err) {
return Promise.reject(err)
}
return r
}
/**
* 背景執行程序
*
* @class
* @param {Array|String} inp 輸入設定陣列或設定檔名稱字串
* @returns {Promise} 回傳Promise,revolve回傳成功訊息,reject回傳錯誤訊息
* @example
*
* let inp = [
* {
* "settings":{
* "logFd":"./testLog",
* "logWhenSuccess":true,
* "logWhenError":true,
* },
* },
* {
* "prog":"node",
* "args":"-v",
* "wait":true,
* },
* ]
* let msg = await WBatch(inp)
* console.log('msg', msg)
*
*/
async function WBatch(inp) {
async function core(inp) {
let s
//check
if (isearr(inp)) {
s = inp
}
else if (isestr(inp)) {
s = await readSetting(inp)
}
else {
return Promise.reject('input is not a string for path of json file or not an array for settings')
}
//msg
let msg = []
try {
//pmSeries, 需循序操作
await pmSeries(s, async (v) => {
//settings
let settings = get(v, 'settings', null)
if (settings !== null) {
//logFd
let _logFd = get(settings, 'logFd', null)
if (isestr(_logFd)) {
logFd = _logFd
}
//logWhenSuccess
let _logWhenSuccess = get(settings, 'logWhenSuccess', null)
if (isbol(_logWhenSuccess)) {
logWhenSuccess = _logWhenSuccess
}
//logWhenError
let _logWhenError = get(settings, 'logWhenError', null)
if (isbol(_logWhenError)) {
logWhenError = _logWhenError
}
return
}
//prog
let prog = get(v, 'prog', '')
if (!isestr(prog)) {
msg.push('invalid prog')
return
}
//args
let args = get(v, 'args', [])
if (isestr(args)) {
args = [args] //為單參數之指令字串時才能自動轉陣列, 若為多參數之指令字串得要切分成陣列
}
//wait
let wait = get(v, 'wait', true)
if (!isbol(wait)) {
wait = true
}
//wait
// console.log('prog', prog)
// console.log('args', args)
// console.log('wait', wait)
if (wait) {
// console.log('call execProcess')
await execProcess(prog, args)
.then((res) => {
// console.log('res', res)
msg.push(res)
})
.catch((err) => {
// console.log('err', err)
msg.push(err)
})
}
else {
// console.log('call spawn')
let ls = cp.spawn(prog, args, { encoding: 'utf8' })
ls.stdout.on('data', (data) => {
// console.log(`stdout: ${data}`)
msg.push(`stdout: ${data}`)
})
ls.stderr.on('data', (data) => {
// console.log(`stderr: ${data}`)
msg.push(`stderr: ${data}`)
})
ls.on('close', (code) => {
// console.log(`child process exited with code ${code}`)
msg.push(`close: code[${code}]`)
})
}
})
}
catch (err) {
return Promise.reject(err)
}
//finish
let r = `finish at ${now2str()}`
msg.push(r)
return msg
}
function logMsg(type, msg) {
if (logFd !== '') {
//logFd
if (strright(logFd, 1) !== path.sep) {
logFd += path.sep
}
//check
if (!fsIsFolder(logFd)) {
fsCreateFolder(logFd)
}
//fn
let fn = `${type}-${now2strp()}.log`
fn = logFd + fn
console.log(`output ${type} to: ${path.resolve(fn)}`)
//msg
msg = o2j(msg, true)
//write
fs.writeFileSync(fn, msg, 'utf8')
}
}
//pm
let pm = genPm()
//core
core(inp)
.then((msg) => {
//console.log('then', msg)
if (logWhenSuccess) {
logMsg('success', msg)
}
pm.resolve(msg)
})
.catch((err) => {
//console.log('catch', err)
if (logWhenError) {
logMsg('error', err)
}
pm.reject(err)
})
return pm
}
export default WBatch