2
0
Fork 0
node-ff-assets/lib/asset-assembler.js
2015-06-28 16:41:57 +02:00

273 lines
7.3 KiB
JavaScript

'use strict';
var debug = require('debug')('ff:assets:asset-assembler');
var u = require('underscore');
var events = require('events');
var fetch = require('fetch');
var fs = require('fs-extra');
var factory = require('./factory');
var config = require('./asset-assembler-config');
function buildEnd(assembler, targetFile, resultUriList, callback) {
var footer = '';
if (assembler.config.assetFooter !== null) {
footer = assembler.config.assetFooter;
}
fs.appendFile(targetFile, footer, function (err) {
if (err) {
callback(err);
} else {
var buildTime = new Date().getTime() - assembler.startTime,
buildResultSize = resultUriList.length,
targetStats = fs.statSync(targetFile),
targetSize = targetStats.size;
if (assembler.config.linkTargetSingleResult) {
resultUriList = [assembler.config.linkTarget];
}
assembler.emit('file-write-post',targetFile);
debug('target file: %s',targetFile);
debug('target size: %s',targetSize);
assembler.emit('log','build result size: '+resultUriList.length+' from: '+buildResultSize);
assembler.emit('log','build done in: '+buildTime+' ms.');
assembler.emit('result',resultUriList);
assembler.emit('end');
callback();
}
});
}
function downloadFile(assembler, remoteUrl, localFile, callback) {
assembler.emit('file-download-pre',remoteUrl);
debug('downloadFile: %s',remoteUrl);
fs.ensureFile(localFile, function(err) {
if (err) {
callback(err);
} else {
var stream = new fetch.FetchStream(remoteUrl);
var streamCallbackErrorOnEnd = null;
var streamCallback = function(err) {
if (err) {
streamCallbackErrorOnEnd = err;
return;
} else {
callback(streamCallbackErrorOnEnd);
}
};
stream.on('error', function(err) {
callback(err); // check !!
//streamCallback(err);
});
stream.on('meta', function(meta) {
if (meta.status !== 200) {
streamCallback(new Error('Got status: '+meta.status));
}
});
stream.on('end', function() {
assembler.emit('file-download-post',remoteUrl);
streamCallback();
});
stream.pipe(fs.createWriteStream(localFile));
}
});
}
function downloadFileList(assembler, downloadList, callback) {
if (downloadList.length === 0) {
callback();
return;
}
var download = downloadList.pop();
downloadFile(assembler, download.remoteUrl, download.localFile, function(err) {
if (err) {
callback(err);
} else {
downloadFileList(assembler, downloadList, callback);
}
});
}
function aggregateFileList(assembler, targetFile, aggregateList, readFile, callback) {
if (aggregateList.length === 0) {
callback();
return;
}
var aggregateFile = aggregateList.pop();
assembler.emit('file-read-pre',aggregateFile);
readFile(aggregateFile, function(err, data) {
if (err) {
callback(err);
} else {
assembler.emit('file-read-post',aggregateFile);
debug('readFile: '+aggregateFile+' size: '+data.length);
if (assembler.config.assetSeperator !== null && assembler.config.assetSeperator.length > 0) {
var seperatorTemplate = u.template(assembler.config.assetSeperator);
data = seperatorTemplate({file: aggregateFile}) + data;
}
fs.appendFile(targetFile, data + '\n', function (err) {
if (err) {
callback(err);
} else {
aggregateFileList(assembler, targetFile, aggregateList, readFile, callback);
}
});
}
});
}
function mapLocalFileSync(assembler, linkSource) {
var uriMapping = assembler.config.linkMapping;
if (uriMapping) {
var uriMappingKeys = Object.keys(uriMapping);
uriMappingKeys.sort(function(a, b) {
return a.length < b.length; // longest first as we break on first hit
});
for (var ii = 0; ii < uriMappingKeys.length; ii++) {
var uriKey = uriMappingKeys[ii];
var localPath = uriMapping[uriKey];
var mapIndex = linkSource.indexOf(uriKey);
if (mapIndex === 0) {
return localPath+linkSource.substring(uriKey.length);
}
}
}
return linkSource;
}
function buildAsset(assembler, targetFile, readFile, callback) {
var uriList = assembler.config.linkSources;
var readFileList = [];
var resultUriList = [];
var downloadList = [];
for (var i = 0; i < uriList.length; i++) {
var assetItem = uriList[i];
var remoteUrl = null;
var remoteForce = null;
var remoteIndex = assetItem.indexOf('@');
if (remoteIndex > 0) {
remoteUrl = assetItem.substring(remoteIndex + 1);
if (remoteUrl.indexOf('@') === 0) {
remoteUrl = assetItem.substring(remoteIndex + 2);
remoteForce = true;
}
assetItem = assetItem.substring(0,remoteIndex);
}
var localFile = mapLocalFileSync(assembler, assetItem);
// override force on all files
if (remoteForce===undefined && assembler.config.downloadForce !== undefined) {
remoteForce = assembler.config.downloadForce;
}
if (remoteUrl && (remoteForce || !fs.existsSync(localFile))) {
downloadList.push({
remoteUrl: remoteUrl,
localFile: localFile
});
}
readFileList.push(localFile);
resultUriList.push(assetItem);
}
downloadList.reverse();
readFileList.reverse();
debug('downloadList size: %s',downloadList.length);
debug('readFileList size: %s',readFileList.length);
downloadFileList(assembler, downloadList, function(err) {
if (err) {
callback(err);
} else {
//for(....
//if (!fs.existsSync(localFile)) {
// Log.warn("illegal entry: "+localFile);
// continue;
//}
aggregateFileList(assembler, targetFile, readFileList, readFile, function(err) {
if (err) {
callback(err);
} else {
buildEnd(assembler, targetFile, resultUriList, callback);
}
});
}
});
}
function buildStart(assembler, readFile, callback) {
assembler.startTime = new Date().getTime();
assembler.emit('begin');
assembler.emit('log','build begin for: '+assembler.config.linkTarget);
if (assembler.config.downloadForce) {
assembler.emit('log','build using forced downloads.');
}
var targetFile = mapLocalFileSync(assembler, assembler.config.linkTarget);
fs.ensureFile(targetFile, function (err) {
if (err) {
callback(err);
} else {
assembler.emit('file-write-pre',targetFile);
var header = '';
if (assembler.config.assetHeader !== null) {
header = assembler.config.assetHeader;
}
fs.writeFile(targetFile, header, function(err) {
if (err) {
callback(err);
} else {
buildAsset(assembler, targetFile, readFile, callback);
}
});
}
});
}
function runAssembler(assembler, readFile, callback) {
if (assembler.config.downloadStartDelay) {
setTimeout(function() {
buildStart(assembler, readFile, callback);
}, assembler.config.downloadStartDelay);
} else {
buildStart(assembler, readFile, callback);
}
}
function AssetAssembler(config, readFile) {
if (config === undefined) {
throw new Error('no config');
}
this.config = config;
this.startTime = 0;
this.readFile = readFile || factory.assembler.constructor.readFile();
events.EventEmitter.call(this);
}
AssetAssembler.prototype.__proto__ = events.EventEmitter.prototype;
AssetAssembler.prototype.run = function(callback) {
if (callback === undefined) {
throw new Error('no callback');
}
var self = this;
config.checkConfig(self.config,function(err) {
if (err) {
callback(err);
} else {
config.fillDefaults(self.config, function (err) {
if (err) {
callback(err);
} else {
runAssembler(self, self.readFile, callback);
}
});
}
});
};
module.exports = AssetAssembler;