File info fix #735

Closed
hackrush01 wants to merge 4 commits from file_info_fix into master
8 changed files with 166 additions and 112 deletions

View file

@ -13,6 +13,7 @@ Web UI version numbers should always match the corresponding version of LBRY App
### Changed
* Moved all redux code into /redux folder
* Lots of changes in selectors, reducers and actions for deprecating `outpoints` and using `sd_hash` in `file_list` API call(#693$)
*
### Fixed
@ -24,7 +25,7 @@ Web UI version numbers should always match the corresponding version of LBRY App
*
### Deprecated
*
* Use of `outpoints` in `file_list` API call. `sd_hash` has to be used instead.(#693)
*
### Removed

View file

@ -250,8 +250,14 @@ lbry.getAppVersionInfo = function() {
*/
lbry.file_list = function(params = {}) {
return new Promise((resolve, reject) => {
const { name, channel_name, outpoint } = params;
const { name, channel_name, outpoint, sd_hash } = params;
/**
* sd_hash is now used as a param to the API call
* see https://github.com/lbryio/lbry-app/issues/693 for reference
* rest all of the functionality remains the same and it is still based on outpoints
*/
const newParams = { sd_hash, full_status: params.full_status };
/**
* If we're searching by outpoint, check first to see if there's a matching pending publish.
* Pending publishes use their own faux outpoints that are always unique, so we don't need
@ -267,7 +273,7 @@ lbry.file_list = function(params = {}) {
apiCall(
"file_list",
params,
newParams,
fileInfos => {
removePendingPublishIfNeeded({ name, channel_name, outpoint });

View file

@ -13,10 +13,14 @@ class FileListDownloaded extends React.PureComponent {
render() {
const { fileInfos, isFetching, navigate } = this.props;
const filteredFileInfos = fileInfos.filter(
fileInfo => fileInfo.outpoint !== null
);
let content;
if (fileInfos && fileInfos.length > 0) {
content = <FileList fileInfos={fileInfos} fetching={isFetching} />;
if (filteredFileInfos && filteredFileInfos.length > 0) {
content = (
<FileList fileInfos={filteredFileInfos} fetching={isFetching} />
);
} else {
if (isFetching) {
content = <BusyMessage message={__("Loading")} />;

View file

@ -7,7 +7,7 @@ import { makeSelectClientSetting } from "redux/selectors/settings";
import { selectBalance, selectTransactionItems } from "redux/selectors/wallet";
import {
makeSelectFileInfoForUri,
selectDownloadingByOutpoint,
selectDownloadingBySdHash,
} from "redux/selectors/file_info";
import { selectResolvingUris } from "redux/selectors/content";
import { makeSelectCostInfoForUri } from "redux/selectors/cost_info";
@ -138,12 +138,13 @@ export function doFetchRewardedContent() {
};
}
export function doUpdateLoadStatus(uri, outpoint) {
export function doUpdateLoadStatus(uri, outpoint, sd_hash) {
return function(dispatch, getState) {
const state = getState();
lbry
.file_list({
sd_hash: sd_hash,
outpoint: outpoint,
full_status: true,
})
@ -151,7 +152,7 @@ export function doUpdateLoadStatus(uri, outpoint) {
if (!fileInfo || fileInfo.written_bytes == 0) {
// download hasn't started yet
setTimeout(() => {
dispatch(doUpdateLoadStatus(uri, outpoint));
dispatch(doUpdateLoadStatus(uri, outpoint, sd_hash));
}, DOWNLOAD_POLL_INTERVAL);
} else if (fileInfo.completed) {
// TODO this isn't going to get called if they reload the client before
@ -160,8 +161,8 @@ export function doUpdateLoadStatus(uri, outpoint) {
type: types.DOWNLOADING_COMPLETED,
data: {
uri,
outpoint,
fileInfo,
sd_hash,
},
});
@ -187,9 +188,9 @@ export function doUpdateLoadStatus(uri, outpoint) {
type: types.DOWNLOADING_PROGRESSED,
data: {
uri,
outpoint,
fileInfo,
progress,
sd_hash,
},
});
@ -197,14 +198,14 @@ export function doUpdateLoadStatus(uri, outpoint) {
setProgressBar(totalProgress);
setTimeout(() => {
dispatch(doUpdateLoadStatus(uri, outpoint));
dispatch(doUpdateLoadStatus(uri, outpoint, sd_hash));
}, DOWNLOAD_POLL_INTERVAL);
}
});
};
}
export function doStartDownload(uri, outpoint) {
export function doStartDownload(uri, outpoint, sd_hash) {
return function(dispatch, getState) {
const state = getState();
@ -212,22 +213,24 @@ export function doStartDownload(uri, outpoint) {
throw new Error("outpoint is required to begin a download");
}
const { downloadingByOutpoint = {} } = state.fileInfo;
const { downloadingBySdHash = {} } = state.fileInfo;
if (downloadingByOutpoint[outpoint]) return;
if (downloadingBySdHash[sd_hash]) return;
lbry.file_list({ outpoint, full_status: true }).then(([fileInfo]) => {
dispatch({
type: types.DOWNLOADING_STARTED,
data: {
uri,
outpoint,
fileInfo,
},
lbry
.file_list({ sd_hash, outpoint, full_status: true })
.then(([fileInfo]) => {
dispatch({
type: types.DOWNLOADING_STARTED,
data: {
uri,
fileInfo,
sd_hash,
},
});
dispatch(doUpdateLoadStatus(uri, outpoint, sd_hash));
});
dispatch(doUpdateLoadStatus(uri, outpoint));
});
};
}
@ -235,7 +238,7 @@ export function doDownloadFile(uri, streamInfo) {
return function(dispatch, getState) {
const state = getState();
dispatch(doStartDownload(uri, streamInfo.outpoint));
dispatch(doStartDownload(uri, streamInfo.outpoint, streamInfo.sd_hash));
lbryio
.call("file", "view", {
@ -296,9 +299,9 @@ export function doPurchaseUri(uri) {
const state = getState();
const balance = selectBalance(state);
const fileInfo = makeSelectFileInfoForUri(uri)(state);
const downloadingByOutpoint = selectDownloadingByOutpoint(state);
const downloadingBySdHash = selectDownloadingBySdHash(state);
const alreadyDownloading =
fileInfo && !!downloadingByOutpoint[fileInfo.outpoint];
fileInfo && !!downloadingBySdHash[fileInfo.sd_hash];
function attemptPlay(cost, instantPurchaseMax = null) {
if (cost > 0 && (!instantPurchaseMax || cost > instantPurchaseMax)) {

View file

@ -8,9 +8,10 @@ import {
} from "redux/selectors/claims";
import {
selectIsFetchingFileList,
selectFileInfosByOutpoint,
selectUrisLoading,
selectFileInfosBySdHash,
selectFetchingSdHash,
selectTotalDownloadProgress,
selectSdHashesByOutpoint,
} from "redux/selectors/file_info";
import { doCloseModal } from "redux/actions/app";
import { doNavigate, doHistoryBack } from "redux/actions/navigation";
@ -23,24 +24,24 @@ export function doFetchFileInfo(uri) {
return function(dispatch, getState) {
const state = getState();
const claim = selectClaimsByUri(state)[uri];
const outpoint = claim ? `${claim.txid}:${claim.nout}` : null;
const alreadyFetching = !!selectUrisLoading(state)[uri];
const sd_hash = claim.value.stream.source.source;
const alreadyFetching = !!selectFetchingSdHash(state)[sd_hash];
if (!alreadyFetching) {
dispatch({
type: types.FETCH_FILE_INFO_STARTED,
data: {
outpoint,
sd_hash,
},
});
lbry
.file_list({ outpoint: outpoint, full_status: true })
.file_list({ sd_hash: sd_hash, full_status: true })
.then(fileInfos => {
dispatch({
type: types.FETCH_FILE_INFO_COMPLETED,
data: {
outpoint,
sd_hash,
fileInfo: fileInfos && fileInfos.length ? fileInfos[0] : null,
},
});
@ -89,6 +90,7 @@ export function doOpenFileInFolder(path) {
export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) {
return function(dispatch, getState) {
const state = getState();
const sdHash = selectSdHashesByOutpoint(state)[outpoint];
lbry.file_delete({
outpoint: outpoint,
@ -98,8 +100,8 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) {
// If the file is for a claim we published then also abandom the claim
const myClaimsOutpoints = selectMyClaimsOutpoints(state);
if (abandonClaim && myClaimsOutpoints.indexOf(outpoint) !== -1) {
const byOutpoint = selectFileInfosByOutpoint(state);
const fileInfo = byOutpoint[outpoint];
const bySdHash = selectFileInfosBySdHash(state);
const fileInfo = bySdHash[sd_hash];
if (fileInfo) {
txid = fileInfo.outpoint.slice(0, -2);
@ -112,7 +114,7 @@ export function doDeleteFile(outpoint, deleteFromComputer, abandonClaim) {
dispatch({
type: types.FILE_DELETE,
data: {
outpoint,
sdHash,
},
});

View file

@ -12,27 +12,27 @@ reducers[types.FILE_LIST_STARTED] = function(state, action) {
reducers[types.FILE_LIST_SUCCEEDED] = function(state, action) {
const { fileInfos } = action.data;
const newByOutpoint = Object.assign({}, state.byOutpoint);
const pendingByOutpoint = Object.assign({}, state.pendingByOutpoint);
const newBySdHash = Object.assign({}, state.bySdHash);
const pendingBySdHash = Object.assign({}, state.pendingBySdHash);
fileInfos.forEach(fileInfo => {
const { outpoint } = fileInfo;
const { sd_hash } = fileInfo;
if (outpoint) newByOutpoint[fileInfo.outpoint] = fileInfo;
if (sd_hash) newBySdHash[fileInfo.sd_hash] = fileInfo;
});
return Object.assign({}, state, {
isFetchingFileList: false,
byOutpoint: newByOutpoint,
pendingByOutpoint,
bySdHash: newBySdHash,
pendingBySdHash,
});
};
reducers[types.FETCH_FILE_INFO_STARTED] = function(state, action) {
const { outpoint } = action.data;
const { sd_hash } = action.data;
const newFetching = Object.assign({}, state.fetching);
newFetching[outpoint] = true;
newFetching[sd_hash] = true;
return Object.assign({}, state, {
fetching: newFetching,
@ -40,80 +40,80 @@ reducers[types.FETCH_FILE_INFO_STARTED] = function(state, action) {
};
reducers[types.FETCH_FILE_INFO_COMPLETED] = function(state, action) {
const { fileInfo, outpoint } = action.data;
const { fileInfo, sd_hash } = action.data;
const newByOutpoint = Object.assign({}, state.byOutpoint);
const newBySdHash = Object.assign({}, state.bySdHash);
const newFetching = Object.assign({}, state.fetching);
newByOutpoint[outpoint] = fileInfo;
delete newFetching[outpoint];
newBySdHash[sd_hash] = fileInfo;
delete newFetching[sd_hash];
return Object.assign({}, state, {
byOutpoint: newByOutpoint,
bySdHash: newBySdHash,
fetching: newFetching,
});
};
reducers[types.DOWNLOADING_STARTED] = function(state, action) {
const { uri, outpoint, fileInfo } = action.data;
const { uri, sd_hash, fileInfo } = action.data;
const newByOutpoint = Object.assign({}, state.byOutpoint);
const newDownloading = Object.assign({}, state.downloadingByOutpoint);
const newBySdHash = Object.assign({}, state.bySdHash);
const newDownloading = Object.assign({}, state.downloadingBySdHash);
const newLoading = Object.assign({}, state.urisLoading);
newDownloading[outpoint] = true;
newByOutpoint[outpoint] = fileInfo;
newDownloading[sd_hash] = true;
newBySdHash[sd_hash] = fileInfo;
delete newLoading[uri];
return Object.assign({}, state, {
downloadingByOutpoint: newDownloading,
downloadingBySdHash: newDownloading,
urisLoading: newLoading,
byOutpoint: newByOutpoint,
bySdHash: newBySdHash,
});
};
reducers[types.DOWNLOADING_PROGRESSED] = function(state, action) {
const { uri, outpoint, fileInfo } = action.data;
const { uri, sd_hash, fileInfo } = action.data;
const newByOutpoint = Object.assign({}, state.byOutpoint);
const newDownloading = Object.assign({}, state.downloadingByOutpoint);
const newBySdHash = Object.assign({}, state.bySdHash);
const newDownloading = Object.assign({}, state.downloadingBySdHash);
newByOutpoint[outpoint] = fileInfo;
newDownloading[outpoint] = true;
newBySdHash[sd_hash] = fileInfo;
newDownloading[sd_hash] = true;
return Object.assign({}, state, {
byOutpoint: newByOutpoint,
downloadingByOutpoint: newDownloading,
bySdHash: newBySdHash,
downloadingBySdHash: newDownloading,
});
};
reducers[types.DOWNLOADING_COMPLETED] = function(state, action) {
const { uri, outpoint, fileInfo } = action.data;
const { uri, sd_hash, fileInfo } = action.data;
const newByOutpoint = Object.assign({}, state.byOutpoint);
const newDownloading = Object.assign({}, state.downloadingByOutpoint);
const newBySdHash = Object.assign({}, state.bySdHash);
const newDownloading = Object.assign({}, state.downloadingBySdHash);
newByOutpoint[outpoint] = fileInfo;
delete newDownloading[outpoint];
newBySdHash[sd_hash] = fileInfo;
delete newDownloading[sd_hash];
return Object.assign({}, state, {
byOutpoint: newByOutpoint,
downloadingByOutpoint: newDownloading,
bySdHash: newBySdHash,
downloadingBySdHash: newDownloading,
});
};
reducers[types.FILE_DELETE] = function(state, action) {
const { outpoint } = action.data;
const { sd_hash } = action.data;
const newByOutpoint = Object.assign({}, state.byOutpoint);
const downloadingByOutpoint = Object.assign({}, state.downloadingByOutpoint);
const newBySdHash = Object.assign({}, state.bySdHash);
const downloadingBySdHash = Object.assign({}, state.downloadingBySdHash);
delete newByOutpoint[outpoint];
delete downloadingByOutpoint[outpoint];
delete newBySdHash[sd_hash];
delete downloadingBySdHash[sd_hash];
return Object.assign({}, state, {
byOutpoint: newByOutpoint,
downloadingByOutpoint,
bySdHash: newBySdHash,
downloadingBySdHash,
});
};

View file

@ -189,6 +189,20 @@ export const selectMyClaimsOutpoints = createSelector(
}
);
export const selectMyClaimSdHashesByOutpoint = createSelector(
selectMyClaims,
myClaims => {
const sdHashByOutpoint = {};
myClaims.forEach(claim => {
sdHashByOutpoint[`${claim.txid}:${claim.nout}`] =
claim.value.stream.source.source;
});
return sdHashByOutpoint;
}
);
export const selectFetchingMyChannels = createSelector(
_selectState,
state => !!state.fetchingMyChannels

View file

@ -4,14 +4,14 @@ import {
selectClaimsByUri,
selectIsFetchingClaimListMine,
selectMyClaims,
selectMyClaimsOutpoints,
selectMyClaimSdHashesByOutpoint,
} from "redux/selectors/claims";
export const _selectState = state => state.fileInfo || {};
export const selectFileInfosByOutpoint = createSelector(
export const selectFileInfosBySdHash = createSelector(
_selectState,
state => state.byOutpoint || {}
state => state.bySdHash || {}
);
export const selectIsFetchingFileList = createSelector(
@ -29,28 +29,32 @@ export const selectIsFetchingFileListDownloadedOrPublished = createSelector(
export const makeSelectFileInfoForUri = uri => {
return createSelector(
selectClaimsByUri,
selectFileInfosByOutpoint,
(claims, byOutpoint) => {
const claim = claims[uri],
outpoint = claim ? `${claim.txid}:${claim.nout}` : undefined;
selectFileInfosBySdHash,
(claims, bySdHash) => {
const claim = claims[uri];
let sd_hash = undefined;
return outpoint ? byOutpoint[outpoint] : undefined;
if (claim && !claim.name.startsWith("@")) {
sd_hash = claim ? claim.value.stream.source.source : undefined;
}
return sd_hash ? bySdHash[sd_hash] : undefined;
}
);
};
export const selectDownloadingByOutpoint = createSelector(
export const selectDownloadingBySdHash = createSelector(
_selectState,
state => state.downloadingByOutpoint || {}
state => state.downloadingBySdHash || {}
);
export const makeSelectDownloadingForUri = uri => {
return createSelector(
selectDownloadingByOutpoint,
selectDownloadingBySdHash,
makeSelectFileInfoForUri(uri),
(byOutpoint, fileInfo) => {
(bySdHash, fileInfo) => {
if (!fileInfo) return false;
return byOutpoint[fileInfo.outpoint];
return bySdHash[fileInfo.sd_hash];
}
);
};
@ -64,16 +68,21 @@ export const makeSelectLoadingForUri = uri => {
return createSelector(selectUrisLoading, byUri => byUri && byUri[uri]);
};
export const selectFetchingSdHash = createSelector(
_selectState,
state => state.fetching || {}
);
export const selectFileInfosPendingPublish = createSelector(
_selectState,
state => Object.values(state.pendingByOutpoint || {})
state => Object.values(state.pendingBySdHash || {})
);
export const selectFileInfosDownloaded = createSelector(
selectFileInfosByOutpoint,
selectFileInfosBySdHash,
selectMyClaims,
(byOutpoint, myClaims) => {
return Object.values(byOutpoint).filter(fileInfo => {
(bySdHash, myClaims) => {
return Object.values(bySdHash).filter(fileInfo => {
const myClaimIds = myClaims.map(claim => claim.claim_id);
return (
@ -86,15 +95,17 @@ export const selectFileInfosDownloaded = createSelector(
);
export const selectFileInfosPublished = createSelector(
selectFileInfosByOutpoint,
selectMyClaimsOutpoints,
selectFileInfosBySdHash,
selectMyClaimSdHashesByOutpoint,
selectFileInfosPendingPublish,
(byOutpoint, outpoints, pendingPublish) => {
(bySdHash, sdHashesByOutpoint, pendingPublish) => {
const fileInfos = [];
outpoints.forEach(outpoint => {
const fileInfo = byOutpoint[outpoint];
Object.keys(sdHashesByOutpoint).forEach(outpoint => {
const fileInfo = bySdHash[sdHashesByOutpoint[outpoint]];
if (fileInfo) fileInfos.push(fileInfo);
});
return [...fileInfos, ...pendingPublish];
}
);
@ -110,16 +121,16 @@ export const selectFileInfosPublished = createSelector(
export const selectFileInfosByUri = createSelector(
selectClaimsByUri,
selectFileInfosByOutpoint,
(claimsByUri, byOutpoint) => {
selectFileInfosBySdHash,
(claimsByUri, bySdHash) => {
const fileInfos = {};
const uris = Object.keys(claimsByUri);
uris.forEach(uri => {
const claim = claimsByUri[uri];
if (claim) {
const outpoint = `${claim.txid}:${claim.nout}`;
const fileInfo = byOutpoint[outpoint];
const sd_hash = claim.value.stream.source.source;
const fileInfo = bySdHash[sd_hash];
if (fileInfo) fileInfos[uri] = fileInfo;
}
@ -129,14 +140,14 @@ export const selectFileInfosByUri = createSelector(
);
export const selectDownloadingFileInfos = createSelector(
selectDownloadingByOutpoint,
selectFileInfosByOutpoint,
(downloadingByOutpoint, fileInfosByOutpoint) => {
const outpoints = Object.keys(downloadingByOutpoint);
selectDownloadingBySdHash,
selectFileInfosBySdHash,
(downloadingBySdHash, fileInfosBySdHash) => {
const sdHashes = Object.keys(downloadingBySdHash);
const fileInfos = [];
outpoints.forEach(outpoint => {
const fileInfo = fileInfosByOutpoint[outpoint];
sdHashes.forEach(sdHash => {
const fileInfo = fileInfosBySdHash[sdHash];
if (fileInfo) fileInfos.push(fileInfo);
});
@ -160,3 +171,16 @@ export const selectTotalDownloadProgress = createSelector(
else return -1;
}
);
export const selectSdHashesByOutpoint = createSelector(
selectFileInfosBySdHash,
fileInfos => {
const sdHashesByOutpoint = {};
Object.keys(fileInfos).forEach(fileInfo => {
sdHashesByOutpoint[fileInfo.outpoint] = fileInfo.sd_hash;
});
return sdHashesByOutpoint;
}
);