@audius/sdk 1.0.30 → 1.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,15 @@
1
1
  import type { AudiusLibs } from '../AudiusLibs';
2
+ import type { Nullable } from '../utils';
2
3
  export declare class SanityChecks {
3
4
  libs: AudiusLibs;
4
- constructor(libsInstance: AudiusLibs);
5
+ options: {
6
+ skipRollover: boolean;
7
+ };
8
+ constructor(libsInstance: AudiusLibs, options?: {
9
+ skipRollover: boolean;
10
+ });
5
11
  /**
6
12
  * Runs sanity checks
7
13
  */
8
- run(): Promise<void>;
14
+ run(creatorNodeWhitelist?: Nullable<Set<string>>, creatorNodeBlacklist?: Nullable<Set<string>>): Promise<void>;
9
15
  }
@@ -0,0 +1,3 @@
1
+ import { Nullable } from '../utils';
2
+ import type { AudiusLibs } from '../AudiusLibs';
3
+ export declare const rolloverNodes: (libs: AudiusLibs, creatorNodeWhitelist: Nullable<Set<string>>, creatorNodeBlacklist: Nullable<Set<string>>) => Promise<void>;
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@audius/sdk",
3
- "version": "1.0.30",
3
+ "version": "1.0.32",
4
4
  "audius": {
5
- "releaseSHA": "7ce874a45ba7adba69a2f46056ce11392c38509e"
5
+ "releaseSHA": "4a054eaea012fe2486864db78f64558101523e33"
6
6
  },
7
7
  "description": "",
8
8
  "main": "dist/index.cjs.js",
@@ -1,24 +1,34 @@
1
1
  import { addSecondaries } from './addSecondaries'
2
2
  import { syncNodes } from './syncNodes'
3
+ import { rolloverNodes } from './rolloverNodes'
3
4
  import { needsRecoveryEmail } from './needsRecoveryEmail'
4
5
  import { assignReplicaSetIfNecessary } from './assignReplicaSetIfNecessary'
5
6
  import type { AudiusLibs } from '../AudiusLibs'
7
+ import type { Nullable } from '../utils'
6
8
 
7
9
  // Checks to run at startup to ensure a user is in a good state.
8
10
  export class SanityChecks {
9
11
  libs: AudiusLibs
12
+ options: { skipRollover: boolean }
10
13
 
11
- constructor(libsInstance: AudiusLibs) {
14
+ constructor(libsInstance: AudiusLibs, options = { skipRollover: false }) {
12
15
  this.libs = libsInstance
16
+ this.options = options
13
17
  }
14
18
 
15
19
  /**
16
20
  * Runs sanity checks
17
21
  */
18
- async run() {
22
+ async run(
23
+ creatorNodeWhitelist: Nullable<Set<string>> = null,
24
+ creatorNodeBlacklist: Nullable<Set<string>> = null
25
+ ) {
19
26
  await addSecondaries(this.libs)
20
27
  await assignReplicaSetIfNecessary(this.libs)
21
28
  await syncNodes(this.libs)
29
+ if (!this.options.skipRollover) {
30
+ await rolloverNodes(this.libs, creatorNodeWhitelist, creatorNodeBlacklist)
31
+ }
22
32
  await needsRecoveryEmail(this.libs)
23
33
  }
24
34
  }
@@ -0,0 +1,92 @@
1
+ import { Nullable, Utils } from '../utils'
2
+ import { CreatorNode } from '../services/creatorNode'
3
+ import type { AudiusLibs } from '../AudiusLibs'
4
+
5
+ const THREE_SECONDS = 3000
6
+ const MAX_TRIES = 3
7
+
8
+ /** Check if the user's primary creator node is healthy */
9
+ const checkPrimaryHealthy = async (
10
+ libs: AudiusLibs,
11
+ primary: string,
12
+ tries: number
13
+ ): Promise<boolean> => {
14
+ const healthy = await Utils.isHealthy(primary)
15
+ if (healthy) return healthy
16
+ else {
17
+ if (tries === 0) {
18
+ return false
19
+ }
20
+ await Utils.wait(THREE_SECONDS)
21
+ return await checkPrimaryHealthy(libs, primary, tries - 1)
22
+ }
23
+ }
24
+
25
+ /** Gets new endpoints from a user's secondaries */
26
+ const getNewPrimary = async (libs: AudiusLibs, secondaries: string[]) => {
27
+ for (const secondary of secondaries) {
28
+ const syncStatus = await libs.creatorNode?.getSyncStatus(secondary)
29
+ if (!syncStatus) continue
30
+ if (!syncStatus.isBehind) {
31
+ return secondary
32
+ }
33
+ }
34
+ throw new Error(`Could not find valid secondaries for user ${secondaries}`)
35
+ }
36
+
37
+ export const rolloverNodes = async (
38
+ libs: AudiusLibs,
39
+ creatorNodeWhitelist: Nullable<Set<string>>,
40
+ creatorNodeBlacklist: Nullable<Set<string>>
41
+ ) => {
42
+ console.debug('Sanity Check - rolloverNodes')
43
+ const user = libs.userStateManager?.getCurrentUser()
44
+
45
+ if (!user) return
46
+
47
+ const primary = CreatorNode.getPrimary(user.creator_node_endpoint)
48
+ if (!primary) return
49
+
50
+ const healthy = await checkPrimaryHealthy(libs, primary, MAX_TRIES)
51
+ if (healthy && !creatorNodeBlacklist?.has(primary)) return
52
+
53
+ const secondaries = CreatorNode.getSecondaries(user.creator_node_endpoint)
54
+
55
+ try {
56
+ // Get a new primary
57
+ const newPrimary = await getNewPrimary(libs, secondaries)
58
+ const index = secondaries.indexOf(newPrimary)
59
+ // Get new secondaries and backfill up to 2
60
+ let newSecondaries = [...secondaries]
61
+ newSecondaries.splice(index, 1)
62
+ const autoselect = await libs.ServiceProvider?.autoSelectCreatorNodes({
63
+ numberOfNodes: 2 - newSecondaries.length,
64
+ whitelist: creatorNodeWhitelist,
65
+ // Exclude ones we currently have
66
+ blacklist: new Set([newPrimary, ...newSecondaries]),
67
+ preferHigherPatchForPrimary: libs.User?.preferHigherPatchForPrimary,
68
+ preferHigherPatchForSecondaries:
69
+ libs.User?.preferHigherPatchForSecondaries
70
+ })
71
+ if (autoselect) {
72
+ newSecondaries = newSecondaries.concat([
73
+ autoselect.primary,
74
+ ...autoselect.secondaries
75
+ ])
76
+ }
77
+
78
+ // Set the new endpoint and connect to it
79
+ const newEndpoints = [newPrimary, ...newSecondaries]
80
+ await libs.creatorNode?.setEndpoint(newEndpoints[0]!)
81
+
82
+ // Update the user
83
+ const newMetadata = { ...user }
84
+ newMetadata.creator_node_endpoint = newEndpoints.join(',')
85
+ console.debug(
86
+ `Sanity Check - rolloverNodes - new nodes ${newMetadata.creator_node_endpoint}`
87
+ )
88
+ await libs.User?.updateCreator(user.user_id, newMetadata)
89
+ } catch (e) {
90
+ console.error(e)
91
+ }
92
+ }