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

Commit

Permalink
[C-796] Refactor AudiusAPIClient to work in native context (#1687)
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanjeffers committed Aug 8, 2022
1 parent a185c09 commit afdbe97
Show file tree
Hide file tree
Showing 70 changed files with 1,641 additions and 534 deletions.
1,122 changes: 1,100 additions & 22 deletions packages/mobile/package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion packages/mobile/package.json
Expand Up @@ -71,6 +71,7 @@
"lodash.samplesize": "4.2.0",
"lottie-ios": "3.2.3",
"lottie-react-native": "4.1.3",
"module": "1.2.5",
"moment": "2.24.0",
"node-libs-react-native": "1.2.1",
"numeral": "2.0.6",
Expand Down Expand Up @@ -119,7 +120,8 @@
"rn-fetch-blob": "0.12.0",
"semver": "7.3.7",
"tls-browserify": "0.2.2",
"type-fest": "2.16.0"
"type-fest": "2.16.0",
"typed-redux-saga": "1.3.1"
},
"optionalDependencies": {
"ios-deploy": "1.11.4"
Expand All @@ -144,6 +146,7 @@
"@types/react-redux": "7.1.18",
"@types/react-test-renderer": "16.9.0",
"babel-jest": "24.9.0",
"babel-plugin-macros": "3.1.0",
"eslint": "8.19.0",
"eslint-config-audius": "1.2.2",
"jest": "24.9.0",
Expand Down
5 changes: 1 addition & 4 deletions packages/mobile/src/App.tsx
Expand Up @@ -20,7 +20,7 @@ import useConnectivity from 'app/components/web/useConnectivity'
import { incrementSessionCount } from 'app/hooks/useSessionCount'
import PushNotifications from 'app/notifications'
import { RootScreen } from 'app/screens/root-screen'
import createStore from 'app/store'
import { store } from 'app/store'
import { setup as setupAnalytics } from 'app/utils/analytics'

import { Drawers } from './Drawers'
Expand All @@ -31,9 +31,6 @@ Sentry.init({
dsn: Config.SENTRY_DSN
})

const store = createStore()
export const dispatch = store.dispatch

const Airplay = Platform.select({
ios: () => require('./components/audio/Airplay').default,
android: () => () => null
Expand Down
2 changes: 1 addition & 1 deletion packages/mobile/src/message/handlers/download.ts
Expand Up @@ -7,9 +7,9 @@ import type {
} from 'rn-fetch-blob'
import RNFetchBlob from 'rn-fetch-blob'

import { dispatch } from 'app/App'
import type { MessageHandlers } from 'app/message/types'
import { MessageType } from 'app/message/types'
import { dispatch } from 'app/store'
import {
setDownloadedPercentage,
setFileInfo,
Expand Down
2 changes: 1 addition & 1 deletion packages/mobile/src/notifications.ts
Expand Up @@ -7,7 +7,7 @@ import Config from 'react-native-config'
// https://dev.to/edmondso006/react-native-local-ios-and-android-notifications-2c58
import PushNotification from 'react-native-push-notification'

import { dispatch } from 'app/App'
import { dispatch } from 'app/store'
import { open } from 'app/store/notifications/actions'
import type { MessagePostingWebView } from 'app/types/MessagePostingWebView'
import { EventNames } from 'app/types/analytics'
Expand Down
7 changes: 7 additions & 0 deletions packages/mobile/src/services/audius-backend-instance.ts
Expand Up @@ -10,6 +10,13 @@ import { monitoringCallbacks } from './monitoringCallbacks'
import { getFeatureEnabled } from './remote-config'
import { remoteConfigInstance } from './remote-config/remote-config-instance'

// TODO: declare this at the root and use actual audiusLibs type
declare global {
interface Window {
audiusLibs: any
}
}

let audiusLibs: AudiusLibs

/**
Expand Down
70 changes: 1 addition & 69 deletions packages/mobile/src/store/index.ts
@@ -1,69 +1 @@
import type { CommonState } from 'audius-client/src/common/store'
import type { RemoteConfigState } from 'audius-client/src/common/store/remote-config/slice'
import remoteConfig from 'audius-client/src/common/store/remote-config/slice'
import { createStore, combineReducers, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import createSagaMiddleware from 'redux-saga'

import type { AudioState } from './audio/reducer'
import audio from './audio/reducer'
import { reducer as common } from './common/reducer'
import type { DownloadState } from './download/slice'
import downloads from './download/slice'
import type { DrawersState } from './drawers/slice'
import drawers from './drawers/slice'
import type { KeyboardState } from './keyboard/slice'
import keyboard from './keyboard/slice'
import type { LifecycleState } from './lifecycle/reducer'
import lifecycle from './lifecycle/reducer'
import type { NotificationsState } from './notifications/reducer'
import notifications from './notifications/reducer'
import type { OAuthState } from './oauth/reducer'
import oauth from './oauth/reducer'
import rootSaga from './sagas'
import type { SearchState } from './search/reducer'
import search from './search/reducer'
import type { SignonState } from './signon/reducer'
import signon from './signon/reducer'
import type { WebState } from './web/reducer'
import web from './web/reducer'

export type AppState = {
audio: AudioState
common: CommonState
drawers: DrawersState
downloads: DownloadState
keyboard: KeyboardState
lifecycle: LifecycleState
notifications: NotificationsState
oauth: OAuthState
remoteConfig: RemoteConfigState
search: SearchState
signon: SignonState
web: WebState
}

const createRootReducer = () =>
combineReducers({
audio,
common,
drawers,
downloads,
keyboard,
lifecycle,
notifications,
oauth,
remoteConfig,
search,
signon,
web
})

export default () => {
const sagaMiddleware = createSagaMiddleware()
const middlewares = applyMiddleware(sagaMiddleware)
const composeEnhancers = composeWithDevTools({ trace: true, traceLimit: 25 })
const store = createStore(createRootReducer(), composeEnhancers(middlewares))
sagaMiddleware.run(rootSaga)
return store
}
export * from './store'
4 changes: 2 additions & 2 deletions packages/mobile/src/store/sagas.ts
@@ -1,5 +1,5 @@
import remoteConfig from 'audius-client/src/common/store/remote-config/sagas'
import { all, fork } from 'redux-saga/effects'
import { all, fork } from 'typed-redux-saga/macro'

import { remoteConfigInstance } from 'app/services/remote-config/remote-config-instance'

Expand All @@ -12,5 +12,5 @@ export default function* rootSaga() {
...remoteConfig(remoteConfigInstance),
...oauthSagas()
]
yield all(sagas.map(fork))
yield* all(sagas.map(fork))
}
72 changes: 72 additions & 0 deletions packages/mobile/src/store/store.ts
@@ -0,0 +1,72 @@
import type { CommonState } from 'audius-client/src/common/store'
import type { RemoteConfigState } from 'audius-client/src/common/store/remote-config/slice'
import remoteConfig from 'audius-client/src/common/store/remote-config/slice'
import { createStore, combineReducers, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import createSagaMiddleware from 'redux-saga'

import type { AudioState } from './audio/reducer'
import audio from './audio/reducer'
import { reducer as common } from './common/reducer'
import type { DownloadState } from './download/slice'
import downloads from './download/slice'
import type { DrawersState } from './drawers/slice'
import drawers from './drawers/slice'
import type { KeyboardState } from './keyboard/slice'
import keyboard from './keyboard/slice'
import type { LifecycleState } from './lifecycle/reducer'
import lifecycle from './lifecycle/reducer'
import type { NotificationsState } from './notifications/reducer'
import notifications from './notifications/reducer'
import type { OAuthState } from './oauth/reducer'
import oauth from './oauth/reducer'
import rootSaga from './sagas'
import type { SearchState } from './search/reducer'
import search from './search/reducer'
import type { SignonState } from './signon/reducer'
import signon from './signon/reducer'
import type { WebState } from './web/reducer'
import web from './web/reducer'

export type AppState = {
audio: AudioState
common: CommonState
drawers: DrawersState
downloads: DownloadState
keyboard: KeyboardState
lifecycle: LifecycleState
notifications: NotificationsState
oauth: OAuthState
remoteConfig: RemoteConfigState
search: SearchState
signon: SignonState
web: WebState
}

const createRootReducer = () =>
combineReducers({
audio,
common,
drawers,
downloads,
keyboard,
lifecycle,
notifications,
oauth,
remoteConfig,
search,
signon,
web
})

const sagaMiddleware = createSagaMiddleware()
const middlewares = applyMiddleware(sagaMiddleware)
const composeEnhancers = composeWithDevTools({ trace: true, traceLimit: 25 })
export const store = createStore(
createRootReducer(),
composeEnhancers(middlewares)
)
sagaMiddleware.run(rootSaga)

const { dispatch } = store
export { dispatch }
Expand Up @@ -5,19 +5,21 @@ import {
Nullable,
removeNullable,
IntKeys,
StringKeys
StringKeys,
RemoteConfigInstance
} from '@audius/common'
import { AudiusLibs } from '@audius/sdk'

import { AuthHeaders } from 'common/services/audius-backend'
import { SearchKind } from 'common/store/pages/search-results/types'
import { decodeHashId, encodeHashId } from 'common/utils/hashIds'
import { SupporterResponse } from 'services/audius-backend/Tipping'
import { audiusBackendInstance } from 'services/audius-backend/audius-backend-instance'
import type { SupporterResponse } from 'services/audius-backend/Tipping'
import {
getEagerDiscprov,
waitForLibsInit
} from 'services/audius-backend/eagerLoadUtils'
import { remoteConfigInstance } from 'services/remote-config/remote-config-instance'

import type { AudiusBackend } from '../audius-backend'

import * as adapter from './ResponseAdapter'
import { processSearchResults } from './helper'
Expand All @@ -34,6 +36,7 @@ import {
OpaqueID
} from './types'

// TODO: declare this at the root and use actual audiusLibs type
declare global {
interface Window {
audiusLibs: any
Expand Down Expand Up @@ -419,15 +422,33 @@ type GetUserSupporterArgs = {
currentUserId: Nullable<ID>
}

class AudiusAPIClient {
type AudiusAPIClientConfig = {
audiusBackendInstance: AudiusBackend
audiusLibs?: AudiusLibs
overrideEndpoint?: string
remoteConfigInstance: RemoteConfigInstance
}

export class AudiusAPIClient {
initializationState: InitializationState = {
state: 'uninitialized'
}

audiusBackendInstance: AudiusBackend
audiusLibs?: AudiusLibs
overrideEndpoint?: string

constructor({ overrideEndpoint }: { overrideEndpoint?: string } = {}) {
remoteConfigInstance: RemoteConfigInstance

constructor({
audiusBackendInstance,
audiusLibs,
overrideEndpoint,
remoteConfigInstance
}: AudiusAPIClientConfig) {
this.audiusBackendInstance = audiusBackendInstance
this.audiusLibs = audiusLibs
this.overrideEndpoint = overrideEndpoint
this.remoteConfigInstance = remoteConfigInstance
}

async getTrending({
Expand All @@ -446,7 +467,7 @@ class AudiusAPIClient {
user_id: encodedCurrentUserId || undefined,
genre: genre || undefined
}
const experiment = remoteConfigInstance.getRemoteVar(
const experiment = this.remoteConfigInstance.getRemoteVar(
StringKeys.TRENDING_EXPERIMENT
)
const trendingResponse: Nullable<APIResponse<APITrack[]>> =
Expand All @@ -472,7 +493,7 @@ class AudiusAPIClient {
offset,
user_id: encodedCurrentUserId
}
const experiment = remoteConfigInstance.getRemoteVar(
const experiment = this.remoteConfigInstance.getRemoteVar(
StringKeys.UNDERGROUND_TRENDING_EXPERIMENT
)
const trendingResponse: Nullable<APIResponse<APITrack[]>> =
Expand All @@ -495,7 +516,7 @@ class AudiusAPIClient {
limit,
genre: genre || undefined
}
const experiment = remoteConfigInstance.getRemoteVar(
const experiment = this.remoteConfigInstance.getRemoteVar(
StringKeys.TRENDING_EXPERIMENT
)
const trendingIdsResponse: Nullable<APIResponse<TrendingIdsResponse>> =
Expand Down Expand Up @@ -534,7 +555,8 @@ class AudiusAPIClient {
const encodedCurrentUserId = encodeHashId(currentUserId)
const params = {
genre,
limit: remoteConfigInstance.getRemoteVar(IntKeys.AUTOPLAY_LIMIT) || 10,
limit:
this.remoteConfigInstance.getRemoteVar(IntKeys.AUTOPLAY_LIMIT) || 10,
exclusion_list:
exclusionList.length > 0 ? exclusionList.map(String) : undefined,
user_id: encodedCurrentUserId || undefined
Expand Down Expand Up @@ -918,7 +940,7 @@ class AudiusAPIClient {
let headers = {}
if (encodedCurrentUserId && getUnlisted) {
const { data, signature } =
await audiusBackendInstance.signDiscoveryNodeRequest()
await this.audiusBackendInstance.signDiscoveryNodeRequest()
headers = {
[AuthHeaders.Message]: data,
[AuthHeaders.Signature]: signature
Expand Down Expand Up @@ -1144,7 +1166,7 @@ class AudiusAPIClient {
time
}

const experiment = remoteConfigInstance.getRemoteVar(
const experiment = this.remoteConfigInstance.getRemoteVar(
StringKeys.PLAYLIST_TRENDING_EXPERIMENT
)
const response: Nullable<APIResponse<APIPlaylist[]>> =
Expand Down Expand Up @@ -1410,7 +1432,7 @@ class AudiusAPIClient {
}

// Listen for libs on chain selection
audiusBackendInstance.addDiscoveryProviderSelectionListener(
this.audiusBackendInstance.addDiscoveryProviderSelectionListener(
(endpoint: string | null) => {
if (endpoint) {
console.debug(`APIClient: Setting to libs discprov: ${endpoint}`)
Expand Down Expand Up @@ -1463,8 +1485,11 @@ class AudiusAPIClient {
}, {})

const formattedPath = this._formatPath(pathType, path)
if (this.initializationState.type === 'libs' && window.audiusLibs) {
const data = await window.audiusLibs.discoveryProvider._makeRequest(
const audiusLibs =
this.audiusLibs ??
(this.initializationState.type === 'libs' && window.audiusLibs)
if (audiusLibs) {
const data = await audiusLibs.discoveryProvider._makeRequest(
{
endpoint: formattedPath,
queryParams: sanitizedParams,
Expand Down Expand Up @@ -1542,7 +1567,3 @@ class AudiusAPIClient {
return `${this.initializationState.endpoint}${path}?${params}`
}
}

const instance = new AudiusAPIClient()

export default instance
@@ -0,0 +1 @@
export * from './AudiusAPIClient'

0 comments on commit afdbe97

Please sign in to comment.