Merge branch 'master' into licenseDev2

This commit is contained in:
jessopb 2019-02-26 03:32:34 -05:00 committed by GitHub
commit b107346c28
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 148 additions and 61 deletions

View file

@ -47,6 +47,7 @@ For a closed, custom-hosted and branded example, check out https://lbry.theantim
- `./lbrynet account_balance` gets your balance (initially 0.0) - `./lbrynet account_balance` gets your balance (initially 0.0)
- `./lbrynet address_list` gets addresses you can use to recieve LBC - `./lbrynet address_list` gets addresses you can use to recieve LBC
- [FFmpeg](https://www.ffmpeg.org/download.html) - [FFmpeg](https://www.ffmpeg.org/download.html)
- [ImageMagick](https://packages.ubuntu.com/xenial/graphics/imagemagick)
- Spee.ch (below) - Spee.ch (below)
- pm2 (optional) process manager such as pm2 to run speech server.js - pm2 (optional) process manager such as pm2 to run speech server.js
- http proxy server e.g. caddy, nginx, or traefik, to forward 80/443 to speech port 3000 - http proxy server e.g. caddy, nginx, or traefik, to forward 80/443 to speech port 3000
@ -260,9 +261,11 @@ Spee.ch has a few types of URL formats that return different assets from the LBR
- retrieve the controlling `LBRY` claim: - retrieve the controlling `LBRY` claim:
- https://spee.ch/`claim` - https://spee.ch/`claim`
- https://spee.ch/`claim`.`ext` (serve) - https://spee.ch/`claim`.`ext` (serve)
- https://spee.ch/`claim`.`ext`&`querystring` (serve transformed)
- retrieve a specific `LBRY` claim: - retrieve a specific `LBRY` claim:
- https://spee.ch/`claim_id`/`claim` - https://spee.ch/`claim_id`/`claim`
- https://spee.ch/`claim_id`/`claim`.`ext` (serve) - https://spee.ch/`claim_id`/`claim`.`ext` (serve)
- https://spee.ch/`claim_id`/`claim`.`ext`&`querystring` (serve transformed)
- retrieve all contents for the controlling `LBRY` channel - retrieve all contents for the controlling `LBRY` channel
- https://spee.ch/`@channel` - https://spee.ch/`@channel`
- a specific `LBRY` channel - a specific `LBRY` channel
@ -270,9 +273,15 @@ Spee.ch has a few types of URL formats that return different assets from the LBR
- retrieve a specific claim within the controlling `LBRY` channel - retrieve a specific claim within the controlling `LBRY` channel
- https://spee.ch/`@channel`/`claim` - https://spee.ch/`@channel`/`claim`
- https://spee.ch/`@channel`/`claim`.`ext` (serve) - https://spee.ch/`@channel`/`claim`.`ext` (serve)
- https://spee.ch/`@channel`/`claim`.`ext`&`querystring` (serve)
- retrieve a specific claim within a specific `LBRY` channel - retrieve a specific claim within a specific `LBRY` channel
- https://spee.ch/`@channel`:`channel_id`/`claim` - https://spee.ch/`@channel`:`channel_id`/`claim`
- https://spee.ch/`@channel`:`channel_id`/`claim`.`ext` (serve) - https://spee.ch/`@channel`:`channel_id`/`claim`.`ext` (serve)
- https://spee.ch/`@channel`:`channel_id`/`claim`.`ext`&`querystring` (serve)
- `querystring` can include the following transformation values separated by `&`
- h=`number` (defines height)
- w=`number` (defines width)
- t=`crop` or `stretch` (defines transformation - missing implies constrained proportions)
### Dependencies ### Dependencies

0
changelog.md Normal file
View file

View file

@ -49,6 +49,10 @@
} }
}, },
"serving": { "serving": {
"dynamicFileSizing": {
"enabled": true,
"maxDimension": 2000
},
"markdownSettings": { "markdownSettings": {
"skipHtmlMain": true, "skipHtmlMain": true,
"escapeHtmlMain": true, "escapeHtmlMain": true,
@ -83,10 +87,7 @@
"code", "code",
"html", "html",
"parsedHtml" "parsedHtml"
], ]
"disallowedTypesMain": [],
"disallowedTypesDescriptions": ["image", "html"],
"disallowedTypesExample": ["image", "html"]
}, },
"customFileExtensions": { "customFileExtensions": {
"application/x-troff-man": "man", "application/x-troff-man": "man",

View file

@ -26,7 +26,6 @@ PUBLISHING:
"primaryClaimAddress": null, - generally supplied by your lbrynet sdk "primaryClaimAddress": null, - generally supplied by your lbrynet sdk
"uploadDirectory": "/home/lbry/Uploads", - lbrynet sdk will know your uploads are here "uploadDirectory": "/home/lbry/Uploads", - lbrynet sdk will know your uploads are here
"lbrynetHome": "/home/lbry",
"thumbnailChannel": null, - when publishing non-image content, thumbnails will go here. "thumbnailChannel": null, - when publishing non-image content, thumbnails will go here.
"thumbnailChannelId": null, "thumbnailChannelId": null,
"additionalClaimAddresses": [], "additionalClaimAddresses": [],
@ -53,6 +52,10 @@ PUBLISHING:
SERVING: SERVING:
"dynamicFileSizing": {
"enabled": false, - if you choose to allow your instance to serve transform images
"maxDimension": 2000 - the maximum size you allow transform to scale
},
"markdownSettings": { "markdownSettings": {
"skipHtmlMain": true, - false: render html, in a somewhat unpredictable way~ "skipHtmlMain": true, - false: render html, in a somewhat unpredictable way~
"escapeHtmlMain": true, - true: rather than render html, escape it and print it visibly "escapeHtmlMain": true, - true: rather than render html, escape it and print it visibly

View file

@ -1,11 +1,13 @@
const { getClaim } = require('../../../../lbrynet'); const { getClaim } = require('../../../../lbrynet');
const { createFileRecordDataAfterGet } = require('../../../../models/utils/createFileRecordData.js'); const {
createFileRecordDataAfterGet,
} = require('../../../../models/utils/createFileRecordData.js');
const { handleErrorResponse } = require('../../../utils/errorHandlers.js'); const { handleErrorResponse } = require('../../../utils/errorHandlers.js');
const getClaimData = require('server/utils/getClaimData'); const getClaimData = require('server/utils/getClaimData');
const chainquery = require('chainquery').default; const chainquery = require('chainquery').default;
const db = require('../../../../models'); const db = require('../../../../models');
const waitOn = require('wait-on');
const logger = require('winston'); const logger = require('winston');
const awaitFileSize = require('server/utils/awaitFileSize');
/* /*
@ -36,11 +38,11 @@ const claimGet = async ({ ip, originalUrl, params }, res) => {
if (!claimData) { if (!claimData) {
throw new Error('claim/get: getClaimData failed to get file blobs'); throw new Error('claim/get: getClaimData failed to get file blobs');
} }
await waitOn({ let fileReady = await awaitFileSize(lbrynetResult.download_path, 2000000, 10000, 250);
resources: [ lbrynetResult.download_path ],
timeout : 10000, // 10 seconds if (fileReady !== 'ready') {
window : 500, throw new Error('claim/get: failed to get file after 10 seconds');
}); }
const fileData = await createFileRecordDataAfterGet(claimData, lbrynetResult); const fileData = await createFileRecordDataAfterGet(claimData, lbrynetResult);
if (!fileData) { if (!fileData) {
throw new Error('claim/get: createFileRecordDataAfterGet failed to create file in time'); throw new Error('claim/get: createFileRecordDataAfterGet failed to create file in time');

View file

@ -1,6 +1,12 @@
const logger = require('winston'); const logger = require('winston');
const transformImage = require('./transformImage'); const transformImage = require('./transformImage');
const isValidQueryObject = require('server/utils/isValidQueryObj');
const {
serving: { dynamicFileSizing },
} = require('@config/siteConfig');
const { enabled: dynamicEnabled } = dynamicFileSizing;
const serveFile = async ({ filePath, fileType }, res, originalUrl) => { const serveFile = async ({ filePath, fileType }, res, originalUrl) => {
const queryObject = {}; const queryObject = {};
// TODO: replace quick/dirty try catch with better practice // TODO: replace quick/dirty try catch with better practice
@ -22,7 +28,10 @@ const serveFile = async ({ filePath, fileType }, res, originalUrl) => {
let mediaType = fileType ? fileType.substr(0, fileType.indexOf('/')) : ''; let mediaType = fileType ? fileType.substr(0, fileType.indexOf('/')) : '';
const transform = const transform =
mediaType === 'image' && queryObject.hasOwnProperty('h') && queryObject.hasOwnProperty('w'); mediaType === 'image' &&
queryObject.hasOwnProperty('h') &&
queryObject.hasOwnProperty('w') &&
dynamicEnabled;
const sendFileOptions = { const sendFileOptions = {
headers: { headers: {
@ -33,7 +42,16 @@ const serveFile = async ({ filePath, fileType }, res, originalUrl) => {
}, },
}; };
logger.debug(`fileOptions for ${filePath}:`, sendFileOptions); logger.debug(`fileOptions for ${filePath}:`, sendFileOptions);
try {
if (transform) { if (transform) {
if (!isValidQueryObject(queryObject)) {
logger.debug(`Unacceptable querystring`, { queryObject });
res.status(400).json({
success: false,
message: 'Querystring may not have dimensions greater than 2000',
});
res.end();
}
logger.debug(`transforming and sending file`); logger.debug(`transforming and sending file`);
let xformed = await transformImage(filePath, queryObject); let xformed = await transformImage(filePath, queryObject);
@ -42,6 +60,9 @@ const serveFile = async ({ filePath, fileType }, res, originalUrl) => {
} else { } else {
res.status(200).sendFile(filePath, sendFileOptions); res.status(200).sendFile(filePath, sendFileOptions);
} }
} catch (e) {
logger.debug(e);
}
}; };
module.exports = serveFile; module.exports = serveFile;

View file

@ -0,0 +1,27 @@
const fs = require('fs');
const { promisify } = require('util');
const fsstat = promisify(fs.stat);
const awaitFileSize = (path, sizeInBytes, timeout, interval) => {
return new Promise((resolve, reject) => {
let totalTime = 0;
let timer = setInterval(() => {
totalTime = totalTime + interval;
fsstat(path)
.then(stats => {
if (stats.size > sizeInBytes) {
clearInterval(interval);
resolve('ready');
}
if (totalTime > timeout) {
const error = new Error('File did not arrive in time');
error.name = 'FILE_NOT_ARRIVED';
reject(error);
}
})
.catch();
}, interval);
});
};
module.exports = awaitFileSize;

View file

@ -0,0 +1,24 @@
const {
serving: { dynamicFileSizing },
} = require('@config/siteConfig');
const { maxDimension } = dynamicFileSizing;
const isValidQueryObj = queryObj => {
let {
h: cHeight = null,
w: cWidth = null,
t: transform = null,
x: xOrigin = null,
y: yOrigin = null,
} = queryObj;
return (
((cHeight <= maxDimension && cHeight > 0) || cHeight === null) &&
((cWidth <= maxDimension && cWidth > 0) || cWidth === null) &&
(transform === null || transform === 'crop' || transform === 'stretch') &&
((xOrigin <= maxDimension && xOrigin >= 0) || xOrigin === null) &&
((yOrigin <= maxDimension && yOrigin >= 0) || yOrigin === null)
);
};
module.exports = isValidQueryObj;