mirror of
https://github.com/ragestudio/relic.git
synced 2025-06-09 10:34:18 +00:00
support for torrent download
This commit is contained in:
parent
93201a5c19
commit
bd719202c1
@ -16,6 +16,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@foxify/events": "^2.1.0",
|
"@foxify/events": "^2.1.0",
|
||||||
"adm-zip": "^0.5.12",
|
"adm-zip": "^0.5.12",
|
||||||
|
"aria2": "^4.1.2",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"checksum": "^1.0.0",
|
"checksum": "^1.0.0",
|
||||||
"cli-color": "^2.0.4",
|
"cli-color": "^2.0.4",
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
|
import fs from "node:fs"
|
||||||
|
|
||||||
import parseStringVars from "../utils/parseStringVars"
|
import parseStringVars from "../utils/parseStringVars"
|
||||||
//import downloadTorrent from "../helpers/downloadTorrent"
|
import downloadTorrent from "../helpers/downloadTorrent"
|
||||||
|
|
||||||
export default async (pkg, step, logger, abortController) => {
|
export default async (pkg, step, logger, abortController) => {
|
||||||
throw new Error("Not implemented")
|
if (!step.magnet) {
|
||||||
|
throw new Error(`Magnet is required for torrent step`)
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof step.path === "undefined") {
|
if (typeof step.path === "undefined") {
|
||||||
step.path = `.`
|
step.path = `.`
|
||||||
|
@ -10,7 +10,7 @@ import Apply from "../handlers/apply"
|
|||||||
|
|
||||||
const BaseLog = Logger.child({ service: "INSTALLER" })
|
const BaseLog = Logger.child({ service: "INSTALLER" })
|
||||||
|
|
||||||
export default async function install(manifest) {
|
export default async function install(manifest, options = {}) {
|
||||||
let id = null
|
let id = null
|
||||||
let abortController = new AbortController()
|
let abortController = new AbortController()
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ export default async function install(manifest) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(manifest.installSteps)) {
|
if (Array.isArray(manifest.installSteps) && !options.noInstallSteps) {
|
||||||
Log.info(`Executing generic install steps...`)
|
Log.info(`Executing generic install steps...`)
|
||||||
|
|
||||||
global._relic_eventBus.emit(`pkg:update:state`, {
|
global._relic_eventBus.emit(`pkg:update:state`, {
|
||||||
|
@ -2,6 +2,7 @@ import fs from "node:fs"
|
|||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
import cliProgress from "cli-progress"
|
import cliProgress from "cli-progress"
|
||||||
import humanFormat from "human-format"
|
import humanFormat from "human-format"
|
||||||
|
import aria2 from "aria2"
|
||||||
|
|
||||||
function convertSize(size) {
|
function convertSize(size) {
|
||||||
return `${humanFormat(size, {
|
return `${humanFormat(size, {
|
||||||
@ -30,51 +31,46 @@ export default async function downloadTorrent(
|
|||||||
speedString: "0B/s",
|
speedString: "0B/s",
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = new WebTorrent()
|
const client = new aria2({
|
||||||
|
host: 'localhost',
|
||||||
|
port: 6800,
|
||||||
|
secure: false,
|
||||||
|
secret: '',
|
||||||
|
path: '/jsonrpc'
|
||||||
|
})
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
await client.open()
|
||||||
client.add(magnet, (torrentInstance) => {
|
|
||||||
const progressBar = new cliProgress.SingleBar({
|
|
||||||
format: "[{bar}] {percentage}% | {total_formatted} | {speed}/s | {eta_formatted}",
|
|
||||||
barCompleteChar: "\u2588",
|
|
||||||
barIncompleteChar: "\u2591",
|
|
||||||
hideCursor: true
|
|
||||||
}, cliProgress.Presets.shades_classic)
|
|
||||||
|
|
||||||
|
let downloadId = await client.call(
|
||||||
|
"addUri",
|
||||||
|
[magnet],
|
||||||
|
{
|
||||||
|
dir: destination,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
await new Promise(async (resolve, reject) => {
|
||||||
if (typeof onStart === "function") {
|
if (typeof onStart === "function") {
|
||||||
onStart(torrentInstance)
|
onStart()
|
||||||
}
|
}
|
||||||
|
|
||||||
progressBar.start(tickProgress.total, 0, {
|
progressInterval = setInterval(async () => {
|
||||||
speed: "0B/s",
|
const data = await client.call("tellStatus", downloadId)
|
||||||
total_formatted: tickProgress.totalString,
|
const isMetadata = data.totalLength === "0" && data.status === "active"
|
||||||
})
|
|
||||||
|
|
||||||
torrentInstance.on("done", () => {
|
console.log(data)
|
||||||
progressBar.stop()
|
|
||||||
clearInterval(progressInterval)
|
|
||||||
|
|
||||||
if (typeof onDone === "function") {
|
if (data.status === "complete") {
|
||||||
onDone(torrentInstance)
|
if (Array.isArray(data.followedBy) && data.followedBy[0]) {
|
||||||
|
// replace downloadId
|
||||||
|
downloadId = data.followedBy[0]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(torrentInstance)
|
tickProgress.total = parseInt(data.totalLength)
|
||||||
})
|
tickProgress.speed = parseInt(data.downloadSpeed)
|
||||||
|
tickProgress.transferred = parseInt(data.completedLength)
|
||||||
torrentInstance.on("error", (error) => {
|
tickProgress.connections = data.connections
|
||||||
progressBar.stop()
|
|
||||||
clearInterval(progressInterval)
|
|
||||||
|
|
||||||
if (typeof onError === "function") {
|
|
||||||
onError(error)
|
|
||||||
} else {
|
|
||||||
reject(error)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
progressInterval = setInterval(() => {
|
|
||||||
tickProgress.speed = torrentInstance.downloadSpeed
|
|
||||||
tickProgress.transferred = torrentInstance.downloaded
|
|
||||||
|
|
||||||
tickProgress.transferredString = convertSize(tickProgress.transferred)
|
tickProgress.transferredString = convertSize(tickProgress.transferred)
|
||||||
tickProgress.totalString = convertSize(tickProgress.total)
|
tickProgress.totalString = convertSize(tickProgress.total)
|
||||||
@ -83,11 +79,54 @@ export default async function downloadTorrent(
|
|||||||
if (typeof onProgress === "function") {
|
if (typeof onProgress === "function") {
|
||||||
onProgress(tickProgress)
|
onProgress(tickProgress)
|
||||||
}
|
}
|
||||||
|
|
||||||
progressBar.update(tickProgress.transferred, {
|
|
||||||
speed: tickProgress.speedString,
|
|
||||||
})
|
|
||||||
}, 1000)
|
}, 1000)
|
||||||
})
|
|
||||||
})
|
client.on("onDownloadStart", async ([{ gid }]) => {
|
||||||
|
const data = await client.call("tellStatus", gid)
|
||||||
|
|
||||||
|
console.log(data)
|
||||||
|
|
||||||
|
if (typeof data.following !== "undefined") {
|
||||||
|
if (data.following === downloadId) {
|
||||||
|
downloadId = data.gid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
client.on("onBtDownloadComplete", ([{ gid }]) => {
|
||||||
|
if (gid !== downloadId) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
clearInterval(progressInterval)
|
||||||
|
|
||||||
|
if (typeof onDone === "function") {
|
||||||
|
onDone()
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
downloadId,
|
||||||
|
})
|
||||||
|
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
client.on("onDownloadError", ([{ gid }]) => {
|
||||||
|
if (gid !== downloadId) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
clearInterval(progressInterval)
|
||||||
|
|
||||||
|
if (typeof onError === "function") {
|
||||||
|
onError()
|
||||||
|
} else {
|
||||||
|
reject()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
await client.call("remove", downloadId)
|
||||||
|
|
||||||
|
return downloadId
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import { onExit } from "signal-exit"
|
|||||||
import open from "open"
|
import open from "open"
|
||||||
|
|
||||||
import SetupHelper from "./helpers/setup"
|
import SetupHelper from "./helpers/setup"
|
||||||
|
import { execa } from "./libraries/execa"
|
||||||
import Logger from "./logger"
|
import Logger from "./logger"
|
||||||
|
|
||||||
import Settings from "./classes/Settings"
|
import Settings from "./classes/Settings"
|
||||||
@ -49,6 +50,15 @@ export default class RelicCore {
|
|||||||
await Settings.set("packages_path", Vars.packages_path)
|
await Settings.set("packages_path", Vars.packages_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.aria2c_instance = execa(
|
||||||
|
Vars.aria2_bin,
|
||||||
|
["--enable-rpc", "--rpc-listen-all=true", "--rpc-allow-origin-all", "--file-allocation=none"],
|
||||||
|
{
|
||||||
|
stdout: "inherit",
|
||||||
|
stderr: "inherit",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
onExit(this.onExit)
|
onExit(this.onExit)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +66,10 @@ export default class RelicCore {
|
|||||||
if (fs.existsSync(Vars.cache_path)) {
|
if (fs.existsSync(Vars.cache_path)) {
|
||||||
fs.rmSync(Vars.cache_path, { recursive: true, force: true })
|
fs.rmSync(Vars.cache_path, { recursive: true, force: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.aria2c_instance) {
|
||||||
|
this.aria2c_instance.kill("SIGINT")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async setup() {
|
async setup() {
|
||||||
|
34
packages/core/src/manifest/libs/extract/index.js
Normal file
34
packages/core/src/manifest/libs/extract/index.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import extractFile from "../../../utils/extractFile"
|
||||||
|
import { execa } from "../../../libraries/execa"
|
||||||
|
import Vars from "../../../vars"
|
||||||
|
|
||||||
|
export default class Extract {
|
||||||
|
async extractFull(file, dest, { password } = {}) {
|
||||||
|
const args = [
|
||||||
|
"x",
|
||||||
|
"-y",
|
||||||
|
]
|
||||||
|
|
||||||
|
if (password) {
|
||||||
|
args.push(`-p"${password}"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push(`-o"${dest}"`)
|
||||||
|
|
||||||
|
args.push(`"${file}"`)
|
||||||
|
|
||||||
|
const cmd = `${Vars.sevenzip_bin} ${args.join(" ")}`
|
||||||
|
|
||||||
|
console.log(cmd)
|
||||||
|
|
||||||
|
await execa(cmd, {
|
||||||
|
shell: true,
|
||||||
|
stdout: "inherit",
|
||||||
|
stderr: "inherit",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async autoExtract(file, dest) {
|
||||||
|
return await extractFile(file, dest)
|
||||||
|
}
|
||||||
|
}
|
@ -36,4 +36,36 @@ export default class SecureFileSystem {
|
|||||||
existsSync(...args) {
|
existsSync(...args) {
|
||||||
return fs.existsSync(...args)
|
return fs.existsSync(...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async rename(from, to) {
|
||||||
|
this.checkOutsideJail(from)
|
||||||
|
this.checkOutsideJail(to)
|
||||||
|
|
||||||
|
return await fs.promises.rename(from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
async writeFile(path, data, options) {
|
||||||
|
this.checkOutsideJail(path)
|
||||||
|
return await fs.promises.writeFile(path, data, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
async readDir(path) {
|
||||||
|
this.checkOutsideJail(path)
|
||||||
|
return await fs.promises.readdir(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
async rm(path, options) {
|
||||||
|
this.checkOutsideJail(path)
|
||||||
|
return await fs.promises.rm(path, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
async mkdir(path, options) {
|
||||||
|
this.checkOutsideJail(path)
|
||||||
|
return await fs.promises.mkdir(path, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
async stat(path) {
|
||||||
|
this.checkOutsideJail(path)
|
||||||
|
return await fs.promises.stat(path)
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ import Open from "./open"
|
|||||||
import Path from "./path"
|
import Path from "./path"
|
||||||
import Fs from "./fs"
|
import Fs from "./fs"
|
||||||
import Auth from "./auth"
|
import Auth from "./auth"
|
||||||
|
import Extract from "./extract"
|
||||||
|
|
||||||
// Third party libraries
|
// Third party libraries
|
||||||
import Mcl from "./mcl"
|
import Mcl from "./mcl"
|
||||||
@ -11,5 +12,6 @@ export default {
|
|||||||
path: Path,
|
path: Path,
|
||||||
open: Open,
|
open: Open,
|
||||||
auth: Auth,
|
auth: Auth,
|
||||||
mcl: Mcl
|
extract: Extract,
|
||||||
|
mcl: Mcl,
|
||||||
}
|
}
|
@ -9,9 +9,11 @@ export default [
|
|||||||
{
|
{
|
||||||
id: "7z-bin",
|
id: "7z-bin",
|
||||||
finalBin: Vars.sevenzip_bin,
|
finalBin: Vars.sevenzip_bin,
|
||||||
url: resolveRemoteBinPath(`${baseURL}/7zip-bin`, process.platform === "win32" ? "7za.exe" : "7za"),
|
url: resolveRemoteBinPath(`${baseURL}/7z-full`, "7z.zip"),
|
||||||
destination: Vars.sevenzip_bin,
|
destination: path.resolve(Vars.binaries_path, "7z.zip"),
|
||||||
|
extract: path.resolve(Vars.binaries_path, "7z-bin"),
|
||||||
rewriteExecutionPermission: true,
|
rewriteExecutionPermission: true,
|
||||||
|
deleteBeforeExtract: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "git-bin",
|
id: "git-bin",
|
||||||
@ -24,14 +26,13 @@ export default [
|
|||||||
deleteBeforeExtract: true,
|
deleteBeforeExtract: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "rclone-bin",
|
id: "aria2",
|
||||||
finalBin: Vars.rclone_bin,
|
finalBin: Vars.aria2_bin,
|
||||||
url: resolveRemoteBinPath(`${baseURL}/rclone`, "rclone-bin.zip"),
|
url: async (os, arch) => {
|
||||||
destination: path.resolve(Vars.binaries_path, "rclone-bin.zip"),
|
return `https://storage.ragestudio.net/rstudio/binaries/aria2/${os}/${arch}/${os === "win32" ? "aria2c.exe" : "aria2c"}`
|
||||||
extract: path.resolve(Vars.binaries_path, "rclone-bin"),
|
},
|
||||||
requireOs: ["win32"],
|
destination: Vars.aria2_bin,
|
||||||
rewriteExecutionPermission: true,
|
rewriteExecutionPermission: Vars.aria2_bin,
|
||||||
deleteBeforeExtract: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "java22_jre_bin",
|
id: "java22_jre_bin",
|
||||||
|
@ -2,10 +2,10 @@ export default (pre, post) => {
|
|||||||
let url = null
|
let url = null
|
||||||
|
|
||||||
if (process.platform === "darwin") {
|
if (process.platform === "darwin") {
|
||||||
url = `${pre}/mac/${process.arch}/${post}`
|
url = `${pre}/darwin/${process.arch}/${post}`
|
||||||
}
|
}
|
||||||
else if (process.platform === "win32") {
|
else if (process.platform === "win32") {
|
||||||
url = `${pre}/win/${process.arch}/${post}`
|
url = `${pre}/win32/${process.arch}/${post}`
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
url = `${pre}/linux/${process.arch}/${post}`
|
url = `${pre}/linux/${process.arch}/${post}`
|
||||||
|
@ -2,7 +2,7 @@ import path from "node:path"
|
|||||||
import upath from "upath"
|
import upath from "upath"
|
||||||
import resolveUserDataPath from "./utils/resolveUserDataPath"
|
import resolveUserDataPath from "./utils/resolveUserDataPath"
|
||||||
|
|
||||||
const isWin = process.platform.includes("win")
|
const isWin = process.platform.includes("win32")
|
||||||
const isMac = process.platform.includes("darwin")
|
const isMac = process.platform.includes("darwin")
|
||||||
|
|
||||||
const runtimeName = "rs-relic"
|
const runtimeName = "rs-relic"
|
||||||
@ -15,9 +15,9 @@ const binaries_path = upath.normalizeSafe(path.resolve(runtime_path, "binaries")
|
|||||||
const db_path = upath.normalizeSafe(path.resolve(runtime_path, "db.json"))
|
const db_path = upath.normalizeSafe(path.resolve(runtime_path, "db.json"))
|
||||||
|
|
||||||
const binaries = {
|
const binaries = {
|
||||||
sevenzip_bin: upath.normalizeSafe(path.resolve(binaries_path, "7z-bin", isWin ? "7za.exe" : "7za")),
|
sevenzip_bin: upath.normalizeSafe(path.resolve(binaries_path, "7z-bin", isWin ? "7z.exe" : "7zz")),
|
||||||
git_bin: upath.normalizeSafe(path.resolve(binaries_path, "git-bin", "bin", isWin ? "git.exe" : "git")),
|
git_bin: upath.normalizeSafe(path.resolve(binaries_path, "git-bin", "bin", isWin ? "git.exe" : "git")),
|
||||||
rclone_bin: upath.normalizeSafe(path.resolve(binaries_path, "rclone-bin", isWin ? "rclone.exe" : "rclone")),
|
aria2_bin: upath.normalizeSafe(path.resolve(binaries_path, "aria2", isWin ? "aria2c.exe" : "aria2c")),
|
||||||
java22_jre_bin: upath.normalizeSafe(path.resolve(binaries_path, "java22_jre_bin", (isMac ? "Contents/Home/bin/java" : (isWin ? "bin/java.exe" : "bin/java")))),
|
java22_jre_bin: upath.normalizeSafe(path.resolve(binaries_path, "java22_jre_bin", (isMac ? "Contents/Home/bin/java" : (isWin ? "bin/java.exe" : "bin/java")))),
|
||||||
java17_jre_bin: upath.normalizeSafe(path.resolve(binaries_path, "java17_jre_bin", (isMac ? "Contents/Home/bin/java" : (isWin ? "bin/java.exe" : "bin/java")))),
|
java17_jre_bin: upath.normalizeSafe(path.resolve(binaries_path, "java17_jre_bin", (isMac ? "Contents/Home/bin/java" : (isWin ? "bin/java.exe" : "bin/java")))),
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user