Minor refactors in doResolveUri()

Add doResolveUris()

Always call resolveUri() in FileTile and FileCard

Before, these components would only try and resolve if claim info
wasn't provided.

Don't require uri param in lbry.resolve()

It can now be "uris" instead, plus the error message about caching
doesn't really apply anymore.

Don't cache/cancel open resolve requests

No longer needed because we're not doing resolve requests in bulk

Add support for multiple URI resolution in lbry.resolve()

Handle multi URL resolves with one action

Update CHANGELOG.md
This commit is contained in:
Alex Liebowitz 2017-10-09 02:23:44 -04:00 committed by Jeremy Kauffman
parent 80f1cac4e5
commit c5c67a0de5
15 changed files with 89 additions and 153 deletions

View file

@ -16,6 +16,7 @@ Web UI version numbers should always match the corresponding version of LBRY App
* There is no longer a minimum channel length (#645)
* Changed the File page to make it clearer how to to open the folder for a file
* The upgrade message is now friendlier and includes a link to the release notes.
* Improved Discover page load time by batching all URIs into one API call
### Fixed
* Improve layout (and implementation) of the icon panel in file tiles and cards

View file

@ -24,68 +24,46 @@ const { ipcRenderer } = require("electron");
const DOWNLOAD_POLL_INTERVAL = 250;
export function doResolveUri(uri) {
export function doResolveUris(uris) {
return function(dispatch, getState) {
uri = lbryuri.normalize(uri);
uris = uris.map(lbryuri.normalize);
const state = getState();
const alreadyResolving = selectResolvingUris(state).indexOf(uri) !== -1;
if (!alreadyResolving) {
dispatch({
type: types.RESOLVE_URI_STARTED,
data: { uri },
});
lbry.resolve({ uri }).then(resolutionInfo => {
const { claim, certificate } = resolutionInfo
? resolutionInfo
: { claim: null, certificate: null };
dispatch({
type: types.RESOLVE_URI_COMPLETED,
data: {
uri,
claim,
certificate,
},
});
});
}
};
}
export function doCancelResolveUri(uri) {
return function(dispatch, getState) {
uri = lbryuri.normalize(uri);
const state = getState();
const alreadyResolving = selectResolvingUris(state).indexOf(uri) !== -1;
if (alreadyResolving) {
lbry.cancelResolve({ uri });
dispatch({
type: types.RESOLVE_URI_CANCELED,
data: {
uri,
},
});
}
};
}
export function doCancelAllResolvingUris() {
return function(dispatch, getState) {
const state = getState();
// Filter out URIs that are already resolving
const resolvingUris = selectResolvingUris(state);
const actions = [];
const urisToResolve = uris.filter(uri => !resolvingUris.includes(uri));
resolvingUris.forEach(uri => actions.push(doCancelResolveUri(uri)));
if (urisToResolve.length === 0) {
return;
}
dispatch(batchActions(...actions));
dispatch({
type: types.RESOLVE_URIS_STARTED,
data: { uris },
});
let resolveInfo = {};
lbry.resolve({ uris: urisToResolve }).then(result => {
for (let [uri, uriResolveInfo] of Object.entries(result)) {
const { claim, certificate } = uriResolveInfo || {
claim: null,
certificate: null,
};
resolveInfo[uri] = { claim, certificate };
}
dispatch({
type: types.RESOLVE_URIS_COMPLETED,
data: { resolveInfo },
});
});
};
}
export function doResolveUri(uri) {
return doResolveUris([uri]);
}
export function doFetchFeaturedUris() {
return function(dispatch, getState) {
const state = getState();
@ -96,28 +74,27 @@ export function doFetchFeaturedUris() {
const success = ({ Categories, Uris }) => {
let featuredUris = {};
const actions = [];
let urisToResolve = [];
Categories.forEach(category => {
if (Uris[category] && Uris[category].length) {
const uris = Uris[category];
featuredUris[category] = uris;
uris.forEach(uri => {
actions.push(doResolveUri(uri));
});
urisToResolve = [...urisToResolve, ...uris];
}
});
actions.push({
type: types.FETCH_FEATURED_CONTENT_COMPLETED,
data: {
categories: Categories,
uris: featuredUris,
success: true,
const actions = [
doResolveUris(urisToResolve),
{
type: types.FETCH_FEATURED_CONTENT_COMPLETED,
data: {
categories: Categories,
uris: featuredUris,
success: true,
},
},
});
];
dispatch(batchActions(...actions));
};

View file

@ -20,19 +20,13 @@ class FileCard extends React.PureComponent {
}
componentWillMount() {
this.resolve(this.props);
const { uri, resolveUri } = this.props;
resolveUri(uri);
}
componentWillReceiveProps(nextProps) {
this.resolve(nextProps);
}
resolve(props) {
const { isResolvingUri, resolveUri, claim, uri } = props;
if (!isResolvingUri && claim === undefined && uri) {
resolveUri(uri);
}
const { uri, resolveUri } = nextProps;
resolveUri(uri);
}
handleMouseOver() {

View file

@ -26,15 +26,15 @@ class FileTile extends React.PureComponent {
}
componentDidMount() {
const { isResolvingUri, claim, uri, resolveUri } = this.props;
const { uri, resolveUri } = this.props;
if (!isResolvingUri && !claim && uri) resolveUri(uri);
resolveUri(uri);
}
componentWillReceiveProps(nextProps) {
const { isResolvingUri, claim, uri, resolveUri } = this.props;
const { uri, resolveUri } = this.props;
if (!isResolvingUri && claim === undefined && uri) resolveUri(uri);
resolveUri(uri);
}
handleMouseOver() {

View file

@ -47,9 +47,8 @@ export const SUPPORT_TRANSACTION_FAILED = "SUPPORT_TRANSACTION_FAILED";
export const FETCH_FEATURED_CONTENT_STARTED = "FETCH_FEATURED_CONTENT_STARTED";
export const FETCH_FEATURED_CONTENT_COMPLETED =
"FETCH_FEATURED_CONTENT_COMPLETED";
export const RESOLVE_URI_STARTED = "RESOLVE_URI_STARTED";
export const RESOLVE_URI_COMPLETED = "RESOLVE_URI_COMPLETED";
export const RESOLVE_URI_CANCELED = "RESOLVE_URI_CANCELED";
export const RESOLVE_URIS_STARTED = "RESOLVE_URIS_STARTED";
export const RESOLVE_URIS_COMPLETED = "RESOLVE_URIS_COMPLETED";
export const FETCH_CHANNEL_CLAIMS_STARTED = "FETCH_CHANNEL_CLAIMS_STARTED";
export const FETCH_CHANNEL_CLAIMS_COMPLETED = "FETCH_CHANNEL_CLAIMS_COMPLETED";
export const FETCH_CHANNEL_CLAIM_COUNT_STARTED =

View file

@ -311,30 +311,24 @@ lbry.claim_list_mine = function(params = {}) {
});
};
lbry._resolveXhrs = {};
lbry.resolve = function(params = {}) {
return new Promise((resolve, reject) => {
if (!params.uri) {
throw __("Resolve has hacked cache on top of it that requires a URI");
}
lbry._resolveXhrs[params.uri] = apiCall(
apiCall(
"resolve",
params,
function(data) {
resolve(data && data[params.uri] ? data[params.uri] : {});
if ("uri" in params) {
// If only a single URI was requested, don't nest the results in an object
resolve(data && data[params.uri] ? data[params.uri] : {});
} else {
resolve(data || {});
}
},
reject
);
});
};
lbry.cancelResolve = function(params = {}) {
const xhr = lbry._resolveXhrs[params.uri];
if (xhr && xhr.readyState > 0 && xhr.readyState < 4) {
xhr.abort();
}
};
lbry = new Proxy(lbry, {
get: function(target, name) {
if (name in target) {

View file

@ -1,6 +1,6 @@
import React from "react";
import { connect } from "react-redux";
import { doFetchFeaturedUris, doCancelAllResolvingUris } from "actions/content";
import { doFetchFeaturedUris } from "actions/content";
import {
selectFeaturedUris,
selectFetchingFeaturedUris,
@ -14,7 +14,6 @@ const select = state => ({
const perform = dispatch => ({
fetchFeaturedUris: () => dispatch(doFetchFeaturedUris()),
cancelResolvingUris: () => dispatch(doCancelAllResolvingUris()),
});
export default connect(select, perform)(DiscoverPage);

View file

@ -204,10 +204,6 @@ class DiscoverPage extends React.PureComponent {
this.props.fetchFeaturedUris();
}
componentWillUnmount() {
this.props.cancelResolvingUris();
}
render() {
const { featuredUris, fetchingFeaturedUris } = this.props;
const hasContent =

View file

@ -11,7 +11,6 @@ import {
} from "selectors/claims";
import { doFetchClaimListMine } from "actions/content";
import { doNavigate } from "actions/navigation";
import { doCancelAllResolvingUris } from "actions/content";
import FileListDownloaded from "./view";
const select = state => ({
@ -25,7 +24,6 @@ const perform = dispatch => ({
navigate: path => dispatch(doNavigate(path)),
fetchFileInfosDownloaded: () =>
dispatch(doFetchFileInfosAndPublishedClaims()),
cancelResolvingUris: () => dispatch(doCancelAllResolvingUris()),
fetchClaims: () => dispatch(doFetchClaimListMine()),
});

View file

@ -11,10 +11,6 @@ class FileListDownloaded extends React.PureComponent {
if (!this.props.isFetching) this.props.fetchFileInfosDownloaded();
}
componentWillUnmount() {
this.props.cancelResolvingUris();
}
render() {
const { fileInfos, isFetching, navigate } = this.props;

View file

@ -8,7 +8,6 @@ import {
} from "selectors/claims";
import { doClaimRewardType } from "actions/rewards";
import { doNavigate } from "actions/navigation";
import { doCancelAllResolvingUris } from "actions/content";
import FileListPublished from "./view";
const select = state => ({
@ -21,7 +20,6 @@ const perform = dispatch => ({
fetchClaims: () => dispatch(doFetchClaimListMine()),
claimFirstPublishReward: () =>
dispatch(doClaimRewardType(rewards.TYPE_FIRST_PUBLISH)),
cancelResolvingUris: () => dispatch(doCancelAllResolvingUris()),
});
export default connect(select, perform)(FileListPublished);

View file

@ -14,10 +14,6 @@ class FileListPublished extends React.PureComponent {
// if (this.props.claims.length > 0) this.props.fetchClaims();
}
componentWillUnmount() {
this.props.cancelResolvingUris();
}
render() {
const { claims, isFetching, navigate } = this.props;

View file

@ -6,17 +6,15 @@ import FilePage from "page/file";
class ShowPage extends React.PureComponent {
componentWillMount() {
const { isResolvingUri, resolveUri, uri } = this.props;
const { resolveUri, uri } = this.props;
if (!isResolvingUri) resolveUri(uri);
resolveUri(uri);
}
componentWillReceiveProps(nextProps) {
const { isResolvingUri, resolveUri, claim, uri } = nextProps;
const { resolveUri, uri } = nextProps;
if (!isResolvingUri && claim === undefined && uri) {
resolveUri(uri);
}
resolveUri(uri);
}
render() {

View file

@ -4,26 +4,27 @@ const reducers = {};
const defaultState = {};
reducers[types.RESOLVE_URI_COMPLETED] = function(state, action) {
const { uri, certificate, claim } = action.data;
reducers[types.RESOLVE_URIS_COMPLETED] = function(state, action) {
const { resolveInfo } = action.data;
const byUri = Object.assign({}, state.claimsByUri);
const byId = Object.assign({}, state.byId);
if (claim) {
byId[claim.claim_id] = claim;
byUri[uri] = claim.claim_id;
} else if (claim === undefined && certificate !== undefined) {
byId[certificate.claim_id] = certificate;
// Don't point URI at the channel certificate unless it actually is
// a channel URI. This is brittle.
if (!uri.split(certificate.name)[1].match(/\//)) {
byUri[uri] = certificate.claim_id;
for (let [uri, { certificate, claim }] of Object.entries(resolveInfo)) {
if (claim) {
byId[claim.claim_id] = claim;
byUri[uri] = claim.claim_id;
} else if (claim === undefined && certificate !== undefined) {
byId[certificate.claim_id] = certificate;
// Don't point URI at the channel certificate unless it actually is
// a channel URI. This is brittle.
if (!uri.split(certificate.name)[1].match(/\//)) {
byUri[uri] = certificate.claim_id;
} else {
byUri[uri] = null;
}
} else {
byUri[uri] = null;
}
} else {
byUri[uri] = null;
}
return Object.assign({}, state, {

View file

@ -31,34 +31,23 @@ reducers[types.FETCH_REWARD_CONTENT_COMPLETED] = function(state, action) {
});
};
reducers[types.RESOLVE_URI_STARTED] = function(state, action) {
const { uri } = action.data;
reducers[types.RESOLVE_URIS_STARTED] = function(state, action) {
let { uris } = action.data;
const oldResolving = state.resolvingUris || [];
const newResolving = Object.assign([], oldResolving);
if (newResolving.indexOf(uri) === -1) newResolving.push(uri);
for (let uri of uris) {
if (!newResolving.includes(uri)) {
newResolving.push(uri);
}
}
return Object.assign({}, state, {
resolvingUris: newResolving,
});
};
reducers[types.RESOLVE_URI_CANCELED] = reducers[
types.RESOLVE_URI_COMPLETED
] = function(state, action) {
const { uri } = action.data;
const resolvingUris = state.resolvingUris;
const index = state.resolvingUris.indexOf(uri);
const newResolvingUris = [
...resolvingUris.slice(0, index),
...resolvingUris.slice(index + 1),
];
return Object.assign({}, state, {
resolvingUris: newResolvingUris,
});
};
reducers[types.SET_PLAYING_URI] = (state, action) => {
return Object.assign({}, state, {
playingUri: action.data.uri,