fsGetFileHashCore.mjs

import get from 'lodash-es/get.js'
import genPm from './genPm.mjs'
import fsIsFileCore from './fsIsFileCore.mjs'
import isestr from './isestr.mjs'
import fsGetFileBasicHashCore from './fsGetFileBasicHashCore.mjs'
import fsGetFileXxHashCore from './fsGetFileXxHashCore.mjs'
import errToStr from './_errToStr.mjs'
import optVal from './_optVal.mjs'
import chkFsPath from './_chkFsPath.mjs'


//chunkSize: opt類參數, 有效整數且為個數(iseint, use: 'count', 1~2^30, 同fsGetFileXxHashCore), 非預期改用預設64mb; 於此即判定並改用預設, 傳給fsGetFileXxHashCore者為解析後之值
let RULE_CHUNK_SIZE = { fn: 'fsGetFileHashCore', name: 'opt.chunkSize', kind: 'eint', chk: { use: 'count', min: 1, max: 2 ** 30 } }


/**
 * 後端nodejs計算檔案HASH值
 *
 * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/fsGetFileHashCore.test.mjs Github}
 * @memberOf wsemi
 * @param {String} fp 輸入檔案路徑字串
 * @param {Object} [opt={}] 輸入設定物件,預設{}
 * @param {String} [opt.type='sha512'] 輸入計算HASH方法字串,預設'sha512'
 * @param {Number|String} [opt.chunkSize=64*1024*1024] 輸入計算HASH方法字串為'xxhash64'時,使用切片長度,單位位元,opt類參數(有效整數,1~2^30即1024*1024*1024即1gb,數字字串亦可,去頭尾空白後取值),非預期之輸入(非有效整數、0、負數、小數、超過上限、Infinity、'0x10'、包裝物件等)視為未給而改用預設,不報錯,預設64*1024*1024(64mb)
 * @param {Boolean} [opt.debug=false] 輸入是否於chunkSize為非預期之輸入而改用預設時輸出警告,非布林視為false,警告為固定詞彙(不含傳入之值),同一參數每個行程只警告一次,預設false
 * @param {Function} [opt.funLog=null] 輸入警告出口函數,以(msg, { fn, reason, key })呼叫,未給則用console.warn,預設null
 * @returns {Promise} 回傳Promise,resolve回傳檔案HASH值,reject回傳錯誤訊息字串,路徑參數須為非空字串且不含NUL字元,無效時reject說明字串(如'invalid <參數名>: must be a non-empty string',不帶輸入值,與路徑不存在分開)
 * @example
 * need test in nodejs.
 *
 * //see fsGetFileHash
 *
 */
function fsGetFileHashCore(fp, opt = {}) {

    //pm
    let pm = genPm()

    //check, 路徑須為非空字串(無效與不存在分開判定, 不走到fs, 不回顯輸入值; R-FS-INVALID-PATH-01)
    let msgFp = chkFsPath(fp, 'fp')
    if (msgFp) {
        pm.reject(msgFp)
        return pm
    }

    //讀取opt與check, 本函數非async, opt本身或其屬性不可讀(getter拋錯、已撤銷之Proxy)時get拋出與注入之fs之lstatSync拋錯須於此攔截, 否則成同步拋錯
    let fs = null
    let crypto = null
    let type = ''
    let chunkSize = 0
    let isFile = false
    try {

        //fs, crypto
        fs = get(opt, 'fs')
        crypto = get(opt, 'crypto')

        //type
        type = get(opt, 'type', '')
        if (!isestr(type)) {
            type = 'sha512'
        }

        //chunkSize, opt類參數(預設64mb), 須為有效整數且為1~2^30, 非預期(含Infinity、0、負數、小數、超過上限)視為未給、改用預設
        chunkSize = optVal(get(opt, 'chunkSize'), 64 * 1024 * 1024, RULE_CHUNK_SIZE, opt)

        //check
        isFile = fsIsFileCore(fp, { fs })

    }
    catch (err) {
        pm.reject(errToStr(err))
        return pm
    }
    if (!isFile) {
        pm.reject(`fp[${fp}] is not a file`)
        return pm
    }

    if (type === 'xxhash64') {
        return fsGetFileXxHashCore(fp, { fs, chunkSize })
    }
    else {
        return fsGetFileBasicHashCore(fp, { fs, crypto, type })
    }

}


export default fsGetFileHashCore