diff --git a/src/curse.ts b/src/curse.ts index f06361a..af3f6a1 100644 --- a/src/curse.ts +++ b/src/curse.ts @@ -1,5 +1,6 @@ import { https } from "follow-redirects"; import fs from "fs"; +import {modBase, config} from "./modBase"; interface modLockElement { fileId: number; url: string; @@ -10,111 +11,111 @@ interface Dependency { readonly addonId: number; readonly type: number; } -let mods_lock: modLockMap; -let downloadStarted: boolean = false; -let globCallback; -let config; -let dep: modLockMap = new Map(); -function main() { - mods_lock = new Map(Object.entries(mods_lock)); - if(config.mods.curse.length === 0) globCallback("curse", {}); - config.mods.curse.forEach((mod: string) => { - getData(`search?categoryId=0&gameId=432&gameVersion=${encodeURI(config.gameVersion)}&index=0&pageSize=15&searchFilter=${encodeURI(mod)}§ionId=6&sort=0`, (result: Array) => { // resolve projectID - let i = 0; - while(result[i].name !== mod) { - ++i; - if(i === result.length) { - console.log(`cursemod ${mod} not found`); - return; +class curse extends modBase { + private dep: modLockMap = new Map(); + private downloadStarted: boolean = false; + constructor(private modsLock: modLockMap, config: config, callback: Function) { + super(config, callback); + if(config.mods.curse.length === 0) callback("curse", {}); + config.mods.curse.forEach((mod: string) => { + this.getData(`search?categoryId=0&gameId=432&gameVersion=${encodeURI(config.gameVersion)}&index=0&pageSize=15&searchFilter=${encodeURI(mod)}§ionId=6&sort=0`, (result: Array) => { // resolve projectID + let i = 0; + while(result[i].name !== mod) { + ++i; + if(i === result.length) { + console.log(`cursemod ${mod} not found`); + return; + } + } + this.resolveDep(result[i].id, () => { + this.downloadMods(); + }); + }); + }); + } + + private resolveDepRecursionCount = 0; + private resolveDep(modId: number, callback: Function):void { + ++this.resolveDepRecursionCount; + this.getData(`${modId}/files`, (files: Array) => { + let rightVersion; + for(let i = files.length - 1; i >= 0; --i) { + let versionArray = files[i].gameVersion; + if(this.versionMatch(versionArray, this.config.gameVersion) && (this.versionMatch(versionArray, this.config.modloader) || this.modloaderMatch(versionArray, this.config.modloader))) { + rightVersion = files[i]; } } - resolveDep(result[i].id, downloadMods); - }); - }); -} - -var resolveDepRecursionCount = 0; -function resolveDep(modId: number, callback: Function) { - ++resolveDepRecursionCount; - getData(`${modId}/files`, (files: Array) => { - let rightVersion: any; - for(let i = files.length - 1; i >= 0; --i) { - let versionArray = files[i].gameVersion; - if(versionMatch(versionArray, config.gameVersion) && (versionMatch(versionArray, config.modloader) || modloaderMatch(versionArray, config.modloader))) { - rightVersion = files[i]; + if(rightVersion === undefined) { + this.getData(String(modId), (mod: any) => { + console.log(`cursemod ${mod.name}: no version for the correct minecraft version and modloader found`); + }); + return; } - } - if(rightVersion === undefined) { - getData(String(modId), (mod: any) => { - console.log(`cursemod ${mod.name}: no version for the correct minecraft version and modloader found`); + this.dep.set(String(modId), {fileId: rightVersion.id, url: rightVersion.downloadUrl, filename: rightVersion.fileName}); + rightVersion.dependencies.forEach((mod: Dependency) => { + if(mod.type !== 3) return; + this.resolveDep(mod.addonId, callback); }); - return; - } - dep.set(String(modId), {fileId: rightVersion.id, url: rightVersion.downloadUrl, filename: rightVersion.fileName}); - rightVersion.dependencies.forEach((mod: Dependency) => { - if(mod.type !== 3) return; - resolveDep(mod.addonId, callback); + --this.resolveDepRecursionCount; + if(this.resolveDepRecursionCount == 0) callback(); }); - --resolveDepRecursionCount; - if(resolveDepRecursionCount == 0) callback(); - }); -} + } -function getData(url: string, callback: Function) { - https.get(`https://addons-ecs.forgesvc.net/api/v2/addon/${url}`, (resp) => { - let data: string = ''; + private getData(url: string, callback: Function):void { + https.get(`https://addons-ecs.forgesvc.net/api/v2/addon/${url}`, (resp) => { + let data: string = ''; resp.on('data', (chunk) => { data += chunk; }); resp.on("end", () => { callback(JSON.parse(data)); }); - }); -} - -function versionMatch(versionArray, gameVersion) { - let gameVersionMatch = false; - versionArray.forEach(version => { - gameVersionMatch = gameVersionMatch || version == gameVersion; - }); - return gameVersionMatch; -} - -function modloaderMatch(versionArray, modloaderVersion) { - for(let i = 0; i < versionArray.length; ++i) { - if(/^[a-zA-Z]+$/.test(versionArray[i]) && versionArray[i] != modloaderVersion) return false; - } - return true; -} - -function downloadMods() { - if(!downloadStarted) { - downloadStarted = true; - globCallback("curse", Object.fromEntries(dep)); - dep.forEach((mod: modLockElement, modId: string) => { - let path = modPath(mod) - if(mods_lock.has(modId)) { - if(mods_lock.get(modId)!.fileId === mod.fileId) return; - fs.unlink(path, () => {}); - } - downloadFile(mod.url, path); - }); - mods_lock.forEach((mod: modLockElement, modId: string) => { - if(!dep.has(modId)) fs.unlink(modPath(mod), () => {}) }); } -} -function downloadFile(url: string, dest: string) { - let file = fs.createWriteStream(dest); - console.log(`downloading ${url}`); - let request = https.get(url, (response) => { - // check if response is success - if (response.statusCode !== 200) { - throw response.statusCode; + versionMatch(versionArray, gameVersion):boolean { + let gameVersionMatch = false; + versionArray.forEach(version => { + gameVersionMatch = gameVersionMatch || version == gameVersion; + }); + return gameVersionMatch; + } + + private modloaderMatch(versionArray: Array, modloaderVersion: string):boolean { + for(let i = 0; i < versionArray.length; ++i) { + if(/^[a-zA-Z]+$/.test(versionArray[i]) && versionArray[i] != modloaderVersion) return false; } + return true; + } - response.pipe(file); + private downloadMods():void { + if(!this.downloadStarted) { + this.downloadStarted = true; + this.callback("curse", Object.fromEntries(this.dep)); + this.dep.forEach((mod: modLockElement, modId: string) => { + let path = this.modPath(mod) + if(this.modsLock.has(modId)) { + if(this.modsLock.get(modId)!.fileId === mod.fileId) return; + fs.unlink(path, () => {}); + } + this.downloadFile(mod.url, path); + }); + this.modsLock.forEach((mod: modLockElement, modId: string) => { + if(!this.dep.has(modId)) fs.unlink(this.modPath(mod), () => {}) + }); + } + } + + private downloadFile(url: string, dest: string):void { + let file = fs.createWriteStream(dest); + console.log(`downloading ${url}`); + let request = https.get(url, (response) => { + // check if response is success + if (response.statusCode !== 200) { + throw response.statusCode; + } + + response.pipe(file); }); // close() is async, call cb after close completes @@ -131,10 +132,6 @@ function downloadFile(url: string, dest: string) { throw err; }); } +} -module.exports = function(mods_lock_p, _config, callback) { - mods_lock = mods_lock_p; - globCallback = callback; - config = _config; - main(); -}; +export = curse; diff --git a/src/git.ts b/src/git.ts index d861726..bf5db87 100644 --- a/src/git.ts +++ b/src/git.ts @@ -2,6 +2,7 @@ import git from "gift"; import childProcess from "child_process"; import fs from "fs"; import g2js from "gradle-to-js/lib/parser"; +import {modBase, config} from "./modBase"; interface modLockElement { commitId: string; url: string; @@ -11,91 +12,84 @@ type modLockMap = Map; interface commit { id: string; } -let modsLock: modLockMap; -let globCallback: Function; -let loopCounter: number = 0; -let config; -function main () { - modsLock = new Map(Object.entries(modsLock)); - let deleteMods: modLockMap = new Map(modsLock); - let cacheDir = process.env.XDG_CACHE_HOME; - if(cacheDir == null) cacheDir = `${process.env.HOME}/.cache`; - let repoPathRoot = `${cacheDir}/minecraft-mod-packager`; - config.mods.git.forEach((gitRepo) => { - ++loopCounter; - deleteMods.delete(gitRepo.url); - let repoPath = `${repoPathRoot}/${gitRepo.url.replace("://", "+")}/${gitRepo.branch}`; - fs.access(repoPath, (err) => { - if(err) { - if(err.code !== "ENOENT") throw err; - console.log(`cloning git repo ${gitRepo.url}`); - git.clone(gitRepo.url, repoPath, undefined, gitRepo.branch, (err: Error, repo) => { - if(err) throw err; - build(repo, repoPath, gitRepo); - }); - } - else { - let repo = git(repoPath); - console.log(`pulling git repo ${gitRepo.url}`); - repo.pull(["origin"], gitRepo.branch, (err: Error) => { - if(err) throw err; - build(repo, repoPath, gitRepo); - }); - } +class gitMods extends modBase { + private loopCounter: number = 0; + constructor(private modsLock: modLockMap, config: config, callback: Function) { + super(config, callback); + let deleteMods: modLockMap = new Map(this.modsLock); + let cacheDir = process.env.XDG_CACHE_HOME; + if(cacheDir == null) cacheDir = `${process.env.HOME}/.cache`; + let repoPathRoot = `${cacheDir}/minecraft-mod-packager`; + config.mods.git.forEach((gitRepo) => { + ++this.loopCounter; + deleteMods.delete(gitRepo.url); + let repoPath = `${repoPathRoot}/${gitRepo.url.replace("://", "+")}/${gitRepo.branch}`; + fs.access(repoPath, (err) => { + if(err) { + if(err.code !== "ENOENT") throw err; + console.log(`cloning git repo ${gitRepo.url}`); + git.clone(gitRepo.url, repoPath, undefined, gitRepo.branch, (err: Error, repo) => { + if(err) throw err; + this.build(repo, repoPath, gitRepo); + }); + } + else { + let repo = git(repoPath); + console.log(`pulling git repo ${gitRepo.url}`); + repo.pull(["origin"], gitRepo.branch, (err: Error) => { + if(err) throw err; + this.build(repo, repoPath, gitRepo); + }); + } + }); }); - }); - deleteMods.forEach((mod, url) => { - modsLock.delete(url); - fs.unlink(modPath(mod), (err) => { - if(err) throw err; - }); - }); - mayCb(); -} - -function build(repo, repoPath, gitRepo):void { - let newLock: modLockElement; - newLock = modsLock.get(gitRepo.url) ?? {} as modLockElement; - modsLock.set(gitRepo.url, newLock); - repo.current_commit((err: Error, commit: commit) => { - if(err) throw err; - if(commit.id === newLock.commitId) cbDecrease(); - else { - newLock.commitId = commit.id; - console.log(`buidling ${gitRepo.url}`); - childProcess.execFile("gradle", ["build"], {cwd: repoPath}, (err) => { + deleteMods.forEach((mod, url) => { + this.modsLock.delete(url); + fs.unlink(this.modPath(mod), (err) => { if(err) throw err; - let buildPath = `${repoPath}/build/libs`; - fs.readFile(`${repoPath}/gradle.properties`, "utf-8", (err, data) => { + }); + }); + this.mayCb(); + } + + private build(repo, repoPath, gitRepo):void { + let newLock: modLockElement; + newLock = this.modsLock.get(gitRepo.url) ?? {} as modLockElement; + this.modsLock.set(gitRepo.url, newLock); + repo.current_commit((err: Error, commit: commit) => { + if(err) throw err; + if(commit.id === newLock.commitId) this.cbDecrease(); + else { + newLock.commitId = commit.id; + console.log(`buidling ${gitRepo.url}`); + childProcess.execFile("gradle", ["build"], {cwd: repoPath}, (err) => { if(err) throw err; - g2js.parseText(data).then((gradleProp) => { - if(newLock.filename != null) fs.unlink(modPath(newLock), (err) => { - if(err) throw err; + let buildPath = `${repoPath}/build/libs`; + fs.readFile(`${repoPath}/gradle.properties`, "utf-8", (err, data) => { + if(err) throw err; + g2js.parseText(data).then((gradleProp) => { + if(newLock.filename != null) fs.unlink(this.modPath(newLock), (err) => { + if(err) throw err; + }); + newLock.filename = `${gradleProp.archives_base_name}-${gradleProp.mod_version}.jar`; + fs.copyFile(`${buildPath}/${newLock.filename}`, this.modPath(newLock), (err) => { + if(err) throw err; + }); + this.cbDecrease(); }); - newLock.filename = `${gradleProp.archives_base_name}-${gradleProp.mod_version}.jar`; - fs.copyFile(`${buildPath}/${newLock.filename}`, modPath(newLock), (err) => { - if(err) throw err; - }); - cbDecrease(); }); }); - }); - } - }); -} + } + }); + } -function cbDecrease():void { - --loopCounter; - mayCb(); -} + private cbDecrease():void { + --this.loopCounter; + this.mayCb(); + } -function mayCb():void { - if(loopCounter <= 0) globCallback("git", Object.fromEntries(modsLock)); -} - -module.exports = (mods_lock_p, _config, cb) => { - globCallback = cb; - modsLock = mods_lock_p; - config = _config; - main() + private mayCb():void { + if(this.loopCounter <= 0) this.callback("git", Object.fromEntries(this.modsLock)); + } } +export = gitMods; diff --git a/src/main.js b/src/main.ts similarity index 57% rename from src/main.js rename to src/main.ts index b8df951..0f613dd 100644 --- a/src/main.js +++ b/src/main.ts @@ -1,6 +1,10 @@ -const jsonMinify = require("node-json-minify"); -const fs = require("fs"); -let config; +import jsonMinify from "node-json-minify"; +import fs from "fs"; +import {config} from "./modBase"; +import curse from "./curse"; +import git from "./git"; +let config: config; +let modules = ["curse", "git"]; switch(process.argv.length) { case 3: process.chdir(process.argv[2]); @@ -18,14 +22,14 @@ try { } catch(err) { if(err.errno !== -2) throw err; - modsLock = {curse: {}, git: {}}; + modsLock = {}; } -const numberCallback = 2; +const numberCallback = modules.length; let callbackCounter = 0; -require("./curse")(modsLock.curse, config, finnish); -require("./git.js")(modsLock.git, config, finnish); +new git(new Map(Object.entries(modsLock.git ?? {})), config, finnish); +new curse(new Map(Object.entries(modsLock.curse ?? {})), config, finnish); -function finnish(name, data) { +function finnish(name: string, data) { save_mods_lock[name] = data; if(++callbackCounter == numberCallback) { fs.writeFile(modLockPath, JSON.stringify(save_mods_lock), (err) => { diff --git a/src/modBase.ts b/src/modBase.ts new file mode 100644 index 0000000..92a3508 --- /dev/null +++ b/src/modBase.ts @@ -0,0 +1,18 @@ +export interface config { + gameVersion: string; + modloader: string; + mods: { + curse: Array; + git: Array<{ + url: string; + branch: string; + }> + } +} +export class modBase { + constructor(protected config: config, protected callback: Function) { + } + protected modPath(mod: any) { + return `mods/${mod.filename}`; + } +} diff --git a/src/util.ts b/src/util.ts deleted file mode 100644 index 21fca4a..0000000 --- a/src/util.ts +++ /dev/null @@ -1,3 +0,0 @@ -function modPath(mod: any) { - return `mods/${mod.filename}`; -}