UNPKG

nei

Version:
281 lines 7.66 kB
/* * io with cache utility api * @module util/io * @author genify(caijf@corp.netease.com) */ var util = require('util'); var path = require('path'); var fs = require('fs'); var _fs = require('../util/file.js'); var _path = require('../util/path.js'); var _util = require('../util/util.js'); var logger = require('./logger'); // private variable var _gCache = {}; var _gDwnState = {}; var _gListener = []; var _gOutState = {}; var _gOutListener = []; // add event var _addEvent = function (cache, listeners, callback) { // push to listener cache if (listeners.indexOf(callback) < 0) { listeners.push(callback); } // check loading state if (Object.keys(cache).length <= 0) { callback(); } }; // remove event var _removeEvent = function (listeners, callback) { var index = listeners.indexOf(callback); if (index >= 0) { listeners.splice(index, 1); } }; // check event trigger var _checkEvent = function (cache, listener) { if (Object.keys(cache).length <= 0) { listener.forEach(function (callback) { try { callback(); } catch (ex) { console.error(ex.stack); } }); } }; /** * dump file content cache * @return {Object} file content cache */ exports.dump = function () { return _gCache; }; /** * add onload event for io * @param {Function} callback - onload callback * @return {Void} */ exports.onload = function (callback) { _addEvent(_gDwnState, _gListener, callback); }; /** * remove onload callback * @param {Function} callback - onload callback * @return {Void} */ exports.offload = function (callback) { _removeEvent(_gListener, callback); }; /** * get resource content with uri * @param {String} uri - resource uri * @param {Function} callback - callback if resource loaded from fs or server * @return {Boolean} whether uri loading queue */ exports.get = (function () { // format content var _doFormatContent = function (uri, content, callback) { var event = {value: content}; // pre process file content // update file content in callback try { callback(event); } catch (ex) { // ignore console.error(ex.stack); } this.cache(uri, event.value); }; // check download state var _doCheckDownloadState = function () { _checkEvent(_gDwnState, _gListener); }; return function (uri, callback, charset) { // check cache var content = this.getFromCache(uri); if (content != null || !!_gDwnState[uri]) { return !0; } // download file content _gDwnState[uri] = !0; var handler = function (content) { content = content || ''; if (util.isArray(content)) { content = content.join('\n'); } _doFormatContent.call( this, uri, content, callback ); delete _gDwnState[uri]; _doCheckDownloadState(); }.bind(this); // load file from file system or remote server try { if (!_path.isURL(uri)) { _fs.readAsync(uri, handler, charset); } else { this.download(uri + '?v=' + (+new Date), handler); } } catch (ex) { handler("cant load file " + uri + ' for ' + ex.message + '\n' + ex.stack); console.error(ex.stack); } }; })(); /** * get resource content from cache * @param {String} uri - resource uri * @return {String} resource content */ exports.getFromCache = function (uri) { return _gCache[uri]; }; /** * cache resource content * @param {String} uri - resource uri * @param {String} content - resource content * @return {Void} */ exports.cache = function (uri, content) { _gCache[uri] = content; }; /** * fill uri list with content * @param {Array} list - uri list * @param {String} sep - list separate char * @return {String} content of list */ exports.fill = function (list, sep) { var ret = []; (list || []).forEach(function (uri) { var content = this.getFromCache(uri) || ''; if (!!content) { ret.push(content); } }, this); return ret.join(sep || '\n'); }; /** * download content from server * @param {String} uri - resource content * @param {Function} callback - callback after resource loaded * @return {Void} */ exports.download = function (uri, callback) { var https = /^https:\/\//i.test(uri); require(https ? 'https' : 'http').get( uri, function (res) { // if not set this encoding, chinese characters maybe corrupted res.setEncoding('utf8'); var ret = []; res.on('data', function (chunk) { ret.push(chunk.toString()); }); res.on('end', function () { callback(ret.join('')); }); } ).on( 'error', function (error) { callback(util.format( 'download file %s error, cause:\n%s', uri, error.message )); } ); }; /** * add output done event * @param {Function} callback - done callback * @return {Void} */ exports.ondone = function (callback) { _addEvent(_gOutState, _gOutListener, callback); }; /** * remove output done event * @param {Function} callback - done callback * @return {Void} */ exports.offdone = function (callback) { _removeEvent(_gOutListener, callback); }; /** * output file content * @param {String} file - file path * @param {String} content - file content * @param {String=} charset - charset * @return {Void} */ exports.output = function (file, content, charset) { var id = file + 'v' + _util.increment(); _gOutState[id] = !0; _fs.mkdir(path.dirname(file)); _fs.writeAsync( file, content, charset, function () { delete _gOutState[id]; _checkEvent(_gOutState, _gOutListener); } ); }; /** * output file content synchronous * @param {String} file - file path * @param {String} content - file content * @param {String=} charset - charset * @return {Void} */ exports.outputSync = function (file, content, charset) { _fs.mkdir(path.dirname(file)); _fs.write(file, content, charset); }; /** * save resource version * @param {String} uri - uri * @param {String} version - version * @return {Void} */ exports.resource = function (uri, version) { var cache = _gCache.resources; if (!cache) { cache = {}; _gCache.resources = cache; } cache[uri] = version; }; /** * dump resource version cache * @return {Object} version cache */ exports.dumpResource = function () { return _gCache.resources || {}; }; /** * 下载文件 * @param {String} url - 下载url * @param {String} dest - 写文件的目标路径 * @param {Function} [cb] - 回调 */ exports.downloadFile = function (url, dest, cb) { var https = /^https:\/\//i.test(url); var file = fs.createWriteStream(dest); logger.log('debug', { message: `开始下载文件: ${dest}` }); require(https ? 'https' : 'http').get(url, function (res) { res.pipe(file); file.on('finish', function () { logger.log('debug', { message: `文件下载完成: ${dest}` }); file.close(cb); }); }).on('error', function (err) { fs.unlink(dest); cb && cb(err.message); }); }