Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
d75786b3ee | |||
8fc6010214 | |||
8efd9577e1 | |||
948cc0e983 | |||
f56784a24b |
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,5 +3,3 @@ node_modules
|
||||
public
|
||||
dist
|
||||
yarn-error.log
|
||||
|
||||
src/package.json
|
||||
|
@ -6,10 +6,9 @@ $secondaryForeground: $primaryForeground;
|
||||
$backgroundColor: darken($primary, 4%);
|
||||
$defaultTextColor: #ffffff;
|
||||
|
||||
$headerBackground: transparent;
|
||||
$headerContainer: true;
|
||||
$footerBackground: transparent;
|
||||
$panelBackground: darken($backgroundColor, 3.2%);
|
||||
$headerBackground: darken($primary, 7.5%);
|
||||
$footerBackground: lighten($headerBackground, 1%);
|
||||
$panelBackground: lighten($headerBackground, 1%);
|
||||
$inputBackground: darken($panelBackground, 4%);
|
||||
|
||||
$info: #4499ff;
|
||||
@ -30,4 +29,3 @@ $errorColor: desaturate($errorText, 50%);
|
||||
|
||||
// Responsivity
|
||||
$mobileThreshold: 632px;
|
||||
$desktopThreshold: 940px;
|
||||
|
@ -1,6 +1,5 @@
|
||||
@import "vars";
|
||||
@import 'fonts';
|
||||
@import "responsivity_tools";
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
@ -70,31 +69,21 @@ body {
|
||||
body > header {
|
||||
z-index: 50;
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
$headerHeight: 64px;
|
||||
height: $headerHeight;
|
||||
line-height: $headerHeight;
|
||||
|
||||
background: $headerBackground;
|
||||
|
||||
@if $headerContainer {
|
||||
@include container;
|
||||
}
|
||||
|
||||
@media (max-width: $mobileThreshold) {
|
||||
padding: 0;
|
||||
}
|
||||
background-color: $headerBackground;
|
||||
|
||||
.logo {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
padding: 0 16px 0 8px;
|
||||
font-size: 24px;
|
||||
padding: 0 24px 0 16px;
|
||||
font-size: 32px;
|
||||
color: $defaultTextColor;
|
||||
|
||||
&:hover {
|
||||
@ -102,48 +91,34 @@ body > header {
|
||||
}
|
||||
|
||||
img {
|
||||
width: initial;
|
||||
height: calc(#{$headerHeight} - 16px);
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
width: $headerHeight;
|
||||
height: $headerHeight;
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
nav {
|
||||
> ul {
|
||||
position: fixed;
|
||||
z-index: -1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
transform: translateX(-100%);
|
||||
transition: transform ease-out 150ms;
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
margin: 0;
|
||||
padding: $headerHeight 8px 8px;
|
||||
padding: 0;
|
||||
|
||||
font-size: 20px;
|
||||
|
||||
background: $panelBackground;
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
list-style: none;
|
||||
margin-top: 8px;
|
||||
|
||||
a, button {
|
||||
position: relative;
|
||||
height: 64px;
|
||||
margin: 0;
|
||||
padding: 0 24px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
height: auto;
|
||||
padding: 8px;
|
||||
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover, &:active {
|
||||
&:not(button) {
|
||||
@ -152,40 +127,13 @@ body > header {
|
||||
}
|
||||
|
||||
.feather {
|
||||
--icon-size: 16px;
|
||||
}
|
||||
|
||||
.tip {
|
||||
position: static;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
display: block;
|
||||
height: auto;
|
||||
margin-left: 8px;
|
||||
padding: 0 0 0 4px;
|
||||
transform: none;
|
||||
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
|
||||
color: inherit;
|
||||
text-transform: uppercase;
|
||||
font-weight: inherit;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.tip {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity ease-out 100ms;
|
||||
transition-delay: 150ms;
|
||||
}
|
||||
--icon-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
margin: 8px;
|
||||
padding: 24px;
|
||||
height: 32px;
|
||||
|
||||
.feather {
|
||||
@ -210,27 +158,45 @@ body > header {
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: initial;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
|
||||
white-space: nowrap;
|
||||
background: $headerBackground;
|
||||
border-radius: 0 0 3px 3px;
|
||||
|
||||
a {
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .dropdown {
|
||||
display: block;
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> li:not(:first-child) {
|
||||
border-top: 1px solid transparentize($defaultTextColor, 0.8);
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
&.open {
|
||||
transform: translateX(0%);
|
||||
box-shadow: 0 0 5px darken($panelBackground, 20%);
|
||||
}
|
||||
}
|
||||
|
||||
#menu-button {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $mobileThreshold) {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.logo {
|
||||
padding: 0 16px 0 8px;
|
||||
font-size: 24px;
|
||||
|
||||
img {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
nav {
|
||||
#menu-button {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0 16px;
|
||||
@ -246,32 +212,46 @@ body > header {
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-bottom: 1px solid $defaultTextColor;
|
||||
opacity: 0.2;
|
||||
> ul {
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
left: 0;
|
||||
transform: translateX(-100%);
|
||||
transition: transform ease-out 150ms;
|
||||
|
||||
background-color: $headerBackground;
|
||||
|
||||
&.open {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
|
||||
li {
|
||||
a, button {
|
||||
.tip {
|
||||
display: block;
|
||||
margin-left: 8px;
|
||||
text-transform: inherit;
|
||||
font-weight: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: initial;
|
||||
display: block;
|
||||
padding-left: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: $mobileThreshold) {
|
||||
flex-direction: row;
|
||||
|
||||
nav {
|
||||
#menu-button {
|
||||
display: none;
|
||||
nav ul li {
|
||||
a, button, .button {
|
||||
@include tip;
|
||||
}
|
||||
|
||||
ul {
|
||||
position: static;
|
||||
flex-direction: row;
|
||||
transform: none;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
|
||||
li {
|
||||
margin-top: 0;
|
||||
margin-left: 8px;
|
||||
|
||||
&:last-child {
|
||||
a, button, .button {
|
||||
.tip {
|
||||
@ -281,46 +261,11 @@ body > header {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
display: none;
|
||||
padding: 8px;
|
||||
|
||||
white-space: nowrap;
|
||||
background: $panelBackground;
|
||||
border-radius: 0 0 3px 3px;
|
||||
|
||||
box-shadow: 0 2px 2px transparentize(darken($panelBackground, 20%), 0.75);
|
||||
border-top: 4px solid lighten($panelBackground, 5%);
|
||||
|
||||
li {
|
||||
margin-left: 0;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .dropdown {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
> li:not(:first-child) {
|
||||
border-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body > footer {
|
||||
footer {
|
||||
padding: 8px;
|
||||
margin-top: 8px;
|
||||
text-align: center;
|
||||
@ -393,7 +338,7 @@ a {
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: lighten($secondary, 30%);
|
||||
color: lighten($secondary, 10%);
|
||||
}
|
||||
|
||||
.feather.feather-external-link {
|
||||
@ -639,10 +584,6 @@ button, .button {
|
||||
|
||||
&.warning {
|
||||
background-color: $warningColor;
|
||||
|
||||
&:hover {
|
||||
background-color: lighten($warningColor, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
&.error, &.danger {
|
||||
@ -662,35 +603,6 @@ button, .button {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---
|
||||
// --- Tables
|
||||
// ---
|
||||
td.actions {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
form {
|
||||
padding: 0;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
button, .button {
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
|
||||
.feather {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> *:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.data-table {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
@ -717,10 +629,6 @@ td.actions {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---
|
||||
// --- Breadcrumb widget
|
||||
// ---
|
||||
.breadcrumb {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
@ -734,7 +642,6 @@ td.actions {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---
|
||||
// --- Layout helpers
|
||||
// ---
|
||||
@ -742,6 +649,24 @@ td.actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@mixin container {
|
||||
width: $mobileThreshold;
|
||||
padding: 0 16px;
|
||||
|
||||
@media (min-width: $mobileThreshold) {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@media (max-width: $mobileThreshold) {
|
||||
width: 100%;
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
@include container;
|
||||
}
|
||||
|
||||
.panel {
|
||||
position: relative;
|
||||
margin: 16px 0 48px;
|
||||
@ -763,14 +688,10 @@ td.actions {
|
||||
}
|
||||
|
||||
.sub-panel {
|
||||
margin: 32px 0;
|
||||
margin: 32px -18px;
|
||||
padding: 1px 16px;
|
||||
border: 2px solid lighten($panelBackground, 4%);
|
||||
border-radius: 5px;
|
||||
|
||||
form > & {
|
||||
margin: 32px -18px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -794,10 +715,6 @@ td.actions {
|
||||
stroke-linejoin: miter;
|
||||
fill: none;
|
||||
vertical-align: middle;
|
||||
|
||||
h1 > &, h2 > &, h3 > & {
|
||||
--icon-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
|
@ -1,19 +0,0 @@
|
||||
@import "vars";
|
||||
|
||||
@mixin container {
|
||||
width: 100%;
|
||||
padding: 0 8px;
|
||||
|
||||
@media (min-width: $mobileThreshold) {
|
||||
margin: 0 auto;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
@media (min-width: $desktopThreshold) {
|
||||
width: $desktopThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
@include container;
|
||||
}
|
@ -12,7 +12,4 @@
|
||||
cache: false,
|
||||
},
|
||||
assets_base_dir: 'downloads',
|
||||
user_redirections: [
|
||||
{from: 'arisu', to: 'ashpie'}
|
||||
],
|
||||
}
|
||||
|
@ -2,5 +2,4 @@
|
||||
log_level: "DEBUG",
|
||||
db_log_level: "ERROR",
|
||||
public_url: "https://update.eternae.ink",
|
||||
user_redirections: [],
|
||||
}
|
||||
|
30
package.json
30
package.json
@ -1,32 +1,31 @@
|
||||
{
|
||||
"name": "eternae.ink.update",
|
||||
"version": "1.3.0",
|
||||
"version": "1.2.0",
|
||||
"description": "A simple redirection to serve a gitea instance's repositories' latest release files as an http file server. (302 redirections)",
|
||||
"repository": "https://eternae.ink/arisu/update.eternae.ink",
|
||||
"author": "Alice Gaudon <alice@gaudon.pro>",
|
||||
"main": "dist/main.js",
|
||||
"main": "dist/src/main.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "jest --verbose --runInBand",
|
||||
"dist-webpack": "webpack --mode production",
|
||||
"clean": "(test ! -d dist || rm -r dist)",
|
||||
"prepareSources": "cp package.json src/",
|
||||
"compile": "yarn clean && tsc",
|
||||
"build": "yarn prepareSources && yarn compile && webpack --mode production",
|
||||
"dev": "yarn prepareSources && concurrently -k -n \"Typescript,Node,Webpack,Maildev\" -p \"[{name}]\" -c \"blue,green,red,yellow\" \"tsc --watch\" \"nodemon\" \"webpack --watch --mode development\" \"maildev\"",
|
||||
"start": "yarn build && node",
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx"
|
||||
"build": "yarn compile && yarn dist-webpack",
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
|
||||
"dev": "concurrently -k -n \"Typescript,Node,Webpack,Maildev\" -p \"[{name}]\" -c \"blue,green,red,yellow\" \"tsc --watch\" \"nodemon\" \"webpack --watch --mode development\" \"maildev\"",
|
||||
"start": "yarn build && node dist/src/main.js",
|
||||
"test": "jest --verbose --runInBand"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.9.0",
|
||||
"@babel/preset-env": "^7.9.5",
|
||||
"@fortawesome/fontawesome-free": "^5.14.0",
|
||||
"@types/config": "^0.0.38",
|
||||
"@types/config": "^0.0.36",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/express-session": "^1.17.0",
|
||||
"@types/feather-icons": "^4.7.0",
|
||||
"@types/formidable": "^1.0.31",
|
||||
"@types/jest": "^26.0.4",
|
||||
"@types/mime": "^2.0.3",
|
||||
"@types/mysql": "^2.15.15",
|
||||
"@types/node": "^14.6.3",
|
||||
"@types/nodemailer": "^6.4.0",
|
||||
@ -35,7 +34,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "^4.3.0",
|
||||
"@typescript-eslint/parser": "^4.3.0",
|
||||
"babel-loader": "^8.1.0",
|
||||
"concurrently": "^6.0.0",
|
||||
"concurrently": "^5.1.0",
|
||||
"css-loader": "^5.0.0",
|
||||
"eslint": "^7.10.0",
|
||||
"feather-icons": "^4.28.0",
|
||||
@ -44,14 +43,13 @@
|
||||
"imagemin-gifsicle": "^7.0.0",
|
||||
"imagemin-mozjpeg": "^9.0.0",
|
||||
"imagemin-pngquant": "^9.0.0",
|
||||
"imagemin-svgo": "^9.0.0",
|
||||
"imagemin-svgo": "^8.0.0",
|
||||
"img-loader": "^3.0.1",
|
||||
"jest": "^26.1.0",
|
||||
"maildev": "^1.1.0",
|
||||
"mini-css-extract-plugin": "^1.2.1",
|
||||
"node-sass": "^5.0.0",
|
||||
"nodemon": "^2.0.3",
|
||||
"sass-loader": "^11.0.1",
|
||||
"sass-loader": "^10.0.1",
|
||||
"terser-webpack-plugin": "^5.0.3",
|
||||
"ts-jest": "^26.1.1",
|
||||
"ts-loader": "^8.0.4",
|
||||
@ -62,8 +60,6 @@
|
||||
"dependencies": {
|
||||
"config": "^3.3.1",
|
||||
"express": "^4.17.1",
|
||||
"mime": "^2.4.6",
|
||||
"send-ranges": "^4.0.0",
|
||||
"swaf": "^0.23.0"
|
||||
"swaf": "^0.22.5"
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import ExpressAppComponent from "swaf/components/ExpressAppComponent";
|
||||
import LogRequestsComponent from "swaf/components/LogRequestsComponent";
|
||||
import GiteaRepoLatestReleaseController from "./controllers/GiteaRepoLatestReleaseController";
|
||||
import NunjucksComponent from "swaf/components/NunjucksComponent";
|
||||
import packageJson = require('./package.json');
|
||||
import packageJson = require('../package.json');
|
||||
|
||||
export default class App extends Application {
|
||||
public constructor(
|
||||
|
@ -2,14 +2,11 @@ import Controller from "swaf/Controller";
|
||||
import {NextFunction, Request, Response} from "express";
|
||||
import * as https from "https";
|
||||
import config from "config";
|
||||
import {NotFoundHttpError, ServiceUnavailableHttpError} from "swaf/HttpError";
|
||||
import {log} from "swaf/Logger";
|
||||
import {NotFoundHttpError} from "swaf/HttpError";
|
||||
import * as fs from "fs";
|
||||
import {promisify} from "util";
|
||||
import path from "path";
|
||||
import sendRanges, {SendRangeGetStreamFn} from "send-ranges";
|
||||
import mime from "mime";
|
||||
import {logger} from "swaf/Logger";
|
||||
import {ParsedUrlQueryInput} from "querystring";
|
||||
|
||||
export const ASSETS_BASE_DIR = config.get<string>('assets_base_dir');
|
||||
|
||||
@ -19,18 +16,10 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
||||
}
|
||||
|
||||
protected async getFile(req: Request, res: Response, next: NextFunction): Promise<void> {
|
||||
logger.info('Serving ' + req.path + ' ...');
|
||||
log.info('Serving ' + req.path + ' ...');
|
||||
const {owner, name, file} = req.params;
|
||||
if (!owner || !name) return next();
|
||||
|
||||
// User redirections
|
||||
const userRedirections = config.get<{ from: string, to: string }[]>('user_redirections');
|
||||
for (const redirection of userRedirections) {
|
||||
if (owner === redirection.from) {
|
||||
return res.redirect(Controller.route('get-repo-release-file', [redirection.to, name, file], req.query as ParsedUrlQueryInput));
|
||||
}
|
||||
}
|
||||
|
||||
const httpRequest = https.get(`${config.get('gitea_instance_url')}/api/v1/repos/${owner}/${name}/releases`, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
@ -41,8 +30,6 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
||||
data += c;
|
||||
});
|
||||
r.on('end', async () => {
|
||||
if (r.statusCode === 404) return next(new NotFoundHttpError('file', req.url));
|
||||
|
||||
try {
|
||||
const releases = JSON.parse(data);
|
||||
|
||||
@ -50,7 +37,7 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
||||
for (const release of releases) {
|
||||
for (const asset of release.assets) {
|
||||
if (asset.name === file) {
|
||||
logger.debug('Download', asset.browser_download_url);
|
||||
log.debug('Download', asset.browser_download_url);
|
||||
return await this.download(req, res, next, {
|
||||
repo: {
|
||||
owner: owner,
|
||||
@ -68,7 +55,7 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
||||
}
|
||||
throw new NotFoundHttpError('Asset', req.url);
|
||||
} else {
|
||||
logger.debug('List files');
|
||||
log.debug('List files');
|
||||
return res.render('list-files', {
|
||||
owner: owner,
|
||||
name: name,
|
||||
@ -81,7 +68,7 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
||||
});
|
||||
});
|
||||
httpRequest.on('error', err => {
|
||||
logger.error(err);
|
||||
log.error(err);
|
||||
});
|
||||
httpRequest.end();
|
||||
}
|
||||
@ -98,16 +85,11 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
||||
}
|
||||
|
||||
const assetPath = path.resolve(ASSETS_BASE_DIR, '' + downloadProperties.asset.id);
|
||||
const tmpAssetPath = assetPath + '.tmp';
|
||||
|
||||
// Download asset if it doesn't exist
|
||||
if (!await promisify(fs.exists)(assetPath)) {
|
||||
if (await promisify(fs.exists)(tmpAssetPath)) {
|
||||
throw new ServiceUnavailableHttpError('This file is currently being cached. Please try again later.');
|
||||
}
|
||||
|
||||
const file = fs.createWriteStream(tmpAssetPath);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const file = fs.createWriteStream(assetPath);
|
||||
await new Promise((resolve, reject) => {
|
||||
const httpRequest = https.get(downloadProperties.asset.url, res => {
|
||||
res.on('end', () => {
|
||||
resolve();
|
||||
@ -120,28 +102,10 @@ export default class GiteaRepoLatestReleaseController extends Controller {
|
||||
httpRequest.end();
|
||||
});
|
||||
file.close();
|
||||
await promisify(fs.rename)(tmpAssetPath, assetPath);
|
||||
}
|
||||
|
||||
logger.debug('Download', assetPath, downloadProperties.asset.name);
|
||||
|
||||
sendRanges(async _ => {
|
||||
const filePath = assetPath;
|
||||
const getStream: SendRangeGetStreamFn = range => fs.createReadStream(filePath, range);
|
||||
const type = mime.getType(downloadProperties.asset.name) || 'application/json';
|
||||
const stats = await promisify(fs.stat)(filePath);
|
||||
|
||||
return {getStream, type, size: stats.size};
|
||||
}, {
|
||||
maxRanges: 1024,
|
||||
})(req, res, (err: unknown) => {
|
||||
if (err) return next(err);
|
||||
|
||||
logger.info('Fallback to express download.');
|
||||
|
||||
// Respond
|
||||
return res.download(assetPath, downloadProperties.asset.name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,25 +0,0 @@
|
||||
import Controller from "swaf/Controller";
|
||||
import {Request, Response} from "express";
|
||||
|
||||
export default class HomeController extends Controller {
|
||||
public routes(): void {
|
||||
this.get('/', this.getHome, 'home');
|
||||
this.get('/about', this.getAbout, 'about');
|
||||
this.get('/back', this.goBack, 'about');
|
||||
}
|
||||
|
||||
protected async getHome(req: Request, res: Response): Promise<void> {
|
||||
res.render('home');
|
||||
}
|
||||
|
||||
protected async getAbout(req: Request, res: Response): Promise<void> {
|
||||
res.render('about');
|
||||
}
|
||||
|
||||
/**
|
||||
* This is to test and assert that swaf extended types are available
|
||||
*/
|
||||
protected async goBack(req: Request, res: Response): Promise<void> {
|
||||
res.redirect(req.getPreviousUrl() || Controller.route('home'));
|
||||
}
|
||||
}
|
10
src/main.ts
10
src/main.ts
@ -2,19 +2,19 @@ import {delimiter} from "path";
|
||||
|
||||
// Load config from specified path or default + swaf/config (default defaults)
|
||||
process.env['NODE_CONFIG_DIR'] =
|
||||
__dirname + '/../node_modules/swaf/config/'
|
||||
__dirname + '/../../node_modules/swaf/config/'
|
||||
+ delimiter
|
||||
+ (process.env['NODE_CONFIG_DIR'] || __dirname + '/../config/');
|
||||
+ (process.env['NODE_CONFIG_DIR'] || __dirname + '/../../config/');
|
||||
|
||||
import {logger} from "swaf/Logger";
|
||||
import {log} from "swaf/Logger";
|
||||
import App from "./App";
|
||||
import config from "config";
|
||||
|
||||
(async () => {
|
||||
logger.debug('Config path:', process.env['NODE_CONFIG_DIR']);
|
||||
log.debug('Config path:', process.env['NODE_CONFIG_DIR']);
|
||||
|
||||
const app = new App(config.get<string>('listen_addr'), config.get<number>('port'));
|
||||
await app.start();
|
||||
})().catch(err => {
|
||||
logger.error(err);
|
||||
log.error(err);
|
||||
});
|
||||
|
24
src/types/send-ranges.d.ts
vendored
24
src/types/send-ranges.d.ts
vendored
@ -1,24 +0,0 @@
|
||||
declare module 'send-ranges' {
|
||||
import {NextFunction, Request, RequestHandler} from "express";
|
||||
import {ReadStream} from "fs";
|
||||
export default function (
|
||||
fetchStream: ((req: Request) => Promise<SendRangeParams | null>),
|
||||
options: SendRangeOptions = {},
|
||||
): RequestHandler;
|
||||
|
||||
export type SendRangeOptions = {
|
||||
beforeSend?: (info, next: NextFunction) => void,
|
||||
maxRanges?: number,
|
||||
};
|
||||
|
||||
export type SendRangeParams = {
|
||||
getStream: SendRangeGetStreamFn;
|
||||
type: string;
|
||||
size: number;
|
||||
};
|
||||
|
||||
export type SendRangeGetStreamFn = (range: {
|
||||
start?: number;
|
||||
end?: number;
|
||||
}) => ReadStream;
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "public/js",
|
||||
"rootDir": "./assets",
|
||||
"target": "ES6",
|
||||
"strict": true,
|
||||
"lib": [
|
||||
|
@ -3,7 +3,6 @@
|
||||
"module": "CommonJS",
|
||||
"esModuleInterop": true,
|
||||
"outDir": "dist",
|
||||
"rootDir": "./src",
|
||||
"target": "ES6",
|
||||
"strict": true,
|
||||
"lib": [
|
||||
|
Loading…
Reference in New Issue
Block a user