hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-29 02:17:12 +0200
committerhachem <im@hachem.wtf>2026-08-29 02:17:12 +0200
commite56d21fa04450d118f76347a96a12d1d5477958f (patch)
tree06d590ef64153e2ab92306a4a7cc63d6fef47286 /cli
parent43d92fd60d75c4a1260757c75b1e1eefc0ea8952 (diff)
setup: prepare go workspace
Diffstat (limited to 'cli')
-rw-r--r--cli/app.js138
-rw-r--r--cli/commands/check.js81
-rw-r--r--cli/commands/clean.js80
-rw-r--r--cli/commands/generate.js237
-rw-r--r--cli/commands/list.js15
-rw-r--r--cli/commands/merge.js156
6 files changed, 0 insertions, 707 deletions
diff --git a/cli/app.js b/cli/app.js
deleted file mode 100644
index 1252358..0000000
--- a/cli/app.js
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/usr/bin/env node
-
-const readline = require("readline")
-
-const { LoadConfig } = require("../lib/config")
-
-const { Check } = require("./commands/check")
-const { Generate } = require("./commands/generate")
-const { Merge } = require("./commands/merge")
-const { CleanGenerated, CleanLatest, CleanAll } = require("./commands/clean")
-const { ListMods } = require("./commands/list")
-
-const pkg = require("../package.json")
-const config = LoadConfig()
-const { minecraft_version } = config
-
-const ShowHelp = () =>
-{
- console.log(`
- Commands:
-
- list-mods List configured mods
- check Check if all mods are compatible before generating
- generate Download mods + server, run to generate files
- merge Backup server, move generated files to server location
- clean generated Remove server directory
- clean latest Remove latest backup zip
- clean all Remove both generated and latest backup
- help Show this help
- exit Exit
-`)
-}
-
-const ProcessCommand = async (input, rl) =>
-{
- const parts = input.trim().toLowerCase().split(/\s+/)
- const cmd = parts[0]
- const arg = parts[1]
-
- switch (cmd)
- {
- case "list-mods":
- ListMods()
- break
-
- case "check":
- await Check()
- break
-
- case "generate":
- await Generate(rl)
- break
-
- case "merge":
- await Merge()
- break
-
- case "clean":
- if (arg === "generated")
- await CleanGenerated()
- else if (arg === "latest")
- await CleanLatest()
- else if (arg === "all")
- await CleanAll()
- else
- console.log(" Usage: clean generated | clean latest | clean all")
- break
-
- case "help":
- case "?":
- ShowHelp()
- break
-
- case "exit":
- case "quit":
- case "q":
- console.log(" Goodbye!\n")
- process.exit(0)
-
- case "":
- break
-
- default:
- console.log(` Unknown command: ${cmd}. Type 'help' for commands.`)
- }
-}
-
-const DrawBox = (lines) =>
-{
- const maxLen = Math.max(...lines.map(l => l.length))
- const pad = (str) => str + " ".repeat(maxLen - str.length)
-
- const top = "╔" + "═".repeat(maxLen + 2) + "╗"
- const bot = "╚" + "═".repeat(maxLen + 2) + "╝"
- const mid = lines.map(l => "║ " + pad(l) + " ║").join("\n ")
-
- return ` ${top}\n ${mid}\n ${bot}`
-}
-
-const Main = () =>
-{
- const title = `BENSON CLI v${pkg.version}`
- const subtitle = `Fabric Server for MC ${minecraft_version}`
-
- const box = DrawBox([title, subtitle])
-
- console.log(`
-${box}
-
- Type 'help' for commands.
-`)
-
- const rl = readline.createInterface
- ({
- input: process.stdin,
- output: process.stdout
- })
-
- const Prompt = () =>
- {
- rl.question("benson> ", async (input) =>
- {
- await ProcessCommand(input, rl)
- Prompt()
- })
- }
-
- rl.on("close", () =>
- {
- console.log("\n Goodbye!\n")
- process.exit(0)
- })
-
- Prompt()
-}
-
-Main()
-
diff --git a/cli/commands/check.js b/cli/commands/check.js
deleted file mode 100644
index f91b710..0000000
--- a/cli/commands/check.js
+++ /dev/null
@@ -1,81 +0,0 @@
-const { LoadConfig } = require("../../lib/config")
-const { GetModVersions, GetCompatibleVersion } = require("../../lib/modrinth")
-
-const config = LoadConfig()
-const { minecraft_version, modrinth_mods } = config
-
-const Check = async () =>
-{
- console.log(`\n Checking mod compatibility for MC ${minecraft_version} (Fabric)...\n`)
-
- const compatible = []
- const incompatible = []
- const failed = []
-
- for (const slug of modrinth_mods)
- {
- try
- {
- const versions = await GetModVersions(slug)
- if (!versions)
- {
- failed.push(slug)
- continue
- }
-
- const match = GetCompatibleVersion(versions, minecraft_version, "fabric")
- if (match)
- {
- const filename = match.files[0]?.filename || match.version_number
- compatible.push({ slug, version: filename })
- }
- else
- {
- incompatible.push(slug)
- }
- }
- catch (err)
- {
- failed.push(slug)
- }
- }
-
- // Display results
- if (compatible.length)
- {
- console.log(" [OK] Compatible:")
- for (const { slug, version } of compatible)
- console.log(` ${slug} -> ${version}`)
- console.log("")
- }
-
- if (incompatible.length)
- {
- console.log(" [FAIL] No compatible version:")
- for (const slug of incompatible)
- console.log(` ${slug}`)
- console.log("")
- }
-
- if (failed.length)
- {
- console.log(" [WARN] Failed to check:")
- for (const slug of failed)
- console.log(` ${slug}`)
- console.log("")
- }
-
- // Summary
- const total = modrinth_mods.length
- const ok = compatible.length
-
- console.log(` Summary: ${ok}/${total} mods compatible\n`)
-
- if (incompatible.length === 0 && failed.length === 0)
- console.log(" [OK] Safe to generate!\n")
- else
- console.log(" [FAIL] Not all mods are compatible. Generate may have issues.\n")
-}
-
-module.exports = { Check }
-
diff --git a/cli/commands/clean.js b/cli/commands/clean.js
deleted file mode 100644
index 99a96f6..0000000
--- a/cli/commands/clean.js
+++ /dev/null
@@ -1,80 +0,0 @@
-const fs = require("fs-extra")
-const path = require("path")
-
-const { LoadConfig } = require("../../lib/config")
-const { serverDir } = require("./generate")
-
-const config = LoadConfig()
-const { backup_location } = config
-
-const CleanGenerated = async () =>
-{
- try
- {
- if (await fs.pathExists(serverDir))
- {
- await fs.remove(serverDir)
- console.log(" Removed server directory.")
- }
- else
- {
- console.log(" Server directory doesn't exist.")
- }
- }
- catch (err)
- {
- console.error(" Failed to remove server directory:", err.message)
- }
-}
-
-const CleanLatest = async () =>
-{
- if (!backup_location)
- {
- console.log(" Error: backup_location must be set in config.")
- return
- }
-
- if (!await fs.pathExists(backup_location))
- {
- console.log(" Backup directory doesn't exist.")
- return
- }
-
- try
- {
- const files = await fs.readdir(backup_location)
- const zipFiles = files
- .filter(f => f.startsWith("backup_") && f.endsWith(".zip"))
- .sort()
- .reverse()
-
- if (zipFiles.length === 0)
- {
- console.log(" No backup files found.")
- return
- }
-
- const latestZip = zipFiles[0]
- const latestPath = path.join(backup_location, latestZip)
-
- await fs.remove(latestPath)
- console.log(` Removed latest backup: ${latestZip}`)
- }
- catch (err)
- {
- console.error(" Failed to remove latest backup:", err.message)
- }
-}
-
-const CleanAll = async () =>
-{
- console.log(" Cleaning generated files...")
- await CleanGenerated()
- console.log("")
- console.log(" Cleaning latest backup...")
- await CleanLatest()
-}
-
-module.exports = { CleanGenerated, CleanLatest, CleanAll }
-
diff --git a/cli/commands/generate.js b/cli/commands/generate.js
deleted file mode 100644
index 183810d..0000000
--- a/cli/commands/generate.js
+++ /dev/null
@@ -1,237 +0,0 @@
-const fs = require("fs-extra")
-const path = require("path")
-const { spawn } = require("child_process")
-
-const { LoadConfig } = require("../../lib/config")
-const { GetModVersions, GetCompatibleVersion, DownloadFile } = require("../../lib/modrinth")
-
-const config = LoadConfig()
-
-const
-{
- minecraft_version,
- fabric_loader_version,
- loader_meta_version,
- java_path,
- modrinth_mods
-} = config
-
-const javaCmd = java_path || "java"
-
-const serverDir = path.join(__dirname, "../../server")
-const modsDir = path.join(serverDir, "mods")
-
-const deleteList =
-[
- "audioplayer_uploads",
- "config",
- "cache",
- "world",
- "logs",
- "banned-players.json",
- "server.properties",
- "banned-ips.json",
- "usercache.json",
- "whitelist.json",
- "ops.json",
- "eula.txt"
-]
-
-const EnsureDirs = async () =>
-{
- await fs.ensureDir(serverDir)
- await fs.ensureDir(modsDir)
-}
-
-const DownloadModrinthMods = async (modList, mcVersion) =>
-{
- const downloadedFiles = []
- const failedMods = []
-
- for (const slug of modList)
- {
- try
- {
- const versions = await GetModVersions(slug)
- if (!versions)
- {
- console.log(` [Modrinth] Could not get versions for ${slug}`)
- failedMods.push(slug)
- continue
- }
-
- const compatible = GetCompatibleVersion(versions, mcVersion, "fabric")
- if (!compatible)
- {
- console.log(` [Modrinth] No Fabric version for ${slug} on MC ${mcVersion}`)
- failedMods.push(slug)
- continue
- }
-
- const fileInfo = compatible.files[0]
- const jarUrl = fileInfo.url
- const filename = fileInfo.filename
- const destPath = path.join(modsDir, filename)
-
- console.log(` [Modrinth] Downloading ${slug} -> ${filename} ...`)
-
- const success = await DownloadFile(jarUrl, destPath)
- if (!success)
- {
- console.log(` [Modrinth] Couldn't download jar for ${slug}`)
- failedMods.push(slug)
- continue
- }
-
- downloadedFiles.push(destPath)
- console.log(` [Modrinth] Downloaded: ${filename}`)
- }
- catch (err)
- {
- console.error(` [Modrinth] Error downloading ${slug}:`, err.message)
- failedMods.push(slug)
- }
- }
-
- return { downloadedFiles, failedMods }
-}
-
-const DownloadFabricServer = async (mcVersion, loaderVersion, metaVersion) =>
-{
- const url = `https://meta.fabricmc.net/v2/versions/loader/${mcVersion}/${loaderVersion}/${metaVersion}/server/jar`
- const filename = "server.jar"
- const destPath = path.join(serverDir, filename)
-
- console.log(` [Fabric] Downloading Fabric server for MC ${mcVersion} ...`)
-
- const success = await DownloadFile(url, destPath)
- if (!success)
- {
- console.log(` [Fabric] Failed to download Fabric server JAR`)
- return null
- }
-
- console.log(` [Fabric] Downloaded: ${filename}`)
- return destPath
-}
-
-const RunServerAutoStop = (rl) =>
-{
- return new Promise((resolve) =>
- {
- const jarPath = path.join(serverDir, "server.jar")
-
- if (!fs.existsSync(jarPath))
- {
- console.log(" Server JAR not found.")
- resolve(false)
- return
- }
-
- const eulaPath = path.join(serverDir, "eula.txt")
- if (!fs.existsSync(eulaPath))
- {
- console.log(" Accepting EULA...")
- fs.writeFileSync(eulaPath, "eula=true\n")
- }
-
- console.log(" Starting server (will auto-stop after loading)...\n")
-
- rl.pause()
-
- let hadError = false
-
- const serverProcess = spawn(javaCmd, ["-jar", "server.jar", "nogui"],
- {
- cwd: serverDir,
- stdio: ["pipe", "pipe", "pipe"]
- })
-
- serverProcess.stdout.on("data", (data) =>
- {
- const line = data.toString()
- process.stdout.write(line)
-
- if (line.includes("Done"))
- {
- console.log("\n Server loaded, stopping...")
- serverProcess.stdin.write("stop\n")
- }
- })
-
- serverProcess.stderr.on("data", (data) =>
- {
- process.stderr.write(data.toString())
- })
-
- serverProcess.on("error", err =>
- {
- hadError = true
- console.error(" Failed to start server:", err.message)
- rl.resume()
- resolve(false)
- })
-
- serverProcess.on("close", () =>
- {
- if (!hadError)
- {
- console.log("\n Server stopped.")
- rl.resume()
- resolve(true)
- }
- })
- })
-}
-
-const DeletePostGenerate = async () =>
-{
- console.log(" Cleaning up server-generated files...")
-
- let removed = 0
- for (const item of deleteList)
- {
- const itemPath = path.join(serverDir, item)
-
- try
- {
- if (await fs.pathExists(itemPath))
- {
- await fs.remove(itemPath)
- removed++
- }
- }
- catch (err)
- {
- console.error(` Failed to remove ${item}:`, err.message)
- }
- }
-
- console.log(` Removed ${removed} items.`)
-}
-
-const Generate = async (rl) =>
-{
- await EnsureDirs()
-
- console.log(`\n Generating server for MC ${minecraft_version}...\n`)
-
- const { downloadedFiles, failedMods } = await DownloadModrinthMods(modrinth_mods, minecraft_version)
- console.log(`\n [OK] Downloaded ${downloadedFiles.length} mods`)
- if (failedMods.length)
- console.log(` [FAIL] Failed: ${failedMods.join(", ")}`)
-
- const serverFile = await DownloadFabricServer(minecraft_version, fabric_loader_version, loader_meta_version)
-
- if (serverFile)
- {
- console.log("")
- await RunServerAutoStop(rl)
- await DeletePostGenerate()
- }
-
- console.log("")
-}
-
-module.exports = { Generate, serverDir }
-
diff --git a/cli/commands/list.js b/cli/commands/list.js
deleted file mode 100644
index 48bb2cf..0000000
--- a/cli/commands/list.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { LoadConfig } = require("../../lib/config")
-
-const config = LoadConfig()
-const { minecraft_version, modrinth_mods } = config
-
-const ListMods = () =>
-{
- console.log(`\n Mods for MC ${minecraft_version}:\n`)
- for (const slug of modrinth_mods)
- console.log(` - ${slug}`)
- console.log(`\n Total: ${modrinth_mods.length} mods\n`)
-}
-
-module.exports = { ListMods }
-
diff --git a/cli/commands/merge.js b/cli/commands/merge.js
deleted file mode 100644
index 138dd54..0000000
--- a/cli/commands/merge.js
+++ /dev/null
@@ -1,156 +0,0 @@
-const fs = require("fs-extra")
-const path = require("path")
-const { spawn } = require("child_process")
-const archiver = require("archiver")
-
-const { LoadConfig } = require("../../lib/config")
-const { serverDir } = require("./generate")
-
-const config = LoadConfig()
-
-const
-{
- server_location,
- backup_location,
- merge_pre_command,
- merge_post_command
-} = config
-
-const RunCommand = (command) =>
-{
- return new Promise((resolve) =>
- {
- console.log(` Running: ${command}`)
-
- const proc = spawn(command, [], { shell: true, stdio: "inherit" })
-
- proc.on("close", (code) =>
- {
- if (code === 0)
- console.log(" Command completed.")
- else
- console.log(` Command exited with code ${code}`)
- resolve(code)
- })
-
- proc.on("error", (err) =>
- {
- console.error(" Command failed:", err.message)
- resolve(1)
- })
- })
-}
-
-const CreateBackup = (sourceDir, backupDir) =>
-{
- return new Promise(async (resolve, reject) =>
- {
- const now = new Date()
- const timestamp = now.toISOString()
- .replace(/[:.]/g, "-")
- .replace("T", "_")
- .slice(0, 19)
-
- const zipName = `backup_${timestamp}.zip`
- const zipPath = path.join(backupDir, zipName)
-
- await fs.ensureDir(backupDir)
-
- const output = fs.createWriteStream(zipPath)
- const archive = archiver("zip", { zlib: { level: 9 } })
-
- output.on("close", () =>
- {
- console.log(` Created backup: ${zipName} (${archive.pointer()} bytes)`)
- resolve(zipPath)
- })
-
- archive.on("error", err => reject(err))
-
- archive.pipe(output)
- archive.directory(sourceDir, false)
- archive.finalize()
- })
-}
-
-const Merge = async () =>
-{
- if (!server_location || !backup_location)
- {
- console.log(" Error: server_location and backup_location must be set in config.")
- return
- }
-
- if (!await fs.pathExists(serverDir))
- {
- console.log(" Error: No generated files found. Run 'generate' first.")
- return
- }
-
- // Run pre-command
- if (merge_pre_command)
- {
- console.log("\n Running pre-merge command...")
- await RunCommand(merge_pre_command)
- console.log("")
- }
-
- // Check if server location exists and back it up
- if (await fs.pathExists(server_location))
- {
- console.log(` Backing up ${server_location}...`)
- try
- {
- await CreateBackup(server_location, backup_location)
- }
- catch (err)
- {
- console.error(" Failed to create backup:", err.message)
- return
- }
- }
- else
- {
- console.log(" Server location doesn't exist, creating it...")
- await fs.ensureDir(server_location)
- }
-
- // Move generated files to server location
- console.log(" Moving generated files to server location...")
- try
- {
- const items = await fs.readdir(serverDir)
- for (const item of items)
- {
- const src = path.join(serverDir, item)
- const dest = path.join(server_location, item)
-
- // Remove existing item at destination
- if (await fs.pathExists(dest))
- await fs.remove(dest)
-
- await fs.move(src, dest)
- console.log(` Moved: ${item}`)
- }
-
- // Remove the now-empty server directory
- await fs.remove(serverDir)
-
- console.log(" Merge complete!")
- }
- catch (err)
- {
- console.error(" Failed to move files:", err.message)
- return
- }
-
- // Run post-command
- if (merge_post_command)
- {
- console.log("\n Running post-merge command...")
- await RunCommand(merge_post_command)
- }
-}
-
-module.exports = { Merge }
-