feat:UI及切换后端为http
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -22,3 +22,7 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
*.zip
|
||||||
|
Dex-v3-core.exe
|
||||||
|
core-x86_64-pc-windows-msvc.exe
|
||||||
|
config.json
|
||||||
1364
backend/package-lock.json
generated
1364
backend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "tsc&&node dist/main.js",
|
"test": "tsc&&node dist/main.js",
|
||||||
"rollup": "rollup -c rollup.config.js",
|
"rollup": "rollup -c rollup.config.js",
|
||||||
"nexe": "nexe -i ./dist/bundle.js --ico Dex.ico --build -t x86-22.13.0 --output ./dist/Dex-v3-core.exe",
|
"nexe": "nexe -i ./dist/bundle.js --build -t x86-22.13.0 --output ./dist/core-x86_64-pc-windows-msvc.exe",
|
||||||
"build": "npm run rollup && npm run nexe"
|
"build": "npm run rollup && npm run nexe"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -17,16 +17,27 @@
|
|||||||
"@rollup/plugin-json": "^6.1.0",
|
"@rollup/plugin-json": "^6.1.0",
|
||||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||||
"@rollup/plugin-typescript": "^12.1.4",
|
"@rollup/plugin-typescript": "^12.1.4",
|
||||||
|
"@types/cors": "^2.8.19",
|
||||||
|
"@types/express": "^5.0.3",
|
||||||
|
"@types/fs-extra": "^11.0.4",
|
||||||
|
"@types/multer": "^2.0.0",
|
||||||
|
"@types/ws": "^8.18.1",
|
||||||
|
"@types/yauzl": "^2.10.3",
|
||||||
"nexe": "^5.0.0-beta.4",
|
"nexe": "^5.0.0-beta.4",
|
||||||
"rollup": "^4.50.1",
|
"rollup": "^4.50.1",
|
||||||
"typescript": "^5.9.2"
|
"typescript": "^5.9.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"express": "^5.1.0",
|
||||||
"fs-extra": "^11.3.1",
|
"fs-extra": "^11.3.1",
|
||||||
"got": "^14.4.8",
|
"got": "^14.4.8",
|
||||||
"inquirer": "^12.9.4",
|
"inquirer": "^12.9.4",
|
||||||
|
"multer": "^2.0.2",
|
||||||
"p-map": "^7.0.3",
|
"p-map": "^7.0.3",
|
||||||
|
"p-retry": "^7.0.0",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"yauzl-promise": "^4.0.0"
|
"ws": "^8.18.3",
|
||||||
|
"yauzl": "^3.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import typescript from '@rollup/plugin-typescript'
|
|||||||
import resolve from '@rollup/plugin-node-resolve';
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
import commonjs from '@rollup/plugin-commonjs'
|
import commonjs from '@rollup/plugin-commonjs'
|
||||||
import json from '@rollup/plugin-json';
|
import json from '@rollup/plugin-json';
|
||||||
|
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
||||||
/** @type {import('rollup').RollupOptions} */
|
/** @type {import('rollup').RollupOptions} */
|
||||||
// ---cut---
|
// ---cut---
|
||||||
export default {
|
export default {
|
||||||
@@ -10,8 +11,10 @@ export default {
|
|||||||
file: 'dist/bundle.js',
|
file: 'dist/bundle.js',
|
||||||
format: 'esm'
|
format: 'esm'
|
||||||
},
|
},
|
||||||
|
//external: (id) => /\\.node$/.test(id) || id.includes('crc32'),
|
||||||
plugins:[
|
plugins:[
|
||||||
typescript(),
|
typescript(),
|
||||||
|
nodeResolve(),
|
||||||
resolve({preferBuiltins: true}),
|
resolve({preferBuiltins: true}),
|
||||||
commonjs(),
|
commonjs(),
|
||||||
json()
|
json()
|
||||||
|
|||||||
@@ -1,16 +1,72 @@
|
|||||||
import config,{ Config } from "./utils/config.js";
|
import config, { Config } from "./utils/config.js";
|
||||||
|
import fsp from "node:fs/promises";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import { pipeline } from "node:stream/promises";
|
||||||
|
import { yauzl_promise } from "./utils/yauzl.promise.js";
|
||||||
|
import express from "express";
|
||||||
|
import multer from "multer";
|
||||||
|
import cors from "cors"
|
||||||
|
import websocket, {WebSocketServer} from "ws"
|
||||||
|
import { createServer } from "node:http";
|
||||||
|
const app = express();
|
||||||
|
const upload = multer()
|
||||||
|
app.use(cors())
|
||||||
|
app.use(express.json())
|
||||||
|
const server = createServer(app);
|
||||||
|
const wss = new WebSocketServer({server})
|
||||||
|
const tasks = new Map<number, {status: "peding"|"success",result: any}>()
|
||||||
|
let timespm = 0;
|
||||||
|
let ws:websocket|undefined = undefined;
|
||||||
|
/* 对外API */
|
||||||
|
// Express
|
||||||
|
app.post("/start",upload.single("file"),(req,res)=>{
|
||||||
|
if (!req.file){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DeX(req.file.buffer)
|
||||||
|
timespm = Date.now();
|
||||||
|
tasks.set(timespm,{status:"peding",result:undefined});
|
||||||
|
res.json({taskId:timespm})
|
||||||
|
//const buffer = Buffer.from(req.body);
|
||||||
|
//console.log(buffer);
|
||||||
|
})
|
||||||
|
|
||||||
const input = process.argv[2];
|
app.get('/getconfig',(req,res)=>{
|
||||||
|
res.json(config)
|
||||||
|
})
|
||||||
|
|
||||||
switch (input) {
|
app.post('/writeconfig',(req,res)=>{
|
||||||
case 'getconfig': //读取配置
|
Config.write_config(req.body)
|
||||||
process.stdout.write(JSON.stringify(config));
|
res.json({status:200})
|
||||||
break;
|
})
|
||||||
case 'writeconfig': //写入配置
|
// WebSocket
|
||||||
if(process.argv.length < 4){
|
wss.on("connection",(wsx)=>{
|
||||||
process.exit(1);
|
ws = wsx;
|
||||||
}
|
})
|
||||||
Config.write_config(JSON.parse(process.argv[3]));
|
|
||||||
break;
|
server.listen(37019,()=>{
|
||||||
case 'start':
|
console.log("Server is running on http://localhost:37019")
|
||||||
|
})
|
||||||
|
|
||||||
|
async function DeX(buffer: Buffer) {
|
||||||
|
/* 解压Zip */
|
||||||
|
const zip = await yauzl_promise(buffer);
|
||||||
|
for await (const entry of zip) {
|
||||||
|
const ew = entry.fileName.endsWith('/')
|
||||||
|
if (ew){
|
||||||
|
await fsp.mkdir(`./test/${entry.fileName}`,{recursive:true})
|
||||||
|
}
|
||||||
|
if (!ew) {
|
||||||
|
const dirPath = `./test/${entry.fileName.substring(0, entry.fileName.lastIndexOf('/'))}`;
|
||||||
|
await fsp.mkdir(dirPath, { recursive: true });
|
||||||
|
const stream = await entry.openReadStream;
|
||||||
|
const write = fs.createWriteStream(`./test/${entry.fileName}`);
|
||||||
|
await pipeline(stream, write);
|
||||||
|
}
|
||||||
|
if(ws){
|
||||||
|
ws.send(JSON.stringify({status:"unzip",result:entry.fileName}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 解压完成 */
|
||||||
|
ws?.send(JSON.stringify({status:"changed",result:undefined}))
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,8 @@
|
|||||||
import got from "got";
|
import got from "got";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { fastdownload, usemirror } from "../utils/utils.js";
|
import { fastdownload, Utils } from "../utils/utils.js";
|
||||||
import { modpack_info, XPlatform } from "./index.js";
|
import { modpack_info, XPlatform } from "./index.js";
|
||||||
|
|
||||||
const cf_url = (() => {
|
|
||||||
if (usemirror) {
|
|
||||||
return "https://mod.mcimirror.top/curseforge";
|
|
||||||
} else {
|
|
||||||
return "https://api.curseforge.com";
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
export interface CurseForgeManifest {
|
export interface CurseForgeManifest {
|
||||||
minecraft: {
|
minecraft: {
|
||||||
version: string;
|
version: string;
|
||||||
@@ -19,6 +12,10 @@ export interface CurseForgeManifest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CurseForge implements XPlatform {
|
export class CurseForge implements XPlatform {
|
||||||
|
private utils: Utils;
|
||||||
|
constructor() {
|
||||||
|
this.utils = new Utils();
|
||||||
|
}
|
||||||
async getinfo(manifest: object): Promise<modpack_info> {
|
async getinfo(manifest: object): Promise<modpack_info> {
|
||||||
let result: modpack_info = Object.create({});
|
let result: modpack_info = Object.create({});
|
||||||
const local_manifest = manifest as CurseForgeManifest;
|
const local_manifest = manifest as CurseForgeManifest;
|
||||||
@@ -40,7 +37,7 @@ export class CurseForge implements XPlatform {
|
|||||||
});
|
});
|
||||||
let tmp: [string, string] | string[][] = [];
|
let tmp: [string, string] | string[][] = [];
|
||||||
await got
|
await got
|
||||||
.post(cf_url + "/v1/mods/files", {
|
.post(this.utils.curseforge_url + "/v1/mods/files", {
|
||||||
body: FileID,
|
body: FileID,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -57,14 +54,16 @@ export class CurseForge implements XPlatform {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const unpath = join(path + "/mods/", e.fileName);
|
const unpath = join(path + "/mods/", e.fileName);
|
||||||
if (usemirror) {
|
const url = e.downloadUrl.replace("https://edge.forgecdn.net", this.utils.curseforge_Durl)
|
||||||
tmp.push([
|
tmp.push([url, unpath])
|
||||||
"https://mod.mcimirror.top" + new URL(e.downloadUrl).pathname,
|
// if (usemirror) {
|
||||||
unpath,
|
// tmp.push([
|
||||||
]);
|
// "https://mod.mcimirror.top" + new URL(e.downloadUrl).pathname,
|
||||||
} else {
|
// unpath,
|
||||||
tmp.push([e.downloadUrl, unpath]);
|
// ]);
|
||||||
}
|
// } else {
|
||||||
|
// tmp.push([e.downloadUrl, unpath]);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import { mr_fastdownload, usemirror } from "../utils/utils.js";
|
import { mr_fastdownload, Utils } from "../utils/utils.js";
|
||||||
import { modpack_info, XPlatform } from "./index.js";
|
import { modpack_info, XPlatform } from "./index.js";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
|
|
||||||
@@ -15,6 +15,10 @@ interface ModrinthManifest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Modrinth implements XPlatform {
|
export class Modrinth implements XPlatform {
|
||||||
|
private utils: Utils;
|
||||||
|
constructor() {
|
||||||
|
this.utils = new Utils();
|
||||||
|
}
|
||||||
async getinfo(manifest: object): Promise<modpack_info> {
|
async getinfo(manifest: object): Promise<modpack_info> {
|
||||||
let result: modpack_info = Object.create({});
|
let result: modpack_info = Object.create({});
|
||||||
const local_manifest = manifest as ModrinthManifest;
|
const local_manifest = manifest as ModrinthManifest;
|
||||||
@@ -37,12 +41,14 @@ export class Modrinth implements XPlatform {
|
|||||||
if (e.path.endsWith(".zip")) {
|
if (e.path.endsWith(".zip")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const url = e.downloads[0].replace("https://cdn.modrinth.com",this.utils.modrinth_Durl)
|
||||||
const unpath = join(path,e.path)
|
const unpath = join(path,e.path)
|
||||||
if (usemirror){
|
tmp.push([e.downloads[0],unpath,String(e.fileSize)])
|
||||||
tmp.push(["https://mod.mcimirror.top"+new URL(e.downloads[0]).pathname,unpath,String(e.fileSize)])
|
// if (usemirror){
|
||||||
}else{
|
// tmp.push(["https://mod.mcimirror.top"+new URL(e.downloads[0]).pathname,unpath,String(e.fileSize)])
|
||||||
tmp.push([e.downloads[0],unpath,String(e.fileSize)])
|
// }else{
|
||||||
}
|
// tmp.push([e.downloads[0],unpath,String(e.fileSize)])
|
||||||
|
// }
|
||||||
});
|
});
|
||||||
await mr_fastdownload(tmp as unknown as [string, string, string])
|
await mr_fastdownload(tmp as unknown as [string, string, string])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,106 @@
|
|||||||
|
import pMap from "p-map";
|
||||||
import config from "./config.js";
|
import config from "./config.js";
|
||||||
|
import got from "got";
|
||||||
|
import pRetry from "p-retry";
|
||||||
|
import fs from "fs";
|
||||||
|
import fse from "fs-extra";
|
||||||
|
|
||||||
export class Utils{
|
export class Utils {
|
||||||
public modrinth_url: string;
|
public modrinth_url: string;
|
||||||
public curseforge_url: string;
|
public curseforge_url: string;
|
||||||
constructor(){
|
public curseforge_Durl: string;
|
||||||
this.modrinth_url = "https://api.modrinth.com"
|
public modrinth_Durl: string;
|
||||||
this.curseforge_url = "https://api.curseforge.com"
|
constructor() {
|
||||||
if(config.mirror.mcimirror){
|
this.modrinth_url = "https://api.modrinth.com";
|
||||||
this.modrinth_url = "https://mod.mcimirror.top/modrinth"
|
this.curseforge_url = "https://api.curseforge.com";
|
||||||
this.curseforge_url = "https://mod.mcimirror.top/curseforge"
|
this.modrinth_Durl = "https://cdn.modrinth.com";
|
||||||
|
this.curseforge_Durl = "https://media.forgecdn.net";
|
||||||
|
if (config.mirror.mcimirror) {
|
||||||
|
this.modrinth_url = "https://mod.mcimirror.top/modrinth";
|
||||||
|
this.curseforge_url = "https://mod.mcimirror.top/curseforge";
|
||||||
|
this.modrinth_Durl = "https://mod.mcimirror.top";
|
||||||
|
this.curseforge_Durl = "https://mod.mcimirror.top";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fastdownload(data: [string, string]) {
|
||||||
|
return await pMap(
|
||||||
|
data,
|
||||||
|
async (e) => {
|
||||||
|
try {
|
||||||
|
await pRetry(
|
||||||
|
async () => {
|
||||||
|
if (!fs.existsSync(e[1])) {
|
||||||
|
const size: number = await (async () => {
|
||||||
|
const head = (
|
||||||
|
await got.head(
|
||||||
|
e[0] /*.replace("https://mod.mcimirror.top","https://edge.forgecdn.net")*/,
|
||||||
|
{ headers: { "user-agent": "DeEarthX" } }
|
||||||
|
)
|
||||||
|
).headers["content-length"];
|
||||||
|
if (head) {
|
||||||
|
return Number(head);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
await got
|
||||||
|
.get(e[0], {
|
||||||
|
responseType: "buffer",
|
||||||
|
headers: {
|
||||||
|
"user-agent": "DeEarthX",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.on("downloadProgress", (progress) => {
|
||||||
|
//bar.update(progress.transferred);
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
fse.outputFileSync(e[1], res.rawBody);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ retries: 3 }
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
//LOGGER.error({ err: e });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ concurrency: 16 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function mr_fastdownload(data: [string, string, string]) {
|
||||||
|
return await pMap(
|
||||||
|
data,
|
||||||
|
async (e) => {
|
||||||
|
//const bar = multibar.create(Number(e[2]), 0, { filename: e[1] });
|
||||||
|
try {
|
||||||
|
await pRetry(
|
||||||
|
async () => {
|
||||||
|
if (!fse.existsSync(e[1])) {
|
||||||
|
await got
|
||||||
|
.get(e[0], {
|
||||||
|
responseType: "buffer",
|
||||||
|
headers: {
|
||||||
|
"user-agent": "DeEarthX",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.on("downloadProgress", (progress) => {
|
||||||
|
//bar.update(progress.transferred);
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
fse.outputFileSync(e[1], res.rawBody);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ retries: 3 }
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
//LOGGER.error({ err: e });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ concurrency: 16 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
52
backend/src/utils/yauzl.promise.ts
Normal file
52
backend/src/utils/yauzl.promise.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import yauzl from "yauzl";
|
||||||
|
import Stream from "node:stream"
|
||||||
|
|
||||||
|
export interface IentryP extends yauzl.Entry {
|
||||||
|
openReadStream: Promise<Stream.Readable>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function yauzl_promise(buffer: Buffer): Promise<IentryP[]>{
|
||||||
|
const zip = await (new Promise((resolve,reject)=>{
|
||||||
|
yauzl.fromBuffer(buffer,/*{lazyEntries:true},*/ (err, zipfile) => {
|
||||||
|
if (err){
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(zipfile);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}) as Promise<yauzl.ZipFile>);
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const entries: IentryP[]= []
|
||||||
|
zip.on("entry", async (entry: yauzl.Entry) => {
|
||||||
|
const _entry = {
|
||||||
|
...entry,
|
||||||
|
getLastModDate: entry.getLastModDate,
|
||||||
|
isEncrypted: entry.isEncrypted,
|
||||||
|
isCompressed: entry.isCompressed,
|
||||||
|
openReadStream: _openReadStream(zip,entry)
|
||||||
|
}
|
||||||
|
entries.push(_entry)
|
||||||
|
if (zip.entryCount === entries.length){
|
||||||
|
zip.close();
|
||||||
|
resolve(entries);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
zip.on("error",err=>{
|
||||||
|
reject(err);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _openReadStream(zip:yauzl.ZipFile,entry:yauzl.Entry): Promise<Stream.Readable>{
|
||||||
|
return new Promise((resolve,reject)=>{
|
||||||
|
zip.openReadStream(entry,(err,stream)=>{
|
||||||
|
if (err){
|
||||||
|
reject(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(stream);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
11
front/package-lock.json
generated
11
front/package-lock.json
generated
@@ -20,6 +20,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "^2",
|
"@tauri-apps/cli": "^2",
|
||||||
|
"@tauri-apps/plugin-shell": "^2.3.1",
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
"typescript": "~5.6.2",
|
"typescript": "~5.6.2",
|
||||||
"vite": "^6.0.3",
|
"vite": "^6.0.3",
|
||||||
@@ -1384,6 +1385,16 @@
|
|||||||
"@tauri-apps/api": "^2.8.0"
|
"@tauri-apps/api": "^2.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tauri-apps/plugin-shell": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@tauri-apps/plugin-shell/-/plugin-shell-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-jjs2WGDO/9z2pjNlydY/F5yYhNsscv99K5lCmU5uKjsVvQ3dRlDhhtVYoa4OLDmktLtQvgvbQjCFibMl6tgGfw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT OR Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@tauri-apps/api": "^2.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tauri-apps/plugin-store": {
|
"node_modules/@tauri-apps/plugin-store": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@tauri-apps/plugin-store/-/plugin-store-2.4.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@tauri-apps/plugin-store/-/plugin-store-2.4.0.tgz",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"build": "vue-tsc --noEmit && vite build",
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"tauri": "tauri",
|
"tauri": "tauri",
|
||||||
"tauri-dev": "tauri dev",
|
"tauri-dev": "tauri dev --no-watch",
|
||||||
"tauri-build": "tauri build"
|
"tauri-build": "tauri build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "^2",
|
"@tauri-apps/cli": "^2",
|
||||||
|
"@tauri-apps/plugin-shell": "^2.3.1",
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
"typescript": "~5.6.2",
|
"typescript": "~5.6.2",
|
||||||
"vite": "^6.0.3",
|
"vite": "^6.0.3",
|
||||||
|
|||||||
3
front/src-tauri/.taurignore
Normal file
3
front/src-tauri/.taurignore
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
capabilities/
|
||||||
|
target/debug/
|
||||||
|
target/release/
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
up to date in 749ms
|
up to date in 1s
|
||||||
|
|
||||||
16 packages are looking for funding
|
16 packages are looking for funding
|
||||||
run `npm fund` for details
|
run `npm fund` for details
|
||||||
|
|||||||
73
front/src-tauri/Cargo.lock
generated
73
front/src-tauri/Cargo.lock
generated
@@ -703,6 +703,7 @@ dependencies = [
|
|||||||
"tauri",
|
"tauri",
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
"tauri-plugin-opener",
|
"tauri-plugin-opener",
|
||||||
|
"tauri-plugin-shell",
|
||||||
"tauri-plugin-store",
|
"tauri-plugin-store",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -843,6 +844,15 @@ version = "1.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
|
checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding_rs"
|
||||||
|
version = "0.8.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "endi"
|
name = "endi"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -2420,6 +2430,16 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_pipe"
|
||||||
|
version = "1.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db335f4760b14ead6290116f2427bf33a14d4f0617d49f78a246de10c1831224"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pango"
|
name = "pango"
|
||||||
version = "0.18.3"
|
version = "0.18.3"
|
||||||
@@ -3304,12 +3324,44 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shared_child"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"sigchld",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sigchld"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"os_pipe",
|
||||||
|
"signal-hook",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook"
|
||||||
|
version = "0.3.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"signal-hook-registry",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.6"
|
version = "1.4.6"
|
||||||
@@ -3727,6 +3779,27 @@ dependencies = [
|
|||||||
"zbus",
|
"zbus",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-shell"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "54777d0c0d8add34eea3ced84378619ef5b97996bd967d3038c668feefd21071"
|
||||||
|
dependencies = [
|
||||||
|
"encoding_rs",
|
||||||
|
"log",
|
||||||
|
"open",
|
||||||
|
"os_pipe",
|
||||||
|
"regex",
|
||||||
|
"schemars 0.8.22",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"shared_child",
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
"thiserror 2.0.16",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-store"
|
name = "tauri-plugin-store"
|
||||||
version = "2.4.0"
|
version = "2.4.0"
|
||||||
|
|||||||
@@ -24,4 +24,5 @@ serde = { version = "1", features = ["derive"] }
|
|||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
open = "5.3.2"
|
open = "5.3.2"
|
||||||
tauri-plugin-store = "2"
|
tauri-plugin-store = "2"
|
||||||
|
tauri-plugin-shell = "2"
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,20 @@
|
|||||||
"permissions": [
|
"permissions": [
|
||||||
"core:default",
|
"core:default",
|
||||||
"opener:default",
|
"opener:default",
|
||||||
"store:default"
|
"store:default",
|
||||||
|
"shell:default",
|
||||||
|
"shell:allow-execute",
|
||||||
|
"shell:allow-spawn",
|
||||||
|
"shell:allow-open",
|
||||||
|
{
|
||||||
|
"identifier": "shell:allow-execute",
|
||||||
|
"allow": [
|
||||||
|
{
|
||||||
|
"name": "core",
|
||||||
|
"cmd": "core.exe",
|
||||||
|
"args": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,7 @@ fn open_url(url: &str) {
|
|||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_shell::init())
|
||||||
.plugin(tauri_plugin_store::Builder::new().build())
|
.plugin(tauri_plugin_store::Builder::new().build())
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.invoke_handler(tauri::generate_handler![greet])
|
.invoke_handler(tauri::generate_handler![greet])
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"icons/128x128@2x.png",
|
"icons/128x128@2x.png",
|
||||||
"icons/icon.icns",
|
"icons/icon.icns",
|
||||||
"icons/icon.ico"
|
"icons/icon.ico"
|
||||||
]
|
],
|
||||||
|
"externalBin": ["binaries/core"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { nextTick, ref, VNodeRef } from 'vue';
|
||||||
import { InboxOutlined } from '@ant-design/icons-vue';
|
import { InboxOutlined } from '@ant-design/icons-vue';
|
||||||
import { message, StepsProps } from 'ant-design-vue';
|
import { message, StepsProps } from 'ant-design-vue';
|
||||||
import type { UploadFile, UploadChangeParam } from 'ant-design-vue';
|
import type { UploadFile, UploadChangeParam, Upload } from 'ant-design-vue';
|
||||||
|
import * as shell from '@tauri-apps/plugin-shell';
|
||||||
|
interface IWSM {
|
||||||
|
status: "unzip"|"pending"|"changed",
|
||||||
|
result: string
|
||||||
|
}
|
||||||
/* 进度显示区 */
|
/* 进度显示区 */
|
||||||
const disp_steps = ref(true);
|
const disp_steps = ref(true);
|
||||||
const setyps_current = ref(0);
|
const setyps_current = ref(0);
|
||||||
@@ -45,32 +50,66 @@ function handleUpload() {
|
|||||||
message.warning('请先拖拽或选择文件')
|
message.warning('请先拖拽或选择文件')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let data: ArrayBuffer[] = [];
|
if (!FileList.value[0].originFileObj){
|
||||||
FileList.value[0].originFileObj?.arrayBuffer().then(buffer => {data=[buffer];console.log(data);}) //获取文件内容
|
return;
|
||||||
console.log(data);
|
}
|
||||||
|
runDeEarthX(FileList.value[0].originFileObj) //获取文件内容
|
||||||
BtnisDisabled.value = true; //禁用按钮
|
BtnisDisabled.value = true; //禁用按钮
|
||||||
disp_steps.value = true; //开始显示进度条
|
disp_steps.value = true; //开始显示进度条
|
||||||
}
|
}
|
||||||
|
|
||||||
function runDeEarthX() {
|
|
||||||
reactFL()
|
|
||||||
}
|
|
||||||
|
|
||||||
function reactFL() {
|
function reactFL() {
|
||||||
FileList.value = [];
|
FileList.value = [];
|
||||||
isDisabled.value = false;
|
isDisabled.value = false;
|
||||||
}
|
}
|
||||||
runDeEarthX();
|
|
||||||
/* 获取文件区 */
|
/* 获取文件区 */
|
||||||
|
shell.Command.create('core',['start']).spawn()
|
||||||
|
function runDeEarthX(data: Blob) {
|
||||||
|
console.log(data)
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.append('file', data);
|
||||||
|
console.log(fd.getAll('file'))
|
||||||
|
fetch('http://localhost:37019/start',{
|
||||||
|
method:'POST',
|
||||||
|
body:fd
|
||||||
|
}).then(async res=>res.json()).then(res=>{
|
||||||
|
prews(res)
|
||||||
|
})
|
||||||
|
// shell.Command.create('core',['start',new BigUint64Array(data).toString()]).stdout.on('data',(data)=>{
|
||||||
|
// console.log(data)
|
||||||
|
// })
|
||||||
|
reactFL()
|
||||||
|
}
|
||||||
|
|
||||||
|
function prews(res: object){
|
||||||
|
const ws = new WebSocket('ws://localhost:37019/')
|
||||||
|
ws.addEventListener('message',(wsm)=>{
|
||||||
|
const _data = JSON.parse(wsm.data) as IWSM
|
||||||
|
if (_data.status === "changed") {
|
||||||
|
setyps_current.value ++;
|
||||||
|
}
|
||||||
|
logs.value.push({message:_data.result})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 日志区 */
|
||||||
|
const logs = ref<{message:string}[]>([]);
|
||||||
|
//logs.value.push({message:"114514"})
|
||||||
|
const logContainer = ref<HTMLDivElement>();
|
||||||
|
nextTick(()=>{
|
||||||
|
if(logContainer.value){
|
||||||
|
logContainer.value.scrollTop = logContainer.value.scrollHeight;
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="tw:h-full tw:w-full">
|
<div class="tw:h-full tw:w-full tw:relative">
|
||||||
<div class="tw:h-full tw:w-full tw:flex tw:flex-col tw:justify-center tw:items-center">
|
<div class="tw:h-full tw:w-full tw:flex tw:flex-col tw:justify-center tw:items-center">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="tw:text-4xl tw:text-center tw:animate-pulse">DeEarthX</h1>
|
<h1 class="tw:text-4xl tw:text-center tw:animate-pulse">DeEarthX</h1>
|
||||||
<h1 class="tw:text-sm tw:text-gray-500 tw:text-center">让开服变成随时随地的事情!</h1>
|
<h1 class="tw:text-sm tw:text-gray-500 tw:text-center">让开服变成随时随地的事情!</h1>
|
||||||
</div>
|
</div>
|
||||||
<a-upload-dragger :disabled="isDisabled" class="tw:w-128 tw:h-48" name="file" action="/" :multiple="false"
|
<a-upload-dragger :disabled="isDisabled" class="tw:w-144 tw:h-48" name="file" action="/" :multiple="false"
|
||||||
:before-upload="beforeUpload" @change="handleChange" @drop="handleDrop" v-model:fileList="FileList"
|
:before-upload="beforeUpload" @change="handleChange" @drop="handleDrop" v-model:fileList="FileList"
|
||||||
accept=".zip,.mrpack">
|
accept=".zip,.mrpack">
|
||||||
<p class="ant-upload-drag-icon">
|
<p class="ant-upload-drag-icon">
|
||||||
@@ -89,5 +128,11 @@ runDeEarthX();
|
|||||||
class="tw:fixed tw:bottom-2 tw:ml-4 tw:w-272 tw:h-16 tw:flex tw:justify-center tw:items-center tw:text-sm">
|
class="tw:fixed tw:bottom-2 tw:ml-4 tw:w-272 tw:h-16 tw:flex tw:justify-center tw:items-center tw:text-sm">
|
||||||
<a-steps :current="setyps_current" :items="setps_items" />
|
<a-steps :current="setyps_current" :items="setps_items" />
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="disp_steps" ref="logContainer" class="tw:absolute tw:right-2 tw:bottom-20 tw:h-96 tw:w-56 tw:bg-gray-200 tw:rounded-xl tw:container tw:overflow-y-auto">
|
||||||
|
<div v-for="log in logs" class="tw:mt-2 tw:last:mb-0">
|
||||||
|
<span class="tw:text-blue-500">{{ log.message }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
@@ -1,9 +1,49 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import * as fs from "@tauri-apps/plugin-store"
|
import * as shell from '@tauri-apps/plugin-shell';
|
||||||
const config = ref({})
|
import { message } from 'ant-design-vue';
|
||||||
|
/* Config */
|
||||||
|
interface IConfig {
|
||||||
|
mirror: {
|
||||||
|
bmclapi: boolean;
|
||||||
|
mcimirror: boolean;
|
||||||
|
};
|
||||||
|
filter: {
|
||||||
|
hashes: boolean;
|
||||||
|
dexpub: boolean;
|
||||||
|
mixins: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const config = ref<IConfig>({mirror: {bmclapi: false, mcimirror: false}, filter: {hashes: false, dexpub: false, mixins: false}})
|
||||||
|
fetch('http://localhost:37019/getconfig',{
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}).then(res=>res.json()).then(res=>config.value = res)
|
||||||
|
|
||||||
const checked = ref(false);
|
let first = true;
|
||||||
|
watch(config,(newv)=>{ //写入Config
|
||||||
|
if(!first){
|
||||||
|
fetch('http://localhost:37019/writeconfig',{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(newv)
|
||||||
|
}).then(res=>{
|
||||||
|
if(res.status === 200){
|
||||||
|
message.success('配置已保存')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// shell.Command.create('core',['writeconfig',JSON.stringify(newv)]).execute().then(()=>{
|
||||||
|
// message.success('配置已保存')
|
||||||
|
// })
|
||||||
|
console.log(newv)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
},{deep:true})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -20,15 +60,15 @@ const checked = ref(false);
|
|||||||
<div class="tw:flex">
|
<div class="tw:flex">
|
||||||
<div class="tw:flex tw:ml-5 tw:mt-2">
|
<div class="tw:flex tw:ml-5 tw:mt-2">
|
||||||
<p class="tw:text-gray-600">哈希过滤</p>
|
<p class="tw:text-gray-600">哈希过滤</p>
|
||||||
<a-switch class="tw:left-2" v-model:checked="checked" />
|
<a-switch class="tw:left-2" v-model:checked="config.filter.hashes" />
|
||||||
</div>
|
</div>
|
||||||
<div class="tw:flex tw:ml-5 tw:mt-2">
|
<div class="tw:flex tw:ml-5 tw:mt-2">
|
||||||
<p class="tw:text-gray-600">DeP过滤</p>
|
<p class="tw:text-gray-600">DeP过滤</p>
|
||||||
<a-switch class="tw:left-2" v-model:checked="checked" />
|
<a-switch class="tw:left-2" v-model:checked="config.filter.dexpub" />
|
||||||
</div>
|
</div>
|
||||||
<div class="tw:flex tw:ml-5 tw:mt-2">
|
<div class="tw:flex tw:ml-5 tw:mt-2">
|
||||||
<p class="tw:text-gray-600">Mixin过滤</p>
|
<p class="tw:text-gray-600">Mixin过滤</p>
|
||||||
<a-switch class="tw:left-2" v-model:checked="checked" />
|
<a-switch class="tw:left-2" v-model:checked="config.filter.mixins" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- DeEarth设置 -->
|
<!-- DeEarth设置 -->
|
||||||
@@ -38,7 +78,7 @@ const checked = ref(false);
|
|||||||
<div class="tw:flex">
|
<div class="tw:flex">
|
||||||
<div class="tw:flex tw:ml-5 tw:mt-2">
|
<div class="tw:flex tw:ml-5 tw:mt-2">
|
||||||
<p class="tw:text-gray-600">MCIM镜像源</p>
|
<p class="tw:text-gray-600">MCIM镜像源</p>
|
||||||
<a-switch class="tw:left-2" v-model:checked="checked" />
|
<a-switch class="tw:left-2" v-model:checked="config.mirror.mcimirror" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user