|
|
@@ -12,13 +12,6 @@
|
|
|
* 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 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 AssetGuard instance. This can be listened to by external modules allowing for
|
|
|
- * categorical tracking of the downloading process.
|
|
|
- *
|
|
|
* @module assetguard
|
|
|
*/
|
|
|
// Requirements
|
|
|
@@ -36,6 +29,9 @@ const request = require('request')
|
|
|
const tar = require('tar-fs')
|
|
|
const zlib = require('zlib')
|
|
|
|
|
|
+const ConfigManager = require('./configmanager')
|
|
|
+const DistroManager = require('./distromanager')
|
|
|
+
|
|
|
// Constants
|
|
|
const PLATFORM_MAP = {
|
|
|
win32: '-windows-x64.tar.gz',
|
|
|
@@ -161,9 +157,6 @@ class DLTracker {
|
|
|
|
|
|
}
|
|
|
|
|
|
-let distributionData = null
|
|
|
-let launchWithLocal = false
|
|
|
-
|
|
|
/**
|
|
|
* Central object class used for control flow. This object stores data about
|
|
|
* categories of downloads. Each category is assigned an identifier with a
|
|
|
@@ -180,12 +173,10 @@ class AssetGuard extends EventEmitter {
|
|
|
* values. Each identifier is resolved to an empty DLTracker.
|
|
|
*
|
|
|
* @param {string} commonPath The common path for shared game files.
|
|
|
- * @param {string} launcherPath The root launcher directory.
|
|
|
* @param {string} javaexec The path to a java executable which will be used
|
|
|
* to finalize installation.
|
|
|
- * @param {string} instancePath The path to the instances directory.
|
|
|
*/
|
|
|
- constructor(commonPath, launcherPath, javaexec, instancePath){
|
|
|
+ constructor(commonPath, javaexec){
|
|
|
super()
|
|
|
this.totaldlsize = 0
|
|
|
this.progress = 0
|
|
|
@@ -196,73 +187,12 @@ class AssetGuard extends EventEmitter {
|
|
|
this.java = new DLTracker([], 0)
|
|
|
this.extractQueue = []
|
|
|
this.commonPath = commonPath
|
|
|
- this.launcherPath = launcherPath
|
|
|
this.javaexec = javaexec
|
|
|
- this.instancePath = instancePath
|
|
|
}
|
|
|
|
|
|
// Static Utility Functions
|
|
|
// #region
|
|
|
|
|
|
- // Static General Resolve Functions
|
|
|
- // #region
|
|
|
-
|
|
|
- /**
|
|
|
- * Resolve an artifact id into a path. For example, on windows
|
|
|
- * 'net.minecraftforge:forge:1.11.2-13.20.0.2282', '.jar' becomes
|
|
|
- * net\minecraftforge\forge\1.11.2-13.20.0.2282\forge-1.11.2-13.20.0.2282.jar
|
|
|
- *
|
|
|
- * @param {string} artifactid The artifact id string.
|
|
|
- * @param {string} extension The extension of the file at the resolved path.
|
|
|
- * @returns {string} The resolved relative path from the artifact id.
|
|
|
- */
|
|
|
- static _resolvePath(artifactid, extension){
|
|
|
- let ps = artifactid.split(':')
|
|
|
- let cs = ps[0].split('.')
|
|
|
-
|
|
|
- cs.push(ps[1])
|
|
|
- cs.push(ps[2])
|
|
|
- cs.push(ps[1].concat('-').concat(ps[2]).concat(extension))
|
|
|
-
|
|
|
- return path.join.apply(path, cs)
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Resolve an artifact id into a URL. For example,
|
|
|
- * 'net.minecraftforge:forge:1.11.2-13.20.0.2282', '.jar' becomes
|
|
|
- * net/minecraftforge/forge/1.11.2-13.20.0.2282/forge-1.11.2-13.20.0.2282.jar
|
|
|
- *
|
|
|
- * @param {string} artifactid The artifact id string.
|
|
|
- * @param {string} extension The extension of the file at the resolved url.
|
|
|
- * @returns {string} The resolved relative URL from the artifact id.
|
|
|
- */
|
|
|
- static _resolveURL(artifactid, extension){
|
|
|
- let ps = artifactid.split(':')
|
|
|
- let cs = ps[0].split('.')
|
|
|
-
|
|
|
- cs.push(ps[1])
|
|
|
- cs.push(ps[2])
|
|
|
- cs.push(ps[1].concat('-').concat(ps[2]).concat(extension))
|
|
|
-
|
|
|
- return cs.join('/')
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Resolves an artiface id without the version. For example,
|
|
|
- * 'net.minecraftforge:forge:1.11.2-13.20.0.2282' becomes
|
|
|
- * 'net.minecraftforge:forge'.
|
|
|
- *
|
|
|
- * @param {string} artifactid The artifact id string.
|
|
|
- * @returns {string} The resolved identifier without the version.
|
|
|
- */
|
|
|
- static _resolveWithoutVersion(artifactid){
|
|
|
- let ps = artifactid.split(':')
|
|
|
-
|
|
|
- return ps[0] + ':' + ps[1]
|
|
|
- }
|
|
|
-
|
|
|
- // #endregion
|
|
|
-
|
|
|
// Static Hash Validation Functions
|
|
|
// #region
|
|
|
|
|
|
@@ -386,145 +316,6 @@ class AssetGuard extends EventEmitter {
|
|
|
|
|
|
// #endregion
|
|
|
|
|
|
- // Static Distribution Index Functions
|
|
|
- // #region
|
|
|
-
|
|
|
- /**
|
|
|
- * Retrieve a new copy of the distribution index from our servers.
|
|
|
- *
|
|
|
- * @param {string} launcherPath The root launcher directory.
|
|
|
- * @returns {Promise.<Object>} A promise which resolves to the distribution data object.
|
|
|
- */
|
|
|
- static refreshDistributionDataRemote(launcherPath){
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/westeroscraft.json'
|
|
|
- const opts = {
|
|
|
- url: distroURL,
|
|
|
- timeout: 2500
|
|
|
- }
|
|
|
- const distroDest = path.join(launcherPath, 'westeroscraft.json')
|
|
|
- request(opts, (error, resp, body) => {
|
|
|
- if(!error){
|
|
|
- distributionData = JSON.parse(body)
|
|
|
-
|
|
|
- fs.writeFile(distroDest, body, 'utf-8', (err) => {
|
|
|
- if(!err){
|
|
|
- resolve(distributionData)
|
|
|
- } else {
|
|
|
- reject(err)
|
|
|
- }
|
|
|
- })
|
|
|
- } else {
|
|
|
- reject(error)
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Retrieve a local copy of the distribution index asynchronously.
|
|
|
- *
|
|
|
- * @param {string} launcherPath The root launcher directory.
|
|
|
- * @returns {Promise.<Object>} A promise which resolves to the distribution data object.
|
|
|
- */
|
|
|
- static refreshDistributionDataLocal(launcherPath){
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- fs.readFile(path.join(launcherPath, 'westeroscraft.json'), 'utf-8', (err, data) => {
|
|
|
- if(!err){
|
|
|
- distributionData = JSON.parse(data)
|
|
|
- resolve(distributionData)
|
|
|
- } else {
|
|
|
- reject(err)
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Retrieve a local copy of the distribution index synchronously.
|
|
|
- *
|
|
|
- * @param {string} launcherPath The root launcher directory.
|
|
|
- * @returns {Object} The distribution data object.
|
|
|
- */
|
|
|
- static refreshDistributionDataLocalSync(launcherPath){
|
|
|
- distributionData = JSON.parse(fs.readFileSync(path.join(launcherPath, 'westeroscraft.json'), 'utf-8'))
|
|
|
- return distributionData
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Get a cached copy of the distribution index.
|
|
|
- */
|
|
|
- static getDistributionData(){
|
|
|
- return distributionData
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Resolve the default selected server from the distribution index.
|
|
|
- *
|
|
|
- * @returns {Object} An object resolving to the default selected server.
|
|
|
- */
|
|
|
- static resolveSelectedServer(){
|
|
|
- const distro = AssetGuard.getDistributionData()
|
|
|
- const servers = distro.servers
|
|
|
- for(let i=0; i<servers.length; i++){
|
|
|
- if(servers[i].default_selected){
|
|
|
- return servers[i]
|
|
|
- }
|
|
|
- }
|
|
|
- // If no server declares default_selected, default to the first one declared.
|
|
|
- return (servers.length > 0) ? servers[0] : null
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Gets a server from the distro index which maches the provided ID.
|
|
|
- * Returns null if the ID could not be found or the distro index has
|
|
|
- * not yet been loaded.
|
|
|
- *
|
|
|
- * @param {string} serverID The id of the server to retrieve.
|
|
|
- * @returns {Object} The server object whose id matches the parameter.
|
|
|
- */
|
|
|
- static getServerById(serverID){
|
|
|
- const distro = AssetGuard.getDistributionData()
|
|
|
- const servers = distro.servers
|
|
|
- let serv = null
|
|
|
- for(let i=0; i<servers.length; i++){
|
|
|
- if(servers[i].id === serverID){
|
|
|
- serv = servers[i]
|
|
|
- }
|
|
|
- }
|
|
|
- return serv
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Set whether or not we should launch with a local copy of the distribution
|
|
|
- * index. This is useful for testing experimental changes to the distribution index.
|
|
|
- *
|
|
|
- * @param {boolean} value True if we should launch with a local copy. Otherwise false.
|
|
|
- */
|
|
|
- static launchWithLocal(value, silent = false){
|
|
|
- if(!silent){
|
|
|
- if(value){
|
|
|
- console.log('%c[AssetGuard]', 'color: #a02d2a; font-weight: bold', 'Will now launch using a local copy of the distribution index.')
|
|
|
- console.log('%c[AssetGuard]', 'color: #a02d2a; font-weight: bold', 'Unless you are a developer, revert this change immediately.')
|
|
|
- } else {
|
|
|
- console.log('%c[AssetGuard]', 'color: #a02d2a; font-weight: bold', 'Will now retrieve a fresh copy of the distribution index on launch.')
|
|
|
- }
|
|
|
- }
|
|
|
- launchWithLocal = value
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Check if AssetGuard is configured to launch with a local copy
|
|
|
- * of the distribution index.
|
|
|
- *
|
|
|
- * @returns {boolean} True if launching with local, otherwise false.
|
|
|
- */
|
|
|
- static isLocalLaunch(){
|
|
|
- return launchWithLocal
|
|
|
- }
|
|
|
-
|
|
|
- // #endregion
|
|
|
-
|
|
|
// Miscellaneous Static Functions
|
|
|
// #region
|
|
|
|
|
|
@@ -538,8 +329,6 @@ class AssetGuard extends EventEmitter {
|
|
|
console.log('[PackXZExtract] Starting')
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
-
|
|
|
-
|
|
|
let libPath
|
|
|
if(isDev){
|
|
|
libPath = path.join(process.cwd(), 'libraries', 'java', 'PackXZExtract.jar')
|
|
|
@@ -1320,11 +1109,11 @@ class AssetGuard extends EventEmitter {
|
|
|
//const objKeys = Object.keys(data.objects)
|
|
|
async.forEachOfLimit(indexData.objects, 10, (value, key, cb) => {
|
|
|
acc++
|
|
|
- self.emit('assetVal', {acc, total})
|
|
|
+ self.emit('progress', 'assets', acc, total)
|
|
|
const hash = value.hash
|
|
|
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))
|
|
|
+ const ast = new Asset(key, hash, value.size, resourceURL + urlName, path.join(objectPath, assetName))
|
|
|
if(!AssetGuard._validateLocal(ast.to, 'sha1', ast.hash)){
|
|
|
dlSize += (ast.size*1)
|
|
|
assetDlQueue.push(ast)
|
|
|
@@ -1461,30 +1250,22 @@ class AssetGuard extends EventEmitter {
|
|
|
/**
|
|
|
* Validate the distribution.
|
|
|
*
|
|
|
- * @param {string} serverpackid The id of the server to validate.
|
|
|
+ * @param {Server} server The Server to validate.
|
|
|
* @returns {Promise.<Object>} A promise which resolves to the server distribution object.
|
|
|
*/
|
|
|
- validateDistribution(serverpackid){
|
|
|
+ validateDistribution(server){
|
|
|
const self = this
|
|
|
return new Promise((resolve, reject) => {
|
|
|
- AssetGuard.refreshDistributionDataLocal(self.launcherPath).then((v) => {
|
|
|
- const serv = AssetGuard.getServerById(serverpackid)
|
|
|
-
|
|
|
- if(serv == null) {
|
|
|
- console.error('Invalid server pack id:', serverpackid)
|
|
|
+ self.forge = self._parseDistroModules(server.getModules(), server.getMinecraftVersion(), server.getID())
|
|
|
+ // Correct our workaround here.
|
|
|
+ let decompressqueue = self.forge.callback
|
|
|
+ self.extractQueue = decompressqueue
|
|
|
+ self.forge.callback = (asset, self) => {
|
|
|
+ if(asset.type === DistroManager.Types.ForgeHosted || asset.type === DistroManager.Types.Forge){
|
|
|
+ AssetGuard._finalizeForgeAsset(asset, self.commonPath).catch(err => console.log(err))
|
|
|
}
|
|
|
-
|
|
|
- self.forge = self._parseDistroModules(serv.modules, serv.mc_version, serv.id)
|
|
|
- // Correct our workaround here.
|
|
|
- let decompressqueue = self.forge.callback
|
|
|
- self.extractQueue = decompressqueue
|
|
|
- self.forge.callback = (asset, self) => {
|
|
|
- if(asset.type === 'forge-hosted' || asset.type === 'forge'){
|
|
|
- AssetGuard._finalizeForgeAsset(asset, self.commonPath)
|
|
|
- }
|
|
|
- }
|
|
|
- resolve(serv)
|
|
|
- })
|
|
|
+ }
|
|
|
+ resolve(server)
|
|
|
})
|
|
|
}
|
|
|
|
|
|
@@ -1492,27 +1273,11 @@ class AssetGuard extends EventEmitter {
|
|
|
let alist = []
|
|
|
let asize = 0;
|
|
|
let decompressqueue = []
|
|
|
- for(let i=0; i<modules.length; i++){
|
|
|
- let ob = modules[i]
|
|
|
- let obType = ob.type
|
|
|
- let obArtifact = ob.artifact
|
|
|
- let obPath = obArtifact.path == null ? AssetGuard._resolvePath(ob.id, obArtifact.extension) : obArtifact.path
|
|
|
- switch(obType){
|
|
|
- case 'forge-hosted':
|
|
|
- case 'forge':
|
|
|
- case 'liteloader':
|
|
|
- case 'library':
|
|
|
- obPath = path.join(this.commonPath, 'libraries', obPath)
|
|
|
- break
|
|
|
- case 'forgemod':
|
|
|
- case 'litemod':
|
|
|
- obPath = path.join(this.commonPath, 'modstore', obPath)
|
|
|
- break
|
|
|
- case 'file':
|
|
|
- default:
|
|
|
- obPath = path.join(this.instancePath, servid, obPath)
|
|
|
- }
|
|
|
- let artifact = new DistroModule(ob.id, obArtifact.MD5, obArtifact.size, obArtifact.url, obPath, obType)
|
|
|
+ for(let ob of modules){
|
|
|
+ let obType = ob.getType
|
|
|
+ let obArtifact = ob.getArtifact()
|
|
|
+ let obPath = obArtifact.getPath()
|
|
|
+ let artifact = new DistroModule(ob.getIdentifier(), obArtifact.getHash(), obArtifact.getSize(), obArtifact.getURL(), obPath, obType)
|
|
|
const validationPath = obPath.toLowerCase().endsWith('.pack.xz') ? obPath.substring(0, obPath.toLowerCase().lastIndexOf('.pack.xz')) : obPath
|
|
|
if(!AssetGuard._validateLocal(validationPath, 'MD5', artifact.hash)){
|
|
|
asize += artifact.size*1
|
|
|
@@ -1520,8 +1285,8 @@ class AssetGuard extends EventEmitter {
|
|
|
if(validationPath !== obPath) decompressqueue.push(obPath)
|
|
|
}
|
|
|
//Recursively process the submodules then combine the results.
|
|
|
- if(ob.sub_modules != null){
|
|
|
- let dltrack = this._parseDistroModules(ob.sub_modules, version, servid)
|
|
|
+ if(ob.getSubModules() != null){
|
|
|
+ let dltrack = this._parseDistroModules(ob.getSubModules(), version, servid)
|
|
|
asize += dltrack.dlsize*1
|
|
|
alist = alist.concat(dltrack.dlqueue)
|
|
|
decompressqueue = decompressqueue.concat(dltrack.callback)
|
|
|
@@ -1535,30 +1300,19 @@ class AssetGuard extends EventEmitter {
|
|
|
/**
|
|
|
* Loads Forge's version.json data into memory for the specified server id.
|
|
|
*
|
|
|
- * @param {string} serverpack The id of the server to load Forge data for.
|
|
|
+ * @param {string} server The Server to load Forge data for.
|
|
|
* @returns {Promise.<Object>} A promise which resolves to Forge's version.json data.
|
|
|
*/
|
|
|
- loadForgeData(serverpack){
|
|
|
+ loadForgeData(server){
|
|
|
const self = this
|
|
|
return new Promise(async (resolve, reject) => {
|
|
|
- let distro = AssetGuard.getDistributionData()
|
|
|
-
|
|
|
- const servers = distro.servers
|
|
|
- let serv = null
|
|
|
- for(let i=0; i<servers.length; i++){
|
|
|
- if(servers[i].id === serverpack){
|
|
|
- serv = servers[i]
|
|
|
- break
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- const modules = serv.modules
|
|
|
- for(let i=0; i<modules.length; i++){
|
|
|
- const ob = modules[i]
|
|
|
- if(ob.type === 'forge-hosted' || ob.type === 'forge'){
|
|
|
- let obArtifact = ob.artifact
|
|
|
- let obPath = obArtifact.path == null ? path.join(self.commonPath, 'libraries', AssetGuard._resolvePath(ob.id, obArtifact.extension)) : obArtifact.path
|
|
|
- let asset = new DistroModule(ob.id, obArtifact.MD5, obArtifact.size, obArtifact.url, obPath, ob.type)
|
|
|
+ const modules = server.getModules()
|
|
|
+ for(let ob of modules){
|
|
|
+ const type = ob.getType()
|
|
|
+ if(type === DistroManager.Types.ForgeHosted || type === DistroManager.Types.Forge){
|
|
|
+ let obArtifact = ob.getArtifact()
|
|
|
+ let obPath = obArtifact.getPath()
|
|
|
+ let asset = new DistroModule(ob.getIdentifier(), obArtifact.getHash(), obArtifact.getSize(), obArtifact.getURL(), obPath, type)
|
|
|
let forgeData = await AssetGuard._finalizeForgeAsset(asset, self.commonPath)
|
|
|
resolve(forgeData)
|
|
|
return
|
|
|
@@ -1602,7 +1356,7 @@ class AssetGuard extends EventEmitter {
|
|
|
dataDir = path.join(dataDir, 'runtime', 'x64')
|
|
|
const name = combined.substring(combined.lastIndexOf('/')+1)
|
|
|
const fDir = path.join(dataDir, name)
|
|
|
- const jre = new Asset(name, null, resp.headers['content-length'], opts, fDir)
|
|
|
+ const jre = new Asset(name, null, parseInt(resp.headers['content-length']), opts, fDir)
|
|
|
this.java = new DLTracker([jre], jre.size, (a, self) => {
|
|
|
let h = null
|
|
|
fs.createReadStream(a.to)
|
|
|
@@ -1626,7 +1380,7 @@ class AssetGuard extends EventEmitter {
|
|
|
h = h.substring(0, h.indexOf('/'))
|
|
|
}
|
|
|
const pos = path.join(dataDir, h)
|
|
|
- self.emit('jExtracted', AssetGuard.javaExecFromRoot(pos))
|
|
|
+ self.emit('complete', 'java', AssetGuard.javaExecFromRoot(pos))
|
|
|
})
|
|
|
})
|
|
|
|
|
|
@@ -1696,74 +1450,109 @@ class AssetGuard extends EventEmitter {
|
|
|
* @returns {boolean} True if the process began, otherwise false.
|
|
|
*/
|
|
|
startAsyncProcess(identifier, limit = 5){
|
|
|
+
|
|
|
const self = this
|
|
|
- let acc = 0
|
|
|
- const concurrentDlTracker = this[identifier]
|
|
|
- const concurrentDlQueue = concurrentDlTracker.dlqueue.slice(0)
|
|
|
- if(concurrentDlQueue.length === 0){
|
|
|
- return false
|
|
|
- } else {
|
|
|
- console.log('DLQueue', concurrentDlQueue)
|
|
|
- async.eachLimit(concurrentDlQueue, limit, (asset, cb) => {
|
|
|
- let count = 0;
|
|
|
- mkpath.sync(path.join(asset.to, ".."))
|
|
|
+ const dlTracker = this[identifier]
|
|
|
+ const dlQueue = dlTracker.dlqueue
|
|
|
+
|
|
|
+ if(dlQueue.length > 0){
|
|
|
+ console.log('DLQueue', dlQueue)
|
|
|
+
|
|
|
+ async.eachLimit(dlQueue, limit, (asset, cb) => {
|
|
|
+
|
|
|
+ mkpath.sync(path.join(asset.to, '..'))
|
|
|
+
|
|
|
let req = request(asset.from)
|
|
|
req.pause()
|
|
|
+
|
|
|
req.on('response', (resp) => {
|
|
|
+
|
|
|
if(resp.statusCode === 200){
|
|
|
+
|
|
|
+ let doHashCheck = false
|
|
|
+ const contentLength = parseInt(resp.headers['content-length'])
|
|
|
+
|
|
|
+ if(contentLength !== asset.size){
|
|
|
+ console.log(`WARN: Got ${contentLength} bytes for ${asset.id}: Expected ${asset.size}`)
|
|
|
+ doHashCheck = true
|
|
|
+
|
|
|
+ // Adjust download
|
|
|
+ this.totaldlsize -= asset.size
|
|
|
+ this.totaldlsize += contentLength
|
|
|
+ }
|
|
|
+
|
|
|
let writeStream = fs.createWriteStream(asset.to)
|
|
|
writeStream.on('close', () => {
|
|
|
- //console.log('DLResults ' + asset.size + ' ' + count + ' ', asset.size === count)
|
|
|
- if(concurrentDlTracker.callback != null){
|
|
|
- concurrentDlTracker.callback.apply(concurrentDlTracker, [asset, self])
|
|
|
+ if(dlTracker.callback != null){
|
|
|
+ dlTracker.callback.apply(dlTracker, [asset, self])
|
|
|
}
|
|
|
+
|
|
|
+ if(doHashCheck){
|
|
|
+ const v = AssetGuard._validateLocal(asset.to, asset.type != null ? 'md5' : 'sha1', asset.hash)
|
|
|
+ if(v){
|
|
|
+ console.log(`Hashes match for ${asset.id}, byte mismatch is an issue in the distro index.`)
|
|
|
+ } else {
|
|
|
+ console.error(`Hashes do not match, ${asset.id} may be corrupted.`)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
cb()
|
|
|
})
|
|
|
req.pipe(writeStream)
|
|
|
req.resume()
|
|
|
+
|
|
|
} else {
|
|
|
+
|
|
|
req.abort()
|
|
|
- const realFrom = typeof asset.from === 'object' ? asset.from.url : asset.from
|
|
|
- console.log('Failed to download ' + realFrom + '. Response code', resp.statusCode)
|
|
|
+ console.log(`Failed to download ${asset.id}(${typeof asset.from === 'object' ? asset.from.url : asset.from}). Response code ${resp.statusCode}`)
|
|
|
self.progress += asset.size*1
|
|
|
- self.emit('totaldlprogress', {acc: self.progress, total: self.totaldlsize})
|
|
|
+ self.emit('progress', 'download', self.progress, self.totaldlsize)
|
|
|
cb()
|
|
|
+
|
|
|
}
|
|
|
+
|
|
|
})
|
|
|
+
|
|
|
req.on('error', (err) => {
|
|
|
- self.emit('dlerror', err)
|
|
|
+ self.emit('error', 'download', err)
|
|
|
})
|
|
|
+
|
|
|
req.on('data', (chunk) => {
|
|
|
- count += chunk.length
|
|
|
self.progress += chunk.length
|
|
|
- acc += chunk.length
|
|
|
- self.emit(identifier + 'dlprogress', acc)
|
|
|
- self.emit('totaldlprogress', {acc: self.progress, total: self.totaldlsize})
|
|
|
+ self.emit('progress', 'download', self.progress, self.totaldlsize)
|
|
|
})
|
|
|
+
|
|
|
}, (err) => {
|
|
|
+
|
|
|
if(err){
|
|
|
- self.emit(identifier + 'dlerror')
|
|
|
console.log('An item in ' + identifier + ' failed to process');
|
|
|
} else {
|
|
|
- self.emit(identifier + 'dlcomplete')
|
|
|
console.log('All ' + identifier + ' have been processed successfully')
|
|
|
}
|
|
|
- self.totaldlsize -= self[identifier].dlsize
|
|
|
- self.progress -= self[identifier].dlsize
|
|
|
+
|
|
|
+ //self.totaldlsize -= dlTracker.dlsize
|
|
|
+ //self.progress -= dlTracker.dlsize
|
|
|
self[identifier] = new DLTracker([], 0)
|
|
|
- if(self.totaldlsize === 0) {
|
|
|
+
|
|
|
+ if(self.progress >= self.totaldlsize) {
|
|
|
if(self.extractQueue.length > 0){
|
|
|
- self.emit('extracting')
|
|
|
+ self.emit('progress', 'extract', 1, 1)
|
|
|
+ //self.emit('extracting')
|
|
|
AssetGuard._extractPackXZ(self.extractQueue, self.javaexec).then(() => {
|
|
|
self.extractQueue = []
|
|
|
- self.emit('dlcomplete')
|
|
|
+ self.emit('complete', 'download')
|
|
|
})
|
|
|
} else {
|
|
|
- self.emit('dlcomplete')
|
|
|
+ self.emit('complete', 'download')
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
})
|
|
|
+
|
|
|
return true
|
|
|
+
|
|
|
+ } else {
|
|
|
+ return false
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1772,32 +1561,69 @@ class AssetGuard extends EventEmitter {
|
|
|
* 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 object and processing will complete
|
|
|
- * immediately. Once all downloads are complete, this function will fire the 'dlcomplete' event on the
|
|
|
+ * immediately. Once all downloads are complete, this function will fire the 'complete' event on the
|
|
|
* global object instance.
|
|
|
*
|
|
|
* @param {Array.<{id: string, limit: number}>} identifiers Optional. The identifiers to process and corresponding parallel async task limit.
|
|
|
*/
|
|
|
processDlQueues(identifiers = [{id:'assets', limit:20}, {id:'libraries', limit:5}, {id:'files', limit:5}, {id:'forge', limit:5}]){
|
|
|
- this.progress = 0;
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ let shouldFire = true
|
|
|
|
|
|
- let shouldFire = true
|
|
|
+ // Assign dltracking variables.
|
|
|
+ this.totaldlsize = 0
|
|
|
+ this.progress = 0
|
|
|
|
|
|
- // Assign dltracking variables.
|
|
|
- this.totaldlsize = 0
|
|
|
- this.progress = 0
|
|
|
- for(let i=0; i<identifiers.length; i++){
|
|
|
- this.totaldlsize += this[identifiers[i].id].dlsize
|
|
|
- }
|
|
|
+ for(let iden of identifiers){
|
|
|
+ this.totaldlsize += this[iden.id].dlsize
|
|
|
+ }
|
|
|
|
|
|
- for(let i=0; i<identifiers.length; i++){
|
|
|
- let iden = identifiers[i]
|
|
|
- let r = this.startAsyncProcess(iden.id, iden.limit)
|
|
|
- if(r) shouldFire = false
|
|
|
- }
|
|
|
+ this.once('complete', (data) => {
|
|
|
+ resolve()
|
|
|
+ })
|
|
|
|
|
|
- if(shouldFire){
|
|
|
- this.emit('dlcomplete')
|
|
|
+ for(let iden of identifiers){
|
|
|
+ let r = this.startAsyncProcess(iden.id, iden.limit)
|
|
|
+ if(r) shouldFire = false
|
|
|
+ }
|
|
|
+
|
|
|
+ if(shouldFire){
|
|
|
+ this.emit('complete', 'download')
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ async validateEverything(serverid, dev = false){
|
|
|
+
|
|
|
+ if(!ConfigManager.isLoaded()){
|
|
|
+ ConfigManager.load()
|
|
|
+ }
|
|
|
+ DistroManager.setDevMode(dev)
|
|
|
+ const dI = await DistroManager.pullLocal()
|
|
|
+
|
|
|
+ const server = dI.getServer(serverid)
|
|
|
+
|
|
|
+ // Validate Everything
|
|
|
+
|
|
|
+ await this.validateDistribution(server)
|
|
|
+ this.emit('validate', 'distribution')
|
|
|
+ const versionData = await this.loadVersionData(server.getMinecraftVersion())
|
|
|
+ this.emit('validate', 'version')
|
|
|
+ await this.validateAssets(versionData)
|
|
|
+ this.emit('validate', 'assets')
|
|
|
+ await this.validateLibraries(versionData)
|
|
|
+ this.emit('validate', 'libraries')
|
|
|
+ await this.validateMiscellaneous(versionData)
|
|
|
+ this.emit('validate', 'files')
|
|
|
+ await this.processDlQueues()
|
|
|
+ //this.emit('complete', 'download')
|
|
|
+ const forgeData = await this.loadForgeData(server)
|
|
|
+
|
|
|
+ return {
|
|
|
+ versionData,
|
|
|
+ forgeData
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
|
|
|
// #endregion
|