Change redirection to caching local copy and then serving download
i.e. this allows clients to request partial downloads with range headers
This commit is contained in:
parent
92c1a2ac07
commit
20d276cd10
@ -11,4 +11,5 @@
|
|||||||
view: {
|
view: {
|
||||||
cache: false,
|
cache: false,
|
||||||
},
|
},
|
||||||
|
assets_base_dir: 'downloads',
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,11 @@ import * as https from "https";
|
|||||||
import config from "config";
|
import config from "config";
|
||||||
import {log} from "swaf/Logger";
|
import {log} from "swaf/Logger";
|
||||||
import {NotFoundHttpError} from "swaf/HttpError";
|
import {NotFoundHttpError} from "swaf/HttpError";
|
||||||
|
import * as fs from "fs";
|
||||||
|
import {promisify} from "util";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
export const ASSETS_BASE_DIR = config.get<string>('assets_base_dir');
|
||||||
|
|
||||||
export default class GiteaRepoLatestReleaseController extends Controller {
|
export default class GiteaRepoLatestReleaseController extends Controller {
|
||||||
public routes(): void {
|
public routes(): void {
|
||||||
@ -15,7 +20,7 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
|||||||
const {owner, name, file} = req.params;
|
const {owner, name, file} = req.params;
|
||||||
if (!owner || !name) return next();
|
if (!owner || !name) return next();
|
||||||
|
|
||||||
https.get(`${config.get('gitea_instance_url')}/api/v1/repos/${owner}/${name}/releases`, {
|
const httpRequest = https.get(`${config.get('gitea_instance_url')}/api/v1/repos/${owner}/${name}/releases`, {
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
},
|
},
|
||||||
@ -24,7 +29,7 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
|||||||
r.on('data', c => {
|
r.on('data', c => {
|
||||||
data += c;
|
data += c;
|
||||||
});
|
});
|
||||||
r.on('end', () => {
|
r.on('end', async () => {
|
||||||
try {
|
try {
|
||||||
const releases = JSON.parse(data);
|
const releases = JSON.parse(data);
|
||||||
|
|
||||||
@ -32,8 +37,19 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
|||||||
for (const release of releases) {
|
for (const release of releases) {
|
||||||
for (const asset of release.assets) {
|
for (const asset of release.assets) {
|
||||||
if (asset.name === file) {
|
if (asset.name === file) {
|
||||||
log.debug('Redirect to', asset.browser_download_url);
|
log.debug('Download', asset.browser_download_url);
|
||||||
return res.redirect(302, asset.browser_download_url);
|
return await this.download(req, res, next, {
|
||||||
|
repo: {
|
||||||
|
owner: owner,
|
||||||
|
name: name,
|
||||||
|
},
|
||||||
|
asset: {
|
||||||
|
id: asset.id,
|
||||||
|
name: asset.name,
|
||||||
|
url: asset.browser_download_url,
|
||||||
|
size: asset.size,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,8 +66,58 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
|||||||
return next(e);
|
return next(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).on('error', err => {
|
});
|
||||||
|
httpRequest.on('error', err => {
|
||||||
log.error(err);
|
log.error(err);
|
||||||
});
|
});
|
||||||
|
httpRequest.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async download(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction,
|
||||||
|
downloadProperties: DownloadProperties,
|
||||||
|
): Promise<void> {
|
||||||
|
// Make base dir
|
||||||
|
if (!await promisify(fs.exists)(ASSETS_BASE_DIR)) {
|
||||||
|
await promisify(fs.mkdir)(ASSETS_BASE_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
const assetPath = path.resolve(ASSETS_BASE_DIR, '' + downloadProperties.asset.id);
|
||||||
|
|
||||||
|
// Download asset if it doesn't exist
|
||||||
|
if (!await promisify(fs.exists)(assetPath)) {
|
||||||
|
const file = fs.createWriteStream(assetPath);
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
const httpRequest = https.get(downloadProperties.asset.url, res => {
|
||||||
|
res.on('end', () => {
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
res.pipe(file);
|
||||||
|
});
|
||||||
|
httpRequest.on('error', () => {
|
||||||
|
reject();
|
||||||
|
});
|
||||||
|
httpRequest.end();
|
||||||
|
});
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Respond
|
||||||
|
return res.download(assetPath, downloadProperties.asset.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type DownloadProperties = {
|
||||||
|
repo: {
|
||||||
|
owner: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
asset: {
|
||||||
|
id: string,
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
size: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user