import path from 'path'
import fs from 'fs'
import events from 'events'
import get from 'lodash-es/get.js'
import now2str from './now2str.mjs'
import haskey from './haskey.mjs'
import isbol from './isbol.mjs'
import isstr from './isstr.mjs'
import isestr from './isestr.mjs'
import iseobj from './iseobj.mjs'
import ispint from './ispint.mjs'
import cint from './cint.mjs'
import j2o from './j2o.mjs'
import o2j from './o2j.mjs'
import getFileTrueName from './getFileTrueName.mjs'
import fsCreateFolder from './fsCreateFolder.mjs'
import fsIsFolder from './fsIsFolder.mjs'
import fsDeleteFolder from './fsDeleteFolder.mjs'
import fsWatchFolder from './fsWatchFolder.mjs'
/**
* 後端nodejs跨程序事件發布與訂閱,主要為通過檔案內容變更與監測進行傳遞事件
*
* 因使用chokidar,變更至少要3秒才能監測,不適用於頻繁觸發事件之工作
*
* Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/fsEvem.test.mjs Github}
* @memberOf wsemi
* @param {Object} [opt={}] 輸入設定物件,預設{}
* @param {String} [opt.fd='./_evps'] 輸入建置事件檔案所在資料夾路徑字串,預設'./_evps'
* @param {Boolean} [opt.polling=false] 輸入是否使用輪循布林值,代表chokidar的usePolling,預設為false
* @param {Integer} [opt.timeInterval=100] 輸入當polling為true時偵測檔案變更間隔時間整數,代表chokidar開啟polling時的interval,單位為毫秒ms,預設為100
* @param {Integer} [opt.timeBinaryInterval=300] 輸入當polling為true時偵測二進位檔案變更間隔時間整數,代表chokidar開啟polling時的binaryInterval,單位為毫秒ms,預設為300
* @returns {Object} 回傳事件物件,包含on、clear函數,on可進行監聽指定事件,clear為停止全部監聽,不須輸入
* @example
* need test in nodejs.
*
* import fsDeleteFolder from './src/fsDeleteFolder.mjs'
* import fsEvem from './src/fsEvem.mjs'
*
* let test = async () => {
* return new Promise((resolve, reject) => {
* let ms = []
*
* fsDeleteFolder('./_evps')
*
* let ev = fsEvem()
*
* ev.on('conut', (msg) => {
* console.log('conut', msg)
* ms.push(msg)
* })
*
* let n = 0
* let t = setInterval(() => {
* n++
* ev.emit('conut', n)
* if (n >= 3) {
* clearTimeout(t)
* }
* }, 3000)
*
* setTimeout(() => {
* ev.clear()
* console.log('ms', ms)
* resolve(ms)
* }, 12000)
*
* })
* }
* test()
* .catch(() => {})
* // conut 1
* // conut 2
* // conut 3
* // ms [ 1, 2, 3 ]
*
*/
function fsEvem(opt = {}) {
//fd
let fd = get(opt, 'fd')
if (!isestr(fd)) {
fd = './_evps'
}
//polling
let polling = get(opt, 'polling')
if (!isbol(polling)) {
polling = false
}
//timeInterval
let timeInterval = get(opt, 'timeInterval')
if (!ispint(timeInterval)) {
timeInterval = 100
}
timeInterval = cint(timeInterval)
//timeBinaryInterval
let timeBinaryInterval = get(opt, 'timeBinaryInterval')
if (!ispint(timeBinaryInterval)) {
timeBinaryInterval = 300
}
timeBinaryInterval = cint(timeBinaryInterval)
//keySys
let keySys = get(opt, 'keySys')
if (!isestr(keySys)) {
keySys = '[::pkg_content::]'
}
//check
if (!fsIsFolder(fd)) {
fsCreateFolder(fd)
}
//writeEventFile
let writeEventFile = (evName, msg) => {
// console.log('writeEventFile', evName, msg)
//fp
let fp = path.resolve(fd, evName)
// console.log('watchEmit fp ', fp)
//check
if (isstr(msg)) {
//不用處理
}
else {
msg = o2j(msg)
}
//writeFileSync
fs.writeFileSync(fp, msg, 'utf8')
// console.log('writeFileSync', fp, msg)
}
//evl
let evl = fsWatchFolder(fd, {
polling,
timeInterval,
timeBinaryInterval,
})
//change
evl.on('change', (msg) => {
// console.log('fsWatchFolder change', msg.type, msg.fp)
//check
if (msg.type !== 'add' && msg.type !== 'change') {
return
}
// console.log('msg.type', msg.type)
//evName
let evName = getFileTrueName(msg.fp)
// console.log('evName', evName)
//content
let content = ''
try {
content = fs.readFileSync(msg.fp, 'utf8')
content = j2o(content)
}
catch (err) {}
// console.log(evName, content)
//check
if (!iseobj(content)) {
return
}
//emit
ev.emit(evName, { [keySys]: content })
})
//clear
let clear = () => {
evl.clear()
fsDeleteFolder(fd)
}
//ev
let ev = new events.EventEmitter()
let emt = ev.emit
ev.emit = function (evName, msg) { //攔截emit與額外處理, 因使用this記得須維持使用funtion
// console.log('攔截ev.emit', evName, msg)
let b = false
if (iseobj(msg)) {
b = haskey(msg, keySys)
}
if (b) {
// console.log('攔截回call', evName, msg)
let value = get(msg, keySys, null)
let pkg = get(value, 'pkg', '')
let time = get(value, 'time', '')
return emt.call(this, evName, pkg, time)
}
else {
// console.log('攔截不回call改寫檔', evName, msg)
writeEventFile(evName, {
pkg: msg,
time: now2str(),
})
}
}
//save
ev.clear = clear
return ev
}
export default fsEvem