updated routes to handle serves only and return to client for show requests

This commit is contained in:
bill bittner 2018-01-31 19:12:54 -08:00
parent 37442cd9e6
commit 0e88bb4c60
9 changed files with 165 additions and 132 deletions

View file

@ -55,14 +55,14 @@ module.exports = {
claimId,
};
},
parseName: function (name) {
logger.debug('parsing name:', name);
parseClaim: function (claim) {
logger.debug('parsing name:', claim);
const componentsRegex = new RegExp(
'([^:$#/.]*)' + // name (stops at the first modifier)
'([:$#.]?)([^/]*)' // modifier separator, modifier (stops at the first path separator or end)
);
const [proto, claimName, modifierSeperator, modifier] = componentsRegex
.exec(name)
.exec(claim)
.map(match => match || null);
logger.debug(`${proto}, ${claimName}, ${modifierSeperator}, ${modifier}`);
@ -75,7 +75,6 @@ module.exports = {
throw new Error(`Invalid characters in claim name: ${nameBadChars.join(', ')}.`);
}
// Validate and process modifier
let isServeRequest = false;
if (modifierSeperator) {
if (!modifier) {
throw new Error(`No file extension provided after separator ${modifierSeperator}.`);
@ -83,11 +82,29 @@ module.exports = {
if (modifierSeperator !== '.') {
throw new Error(`The ${modifierSeperator} modifier is not supported in the claim name`);
}
isServeRequest = true;
}
// return results
return {
claimName,
isServeRequest,
};
},
parseModifier: function (claim) {
logger.debug('parsing modifier:', claim);
const componentsRegex = new RegExp(
'([^:$#/.]*)' + // name (stops at the first modifier)
'([:$#.]?)([^/]*)' // modifier separator, modifier (stops at the first path separator or end)
);
const [proto, claimName, modifierSeperator, modifier] = componentsRegex
.exec(claim)
.map(match => match || null);
logger.debug(`${proto}, ${claimName}, ${modifierSeperator}, ${modifier}`);
// Validate and process modifier
let hasFileExtension = false;
if (modifierSeperator) {
hasFileExtension = true;
}
return {
hasFileExtension,
};
},
};

View file

@ -1,9 +1,9 @@
import React from 'react';
const AssetDisplay = ({ claimName, claimId }) => {
const AssetDisplay = ({ name, claimId }) => {
return (
<div>
<p>display {claimName}#{claimId} here</p>
<p>display {name}#{claimId} here</p>
</div>
);
};

View file

@ -54,7 +54,7 @@ class AssetInfo extends React.Component {
<div className="row row--padded row--wide row--no-top">
<div id="show-short-link">
<div className="column column--2 column--med-10">
<a className="link--primary" href={`/${this.props.shortId}/${this.props.name}.${this.props.fileExt}`}><span
<a className="link--primary" href={`/${this.props.shortClaimId}/${this.props.name}.${this.props.fileExt}`}><span
className="text">Link:</span></a>
</div>
<div className="column column--8 column--med-10">
@ -63,7 +63,7 @@ class AssetInfo extends React.Component {
<div className="input-error" id="input-error-copy-short-link" hidden="true">error here</div>
<input type="text" id="short-link" className="input-disabled input-text--full-width" readOnly
spellCheck="false"
value={`${this.props.host}/${this.props.shortId}/${this.props.name}.${this.props.fileExt}`}
value={`${this.props.host}/${this.props.shortClaimId}/${this.props.name}.${this.props.fileExt}`}
onClick={this.select}/>
</div>
<div className="column column--1"> </div>
@ -114,13 +114,13 @@ class AssetInfo extends React.Component {
<div
className="row row--short row--wide flex-container--row flex-container--space-between-bottom flex-container--wrap">
<a className="link--primary" target="_blank"
href={`https://twitter.com/intent/tweet?text=${this.props.host}/${this.props.shortId}/${this.props.name}`}>twitter</a>
href={`https://twitter.com/intent/tweet?text=${this.props.host}/${this.props.shortClaimId}/${this.props.name}`}>twitter</a>
<a className="link--primary" target="_blank"
href={`https://www.facebook.com/sharer/sharer.php?u=${this.props.host}/${this.props.shortId}/${this.props.name}`}>facebook</a>
href={`https://www.facebook.com/sharer/sharer.php?u=${this.props.host}/${this.props.shortClaimId}/${this.props.name}`}>facebook</a>
<a className="link--primary" target="_blank"
href={`http://tumblr.com/widgets/share/tool?canonicalUrl=${this.props.host}/${this.props.shortId}/${this.props.name}`}>tumblr</a>
href={`http://tumblr.com/widgets/share/tool?canonicalUrl=${this.props.host}/${this.props.shortClaimId}/${this.props.name}`}>tumblr</a>
<a className="link--primary" target="_blank"
href={`https://www.reddit.com/submit?url=${this.props.host}/${this.props.shortId}/${this.props.name}&title=${this.props.name}`}>reddit</a>
href={`https://www.reddit.com/submit?url=${this.props.host}/${this.props.shortClaimId}/${this.props.name}&title=${this.props.name}`}>reddit</a>
</div>
</div>
</div>
@ -168,6 +168,6 @@ class AssetInfo extends React.Component {
};
// required props
// {channelName, certificateId, description, shortId, name, fileExt, claimId, contentType, thumbnail, host}
// {channelName, certificateId, description, shortClaimId, name, fileExt, claimId, contentType, thumbnail, host}
export default AssetInfo;

View file

@ -0,0 +1,20 @@
import React from 'react';
import NavBar from 'containers/NavBar';
class ErrorPage extends React.Component {
render () {
return (
<div>
<NavBar/>
<div className="row row--padded">
<p>{this.props.error}</p>
</div>
</div>
);
}
};
// required props
// error
export default ErrorPage;

View file

@ -1,6 +1,6 @@
import React from 'react';
import ShowLite from 'components/ShowAssetLite';
import ShowDetails from 'components/ShowAssetDetails';
import ShowAssetLite from 'components/ShowAssetLite';
import ShowAssetDetails from 'components/ShowAssetDetails';
import request from 'utils/request';
class ShowAsset extends React.Component {
@ -83,14 +83,14 @@ class ShowAsset extends React.Component {
render () {
if (this.props.isServeRequest) {
return (
<ShowLite
<ShowAssetLite
error={this.state.error}
claimData={this.state.claimData}
/>
);
}
return (
<ShowDetails
<ShowAssetDetails
error={this.state.error}
claimData={this.state.claimData}
/>

View file

@ -13,7 +13,9 @@ class ShowDetails extends React.Component {
<div>
<NavBar/>
{this.props.error &&
<p>{this.props.error}</p>
<div className="row row--padded">
<p>{this.props.error}</p>
</div>
}
{this.props.claimData &&
<div className="row row--tall row--padded">
@ -23,13 +25,24 @@ class ShowDetails extends React.Component {
<div className="column column--5 column--sml-10 align-content-top">
<div className="row row--padded">
<AssetDisplay
claimName={this.props.claimData.name}
name={this.props.claimData.name}
claimId={this.props.claimData.claimId}
/>
</div>
</div><div className="column column--5 column--sml-10 align-content-top">
<div className="row row--padded">
<AssetInfo claimId={this.props.claimData.claimId}/>
<AssetInfo
channelName={this.props.claimData.channelName}
certificateId={this.props.claimData.certificateId}
description={this.props.claimData.description}
shortClaimId={this.props.claimData.shortClaimId}
name={this.props.claimData.name}
fileExt={this.props.claimData.fileExt}
claimId={this.props.claimData.claimId}
contentType={this.props.claimData.contentType}
thumbnail={this.props.claimData.thumbnail}
host={this.props.claimData.host}
/>
</div>
</div>
</div>

View file

@ -1,4 +1,5 @@
import React from 'react';
import ErrorPage from 'components/ErrorPage';
import ShowAsset from 'components/ShowAsset';
import ShowChannel from 'components/ShowChannel';
import lbryUri from 'utils/lbryUri';
@ -10,6 +11,7 @@ class ShowPage extends React.Component {
constructor (props) {
super(props);
this.state = {
error : null,
identifier : null,
claim : null,
isServeRequest: null,
@ -46,9 +48,9 @@ class ShowPage extends React.Component {
let isChannel, channelName, channelClaimId, claimId, claimName, isServeRequest;
try {
({ isChannel, channelName, channelClaimId, claimId } = lbryUri.parseIdentifier(identifier));
({ claimName, isServeRequest } = lbryUri.parseName(claim));
({ claimName, isServeRequest } = lbryUri.parseClaim(claim));
} catch (error) {
return console.log('error:', error);
return this.setState({error: error.message});
}
// set state
return this.setState({
@ -72,7 +74,7 @@ class ShowPage extends React.Component {
try {
({ isChannel, channelName, channelClaimId } = lbryUri.parseIdentifier(claim));
} catch (error) {
return console.log('error:', error);
return this.setState({error: error.message});
}
if (isChannel) {
return this.setState({
@ -85,9 +87,9 @@ class ShowPage extends React.Component {
}
let claimName, isServeRequest;
try {
({claimName, isServeRequest} = lbryUri.parseName(claim));
({claimName, isServeRequest} = lbryUri.parseClaim(claim));
} catch (error) {
return console.log('error:', error);
return this.setState({error: error.message});
}
this.setState({
claim: {
@ -98,6 +100,11 @@ class ShowPage extends React.Component {
}
render () {
console.log('rendering ShowPage');
if (this.state.error) {
return (
<ErrorPage error={this.state.error}/>
);
}
if (this.state.claim) {
if (this.state.claim.isChannel) {
return (

View file

@ -16,18 +16,18 @@ module.exports = {
// Validate and process name
if (!value) {
throw new Error(`Check your url. No channel name provided before "${modifierSeperator}"`);
throw new Error(`Check your URL. No channel name provided before "${modifierSeperator}"`);
}
const isChannel = value.startsWith(module.exports.CHANNEL_CHAR);
const channelName = isChannel ? value : null;
let claimId;
if (isChannel) {
if (!channelName) {
throw new Error('No channel name after @.');
throw new Error('Check your URL. No channel name after "@".');
}
const nameBadChars = (channelName).match(module.exports.REGEXP_INVALID_CHANNEL);
if (nameBadChars) {
throw new Error(`Invalid characters in channel name: ${nameBadChars.join(', ')}.`);
throw new Error(`Check your URL. Invalid characters in channel name: "${nameBadChars.join(', ')}".`);
}
} else {
claimId = value;
@ -37,13 +37,13 @@ module.exports = {
let channelClaimId;
if (modifierSeperator) {
if (!modifier) {
throw new Error(`No modifier provided after separator "${modifierSeperator}"`);
throw new Error(`Check your URL. No modifier provided after separator "${modifierSeperator}"`);
}
if (modifierSeperator === ':') {
channelClaimId = modifier;
} else {
throw new Error(`The "${modifierSeperator}" modifier is not currently supported`);
throw new Error(`Check your URL. The "${modifierSeperator}" modifier is not currently supported`);
}
}
return {
@ -53,7 +53,7 @@ module.exports = {
claimId,
};
},
parseName: function (name) {
parseClaim: function (name) {
console.log('parsing name:', name);
const componentsRegex = new RegExp(
'([^:$#/.]*)' + // name (stops at the first modifier)
@ -66,20 +66,20 @@ module.exports = {
// Validate and process name
if (!claimName) {
throw new Error('No claim name provided before .');
throw new Error('Check your URL. No claim name provided before "."');
}
const nameBadChars = (claimName).match(module.exports.REGEXP_INVALID_CLAIM);
if (nameBadChars) {
throw new Error(`Invalid characters in claim name: ${nameBadChars.join(', ')}.`);
throw new Error(`Check your URL. Invalid characters in claim name: "${nameBadChars.join(', ')}".`);
}
// Validate and process modifier
let isServeRequest = false;
if (modifierSeperator) {
if (!modifier) {
throw new Error(`No file extension provided after separator ${modifierSeperator}.`);
throw new Error(`Check your URL. No file extension provided after separator "${modifierSeperator}".`);
}
if (modifierSeperator !== '.') {
throw new Error(`The ${modifierSeperator} modifier is not supported in the claim name`);
throw new Error(`Check your URL. The "${modifierSeperator}" modifier is not supported in the claim name.`);
}
isServeRequest = true;
}

View file

@ -2,13 +2,10 @@ const logger = require('winston');
const { getClaimId, getLocalFileRecord } = require('../controllers/serveController.js');
const serveHelpers = require('../helpers/serveHelpers.js');
const { handleRequestError } = require('../helpers/errorHandlers.js');
const { postToStats } = require('../helpers/statsHelpers.js');
const db = require('../models');
const lbryUri = require('../helpers/lbryUri.js');
const SERVE = 'SERVE';
const SHOW = 'SHOW';
const SHOWLITE = 'SHOWLITE';
const NO_CHANNEL = 'NO_CHANNEL';
const NO_CLAIM = 'NO_CLAIM';
const NO_FILE = 'NO_FILE';
@ -39,49 +36,23 @@ function clientWantsAsset ({accept, range}) {
return imageIsWanted || videoIsWanted;
}
function determineResponseType (isServeRequest, headers) {
function determineResponseType (hasFileExtension, headers) {
let responseType;
if (isServeRequest) {
responseType = SERVE;
if (clientAcceptsHtml(headers)) { // this is in case a serve request comes from a browser
responseType = SHOWLITE;
if (hasFileExtension) {
responseType = SERVE; // assume a serve request if file extension is present
if (clientAcceptsHtml(headers)) { // if the request comes from a browser, change it to a show request
responseType = SHOW;
}
} else {
responseType = SHOW;
if (clientWantsAsset(headers) && requestIsFromBrowser(headers)) { // this is in case someone embeds a show url
logger.debug('Show request came from browser and wants an image/video; changing response to serve.');
logger.debug('Show request came from browser but wants an image/video. Changing response to serve...');
responseType = SERVE;
}
}
return responseType;
}
// function showAssetToClient (claimId, name, res) {
// return Promise
// .all([db.Claim.resolveClaim(name, claimId), db.Claim.getShortClaimIdFromLongClaimId(claimId, name)])
// .then(([claimInfo, shortClaimId]) => {
// // logger.debug('claimInfo:', claimInfo);
// // logger.debug('shortClaimId:', shortClaimId);
// return serveHelpers.showFile(claimInfo, shortClaimId, res);
// })
// .catch(error => {
// throw error;
// });
// }
//
// function showLiteAssetToClient (claimId, name, res) {
// return Promise
// .all([db.Claim.resolveClaim(name, claimId), db.Claim.getShortClaimIdFromLongClaimId(claimId, name)])
// .then(([claimInfo, shortClaimId]) => {
// // logger.debug('claimInfo:', claimInfo);
// // logger.debug('shortClaimId:', shortClaimId);
// return serveHelpers.showFileLite(claimInfo, shortClaimId, res);
// })
// .catch(error => {
// throw error;
// });
// }
function serveAssetToClient (claimId, name, res) {
return getLocalFileRecord(claimId, name)
.then(fileInfo => {
@ -115,82 +86,87 @@ function logRequestData (responseType, claimName, channelName, claimId) {
module.exports = (app) => {
// route to serve a specific asset using the channel or claim id
app.get('/:identifier/:name', ({ headers, ip, originalUrl, params }, res) => {
let isChannel, channelName, channelClaimId, claimId, claimName, isServeRequest;
app.get('/:identifier/:claim', ({ headers, ip, originalUrl, params }, res) => {
// decide if this is a show request
let hasFileExtension;
try {
({ hasFileExtension } = lbryUri.parseModifier(params.claim));
} catch (error) {
return res.status(200).json({success: false, message: error.message});
}
let responseType = determineResponseType(hasFileExtension, headers);
if (responseType !== SERVE) {
return res.status(200).render('index');
}
// parse the claim
let claimName;
try {
({ claimName } = lbryUri.parseClaim(params.claim));
} catch (error) {
return res.status(200).json({success: false, message: error.message});
}
// parse the identifier
let isChannel, channelName, channelClaimId, claimId;
try {
({ isChannel, channelName, channelClaimId, claimId } = lbryUri.parseIdentifier(params.identifier));
({ claimName, isServeRequest } = lbryUri.parseName(params.name));
} catch (error) {
return handleRequestError(originalUrl, ip, error, res);
}
if (!isChannel) {
[claimId, claimName] = flipClaimNameAndIdForBackwardsCompatibility(claimId, claimName);
}
let responseType = determineResponseType(isServeRequest, headers);
// log the request data for debugging
logRequestData(responseType, claimName, channelName, claimId);
// if a serve request, serve, otherwise send the react app
if (responseType === SERVE) {
// get the claim Id and then serve/show the asset
getClaimId(channelName, channelClaimId, claimName, claimId)
.then(fullClaimId => {
if (fullClaimId === NO_CLAIM) {
return res.status(200).json({success: false, message: 'no claim id could be found'});
} else if (fullClaimId === NO_CHANNEL) {
return res.status(200).json({success: false, message: 'no channel id could be found'});
}
serveAssetToClient(fullClaimId, claimName, res);
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'success');
})
.catch(error => {
handleRequestError(originalUrl, ip, error, res);
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'fail');
});
} else {
res.status(200).render('index');
}
// get the claim Id and then serve the asset
getClaimId(channelName, channelClaimId, claimName, claimId)
.then(fullClaimId => {
if (fullClaimId === NO_CLAIM) {
return res.status(200).json({success: false, message: 'no claim id could be found'});
} else if (fullClaimId === NO_CHANNEL) {
return res.status(200).json({success: false, message: 'no channel id could be found'});
}
serveAssetToClient(fullClaimId, claimName, res);
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'success');
})
.catch(error => {
handleRequestError(originalUrl, ip, error, res);
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'fail');
});
});
// route to serve the winning asset at a claim or a channel page
app.get('/:identifier', ({ headers, ip, originalUrl, params, query }, res) => {
let isChannel, channelName, channelClaimId;
app.get('/:claim', ({ headers, ip, originalUrl, params, query }, res) => {
// decide if this is a show request
let hasFileExtension;
try {
({ isChannel, channelName, channelClaimId } = lbryUri.parseIdentifier(params.identifier));
// log the result
logger.debug(`isChannel: ${isChannel}, channelName: ${channelName}, channelClaimId: ${channelClaimId}`);
({ hasFileExtension } = lbryUri.parseModifier(params.claim));
} catch (error) {
return handleRequestError(originalUrl, ip, error, res);
return res.status(200).json({success: false, message: error.message});
}
if (isChannel) {
// handle showing the channel page
let responseType = determineResponseType(hasFileExtension, headers);
if (responseType !== SERVE) {
return res.status(200).render('index');
} else {
let claimName, isServeRequest;
try {
({claimName, isServeRequest} = lbryUri.parseName(params.identifier));
} catch (error) {
return handleRequestError(originalUrl, ip, error, res);
}
let responseType = determineResponseType(isServeRequest, headers);
// log the request data for debugging
logRequestData(responseType, claimName, null, null);
// if a serve request, serve, otherwise send the react app
if (responseType === SERVE) {
// get the claim Id and then serve/show the asset
getClaimId(null, null, claimName, null)
.then(fullClaimId => {
if (fullClaimId === NO_CLAIM) {
return res.status(200).render('index');
}
serveAssetToClient(fullClaimId, claimName, res);
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'success');
})
.catch(error => {
handleRequestError(originalUrl, ip, error, res);
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'fail');
});
} else {
res.status(200).render('index');
}
}
// parse the claim
let claimName;
try {
({claimName} = lbryUri.parseClaim(params.claim));
} catch (error) {
return res.status(200).json({success: false, message: error.message});
}
// log the request data for debugging
logRequestData(responseType, claimName, null, null);
// get the claim Id and then serve the asset
getClaimId(null, null, claimName, null)
.then(fullClaimId => {
if (fullClaimId === NO_CLAIM) {
return res.status(200).render('index');
}
serveAssetToClient(fullClaimId, claimName, res);
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'success');
})
.catch(error => {
handleRequestError(originalUrl, ip, error, res);
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'fail');
});
});
};