Large update to AssetGuard to make the module purely object based. This fixed several issues which were present with the static implementation and seems to have increased performance. Several other bugs related to the front-end scripts have been fixed.

This commit is contained in:
Daniel Scalzi 2017-11-30 03:00:06 -05:00
parent 4c2c46f535
commit 52ab270ce3
4 changed files with 703 additions and 691 deletions

View File

@ -1,10 +1,10 @@
const mojang = require('mojang')
const path = require('path')
const AssetGuard = require(path.join(__dirname, 'assets', 'js', 'assetguard.js'))
const {AssetGuard} = require(path.join(__dirname, 'assets', 'js', 'assetguard.js'))
const ProcessBuilder = require(path.join(__dirname, 'assets', 'js', 'processbuilder.js'))
const {GAME_DIRECTORY, DEFAULT_CONFIG} = require(path.join(__dirname, 'assets', 'js', 'constants.js'))
document.onreadystatechange = function(){
document.addEventListener('readystatechange', function(){
if (document.readyState === 'interactive'){
// Bind launch button
@ -14,7 +14,10 @@ document.onreadystatechange = function(){
})
}
}
}, false)
// Keep reference to AssetGuard object temporarily
let tracker;
testdownloads = async function(){
const content = document.getElementById("launch_content")
@ -28,45 +31,48 @@ testdownloads = async function(){
details.style.display = 'flex'
content.style.display = 'none'
tracker = new AssetGuard()
det_text.innerHTML = 'Loading version information..'
const versionData = await AssetGuard.loadVersionData('1.11.2', GAME_DIRECTORY)
const versionData = await tracker.loadVersionData('1.11.2', GAME_DIRECTORY)
progress.setAttribute('value', 20)
progress_text.innerHTML = '20%'
det_text.innerHTML = 'Validating asset integrity..'
await AssetGuard.validateAssets(versionData, GAME_DIRECTORY)
await tracker.validateAssets(versionData, GAME_DIRECTORY)
progress.setAttribute('value', 40)
progress_text.innerHTML = '40%'
console.log('assets done')
det_text.innerHTML = 'Validating library integrity..'
await AssetGuard.validateLibraries(versionData, GAME_DIRECTORY)
await tracker.validateLibraries(versionData, GAME_DIRECTORY)
progress.setAttribute('value', 60)
progress_text.innerHTML = '60%'
console.log('libs done')
det_text.innerHTML = 'Validating miscellaneous file integrity..'
await AssetGuard.validateMiscellaneous(versionData, GAME_DIRECTORY)
await tracker.validateMiscellaneous(versionData, GAME_DIRECTORY)
progress.setAttribute('value', 80)
progress_text.innerHTML = '80%'
console.log('files done')
det_text.innerHTML = 'Validating server distribution files..'
const serv = await AssetGuard.validateDistribution('WesterosCraft-1.11.2', GAME_DIRECTORY)
const serv = await tracker.validateDistribution('WesterosCraft-1.11.2', GAME_DIRECTORY)
progress.setAttribute('value', 100)
progress_text.innerHTML = '100%'
console.log('forge stuff done')
det_text.innerHTML = 'Downloading files..'
AssetGuard.instance.on('totaldlprogress', function(data){
tracker.on('totaldlprogress', function(data){
progress.setAttribute('max', data.total)
progress.setAttribute('value', data.acc)
progress_text.innerHTML = parseInt((data.acc/data.total)*100) + '%'
})
AssetGuard.instance.on('dlcomplete', async function(){
tracker.on('dlcomplete', async function(){
det_text.innerHTML = 'Preparing to launch..'
const forgeData = await AssetGuard.loadForgeData('WesterosCraft-1.11.2', GAME_DIRECTORY)
const forgeData = await tracker.loadForgeData('WesterosCraft-1.11.2', GAME_DIRECTORY)
const authUser = await mojang.auth('EMAIL', 'PASS', DEFAULT_CONFIG.getClientToken(), {
name: 'Minecraft',
version: 1
@ -94,6 +100,8 @@ testdownloads = async function(){
content.style.display = 'inline-flex'
}, 5000)
}
// Remove reference to tracker.
tracker = null
})
AssetGuard.processDlQueues()
tracker.processDlQueues()
}

View File

@ -2,21 +2,21 @@
* AssetGuard
*
* This module aims to provide a comprehensive and stable method for processing
* and downloading game assets for the WesterosCraft server. A central object
* stores download meta for several identifiers (categories). This meta data
* is initially empty until one of the module's processing functions are called.
* That function will process the corresponding asset index and validate any exisitng
* local files. If a file is missing or fails validation, it will be placed into an
* array which acts as a queue. This queue is wrapped in a download tracker object
* and downloading game assets for the WesterosCraft server. Download meta is
* for several identifiers (categories) is stored inside of an AssetGuard object.
* This meta data is initially empty until one of the module's processing functions
* are called. That function will process the corresponding asset index and validate
* any exisitng local files. If a file is missing or fails validation, it will be
* placed into a download queue (array). This queue is wrapped in a download tracker object
* so that essential information can be cached. The download tracker object is then
* assigned as the value of the identifier in the central object. These download
* assigned as the value of the identifier in the AssetGuard object. These download
* trackers will remain idle until an async process is started to process them.
*
* Once the async process is started, any enqueued assets will be downloaded. The central
* Once the async process is started, any enqueued assets will be downloaded. The AssetGuard
* object will emit events throughout the download whose name correspond to the identifier
* being processed. For example, if the 'assets' identifier was being processed, whenever
* the download stream recieves data, the event 'assetsdlprogress' will be emitted off of
* the central object instance. This can be listened to by external modules allowing for
* the AssetGuard instance. This can be listened to by external modules allowing for
* categorical tracking of the downloading process.
*
* @module assetguard
@ -136,6 +136,7 @@ class DistroModule extends Asset {
* about a download queue, including the queue itself.
*/
class DLTracker {
/**
* Create a DLTracker
*
@ -148,6 +149,7 @@ class DLTracker {
this.dlsize = dlsize
this.callback = callback
}
}
/**
@ -159,6 +161,7 @@ class DLTracker {
* this module.
*/
class AssetGuard extends EventEmitter {
/**
* AssetGuard class should only ever have one instance which is defined in
* this module. On creation the object's properties are never-null default
@ -173,14 +176,8 @@ class AssetGuard extends EventEmitter{
this.files = new DLTracker([], 0)
this.forge = new DLTracker([], 0)
}
}
/**
* Global static final instance of AssetGuard
*/
const instance = new AssetGuard()
// Utility Functions
// Static Utility Functions
/**
* Resolve an artifact id into a path. For example, on windows
@ -191,7 +188,7 @@ const instance = new AssetGuard()
* @param {String} extension - the extension of the file at the resolved path.
* @returns {String} - the resolved relative path from the artifact id.
*/
function _resolvePath(artifactid, extension){
static _resolvePath(artifactid, extension){
let ps = artifactid.split(':')
let cs = ps[0].split('.')
@ -211,7 +208,7 @@ function _resolvePath(artifactid, extension){
* @param {String} extension - the extension of the file at the resolved url.
* @returns {String} - the resolved relative URL from the artifact id.
*/
function _resolveURL(artifactid, extension){
static _resolveURL(artifactid, extension){
let ps = artifactid.split(':')
let cs = ps[0].split('.')
@ -229,7 +226,7 @@ function _resolveURL(artifactid, extension){
* @param {String} algo - the hash algorithm.
* @returns {String} - the calculated hash in hex.
*/
function _calculateHash(buf, algo){
static _calculateHash(buf, algo){
return crypto.createHash(algo).update(buf).digest('hex')
}
@ -240,7 +237,7 @@ function _calculateHash(buf, algo){
* @param {String} content - the string content of the checksums file.
* @returns {Object} - an object with keys being the file names, and values being the hashes.
*/
function _parseChecksumsFile(content){
static _parseChecksumsFile(content){
let finalContent = {}
let lines = content.split('\n')
for(let i=0; i<lines.length; i++){
@ -261,7 +258,7 @@ function _parseChecksumsFile(content){
* @param {String} hash - the existing hash to check against.
* @returns {Boolean} - true if the file exists and calculated hash matches the given hash, otherwise false.
*/
function _validateLocal(filePath, algo, hash){
static _validateLocal(filePath, algo, hash){
if(fs.existsSync(filePath)){
//No hash provided, have to assume it's good.
if(hash == null){
@ -269,7 +266,7 @@ function _validateLocal(filePath, algo, hash){
}
let fileName = path.basename(filePath)
let buf = fs.readFileSync(filePath)
let calcdhash = _calculateHash(buf, algo)
let calcdhash = AssetGuard._calculateHash(buf, algo)
return calcdhash === hash
}
return false;
@ -282,16 +279,16 @@ function _validateLocal(filePath, algo, hash){
* @param {Array.<String>} checksums - the checksums listed in the forge version index.
* @returns {Boolean} - true if the file exists and the hashes match, otherwise false.
*/
function _validateForgeChecksum(filePath, checksums){
static _validateForgeChecksum(filePath, checksums){
if(fs.existsSync(filePath)){
if(checksums == null || checksums.length === 0){
return true
}
let buf = fs.readFileSync(filePath)
let calcdhash = _calculateHash(buf, 'sha1')
let calcdhash = AssetGuard._calculateHash(buf, 'sha1')
let valid = checksums.includes(calcdhash)
if(!valid && filePath.endsWith('.jar')){
valid = _validateForgeJar(filePath, checksums)
valid = AssetGuard._validateForgeJar(filePath, checksums)
}
return valid
}
@ -307,7 +304,7 @@ function _validateForgeChecksum(filePath, checksums){
* @param {Array.<String>} checksums - the checksums listed in the forge version index.
* @returns {Boolean} - true if all hashes declared in the checksums.sha1 file match the actual hashes.
*/
function _validateForgeJar(buf, checksums){
static _validateForgeJar(buf, checksums){
// Double pass method was the quickest I found. I tried a version where we store data
// to only require a single pass, plus some quick cleanup but that seemed to take slightly more time.
@ -321,9 +318,9 @@ function _validateForgeJar(buf, checksums){
for(let i=0; i<zipEntries.length; i++){
let entry = zipEntries[i]
if(entry.entryName === 'checksums.sha1'){
expected = _parseChecksumsFile(zip.readAsText(entry))
expected = AssetGuard._parseChecksumsFile(zip.readAsText(entry))
}
hashes[entry.entryName] = _calculateHash(entry.getData(), 'sha1')
hashes[entry.entryName] = AssetGuard._calculateHash(entry.getData(), 'sha1')
}
if(!checksums.includes(hashes['checksums.sha1'])){
@ -346,7 +343,7 @@ function _validateForgeJar(buf, checksums){
* @param {Array.<String>} filePaths - The paths of the files to be extracted and unpacked.
* @returns {Promise.<Void>} - An empty promise to indicate the extraction has completed.
*/
function _extractPackXZ(filePaths){
static _extractPackXZ(filePaths){
return new Promise(function(fulfill, reject){
const libPath = path.join(__dirname, '..', 'libraries', 'java', 'PackXZExtract.jar')
const filePath = filePaths.join(',')
@ -374,7 +371,7 @@ function _extractPackXZ(filePaths){
* @param {String} basePath
* @returns {Promise.<Object>} - A promise which resolves to the contents of forge's version.json.
*/
function _finalizeForgeAsset(asset, basePath){
static _finalizeForgeAsset(asset, basePath){
return new Promise(function(fulfill, reject){
fs.readFile(asset.to, (err, data) => {
const zip = new AdmZip(data)
@ -409,10 +406,11 @@ function _finalizeForgeAsset(asset, basePath){
* @param {Number} limit - optional. The number of async processes to run in parallel.
* @returns {Boolean} - true if the process began, otherwise false.
*/
function startAsyncProcess(identifier, limit = 5){
startAsyncProcess(identifier, limit = 5){
const self = this
let win = remote.getCurrentWindow()
let acc = 0
const concurrentDlTracker = instance[identifier]
const concurrentDlTracker = this[identifier]
const concurrentDlQueue = concurrentDlTracker.dlqueue.slice(0)
if(concurrentDlQueue.length === 0){
return false
@ -437,35 +435,35 @@ function startAsyncProcess(identifier, limit = 5){
} else {
req.abort()
console.log('Failed to download ' + asset.from + '. Response code', resp.statusCode)
instance.progress += asset.size*1
win.setProgressBar(instance.progress/instance.totaldlsize)
instance.emit('totaldlprogress', {acc: instance.progress, total: instance.totaldlsize})
self.progress += asset.size*1
win.setProgressBar(self.progress/self.totaldlsize)
self.emit('totaldlprogress', {acc: self.progress, total: self.totaldlsize})
cb()
}
})
req.on('data', function(chunk){
count += chunk.length
instance.progress += chunk.length
self.progress += chunk.length
acc += chunk.length
instance.emit(identifier + 'dlprogress', acc)
//console.log(identifier + ' Progress', acc/instance[identifier].dlsize)
win.setProgressBar(instance.progress/instance.totaldlsize)
instance.emit('totaldlprogress', {acc: instance.progress, total: instance.totaldlsize})
self.emit(identifier + 'dlprogress', acc)
//console.log(identifier + ' Progress', acc/this[identifier].dlsize)
win.setProgressBar(self.progress/self.totaldlsize)
self.emit('totaldlprogress', {acc: self.progress, total: self.totaldlsize})
})
}, function(err){
if(err){
instance.emit(identifier + 'dlerror')
self.emit(identifier + 'dlerror')
console.log('An item in ' + identifier + ' failed to process');
} else {
instance.emit(identifier + 'dlcomplete')
self.emit(identifier + 'dlcomplete')
console.log('All ' + identifier + ' have been processed successfully')
}
instance.totaldlsize -= instance[identifier].dlsize
instance.progress -= instance[identifier].dlsize
instance[identifier] = new DLTracker([], 0)
if(instance.totaldlsize === 0) {
self.totaldlsize -= self[identifier].dlsize
self.progress -= self[identifier].dlsize
self[identifier] = new DLTracker([], 0)
if(self.totaldlsize === 0) {
win.setProgressBar(-1)
instance.emit('dlcomplete')
self.emit('dlcomplete')
}
})
return true
@ -482,7 +480,7 @@ function startAsyncProcess(identifier, limit = 5){
* @param {Boolean} force - optional. If true, the version index will be downloaded even if it exists locally. Defaults to false.
* @returns {Promise.<Object>} - Promise which resolves to the version data object.
*/
function loadVersionData(version, basePath, force = false){
loadVersionData(version, basePath, force = false){
return new Promise(function(fulfill, reject){
const name = version + '.json'
const url = 'https://s3.amazonaws.com/Minecraft.Download/versions/' + version + '/' + name
@ -515,9 +513,10 @@ function loadVersionData(version, basePath, force = false){
* @param {Boolean} force - optional. If true, the asset index will be downloaded even if it exists locally. Defaults to false.
* @returns {Promise.<Void>} - An empty promise to indicate the async processing has completed.
*/
function validateAssets(versionData, basePath, force = false){
validateAssets(versionData, basePath, force = false){
const self = this
return new Promise(function(fulfill, reject){
_assetChainIndexData(versionData, basePath, force).then(() => {
self._assetChainIndexData(versionData, basePath, force).then(() => {
fulfill()
})
})
@ -532,7 +531,8 @@ function validateAssets(versionData, basePath, force = false){
* @param {Boolean} force
* @returns {Promise.<Void>} - An empty promise to indicate the async processing has completed.
*/
function _assetChainIndexData(versionData, basePath, force = false){
_assetChainIndexData(versionData, basePath, force = false){
const self = this
return new Promise(function(fulfill, reject){
//Asset index constants.
const assetIndex = versionData.assetIndex
@ -547,13 +547,13 @@ function _assetChainIndexData(versionData, basePath, force = false){
const stream = request(assetIndex.url).pipe(fs.createWriteStream(assetIndexLoc))
stream.on('finish', function() {
data = JSON.parse(fs.readFileSync(assetIndexLoc, 'utf-8'))
_assetChainValidateAssets(versionData, basePath, data).then(() => {
self._assetChainValidateAssets(versionData, basePath, data).then(() => {
fulfill()
})
})
} else {
data = JSON.parse(fs.readFileSync(assetIndexLoc, 'utf-8'))
_assetChainValidateAssets(versionData, basePath, data).then(() => {
self._assetChainValidateAssets(versionData, basePath, data).then(() => {
fulfill()
})
}
@ -568,7 +568,8 @@ function _assetChainIndexData(versionData, basePath, force = false){
* @param {Boolean} force
* @returns {Promise.<Void>} - An empty promise to indicate the async processing has completed.
*/
function _assetChainValidateAssets(versionData, basePath, indexData){
_assetChainValidateAssets(versionData, basePath, indexData){
const self = this
return new Promise(function(fulfill, reject){
//Asset constants
@ -585,13 +586,13 @@ function _assetChainValidateAssets(versionData, basePath, indexData){
const assetName = path.join(hash.substring(0, 2), hash)
const urlName = hash.substring(0, 2) + "/" + hash
const ast = new Asset(key, hash, String(value.size), resourceURL + urlName, path.join(objectPath, assetName))
if(!_validateLocal(ast.to, 'sha1', ast.hash)){
if(!AssetGuard._validateLocal(ast.to, 'sha1', ast.hash)){
dlSize += (ast.size*1)
assetDlQueue.push(ast)
}
cb()
}, function(err){
instance.assets = new DLTracker(assetDlQueue, dlSize)
self.assets = new DLTracker(assetDlQueue, dlSize)
fulfill()
})
})
@ -607,7 +608,8 @@ function _assetChainValidateAssets(versionData, basePath, indexData){
* @param {String} basePath - the absolute file path which will be prepended to the given relative paths.
* @returns {Promise.<Void>} - An empty promise to indicate the async processing has completed.
*/
function validateLibraries(versionData, basePath){
validateLibraries(versionData, basePath){
const self = this
return new Promise(function(fulfill, reject){
const libArr = versionData.libraries
@ -621,14 +623,14 @@ function validateLibraries(versionData, basePath){
if(Library.validateRules(lib.rules)){
let artifact = (lib.natives == null) ? lib.downloads.artifact : lib.downloads.classifiers[lib.natives[Library.mojangFriendlyOS()]]
const libItm = new Library(lib.name, artifact.sha1, artifact.size, artifact.url, path.join(libPath, artifact.path))
if(!_validateLocal(libItm.to, 'sha1', libItm.hash)){
if(!AssetGuard._validateLocal(libItm.to, 'sha1', libItm.hash)){
dlSize += (libItm.size*1)
libDlQueue.push(libItm)
}
}
cb()
}, function(err){
instance.libraries = new DLTracker(libDlQueue, dlSize)
self.libraries = new DLTracker(libDlQueue, dlSize)
fulfill()
})
})
@ -642,10 +644,11 @@ function validateLibraries(versionData, basePath){
* @param {String} basePath - the absolute file path which will be prepended to the given relative paths.
* @returns {Promise.<Void>} - An empty promise to indicate the async processing has completed.
*/
function validateMiscellaneous(versionData, basePath){
validateMiscellaneous(versionData, basePath){
const self = this
return new Promise(async function(fulfill, reject){
await validateClient(versionData, basePath)
await validateLogConfig(versionData, basePath)
await self.validateClient(versionData, basePath)
await self.validateLogConfig(versionData, basePath)
fulfill()
})
}
@ -658,7 +661,8 @@ function validateMiscellaneous(versionData, basePath){
* @param {Boolean} force - optional. If true, the asset index will be downloaded even if it exists locally. Defaults to false.
* @returns {Promise.<Void>} - An empty promise to indicate the async processing has completed.
*/
function validateClient(versionData, basePath, force = false){
validateClient(versionData, basePath, force = false){
const self = this
return new Promise(function(fulfill, reject){
const clientData = versionData.downloads.client
const version = versionData.id
@ -667,9 +671,9 @@ function validateClient(versionData, basePath, force = false){
let client = new Asset(version + ' client', clientData.sha1, clientData.size, clientData.url, path.join(targetPath, targetFile))
if(!_validateLocal(client.to, 'sha1', client.hash) || force){
instance.files.dlqueue.push(client)
instance.files.dlsize += client.size*1
if(!AssetGuard._validateLocal(client.to, 'sha1', client.hash) || force){
self.files.dlqueue.push(client)
self.files.dlsize += client.size*1
fulfill()
} else {
fulfill()
@ -685,7 +689,8 @@ function validateClient(versionData, basePath, force = false){
* @param {Boolean} force - optional. If true, the asset index will be downloaded even if it exists locally. Defaults to false.
* @returns {Promise.<Void>} - An empty promise to indicate the async processing has completed.
*/
function validateLogConfig(versionData, basePath){
validateLogConfig(versionData, basePath){
const self = this
return new Promise(function(fulfill, reject){
const client = versionData.logging.client
const file = client.file
@ -693,9 +698,9 @@ function validateLogConfig(versionData, basePath){
let logConfig = new Asset(file.id, file.sha1, file.size, file.url, path.join(targetPath, file.id))
if(!_validateLocal(logConfig.to, 'sha1', logConfig.hash)){
instance.files.dlqueue.push(logConfig)
instance.files.dlsize += logConfig.size*1
if(!AssetGuard._validateLocal(logConfig.to, 'sha1', logConfig.hash)){
self.files.dlqueue.push(logConfig)
self.files.dlsize += logConfig.size*1
fulfill()
} else {
fulfill()
@ -710,9 +715,10 @@ function validateLogConfig(versionData, basePath){
* @param {String} basePath - the absolute file path which will be prepended to the given relative paths.
* @returns {Promise.<Object>} - A promise which resolves to the server distribution object.
*/
function validateDistribution(serverpackid, basePath){
validateDistribution(serverpackid, basePath){
const self = this
return new Promise(function(fulfill, reject){
_chainValidateDistributionIndex(basePath).then((value) => {
self._chainValidateDistributionIndex(basePath).then((value) => {
let servers = value.servers
let serv = null
for(let i=0; i<servers.length; i++){
@ -722,15 +728,15 @@ function validateDistribution(serverpackid, basePath){
}
}
instance.forge = _parseDistroModules(serv.modules, basePath, serv.mc_version)
self.forge = self._parseDistroModules(serv.modules, basePath, serv.mc_version)
//Correct our workaround here.
let decompressqueue = instance.forge.callback
instance.forge.callback = function(asset){
let decompressqueue = self.forge.callback
self.forge.callback = function(asset){
if(asset.to.toLowerCase().endsWith('.pack.xz')){
_extractPackXZ([asset.to])
AssetGuard._extractPackXZ([asset.to])
}
if(asset.type === 'forge-hosted' || asset.type === 'forge'){
_finalizeForgeAsset(asset, basePath)
AssetGuard._finalizeForgeAsset(asset, basePath)
}
}
fulfill(serv)
@ -740,7 +746,7 @@ function validateDistribution(serverpackid, basePath){
//TODO The distro index should be downloaded in the 'pre-loader'. This is because
//we will eventually NEED the index to generate the server list on the ui.
function _chainValidateDistributionIndex(basePath){
_chainValidateDistributionIndex(basePath){
return new Promise(function(fulfill, reject){
//const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/westeroscraft.json'
const targetFile = path.join(basePath, 'westeroscraft.json')
@ -752,7 +758,7 @@ function _chainValidateDistributionIndex(basePath){
})
}
function _parseDistroModules(modules, basePath, version){
_parseDistroModules(modules, basePath, version){
let alist = []
let asize = 0;
//This may be removed soon, considering the most efficient way to extract.
@ -761,7 +767,7 @@ function _parseDistroModules(modules, basePath, version){
let ob = modules[i]
let obType = ob.type
let obArtifact = ob.artifact
let obPath = obArtifact.path == null ? _resolvePath(ob.id, obArtifact.extension) : obArtifact.path
let obPath = obArtifact.path == null ? AssetGuard._resolvePath(ob.id, obArtifact.extension) : obArtifact.path
switch(obType){
case 'forge-hosted':
case 'forge':
@ -782,14 +788,14 @@ function _parseDistroModules(modules, basePath, version){
}
let artifact = new DistroModule(ob.id, obArtifact.MD5, obArtifact.size, obArtifact.url, obPath, obType)
const validationPath = obPath.toLowerCase().endsWith('.pack.xz') ? obPath.substring(0, obPath.toLowerCase().lastIndexOf('.pack.xz')) : obPath
if(!_validateLocal(validationPath, 'MD5', artifact.hash)){
if(!AssetGuard._validateLocal(validationPath, 'MD5', artifact.hash)){
asize += artifact.size*1
alist.push(artifact)
if(validationPath !== obPath) decompressqueue.push(obPath)
}
//Recursively process the submodules then combine the results.
if(ob.sub_modules != null){
let dltrack = _parseDistroModules(ob.sub_modules, basePath, version)
let dltrack = this._parseDistroModules(ob.sub_modules, basePath, version)
asize += dltrack.dlsize*1
alist = alist.concat(dltrack.dlqueue)
decompressqueue = decompressqueue.concat(dltrack.callback)
@ -807,9 +813,10 @@ function _parseDistroModules(modules, basePath, version){
* @param {String} basePath
* @returns {Promise.<Object>} - A promise which resolves to Forge's version.json data.
*/
function loadForgeData(serverpack, basePath){
loadForgeData(serverpack, basePath){
const self = this
return new Promise(async function(fulfill, reject){
let distro = await _chainValidateDistributionIndex(basePath)
let distro = await self._chainValidateDistributionIndex(basePath)
const servers = distro.servers
let serv = null
@ -825,9 +832,9 @@ function loadForgeData(serverpack, basePath){
const ob = modules[i]
if(ob.type === 'forge-hosted' || ob.type === 'forge'){
let obArtifact = ob.artifact
let obPath = obArtifact.path == null ? path.join(basePath, 'libraries', _resolvePath(ob.id, obArtifact.extension)) : obArtifact.path
let obPath = obArtifact.path == null ? path.join(basePath, 'libraries', AssetGuard._resolvePath(ob.id, obArtifact.extension)) : obArtifact.path
let asset = new DistroModule(ob.id, obArtifact.MD5, obArtifact.size, obArtifact.url, obPath, ob.type)
let forgeData = await _finalizeForgeAsset(asset, basePath)
let forgeData = await AssetGuard._finalizeForgeAsset(asset, basePath)
fulfill(forgeData)
return
}
@ -836,7 +843,7 @@ function loadForgeData(serverpack, basePath){
})
}
function _parseForgeLibraries(){
_parseForgeLibraries(){
/* TODO
* Forge asset validations are already implemented. When there's nothing much
* to work on, implement forge downloads using forge's version.json. This is to
@ -848,46 +855,40 @@ function _parseForgeLibraries(){
* This function will initiate the download processed for the specified identifiers. If no argument is
* given, all identifiers will be initiated. Note that in order for files to be processed you need to run
* the processing function corresponding to that identifier. If you run this function without processing
* the files, it is likely nothing will be enqueued in the global object and processing will complete
* the files, it is likely nothing will be enqueued in the object and processing will complete
* immediately. Once all downloads are complete, this function will fire the 'dlcomplete' event on the
* global object instance.
*
* @param {Array.<{id: string, limit: number}>} identifiers - optional. The identifiers to process and corresponding parallel async task limit.
*/
function processDlQueues(identifiers = [{id:'assets', limit:20}, {id:'libraries', limit:5}, {id:'files', limit:5}, {id:'forge', limit:5}]){
processDlQueues(identifiers = [{id:'assets', limit:20}, {id:'libraries', limit:5}, {id:'files', limit:5}, {id:'forge', limit:5}]){
this.progress = 0;
let win = remote.getCurrentWindow()
let shouldFire = true
// Assign global dltracking variables.
instance.totaldlsize = 0
instance.progress = 0
// Assign dltracking variables.
this.totaldlsize = 0
this.progress = 0
for(let i=0; i<identifiers.length; i++){
instance.totaldlsize += instance[identifiers[i].id].dlsize
this.totaldlsize += this[identifiers[i].id].dlsize
}
for(let i=0; i<identifiers.length; i++){
let iden = identifiers[i]
let r = startAsyncProcess(iden.id, iden.limit)
let r = this.startAsyncProcess(iden.id, iden.limit)
if(r) shouldFire = false
}
if(shouldFire){
instance.emit('dlcomplete')
this.emit('dlcomplete')
}
}
module.exports = {
loadVersionData,
loadForgeData,
validateAssets,
validateLibraries,
validateMiscellaneous,
validateDistribution,
processDlQueues,
instance,
Asset,
Library,
_resolvePath
}
module.exports = {
AssetGuard,
Asset,
Library
}

View File

@ -6,7 +6,7 @@
* TODO why are logs not working??????
*/
const AdmZip = require('adm-zip')
const ag = require('./assetguard.js')
const {AssetGuard, Library} = require('./assetguard.js')
const child_process = require('child_process')
const {DEFAULT_CONFIG} = require('./constants')
const fs = require('fs')
@ -232,7 +232,7 @@ class ProcessBuilder {
const nativePath = path.join(this.dir, 'natives')
for(let i=0; i<libArr.length; i++){
const lib = libArr[i]
if(ag.Library.validateRules(lib.rules)){
if(Library.validateRules(lib.rules)){
if(lib.natives == null){
const dlInfo = lib.downloads
const artifact = dlInfo.artifact
@ -243,7 +243,7 @@ class ProcessBuilder {
const natives = lib.natives
const extractInst = lib.extract
const exclusionArr = extractInst.exclude
const opSys = ag.Library.mojangFriendlyOS()
const opSys = Library.mojangFriendlyOS()
const indexId = natives[opSys]
const dlInfo = lib.downloads
const classifiers = dlInfo.classifiers
@ -304,7 +304,7 @@ class ProcessBuilder {
for(let i=0; i<mdles.length; i++){
if(mdles[i].type != null && (mdles[i].type === 'forge-hosted' || mdles[i].type === 'library')){
let lib = mdles[i]
libs.push(path.join(this.libPath, lib.artifact.path == null ? ag._resolvePath(lib.id, lib.artifact.extension) : lib.artifact.path))
libs.push(path.join(this.libPath, lib.artifact.path == null ? AssetGuard._resolvePath(lib.id, lib.artifact.extension) : lib.artifact.path))
if(lib.sub_modules != null){
const res = this._resolveModuleLibraries(lib)
if(res.length > 0){
@ -341,7 +341,7 @@ class ProcessBuilder {
for(let i=0; i<mdle.sub_modules.length; i++){
const sm = mdle.sub_modules[i]
if(sm.type != null && sm.type == 'library'){
libs.push(path.join(this.libPath, sm.artifact.path == null ? ag._resolvePath(sm.id, sm.artifact.extension) : sm.artifact.path))
libs.push(path.join(this.libPath, sm.artifact.path == null ? AssetGuard._resolvePath(sm.id, sm.artifact.extension) : sm.artifact.path))
}
// If this module has submodules, we need to resolve the libraries for those.
// To avoid unnecessary recursive calls, base case is checked here.

View File

@ -10,9 +10,8 @@ $(function(){
console.log('UICore Initialized');
})*/
document.onreadystatechange = function () {
if (document.readyState === "interactive") {
document.addEventListener('readystatechange', function () {
if (document.readyState === 'interactive'){
console.log('UICore Initializing..');
// Bind close button.
@ -37,6 +36,8 @@ document.onreadystatechange = function () {
window.minimize()
})
} else if(document.readyState === 'complete'){
// Bind progress bar length to length of bot wrapper
const targetWidth = document.getElementById("launch_content").getBoundingClientRect().width
const targetWidth2 = document.getElementById("server_selection").getBoundingClientRect().width
@ -45,8 +46,10 @@ document.onreadystatechange = function () {
document.getElementById("launch_progress").style.width = targetWidth2
document.getElementById("launch_details_right").style.maxWidth = targetWidth2
document.getElementById("launch_progress_label").style.width = targetWidth3
}
}
}, false)
/**
* Open web links in the user's default browser.