feat:缓存与hash下载

This commit is contained in:
Tianpao
2025-10-06 00:11:23 +08:00
parent ce2d44689d
commit 77622cd150
6 changed files with 93 additions and 32 deletions

View File

@@ -1,16 +1,20 @@
import { createHash } from "node:crypto"; import { createHash } from "node:crypto";
import { Pool } from "pg"; import { Pool } from "pg";
import { ILibraries, ILibrariesMap, IVersion, IVersionPool } from "../types/versionlist.types.js";
export class VersionListController { export class VersionListController {
versionCache: Version[]; versionCache: IVersion[];
private pool: Pool; private pool: Pool;
hashList: string[]; hashList: string[];
libmap: Map<string, ILibrariesMap>;
constructor(pool: Pool) { constructor(pool: Pool) {
this.pool = pool; this.pool = pool;
this.versionCache = []; this.versionCache = [];
this.hashList = ["md5", "sha1", "sha256"]; this.hashList = ["md5", "sha1", "sha256"];
this.libmap = new Map();
this._refreshCache(); // 初始化缓存 this._refreshCache(); // 初始化缓存
setInterval(this._refreshCache, 1000 * 60 * 60 * 2); // 2小时刷新缓存 setInterval(this._refreshCache, 1000 * 60 * 60 * 2); // 2小时刷新缓存
setInterval(this._refreshLib,1000*60*60*1) // 1小时刷新libmap
} }
async getVersionList() { async getVersionList() {
@@ -36,19 +40,19 @@ GROUP BY mcversion."version", mcversion."Type", mcversion."Date", variation."OSb
ORDER BY "Date" DESC ORDER BY "Date" DESC
`) `)
).rows; ).rows;
result.forEach((row: VersionPool) => { result.forEach((row: IVersionPool) => {
const url: string[] = []; const url: string[] = [];
for (const arch of row.arch) { for (const arch of row.arch) {
url.push(`./mc/version/${row.version}/${arch}`); url.push(`./mc/version/${row.version}/${arch}`);
arr.push({
id: row.version,
type: row.Type,
BuildType: "UWP",
Arch: ["x64", "x86"],
url,
time: row.Date,
});
} }
arr.push({
id: row.version,
type: row.Type,
BuildType: "UWP",
Arch: row.arch,
url,
time: row.Date,
});
}); });
this.versionCache = arr; this.versionCache = arr;
} }
@@ -61,6 +65,15 @@ ORDER BY "Date" DESC
) { ) {
return; return;
} }
const ver = `${id}-${arch}`
let value = this.libmap.get(ver)
if (value){
value.hits++
console.log("lib hits"+value.hits)
return {libraries:value.libraries}
}
const r = ( const r = (
await this.pool.query( await this.pool.query(
` `
@@ -75,12 +88,14 @@ LIMIT 1
) )
).rows; // 获取版本id ).rows; // 获取版本id
const data = ( const data: ILibraries[] = (
await this.pool.query( await this.pool.query(
` `
SELECT "filePathName"."pathName", SELECT "filePathName"."pathName",
"filesHash"."size", "filesHash"."size",
${this.hashList.map(hash => `encode("filesHash"."${hash}", 'hex') as "${hash}"`).join(', ')} ${this.hashList
.map((hash) => `encode("filesHash"."${hash}", 'hex') as "${hash}"`)
.join(", ")}
FROM variation_files_data FROM variation_files_data
LEFT JOIN files ON files.id = variation_files_data."filesId" LEFT JOIN files ON files.id = variation_files_data."filesId"
LEFT JOIN "filePathName" ON "filePathName".id = files."pathNameId" LEFT JOIN "filePathName" ON "filePathName".id = files."pathNameId"
@@ -89,22 +104,16 @@ WHERE variation_files_data."variationId" = $1
`, `,
[r[0].id] [r[0].id]
) )
).rows; ).rows; //获取信息
console.log(data); this.libmap.set(ver,{libraries:data,hits:0}) //初始化
return data; return { libraries: data};
}
_refreshLib(){
this.libmap.forEach((val,key)=>{
if (val.hits<15){
this.libmap.delete(key);
}
})
} }
} }
interface VersionPool {
id: number;
version: string;
Type: string;
Date: string;
arch: string;
}
interface Version {
id: string;
type: string;
url: string;
time: string;
}

View File

@@ -1,10 +1,12 @@
import express from "express"; import express from "express";
import config from "./utils/config.js"; import config from "./utils/config.js";
import versionlistRouter from "./router/versionlist.router.js"; import versionlistRouter from "./router/versionlist.router.js";
import downloadRouter from "./router/download.router.js";
const app = express(); const app = express();
app.use('/mc',versionlistRouter) app.use('/mc',versionlistRouter)
app.use('/download',downloadRouter)
app.listen(config.express.port,()=>{ app.listen(config.express.port,()=>{
console.log(`server is running on port ${config.express.port}`); console.log(`server is running on port ${config.express.port}`);
}) })

View File

@@ -0,0 +1,9 @@
import { Request, Response, NextFunction } from "express";
export function hashMiddleware(req:Request,res:Response,next:NextFunction){
if (req.params.hash.length !== 32){
res.sendStatus(400);
return;
}
next();
return;
}

View File

@@ -0,0 +1,14 @@
import { Router, Request, Response } from "express";
//import pool from "../utils/pgsql.js";
import { hashMiddleware } from "../middleware/download.mw.js";
const router = Router();
//const map = new Map<string,string>();
router.get("/:hash",hashMiddleware,(req:Request,res:Response)=>{
const hash = req.params.hash;
const hash1 = hash.substring(0,2)
res.redirect(302,`r2.cloudflare.com/${hash1}/${hash}`)
})
export default router;

View File

@@ -6,8 +6,8 @@ const versionListController = new VersionListController(pool);
const router = Router(); const router = Router();
router.get("/version_manifest", async (req: Request, res: Response) => { router.get("/version_manifest", async (req: Request, res: Response) => {
const version = await versionListController.getVersionList(); const versions = await versionListController.getVersionList();
res.status(200).json({ version }); res.status(200).json({ versions });
}); });
router.get("/version/:id/:arch", async (req: Request, res: Response) => { router.get("/version/:id/:arch", async (req: Request, res: Response) => {
@@ -18,6 +18,6 @@ router.get("/version/:id/:arch", async (req: Request, res: Response) => {
res.sendStatus(404); res.sendStatus(404);
return; return;
} }
res.status(200).json({ libraries }); res.status(200).json(libraries);
}) })
export default router; export default router;

View File

@@ -0,0 +1,27 @@
export interface IVersionPool {
id: number;
version: string;
Type: string;
Date: string;
arch: string;
}
export interface IVersion {
id: string;
type: string;
url: string;
time: string;
}
export interface ILibraries {
pathName: string;
size: number;
md5: string;
sha1: string;
sha256: string;
}
export interface ILibrariesMap {
libraries: ILibraries[];
hits: number;
}