From e175cfbdce83292e7fb296edf7b75075673b372d Mon Sep 17 00:00:00 2001 From: joe Date: Wed, 17 Aug 2022 15:15:35 +0000 Subject: [PATCH 1/3] Track entity manager --- libs/src/api/Track.ts | 131 ++++++++++++++---- libs/src/api/entityManager.ts | 13 +- .../dataContracts/EntityManagerClient.ts | 30 +++- libs/src/utils/utils.ts | 6 + 4 files changed, 136 insertions(+), 44 deletions(-) diff --git a/libs/src/api/Track.ts b/libs/src/api/Track.ts index 35233284298..9aa66129213 100644 --- a/libs/src/api/Track.ts +++ b/libs/src/api/Track.ts @@ -5,6 +5,7 @@ import { CreatorNode } from '../services/creatorNode' import { Nullable, TrackMetadata, Utils } from '../utils' import retry from 'async-retry' import type { TransactionReceipt } from 'web3-core' +import { EntityManagerClient } from '../services/dataContracts/EntityManagerClient' const TRACK_PROPS = [ 'owner_id', @@ -343,12 +344,19 @@ export class Track extends Base { * @param metadata json of the track metadata with all fields, missing fields will error * @param onProgress callback fired with (loaded, total) on byte upload progress */ - async uploadTrack( - trackFile: File, - coverArtFile: File, - metadata: TrackMetadata, + async uploadTrack({ + trackFile, + coverArtFile, + metadata, + useEntityManager, + onProgress + }: { + trackFile: File + coverArtFile: File + metadata: TrackMetadata + useEntityManager: boolean onProgress: () => void - ) { + }) { this.REQUIRES(Services.CREATOR_NODE) this.FILE_IS_VALID(trackFile) @@ -411,21 +419,36 @@ export class Track extends Base { phase = phases.ADDING_TRACK // Write metadata to chain - const multihashDecoded = Utils.decodeMultihash(metadataMultihash) - const { txReceipt, trackId } = - await this.contracts.TrackFactoryClient.addTrack( + let txReceipt: TransactionReceipt + let trackId: number + if (useEntityManager) { + trackId = Track.generateTrackId() + const response = await this.contracts.EntityManagerClient!.manageEntity( + ownerId, + EntityManagerClient!.EntityType.TRACK, + trackId, + EntityManagerClient.Action.CREATE, + metadataMultihash + ) + txReceipt = response.txReceipt + } else { + const multihashDecoded = Utils.decodeMultihash(metadataMultihash) + const response = await this.contracts.TrackFactoryClient.addTrack( ownerId, multihashDecoded.digest, multihashDecoded.hashFn, multihashDecoded.size ) + txReceipt = response.txReceipt + trackId = response.trackId + } phase = phases.ASSOCIATING_TRACK // Associate the track id with the file metadata and block number await this.creatorNode.associateTrack( - trackId, + trackId!, metadataFileUUID, - txReceipt.blockNumber, + txReceipt!.blockNumber, transcodedTrackUUID ) return { @@ -512,7 +535,10 @@ export class Track extends Base { * Adds tracks to chain for this user * Associates tracks with user on creatorNode */ - async addTracksToChainAndCnode(trackMultihashAndUUIDList: ChainInfo[]) { + async addTracksToChainAndCnode( + trackMultihashAndUUIDList: ChainInfo[], + useEntityManager: boolean + ) { this.REQUIRES(Services.CREATOR_NODE) const ownerId = this.userStateManager.getCurrentUserId() if (!ownerId) { @@ -533,15 +559,30 @@ export class Track extends Base { trackInfo // Write metadata to chain - const multihashDecoded = Utils.decodeMultihash(metadataMultihash) - const { txReceipt, trackId } = - await this.contracts.TrackFactoryClient.addTrack( + let txReceipt: TransactionReceipt + let trackId: number + if (useEntityManager) { + trackId = Track.generateTrackId() + const response = + await this.contracts.EntityManagerClient!.manageEntity( + ownerId, + EntityManagerClient!.EntityType.TRACK, + trackId, + EntityManagerClient.Action.CREATE, + metadataMultihash + ) + txReceipt = response.txReceipt + } else { + const multihashDecoded = Utils.decodeMultihash(metadataMultihash) + const response = await this.contracts.TrackFactoryClient.addTrack( ownerId, multihashDecoded.digest, multihashDecoded.hashFn, multihashDecoded.size ) - + txReceipt = response.txReceipt + trackId = response.trackId + } addedToChain[i] = { trackId, metadataFileUUID, @@ -597,7 +638,7 @@ export class Track extends Base { * such as track content, cover art are already on creator node. * @param metadata json of the track metadata with all fields, missing fields will error */ - async updateTrack(metadata: TrackMetadata) { + async updateTrack(metadata: TrackMetadata, useEntityManager: boolean) { this.REQUIRES(Services.CREATOR_NODE) this.IS_OBJECT(metadata) @@ -613,15 +654,28 @@ export class Track extends Base { const { metadataMultihash, metadataFileUUID } = await this.creatorNode.uploadTrackMetadata(metadata) // Write the new metadata to chain - const multihashDecoded = Utils.decodeMultihash(metadataMultihash) - const trackId = metadata.track_id - const { txReceipt } = await this.contracts.TrackFactoryClient.updateTrack( - trackId, - ownerId, - multihashDecoded.digest, - multihashDecoded.hashFn, - multihashDecoded.size - ) + let txReceipt: TransactionReceipt + const trackId: number = metadata.track_id + if (useEntityManager) { + const response = await this.contracts.EntityManagerClient!.manageEntity( + ownerId, + EntityManagerClient!.EntityType.TRACK, + trackId, + EntityManagerClient.Action.UPDATE, + metadataMultihash + ) + txReceipt = response.txReceipt + } else { + const multihashDecoded = Utils.decodeMultihash(metadataMultihash) + const response = await this.contracts.TrackFactoryClient.updateTrack( + trackId, + ownerId, + multihashDecoded.digest, + multihashDecoded.hashFn, + multihashDecoded.size + ) + txReceipt = response.txReceipt + } // Re-associate the track id with the new metadata await this.creatorNode.associateTrack( trackId, @@ -709,10 +763,33 @@ export class Track extends Base { * Marks a tracks as deleted * @param trackId */ - async deleteTrack(trackId: number) { - return await this.contracts.TrackFactoryClient.deleteTrack(trackId) + async deleteTrack(trackId: number, useEntityManager: boolean) { + if (useEntityManager) { + const ownerId = this.userStateManager.getCurrentUserId() + + if (!ownerId) throw new Error('No users loaded for this wallet') + + return await this.contracts.EntityManagerClient!.manageEntity( + ownerId, + EntityManagerClient!.EntityType.TRACK, + trackId, + EntityManagerClient.Action.DELETE, + '' + ) + } else { + return await this.contracts.TrackFactoryClient.deleteTrack(trackId) + } } + // Minimum track ID, intentionally higher than legacy track ID range + static MIN_TRACK_ID = 1000000 + + // Maximum track ID, reflects postgres max integer value + static MAX_TRACK_ID = 2147483647 + + static generateTrackId (): number { + return Utils.getRandomInt(Track.MIN_TRACK_ID, Track.MAX_TRACK_ID) + } /* ------- PRIVATE ------- */ _validateTrackMetadata(metadata: TrackMetadata) { diff --git a/libs/src/api/entityManager.ts b/libs/src/api/entityManager.ts index 2d54985f546..94edb77f2de 100644 --- a/libs/src/api/entityManager.ts +++ b/libs/src/api/entityManager.ts @@ -1,16 +1,7 @@ import { Base, Services } from './base' import type { PlaylistMetadata } from '../services/creatorNode' -import type { Nullable } from '../utils' - -export enum Action { - CREATE = 'Create', - UPDATE = 'Update', - DELETE = 'Delete' -} - -export enum EntityType { - PLAYLIST = 'Playlist' -} +import { Nullable, Utils } from '../utils' +import { EntityType, Action } from '../services/dataContracts/EntityManagerClient' export interface PlaylistOperationResponse { /** diff --git a/libs/src/services/dataContracts/EntityManagerClient.ts b/libs/src/services/dataContracts/EntityManagerClient.ts index fdc10f91ca2..0b8e18d971d 100644 --- a/libs/src/services/dataContracts/EntityManagerClient.ts +++ b/libs/src/services/dataContracts/EntityManagerClient.ts @@ -1,20 +1,38 @@ +import type { TransactionReceipt } from 'web3-core' + import { ContractClient } from '../contracts/ContractClient' import * as signatureSchemas from '../../data-contracts/signatureSchemas' import type { Web3Manager } from '../web3Manager' + +export enum Action { + CREATE = 'Create', + UPDATE = 'Update', + DELETE = 'Delete' +} + +export enum EntityType { + PLAYLIST = 'Playlist', + TRACK = 'Track', + USER = 'User' +} + /** * Generic management of Audius Data entities **/ export class EntityManagerClient extends ContractClient { override web3Manager!: Web3Manager + static Action = Action + static EntityType = EntityType + async manageEntity( userId: number, - entityType: string, + entityType: EntityType, entityId: number, - action: string, - metadata: string - ): Promise<{ txReceipt: any }> { + action: Action, + metadataMultihash: string + ): Promise<{ txReceipt: TransactionReceipt }> { const nonce = signatureSchemas.getNonce() const chainId = await this.getEthNetId() const contractAddress = await this.getAddress() @@ -25,7 +43,7 @@ export class EntityManagerClient extends ContractClient { entityType, entityId, action, - metadata, + metadataMultihash, nonce ) const sig = await this.web3Manager.signTypedData(signatureData) @@ -35,7 +53,7 @@ export class EntityManagerClient extends ContractClient { entityType, entityId, action, - metadata, + metadataMultihash, nonce, sig ) diff --git a/libs/src/utils/utils.ts b/libs/src/utils/utils.ts index fd1865a89a7..691b19e020d 100644 --- a/libs/src/utils/utils.ts +++ b/libs/src/utils/utils.ts @@ -226,5 +226,11 @@ export class Utils { return await Promise.race([promise, timeoutPromise]) } + static getRandomInt(min: number, max: number): number { + min = Math.ceil(min) + max = Math.floor(max) + return Math.floor(Math.random() * (max - min) + min) + } + static fileHasher = fileHasher } From f88e42650ad80f3f80833c3285b439b16907ff5e Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 23 Aug 2022 18:15:14 +0000 Subject: [PATCH 2/3] fix --- libs/src/api/Track.ts | 10 +++++----- libs/src/api/entityManager.ts | 5 ++++- libs/src/services/dataContracts/EntityManagerClient.ts | 1 - 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libs/src/api/Track.ts b/libs/src/api/Track.ts index 9aa66129213..6b0bd47a874 100644 --- a/libs/src/api/Track.ts +++ b/libs/src/api/Track.ts @@ -425,7 +425,7 @@ export class Track extends Base { trackId = Track.generateTrackId() const response = await this.contracts.EntityManagerClient!.manageEntity( ownerId, - EntityManagerClient!.EntityType.TRACK, + EntityManagerClient.EntityType.TRACK, trackId, EntityManagerClient.Action.CREATE, metadataMultihash @@ -566,7 +566,7 @@ export class Track extends Base { const response = await this.contracts.EntityManagerClient!.manageEntity( ownerId, - EntityManagerClient!.EntityType.TRACK, + EntityManagerClient.EntityType.TRACK, trackId, EntityManagerClient.Action.CREATE, metadataMultihash @@ -659,7 +659,7 @@ export class Track extends Base { if (useEntityManager) { const response = await this.contracts.EntityManagerClient!.manageEntity( ownerId, - EntityManagerClient!.EntityType.TRACK, + EntityManagerClient.EntityType.TRACK, trackId, EntityManagerClient.Action.UPDATE, metadataMultihash @@ -771,7 +771,7 @@ export class Track extends Base { return await this.contracts.EntityManagerClient!.manageEntity( ownerId, - EntityManagerClient!.EntityType.TRACK, + EntityManagerClient.EntityType.TRACK, trackId, EntityManagerClient.Action.DELETE, '' @@ -787,7 +787,7 @@ export class Track extends Base { // Maximum track ID, reflects postgres max integer value static MAX_TRACK_ID = 2147483647 - static generateTrackId (): number { + static generateTrackId(): number { return Utils.getRandomInt(Track.MIN_TRACK_ID, Track.MAX_TRACK_ID) } /* ------- PRIVATE ------- */ diff --git a/libs/src/api/entityManager.ts b/libs/src/api/entityManager.ts index 94edb77f2de..478ea9a9e2e 100644 --- a/libs/src/api/entityManager.ts +++ b/libs/src/api/entityManager.ts @@ -1,7 +1,10 @@ import { Base, Services } from './base' import type { PlaylistMetadata } from '../services/creatorNode' import { Nullable, Utils } from '../utils' -import { EntityType, Action } from '../services/dataContracts/EntityManagerClient' +import { + EntityType, + Action +} from '../services/dataContracts/EntityManagerClient' export interface PlaylistOperationResponse { /** diff --git a/libs/src/services/dataContracts/EntityManagerClient.ts b/libs/src/services/dataContracts/EntityManagerClient.ts index 0b8e18d971d..7c7f1ea1f45 100644 --- a/libs/src/services/dataContracts/EntityManagerClient.ts +++ b/libs/src/services/dataContracts/EntityManagerClient.ts @@ -4,7 +4,6 @@ import { ContractClient } from '../contracts/ContractClient' import * as signatureSchemas from '../../data-contracts/signatureSchemas' import type { Web3Manager } from '../web3Manager' - export enum Action { CREATE = 'Create', UPDATE = 'Update', From d4ee10b113526dc9aab9927b11f64149373897ed Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 23 Aug 2022 19:21:57 +0000 Subject: [PATCH 3/3] Fix lint --- libs/src/api/Track.ts | 8 ++++---- libs/src/api/entityManager.ts | 6 +----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/libs/src/api/Track.ts b/libs/src/api/Track.ts index 6b0bd47a874..f6bd16e1473 100644 --- a/libs/src/api/Track.ts +++ b/libs/src/api/Track.ts @@ -446,7 +446,7 @@ export class Track extends Base { phase = phases.ASSOCIATING_TRACK // Associate the track id with the file metadata and block number await this.creatorNode.associateTrack( - trackId!, + trackId, metadataFileUUID, txReceipt!.blockNumber, transcodedTrackUUID @@ -561,10 +561,10 @@ export class Track extends Base { // Write metadata to chain let txReceipt: TransactionReceipt let trackId: number - if (useEntityManager) { + if (useEntityManager && this.contracts.EntityManagerClient) { trackId = Track.generateTrackId() const response = - await this.contracts.EntityManagerClient!.manageEntity( + await this.contracts.EntityManagerClient.manageEntity( ownerId, EntityManagerClient.EntityType.TRACK, trackId, @@ -782,7 +782,7 @@ export class Track extends Base { } // Minimum track ID, intentionally higher than legacy track ID range - static MIN_TRACK_ID = 1000000 + static MIN_TRACK_ID = 2000000 // Maximum track ID, reflects postgres max integer value static MAX_TRACK_ID = 2147483647 diff --git a/libs/src/api/entityManager.ts b/libs/src/api/entityManager.ts index 478ea9a9e2e..ea5a1c7e1f0 100644 --- a/libs/src/api/entityManager.ts +++ b/libs/src/api/entityManager.ts @@ -42,11 +42,7 @@ export class EntityManager extends Base { /** * Generate random integer between two known values */ - getRandomInt(min: number, max: number): number { - min = Math.ceil(min) - max = Math.floor(max) - return Math.floor(Math.random() * (max - min) + min) - } + getRandomInt = Utils.getRandomInt mapTimestamps(addedTimestamps: PlaylistTrack[]) { const trackIds = addedTimestamps.map((trackObj) => ({