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: {
|
||||
cache: false,
|
||||
},
|
||||
assets_base_dir: 'downloads',
|
||||
}
|
||||
|
@ -4,6 +4,11 @@ import * as https from "https";
|
||||
import config from "config";
|
||||
import {log} from "swaf/Logger";
|
||||
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 {
|
||||
public routes(): void {
|
||||
@ -15,7 +20,7 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
||||
const {owner, name, file} = req.params;
|
||||
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: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
@ -24,7 +29,7 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
||||
r.on('data', c => {
|
||||
data += c;
|
||||
});
|
||||
r.on('end', () => {
|
||||
r.on('end', async () => {
|
||||
try {
|
||||
const releases = JSON.parse(data);
|
||||
|
||||
@ -32,8 +37,19 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
||||
for (const release of releases) {
|
||||
for (const asset of release.assets) {
|
||||
if (asset.name === file) {
|
||||
log.debug('Redirect to', asset.browser_download_url);
|
||||
return res.redirect(302, asset.browser_download_url);
|
||||
log.debug('Download', 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);
|
||||
}
|
||||
});
|
||||
}).on('error', err => {
|
||||
});
|
||||
httpRequest.on('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