Removing old and deprecated assets in preparation for the new design.

This commit is contained in:
Daniel Scalzi
2017-08-26 14:43:24 -04:00
parent 4a8bffe8f6
commit 6a44694a32
18 changed files with 85 additions and 1155 deletions

View File

@@ -1,239 +0,0 @@
const fs = require('fs')
const request = require('request')
const path = require('path')
const mkpath = require('mkdirp');
const async = require('async')
const crypto = require('crypto')
const Library = require('./library.js')
const {BrowserWindow} = require('electron')
/**
* PHASING THIS OUT, WILL BE REMOVED WHEN ASSET GUARD MODULE IS COMPLETE!
*/
function Asset(from, to, size, hash){
this.from = from
this.to = to
this.size = size
this.hash = hash
}
function AssetIndex(id, sha1, size, url, totalSize){
this.id = id
this.sha1 = sha1
this.size = size
this.url = url
this.totalSize = totalSize
}
/**
* This function will download the version index data and read it into a Javascript
* Object. This object will then be returned.
*/
parseVersionData = function(version, basePath){
const name = version + '.json'
const baseURL = 'https://s3.amazonaws.com/Minecraft.Download/versions/' + version + '/' + name
const versionPath = path.join(basePath, 'versions', version)
return new Promise(function(fulfill, reject){
request.head(baseURL, function(err, res, body){
console.log('Preparing download of ' + version + ' assets.')
mkpath.sync(versionPath)
const stream = request(baseURL).pipe(fs.createWriteStream(path.join(versionPath, name)))
stream.on('finish', function(){
fulfill(JSON.parse(fs.readFileSync(path.join(versionPath, name))))
})
})
})
}
/**
* Download the client for version. This file is 'client.jar' although
* it must be renamed to '{version}'.jar.
*/
downloadClient = function(versionData, basePath){
const dls = versionData['downloads']
const clientData = dls['client']
const url = clientData['url']
const size = clientData['size']
const version = versionData['id']
const sha1 = clientData['sha1']
const targetPath = path.join(basePath, 'versions', version)
const targetFile = version + '.jar'
if(!validateLocalIntegrity(path.join(targetPath, targetFile), 'sha1', sha1)){
request.head(url, function(err, res, body){
console.log('Downloading ' + version + ' client..')
mkpath.sync(targetPath)
const stream = request(url).pipe(fs.createWriteStream(path.join(targetPath, targetFile)))
stream.on('finish', function(){
console.log('Finished downloading ' + version + ' client.')
})
})
}
}
downloadLogConfig = function(versionData, basePath){
const logging = versionData['logging']
const client = logging['client']
const file = client['file']
const version = versionData['id']
const sha1 = file['sha1']
const targetPath = path.join(basePath, 'assets', 'log_configs')
const name = file['id']
const url = file['url']
if(!validateLocalIntegrity(path.join(targetPath, name), 'sha1', sha1)){
request.head(url, function(err, res, body){
console.log('Downloading ' + version + ' log config..')
mkpath.sync(targetPath)
const stream = request(url).pipe(fs.createWriteStream(path.join(targetPath, name)))
stream.on('finish', function(){
console.log('Finished downloading ' + version + ' log config..')
})
})
}
}
downloadLibraries = function(versionData, basePath){
const libArr = versionData['libraries']
const libPath = path.join(basePath, 'libraries')
let win = BrowserWindow.getFocusedWindow()
const libDlQueue = []
let dlSize = 0
//Check validity of each library. If the hashs don't match, download the library.
libArr.forEach(function(lib, index){
if(Library.validateRules(lib.rules)){
let artifact = null
if(lib.natives == null){
artifact = lib.downloads.artifact
} else {
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(!validateLocalIntegrity(libItm.to, 'sha1', libItm.sha1)){
dlSize += libItm.size
libDlQueue.push(libItm)
}
}
})
let acc = 0;
//Download all libraries that failed validation.
async.eachLimit(libDlQueue, 1, function(lib, cb){
mkpath.sync(path.join(lib.to, '..'))
let req = request(lib.from)
let writeStream = fs.createWriteStream(lib.to)
req.pipe(writeStream)
req.on('data', function(chunk){
acc += chunk.length
//console.log('Progress', acc/dlSize)
win.setProgressBar(acc/dlSize)
})
writeStream.on('close', cb)
}, function(err){
if(err){
console.log('A library failed to process');
} else {
console.log('All libraries have been processed successfully');
}
win.setProgressBar(-1)
})
}
/**
* Given an index url, this function will asynchonously download the
* assets associated with that version.
*/
downloadAssets = function(versionData, basePath){
//Asset index constants.
const assetIndex = versionData.assetIndex
const indexURL = assetIndex.url
const gameVersion = versionData.id
const assetVersion = assetIndex.id
const name = assetVersion + '.json'
//Asset constants
const resourceURL = 'http://resources.download.minecraft.net/'
const localPath = path.join(basePath, 'assets')
const indexPath = path.join(localPath, 'indexes')
const objectPath = path.join(localPath, 'objects')
let win = BrowserWindow.getFocusedWindow()
const assetIndexLoc = path.join(indexPath, name)
/*if(!fs.existsSync(assetIndexLoc)){
}*/
console.log('Downloading ' + gameVersion + ' asset index.')
mkpath.sync(indexPath)
const stream = request(indexURL).pipe(fs.createWriteStream(assetIndexLoc))
stream.on('finish', function() {
const data = JSON.parse(fs.readFileSync(assetIndexLoc, 'utf-8'))
const assetDlQueue = []
let dlSize = 0;
Object.keys(data.objects).forEach(function(key, index){
const ob = data.objects[key]
const hash = ob.hash
const assetName = path.join(hash.substring(0, 2), hash)
const urlName = hash.substring(0, 2) + "/" + hash
const ast = new Asset(resourceURL + urlName, path.join(objectPath, assetName), ob.size, String(ob.hash))
if(!validateLocalIntegrity(ast.to, 'sha1', ast.hash)){
dlSize += ast.size
assetDlQueue.push(ast)
}
})
let acc = 0;
async.eachLimit(assetDlQueue, 5, function(asset, cb){
mkpath.sync(path.join(asset.to, ".."))
let req = request(asset.from)
let writeStream = fs.createWriteStream(asset.to)
req.pipe(writeStream)
req.on('data', function(chunk){
acc += chunk.length
console.log('Progress', acc/dlSize)
win.setProgressBar(acc/dlSize)
})
writeStream.on('close', cb)
}, function(err){
if(err){
console.log('An asset failed to process');
} else {
console.log('All assets have been processed successfully');
}
win.setProgressBar(-1)
})
})
}
validateLocalIntegrity = function(filePath, algo, hash){
if(fs.existsSync(filePath)){
let fileName = path.basename(filePath)
console.log('Validating integrity of local file', fileName)
let shasum = crypto.createHash(algo)
let content = fs.readFileSync(filePath)
shasum.update(content)
let localhash = shasum.digest('hex')
if(localhash === hash){
console.log('Hash value of ' + fileName + ' matches the index hash, woo!')
return true
} else {
console.log('Hash value of ' + fileName + ' (' + localhash + ')' + ' does not match the index hash. Redownloading..')
return false
}
}
return false;
}
module.exports = {
parseVersionData,
downloadClient,
downloadLogConfig,
downloadLibraries,
downloadAssets
}

View File

@@ -307,7 +307,9 @@ function _validateForgeChecksum(filePath, checksums){
* @returns {Boolean} - true if all hashes declared in the checksums.sha1 file match the actual hashes.
*/
function _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.
const hashes = {}
let expected = {}
@@ -361,6 +363,16 @@ function _extractPackXZ(filePaths){
})
}
/**
* Function which finalizes the forge installation process. This creates a 'version'
* instance for forge and saves its version.json file into that instance. If that
* instance already exists, the contents of the version.json file are read and returned
* in a promise.
*
* @param {Asset} asset - The Asset object representing Forge.
* @param {String} basePath
* @returns {Promise.<Object>} - A promise which resolves to the contents of forge's version.json.
*/
function _finalizeForgeAsset(asset, basePath){
return new Promise(function(fulfill, reject){
fs.readFile(asset.to, (err, data) => {
@@ -377,11 +389,14 @@ function _finalizeForgeAsset(asset, basePath){
fs.writeFileSync(path.join(versionPath, forgeVersion.id + '.json'), zipEntries[i].getData())
fulfill(forgeVersion)
} else {
//Read the saved file to allow for user modifications.
fulfill(JSON.parse(fs.readFileSync(versionFile, 'utf-8')))
}
return
}
}
//We didn't find forge's version.json.
reject('Unable to finalize Forge processing, version.json not found! Has forge changed their format?')
})
})
}
@@ -402,7 +417,7 @@ function startAsyncProcess(identifier, limit = 5){
if(concurrentDlQueue.length === 0){
return false
} else {
console.log(instance.progress)
console.log(concurrentDlQueue)
async.eachLimit(concurrentDlQueue, limit, function(asset, cb){
let count = 0;
mkpath.sync(path.join(asset.to, ".."))
@@ -745,32 +760,29 @@ function _parseDistroModules(modules, basePath, version){
switch(obType){
case 'forge-hosted':
case 'forge':
obPath = path.join(basePath, 'libraries', obPath)
break
case 'library':
obPath = path.join(basePath, 'libraries', obPath)
break
case 'forgemod':
obPath = path.join(basePath, 'mods', obPath)
//obPath = path.join(basePath, 'mods', obPath)
obPath = path.join(basePath, 'modstore', obPath)
break
case 'litemod':
obPath = path.join(basePath, 'mods', version, obPath)
//obPath = path.join(basePath, 'mods', version, obPath)
obPath = path.join(basePath, 'modstore', obPath)
break
case 'file':
default:
obPath = path.join(basePath, obPath)
}
let artifact = new DistroModule(ob.id, obArtifact.MD5, obArtifact.size, obArtifact.url, obPath, obType)
if(obPath.toLowerCase().endsWith('.pack.xz')){
if(!_validateLocal(obPath.substring(0, obPath.toLowerCase().lastIndexOf('.pack.xz')), 'MD5', artifact.hash)){
asize += artifact.size*1
alist.push(artifact)
decompressqueue.push(obPath)
}
} else if(!_validateLocal(obPath, 'MD5', artifact.hash)){
const validationPath = obPath.toLowerCase().endsWith('.pack.xz') ? obPath.substring(0, obPath.toLowerCase().lastIndexOf('.pack.xz')) : obPath
if(!_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)
asize += dltrack.dlsize*1
@@ -778,9 +790,18 @@ function _parseDistroModules(modules, basePath, version){
decompressqueue = decompressqueue.concat(dltrack.callback)
}
}
//Since we have no callback at this point, we use this value to store the decompressqueue.
return new DLTracker(alist, asize, decompressqueue)
}
/**
* 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} basePath
* @returns {Promise.<Object>} - A promise which resolves to Forge's version.json data.
*/
function loadForgeData(serverpack, basePath){
return new Promise(async function(fulfill, reject){
let distro = await _chainValidateDistributionIndex(basePath)
@@ -811,7 +832,11 @@ function loadForgeData(serverpack, basePath){
}
function _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
* have the code on standby if we ever need it (since it's half implemented already).
*/
}
/**

View File

@@ -8,12 +8,16 @@ const fs = require('fs')
const mkpath = require('mkdirp');
function launchMinecraft(versionData, forgeData, basePath){
const authPromise = mojang.auth('EMAIL', 'PASS', uuidV4(), {
const authPromise = mojang.auth('nytrocraft@live.com', 'applesrsogood123', uuidV4(), {
name: 'Minecraft',
version: 1
})
authPromise.then(function(data){
console.log(data)
const args = finalizeArgumentsForge(versionData, forgeData, data, basePath)
//BRUTEFORCE for testing
//args.push('-mods modstore\\chatbubbles\\chatbubbles\\1.0.1_for_1.11.2\\mod_chatBubbles-1.0.1_for_1.11.2.litemod,modstore\\com\\westeroscraft\\westerosblocks\\3.0.0-beta-71\\westerosblocks-3.0.0-beta-71.jar,modstore\\mezz\\jei\\1.11.2-4.3.5.277\\jei-1.11.2-4.3.5.277.jar,modstore\\net\\optifine\\optifine\\1.11.2_HD_U_B9\\optifine-1.11.2_HD_U_B9.jar')
//args.push('--modListFile absolute:C:\\Users\\Asus\\Desktop\\LauncherElectron\\app\\assets\\WesterosCraft-1.11.2.json')
//TODO make this dynamic
const child = child_process.spawn('C:\\Program Files\\Java\\jre1.8.0_131\\bin\\javaw.exe', args)
child.stdout.on('data', (data) => {
@@ -51,7 +55,8 @@ function finalizeArgumentsForge(versionData, forgeData, authData, basePath){
newVal = gameProfile['name']
break
case 'version_name':
newVal = versionData['id']
//newVal = versionData['id']
newVal = 'WesterosCraft-1.11.2'
break
case 'game_directory':
newVal = basePath
@@ -200,6 +205,10 @@ function classpathArg(versionData, basePath){
}
})
//BRUTEFORCE LIB INJECTION
//FOR TESTING ONLY
cpArgs.push(path.join(libPath, 'com', 'mumfrey', 'liteloader', '1.11.2-SNAPSHOT', 'liteloader-1.11.2-SNAPSHOT.jar'))
return cpArgs
}

View File

@@ -45,7 +45,7 @@ export class ModList {
* @param {Object} distro - the distribution index.
*/
static generateModList(distro){
}
}

View File

@@ -26,7 +26,7 @@ $(document).on('ready', function(){
$(this).parent().toggleClass("success")
}
})
console.log = function(){
/*console.log = function(){
$('#launcher-log').append(timestamp() + ' [Log] - ' + Array.prototype.slice.call(arguments).join(' ') + os.EOL)
}
console.error = function(){
@@ -36,7 +36,7 @@ $(document).on('ready', function(){
$('#launcher-log').append('<span class="log_debug">' + timestamp() + ' [Error] - ' + Array.prototype.slice.call(arguments).join(' ') + "</span>" + os.EOL)
}
console.log('test')
console.debug('test')
console.debug('test')*/
})
/* Open web links in the user's default browser. */