React router #343
|
@ -55,14 +55,14 @@ module.exports = {
|
||||||
claimId,
|
claimId,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
parseName: function (name) {
|
parseClaim: function (claim) {
|
||||||
logger.debug('parsing name:', name);
|
logger.debug('parsing name:', claim);
|
||||||
const componentsRegex = new RegExp(
|
const componentsRegex = new RegExp(
|
||||||
'([^:$#/.]*)' + // name (stops at the first modifier)
|
'([^:$#/.]*)' + // name (stops at the first modifier)
|
||||||
'([:$#.]?)([^/]*)' // modifier separator, modifier (stops at the first path separator or end)
|
'([:$#.]?)([^/]*)' // modifier separator, modifier (stops at the first path separator or end)
|
||||||
);
|
);
|
||||||
const [proto, claimName, modifierSeperator, modifier] = componentsRegex
|
const [proto, claimName, modifierSeperator, modifier] = componentsRegex
|
||||||
.exec(name)
|
.exec(claim)
|
||||||
.map(match => match || null);
|
.map(match => match || null);
|
||||||
logger.debug(`${proto}, ${claimName}, ${modifierSeperator}, ${modifier}`);
|
logger.debug(`${proto}, ${claimName}, ${modifierSeperator}, ${modifier}`);
|
||||||
|
|
||||||
|
@ -75,7 +75,6 @@ module.exports = {
|
||||||
throw new Error(`Invalid characters in claim name: ${nameBadChars.join(', ')}.`);
|
throw new Error(`Invalid characters in claim name: ${nameBadChars.join(', ')}.`);
|
||||||
}
|
}
|
||||||
// Validate and process modifier
|
// Validate and process modifier
|
||||||
let isServeRequest = false;
|
|
||||||
if (modifierSeperator) {
|
if (modifierSeperator) {
|
||||||
if (!modifier) {
|
if (!modifier) {
|
||||||
throw new Error(`No file extension provided after separator ${modifierSeperator}.`);
|
throw new Error(`No file extension provided after separator ${modifierSeperator}.`);
|
||||||
|
@ -83,11 +82,29 @@ module.exports = {
|
||||||
if (modifierSeperator !== '.') {
|
if (modifierSeperator !== '.') {
|
||||||
throw new Error(`The ${modifierSeperator} modifier is not supported in the claim name`);
|
throw new Error(`The ${modifierSeperator} modifier is not supported in the claim name`);
|
||||||
}
|
}
|
||||||
isServeRequest = true;
|
|
||||||
}
|
}
|
||||||
|
// return results
|
||||||
return {
|
return {
|
||||||
claimName,
|
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,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
I had a misunderstanding of how the I had a misunderstanding of how the `this` context works and when I needed to pass this in to a function manually. I was able to remove it from the app in multiple places where it isn't necessary.
Why do you do Why do you do `const that = this`?
I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same `<AssetDisplay />` it will make these requests again, even if you just made them a second ago
I had a misunderstanding of how the I had a misunderstanding of how the `this` context works and when I needed to pass this in to a function manually. I was able to remove it from the app in multiple places where it isn't necessary.
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const AssetDisplay = ({ claimName, claimId }) => {
|
const AssetDisplay = ({ name, claimId }) => {
|
||||||
Why do you do Why do you do `const that = this`?
I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same `<AssetDisplay />` it will make these requests again, even if you just made them a second ago
I had a misunderstanding of how the I had a misunderstanding of how the `this` context works and when I needed to pass this in to a function manually. I was able to remove it from the app in multiple places where it isn't necessary.
Why do you do Why do you do `const that = this`?
I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same `<AssetDisplay />` it will make these requests again, even if you just made them a second ago
I had a misunderstanding of how the I had a misunderstanding of how the `this` context works and when I needed to pass this in to a function manually. I was able to remove it from the app in multiple places where it isn't necessary.
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>display {claimName}#{claimId} here</p>
|
<p>display {name}#{claimId} here</p>
|
||||||
Why do you do Why do you do `const that = this`?
I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same `<AssetDisplay />` it will make these requests again, even if you just made them a second ago
I had a misunderstanding of how the I had a misunderstanding of how the `this` context works and when I needed to pass this in to a function manually. I was able to remove it from the app in multiple places where it isn't necessary.
Why do you do Why do you do `const that = this`?
I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same `<AssetDisplay />` it will make these requests again, even if you just made them a second ago
I had a misunderstanding of how the I had a misunderstanding of how the `this` context works and when I needed to pass this in to a function manually. I was able to remove it from the app in multiple places where it isn't necessary.
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Why do you do Why do you do `const that = this`?
I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same `<AssetDisplay />` it will make these requests again, even if you just made them a second ago
I had a misunderstanding of how the I had a misunderstanding of how the `this` context works and when I needed to pass this in to a function manually. I was able to remove it from the app in multiple places where it isn't necessary.
Why do you do Why do you do `const that = this`?
I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same `<AssetDisplay />` it will make these requests again, even if you just made them a second ago
I had a misunderstanding of how the I had a misunderstanding of how the `this` context works and when I needed to pass this in to a function manually. I was able to remove it from the app in multiple places where it isn't necessary.
|
|
@ -54,7 +54,7 @@ class AssetInfo extends React.Component {
|
||||||
This should be a This should be a `button` if it isn't linking anywhere.
This should be a This should be a `button` if it isn't linking anywhere.
|
|||||||
<div className="row row--padded row--wide row--no-top">
|
<div className="row row--padded row--wide row--no-top">
|
||||||
<div id="show-short-link">
|
<div id="show-short-link">
|
||||||
<div className="column column--2 column--med-10">
|
<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
|
||||||
This should be a This should be a `button` if it isn't linking anywhere.
This should be a This should be a `button` if it isn't linking anywhere.
|
|||||||
className="text">Link:</span></a>
|
className="text">Link:</span></a>
|
||||||
</div>
|
</div>
|
||||||
<div className="column column--8 column--med-10">
|
<div className="column column--8 column--med-10">
|
||||||
|
@ -63,7 +63,7 @@ class AssetInfo extends React.Component {
|
||||||
This should be a This should be a `button` if it isn't linking anywhere.
This should be a This should be a `button` if it isn't linking anywhere.
|
|||||||
<div className="input-error" id="input-error-copy-short-link" hidden="true">error here</div>
|
<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
|
<input type="text" id="short-link" className="input-disabled input-text--full-width" readOnly
|
||||||
spellCheck="false"
|
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}`}
|
||||||
This should be a This should be a `button` if it isn't linking anywhere.
This should be a This should be a `button` if it isn't linking anywhere.
|
|||||||
onClick={this.select}/>
|
onClick={this.select}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="column column--1"> </div>
|
<div className="column column--1"> </div>
|
||||||
|
@ -114,13 +114,13 @@ class AssetInfo extends React.Component {
|
||||||
This should be a This should be a `button` if it isn't linking anywhere.
This should be a This should be a `button` if it isn't linking anywhere.
|
|||||||
<div
|
<div
|
||||||
className="row row--short row--wide flex-container--row flex-container--space-between-bottom flex-container--wrap">
|
className="row row--short row--wide flex-container--row flex-container--space-between-bottom flex-container--wrap">
|
||||||
<a className="link--primary" target="_blank"
|
<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>
|
||||||
This should be a This should be a `button` if it isn't linking anywhere.
This should be a This should be a `button` if it isn't linking anywhere.
|
|||||||
<a className="link--primary" target="_blank"
|
<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>
|
||||||
This should be a This should be a `button` if it isn't linking anywhere.
This should be a This should be a `button` if it isn't linking anywhere.
|
|||||||
<a className="link--primary" target="_blank"
|
<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>
|
||||||
This should be a This should be a `button` if it isn't linking anywhere.
This should be a This should be a `button` if it isn't linking anywhere.
|
|||||||
<a className="link--primary" target="_blank"
|
<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>
|
||||||
This should be a This should be a `button` if it isn't linking anywhere.
This should be a This should be a `button` if it isn't linking anywhere.
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -168,6 +168,6 @@ class AssetInfo extends React.Component {
|
||||||
This should be a This should be a `button` if it isn't linking anywhere.
This should be a This should be a `button` if it isn't linking anywhere.
|
|||||||
};
|
};
|
||||||
|
|
||||||
// required props
|
// required props
|
||||||
// {channelName, certificateId, description, shortId, name, fileExt, claimId, contentType, thumbnail, host}
|
// {channelName, certificateId, description, shortClaimId, name, fileExt, claimId, contentType, thumbnail, host}
|
||||||
This should be a This should be a `button` if it isn't linking anywhere.
This should be a This should be a `button` if it isn't linking anywhere.
|
|||||||
|
|
||||||
export default AssetInfo;
|
export default AssetInfo;
|
||||||
|
|
||||||
This should be a This should be a `button` if it isn't linking anywhere.
This should be a This should be a `button` if it isn't linking anywhere.
|
20
react/components/ErrorPage/index.js
Normal 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;
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ShowLite from 'components/ShowAssetLite';
|
import ShowAssetLite from 'components/ShowAssetLite';
|
||||||
import ShowDetails from 'components/ShowAssetDetails';
|
import ShowAssetDetails from 'components/ShowAssetDetails';
|
||||||
import request from 'utils/request';
|
import request from 'utils/request';
|
||||||
|
|
||||||
class ShowAsset extends React.Component {
|
class ShowAsset extends React.Component {
|
||||||
|
@ -83,14 +83,14 @@ class ShowAsset extends React.Component {
|
||||||
render () {
|
render () {
|
||||||
if (this.props.isServeRequest) {
|
if (this.props.isServeRequest) {
|
||||||
return (
|
return (
|
||||||
<ShowLite
|
<ShowAssetLite
|
||||||
error={this.state.error}
|
error={this.state.error}
|
||||||
claimData={this.state.claimData}
|
claimData={this.state.claimData}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ShowDetails
|
<ShowAssetDetails
|
||||||
error={this.state.error}
|
error={this.state.error}
|
||||||
claimData={this.state.claimData}
|
claimData={this.state.claimData}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -13,7 +13,9 @@ class ShowDetails extends React.Component {
|
||||||
<div>
|
<div>
|
||||||
<NavBar/>
|
<NavBar/>
|
||||||
{this.props.error &&
|
{this.props.error &&
|
||||||
<p>{this.props.error}</p>
|
<div className="row row--padded">
|
||||||
|
<p>{this.props.error}</p>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
{this.props.claimData &&
|
{this.props.claimData &&
|
||||||
<div className="row row--tall row--padded">
|
<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="column column--5 column--sml-10 align-content-top">
|
||||||
<div className="row row--padded">
|
<div className="row row--padded">
|
||||||
<AssetDisplay
|
<AssetDisplay
|
||||||
claimName={this.props.claimData.name}
|
name={this.props.claimData.name}
|
||||||
claimId={this.props.claimData.claimId}
|
claimId={this.props.claimData.claimId}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div><div className="column column--5 column--sml-10 align-content-top">
|
</div><div className="column column--5 column--sml-10 align-content-top">
|
||||||
<div className="row row--padded">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import ErrorPage from 'components/ErrorPage';
|
||||||
import ShowAsset from 'components/ShowAsset';
|
import ShowAsset from 'components/ShowAsset';
|
||||||
import ShowChannel from 'components/ShowChannel';
|
import ShowChannel from 'components/ShowChannel';
|
||||||
import lbryUri from 'utils/lbryUri';
|
import lbryUri from 'utils/lbryUri';
|
||||||
|
@ -10,6 +11,7 @@ class ShowPage extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
error : null,
|
||||||
identifier : null,
|
identifier : null,
|
||||||
claim : null,
|
claim : null,
|
||||||
isServeRequest: null,
|
isServeRequest: null,
|
||||||
|
@ -46,9 +48,9 @@ class ShowPage extends React.Component {
|
||||||
let isChannel, channelName, channelClaimId, claimId, claimName, isServeRequest;
|
let isChannel, channelName, channelClaimId, claimId, claimName, isServeRequest;
|
||||||
try {
|
try {
|
||||||
({ isChannel, channelName, channelClaimId, claimId } = lbryUri.parseIdentifier(identifier));
|
({ isChannel, channelName, channelClaimId, claimId } = lbryUri.parseIdentifier(identifier));
|
||||||
({ claimName, isServeRequest } = lbryUri.parseName(claim));
|
({ claimName, isServeRequest } = lbryUri.parseClaim(claim));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return console.log('error:', error);
|
return this.setState({error: error.message});
|
||||||
}
|
}
|
||||||
// set state
|
// set state
|
||||||
return this.setState({
|
return this.setState({
|
||||||
|
@ -72,7 +74,7 @@ class ShowPage extends React.Component {
|
||||||
try {
|
try {
|
||||||
({ isChannel, channelName, channelClaimId } = lbryUri.parseIdentifier(claim));
|
({ isChannel, channelName, channelClaimId } = lbryUri.parseIdentifier(claim));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return console.log('error:', error);
|
return this.setState({error: error.message});
|
||||||
}
|
}
|
||||||
if (isChannel) {
|
if (isChannel) {
|
||||||
return this.setState({
|
return this.setState({
|
||||||
|
@ -85,9 +87,9 @@ class ShowPage extends React.Component {
|
||||||
}
|
}
|
||||||
let claimName, isServeRequest;
|
let claimName, isServeRequest;
|
||||||
try {
|
try {
|
||||||
({claimName, isServeRequest} = lbryUri.parseName(claim));
|
({claimName, isServeRequest} = lbryUri.parseClaim(claim));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return console.log('error:', error);
|
return this.setState({error: error.message});
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
claim: {
|
claim: {
|
||||||
|
@ -98,6 +100,11 @@ class ShowPage extends React.Component {
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
console.log('rendering ShowPage');
|
console.log('rendering ShowPage');
|
||||||
|
if (this.state.error) {
|
||||||
|
return (
|
||||||
|
<ErrorPage error={this.state.error}/>
|
||||||
|
);
|
||||||
|
}
|
||||||
if (this.state.claim) {
|
if (this.state.claim) {
|
||||||
if (this.state.claim.isChannel) {
|
if (this.state.claim.isChannel) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -16,18 +16,18 @@ module.exports = {
|
||||||
|
|
||||||
// Validate and process name
|
// Validate and process name
|
||||||
if (!value) {
|
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 isChannel = value.startsWith(module.exports.CHANNEL_CHAR);
|
||||||
const channelName = isChannel ? value : null;
|
const channelName = isChannel ? value : null;
|
||||||
let claimId;
|
let claimId;
|
||||||
if (isChannel) {
|
if (isChannel) {
|
||||||
if (!channelName) {
|
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);
|
const nameBadChars = (channelName).match(module.exports.REGEXP_INVALID_CHANNEL);
|
||||||
if (nameBadChars) {
|
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 {
|
} else {
|
||||||
claimId = value;
|
claimId = value;
|
||||||
|
@ -37,13 +37,13 @@ module.exports = {
|
||||||
let channelClaimId;
|
let channelClaimId;
|
||||||
if (modifierSeperator) {
|
if (modifierSeperator) {
|
||||||
if (!modifier) {
|
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 === ':') {
|
if (modifierSeperator === ':') {
|
||||||
channelClaimId = modifier;
|
channelClaimId = modifier;
|
||||||
} else {
|
} 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 {
|
return {
|
||||||
|
@ -53,7 +53,7 @@ module.exports = {
|
||||||
claimId,
|
claimId,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
parseName: function (name) {
|
parseClaim: function (name) {
|
||||||
console.log('parsing name:', name);
|
console.log('parsing name:', name);
|
||||||
const componentsRegex = new RegExp(
|
const componentsRegex = new RegExp(
|
||||||
'([^:$#/.]*)' + // name (stops at the first modifier)
|
'([^:$#/.]*)' + // name (stops at the first modifier)
|
||||||
|
@ -66,20 +66,20 @@ module.exports = {
|
||||||
|
|
||||||
// Validate and process name
|
// Validate and process name
|
||||||
if (!claimName) {
|
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);
|
const nameBadChars = (claimName).match(module.exports.REGEXP_INVALID_CLAIM);
|
||||||
if (nameBadChars) {
|
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
|
// Validate and process modifier
|
||||||
let isServeRequest = false;
|
let isServeRequest = false;
|
||||||
if (modifierSeperator) {
|
if (modifierSeperator) {
|
||||||
if (!modifier) {
|
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 !== '.') {
|
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;
|
isServeRequest = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,10 @@ const logger = require('winston');
|
||||||
const { getClaimId, getLocalFileRecord } = require('../controllers/serveController.js');
|
const { getClaimId, getLocalFileRecord } = require('../controllers/serveController.js');
|
||||||
const serveHelpers = require('../helpers/serveHelpers.js');
|
const serveHelpers = require('../helpers/serveHelpers.js');
|
||||||
const { handleRequestError } = require('../helpers/errorHandlers.js');
|
const { handleRequestError } = require('../helpers/errorHandlers.js');
|
||||||
const { postToStats } = require('../helpers/statsHelpers.js');
|
|
||||||
const db = require('../models');
|
|
||||||
const lbryUri = require('../helpers/lbryUri.js');
|
const lbryUri = require('../helpers/lbryUri.js');
|
||||||
|
|
||||||
const SERVE = 'SERVE';
|
const SERVE = 'SERVE';
|
||||||
const SHOW = 'SHOW';
|
const SHOW = 'SHOW';
|
||||||
const SHOWLITE = 'SHOWLITE';
|
|
||||||
const NO_CHANNEL = 'NO_CHANNEL';
|
const NO_CHANNEL = 'NO_CHANNEL';
|
||||||
const NO_CLAIM = 'NO_CLAIM';
|
const NO_CLAIM = 'NO_CLAIM';
|
||||||
const NO_FILE = 'NO_FILE';
|
const NO_FILE = 'NO_FILE';
|
||||||
|
@ -39,49 +36,23 @@ function clientWantsAsset ({accept, range}) {
|
||||||
return imageIsWanted || videoIsWanted;
|
return imageIsWanted || videoIsWanted;
|
||||||
}
|
}
|
||||||
|
|
||||||
function determineResponseType (isServeRequest, headers) {
|
function determineResponseType (hasFileExtension, headers) {
|
||||||
let responseType;
|
let responseType;
|
||||||
if (isServeRequest) {
|
if (hasFileExtension) {
|
||||||
responseType = SERVE;
|
responseType = SERVE; // assume a serve request if file extension is present
|
||||||
if (clientAcceptsHtml(headers)) { // this is in case a serve request comes from a browser
|
if (clientAcceptsHtml(headers)) { // if the request comes from a browser, change it to a show request
|
||||||
responseType = SHOWLITE;
|
responseType = SHOW;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
responseType = SHOW;
|
responseType = SHOW;
|
||||||
if (clientWantsAsset(headers) && requestIsFromBrowser(headers)) { // this is in case someone embeds a show url
|
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;
|
responseType = SERVE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return responseType;
|
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) {
|
function serveAssetToClient (claimId, name, res) {
|
||||||
return getLocalFileRecord(claimId, name)
|
return getLocalFileRecord(claimId, name)
|
||||||
.then(fileInfo => {
|
.then(fileInfo => {
|
||||||
|
@ -115,82 +86,87 @@ function logRequestData (responseType, claimName, channelName, claimId) {
|
||||||
|
|
||||||
module.exports = (app) => {
|
module.exports = (app) => {
|
||||||
// route to serve a specific asset using the channel or claim id
|
// route to serve a specific asset using the channel or claim id
|
||||||
app.get('/:identifier/:name', ({ headers, ip, originalUrl, params }, res) => {
|
app.get('/:identifier/:claim', ({ headers, ip, originalUrl, params }, res) => {
|
||||||
let isChannel, channelName, channelClaimId, claimId, claimName, isServeRequest;
|
// 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 {
|
try {
|
||||||
({ isChannel, channelName, channelClaimId, claimId } = lbryUri.parseIdentifier(params.identifier));
|
({ isChannel, channelName, channelClaimId, claimId } = lbryUri.parseIdentifier(params.identifier));
|
||||||
({ claimName, isServeRequest } = lbryUri.parseName(params.name));
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return handleRequestError(originalUrl, ip, error, res);
|
return handleRequestError(originalUrl, ip, error, res);
|
||||||
}
|
}
|
||||||
if (!isChannel) {
|
if (!isChannel) {
|
||||||
[claimId, claimName] = flipClaimNameAndIdForBackwardsCompatibility(claimId, claimName);
|
[claimId, claimName] = flipClaimNameAndIdForBackwardsCompatibility(claimId, claimName);
|
||||||
}
|
}
|
||||||
let responseType = determineResponseType(isServeRequest, headers);
|
|
||||||
// log the request data for debugging
|
// log the request data for debugging
|
||||||
logRequestData(responseType, claimName, channelName, claimId);
|
logRequestData(responseType, claimName, channelName, claimId);
|
||||||
// if a serve request, serve, otherwise send the react app
|
// get the claim Id and then serve the asset
|
||||||
if (responseType === SERVE) {
|
getClaimId(channelName, channelClaimId, claimName, claimId)
|
||||||
// get the claim Id and then serve/show the asset
|
.then(fullClaimId => {
|
||||||
getClaimId(channelName, channelClaimId, claimName, claimId)
|
if (fullClaimId === NO_CLAIM) {
|
||||||
.then(fullClaimId => {
|
return res.status(200).json({success: false, message: 'no claim id could be found'});
|
||||||
if (fullClaimId === NO_CLAIM) {
|
} else if (fullClaimId === NO_CHANNEL) {
|
||||||
return res.status(200).json({success: false, message: 'no claim id could be found'});
|
return res.status(200).json({success: false, message: 'no channel 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');
|
||||||
serveAssetToClient(fullClaimId, claimName, res);
|
})
|
||||||
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'success');
|
.catch(error => {
|
||||||
})
|
handleRequestError(originalUrl, ip, error, res);
|
||||||
.catch(error => {
|
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'fail');
|
||||||
handleRequestError(originalUrl, ip, error, res);
|
});
|
||||||
// postToStats(responseType, originalUrl, ip, claimName, fullClaimId, 'fail');
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
res.status(200).render('index');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
// route to serve the winning asset at a claim or a channel page
|
// route to serve the winning asset at a claim or a channel page
|
||||||
app.get('/:identifier', ({ headers, ip, originalUrl, params, query }, res) => {
|
app.get('/:claim', ({ headers, ip, originalUrl, params, query }, res) => {
|
||||||
let isChannel, channelName, channelClaimId;
|
// decide if this is a show request
|
||||||
|
let hasFileExtension;
|
||||||
try {
|
try {
|
||||||
({ isChannel, channelName, channelClaimId } = lbryUri.parseIdentifier(params.identifier));
|
({ hasFileExtension } = lbryUri.parseModifier(params.claim));
|
||||||
// log the result
|
|
||||||
logger.debug(`isChannel: ${isChannel}, channelName: ${channelName}, channelClaimId: ${channelClaimId}`);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return handleRequestError(originalUrl, ip, error, res);
|
return res.status(200).json({success: false, message: error.message});
|
||||||
}
|
}
|
||||||
if (isChannel) {
|
let responseType = determineResponseType(hasFileExtension, headers);
|
||||||
// handle showing the channel page
|
if (responseType !== SERVE) {
|
||||||
return res.status(200).render('index');
|
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');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
Why do you do
const that = this
?I think this is another piece you can move entirely into redux. Currently if this component is rendered, then a user navigates away and comes back to the same
<AssetDisplay />
it will make these requests again, even if you just made them a second ago