Added Index Processor for Mojang Indices.
Also added test for the mojang processor. TBD: Progress System for Validations. TBD: Processor for Distribution.json.
This commit is contained in:
parent
8764c52fcc
commit
c9147d86a8
7
src/main/asset/model/engine/Asset.ts
Normal file
7
src/main/asset/model/engine/Asset.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export interface Asset {
|
||||
id: string
|
||||
hash: string
|
||||
size: number
|
||||
url: string
|
||||
path: string
|
||||
}
|
33
src/main/asset/model/engine/AssetGuardError.ts
Normal file
33
src/main/asset/model/engine/AssetGuardError.ts
Normal file
@ -0,0 +1,33 @@
|
||||
export class AssetGuardError extends Error {
|
||||
|
||||
code?: string
|
||||
stack!: string
|
||||
error?: Partial<Error & {code?: string;}>
|
||||
|
||||
constructor(message: string, error?: Partial<Error & {code?: string;}>) {
|
||||
super(message)
|
||||
|
||||
Error.captureStackTrace(this, this.constructor)
|
||||
|
||||
// Reference: https://github.com/sindresorhus/got/blob/master/source/core/index.ts#L340
|
||||
if(error) {
|
||||
|
||||
this.error = error
|
||||
this.code = error?.code
|
||||
|
||||
if (error.stack != null) {
|
||||
const indexOfMessage = this.stack.indexOf(this.message) + this.message.length;
|
||||
const thisStackTrace = this.stack.slice(indexOfMessage).split('\n').reverse();
|
||||
const errorStackTrace = error.stack.slice(error.stack.indexOf(error.message!) + error.message!.length).split('\n').reverse();
|
||||
|
||||
// Remove duplicated traces
|
||||
while (errorStackTrace.length !== 0 && errorStackTrace[0] === thisStackTrace[0]) {
|
||||
thisStackTrace.shift();
|
||||
}
|
||||
|
||||
this.stack = `${this.stack.slice(0, indexOfMessage)}${thisStackTrace.reverse().join('\n')}${errorStackTrace.reverse().join('\n')}`;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
12
src/main/asset/model/engine/IndexProcessor.ts
Normal file
12
src/main/asset/model/engine/IndexProcessor.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Asset } from './Asset'
|
||||
|
||||
export abstract class IndexProcessor {
|
||||
|
||||
constructor(
|
||||
protected commonDir: string
|
||||
) {}
|
||||
|
||||
abstract async init(): Promise<void>
|
||||
abstract async validate(): Promise<{[category: string]: Asset[]}>
|
||||
|
||||
}
|
@ -23,7 +23,7 @@ export interface BaseArtifact {
|
||||
|
||||
}
|
||||
|
||||
interface LibraryArtifact extends BaseArtifact {
|
||||
export interface LibraryArtifact extends BaseArtifact {
|
||||
|
||||
path: string
|
||||
|
||||
|
15
src/main/asset/model/mojang/VersionManifest.ts
Normal file
15
src/main/asset/model/mojang/VersionManifest.ts
Normal file
@ -0,0 +1,15 @@
|
||||
export interface MojangVersionManifest {
|
||||
|
||||
latest: {
|
||||
release: string
|
||||
snapshot: string
|
||||
}
|
||||
versions: {
|
||||
id: string
|
||||
type: string
|
||||
url: string
|
||||
time: string
|
||||
releaseTime: string
|
||||
}[]
|
||||
|
||||
}
|
305
src/main/asset/processor/MojangIndexProcessor.ts
Normal file
305
src/main/asset/processor/MojangIndexProcessor.ts
Normal file
@ -0,0 +1,305 @@
|
||||
import { IndexProcessor } from '../model/engine/IndexProcessor'
|
||||
import got, { HTTPError, GotError, RequestError, ParseError, TimeoutError } from 'got'
|
||||
import { LoggerUtil } from '../../logging/loggerutil'
|
||||
import { pathExists, readFile, ensureDir, writeFile, readJson } from 'fs-extra'
|
||||
import { MojangVersionManifest } from '../model/mojang/VersionManifest'
|
||||
import { calculateHash, getVersionJsonPath, validateLocalFile, getLibraryDir, getVersionJarPath } from '../../util/FileUtils'
|
||||
import { dirname, join } from 'path'
|
||||
import { VersionJson, AssetIndex, LibraryArtifact } from '../model/mojang/VersionJson'
|
||||
import { AssetGuardError } from '../model/engine/AssetGuardError'
|
||||
import { Asset } from '../model/engine/Asset'
|
||||
import { isLibraryCompatible, getMojangOS } from '../../util/MojangUtils'
|
||||
|
||||
export class MojangIndexProcessor extends IndexProcessor {
|
||||
|
||||
public static readonly LAUNCHER_JSON_ENDPOINT = 'https://launchermeta.mojang.com/mc/launcher.json'
|
||||
public static readonly VERSION_MANIFEST_ENDPOINT = 'https://launchermeta.mojang.com/mc/game/version_manifest.json'
|
||||
public static readonly ASSET_RESOURCE_ENDPOINT = 'http://resources.download.minecraft.net'
|
||||
|
||||
private readonly logger = LoggerUtil.getLogger('MojangIndexProcessor')
|
||||
|
||||
private versionJson!: VersionJson
|
||||
private assetIndex!: AssetIndex
|
||||
private client = got.extend({
|
||||
responseType: 'json'
|
||||
})
|
||||
|
||||
private handleGotError<T>(operation: string, error: GotError, dataProvider: () => T): T {
|
||||
if(error instanceof HTTPError) {
|
||||
this.logger.error(`Error during ${operation} request (HTTP Response ${error.response.statusCode})`, error)
|
||||
this.logger.debug('Response Details:')
|
||||
this.logger.debug('Body:', error.response.body)
|
||||
this.logger.debug('Headers:', error.response.headers)
|
||||
} else if(error instanceof RequestError) {
|
||||
this.logger.error(`${operation} request recieved no response (${error.code}).`, error)
|
||||
} else if(error instanceof TimeoutError) {
|
||||
this.logger.error(`${operation} request timed out (${error.timings.phases.total}ms).`)
|
||||
} else if(error instanceof ParseError) {
|
||||
this.logger.error(`${operation} request recieved unexepected body (Parse Error).`)
|
||||
} else {
|
||||
// CacheError, ReadError, MaxRedirectsError, UnsupportedProtocolError, CancelError
|
||||
this.logger.error(`Error during ${operation} request.`, error)
|
||||
}
|
||||
|
||||
return dataProvider()
|
||||
}
|
||||
|
||||
private assetPath: string
|
||||
|
||||
constructor(commonDir: string, protected version: string) {
|
||||
super(commonDir)
|
||||
this.assetPath = join(commonDir, 'assets')
|
||||
}
|
||||
|
||||
/**
|
||||
* Download https://launchermeta.mojang.com/mc/game/version_manifest.json
|
||||
* Unable to download:
|
||||
* Proceed, check versions directory for target version
|
||||
* If version.json not present, fatal error.
|
||||
* If version.json present, load and use.
|
||||
* Able to download:
|
||||
* Download, use in memory only.
|
||||
* Locate target version entry.
|
||||
* Extract hash
|
||||
* Validate local exists and matches hash
|
||||
* Condition fails: download
|
||||
* Download fails: fatal error
|
||||
* Download succeeds: Save to disk, continue
|
||||
* Passes: load from file
|
||||
*
|
||||
* Version JSON in memory
|
||||
* Extract assetIndex
|
||||
* Check that local exists and hash matches
|
||||
* if false, download
|
||||
* download fails: fatal error
|
||||
* if true: load from disk and use
|
||||
*
|
||||
* complete init when 3 files are validated and loaded.
|
||||
*
|
||||
*/
|
||||
public async init() {
|
||||
|
||||
const versionManifest = await this.loadVersionManifest()
|
||||
this.versionJson = await this.loadVersionJson(this.version, versionManifest)
|
||||
this.assetIndex = await this.loadAssetIndex(this.versionJson)
|
||||
|
||||
}
|
||||
|
||||
private async loadAssetIndex(versionJson: VersionJson): Promise<AssetIndex> {
|
||||
const assetIndexPath = this.getAssetIndexPath(versionJson.assetIndex.id)
|
||||
const assetIndex = await this.loadContentWithRemoteFallback<AssetIndex>(versionJson.assetIndex.url, assetIndexPath, { algo: 'sha1', value: versionJson.assetIndex.sha1 })
|
||||
if(assetIndex == null) {
|
||||
throw new AssetGuardError(`Failed to download ${versionJson.assetIndex.id} asset index.`)
|
||||
}
|
||||
return assetIndex
|
||||
}
|
||||
|
||||
private async loadVersionJson(version: string, versionManifest: MojangVersionManifest | null): Promise<VersionJson> {
|
||||
const versionJsonPath = getVersionJsonPath(this.commonDir, version)
|
||||
if(versionManifest != null) {
|
||||
const versionJsonUrl = this.getVersionJsonUrl(version, versionManifest)
|
||||
if(versionJsonUrl == null) {
|
||||
throw new AssetGuardError(`Invalid version: ${version}.`)
|
||||
}
|
||||
const hash = this.getVersionJsonHash(versionJsonUrl)
|
||||
if(hash == null) {
|
||||
throw new AssetGuardError(`Format of Mojang's version manifest has changed. Unable to proceed.`)
|
||||
}
|
||||
const versionJson = await this.loadContentWithRemoteFallback<VersionJson>(versionJsonUrl, versionJsonPath, { algo: 'sha1', value: hash })
|
||||
if(versionJson == null) {
|
||||
throw new AssetGuardError(`Failed to download ${version} json index.`)
|
||||
}
|
||||
|
||||
return versionJson
|
||||
|
||||
} else {
|
||||
// Attempt to find local index.
|
||||
if(await pathExists(versionJsonPath)) {
|
||||
return await readJson(versionJsonPath)
|
||||
} else {
|
||||
throw new AssetGuardError(`Unable to load version manifest and ${version} json index does not exist locally.`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async loadContentWithRemoteFallback<T>(url: string, path: string, hash?: {algo: string, value: string}): Promise<T | null> {
|
||||
|
||||
try {
|
||||
if(await pathExists(path)) {
|
||||
const buf = await readFile(path)
|
||||
if(hash) {
|
||||
const bufHash = calculateHash(buf, hash.algo)
|
||||
if(bufHash === hash.value) {
|
||||
return JSON.parse(buf.toString())
|
||||
}
|
||||
} else {
|
||||
return JSON.parse(buf.toString())
|
||||
}
|
||||
}
|
||||
} catch(error) {
|
||||
throw new AssetGuardError(`Failure while loading ${path}.`, error)
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await this.client.get<T>(url)
|
||||
|
||||
await ensureDir(dirname(path))
|
||||
await writeFile(path, res.body)
|
||||
|
||||
return res.body
|
||||
} catch(error) {
|
||||
return this.handleGotError(url, error as GotError, () => null)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async loadVersionManifest(): Promise<MojangVersionManifest | null> {
|
||||
try {
|
||||
const res = await this.client.get<MojangVersionManifest>(MojangIndexProcessor.VERSION_MANIFEST_ENDPOINT)
|
||||
return res.body
|
||||
} catch(error) {
|
||||
return this.handleGotError('Load Mojang Version Manifest', error as GotError, () => null)
|
||||
}
|
||||
}
|
||||
|
||||
private getVersionJsonUrl(id: string, manifest: MojangVersionManifest): string | null {
|
||||
for(const version of manifest.versions) {
|
||||
if(version.id == id){
|
||||
return version.url
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private getVersionJsonHash(url: string): string | null {
|
||||
const regex = /^https:\/\/launchermeta.mojang.com\/v1\/packages\/(.+)\/.+.json$/
|
||||
const match = regex.exec(url)
|
||||
if(match != null && match[1]) {
|
||||
return match[1]
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private getAssetIndexPath(id: string): string {
|
||||
return join(this.assetPath, 'indexes', `${id}.json`)
|
||||
}
|
||||
|
||||
// TODO progress tracker
|
||||
public async validate() {
|
||||
|
||||
const assets = await this.validateAssets(this.assetIndex)
|
||||
const libraries = await this.validateLibraries(this.versionJson)
|
||||
const client = await this.validateClient(this.versionJson)
|
||||
const logConfig = await this.validateLogConfig(this.versionJson)
|
||||
|
||||
return {
|
||||
assets,
|
||||
libraries,
|
||||
client,
|
||||
misc: [
|
||||
...logConfig
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
private async validateAssets(assetIndex: AssetIndex): Promise<Asset[]> {
|
||||
|
||||
const objectDir = join(this.assetPath, 'objects')
|
||||
const notValid: Asset[] = []
|
||||
|
||||
for(const assetEntry of Object.entries(assetIndex.objects)) {
|
||||
const hash = assetEntry[1].hash
|
||||
const path = join(objectDir, hash.substring(0, 2), hash)
|
||||
const url = `${MojangIndexProcessor.ASSET_RESOURCE_ENDPOINT}/${hash.substring(0, 2)}/${hash}`
|
||||
|
||||
if(!await validateLocalFile(path, 'sha1', hash)) {
|
||||
notValid.push({
|
||||
id: assetEntry[0],
|
||||
hash,
|
||||
size: assetEntry[1].size,
|
||||
url,
|
||||
path
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return notValid
|
||||
|
||||
}
|
||||
|
||||
private async validateLibraries(versionJson: VersionJson): Promise<Asset[]> {
|
||||
|
||||
const libDir = getLibraryDir(this.commonDir)
|
||||
const notValid: Asset[] = []
|
||||
|
||||
for(const libEntry of versionJson.libraries) {
|
||||
if(isLibraryCompatible(libEntry.rules, libEntry.natives)) {
|
||||
let artifact: LibraryArtifact
|
||||
if(libEntry.natives == null) {
|
||||
artifact = libEntry.downloads.artifact
|
||||
} else {
|
||||
// @ts-ignore
|
||||
const classifier = libEntry.natives[getMojangOS()].replace('${arch}', process.arch.replace('x', ''))
|
||||
// @ts-ignore
|
||||
artifact = libEntry.downloads.classifiers[classifier]
|
||||
}
|
||||
|
||||
const path = join(libDir, artifact.path)
|
||||
const hash = artifact.sha1
|
||||
if(!await validateLocalFile(path, 'sha1', hash)) {
|
||||
notValid.push({
|
||||
id: libEntry.name,
|
||||
hash,
|
||||
size: artifact.size,
|
||||
url: artifact.url,
|
||||
path
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return notValid
|
||||
}
|
||||
|
||||
private async validateClient(versionJson: VersionJson): Promise<Asset[]> {
|
||||
|
||||
const version = versionJson.id
|
||||
const versionJarPath = getVersionJarPath(this.commonDir, version)
|
||||
const hash = versionJson.downloads.client.sha1
|
||||
|
||||
if(!await validateLocalFile(versionJarPath, 'sha1', hash)) {
|
||||
return [{
|
||||
id: `${version} client`,
|
||||
hash,
|
||||
size: versionJson.downloads.client.size,
|
||||
url: versionJson.downloads.client.url,
|
||||
path: versionJarPath
|
||||
}]
|
||||
}
|
||||
|
||||
return []
|
||||
|
||||
}
|
||||
|
||||
private async validateLogConfig(versionJson: VersionJson): Promise<Asset[]> {
|
||||
|
||||
const logFile = versionJson.logging.client.file
|
||||
const path = join(this.assetPath, 'log_configs', logFile.id)
|
||||
const hash = logFile.sha1
|
||||
|
||||
if(!await validateLocalFile(path, 'sha1', hash)) {
|
||||
return [{
|
||||
id: logFile.id,
|
||||
hash,
|
||||
size: logFile.size,
|
||||
url: logFile.url,
|
||||
path
|
||||
}]
|
||||
}
|
||||
|
||||
return []
|
||||
|
||||
}
|
||||
|
||||
}
|
34
src/main/util/FileUtils.ts
Normal file
34
src/main/util/FileUtils.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { createHash } from 'crypto'
|
||||
import { join } from 'path'
|
||||
import { pathExists, readFile } from 'fs-extra'
|
||||
|
||||
export function calculateHash(buf: Buffer, algo: string) {
|
||||
return createHash(algo).update(buf).digest('hex')
|
||||
}
|
||||
|
||||
export async function validateLocalFile(path: string, algo: string, hash?: string): Promise<boolean> {
|
||||
if(await pathExists(path)) {
|
||||
if(hash == null) {
|
||||
return true
|
||||
}
|
||||
const buf = await readFile(path)
|
||||
return calculateHash(buf, algo) === hash
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function getVersionExtPath(commonDir: string, version: string, ext: string) {
|
||||
return join(commonDir, 'versions', version, `${version}.${ext}`)
|
||||
}
|
||||
|
||||
export function getVersionJsonPath(commonDir: string, version: string) {
|
||||
return getVersionExtPath(commonDir, version, 'json')
|
||||
}
|
||||
|
||||
export function getVersionJarPath(commonDir: string, version: string) {
|
||||
return getVersionExtPath(commonDir, version, 'jar')
|
||||
}
|
||||
|
||||
export function getLibraryDir(commonDir: string) {
|
||||
return join(commonDir, 'libraries')
|
||||
}
|
60
src/main/util/MojangUtils.ts
Normal file
60
src/main/util/MojangUtils.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { Rule, Natives } from "../asset/model/mojang/VersionJson"
|
||||
|
||||
export function getMojangOS(): string {
|
||||
const opSys = process.platform
|
||||
switch(opSys) {
|
||||
case 'darwin':
|
||||
return 'osx'
|
||||
case 'win32':
|
||||
return 'windows'
|
||||
case 'linux':
|
||||
return 'linux'
|
||||
default:
|
||||
return opSys
|
||||
}
|
||||
}
|
||||
|
||||
export function validateLibraryRules(rules?: Rule[]): boolean {
|
||||
if(rules == null) {
|
||||
return false
|
||||
}
|
||||
for(const rule of rules){
|
||||
if(rule.action != null && rule.os != null){
|
||||
const osName = rule.os.name
|
||||
const osMoj = getMojangOS()
|
||||
if(rule.action === 'allow'){
|
||||
return osName === osMoj
|
||||
} else if(rule.action === 'disallow'){
|
||||
return osName !== osMoj
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export function validateLibraryNatives(natives?: Natives): boolean {
|
||||
return natives == null ? true : Object.hasOwnProperty.call(natives, getMojangOS())
|
||||
}
|
||||
|
||||
export function isLibraryCompatible(rules?: Rule[], natives?: Natives): boolean {
|
||||
return rules == null ? validateLibraryNatives(natives) : validateLibraryRules(rules)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the actual version is greater than
|
||||
* or equal to the desired version.
|
||||
*
|
||||
* @param {string} desired The desired version.
|
||||
* @param {string} actual The actual version.
|
||||
*/
|
||||
export function mcVersionAtLeast(desired: string, actual: string){
|
||||
const des = desired.split('.')
|
||||
const act = actual.split('.')
|
||||
|
||||
for(let i=0; i<des.length; i++){
|
||||
if(!(parseInt(act[i]) >= parseInt(des[i]))){
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
132
test/assets/MojangIndexProcessorTest.ts
Normal file
132
test/assets/MojangIndexProcessorTest.ts
Normal file
@ -0,0 +1,132 @@
|
||||
import nock from 'nock'
|
||||
import { URL } from 'url'
|
||||
import { MojangIndexProcessor } from '../../src/main/asset/processor/MojangIndexProcessor'
|
||||
import { dirname, join } from 'path'
|
||||
import { expect } from 'chai'
|
||||
import { remove, pathExists } from 'fs-extra'
|
||||
import { getVersionJsonPath } from '../../src/main/util/FileUtils'
|
||||
|
||||
// @ts-ignore (JSON Modules enabled in tsconfig.test.json)
|
||||
import versionManifest from './files/version_manifest.json'
|
||||
// @ts-ignore (JSON Modules enabled in tsconfig.test.json)
|
||||
import versionJson115 from './files/1.15.2.json'
|
||||
// @ts-ignore (JSON Modules enabled in tsconfig.test.json)
|
||||
import versionJson1710 from './files/1.7.10.json'
|
||||
// @ts-ignore (JSON Modules enabled in tsconfig.test.json)
|
||||
import index115 from './files/index_1.15.json'
|
||||
|
||||
const commonDir = join(__dirname, 'files')
|
||||
const assetDir = join(commonDir, 'assets')
|
||||
const jsonPath115 = getVersionJsonPath(commonDir, '1.15.2')
|
||||
const indexPath115 = join(assetDir, 'indexes', '1.15.json')
|
||||
const jsonPath1710 = getVersionJsonPath(commonDir, '1.7.10')
|
||||
|
||||
describe('Mojang Index Processor', () => {
|
||||
|
||||
after(async () => {
|
||||
nock.cleanAll()
|
||||
await remove(dirname(jsonPath115))
|
||||
await remove(indexPath115)
|
||||
await remove(dirname(jsonPath1710))
|
||||
})
|
||||
|
||||
it('[ MIP ] Validate Full Remote (1.15.2)', async () => {
|
||||
|
||||
const manifestUrl = new URL(MojangIndexProcessor.VERSION_MANIFEST_ENDPOINT)
|
||||
const versionJsonUrl = new URL('https://launchermeta.mojang.com/v1/packages/1a36ca2e147f4fdc4a8b9c371450e1581732c354/1.15.2.json')
|
||||
const assetIndexUrl = new URL('https://launchermeta.mojang.com/v1/packages/5406d9a75dfb58f549070d8bae279562c38a68f6/1.15.json')
|
||||
|
||||
nock(manifestUrl.origin)
|
||||
.get(manifestUrl.pathname)
|
||||
.reply(200, versionManifest)
|
||||
|
||||
nock(versionJsonUrl.origin)
|
||||
.get(versionJsonUrl.pathname)
|
||||
.reply(200, versionJson115)
|
||||
|
||||
nock(assetIndexUrl.origin)
|
||||
.get(assetIndexUrl.pathname)
|
||||
.reply(200, index115)
|
||||
|
||||
const mojangIndexProcessor = new MojangIndexProcessor(commonDir, '1.15.2')
|
||||
await mojangIndexProcessor.init()
|
||||
|
||||
const notValid = await mojangIndexProcessor.validate()
|
||||
|
||||
const savedJson = await pathExists(jsonPath115)
|
||||
const savedIndex = await pathExists(indexPath115)
|
||||
|
||||
expect(notValid).to.haveOwnProperty('assets')
|
||||
expect(notValid.assets).to.have.lengthOf(2109-2)
|
||||
expect(notValid).to.haveOwnProperty('libraries')
|
||||
// Natives are different per OS
|
||||
expect(notValid.libraries).to.have.length.gte(24)
|
||||
expect(notValid).to.haveOwnProperty('client')
|
||||
expect(notValid.client).to.have.lengthOf(1)
|
||||
expect(notValid).to.haveOwnProperty('misc')
|
||||
expect(notValid.misc).to.have.lengthOf(1)
|
||||
|
||||
expect(savedJson).to.equal(true)
|
||||
expect(savedIndex).to.equal(true)
|
||||
|
||||
})
|
||||
|
||||
it('[ MIP ] Validate Full Local (1.12.2)', async () => {
|
||||
|
||||
const manifestUrl = new URL(MojangIndexProcessor.VERSION_MANIFEST_ENDPOINT)
|
||||
|
||||
nock(manifestUrl.origin)
|
||||
.get(manifestUrl.pathname)
|
||||
.reply(200, versionManifest)
|
||||
|
||||
const mojangIndexProcessor = new MojangIndexProcessor(commonDir, '1.12.2')
|
||||
await mojangIndexProcessor.init()
|
||||
|
||||
const notValid = await mojangIndexProcessor.validate()
|
||||
expect(notValid).to.haveOwnProperty('assets')
|
||||
expect(notValid.assets).to.have.lengthOf(1305-2)
|
||||
expect(notValid).to.haveOwnProperty('libraries')
|
||||
// Natives are different per OS
|
||||
expect(notValid.libraries).to.have.length.gte(27)
|
||||
expect(notValid).to.haveOwnProperty('client')
|
||||
expect(notValid.client).to.have.lengthOf(1)
|
||||
expect(notValid).to.haveOwnProperty('misc')
|
||||
expect(notValid.misc).to.have.lengthOf(1)
|
||||
|
||||
})
|
||||
|
||||
it('[ MIP ] Validate Half Remote (1.7.10)', async () => {
|
||||
|
||||
const manifestUrl = new URL(MojangIndexProcessor.VERSION_MANIFEST_ENDPOINT)
|
||||
const versionJsonUrl = new URL('https://launchermeta.mojang.com/v1/packages/2e818dc89e364c7efcfa54bec7e873c5f00b3840/1.7.10.json')
|
||||
|
||||
nock(manifestUrl.origin)
|
||||
.get(manifestUrl.pathname)
|
||||
.reply(200, versionManifest)
|
||||
|
||||
nock(versionJsonUrl.origin)
|
||||
.get(versionJsonUrl.pathname)
|
||||
.reply(200, versionJson1710)
|
||||
|
||||
const mojangIndexProcessor = new MojangIndexProcessor(commonDir, '1.7.10')
|
||||
await mojangIndexProcessor.init()
|
||||
|
||||
const notValid = await mojangIndexProcessor.validate()
|
||||
|
||||
const savedJson = await pathExists(jsonPath1710)
|
||||
|
||||
expect(notValid).to.haveOwnProperty('assets')
|
||||
expect(notValid.assets).to.have.lengthOf(686-2)
|
||||
expect(notValid).to.haveOwnProperty('libraries')
|
||||
// Natives are different per OS
|
||||
expect(notValid.libraries).to.have.length.gte(27)
|
||||
expect(notValid).to.haveOwnProperty('client')
|
||||
expect(notValid.client).to.have.lengthOf(1)
|
||||
expect(notValid).to.haveOwnProperty('misc')
|
||||
expect(notValid.misc).to.have.lengthOf(1)
|
||||
|
||||
expect(savedJson).to.equal(true)
|
||||
|
||||
})
|
||||
|
||||
})
|
1
test/assets/files/1.15.2.json
Normal file
1
test/assets/files/1.15.2.json
Normal file
File diff suppressed because one or more lines are too long
1
test/assets/files/1.7.10.json
Normal file
1
test/assets/files/1.7.10.json
Normal file
File diff suppressed because one or more lines are too long
1
test/assets/files/assets/indexes/1.12.json
Normal file
1
test/assets/files/assets/indexes/1.12.json
Normal file
File diff suppressed because one or more lines are too long
1
test/assets/files/assets/indexes/1.7.10.json
Normal file
1
test/assets/files/assets/indexes/1.7.10.json
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
1
test/assets/files/index_1.15.json
Normal file
1
test/assets/files/index_1.15.json
Normal file
File diff suppressed because one or more lines are too long
1
test/assets/files/version_manifest.json
Normal file
1
test/assets/files/version_manifest.json
Normal file
@ -0,0 +1 @@
|
||||
{"latest":{"release":"1.15.2","snapshot":"20w16a"},"versions":[{"id":"1.15.2","type":"release","url":"https://launchermeta.mojang.com/v1/packages/1a36ca2e147f4fdc4a8b9c371450e1581732c354/1.15.2.json","time":"2020-04-15T13:24:27+00:00","releaseTime":"2020-01-17T10:03:52+00:00"},{"id":"1.12.2","type":"release","url":"https://launchermeta.mojang.com/v1/packages/6e69e85d0f85f4f4b9e12dd99d102092a6e15918/1.12.2.json","time":"2019-06-28T07:05:57+00:00","releaseTime":"2017-09-18T08:39:46+00:00"},{"id":"1.7.10","type":"release","url":"https://launchermeta.mojang.com/v1/packages/2e818dc89e364c7efcfa54bec7e873c5f00b3840/1.7.10.json","time":"2019-06-28T07:06:16+00:00","releaseTime":"2014-05-14T17:29:23+00:00"}]}
|
1
test/assets/files/versions/1.12.2/1.12.2.json
Normal file
1
test/assets/files/versions/1.12.2/1.12.2.json
Normal file
File diff suppressed because one or more lines are too long
@ -1,7 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"esModuleInterop": true
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"extends": "./tsconfig.json"
|
||||
}
|
Loading…
Reference in New Issue
Block a user