From 29c7a4b8326a0dc8bd006208f6f860cad9e7270d Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Wed, 15 May 2019 10:58:36 +0100 Subject: [PATCH 1/7] add account_set sdk call (#146) --- dist/bundle.es.js | 1 + dist/flow-typed/Lbry.js | 14 ++++++++++++++ flow-typed/Lbry.js | 14 ++++++++++++++ src/lbry.js | 1 + 4 files changed, 30 insertions(+) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 9a913dd..9512952 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -651,6 +651,7 @@ const Lbry = { account_unlock: (params = {}) => daemonCallWithResult('account_unlock', params), account_list: (params = {}) => daemonCallWithResult('account_list', params), account_send: (params = {}) => daemonCallWithResult('account_send', params), + account_set: (params = {}) => daemonCallWithResult('account_set', params), address_is_mine: (params = {}) => daemonCallWithResult('address_is_mine', params), address_unused: (params = {}) => daemonCallWithResult('address_unused', params), transaction_list: (params = {}) => daemonCallWithResult('transaction_list', params), diff --git a/dist/flow-typed/Lbry.js b/dist/flow-typed/Lbry.js index 6219328..303de6f 100644 --- a/dist/flow-typed/Lbry.js +++ b/dist/flow-typed/Lbry.js @@ -130,6 +130,19 @@ declare type SyncApplyResponse = { data: string, }; +declare type AccountSetResponse = Array<{ + id: string, + is_default: string, + ledger: string, + name: string, + seed: string, + encrypted: string, + private_key: string, + public_key: string, + address_generator: string, + modified_on: string, +}>; + declare type SupportAbandonResponse = GenericTxResponse; // @@ -174,6 +187,7 @@ declare type LbryTypes = { account_unlock: (params: {}) => Promise, account_list: (params: {}) => Promise, account_send: (params: {}) => Promise, + account_set: (params: {}) => Promise, address_is_mine: (params: {}) => Promise, address_unused: (params: {}) => Promise, // New address transaction_list: (params: {}) => Promise, diff --git a/flow-typed/Lbry.js b/flow-typed/Lbry.js index 6219328..303de6f 100644 --- a/flow-typed/Lbry.js +++ b/flow-typed/Lbry.js @@ -130,6 +130,19 @@ declare type SyncApplyResponse = { data: string, }; +declare type AccountSetResponse = Array<{ + id: string, + is_default: string, + ledger: string, + name: string, + seed: string, + encrypted: string, + private_key: string, + public_key: string, + address_generator: string, + modified_on: string, +}>; + declare type SupportAbandonResponse = GenericTxResponse; // @@ -174,6 +187,7 @@ declare type LbryTypes = { account_unlock: (params: {}) => Promise, account_list: (params: {}) => Promise, account_send: (params: {}) => Promise, + account_set: (params: {}) => Promise, address_is_mine: (params: {}) => Promise, address_unused: (params: {}) => Promise, // New address transaction_list: (params: {}) => Promise, diff --git a/src/lbry.js b/src/lbry.js index ec66286..03e7451 100644 --- a/src/lbry.js +++ b/src/lbry.js @@ -82,6 +82,7 @@ const Lbry: LbryTypes = { account_unlock: (params = {}) => daemonCallWithResult('account_unlock', params), account_list: (params = {}) => daemonCallWithResult('account_list', params), account_send: (params = {}) => daemonCallWithResult('account_send', params), + account_set: (params = {}) => daemonCallWithResult('account_set', params), address_is_mine: (params = {}) => daemonCallWithResult('address_is_mine', params), address_unused: (params = {}) => daemonCallWithResult('address_unused', params), transaction_list: (params = {}) => daemonCallWithResult('transaction_list', params), -- 2.45.2 From ecf9b235fe965023f36c739beaec46ef0ee9dd93 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Thu, 16 May 2019 07:17:26 +0100 Subject: [PATCH 2/7] refactor doPurchaseUri --- dist/bundle.es.js | 347 ++++++++++++++++++++++++---------- src/constants/action_types.js | 6 + src/index.js | 9 + src/redux/actions/file.js | 104 ++++++++++ src/redux/reducers/file.js | 45 +++++ src/redux/selectors/file.js | 19 ++ 6 files changed, 435 insertions(+), 95 deletions(-) create mode 100644 src/redux/actions/file.js create mode 100644 src/redux/reducers/file.js create mode 100644 src/redux/selectors/file.js diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 9a913dd..76ea193 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -7,6 +7,8 @@ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'defau require('proxy-polyfill'); var reselect = require('reselect'); var uuid = _interopDefault(require('uuid/v4')); +var lbryRedux = require('lbry-redux'); +var lbryinc = require('lbryinc'); const WINDOW_FOCUSED = 'WINDOW_FOCUSED'; const DAEMON_READY = 'DAEMON_READY'; @@ -116,6 +118,12 @@ const FETCH_AVAILABILITY_STARTED = 'FETCH_AVAILABILITY_STARTED'; const FETCH_AVAILABILITY_COMPLETED = 'FETCH_AVAILABILITY_COMPLETED'; const FILE_DELETE = 'FILE_DELETE'; const SET_FILE_LIST_SORT = 'SET_FILE_LIST_SORT'; +const PURCHASE_URI_STARTED = 'PURCHASE_URI_STARTED'; +const PURCHASE_URI_COMPLETED = 'PURCHASE_URI_COMPLETED'; +const PURCHASE_URI_FAILED = 'PURCHASE_URI_FAILED'; +const LOADING_FILE_STARTED = 'LOADING_FILE_STARTED'; +const LOADING_FILE_COMPLETED = 'LOADING_FILE_COMPLETED'; +const LOADING_FILE_FAILED = 'LOADING_FILE_FAILED'; // Search const SEARCH_START = 'SEARCH_START'; @@ -327,6 +335,12 @@ var action_types = /*#__PURE__*/Object.freeze({ FETCH_AVAILABILITY_COMPLETED: FETCH_AVAILABILITY_COMPLETED, FILE_DELETE: FILE_DELETE, SET_FILE_LIST_SORT: SET_FILE_LIST_SORT, + PURCHASE_URI_STARTED: PURCHASE_URI_STARTED, + PURCHASE_URI_COMPLETED: PURCHASE_URI_COMPLETED, + PURCHASE_URI_FAILED: PURCHASE_URI_FAILED, + LOADING_FILE_STARTED: LOADING_FILE_STARTED, + LOADING_FILE_COMPLETED: LOADING_FILE_COMPLETED, + LOADING_FILE_FAILED: LOADING_FILE_FAILED, SEARCH_START: SEARCH_START, SEARCH_SUCCESS: SEARCH_SUCCESS, SEARCH_FAIL: SEARCH_FAIL, @@ -2133,6 +2147,92 @@ function doFetchChannelListMine() { }; } +function doLoadFile(uri, saveFile = true) { + return dispatch => { + dispatch({ + type: lbryRedux.ACTIONS.LOADING_FILE_STARTED, + data: { + uri + } + }); + + // set save_file argument to True to save the file (old behaviour) + lbryRedux.Lbry.get({ uri, save_file: saveFile }).then(streamInfo => { + const timeout = streamInfo === null || typeof streamInfo !== 'object' || streamInfo.error === 'Timeout'; + + if (timeout) { + dispatch({ + type: lbryRedux.ACTIONS.LOADING_FILE_FAILED, + data: { uri } + }); + dispatch({ + type: lbryRedux.ACTIONS.PURCHASE_URI_FAILED, + data: { uri } + }); + + dispatch(lbryRedux.doToast({ message: `File timeout for uri ${uri}` })); + } else { + // purchase was completed successfully + dispatch({ + type: lbryRedux.ACTIONS.PURCHASE_URI_COMPLETED, + data: { uri } + }); + } + }).catch(() => { + dispatch({ + type: lbryRedux.ACTIONS.LOADING_FILE_FAILED, + data: { uri } + }); + dispatch({ + type: lbryRedux.ACTIONS.PURCHASE_URI_FAILED, + data: { uri } + }); + + dispatch(lbryRedux.doToast({ + message: `Failed to download ${uri}, please try again. If this problem persists, visit https://lbry.com/faq/support for support.` + })); + }); + }; +} + +function doPurchaseUri(uri, specificCostInfo) { + return (dispatch, getState) => { + dispatch({ + type: lbryRedux.ACTIONS.PURCHASE_URI_STARTED, + data: { uri } + }); + + const state = getState(); + const balance = lbryRedux.selectBalance(state); + const fileInfo = lbryRedux.makeSelectFileInfoForUri(uri)(state); + + // TODO: What about already streaming? + const downloadingByOutpoint = lbryRedux.selectDownloadingByOutpoint(state); + const alreadyDownloading = fileInfo && !!downloadingByOutpoint[fileInfo.outpoint]; + + if (alreadyDownloading) { + dispatch({ + type: lbryRedux.ACTIONS.PURCHASE_URI_FAILED, + data: { uri, error: `Already downloading uri: ${uri}` } + }); + return; + } + + const costInfo = lbryinc.makeSelectCostInfoForUri(uri)(state) || specificCostInfo; + const { cost } = costInfo; + + if (cost > balance) { + dispatch({ + type: lbryRedux.ACTIONS.PURCHASE_URI_FAILED, + data: { uri, error: 'Insufficient credits' } + }); + return; + } + + dispatch(doLoadFile(uri)); + }; +} + const selectState$3 = state => state.fileInfo || {}; const selectFileInfosByOutpoint = reselect.createSelector(selectState$3, state => state.byOutpoint || {}); @@ -2789,15 +2889,58 @@ var _extends$4 = Object.assign || function (target) { for (var i = 1; i < argume const reducers$1 = {}; const defaultState$1 = { + purchasedUris: [], + failedPurchaseUris: [] +}; + +reducers$1[PURCHASE_URI_COMPLETED] = (state, action) => { + const { uri } = action.data; + const newPurchasedUris = state.purchasedUris.slice(); + const newFailedPurchaseUris = state.failedPurchasedUris.slice(); + if (!newPurchasedUris.includes(uri)) { + newPurchasedUris.push(uri); + } + if (newFailedPurchaseUris.includes(uri)) { + newFailedPurchaseUris.splice(newFailedPurchaseUris.indexOf(uri), 1); + } + + return _extends$4({}, state, { + purchasedUris: newPurchasedUris, + failedPurchaseUris: newFailedPurchaseUris + }); +}; + +reducers$1[PURCHASE_URI_FAILED] = (state, action) => { + const { uri } = action.data; + const newFailedPurchaseUris = state.failedPurchasedUris.slice(); + if (!newFailedPurchaseUris.includes(uri)) { + newFailedPurchaseUris.push(uri); + } + + return _extends$4({}, state, { + failedPurchaseUris: newFailedPurchaseUris + }); +}; + +function fileReducer(state = defaultState$1, action) { + const handler = reducers$1[action.type]; + if (handler) return handler(state, action); + return state; +} + +var _extends$5 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +const reducers$2 = {}; +const defaultState$2 = { fileListPublishedSort: DATE_NEW, fileListDownloadedSort: DATE_NEW }; -reducers$1[FILE_LIST_STARTED] = state => Object.assign({}, state, { +reducers$2[FILE_LIST_STARTED] = state => Object.assign({}, state, { isFetchingFileList: true }); -reducers$1[FILE_LIST_SUCCEEDED] = (state, action) => { +reducers$2[FILE_LIST_SUCCEEDED] = (state, action) => { const { fileInfos } = action.data; const newByOutpoint = Object.assign({}, state.byOutpoint); const pendingByOutpoint = Object.assign({}, state.pendingByOutpoint); @@ -2815,7 +2958,7 @@ reducers$1[FILE_LIST_SUCCEEDED] = (state, action) => { }); }; -reducers$1[FETCH_FILE_INFO_STARTED] = (state, action) => { +reducers$2[FETCH_FILE_INFO_STARTED] = (state, action) => { const { outpoint } = action.data; const newFetching = Object.assign({}, state.fetching); @@ -2826,7 +2969,7 @@ reducers$1[FETCH_FILE_INFO_STARTED] = (state, action) => { }); }; -reducers$1[FETCH_FILE_INFO_COMPLETED] = (state, action) => { +reducers$2[FETCH_FILE_INFO_COMPLETED] = (state, action) => { const { fileInfo, outpoint } = action.data; const newByOutpoint = Object.assign({}, state.byOutpoint); @@ -2841,7 +2984,7 @@ reducers$1[FETCH_FILE_INFO_COMPLETED] = (state, action) => { }); }; -reducers$1[DOWNLOADING_STARTED] = (state, action) => { +reducers$2[DOWNLOADING_STARTED] = (state, action) => { const { uri, outpoint, fileInfo } = action.data; const newByOutpoint = Object.assign({}, state.byOutpoint); @@ -2859,7 +3002,7 @@ reducers$1[DOWNLOADING_STARTED] = (state, action) => { }); }; -reducers$1[DOWNLOADING_PROGRESSED] = (state, action) => { +reducers$2[DOWNLOADING_PROGRESSED] = (state, action) => { const { outpoint, fileInfo } = action.data; const newByOutpoint = Object.assign({}, state.byOutpoint); @@ -2874,7 +3017,7 @@ reducers$1[DOWNLOADING_PROGRESSED] = (state, action) => { }); }; -reducers$1[DOWNLOADING_CANCELED] = (state, action) => { +reducers$2[DOWNLOADING_CANCELED] = (state, action) => { const { outpoint } = action.data; const newDownloading = Object.assign({}, state.downloadingByOutpoint); @@ -2885,7 +3028,7 @@ reducers$1[DOWNLOADING_CANCELED] = (state, action) => { }); }; -reducers$1[DOWNLOADING_COMPLETED] = (state, action) => { +reducers$2[DOWNLOADING_COMPLETED] = (state, action) => { const { outpoint, fileInfo } = action.data; const newByOutpoint = Object.assign({}, state.byOutpoint); @@ -2900,7 +3043,7 @@ reducers$1[DOWNLOADING_COMPLETED] = (state, action) => { }); }; -reducers$1[FILE_DELETE] = (state, action) => { +reducers$2[FILE_DELETE] = (state, action) => { const { outpoint } = action.data; const newByOutpoint = Object.assign({}, state.byOutpoint); @@ -2915,37 +3058,37 @@ reducers$1[FILE_DELETE] = (state, action) => { }); }; -reducers$1[LOADING_VIDEO_STARTED] = (state, action) => { +reducers$2[LOADING_VIDEO_STARTED] = (state, action) => { const { uri } = action.data; const newLoading = Object.assign({}, state.urisLoading); newLoading[uri] = true; - const newErrors = _extends$4({}, state.errors); + const newErrors = _extends$5({}, state.errors); if (uri in newErrors) delete newErrors[uri]; return Object.assign({}, state, { urisLoading: newLoading, - errors: _extends$4({}, newErrors) + errors: _extends$5({}, newErrors) }); }; -reducers$1[LOADING_VIDEO_FAILED] = (state, action) => { +reducers$2[LOADING_VIDEO_FAILED] = (state, action) => { const { uri } = action.data; const newLoading = Object.assign({}, state.urisLoading); delete newLoading[uri]; - const newErrors = _extends$4({}, state.errors); + const newErrors = _extends$5({}, state.errors); newErrors[uri] = true; return Object.assign({}, state, { urisLoading: newLoading, - errors: _extends$4({}, newErrors) + errors: _extends$5({}, newErrors) }); }; -reducers$1[FETCH_DATE] = (state, action) => { +reducers$2[FETCH_DATE] = (state, action) => { const { time } = action.data; if (time) { return Object.assign({}, state, { @@ -2955,7 +3098,7 @@ reducers$1[FETCH_DATE] = (state, action) => { return null; }; -reducers$1[SET_FILE_LIST_SORT] = (state, action) => { +reducers$2[SET_FILE_LIST_SORT] = (state, action) => { const pageSortStates = { [PUBLISHED]: 'fileListPublishedSort', [DOWNLOADED]: 'fileListDownloadedSort' @@ -2968,8 +3111,8 @@ reducers$1[SET_FILE_LIST_SORT] = (state, action) => { }); }; -function fileInfoReducer(state = defaultState$1, action) { - const handler = reducers$1[action.type]; +function fileInfoReducer(state = defaultState$2, action) { + const handler = reducers$2[action.type]; if (handler) return handler(state, action); return state; } @@ -2992,9 +3135,9 @@ const handleActions = (actionMap, defaultState) => (state = defaultState, action return state; }; -var _extends$5 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +var _extends$6 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -const defaultState$2 = { +const defaultState$3 = { notifications: [], toasts: [], errors: [] @@ -3007,7 +3150,7 @@ const notificationsReducer = handleActions({ const newToasts = state.toasts.slice(); newToasts.push(toast); - return _extends$5({}, state, { + return _extends$6({}, state, { toasts: newToasts }); }, @@ -3015,7 +3158,7 @@ const notificationsReducer = handleActions({ const newToasts = state.toasts.slice(); newToasts.shift(); - return _extends$5({}, state, { + return _extends$6({}, state, { toasts: newToasts }); }, @@ -3026,7 +3169,7 @@ const notificationsReducer = handleActions({ const newNotifications = state.notifications.slice(); newNotifications.push(notification); - return _extends$5({}, state, { + return _extends$6({}, state, { notifications: newNotifications }); }, @@ -3037,7 +3180,7 @@ const notificationsReducer = handleActions({ notifications = notifications.map(pastNotification => pastNotification.id === notification.id ? notification : pastNotification); - return _extends$5({}, state, { + return _extends$6({}, state, { notifications }); }, @@ -3046,7 +3189,7 @@ const notificationsReducer = handleActions({ let newNotifications = state.notifications.slice(); newNotifications = newNotifications.filter(notification => notification.id !== id); - return _extends$5({}, state, { + return _extends$6({}, state, { notifications: newNotifications }); }, @@ -3057,7 +3200,7 @@ const notificationsReducer = handleActions({ const newErrors = state.errors.slice(); newErrors.push(error); - return _extends$5({}, state, { + return _extends$6({}, state, { errors: newErrors }); }, @@ -3065,15 +3208,15 @@ const notificationsReducer = handleActions({ const newErrors = state.errors.slice(); newErrors.shift(); - return _extends$5({}, state, { + return _extends$6({}, state, { errors: newErrors }); } -}, defaultState$2); +}, defaultState$3); -var _extends$6 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +var _extends$7 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -const defaultState$3 = { +const defaultState$4 = { isActive: false, // does the user have any typed text in the search input focused: false, // is the search input focused searchQuery: '', // needs to be an empty string for input focusing @@ -3091,29 +3234,29 @@ const defaultState$3 = { }; const searchReducer = handleActions({ - [SEARCH_START]: state => _extends$6({}, state, { + [SEARCH_START]: state => _extends$7({}, state, { searching: true }), [SEARCH_SUCCESS]: (state, action) => { const { query, uris } = action.data; - return _extends$6({}, state, { + return _extends$7({}, state, { searching: false, urisByQuery: Object.assign({}, state.urisByQuery, { [query]: uris }) }); }, - [SEARCH_FAIL]: state => _extends$6({}, state, { + [SEARCH_FAIL]: state => _extends$7({}, state, { searching: false }), - [UPDATE_SEARCH_QUERY]: (state, action) => _extends$6({}, state, { + [UPDATE_SEARCH_QUERY]: (state, action) => _extends$7({}, state, { searchQuery: action.data.query, isActive: true }), - [UPDATE_SEARCH_SUGGESTIONS]: (state, action) => _extends$6({}, state, { - suggestions: _extends$6({}, state.suggestions, { + [UPDATE_SEARCH_SUGGESTIONS]: (state, action) => _extends$7({}, state, { + suggestions: _extends$7({}, state.suggestions, { [action.data.query]: action.data.suggestions }) }), @@ -3121,27 +3264,27 @@ const searchReducer = handleActions({ // sets isActive to false so the uri will be populated correctly if the // user is on a file page. The search query will still be present on any // other page - [DISMISS_NOTIFICATION]: state => _extends$6({}, state, { + [DISMISS_NOTIFICATION]: state => _extends$7({}, state, { isActive: false }), - [SEARCH_FOCUS]: state => _extends$6({}, state, { + [SEARCH_FOCUS]: state => _extends$7({}, state, { focused: true }), - [SEARCH_BLUR]: state => _extends$6({}, state, { + [SEARCH_BLUR]: state => _extends$7({}, state, { focused: false }), [UPDATE_SEARCH_OPTIONS]: (state, action) => { const { options: oldOptions } = state; const newOptions = action.data; - const options = _extends$6({}, oldOptions, newOptions); - return _extends$6({}, state, { + const options = _extends$7({}, oldOptions, newOptions); + return _extends$7({}, state, { options }); } -}, defaultState$3); +}, defaultState$4); -var _extends$7 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +var _extends$8 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; const buildDraftTransaction = () => ({ amount: undefined, @@ -3152,7 +3295,7 @@ const buildDraftTransaction = () => ({ // See details in https://github.com/lbryio/lbry/issues/1307 -const defaultState$4 = { +const defaultState$5 = { balance: undefined, totalBalance: undefined, latestBlock: undefined, @@ -3181,25 +3324,25 @@ const defaultState$4 = { }; const walletReducer = handleActions({ - [FETCH_TRANSACTIONS_STARTED]: state => _extends$7({}, state, { + [FETCH_TRANSACTIONS_STARTED]: state => _extends$8({}, state, { fetchingTransactions: true }), [FETCH_TRANSACTIONS_COMPLETED]: (state, action) => { - const byId = _extends$7({}, state.transactions); + const byId = _extends$8({}, state.transactions); const { transactions } = action.data; transactions.forEach(transaction => { byId[transaction.txid] = transaction; }); - return _extends$7({}, state, { + return _extends$8({}, state, { transactions: byId, fetchingTransactions: false }); }, - [FETCH_SUPPORTS_STARTED]: state => _extends$7({}, state, { + [FETCH_SUPPORTS_STARTED]: state => _extends$8({}, state, { fetchingSupports: true }), @@ -3212,7 +3355,7 @@ const walletReducer = handleActions({ byOutpoint[`${txid}:${nout}`] = transaction; }); - return _extends$7({}, state, { supports: byOutpoint, fetchingSupports: false }); + return _extends$8({}, state, { supports: byOutpoint, fetchingSupports: false }); }, [ABANDON_SUPPORT_STARTED]: (state, action) => { @@ -3221,7 +3364,7 @@ const walletReducer = handleActions({ currentlyAbandoning[outpoint] = true; - return _extends$7({}, state, { + return _extends$8({}, state, { abandoningSupportsByOutpoint: currentlyAbandoning }); }, @@ -3234,56 +3377,56 @@ const walletReducer = handleActions({ delete currentlyAbandoning[outpoint]; delete byOutpoint[outpoint]; - return _extends$7({}, state, { + return _extends$8({}, state, { supports: byOutpoint, abandoningSupportsById: currentlyAbandoning }); }, - [GET_NEW_ADDRESS_STARTED]: state => _extends$7({}, state, { + [GET_NEW_ADDRESS_STARTED]: state => _extends$8({}, state, { gettingNewAddress: true }), [GET_NEW_ADDRESS_COMPLETED]: (state, action) => { const { address } = action.data; - return _extends$7({}, state, { gettingNewAddress: false, receiveAddress: address }); + return _extends$8({}, state, { gettingNewAddress: false, receiveAddress: address }); }, - [UPDATE_BALANCE]: (state, action) => _extends$7({}, state, { + [UPDATE_BALANCE]: (state, action) => _extends$8({}, state, { balance: action.data.balance }), - [UPDATE_TOTAL_BALANCE]: (state, action) => _extends$7({}, state, { + [UPDATE_TOTAL_BALANCE]: (state, action) => _extends$8({}, state, { totalBalance: action.data.totalBalance }), - [CHECK_ADDRESS_IS_MINE_STARTED]: state => _extends$7({}, state, { + [CHECK_ADDRESS_IS_MINE_STARTED]: state => _extends$8({}, state, { checkingAddressOwnership: true }), - [CHECK_ADDRESS_IS_MINE_COMPLETED]: state => _extends$7({}, state, { + [CHECK_ADDRESS_IS_MINE_COMPLETED]: state => _extends$8({}, state, { checkingAddressOwnership: false }), [SET_DRAFT_TRANSACTION_AMOUNT]: (state, action) => { const oldDraft = state.draftTransaction; - const newDraft = _extends$7({}, oldDraft, { amount: parseFloat(action.data.amount) }); + const newDraft = _extends$8({}, oldDraft, { amount: parseFloat(action.data.amount) }); - return _extends$7({}, state, { draftTransaction: newDraft }); + return _extends$8({}, state, { draftTransaction: newDraft }); }, [SET_DRAFT_TRANSACTION_ADDRESS]: (state, action) => { const oldDraft = state.draftTransaction; - const newDraft = _extends$7({}, oldDraft, { address: action.data.address }); + const newDraft = _extends$8({}, oldDraft, { address: action.data.address }); - return _extends$7({}, state, { draftTransaction: newDraft }); + return _extends$8({}, state, { draftTransaction: newDraft }); }, [SEND_TRANSACTION_STARTED]: state => { - const newDraftTransaction = _extends$7({}, state.draftTransaction, { sending: true }); + const newDraftTransaction = _extends$8({}, state.draftTransaction, { sending: true }); - return _extends$7({}, state, { draftTransaction: newDraftTransaction }); + return _extends$8({}, state, { draftTransaction: newDraftTransaction }); }, [SEND_TRANSACTION_COMPLETED]: state => Object.assign({}, state, { @@ -3296,127 +3439,127 @@ const walletReducer = handleActions({ error: action.data.error }); - return _extends$7({}, state, { draftTransaction: newDraftTransaction }); + return _extends$8({}, state, { draftTransaction: newDraftTransaction }); }, - [SUPPORT_TRANSACTION_STARTED]: state => _extends$7({}, state, { + [SUPPORT_TRANSACTION_STARTED]: state => _extends$8({}, state, { sendingSupport: true }), - [SUPPORT_TRANSACTION_COMPLETED]: state => _extends$7({}, state, { + [SUPPORT_TRANSACTION_COMPLETED]: state => _extends$8({}, state, { sendingSupport: false }), - [SUPPORT_TRANSACTION_FAILED]: (state, action) => _extends$7({}, state, { + [SUPPORT_TRANSACTION_FAILED]: (state, action) => _extends$8({}, state, { error: action.data.error, sendingSupport: false }), - [WALLET_STATUS_COMPLETED]: (state, action) => _extends$7({}, state, { + [WALLET_STATUS_COMPLETED]: (state, action) => _extends$8({}, state, { walletIsEncrypted: action.result }), - [WALLET_ENCRYPT_START]: state => _extends$7({}, state, { + [WALLET_ENCRYPT_START]: state => _extends$8({}, state, { walletEncryptPending: true, walletEncryptSucceded: null, walletEncryptResult: null }), - [WALLET_ENCRYPT_COMPLETED]: (state, action) => _extends$7({}, state, { + [WALLET_ENCRYPT_COMPLETED]: (state, action) => _extends$8({}, state, { walletEncryptPending: false, walletEncryptSucceded: true, walletEncryptResult: action.result }), - [WALLET_ENCRYPT_FAILED]: (state, action) => _extends$7({}, state, { + [WALLET_ENCRYPT_FAILED]: (state, action) => _extends$8({}, state, { walletEncryptPending: false, walletEncryptSucceded: false, walletEncryptResult: action.result }), - [WALLET_DECRYPT_START]: state => _extends$7({}, state, { + [WALLET_DECRYPT_START]: state => _extends$8({}, state, { walletDecryptPending: true, walletDecryptSucceded: null, walletDecryptResult: null }), - [WALLET_DECRYPT_COMPLETED]: (state, action) => _extends$7({}, state, { + [WALLET_DECRYPT_COMPLETED]: (state, action) => _extends$8({}, state, { walletDecryptPending: false, walletDecryptSucceded: true, walletDecryptResult: action.result }), - [WALLET_DECRYPT_FAILED]: (state, action) => _extends$7({}, state, { + [WALLET_DECRYPT_FAILED]: (state, action) => _extends$8({}, state, { walletDecryptPending: false, walletDecryptSucceded: false, walletDecryptResult: action.result }), - [WALLET_UNLOCK_START]: state => _extends$7({}, state, { + [WALLET_UNLOCK_START]: state => _extends$8({}, state, { walletUnlockPending: true, walletUnlockSucceded: null, walletUnlockResult: null }), - [WALLET_UNLOCK_COMPLETED]: (state, action) => _extends$7({}, state, { + [WALLET_UNLOCK_COMPLETED]: (state, action) => _extends$8({}, state, { walletUnlockPending: false, walletUnlockSucceded: true, walletUnlockResult: action.result }), - [WALLET_UNLOCK_FAILED]: (state, action) => _extends$7({}, state, { + [WALLET_UNLOCK_FAILED]: (state, action) => _extends$8({}, state, { walletUnlockPending: false, walletUnlockSucceded: false, walletUnlockResult: action.result }), - [WALLET_LOCK_START]: state => _extends$7({}, state, { + [WALLET_LOCK_START]: state => _extends$8({}, state, { walletLockPending: false, walletLockSucceded: null, walletLockResult: null }), - [WALLET_LOCK_COMPLETED]: (state, action) => _extends$7({}, state, { + [WALLET_LOCK_COMPLETED]: (state, action) => _extends$8({}, state, { walletLockPending: false, walletLockSucceded: true, walletLockResult: action.result }), - [WALLET_LOCK_FAILED]: (state, action) => _extends$7({}, state, { + [WALLET_LOCK_FAILED]: (state, action) => _extends$8({}, state, { walletLockPending: false, walletLockSucceded: false, walletLockResult: action.result }), - [SET_TRANSACTION_LIST_FILTER]: (state, action) => _extends$7({}, state, { + [SET_TRANSACTION_LIST_FILTER]: (state, action) => _extends$8({}, state, { transactionListFilter: action.data }), - [UPDATE_CURRENT_HEIGHT]: (state, action) => _extends$7({}, state, { + [UPDATE_CURRENT_HEIGHT]: (state, action) => _extends$8({}, state, { latestBlock: action.data }) -}, defaultState$4); +}, defaultState$5); -var _extends$8 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +var _extends$9 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -const reducers$2 = {}; -const defaultState$5 = { +const reducers$3 = {}; +const defaultState$6 = { positions: {} }; -reducers$2[SET_CONTENT_POSITION] = (state, action) => { +reducers$3[SET_CONTENT_POSITION] = (state, action) => { const { claimId, outpoint, position } = action.data; - return _extends$8({}, state, { - positions: _extends$8({}, state.positions, { - [claimId]: _extends$8({}, state.positions[claimId], { + return _extends$9({}, state, { + positions: _extends$9({}, state.positions, { + [claimId]: _extends$9({}, state.positions[claimId], { [outpoint]: position }) }) }); }; -function contentReducer(state = defaultState$5, action) { - const handler = reducers$2[action.type]; +function contentReducer(state = defaultState$6, action) { + const handler = reducers$3[action.type]; if (handler) return handler(state, action); return state; } @@ -3432,14 +3575,14 @@ const makeSelectContentPositionForUri = uri => reselect.createSelector(selectSta return state.positions[id] ? state.positions[id][outpoint] : null; }); -var _extends$9 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +var _extends$a = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; const selectState$5 = state => state.notifications || {}; const selectToast = reselect.createSelector(selectState$5, state => { if (state.toasts.length) { const { id, params } = state.toasts[0]; - return _extends$9({ + return _extends$a({ id }, params); } @@ -3458,6 +3601,14 @@ const selectError = reselect.createSelector(selectState$5, state => { return null; }); +const selectState$6 = state => state.file || {}; + +const selectPurchasedUris = reselect.createSelector(selectState$6, state => state.purchasedUris); + +const selectFailedPurchaseUris = reselect.createSelector(selectState$6, state => state.failedPurchaseUris); + +const selectLastPurchasedUri = reselect.createSelector(selectState$6, state => state.purchasedUris.length > 0 ? state.purchasedUris[state.purchasedUris.length - 1] : null); + exports.ACTIONS = action_types; exports.Lbry = lbryProxy; exports.PAGES = pages; @@ -3490,6 +3641,8 @@ exports.doFetchTransactions = doFetchTransactions; exports.doFileList = doFileList; exports.doFocusSearchInput = doFocusSearchInput; exports.doGetNewAddress = doGetNewAddress; +exports.doLoadFile = doLoadFile; +exports.doPurchaseUri = doPurchaseUri; exports.doResolveUri = doResolveUri; exports.doResolveUris = doResolveUris; exports.doSearch = doSearch; @@ -3511,6 +3664,7 @@ exports.doWalletEncrypt = doWalletEncrypt; exports.doWalletStatus = doWalletStatus; exports.doWalletUnlock = doWalletUnlock; exports.fileInfoReducer = fileInfoReducer; +exports.fileReducer = fileReducer; exports.formatCredits = formatCredits; exports.formatFullPrice = formatFullPrice; exports.isClaimNsfw = isClaimNsfw; @@ -3571,6 +3725,7 @@ exports.selectDraftTransactionAddress = selectDraftTransactionAddress; exports.selectDraftTransactionAmount = selectDraftTransactionAmount; exports.selectDraftTransactionError = selectDraftTransactionError; exports.selectError = selectError; +exports.selectFailedPurchaseUris = selectFailedPurchaseUris; exports.selectFetchingMyChannels = selectFetchingMyChannels; exports.selectFileInfosByOutpoint = selectFileInfosByOutpoint; exports.selectFileInfosDownloaded = selectFileInfosDownloaded; @@ -3584,6 +3739,7 @@ exports.selectIsFetchingFileListDownloadedOrPublished = selectIsFetchingFileList exports.selectIsFetchingTransactions = selectIsFetchingTransactions; exports.selectIsSearching = selectIsSearching; exports.selectIsSendingSupport = selectIsSendingSupport; +exports.selectLastPurchasedUri = selectLastPurchasedUri; exports.selectMyActiveClaims = selectMyActiveClaims; exports.selectMyChannelClaims = selectMyChannelClaims; exports.selectMyClaims = selectMyClaims; @@ -3593,6 +3749,7 @@ exports.selectMyClaimsWithoutChannels = selectMyClaimsWithoutChannels; exports.selectPendingById = selectPendingById; exports.selectPendingClaims = selectPendingClaims; exports.selectPlayingUri = selectPlayingUri; +exports.selectPurchasedUris = selectPurchasedUris; exports.selectReceiveAddress = selectReceiveAddress; exports.selectRecentTransactions = selectRecentTransactions; exports.selectResolvingUris = selectResolvingUris; diff --git a/src/constants/action_types.js b/src/constants/action_types.js index 95d4035..795eea4 100644 --- a/src/constants/action_types.js +++ b/src/constants/action_types.js @@ -106,6 +106,12 @@ export const FETCH_AVAILABILITY_STARTED = 'FETCH_AVAILABILITY_STARTED'; export const FETCH_AVAILABILITY_COMPLETED = 'FETCH_AVAILABILITY_COMPLETED'; export const FILE_DELETE = 'FILE_DELETE'; export const SET_FILE_LIST_SORT = 'SET_FILE_LIST_SORT'; +export const PURCHASE_URI_STARTED = 'PURCHASE_URI_STARTED'; +export const PURCHASE_URI_COMPLETED = 'PURCHASE_URI_COMPLETED'; +export const PURCHASE_URI_FAILED = 'PURCHASE_URI_FAILED'; +export const LOADING_FILE_STARTED = 'LOADING_FILE_STARTED'; +export const LOADING_FILE_COMPLETED = 'LOADING_FILE_COMPLETED'; +export const LOADING_FILE_FAILED = 'LOADING_FILE_FAILED'; // Search export const SEARCH_START = 'SEARCH_START'; diff --git a/src/index.js b/src/index.js index 9fa1fff..3e4c938 100644 --- a/src/index.js +++ b/src/index.js @@ -47,6 +47,8 @@ export { doCreateChannel, } from 'redux/actions/claims'; +export { doPurchaseUri, doLoadFile } from 'redux/actions/file'; + export { doFetchFileInfo, doFileList, @@ -93,6 +95,7 @@ export { isClaimNsfw } from 'util/claim'; // reducers export { claimsReducer } from 'redux/reducers/claims'; +export { fileReducer } from 'redux/reducers/file'; export { fileInfoReducer } from 'redux/reducers/file_info'; export { notificationsReducer } from 'redux/reducers/notifications'; export { searchReducer } from 'redux/reducers/search'; @@ -104,6 +107,12 @@ export { makeSelectContentPositionForUri } from 'redux/selectors/content'; export { selectToast, selectError } from 'redux/selectors/notifications'; +export { + selectPurchasedUris, + selectFailedPurchaseUris, + selectLastPurchasedUri, +} from 'redux/selectors/file'; + export { makeSelectClaimForUri, makeSelectClaimIsMine, diff --git a/src/redux/actions/file.js b/src/redux/actions/file.js new file mode 100644 index 0000000..2a7ff00 --- /dev/null +++ b/src/redux/actions/file.js @@ -0,0 +1,104 @@ +import { + ACTIONS, + Lbry, + doToast, + selectBalance, + makeSelectFileInfoForUri, + selectDownloadingByOutpoint, +} from 'lbry-redux'; +import { makeSelectCostInfoForUri } from 'lbryinc'; + +export function doLoadFile(uri, saveFile = true) { + return dispatch => { + dispatch({ + type: ACTIONS.LOADING_FILE_STARTED, + data: { + uri, + }, + }); + + // set save_file argument to True to save the file (old behaviour) + Lbry.get({ uri, save_file: saveFile }) + .then(streamInfo => { + const timeout = + streamInfo === null || typeof streamInfo !== 'object' || streamInfo.error === 'Timeout'; + + if (timeout) { + dispatch({ + type: ACTIONS.LOADING_FILE_FAILED, + data: { uri }, + }); + dispatch({ + type: ACTIONS.PURCHASE_URI_FAILED, + data: { uri }, + }); + + dispatch(doToast({ message: `File timeout for uri ${uri}` })); + } else { + // purchase was completed successfully + dispatch({ + type: ACTIONS.PURCHASE_URI_COMPLETED, + data: { uri }, + }); + } + }) + .catch(() => { + dispatch({ + type: ACTIONS.LOADING_FILE_FAILED, + data: { uri }, + }); + dispatch({ + type: ACTIONS.PURCHASE_URI_FAILED, + data: { uri }, + }); + + dispatch( + doToast({ + message: `Failed to download ${uri}, please try again. If this problem persists, visit https://lbry.com/faq/support for support.`, + }) + ); + }); + }; +} + +export function doPurchaseUri(uri, specificCostInfo) { + return (dispatch, getState) => { + dispatch({ + type: ACTIONS.PURCHASE_URI_STARTED, + data: { uri }, + }); + + const state = getState(); + const balance = selectBalance(state); + const fileInfo = makeSelectFileInfoForUri(uri)(state); + + // TODO: What about already streaming? + const downloadingByOutpoint = selectDownloadingByOutpoint(state); + const alreadyDownloading = fileInfo && !!downloadingByOutpoint[fileInfo.outpoint]; + + if (alreadyDownloading) { + dispatch({ + type: ACTIONS.PURCHASE_URI_FAILED, + data: { uri, error: `Already downloading uri: ${uri}` }, + }); + + Promise.resolve(); + return; + } + + const costInfo = makeSelectCostInfoForUri(uri)(state) || specificCostInfo; + const { cost } = costInfo; + + if (cost > balance) { + dispatch({ + type: ACTIONS.PURCHASE_URI_FAILED, + data: { uri, error: 'Insufficient credits' }, + }); + + Promise.resolve(); + return; + } + + dispatch(doLoadFile(uri)); + }; +} diff --git a/src/redux/reducers/file.js b/src/redux/reducers/file.js new file mode 100644 index 0000000..830ffc7 --- /dev/null +++ b/src/redux/reducers/file.js @@ -0,0 +1,45 @@ +import * as ACTIONS from 'constants/action_types'; +import { buildURI, parseURI } from 'lbryURI'; + +const reducers = {}; +const defaultState = { + purchasedUris: [], + failedPurchaseUris: [], +}; + +reducers[ACTIONS.PURCHASE_URI_COMPLETED] = (state, action) => { + const { uri } = action.data; + const newPurchasedUris = state.purchasedUris.slice(); + const newFailedPurchaseUris = state.failedPurchasedUris.slice(); + if (!newPurchasedUris.includes(uri)) { + newPurchasedUris.push(uri); + } + if (newFailedPurchaseUris.includes(uri)) { + newFailedPurchaseUris.splice(newFailedPurchaseUris.indexOf(uri), 1); + } + + return { + ...state, + purchasedUris: newPurchasedUris, + failedPurchaseUris: newFailedPurchaseUris, + }; +}; + +reducers[ACTIONS.PURCHASE_URI_FAILED] = (state, action) => { + const { uri } = action.data; + const newFailedPurchaseUris = state.failedPurchasedUris.slice(); + if (!newFailedPurchaseUris.includes(uri)) { + newFailedPurchaseUris.push(uri); + } + + return { + ...state, + failedPurchaseUris: newFailedPurchaseUris, + }; +}; + +export function fileReducer(state = defaultState, action) { + const handler = reducers[action.type]; + if (handler) return handler(state, action); + return state; +} diff --git a/src/redux/selectors/file.js b/src/redux/selectors/file.js new file mode 100644 index 0000000..91bb7f5 --- /dev/null +++ b/src/redux/selectors/file.js @@ -0,0 +1,19 @@ +import { createSelector } from 'reselect'; + +export const selectState = state => state.file || {}; + +export const selectPurchasedUris = createSelector( + selectState, + state => state.purchasedUris +); + +export const selectFailedPurchaseUris = createSelector( + selectState, + state => state.failedPurchaseUris +); + +export const selectLastPurchasedUri = createSelector( + selectState, + state => + state.purchasedUris.length > 0 ? state.purchasedUris[state.purchasedUris.length - 1] : null +); -- 2.45.2 From f1e3e24f82c0719dd41e4090b1c10eb53598c379 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Thu, 16 May 2019 15:44:09 +0100 Subject: [PATCH 3/7] handle streaming. fix imports. --- dist/bundle.es.js | 218 +++++++++++++++++++----------------- src/index.js | 4 +- src/redux/actions/file.js | 24 ++-- src/redux/reducers/file.js | 13 ++- src/redux/selectors/file.js | 15 ++- 5 files changed, 152 insertions(+), 122 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 76ea193..102c993 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -7,7 +7,6 @@ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'defau require('proxy-polyfill'); var reselect = require('reselect'); var uuid = _interopDefault(require('uuid/v4')); -var lbryRedux = require('lbry-redux'); var lbryinc = require('lbryinc'); const WINDOW_FOCUSED = 'WINDOW_FOCUSED'; @@ -2147,92 +2146,6 @@ function doFetchChannelListMine() { }; } -function doLoadFile(uri, saveFile = true) { - return dispatch => { - dispatch({ - type: lbryRedux.ACTIONS.LOADING_FILE_STARTED, - data: { - uri - } - }); - - // set save_file argument to True to save the file (old behaviour) - lbryRedux.Lbry.get({ uri, save_file: saveFile }).then(streamInfo => { - const timeout = streamInfo === null || typeof streamInfo !== 'object' || streamInfo.error === 'Timeout'; - - if (timeout) { - dispatch({ - type: lbryRedux.ACTIONS.LOADING_FILE_FAILED, - data: { uri } - }); - dispatch({ - type: lbryRedux.ACTIONS.PURCHASE_URI_FAILED, - data: { uri } - }); - - dispatch(lbryRedux.doToast({ message: `File timeout for uri ${uri}` })); - } else { - // purchase was completed successfully - dispatch({ - type: lbryRedux.ACTIONS.PURCHASE_URI_COMPLETED, - data: { uri } - }); - } - }).catch(() => { - dispatch({ - type: lbryRedux.ACTIONS.LOADING_FILE_FAILED, - data: { uri } - }); - dispatch({ - type: lbryRedux.ACTIONS.PURCHASE_URI_FAILED, - data: { uri } - }); - - dispatch(lbryRedux.doToast({ - message: `Failed to download ${uri}, please try again. If this problem persists, visit https://lbry.com/faq/support for support.` - })); - }); - }; -} - -function doPurchaseUri(uri, specificCostInfo) { - return (dispatch, getState) => { - dispatch({ - type: lbryRedux.ACTIONS.PURCHASE_URI_STARTED, - data: { uri } - }); - - const state = getState(); - const balance = lbryRedux.selectBalance(state); - const fileInfo = lbryRedux.makeSelectFileInfoForUri(uri)(state); - - // TODO: What about already streaming? - const downloadingByOutpoint = lbryRedux.selectDownloadingByOutpoint(state); - const alreadyDownloading = fileInfo && !!downloadingByOutpoint[fileInfo.outpoint]; - - if (alreadyDownloading) { - dispatch({ - type: lbryRedux.ACTIONS.PURCHASE_URI_FAILED, - data: { uri, error: `Already downloading uri: ${uri}` } - }); - return; - } - - const costInfo = lbryinc.makeSelectCostInfoForUri(uri)(state) || specificCostInfo; - const { cost } = costInfo; - - if (cost > balance) { - dispatch({ - type: lbryRedux.ACTIONS.PURCHASE_URI_FAILED, - data: { uri, error: 'Insufficient credits' } - }); - return; - } - - dispatch(doLoadFile(uri)); - }; -} - const selectState$3 = state => state.fileInfo || {}; const selectFileInfosByOutpoint = reselect.createSelector(selectState$3, state => state.byOutpoint || {}); @@ -2394,6 +2307,104 @@ const selectFileListPublishedSort = reselect.createSelector(selectState$3, state const selectFileListDownloadedSort = reselect.createSelector(selectState$3, state => state.fileListDownloadedSort); +const selectState$4 = state => state.file || {}; + +const selectFailedPurchaseUris = reselect.createSelector(selectState$4, state => state.failedPurchaseUris); + +const selectPurchasedUris = reselect.createSelector(selectState$4, state => state.purchasedUris); + +const selectPurchasedStreamingUrls = reselect.createSelector(selectState$4, state => state.purchasedStreamingUrls); + +const selectLastPurchasedUri = reselect.createSelector(selectState$4, state => state.purchasedUris.length > 0 ? state.purchasedUris[state.purchasedUris.length - 1] : null); + +const makeSelectStreamingUrlForUri = uri => reselect.createSelector(selectPurchasedStreamingUrls, streamingUrls => streamingUrls && streamingUrls[uri]); + +function doLoadFile(uri, saveFile = true) { + return dispatch => { + dispatch({ + type: LOADING_FILE_STARTED, + data: { + uri + } + }); + + // set save_file argument to True to save the file (old behaviour) + lbryProxy.get({ uri, save_file: saveFile }).then(streamInfo => { + const timeout = streamInfo === null || typeof streamInfo !== 'object' || streamInfo.error === 'Timeout'; + + if (timeout) { + dispatch({ + type: LOADING_FILE_FAILED, + data: { uri } + }); + dispatch({ + type: PURCHASE_URI_FAILED, + data: { uri } + }); + + dispatch(doToast({ message: `File timeout for uri ${uri}` })); + } else { + // purchase was completed successfully + const { streaming_url: streamingUrl } = streamInfo; + dispatch({ + type: PURCHASE_URI_COMPLETED, + data: { uri, streamingUrl: !saveFile && streamingUrl ? streamingUrl : null } + }); + } + }).catch(() => { + dispatch({ + type: LOADING_FILE_FAILED, + data: { uri } + }); + dispatch({ + type: PURCHASE_URI_FAILED, + data: { uri } + }); + + dispatch(doToast({ + message: `Failed to download ${uri}, please try again. If this problem persists, visit https://lbry.com/faq/support for support.` + })); + }); + }; +} + +function doPurchaseUri(uri, specificCostInfo) { + return (dispatch, getState) => { + dispatch({ + type: PURCHASE_URI_STARTED, + data: { uri } + }); + + const state = getState(); + const balance = selectBalance(state); + const fileInfo = makeSelectFileInfoForUri(uri)(state); + const downloadingByOutpoint = selectDownloadingByOutpoint(state); + const alreadyDownloading = fileInfo && !!downloadingByOutpoint[fileInfo.outpoint]; + const alreadyStreaming = makeSelectStreamingUrlForUri(uri)(state); + + if (alreadyDownloading || alreadyStreaming) { + dispatch({ + type: PURCHASE_URI_FAILED, + data: { uri, error: `Already downloading / streaming uri: ${uri}` } + }); + return; + } + + const costInfo = lbryinc.makeSelectCostInfoForUri(uri)(state) || specificCostInfo; + const { cost } = costInfo; + + if (cost > balance) { + dispatch({ + type: PURCHASE_URI_FAILED, + data: { uri, error: 'Insufficient credits' } + }); + return; + } + + dispatch(doLoadFile(uri)); + }; +} + function doFetchFileInfo(uri) { return (dispatch, getState) => { const state = getState(); @@ -2889,24 +2900,31 @@ var _extends$4 = Object.assign || function (target) { for (var i = 1; i < argume const reducers$1 = {}; const defaultState$1 = { + failedPurchaseUris: [], purchasedUris: [], - failedPurchaseUris: [] + purchasedStreamingUrls: {} }; reducers$1[PURCHASE_URI_COMPLETED] = (state, action) => { - const { uri } = action.data; + const { uri, streamingUrl } = action.data; const newPurchasedUris = state.purchasedUris.slice(); const newFailedPurchaseUris = state.failedPurchasedUris.slice(); + const newPurchasedStreamingUrls = Object.assign({}, state.newPurchasedStreamingUrls); + if (!newPurchasedUris.includes(uri)) { newPurchasedUris.push(uri); } if (newFailedPurchaseUris.includes(uri)) { newFailedPurchaseUris.splice(newFailedPurchaseUris.indexOf(uri), 1); } + if (streamingUrl) { + newPurchasedStreamingUrls[uri] = streamingUrl; + } return _extends$4({}, state, { + failedPurchaseUris: newFailedPurchaseUris, purchasedUris: newPurchasedUris, - failedPurchaseUris: newFailedPurchaseUris + purchasedStreamingUrls: newPurchasedStreamingUrls }); }; @@ -3564,9 +3582,9 @@ function contentReducer(state = defaultState$6, action) { return state; } -const selectState$4 = state => state.content || {}; +const selectState$5 = state => state.content || {}; -const makeSelectContentPositionForUri = uri => reselect.createSelector(selectState$4, makeSelectClaimForUri(uri), (state, claim) => { +const makeSelectContentPositionForUri = uri => reselect.createSelector(selectState$5, makeSelectClaimForUri(uri), (state, claim) => { if (!claim) { return null; } @@ -3577,9 +3595,9 @@ const makeSelectContentPositionForUri = uri => reselect.createSelector(selectSta var _extends$a = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -const selectState$5 = state => state.notifications || {}; +const selectState$6 = state => state.notifications || {}; -const selectToast = reselect.createSelector(selectState$5, state => { +const selectToast = reselect.createSelector(selectState$6, state => { if (state.toasts.length) { const { id, params } = state.toasts[0]; return _extends$a({ @@ -3590,7 +3608,7 @@ const selectToast = reselect.createSelector(selectState$5, state => { return null; }); -const selectError = reselect.createSelector(selectState$5, state => { +const selectError = reselect.createSelector(selectState$6, state => { if (state.errors.length) { const { error } = state.errors[0]; return { @@ -3601,14 +3619,6 @@ const selectError = reselect.createSelector(selectState$5, state => { return null; }); -const selectState$6 = state => state.file || {}; - -const selectPurchasedUris = reselect.createSelector(selectState$6, state => state.purchasedUris); - -const selectFailedPurchaseUris = reselect.createSelector(selectState$6, state => state.failedPurchaseUris); - -const selectLastPurchasedUri = reselect.createSelector(selectState$6, state => state.purchasedUris.length > 0 ? state.purchasedUris[state.purchasedUris.length - 1] : null); - exports.ACTIONS = action_types; exports.Lbry = lbryProxy; exports.PAGES = pages; @@ -3696,6 +3706,7 @@ exports.makeSelectPendingByUri = makeSelectPendingByUri; exports.makeSelectQueryWithOptions = makeSelectQueryWithOptions; exports.makeSelectRecommendedContentForUri = makeSelectRecommendedContentForUri; exports.makeSelectSearchUris = makeSelectSearchUris; +exports.makeSelectStreamingUrlForUri = makeSelectStreamingUrlForUri; exports.makeSelectThumbnailForUri = makeSelectThumbnailForUri; exports.makeSelectTitleForUri = makeSelectTitleForUri; exports.makeSelectTotalItemsForChannel = makeSelectTotalItemsForChannel; @@ -3749,6 +3760,7 @@ exports.selectMyClaimsWithoutChannels = selectMyClaimsWithoutChannels; exports.selectPendingById = selectPendingById; exports.selectPendingClaims = selectPendingClaims; exports.selectPlayingUri = selectPlayingUri; +exports.selectPurchasedStreamingUrls = selectPurchasedStreamingUrls; exports.selectPurchasedUris = selectPurchasedUris; exports.selectReceiveAddress = selectReceiveAddress; exports.selectRecentTransactions = selectRecentTransactions; diff --git a/src/index.js b/src/index.js index 3e4c938..15fd6aa 100644 --- a/src/index.js +++ b/src/index.js @@ -108,9 +108,11 @@ export { makeSelectContentPositionForUri } from 'redux/selectors/content'; export { selectToast, selectError } from 'redux/selectors/notifications'; export { - selectPurchasedUris, selectFailedPurchaseUris, + selectPurchasedUris, + selectPurchasedStreamingUrls, selectLastPurchasedUri, + makeSelectStreamingUrlForUri, } from 'redux/selectors/file'; export { diff --git a/src/redux/actions/file.js b/src/redux/actions/file.js index 2a7ff00..8842f76 100644 --- a/src/redux/actions/file.js +++ b/src/redux/actions/file.js @@ -1,11 +1,9 @@ -import { - ACTIONS, - Lbry, - doToast, - selectBalance, - makeSelectFileInfoForUri, - selectDownloadingByOutpoint, -} from 'lbry-redux'; +import * as ACTIONS from 'constants/action_types'; +import Lbry from 'lbry'; +import { doToast } from 'redux/actions/notifications'; +import { selectBalance } from 'redux/selectors/wallet'; +import { makeSelectFileInfoForUri, selectDownloadingByOutpoint } from 'redux/selectors/file_info'; +import { makeSelectStreamingUrlForUri } from 'redux/selectors/file'; import { makeSelectCostInfoForUri } from 'lbryinc'; export function doLoadFile(uri, saveFile = true) { @@ -36,9 +34,10 @@ export function doLoadFile(uri, saveFile = true) { dispatch(doToast({ message: `File timeout for uri ${uri}` })); } else { // purchase was completed successfully + const { streaming_url: streamingUrl } = streamInfo; dispatch({ type: ACTIONS.PURCHASE_URI_COMPLETED, - data: { uri }, + data: { uri, streamingUrl: !saveFile && streamingUrl ? streamingUrl : null }, }); } }) @@ -71,15 +70,14 @@ export function doPurchaseUri(uri, specificCostInfo) { const state = getState(); const balance = selectBalance(state); const fileInfo = makeSelectFileInfoForUri(uri)(state); - - // TODO: What about already streaming? const downloadingByOutpoint = selectDownloadingByOutpoint(state); const alreadyDownloading = fileInfo && !!downloadingByOutpoint[fileInfo.outpoint]; + const alreadyStreaming = makeSelectStreamingUrlForUri(uri)(state); - if (alreadyDownloading) { + if (alreadyDownloading || alreadyStreaming) { dispatch({ type: ACTIONS.PURCHASE_URI_FAILED, - data: { uri, error: `Already downloading uri: ${uri}` }, + data: { uri, error: `Already downloading / streaming uri: ${uri}` }, }); Promise.resolve(); diff --git a/src/redux/reducers/file.js b/src/redux/reducers/file.js index 830ffc7..021edfd 100644 --- a/src/redux/reducers/file.js +++ b/src/redux/reducers/file.js @@ -3,25 +3,32 @@ import { buildURI, parseURI } from 'lbryURI'; const reducers = {}; const defaultState = { - purchasedUris: [], failedPurchaseUris: [], + purchasedUris: [], + purchasedStreamingUrls: {}, }; reducers[ACTIONS.PURCHASE_URI_COMPLETED] = (state, action) => { - const { uri } = action.data; + const { uri, streamingUrl } = action.data; const newPurchasedUris = state.purchasedUris.slice(); const newFailedPurchaseUris = state.failedPurchasedUris.slice(); + const newPurchasedStreamingUrls = Object.assign({}, state.newPurchasedStreamingUrls); + if (!newPurchasedUris.includes(uri)) { newPurchasedUris.push(uri); } if (newFailedPurchaseUris.includes(uri)) { newFailedPurchaseUris.splice(newFailedPurchaseUris.indexOf(uri), 1); } + if (streamingUrl) { + newPurchasedStreamingUrls[uri] = streamingUrl; + } return { ...state, - purchasedUris: newPurchasedUris, failedPurchaseUris: newFailedPurchaseUris, + purchasedUris: newPurchasedUris, + purchasedStreamingUrls: newPurchasedStreamingUrls, }; }; diff --git a/src/redux/selectors/file.js b/src/redux/selectors/file.js index 91bb7f5..75806dd 100644 --- a/src/redux/selectors/file.js +++ b/src/redux/selectors/file.js @@ -2,14 +2,19 @@ import { createSelector } from 'reselect'; export const selectState = state => state.file || {}; +export const selectFailedPurchaseUris = createSelector( + selectState, + state => state.failedPurchaseUris +); + export const selectPurchasedUris = createSelector( selectState, state => state.purchasedUris ); -export const selectFailedPurchaseUris = createSelector( +export const selectPurchasedStreamingUrls = createSelector( selectState, - state => state.failedPurchaseUris + state => state.purchasedStreamingUrls ); export const selectLastPurchasedUri = createSelector( @@ -17,3 +22,9 @@ export const selectLastPurchasedUri = createSelector( state => state.purchasedUris.length > 0 ? state.purchasedUris[state.purchasedUris.length - 1] : null ); + +export const makeSelectStreamingUrlForUri = uri => + createSelector( + selectPurchasedStreamingUrls, + streamingUrls => streamingUrls && streamingUrls[uri] + ); -- 2.45.2 From e16b25b9ce68a5bc9dc346c0a4332f67a891caf6 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Fri, 17 May 2019 09:21:12 +0100 Subject: [PATCH 4/7] add costInfo parameter to doPurchaseUri --- dist/bundle.es.js | 25 ++++++++++++++++--------- src/constants/action_types.js | 5 +++++ src/redux/actions/file.js | 9 ++++----- src/redux/reducers/file.js | 5 ++--- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 102c993..5ca15c1 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -7,7 +7,6 @@ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'defau require('proxy-polyfill'); var reselect = require('reselect'); var uuid = _interopDefault(require('uuid/v4')); -var lbryinc = require('lbryinc'); const WINDOW_FOCUSED = 'WINDOW_FOCUSED'; const DAEMON_READY = 'DAEMON_READY'; @@ -235,6 +234,11 @@ const DISMISS_ERROR = 'DISMISS_ERROR'; const FETCH_DATE = 'FETCH_DATE'; +// Cost info +const FETCH_COST_INFO_STARTED = 'FETCH_COST_INFO_STARTED'; +const FETCH_COST_INFO_COMPLETED = 'FETCH_COST_INFO_COMPLETED'; +const FETCH_COST_INFO_FAILED = 'FETCH_COST_INFO_FAILED'; + var action_types = /*#__PURE__*/Object.freeze({ WINDOW_FOCUSED: WINDOW_FOCUSED, DAEMON_READY: DAEMON_READY, @@ -431,7 +435,10 @@ var action_types = /*#__PURE__*/Object.freeze({ DISMISS_TOAST: DISMISS_TOAST, CREATE_ERROR: CREATE_ERROR, DISMISS_ERROR: DISMISS_ERROR, - FETCH_DATE: FETCH_DATE + FETCH_DATE: FETCH_DATE, + FETCH_COST_INFO_STARTED: FETCH_COST_INFO_STARTED, + FETCH_COST_INFO_COMPLETED: FETCH_COST_INFO_COMPLETED, + FETCH_COST_INFO_FAILED: FETCH_COST_INFO_FAILED }); const API_DOWN = 'apiDown'; @@ -2342,7 +2349,7 @@ function doLoadFile(uri, saveFile = true) { data: { uri } }); - dispatch(doToast({ message: `File timeout for uri ${uri}` })); + dispatch(doToast({ message: `File timeout for uri ${uri}`, isError: true })); } else { // purchase was completed successfully const { streaming_url: streamingUrl } = streamInfo; @@ -2362,13 +2369,14 @@ function doLoadFile(uri, saveFile = true) { }); dispatch(doToast({ - message: `Failed to download ${uri}, please try again. If this problem persists, visit https://lbry.com/faq/support for support.` + message: `Failed to download ${uri}, please try again. If this problem persists, visit https://lbry.com/faq/support for support.`, + isError: true })); }); }; } -function doPurchaseUri(uri, specificCostInfo) { +function doPurchaseUri(uri, costInfo, saveFile = true) { return (dispatch, getState) => { dispatch({ type: PURCHASE_URI_STARTED, @@ -2390,7 +2398,6 @@ function doPurchaseUri(uri, specificCostInfo) { return; } - const costInfo = lbryinc.makeSelectCostInfoForUri(uri)(state) || specificCostInfo; const { cost } = costInfo; if (cost > balance) { @@ -2401,7 +2408,7 @@ function doPurchaseUri(uri, specificCostInfo) { return; } - dispatch(doLoadFile(uri)); + dispatch(doLoadFile(uri, saveFile)); }; } @@ -2908,7 +2915,7 @@ const defaultState$1 = { reducers$1[PURCHASE_URI_COMPLETED] = (state, action) => { const { uri, streamingUrl } = action.data; const newPurchasedUris = state.purchasedUris.slice(); - const newFailedPurchaseUris = state.failedPurchasedUris.slice(); + const newFailedPurchaseUris = state.failedPurchaseUris.slice(); const newPurchasedStreamingUrls = Object.assign({}, state.newPurchasedStreamingUrls); if (!newPurchasedUris.includes(uri)) { @@ -2930,7 +2937,7 @@ reducers$1[PURCHASE_URI_COMPLETED] = (state, action) => { reducers$1[PURCHASE_URI_FAILED] = (state, action) => { const { uri } = action.data; - const newFailedPurchaseUris = state.failedPurchasedUris.slice(); + const newFailedPurchaseUris = state.failedPurchaseUris.slice(); if (!newFailedPurchaseUris.includes(uri)) { newFailedPurchaseUris.push(uri); } diff --git a/src/constants/action_types.js b/src/constants/action_types.js index 795eea4..9582f77 100644 --- a/src/constants/action_types.js +++ b/src/constants/action_types.js @@ -223,3 +223,8 @@ export const CREATE_ERROR = 'CREATE_ERROR'; export const DISMISS_ERROR = 'DISMISS_ERROR'; export const FETCH_DATE = 'FETCH_DATE'; + +// Cost info +export const FETCH_COST_INFO_STARTED = 'FETCH_COST_INFO_STARTED'; +export const FETCH_COST_INFO_COMPLETED = 'FETCH_COST_INFO_COMPLETED'; +export const FETCH_COST_INFO_FAILED = 'FETCH_COST_INFO_FAILED'; diff --git a/src/redux/actions/file.js b/src/redux/actions/file.js index 8842f76..5bbedf2 100644 --- a/src/redux/actions/file.js +++ b/src/redux/actions/file.js @@ -4,7 +4,6 @@ import { doToast } from 'redux/actions/notifications'; import { selectBalance } from 'redux/selectors/wallet'; import { makeSelectFileInfoForUri, selectDownloadingByOutpoint } from 'redux/selectors/file_info'; import { makeSelectStreamingUrlForUri } from 'redux/selectors/file'; -import { makeSelectCostInfoForUri } from 'lbryinc'; export function doLoadFile(uri, saveFile = true) { return dispatch => { @@ -31,7 +30,7 @@ export function doLoadFile(uri, saveFile = true) { data: { uri }, }); - dispatch(doToast({ message: `File timeout for uri ${uri}` })); + dispatch(doToast({ message: `File timeout for uri ${uri}`, isError: true })); } else { // purchase was completed successfully const { streaming_url: streamingUrl } = streamInfo; @@ -54,13 +53,14 @@ export function doLoadFile(uri, saveFile = true) { dispatch( doToast({ message: `Failed to download ${uri}, please try again. If this problem persists, visit https://lbry.com/faq/support for support.`, + isError: true, }) ); }); }; } -export function doPurchaseUri(uri, specificCostInfo) { +export function doPurchaseUri(uri, costInfo, saveFile = true) { return (dispatch, getState) => { dispatch({ type: ACTIONS.PURCHASE_URI_STARTED, @@ -84,7 +84,6 @@ export function doPurchaseUri(uri, specificCostInfo) { return; } - const costInfo = makeSelectCostInfoForUri(uri)(state) || specificCostInfo; const { cost } = costInfo; if (cost > balance) { @@ -97,6 +96,6 @@ export function doPurchaseUri(uri, specificCostInfo) { return; } - dispatch(doLoadFile(uri)); + dispatch(doLoadFile(uri, saveFile)); }; } diff --git a/src/redux/reducers/file.js b/src/redux/reducers/file.js index 021edfd..465715e 100644 --- a/src/redux/reducers/file.js +++ b/src/redux/reducers/file.js @@ -1,5 +1,4 @@ import * as ACTIONS from 'constants/action_types'; -import { buildURI, parseURI } from 'lbryURI'; const reducers = {}; const defaultState = { @@ -11,7 +10,7 @@ const defaultState = { reducers[ACTIONS.PURCHASE_URI_COMPLETED] = (state, action) => { const { uri, streamingUrl } = action.data; const newPurchasedUris = state.purchasedUris.slice(); - const newFailedPurchaseUris = state.failedPurchasedUris.slice(); + const newFailedPurchaseUris = state.failedPurchaseUris.slice(); const newPurchasedStreamingUrls = Object.assign({}, state.newPurchasedStreamingUrls); if (!newPurchasedUris.includes(uri)) { @@ -34,7 +33,7 @@ reducers[ACTIONS.PURCHASE_URI_COMPLETED] = (state, action) => { reducers[ACTIONS.PURCHASE_URI_FAILED] = (state, action) => { const { uri } = action.data; - const newFailedPurchaseUris = state.failedPurchasedUris.slice(); + const newFailedPurchaseUris = state.failedPurchaseUris.slice(); if (!newFailedPurchaseUris.includes(uri)) { newFailedPurchaseUris.push(uri); } -- 2.45.2 From 424d18da6585af77d2c27304b7f2242adb830317 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Tue, 21 May 2019 20:00:16 +0100 Subject: [PATCH 5/7] added flow types --- dist/bundle.es.js | 2 ++ dist/flow-typed/File.js | 21 +++++++++++++++++++++ flow-typed/File.js | 22 ++++++++++++++++++++++ src/redux/actions/file.js | 17 ++++++++++------- src/redux/reducers/file.js | 12 ++++++++---- src/redux/selectors/file.js | 15 +++++++++------ 6 files changed, 72 insertions(+), 17 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 5ca15c1..bc05f00 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -2326,6 +2326,8 @@ const selectLastPurchasedUri = reselect.createSelector(selectState$4, state => s const makeSelectStreamingUrlForUri = uri => reselect.createSelector(selectPurchasedStreamingUrls, streamingUrls => streamingUrls && streamingUrls[uri]); +// + function doLoadFile(uri, saveFile = true) { return dispatch => { dispatch({ diff --git a/dist/flow-typed/File.js b/dist/flow-typed/File.js index a4f8a60..f128342 100644 --- a/dist/flow-typed/File.js +++ b/dist/flow-typed/File.js @@ -33,3 +33,24 @@ declare type FileListItem = { txid: string, written_bytes: number, }; + +declare type FileState = { + failedPurchaseUris: Array, + purchasedUris: Array, + purchasedStreamingUrls: {}, +}; + +declare type PurchaseUriCompleted = { + type: ACTIONS.PURCHASE_URI_COMPLETED, + data: { + uri: string, + streamingUrl: string, + }, +}; + +declare type PurchaseUriFailed = { + type: ACTIONS.PURCHASE_URI_FAILED, + data: { + uri: string + }, +}; diff --git a/flow-typed/File.js b/flow-typed/File.js index a4f8a60..4384d3f 100644 --- a/flow-typed/File.js +++ b/flow-typed/File.js @@ -24,6 +24,7 @@ declare type FileListItem = { stopped: false, stream_hash: string, stream_name: string, + streaming_url: string, suggested_file_name: string, total_bytes: number, total_bytes_lower_bound: number, @@ -33,3 +34,24 @@ declare type FileListItem = { txid: string, written_bytes: number, }; + +declare type FileState = { + failedPurchaseUris: Array, + purchasedUris: Array, + purchasedStreamingUrls: {}, +}; + +declare type PurchaseUriCompleted = { + type: ACTIONS.PURCHASE_URI_COMPLETED, + data: { + uri: string, + streamingUrl: string, + }, +}; + +declare type PurchaseUriFailed = { + type: ACTIONS.PURCHASE_URI_FAILED, + data: { + uri: string + }, +}; diff --git a/src/redux/actions/file.js b/src/redux/actions/file.js index 5bbedf2..9fb3093 100644 --- a/src/redux/actions/file.js +++ b/src/redux/actions/file.js @@ -1,3 +1,4 @@ +// @flow import * as ACTIONS from 'constants/action_types'; import Lbry from 'lbry'; import { doToast } from 'redux/actions/notifications'; @@ -5,8 +6,11 @@ import { selectBalance } from 'redux/selectors/wallet'; import { makeSelectFileInfoForUri, selectDownloadingByOutpoint } from 'redux/selectors/file_info'; import { makeSelectStreamingUrlForUri } from 'redux/selectors/file'; -export function doLoadFile(uri, saveFile = true) { - return dispatch => { +type Dispatch = (action: any) => any; +type GetState = () => { file: FileState }; + +export function doLoadFile(uri: string, saveFile: boolean = true) { + return (dispatch: Dispatch) => { dispatch({ type: ACTIONS.LOADING_FILE_STARTED, data: { @@ -16,9 +20,8 @@ export function doLoadFile(uri, saveFile = true) { // set save_file argument to True to save the file (old behaviour) Lbry.get({ uri, save_file: saveFile }) - .then(streamInfo => { - const timeout = - streamInfo === null || typeof streamInfo !== 'object' || streamInfo.error === 'Timeout'; + .then((streamInfo: GetResponse) => { + const timeout = streamInfo === null || typeof streamInfo !== 'object'; if (timeout) { dispatch({ @@ -60,8 +63,8 @@ export function doLoadFile(uri, saveFile = true) { }; } -export function doPurchaseUri(uri, costInfo, saveFile = true) { - return (dispatch, getState) => { +export function doPurchaseUri(uri: string, costInfo: { cost: number }, saveFile: boolean = true) { + return (dispatch: Dispatch, getState: GetState) => { dispatch({ type: ACTIONS.PURCHASE_URI_STARTED, data: { uri }, diff --git a/src/redux/reducers/file.js b/src/redux/reducers/file.js index 465715e..4e2bad1 100644 --- a/src/redux/reducers/file.js +++ b/src/redux/reducers/file.js @@ -1,3 +1,4 @@ +// @flow import * as ACTIONS from 'constants/action_types'; const reducers = {}; @@ -7,11 +8,14 @@ const defaultState = { purchasedStreamingUrls: {}, }; -reducers[ACTIONS.PURCHASE_URI_COMPLETED] = (state, action) => { +reducers[ACTIONS.PURCHASE_URI_COMPLETED] = ( + state: FileState, + action: PurchaseUriCompleted +): FileState => { const { uri, streamingUrl } = action.data; const newPurchasedUris = state.purchasedUris.slice(); const newFailedPurchaseUris = state.failedPurchaseUris.slice(); - const newPurchasedStreamingUrls = Object.assign({}, state.newPurchasedStreamingUrls); + const newPurchasedStreamingUrls = Object.assign({}, state.purchasedStreamingUrls); if (!newPurchasedUris.includes(uri)) { newPurchasedUris.push(uri); @@ -31,7 +35,7 @@ reducers[ACTIONS.PURCHASE_URI_COMPLETED] = (state, action) => { }; }; -reducers[ACTIONS.PURCHASE_URI_FAILED] = (state, action) => { +reducers[ACTIONS.PURCHASE_URI_FAILED] = (state: FileState, action: PurchaseUriFailed) => { const { uri } = action.data; const newFailedPurchaseUris = state.failedPurchaseUris.slice(); if (!newFailedPurchaseUris.includes(uri)) { @@ -44,7 +48,7 @@ reducers[ACTIONS.PURCHASE_URI_FAILED] = (state, action) => { }; }; -export function fileReducer(state = defaultState, action) { +export function fileReducer(state: FileState = defaultState, action: any) { const handler = reducers[action.type]; if (handler) return handler(state, action); return state; diff --git a/src/redux/selectors/file.js b/src/redux/selectors/file.js index 75806dd..11caee5 100644 --- a/src/redux/selectors/file.js +++ b/src/redux/selectors/file.js @@ -1,29 +1,32 @@ +// @flow import { createSelector } from 'reselect'; -export const selectState = state => state.file || {}; +type State = { file: FileState }; -export const selectFailedPurchaseUris = createSelector( +export const selectState = (state: State): FileState => state.file || {}; + +export const selectFailedPurchaseUris: (state: State) => Array = createSelector( selectState, state => state.failedPurchaseUris ); -export const selectPurchasedUris = createSelector( +export const selectPurchasedUris: (state: State) => Array = createSelector( selectState, state => state.purchasedUris ); -export const selectPurchasedStreamingUrls = createSelector( +export const selectPurchasedStreamingUrls: (state: State) => {} = createSelector( selectState, state => state.purchasedStreamingUrls ); -export const selectLastPurchasedUri = createSelector( +export const selectLastPurchasedUri: (state: State) => string = createSelector( selectState, state => state.purchasedUris.length > 0 ? state.purchasedUris[state.purchasedUris.length - 1] : null ); -export const makeSelectStreamingUrlForUri = uri => +export const makeSelectStreamingUrlForUri = (uri: string): ((state: State) => {}) => createSelector( selectPurchasedStreamingUrls, streamingUrls => streamingUrls && streamingUrls[uri] -- 2.45.2 From 7fad5fe4c2312337847bf2c9768a784efd3cc612 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Tue, 21 May 2019 20:03:23 +0100 Subject: [PATCH 6/7] rename doLoadFile --> doFileGet. --- src/index.js | 2 +- src/redux/actions/file.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 15fd6aa..9265f41 100644 --- a/src/index.js +++ b/src/index.js @@ -47,7 +47,7 @@ export { doCreateChannel, } from 'redux/actions/claims'; -export { doPurchaseUri, doLoadFile } from 'redux/actions/file'; +export { doPurchaseUri, doFileGet } from 'redux/actions/file'; export { doFetchFileInfo, diff --git a/src/redux/actions/file.js b/src/redux/actions/file.js index 9fb3093..6d7bb37 100644 --- a/src/redux/actions/file.js +++ b/src/redux/actions/file.js @@ -9,7 +9,7 @@ import { makeSelectStreamingUrlForUri } from 'redux/selectors/file'; type Dispatch = (action: any) => any; type GetState = () => { file: FileState }; -export function doLoadFile(uri: string, saveFile: boolean = true) { +export function doFileGet(uri: string, saveFile: boolean = true) { return (dispatch: Dispatch) => { dispatch({ type: ACTIONS.LOADING_FILE_STARTED, @@ -80,7 +80,7 @@ export function doPurchaseUri(uri: string, costInfo: { cost: number }, saveFile: if (alreadyDownloading || alreadyStreaming) { dispatch({ type: ACTIONS.PURCHASE_URI_FAILED, - data: { uri, error: `Already downloading / streaming uri: ${uri}` }, + data: { uri, error: `Already fetching uri: ${uri}` }, }); Promise.resolve(); @@ -99,6 +99,6 @@ export function doPurchaseUri(uri: string, costInfo: { cost: number }, saveFile: return; } - dispatch(doLoadFile(uri, saveFile)); + dispatch(doFileGet(uri, saveFile)); }; } -- 2.45.2 From 64da66f29d04f937c0a1cc80b8149561ee98768c Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Tue, 21 May 2019 20:17:17 +0100 Subject: [PATCH 7/7] add missing flow annotation --- dist/bundle.es.js | 14 ++++++++------ dist/flow-typed/File.js | 1 + src/redux/reducers/file.js | 5 ++++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index bc05f00..56ff3b9 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -2314,6 +2314,8 @@ const selectFileListPublishedSort = reselect.createSelector(selectState$3, state const selectFileListDownloadedSort = reselect.createSelector(selectState$3, state => state.fileListDownloadedSort); +// + const selectState$4 = state => state.file || {}; const selectFailedPurchaseUris = reselect.createSelector(selectState$4, state => state.failedPurchaseUris); @@ -2328,7 +2330,7 @@ const makeSelectStreamingUrlForUri = uri => reselect.createSelector(selectPurcha // -function doLoadFile(uri, saveFile = true) { +function doFileGet(uri, saveFile = true) { return dispatch => { dispatch({ type: LOADING_FILE_STARTED, @@ -2339,7 +2341,7 @@ function doLoadFile(uri, saveFile = true) { // set save_file argument to True to save the file (old behaviour) lbryProxy.get({ uri, save_file: saveFile }).then(streamInfo => { - const timeout = streamInfo === null || typeof streamInfo !== 'object' || streamInfo.error === 'Timeout'; + const timeout = streamInfo === null || typeof streamInfo !== 'object'; if (timeout) { dispatch({ @@ -2395,7 +2397,7 @@ function doPurchaseUri(uri, costInfo, saveFile = true) { if (alreadyDownloading || alreadyStreaming) { dispatch({ type: PURCHASE_URI_FAILED, - data: { uri, error: `Already downloading / streaming uri: ${uri}` } + data: { uri, error: `Already fetching uri: ${uri}` } }); return; } @@ -2410,7 +2412,7 @@ function doPurchaseUri(uri, costInfo, saveFile = true) { return; } - dispatch(doLoadFile(uri, saveFile)); + dispatch(doFileGet(uri, saveFile)); }; } @@ -2918,7 +2920,7 @@ reducers$1[PURCHASE_URI_COMPLETED] = (state, action) => { const { uri, streamingUrl } = action.data; const newPurchasedUris = state.purchasedUris.slice(); const newFailedPurchaseUris = state.failedPurchaseUris.slice(); - const newPurchasedStreamingUrls = Object.assign({}, state.newPurchasedStreamingUrls); + const newPurchasedStreamingUrls = Object.assign({}, state.purchasedStreamingUrls); if (!newPurchasedUris.includes(uri)) { newPurchasedUris.push(uri); @@ -3657,10 +3659,10 @@ exports.doFetchClaimsByChannel = doFetchClaimsByChannel; exports.doFetchFileInfo = doFetchFileInfo; exports.doFetchFileInfosAndPublishedClaims = doFetchFileInfosAndPublishedClaims; exports.doFetchTransactions = doFetchTransactions; +exports.doFileGet = doFileGet; exports.doFileList = doFileList; exports.doFocusSearchInput = doFocusSearchInput; exports.doGetNewAddress = doGetNewAddress; -exports.doLoadFile = doLoadFile; exports.doPurchaseUri = doPurchaseUri; exports.doResolveUri = doResolveUri; exports.doResolveUris = doResolveUris; diff --git a/dist/flow-typed/File.js b/dist/flow-typed/File.js index f128342..4384d3f 100644 --- a/dist/flow-typed/File.js +++ b/dist/flow-typed/File.js @@ -24,6 +24,7 @@ declare type FileListItem = { stopped: false, stream_hash: string, stream_name: string, + streaming_url: string, suggested_file_name: string, total_bytes: number, total_bytes_lower_bound: number, diff --git a/src/redux/reducers/file.js b/src/redux/reducers/file.js index 4e2bad1..2e593fa 100644 --- a/src/redux/reducers/file.js +++ b/src/redux/reducers/file.js @@ -35,7 +35,10 @@ reducers[ACTIONS.PURCHASE_URI_COMPLETED] = ( }; }; -reducers[ACTIONS.PURCHASE_URI_FAILED] = (state: FileState, action: PurchaseUriFailed) => { +reducers[ACTIONS.PURCHASE_URI_FAILED] = ( + state: FileState, + action: PurchaseUriFailed +): FileState => { const { uri } = action.data; const newFailedPurchaseUris = state.failedPurchaseUris.slice(); if (!newFailedPurchaseUris.includes(uri)) { -- 2.45.2