| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- const fs = require('fs')
- const path = require('path')
- const request = require('request')
- const ConfigManager = require('./configmanager')
- const logger = require('./loggerutil')('%c[DistroManager]', 'color: #a02d2a; font-weight: bold')
- /**
- * Represents the download information
- * for a specific module.
- */
- class Artifact {
-
- /**
- * Parse a JSON object into an Artifact.
- *
- * @param {Object} json A JSON object representing an Artifact.
- *
- * @returns {Artifact} The parsed Artifact.
- */
- static fromJSON(json){
- return Object.assign(new Artifact(), json)
- }
- /**
- * Get the MD5 hash of the artifact. This value may
- * be undefined for artifacts which are not to be
- * validated and updated.
- *
- * @returns {string} The MD5 hash of the Artifact or undefined.
- */
- getHash(){
- return this.MD5
- }
- /**
- * @returns {number} The download size of the artifact.
- */
- getSize(){
- return this.size
- }
- /**
- * @returns {string} The download url of the artifact.
- */
- getURL(){
- return this.url
- }
- /**
- * @returns {string} The artifact's destination path.
- */
- getPath(){
- return this.path
- }
- }
- exports.Artifact
- /**
- * Represents a the requirement status
- * of a module.
- */
- class Required {
-
- /**
- * Parse a JSON object into a Required object.
- *
- * @param {Object} json A JSON object representing a Required object.
- *
- * @returns {Required} The parsed Required object.
- */
- static fromJSON(json){
- if(json == null){
- return new Required(true, true)
- } else {
- return new Required(json.value == null ? true : json.value, json.def == null ? true : json.def)
- }
- }
- constructor(value, def){
- this.value = value
- this.default = def
- }
- /**
- * Get the default value for a required object. If a module
- * is not required, this value determines whether or not
- * it is enabled by default.
- *
- * @returns {boolean} The default enabled value.
- */
- isDefault(){
- return this.default
- }
- /**
- * @returns {boolean} Whether or not the module is required.
- */
- isRequired(){
- return this.value
- }
- }
- exports.Required
- /**
- * Represents a module.
- */
- class Module {
- /**
- * Parse a JSON object into a Module.
- *
- * @param {Object} json A JSON object representing a Module.
- * @param {string} serverid The ID of the server to which this module belongs.
- *
- * @returns {Module} The parsed Module.
- */
- static fromJSON(json, serverid){
- return new Module(json.id, json.name, json.type, json.required, json.artifact, json.subModules, serverid)
- }
- /**
- * Resolve the default extension for a specific module type.
- *
- * @param {string} type The type of the module.
- *
- * @return {string} The default extension for the given type.
- */
- static _resolveDefaultExtension(type){
- switch (type) {
- case exports.Types.Library:
- case exports.Types.ForgeHosted:
- case exports.Types.LiteLoader:
- case exports.Types.ForgeMod:
- return 'jar'
- case exports.Types.LiteMod:
- return 'litemod'
- case exports.Types.File:
- default:
- return 'jar' // There is no default extension really.
- }
- }
- constructor(id, name, type, required, artifact, subModules, serverid) {
- this.identifier = id
- this.type = type
- this._resolveMetaData()
- this.name = name
- this.required = Required.fromJSON(required)
- this.artifact = Artifact.fromJSON(artifact)
- this._resolveArtifactPath(artifact.path, serverid)
- this._resolveSubModules(subModules, serverid)
- }
- _resolveMetaData(){
- try {
- const m0 = this.identifier.split('@')
- this.artifactExt = m0[1] || Module._resolveDefaultExtension(this.type)
- const m1 = m0[0].split(':')
- this.artifactClassifier = m1[3] || undefined
- this.artifactVersion = m1[2] || '???'
- this.artifactID = m1[1] || '???'
- this.artifactGroup = m1[0] || '???'
- } catch (err) {
- // Improper identifier
- logger.error('Improper ID for module', this.identifier, err)
- }
- }
- _resolveArtifactPath(artifactPath, serverid){
- const pth = artifactPath == null ? path.join(...this.getGroup().split('.'), this.getID(), this.getVersion(), `${this.getID()}-${this.getVersion()}${this.artifactClassifier != undefined ? `-${this.artifactClassifier}` : ''}.${this.getExtension()}`) : artifactPath
- switch (this.type){
- case exports.Types.Library:
- case exports.Types.ForgeHosted:
- case exports.Types.LiteLoader:
- this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'libraries', pth)
- break
- case exports.Types.ForgeMod:
- case exports.Types.LiteMod:
- this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'modstore', pth)
- break
- case exports.Types.VersionManifest:
- this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'versions', this.getIdentifier(), `${this.getIdentifier()}.json`)
- break
- case exports.Types.File:
- default:
- this.artifact.path = path.join(ConfigManager.getInstanceDirectory(), serverid, pth)
- break
- }
- }
- _resolveSubModules(json, serverid){
- const arr = []
- if(json != null){
- for(let sm of json){
- arr.push(Module.fromJSON(sm, serverid))
- }
- }
- this.subModules = arr.length > 0 ? arr : null
- }
- /**
- * @returns {string} The full, unparsed module identifier.
- */
- getIdentifier(){
- return this.identifier
- }
- /**
- * @returns {string} The name of the module.
- */
- getName(){
- return this.name
- }
- /**
- * @returns {Required} The required object declared by this module.
- */
- getRequired(){
- return this.required
- }
- /**
- * @returns {Artifact} The artifact declared by this module.
- */
- getArtifact(){
- return this.artifact
- }
- /**
- * @returns {string} The maven identifier of this module's artifact.
- */
- getID(){
- return this.artifactID
- }
- /**
- * @returns {string} The maven group of this module's artifact.
- */
- getGroup(){
- return this.artifactGroup
- }
- /**
- * @returns {string} The identifier without he version or extension.
- */
- getVersionlessID(){
- return this.getGroup() + ':' + this.getID()
- }
- /**
- * @returns {string} The identifier without the extension.
- */
- getExtensionlessID(){
- return this.getIdentifier().split('@')[0]
- }
- /**
- * @returns {string} The version of this module's artifact.
- */
- getVersion(){
- return this.artifactVersion
- }
- /**
- * @returns {string} The classifier of this module's artifact
- */
- getClassifier(){
- return this.artifactClassifier
- }
- /**
- * @returns {string} The extension of this module's artifact.
- */
- getExtension(){
- return this.artifactExt
- }
- /**
- * @returns {boolean} Whether or not this module has sub modules.
- */
- hasSubModules(){
- return this.subModules != null
- }
- /**
- * @returns {Array.<Module>} An array of sub modules.
- */
- getSubModules(){
- return this.subModules
- }
- /**
- * @returns {string} The type of the module.
- */
- getType(){
- return this.type
- }
- }
- exports.Module
- /**
- * Represents a server configuration.
- */
- class Server {
- /**
- * Parse a JSON object into a Server.
- *
- * @param {Object} json A JSON object representing a Server.
- *
- * @returns {Server} The parsed Server object.
- */
- static fromJSON(json){
- const mdls = json.modules
- json.modules = []
- const serv = Object.assign(new Server(), json)
- serv._resolveModules(mdls)
- return serv
- }
- _resolveModules(json){
- const arr = []
- for(let m of json){
- arr.push(Module.fromJSON(m, this.getID()))
- }
- this.modules = arr
- }
- /**
- * @returns {string} The ID of the server.
- */
- getID(){
- return this.id
- }
- /**
- * @returns {string} The name of the server.
- */
- getName(){
- return this.name
- }
- /**
- * @returns {string} The description of the server.
- */
- getDescription(){
- return this.description
- }
- /**
- * @returns {string} The URL of the server's icon.
- */
- getIcon(){
- return this.icon
- }
- /**
- * @returns {string} The version of the server configuration.
- */
- getVersion(){
- return this.version
- }
- /**
- * @returns {string} The IP address of the server.
- */
- getAddress(){
- return this.address
- }
- /**
- * @returns {string} The minecraft version of the server.
- */
- getMinecraftVersion(){
- return this.minecraftVersion
- }
- /**
- * @returns {boolean} Whether or not this server is the main
- * server. The main server is selected by the launcher when
- * no valid server is selected.
- */
- isMainServer(){
- return this.mainServer
- }
- /**
- * @returns {boolean} Whether or not the server is autoconnect.
- * by default.
- */
- isAutoConnect(){
- return this.autoconnect
- }
- /**
- * @returns {Array.<Module>} An array of modules for this server.
- */
- getModules(){
- return this.modules
- }
- }
- exports.Server
- /**
- * Represents the Distribution Index.
- */
- class DistroIndex {
- /**
- * Parse a JSON object into a DistroIndex.
- *
- * @param {Object} json A JSON object representing a DistroIndex.
- *
- * @returns {DistroIndex} The parsed Server object.
- */
- static fromJSON(json){
- const servers = json.servers
- json.servers = []
- const distro = Object.assign(new DistroIndex(), json)
- distro._resolveServers(servers)
- distro._resolveMainServer()
- return distro
- }
- _resolveServers(json){
- const arr = []
- for(let s of json){
- arr.push(Server.fromJSON(s))
- }
- this.servers = arr
- }
- _resolveMainServer(){
- for(let serv of this.servers){
- if(serv.mainServer){
- this.mainServer = serv.id
- return
- }
- }
- // If no server declares default_selected, default to the first one declared.
- this.mainServer = (this.servers.length > 0) ? this.servers[0].getID() : null
- }
- /**
- * @returns {string} The version of the distribution index.
- */
- getVersion(){
- return this.version
- }
- /**
- * @returns {string} The URL to the news RSS feed.
- */
- getRSS(){
- return this.rss
- }
- /**
- * @returns {Array.<Server>} An array of declared server configurations.
- */
- getServers(){
- return this.servers
- }
- /**
- * Get a server configuration by its ID. If it does not
- * exist, null will be returned.
- *
- * @param {string} id The ID of the server.
- *
- * @returns {Server} The server configuration with the given ID or null.
- */
- getServer(id){
- for(let serv of this.servers){
- if(serv.id === id){
- return serv
- }
- }
- return null
- }
- /**
- * Get the main server.
- *
- * @returns {Server} The main server.
- */
- getMainServer(){
- return this.mainServer != null ? this.getServer(this.mainServer) : null
- }
- }
- exports.DistroIndex
- exports.Types = {
- Library: 'Library',
- ForgeHosted: 'ForgeHosted',
- Forge: 'Forge', // Unimplemented
- LiteLoader: 'LiteLoader',
- ForgeMod: 'ForgeMod',
- LiteMod: 'LiteMod',
- File: 'File',
- VersionManifest: 'VersionManifest'
- }
- let DEV_MODE = false
- const DISTRO_PATH = path.join(ConfigManager.getLauncherDirectory(), 'distribution.json')
- const DEV_PATH = path.join(ConfigManager.getLauncherDirectory(), 'dev_distribution.json')
- let data = null
- /**
- * @returns {Promise.<DistroIndex>}
- */
- exports.pullRemote = function(){
- if(DEV_MODE){
- return exports.pullLocal()
- }
- return new Promise((resolve, reject) => {
- const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json'
- //const distroURL = 'https://gist.githubusercontent.com/dscalzi/53b1ba7a11d26a5c353f9d5ae484b71b/raw/'
- const opts = {
- url: distroURL,
- timeout: 2500
- }
- const distroDest = path.join(ConfigManager.getLauncherDirectory(), 'distribution.json')
- request(opts, (error, resp, body) => {
- if(!error){
-
- try {
- data = DistroIndex.fromJSON(JSON.parse(body))
- } catch (e) {
- reject(e)
- }
- fs.writeFile(distroDest, body, 'utf-8', (err) => {
- if(!err){
- resolve(data)
- } else {
- reject(err)
- }
- })
- } else {
- reject(error)
- }
- })
- })
- }
- /**
- * @returns {Promise.<DistroIndex>}
- */
- exports.pullLocal = function(){
- return new Promise((resolve, reject) => {
- fs.readFile(DEV_MODE ? DEV_PATH : DISTRO_PATH, 'utf-8', (err, d) => {
- if(!err){
- data = DistroIndex.fromJSON(JSON.parse(d))
- resolve(data)
- } else {
- reject(err)
- }
- })
- })
- }
- exports.setDevMode = function(value){
- if(value){
- logger.log('Developer mode enabled.')
- logger.log('If you don\'t know what that means, revert immediately.')
- } else {
- logger.log('Developer mode disabled.')
- }
- DEV_MODE = value
- }
- exports.isDevMode = function(){
- return DEV_MODE
- }
- /**
- * @returns {DistroIndex}
- */
- exports.getDistribution = function(){
- return data
- }
|