Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

Commit

Permalink
[C-1184] Fetch lineups after coming back online (#2083)
Browse files Browse the repository at this point in the history
  • Loading branch information
amendelsohn authored Oct 7, 2022
1 parent b416893 commit 92ab4a0
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 62 deletions.
2 changes: 1 addition & 1 deletion packages/common/src/store/reachability/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ReachabilityState } from './types'
type ReachabilityActions = ActionType<typeof actions>

const initialState = {
networkReachable: true
networkReachable: false
}

const reducer = createReducer<ReachabilityState, ReachabilityActions>(
Expand Down
43 changes: 43 additions & 0 deletions packages/mobile/src/hooks/useReachability.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useEffect, useState } from 'react'

import { reachabilitySelectors } from '@audius/common'
import { useSelector } from 'react-redux'
const { getIsReachable } = reachabilitySelectors

type OnBecomeReachable = () => any
type OnBecomeUnreachable = () => any

export const useReachability = (
onBecomeReachable: OnBecomeReachable | null,
onBecomeUnreachable: OnBecomeUnreachable | null
) => {
const isInternetReachable = useSelector(getIsReachable)
const [lastReachabilityState, setLastReachabilityState] =
useState(isInternetReachable)

useEffect(() => {
if (isInternetReachable !== lastReachabilityState) {
isInternetReachable ? onBecomeReachable?.() : onBecomeUnreachable?.()
setLastReachabilityState(isInternetReachable)
}
}, [
isInternetReachable,
lastReachabilityState,
onBecomeReachable,
onBecomeUnreachable
])

return isInternetReachable
}

export const useBecomeReachable = (onBecomeReachable: OnBecomeReachable) => {
return useReachability(onBecomeReachable, null)
}

export const useBecomeUnreachable = (
onBecomeUnreachable: OnBecomeUnreachable
) => {
return useReachability(null, onBecomeUnreachable)
}

export default useReachability
20 changes: 14 additions & 6 deletions packages/mobile/src/screens/root-screen/RootScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { useEffect, useState } from 'react'
import { useCallback, useEffect, useState } from 'react'

import { accountSelectors, Status } from '@audius/common'
import type { NavigatorScreenParams } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { setupBackend } from 'audius-client/src/common/store/backend/actions'
import { getIsSetup } from 'audius-client/src/common/store/backend/selectors'
import { useDispatch, useSelector } from 'react-redux'

import useAppState from 'app/hooks/useAppState'
import { useBecomeReachable } from 'app/hooks/useReachability'
import { useUpdateRequired } from 'app/hooks/useUpdateRequired'
import type { AppScreenParamList } from 'app/screens/app-screen'
import { SignOnScreen } from 'app/screens/signon'
Expand Down Expand Up @@ -41,13 +43,15 @@ export const RootScreen = ({ isReadyToSetupBackend }: RootScreenProps) => {
const accountStatus = useSelector(getAccountStatus)
const [isInitting, setIsInittng] = useState(true)
const { updateRequired } = useUpdateRequired()
const isBackendSetup = useSelector(getIsSetup)

const handleSetupBackend = useCallback(() => {
if (isReadyToSetupBackend && !isBackendSetup) dispatch(setupBackend())
}, [dispatch, isBackendSetup, isReadyToSetupBackend])

useEffect(() => {
// Setup the backend when ready
if (isReadyToSetupBackend) {
dispatch(setupBackend())
}
}, [dispatch, isReadyToSetupBackend])
handleSetupBackend()
}, [dispatch, handleSetupBackend, isBackendSetup, isReadyToSetupBackend])

useAppState(
() => dispatch(enterForeground()),
Expand All @@ -60,6 +64,10 @@ export const RootScreen = ({ isReadyToSetupBackend }: RootScreenProps) => {
}
}, [accountStatus])

useBecomeReachable(() => {
handleSetupBackend()
})

return (
<>
<SplashScreen />
Expand Down
42 changes: 9 additions & 33 deletions packages/web/src/common/store/backend/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,14 @@ import {
reachabilitySelectors,
getContext
} from '@audius/common'
import {
put,
all,
delay,
take,
takeEvery,
select,
call,
race
} from 'typed-redux-saga'
import { put, all, take, takeEvery, select, call } from 'typed-redux-saga'

import { getReachability } from '../reachability/sagas'

import * as backendActions from './actions'
import { watchBackendErrors } from './errorSagas'
const { getIsReachable } = reachabilitySelectors

const REACHABILITY_TIMEOUT_MS = 8 * 1000

/**
* Waits for the backend to be setup. Can be used as a blocking call in another saga,
* For example:
Expand All @@ -44,28 +35,7 @@ export function* waitForBackendSetup() {
}
}

function* awaitReachability() {
const isNativeMobile = yield* getContext('isNativeMobile')
const isReachable = yield* select(getIsReachable)
if (isReachable || !isNativeMobile) return true
const { action } = yield* race({
action: take(reachabilityActions.SET_REACHABLE),
delay: delay(REACHABILITY_TIMEOUT_MS)
})
return !!action
}

export function* setupBackend() {
const establishedReachability = yield* call(awaitReachability)
// If we couldn't connect, show the error page
// and just sit here waiting for reachability.
if (!establishedReachability) {
console.error('No internet connectivity')
yield* put(accountActions.fetchAccountNoInternet())
yield* take(reachabilityActions.SET_REACHABLE)
console.info('Reconnected')
}

const apiClient = yield* getContext('apiClient')
const fingerprintClient = yield* getContext('fingerprintClient')
const audiusBackendInstance = yield* getContext('audiusBackendInstance')
Expand All @@ -74,7 +44,13 @@ export function* setupBackend() {
apiClient.init()
// Fire-and-forget init fp
fingerprintClient.init()
const isReachable = yield* call(getReachability)
yield* put(accountActions.fetchAccount())

if (!isReachable) {
yield* put(accountActions.fetchAccountNoInternet())
}

const { web3Error, libsError } = yield* call(audiusBackendInstance.setup)
if (libsError) {
yield* put(accountActions.fetchAccountFailed({ reason: 'LIBS_ERROR' }))
Expand Down
2 changes: 2 additions & 0 deletions packages/web/src/common/store/backend/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
import { AppState } from 'store/types'

export const getWeb3Error = (state: AppState) => state.backend.web3Error

export const getIsSetup = (state: AppState) => state.backend.isSetup
11 changes: 9 additions & 2 deletions packages/web/src/common/store/lineup/sagas.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import {
import { getToQueue } from 'common/store/queue/sagas'
import { isMobileWeb } from 'common/utils/isMobileWeb'

import { awaitReachability } from '../reachability/sagas'

const { getSource, getUid, getPositions } = queueSelectors
const { getUid: getCurrentPlayerTrackUid } = playerSelectors
const { getUsers } = cacheUsersSelectors
Expand Down Expand Up @@ -117,6 +119,8 @@ function* fetchLineupMetadatasAsync(
action
) {
const initLineup = yield select(lineupSelector)
yield call(awaitReachability)

const initSource = sourceSelector
? yield select((state) =>
sourceSelector(state, action.handle?.toLowerCase())
Expand All @@ -137,14 +141,17 @@ function* fetchLineupMetadatasAsync(

// Let page animations on mobile have time to breathe
// TODO: Get rid of this once we figure out how to make loading better
const isNativeMobile = yield getContext('isNativeMobile')
const isNativeMobile = yield* getContext('isNativeMobile')
if (!isNativeMobile && isMobileWeb()) {
yield delay(100)
}

const lineupMetadatasResponse = yield call(lineupMetadatasCall, action)

if (lineupMetadatasResponse === null) return
if (lineupMetadatasResponse === null) {
yield put(lineupActions.fetchLineupMetadatasFailed())
return
}
const lineup = yield select((state) =>
lineupSelector(state, action.handle?.toLowerCase())
)
Expand Down
40 changes: 20 additions & 20 deletions packages/web/src/common/store/pages/profile/lineups/feed/sagas.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
waitForAccount,
makeUid
} from '@audius/common'
import { select, call, takeEvery, put } from 'redux-saga/effects'
import { select, call, takeEvery, put } from 'typed-redux-saga'

import { getConfirmCalls } from 'common/store/confirmer/selectors'
import { LineupSagas } from 'common/store/lineup/sagas'
Expand All @@ -24,11 +24,11 @@ const { getCollections } = cacheCollectionsSelectors
const { getUserId, getUserHandle } = accountSelectors

function* getReposts({ offset, limit, handle }) {
const profileId = yield select((state) => getProfileUserId(state, handle))
const profileId = yield* select((state) => getProfileUserId(state, handle))

yield waitForAccount()
const currentUserId = yield select(getUserId)
let reposts = yield call(retrieveUserReposts, {
const currentUserId = yield* select(getUserId)
let reposts = yield* call(retrieveUserReposts, {
handle,
currentUserId,
offset,
Expand All @@ -40,7 +40,7 @@ function* getReposts({ offset, limit, handle }) {
// Only do this on page 1 of the reposts tab
if (profileId === currentUserId && offset === 0) {
// Get everything that is confirming
const confirming = yield select(getConfirmCalls)
const confirming = yield* select(getConfirmCalls)
if (Object.keys(confirming).length > 0) {
const repostTrackIds = new Set(
reposts.map((r) => r.track_id).filter(Boolean)
Expand All @@ -49,8 +49,8 @@ function* getReposts({ offset, limit, handle }) {
reposts.map((r) => r.playlist_id).filter(Boolean)
)

const tracks = yield select(getTracks)
const collections = yield select(getCollections)
const tracks = yield* select(getTracks)
const collections = yield* select(getCollections)

// For each confirming entry, check if it's a track or collection,
// then check if we have reposted/favorited it, and check to make
Expand Down Expand Up @@ -103,42 +103,42 @@ class FeedSagas extends LineupSagas {

function* addTrackRepost(action) {
const { trackId, source } = action
const accountHandle = yield select(getUserHandle)
const accountHandle = yield* select(getUserHandle)

const formattedTrack = {
kind: Kind.TRACKS,
id: trackId,
uid: makeUid(Kind.TRACKS, trackId, source)
}

yield put(feedActions.add(formattedTrack, trackId, accountHandle, true))
yield* put(feedActions.add(formattedTrack, trackId, accountHandle, true))
}

function* watchRepostTrack() {
yield takeEvery(tracksSocialActions.REPOST_TRACK, addTrackRepost)
yield* takeEvery(tracksSocialActions.REPOST_TRACK, addTrackRepost)
}

function* removeTrackRepost(action) {
const { trackId } = action
const accountHandle = yield select(getUserHandle)
const lineup = yield select((state) =>
const accountHandle = yield* select(getUserHandle)
const lineup = yield* select((state) =>
getProfileFeedLineup(state, accountHandle)
)
const trackLineupEntry = lineup.entries.find((entry) => entry.id === trackId)
if (trackLineupEntry) {
yield put(
yield* put(
feedActions.remove(Kind.TRACKS, trackLineupEntry.uid, accountHandle)
)
}
}

function* watchUndoRepostTrack() {
yield takeEvery(tracksSocialActions.UNDO_REPOST_TRACK, removeTrackRepost)
yield* takeEvery(tracksSocialActions.UNDO_REPOST_TRACK, removeTrackRepost)
}

function* addCollectionRepost(action) {
const { collectionId, source } = action
const accountHandle = yield select(getUserHandle)
const accountHandle = yield* select(getUserHandle)

const formattedCollection = {
kind: Kind.COLLECTIONS,
Expand All @@ -152,23 +152,23 @@ function* addCollectionRepost(action) {
}

function* watchRepostCollection() {
yield takeEvery(
yield* takeEvery(
collectionsSocialActions.REPOST_COLLECTION,
addCollectionRepost
)
}

function* removeCollectionRepost(action) {
const { collectionId } = action
const accountHandle = yield select(getUserHandle)
const lineup = yield select((state) =>
const accountHandle = yield* select(getUserHandle)
const lineup = yield* select((state) =>
getProfileFeedLineup(state, accountHandle)
)
const collectionLineupEntry = lineup.entries.find(
(entry) => entry.id === collectionId
)
if (collectionLineupEntry) {
yield put(
yield* put(
feedActions.remove(
Kind.COLLECTIONS,
collectionLineupEntry.uid,
Expand All @@ -179,7 +179,7 @@ function* removeCollectionRepost(action) {
}

function* watchUndoRepostCollection() {
yield takeEvery(
yield* takeEvery(
collectionsSocialActions.UNDO_REPOST_COLLECTION,
removeCollectionRepost
)
Expand Down
19 changes: 19 additions & 0 deletions packages/web/src/common/store/reachability/sagas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {
reachabilityActions,
reachabilitySelectors,
getContext
} from '@audius/common'
import { take, select, call } from 'typed-redux-saga'

const { getIsReachable } = reachabilitySelectors

export function* getReachability() {
return yield* select(getIsReachable)
}

export function* awaitReachability() {
const isNativeMobile = yield* getContext('isNativeMobile')
const isReachable = yield* call(getReachability)
if (isReachable || !isNativeMobile) return
yield* take(reachabilityActions.SET_REACHABLE)
}

0 comments on commit 92ab4a0

Please sign in to comment.