lbry-desktop/src/renderer/redux/actions/subscriptions.js

273 lines
8 KiB
JavaScript
Raw Normal View History

2017-12-08 21:14:35 +01:00
// @flow
import * as ACTIONS from 'constants/action_types';
import * as NOTIFICATION_TYPES from 'constants/notification_types';
import rewards from 'rewards';
import type {
Dispatch,
SubscriptionState,
SubscriptionNotifications,
} from 'redux/reducers/subscriptions';
import type { Subscription } from 'types/subscription';
import { selectSubscriptions } from 'redux/selectors/subscriptions';
import { Lbry, buildURI, parseURI } from 'lbry-redux';
import { doPurchaseUri } from 'redux/actions/content';
import { doClaimRewardType } from 'redux/actions/rewards';
import Promise from 'bluebird';
import Lbryio from 'lbryio';
const CHECK_SUBSCRIPTIONS_INTERVAL = 15 * 60 * 1000;
const SUBSCRIPTION_DOWNLOAD_LIMIT = 1;
2017-12-08 21:14:35 +01:00
export const doFetchMySubscriptions = () => (dispatch: Dispatch, getState: () => any) => {
const {
subscriptions: subscriptionState,
settings: { daemonSettings },
} = getState();
const { subscriptions: reduxSubscriptions } = subscriptionState;
const { share_usage_data: isSharingData } = daemonSettings;
2017-12-08 21:14:35 +01:00
if (!isSharingData && isSharingData !== undefined) {
// They aren't sharing their data, subscriptions will be handled by persisted redux state
return;
}
// most of this logic comes from scenarios where the db isn't synced with redux
// this will happen if the user stops sharing data
dispatch({ type: ACTIONS.FETCH_SUBSCRIPTIONS_START });
Lbryio.call('subscription', 'list')
.then(dbSubscriptions => {
const storedSubscriptions = dbSubscriptions || [];
// User has no subscriptions in db or redux
if (!storedSubscriptions.length && (!reduxSubscriptions || !reduxSubscriptions.length)) {
return [];
}
// There is some mismatch between redux state and db state
// If something is in the db, but not in redux, add it to redux
// If something is in redux, but not in the db, add it to the db
if (storedSubscriptions.length !== reduxSubscriptions.length) {
const dbSubMap = {};
const reduxSubMap = {};
const subsNotInDB = [];
const subscriptionsToReturn = reduxSubscriptions.slice();
storedSubscriptions.forEach(sub => {
dbSubMap[sub.claim_id] = 1;
});
reduxSubscriptions.forEach(sub => {
const { claimId } = parseURI(sub.uri);
reduxSubMap[claimId] = 1;
if (!dbSubMap[claimId]) {
subsNotInDB.push({
claim_id: claimId,
channel_name: sub.channelName,
});
}
});
storedSubscriptions.forEach(sub => {
if (!reduxSubMap[sub.claim_id]) {
const uri = `lbry://${sub.channel_name}#${sub.claim_id}`;
subscriptionsToReturn.push({ uri, channelName: sub.channel_name });
}
});
return Promise.all(subsNotInDB.map(payload => Lbryio.call('subscription', 'new', payload)))
.then(() => subscriptionsToReturn)
.catch(
() =>
// let it fail, we will try again when the navigate to the subscriptions page
subscriptionsToReturn
);
}
// DB is already synced, just return the subscriptions in redux
return reduxSubscriptions;
})
.then(subscriptions => {
dispatch({
type: ACTIONS.FETCH_SUBSCRIPTIONS_SUCCESS,
data: subscriptions,
});
})
.catch(() => {
dispatch({
type: ACTIONS.FETCH_SUBSCRIPTIONS_FAIL,
});
});
2018-03-16 19:26:44 +01:00
};
export const setSubscriptionLatest = (subscription: Subscription, uri: string) => (
dispatch: Dispatch
) =>
2017-12-13 22:36:30 +01:00
dispatch({
type: ACTIONS.SET_SUBSCRIPTION_LATEST,
data: {
subscription,
uri,
},
2017-12-08 21:14:35 +01:00
});
export const setSubscriptionNotification = (
subscription: Subscription,
uri: string,
notificationType: string
) => (dispatch: Dispatch) =>
dispatch({
type: ACTIONS.SET_SUBSCRIPTION_NOTIFICATION,
data: {
subscription,
uri,
type: notificationType,
},
});
2018-03-15 09:35:47 +01:00
export const doCheckSubscription = (subscription: Subscription, notify?: boolean) => (
dispatch: Dispatch
) => {
// this action is not implemented
dispatch({
type: ACTIONS.CHECK_SUBSCRIPTION_STARTED,
data: subscription,
});
Lbry.claim_list_by_channel({ uri: subscription.uri, page: 1 }).then(result => {
const claimResult = result[subscription.uri] || {};
const { claims_in_channel: claimsInChannel } = claimResult;
const autodownload = true; // temp
const latestIndex = claimsInChannel.findIndex(
claim => `${claim.name}#${claim.claim_id}` === subscription.latest
);
if (claimsInChannel.length && latestIndex !== 0) {
claimsInChannel.slice(0, latestIndex === -1 ? 10 : latestIndex).forEach((claim, index) => {
const uri = buildURI({ contentName: claim.name, claimId: claim.claim_id }, false);
const shouldDownload = Boolean(
index < SUBSCRIPTION_DOWNLOAD_LIMIT && !claim.value.stream.metadata.fee
);
if (notify) {
dispatch(
setSubscriptionNotification(
subscription,
uri,
shouldDownload ? NOTIFICATION_TYPES.DOWNLOADING : NOTIFICATION_TYPES.NOTIFY_ONLY
)
);
}
if (autodownload && shouldDownload) {
dispatch(doPurchaseUri(uri, { cost: 0 }));
}
});
dispatch(
setSubscriptionLatest(
{
channelName: claimsInChannel[0].channel_name,
2018-03-07 20:19:45 +01:00
uri: buildURI(
{
channelName: claimsInChannel[0].channel_name,
claimId: claimsInChannel[0].claim_id,
},
false
2018-03-07 20:19:45 +01:00
),
},
buildURI(
{ contentName: claimsInChannel[0].name, claimId: claimsInChannel[0].claim_id },
2018-03-15 09:35:47 +01:00
false
)
2018-03-15 09:35:47 +01:00
)
);
}
});
// this action is not implemented
dispatch({
type: ACTIONS.CHECK_SUBSCRIPTION_COMPLETED,
data: subscription,
});
2018-03-06 09:36:04 +01:00
};
export const setSubscriptionNotifications = (notifications: SubscriptionNotifications) => (
2018-03-06 09:36:04 +01:00
dispatch: Dispatch
) =>
dispatch({
type: ACTIONS.SET_SUBSCRIPTION_NOTIFICATIONS,
data: {
notifications,
2018-03-06 09:36:04 +01:00
},
});
export const doChannelSubscribe = (subscription: Subscription) => (
dispatch: Dispatch,
getState: () => any
) => {
const {
settings: { daemonSettings },
} = getState();
const { share_usage_data: isSharingData } = daemonSettings;
dispatch({
type: ACTIONS.CHANNEL_SUBSCRIBE,
data: subscription,
});
// if the user isn't sharing data, keep the subscriptions entirely in the app
if (isSharingData) {
const { claimId } = parseURI(subscription.uri);
// They are sharing data, we can store their subscriptions in our internal database
Lbryio.call('subscription', 'new', {
channel_name: subscription.channelName,
claim_id: claimId,
});
dispatch(doClaimRewardType(rewards.SUBSCRIPTION, { failSilently: true }));
}
dispatch(doCheckSubscription(subscription, true));
};
export const doChannelUnsubscribe = (subscription: Subscription) => (
dispatch: Dispatch,
getState: () => any
) => {
const {
settings: { daemonSettings },
} = getState();
const { share_usage_data: isSharingData } = daemonSettings;
dispatch({
type: ACTIONS.CHANNEL_UNSUBSCRIBE,
data: subscription,
});
if (isSharingData) {
const { claimId } = parseURI(subscription.uri);
Lbryio.call('subscription', 'delete', {
claim_id: claimId,
});
}
};
export const doCheckSubscriptions = () => (
dispatch: Dispatch,
getState: () => SubscriptionState
) => {
function doCheck() {
const subscriptions = selectSubscriptions(getState());
subscriptions.forEach((sub: Subscription) => {
dispatch(doCheckSubscription(sub, true));
});
}
setTimeout(doCheck, 2000); // bad fix for not getting subs on load
const checkSubscriptionsTimer = setInterval(doCheck, 1000 * 20); // temporary; 20 seconds for testing
dispatch({
type: ACTIONS.CHECK_SUBSCRIPTIONS_SUBSCRIBE,
data: { checkSubscriptionsTimer },
});
};