1
0
mirror of https://github.com/oceanprotocol/ocean.js.git synced 2024-11-26 20:39:05 +01:00

add updateServiceTimeout and edit ddo updates (#544)

* add updateServiceTimeout

* remove unnecessary code

* fix travis

* fix

* add fileinfo endpoint

* fix did problem

* namings refactor

* lint fix
This commit is contained in:
Alex Coseru 2021-01-18 12:02:38 +02:00 committed by GitHub
parent 3801c3925b
commit 16c21e1ecb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 137 additions and 189 deletions

View File

@ -29,7 +29,6 @@ before_script:
- export AQUARIUS_URI="http://172.15.0.5:5000" - export AQUARIUS_URI="http://172.15.0.5:5000"
- export DEPLOY_CONTRACTS="true" - export DEPLOY_CONTRACTS="true"
- export CONTRACTS_VERSION=v0.5.7 - export CONTRACTS_VERSION=v0.5.7
- export PROVIDER_VERSION=latest
- bash -x start_ocean.sh --no-dashboard 2>&1 > start_ocean.log & - bash -x start_ocean.sh --no-dashboard 2>&1 > start_ocean.log &
- cd .. - cd ..
- ./scripts/waitforcontracts.sh - ./scripts/waitforcontracts.sh

View File

@ -1,9 +1,7 @@
import { EditableMetadataLinks } from './EditableMetadataLinks' import { EditableMetadataLinks } from './EditableMetadataLinks'
import { ServicePrices } from './ServicePrices'
export interface EditableMetadata { export interface EditableMetadata {
description?: string description?: string
title?: string title?: string
links?: EditableMetadataLinks[] links?: EditableMetadataLinks[]
servicePrices?: ServicePrices[]
} }

View File

@ -9,7 +9,13 @@ export interface File {
* File URL. * File URL.
* @type {string} * @type {string}
*/ */
url: string url?: string
/**
* Is URL accessible.
* @type {boolean}
*/
valid?: boolean
/** /**
* File index. * File index.

View File

@ -201,60 +201,6 @@ export class MetadataCache {
return result return result
} }
/**
* Update Compute Privacy
* @param {DID | string} did DID of the asset to update.
* @param {number } serviceIndex Service index
* @param {boolean} allowRawAlgorithm Allow Raw Algorithms
* @param {boolean} allowNetworkAccess Allow Raw Algorithms
* @param {String[]} trustedAlgorithms Allow Raw Algorithms
* @param {String} updated Updated field of the DDO
* @param {String} signature Signature using updated field to verify that the consumer has rights
* @return {Promise<String>} Result.
*/
public async updateComputePrivacy(
did: DID | string,
serviceIndex: number,
allowRawAlgorithm: boolean,
allowNetworkAccess: boolean,
trustedAlgorithms: string[],
updated: string,
signature: string
): Promise<string> {
did = did && DID.parse(did)
const fullUrl = `${this.url}${apiPath}/computePrivacy/update/${did.getDid()}`
const result = await this.fetch
.put(
fullUrl,
JSON.stringify({
signature: signature,
updated: updated,
serviceIndex: serviceIndex,
allowRawAlgorithm: allowRawAlgorithm,
allowNetworkAccess: allowNetworkAccess,
trustedAlgorithms: trustedAlgorithms
})
)
.then((response: Response) => {
if (response.ok) {
return response.text
}
this.logger.log(
'update compute privacy failed:',
response.status,
response.statusText
)
return null
})
.catch((error) => {
this.logger.error('Error updating compute privacy: ', error)
return null
})
return result
}
public async getOwnerAssets(owner: string): Promise<QueryResult> { public async getOwnerAssets(owner: string): Promise<QueryResult> {
const q = { const q = {
offset: 100, offset: 100,
@ -271,47 +217,6 @@ export class MetadataCache {
return result return result
} }
/**
* Edit Metadata for a DDO.
* @param {did} string DID.
* @param {newMetadata} EditableMetadata Metadata fields & new values.
* @param {String} updated Updated field of the DDO
* @param {String} signature Signature using updated field to verify that the consumer has rights
* @return {Promise<String>} Result.
*/
public async editMetadata(
did: DID | string,
newMetadata: EditableMetadata,
updated: string,
signature: string
): Promise<string> {
did = did && DID.parse(did)
const fullUrl = `${this.url}${apiPath}/metadata/${did.getDid()}`
const data = Object()
if (newMetadata.description != null) data.description = newMetadata.description
if (newMetadata.title != null) data.title = newMetadata.title
if (newMetadata.servicePrices != null) data.servicePrices = newMetadata.servicePrices
if (newMetadata.links != null) data.links = newMetadata.links
data.updated = updated
data.signature = signature
const result = await this.fetch
.put(fullUrl, JSON.stringify(data))
.then((response: Response) => {
if (response.ok) {
return response.text
}
this.logger.log('editMetaData failed:', response.status, response.statusText)
return null
})
.catch((error) => {
this.logger.error('Error transfering ownership metadata: ', error)
return null
})
return result
}
/** /**
* Retire a DDO (Delete) * Retire a DDO (Delete)
* @param {DID | string} did DID of the asset to update. * @param {DID | string} did DID of the asset to update.

View File

@ -239,82 +239,52 @@ export class Assets extends Instantiable {
return (await this.ocean.metadatacache.queryMetadata(searchQuery)).results return (await this.ocean.metadatacache.queryMetadata(searchQuery)).results
} }
/** /** Metadata updates
* Edit Metadata for a DDO. * Don't forget to call ocean.OnChainMetadataCache.update after using this functions
* @param {did} string DID. * ie: ocean.OnChainMetadataCache.update(ddo.id,ddo,account.getId())
* @param {newMetadata} EditableMetadata Metadata fields & new values.
* @param {Account} account Ethereum account of owner to sign and prove the ownership.
* @return {Promise<string>}
*/ */
public async editMetadata(
did: string, /**
newMetadata: EditableMetadata, * Edit Metadata for a DID.
account: Account * @param {ddo} DDO if empty, will trigger a retrieve
): Promise<DDO> { * @param {newMetadata} EditableMetadata Metadata fields & new values.
const oldDdo = await this.ocean.metadatacache.retrieveDDO(did) * @return {Promise<DDO>} the new DDO
let i */
for (i = 0; i < oldDdo.service.length; i++) { public async editMetadata(ddo: DDO, newMetadata: EditableMetadata): Promise<DDO> {
if (oldDdo.service[i].type === 'metadata') { if (!ddo) return null
if (newMetadata.title) oldDdo.service[i].attributes.main.name = newMetadata.title for (let i = 0; i < ddo.service.length; i++) {
if (!oldDdo.service[i].attributes.additionalInformation) if (ddo.service[i].type !== 'metadata') continue
oldDdo.service[i].attributes.additionalInformation = Object() if (newMetadata.title) ddo.service[i].attributes.main.name = newMetadata.title
if (newMetadata.description) if (!ddo.service[i].attributes.additionalInformation)
oldDdo.service[i].attributes.additionalInformation.description = ddo.service[i].attributes.additionalInformation = Object()
newMetadata.description if (newMetadata.description)
if (newMetadata.links) ddo.service[i].attributes.additionalInformation.description =
oldDdo.service[i].attributes.additionalInformation.links = newMetadata.links newMetadata.description
} if (newMetadata.links)
ddo.service[i].attributes.additionalInformation.links = newMetadata.links
} }
if (newMetadata.servicePrices) { return ddo
for (i = 0; i < newMetadata.servicePrices.length; i++) {
if (
newMetadata.servicePrices[i].cost &&
newMetadata.servicePrices[i].serviceIndex
) {
oldDdo.service[newMetadata.servicePrices[i].serviceIndex].attributes.main.cost =
newMetadata.servicePrices[i].cost
}
}
}
const storeTx = await this.ocean.OnChainMetadataCache.update(
oldDdo.id,
oldDdo,
account.getId()
)
if (storeTx) return oldDdo
else return null
} }
/** /**
* Update Compute Privacy * Edit Service Timeouts
* @param {did} string DID. * @param {ddo} DDO if empty, will trigger a retrieve
* @param {number} serviceIndex Index of the compute service in the DDO * @param {number} serviceIndex Index of the compute service in the DDO.
* @param {ServiceComputePrivacy} computePrivacy ComputePrivacy fields & new values. * @param {number} timeout New timeout setting
* @param {Account} account Ethereum account of owner to sign and prove the ownership. * @return {Promise<DDO>}
* @return {Promise<string>}
*/ */
public async updateComputePrivacy( public async editServiceTimeout(
did: string, ddo: DDO,
serviceIndex: number, serviceIndex: number,
computePrivacy: ServiceComputePrivacy, timeout: number
account: Account
): Promise<DDO> { ): Promise<DDO> {
const oldDdo = await this.ocean.metadatacache.retrieveDDO(did) if (!ddo) return null
if (oldDdo.service[serviceIndex].type !== 'compute') return null if (typeof ddo.service[serviceIndex] === 'undefined') return null
oldDdo.service[serviceIndex].attributes.main.privacy.allowRawAlgorithm = if (timeout < 0) return null
computePrivacy.allowRawAlgorithm ddo.service[serviceIndex].attributes.main.timeout = parseInt(timeout.toFixed())
oldDdo.service[serviceIndex].attributes.main.privacy.allowNetworkAccess = return ddo
computePrivacy.allowNetworkAccess
oldDdo.service[serviceIndex].attributes.main.privacy.trustedAlgorithms =
computePrivacy.trustedAlgorithms
const storeTx = await this.ocean.OnChainMetadataCache.update(
oldDdo.id,
oldDdo,
account.getId()
)
if (storeTx) return oldDdo
else return null
} }
/** End metadata updates */
/** /**
* Returns the creator of a asset. * Returns the creator of a asset.

View File

@ -433,4 +433,35 @@ export class Compute extends Instantiable {
return order return order
}) })
} }
/**
* Edit Compute Privacy
* @param {did} string DID. You can leave this empty if you already have the DDO
* @param {ddo} DDO if empty, will trigger a retrieve
* @param {number} serviceIndex Index of the compute service in the DDO. If -1, will try to find it
* @param {ServiceComputePrivacy} computePrivacy ComputePrivacy fields & new values.
* @param {Account} account Ethereum account of owner to sign and prove the ownership.
* @return {Promise<DDO>}
*/
public async editComputePrivacy(
ddo: DDO,
serviceIndex: number,
computePrivacy: ServiceComputePrivacy
): Promise<DDO> {
if (!ddo) return null
if (serviceIndex === -1) {
const service = ddo.findServiceByType('compute')
if (!service) return null
serviceIndex = service.index
}
if (typeof ddo.service[serviceIndex] === 'undefined') return null
if (ddo.service[serviceIndex].type !== 'compute') return null
ddo.service[serviceIndex].attributes.main.privacy.allowRawAlgorithm =
computePrivacy.allowRawAlgorithm
ddo.service[serviceIndex].attributes.main.privacy.allowNetworkAccess =
computePrivacy.allowNetworkAccess
ddo.service[serviceIndex].attributes.main.privacy.trustedAlgorithms =
computePrivacy.trustedAlgorithms
return ddo
}
} }

View File

@ -8,6 +8,7 @@ import { MetadataAlgorithm } from '../ddo/interfaces/MetadataAlgorithm'
import { Versions } from '../ocean/Versions' import { Versions } from '../ocean/Versions'
import { Response } from 'node-fetch' import { Response } from 'node-fetch'
import { DDO } from '../ddo/DDO' import { DDO } from '../ddo/DDO'
import DID from '../ocean/DID'
const apiPath = '/api/v1/services' const apiPath = '/api/v1/services'
@ -73,20 +74,28 @@ export class Provider extends Instantiable {
} }
} }
public async checkURL(url: string): Promise<Record<string, string>> { /** Get URL details (if possible)
const args = { url } * @param {String | DID} url or did
* @return {Promise<File[]>} urlDetails
*/
public async fileinfo(url: string | DID): Promise<File[]> {
let args
const files: File[] = []
if (url instanceof DID) {
args = { did: url.getDid() }
} else args = { url }
try { try {
const response = await this.ocean.utils.fetch.post( const response = await this.ocean.utils.fetch.post(
this.getCheckURLEndpoint(), this.getFileinfoEndpoint(),
decodeURI(JSON.stringify(args)) JSON.stringify(args)
) )
const results: File[] = await response.json()
const result = await response.json() for (const result of results) {
files.push(result)
return result.result }
return files
} catch (e) { } catch (e) {
this.logger.error(e) return null
throw new Error('HTTP request failed')
} }
} }
@ -298,8 +307,8 @@ export class Provider extends Instantiable {
return `${this.url}${apiPath}/encrypt` return `${this.url}${apiPath}/encrypt`
} }
public getCheckURLEndpoint(): string { public getFileinfoEndpoint(): string {
return `${this.url}${apiPath}/checkURL` return `${this.url}${apiPath}/fileinfo`
} }
public getPublishEndpoint(): string { public getPublishEndpoint(): string {

View File

@ -468,13 +468,14 @@ describe('Compute flow', () => {
} }
} }
assert(computeIndex > 0) assert(computeIndex > 0)
const newDdo = await ocean.assets.updateComputePrivacy( const newDdo = await ocean.compute.editComputePrivacy(
ddo.id, ddo,
computeIndex, computeIndex,
newComputePrivacy, newComputePrivacy
alice
) )
assert(newDdo !== null) assert(newDdo !== null)
const txid = await ocean.OnChainMetadataCache.update(newDdo.id, newDdo, alice.getId())
assert(txid !== null)
await sleep(60000) await sleep(60000)
const metaData = await ocean.assets.getServiceByType(ddo.id, 'compute') const metaData = await ocean.assets.getServiceByType(ddo.id, 'compute')
assert.equal( assert.equal(

View File

@ -5,7 +5,8 @@ import spies from 'chai-spies'
import Web3 from 'web3' import Web3 from 'web3'
import { AbiItem } from 'web3-utils/types' import { AbiItem } from 'web3-utils/types'
import { DataTokens } from '../../src/datatokens/Datatokens' import { DataTokens } from '../../src/datatokens/Datatokens'
import { Account, EditableMetadata, Service, ServiceAccess } from '../../src/lib' import { Account, EditableMetadata, Service, ServiceAccess, DID } from '../../src/lib'
import { noDidPrefixed } from '../../src/utils/'
import { Ocean } from '../../src/ocean/Ocean' import { Ocean } from '../../src/ocean/Ocean'
import { ConfigHelper } from '../../src/utils/ConfigHelper' import { ConfigHelper } from '../../src/utils/ConfigHelper'
import { TestContractHandler } from '../TestContractHandler' import { TestContractHandler } from '../TestContractHandler'
@ -89,8 +90,7 @@ describe('Marketplace flow', () => {
license: 'MIT', license: 'MIT',
files: [ files: [
{ {
url: url: 'https://s3.amazonaws.com/testfiles.oceanprotocol.com/info.0.json',
'https://raw.githubusercontent.com/tbertinmahieux/MSongsDB/master/Tasks_Demos/CoverSongs/shs_dataset_test.txt',
checksum: 'efb2c764274b745f5fc37f97c6b0e761', checksum: 'efb2c764274b745f5fc37f97c6b0e761',
contentLength: '4535431', contentLength: '4535431',
contentType: 'text/csv', contentType: 'text/csv',
@ -212,8 +212,10 @@ describe('Marketplace flow', () => {
title: 'new title', title: 'new title',
links: [{ name: 'link1', type: 'sample', url: 'http://example.net' }] links: [{ name: 'link1', type: 'sample', url: 'http://example.net' }]
} }
const newDdo = await ocean.assets.editMetadata(ddo.id, newMetaData, alice) const newDdo = await ocean.assets.editMetadata(ddo, newMetaData)
assert(newDdo !== null) assert(newDdo !== null)
const txid = await ocean.OnChainMetadataCache.update(newDdo.id, newDdo, alice.getId())
assert(txid !== null)
await sleep(60000) await sleep(60000)
const metaData = await ocean.assets.getServiceByType(ddo.id, 'metadata') const metaData = await ocean.assets.getServiceByType(ddo.id, 'metadata')
assert.equal(metaData.attributes.main.name, newMetaData.title) assert.equal(metaData.attributes.main.name, newMetaData.title)
@ -224,6 +226,28 @@ describe('Marketplace flow', () => {
assert.deepEqual(metaData.attributes.additionalInformation.links, newMetaData.links) assert.deepEqual(metaData.attributes.additionalInformation.links, newMetaData.links)
}) })
it('Alice updates timeout for the access service', async () => {
const service = ddo.findServiceByType('access')
assert(service !== null)
const serviceIndex = service.index
const newTimeout = 123
const newDdo = await ocean.assets.editServiceTimeout(ddo, serviceIndex, newTimeout)
assert(newDdo !== null)
const txid = await ocean.OnChainMetadataCache.update(newDdo.id, newDdo, alice.getId())
assert(txid !== null)
await sleep(60000)
const metaData = await ocean.assets.getServiceByType(ddo.id, 'access')
assert(parseInt(metaData.attributes.main.timeout) === parseInt(newTimeout.toFixed()))
})
it('Alice should check if her asset has valid url(s)', async () => {
const did: DID = DID.generate(noDidPrefixed(ddo.id))
const response = await ocean.provider.fileinfo(did)
assert(response[0].valid === true)
assert(response[0].contentLength === '1161')
assert(response[0].contentType === 'application/json')
})
it('Alice publishes a dataset but passed data token is invalid', async () => { it('Alice publishes a dataset but passed data token is invalid', async () => {
price = '10' // in datatoken price = '10' // in datatoken
const publishedDate = new Date(Date.now()).toISOString().split('.')[0] + 'Z' const publishedDate = new Date(Date.now()).toISOString().split('.')[0] + 'Z'

View File

@ -18,8 +18,13 @@ describe('Provider tests', () => {
}) })
it('Check a valid URL', async () => { it('Check a valid URL', async () => {
const url = 'https://s3.amazonaws.com/testfiles.oceanprotocol.com/info.0.json' const url = 'https://s3.amazonaws.com/testfiles.oceanprotocol.com/info.0.json'
const response = await ocean.provider.checkURL(url) const response = await ocean.provider.fileinfo(url)
assert(response.contentLength === '1161') assert(response[0].contentLength === '1161')
assert(response.contentType === 'application/json') assert(response[0].contentType === 'application/json')
})
it('Check a invalid URL', async () => {
const url = 'https://s3.amazonaws.com/testfiles.oceanprotocol.com/nosuchfile'
const response = await ocean.provider.fileinfo(url)
assert(response[0].valid === false)
}) })
}) })