1
0
mirror of https://github.com/oceanprotocol-archive/squid-js.git synced 2024-02-02 15:31:51 +01:00
squid-js/src/ocean/OceanAssets.ts

288 lines
10 KiB
TypeScript
Raw Normal View History

import { SearchQuery } from "../aquarius/Aquarius"
import { DDO } from "../ddo/DDO"
import { MetaData } from "../ddo/MetaData"
import { Service } from "../ddo/Service"
2019-01-21 17:48:40 +01:00
import Account from "./Account"
import DID from "./DID"
import { fillConditionsWithDDO } from "../utils"
import { Instantiable, InstantiableConfig } from "../Instantiable.abstract"
2019-01-21 17:48:40 +01:00
/**
* Assets submodule of Ocean Protocol.
*/
export class OceanAssets extends Instantiable {
2019-01-21 17:48:40 +01:00
/**
* Returns the instance of OceanAssets.
* @return {Promise<OceanAssets>}
*/
public static async getInstance(config: InstantiableConfig): Promise<OceanAssets> {
const instance = new OceanAssets()
instance.setInstanceConfig(config)
2019-01-21 17:48:40 +01:00
return instance
2019-01-21 17:48:40 +01:00
}
/**
* Returns a DDO by DID.
* @param {string} did Decentralized ID.
* @return {Promise<DDO>}
*/
public async resolve(did: string): Promise<DDO> {
const d: DID = DID.parse(did)
return this.ocean.aquarius.retrieveDDO(d)
2019-01-21 17:48:40 +01:00
}
/**
* Creates a new DDO.
* @param {MetaData} metadata DDO metadata.
2019-02-14 11:26:12 +01:00
* @param {Account} publisher Publisher account.
2019-01-21 17:48:40 +01:00
* @return {Promise<DDO>}
*/
public async create(metadata: MetaData, publisher: Account, services: Service[] = []): Promise<DDO> {
const {secretStoreUri} = this.config
const {didRegistry, templates} = this.ocean.keeper
2019-01-21 17:48:40 +01:00
const did: DID = DID.generate()
const encryptedFiles = await this.ocean.secretStore.encrypt(did.getId(), metadata.base.files, publisher)
2019-01-21 17:48:40 +01:00
2019-03-14 21:28:51 +01:00
const serviceAgreementTemplate = await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplate()
2019-01-21 17:48:40 +01:00
const serviceEndpoint = this.ocean.aquarius.getServiceEndpoint(did)
2019-01-21 17:48:40 +01:00
2019-02-07 11:29:55 +01:00
let serviceDefinitionIdCount = 0
2019-01-21 17:48:40 +01:00
// create ddo itself
const ddo: DDO = new DDO({
id: did.getDid(),
2019-01-21 17:48:40 +01:00
authentication: [{
type: "RsaSignatureAuthentication2018",
publicKey: did.getDid() + "#keys-1",
}],
2019-01-21 17:48:40 +01:00
publicKey: [
{
id: did.getDid() + "#keys-1",
type: "Ed25519VerificationKey2018",
owner: did.getDid(),
publicKeyBase58: await publisher.getPublicKey(),
},
2019-01-21 17:48:40 +01:00
],
service: [
2019-01-21 17:48:40 +01:00
{
type: "Access",
purchaseEndpoint: this.ocean.brizo.getPurchaseEndpoint(),
serviceEndpoint: this.ocean.brizo.getConsumeEndpoint(),
2019-02-07 11:29:55 +01:00
serviceDefinitionId: String(serviceDefinitionIdCount++),
templateId: templates.escrowAccessSecretStoreTemplate.getAddress(),
serviceAgreementTemplate,
},
2019-01-21 17:48:40 +01:00
{
type: "Compute",
serviceEndpoint: this.ocean.brizo.getComputeEndpoint(publisher.getId(), String(serviceDefinitionIdCount), "xxx", "xxx"),
2019-02-07 11:29:55 +01:00
serviceDefinitionId: String(serviceDefinitionIdCount++),
},
2019-02-15 23:40:55 +01:00
{
type: "Authorization",
2019-02-21 18:14:07 +01:00
services: "SecretStore",
2019-02-15 23:40:55 +01:00
serviceEndpoint: secretStoreUri,
serviceDefinitionId: String(serviceDefinitionIdCount++),
},
2019-01-21 17:48:40 +01:00
{
type: "Metadata",
serviceEndpoint,
2019-02-07 11:29:55 +01:00
serviceDefinitionId: String(serviceDefinitionIdCount++),
metadata: {
// Default values
curation: {
rating: 0,
numVotes: 0,
},
additionalInformation: {
updateFrecuency: "yearly",
structuredMarkup: [],
},
// Overwrites defaults
...metadata,
// Cleaning not needed information
base: {
...metadata.base,
contentUrls: [],
encryptedFiles,
2019-03-28 09:43:39 +01:00
files: metadata.base.files
.map((file, index) => ({
...file,
index,
url: undefined,
})),
} as any,
},
},
...services
.map((_) => ({..._, serviceDefinitionId: String(serviceDefinitionIdCount++)})),
2019-02-15 23:40:55 +01:00
]
// Remove duplications
.reverse()
.filter(({type}, i, list) => list.findIndex(({type: t}) => t === type) === i)
.reverse() as Service[],
2019-01-21 17:48:40 +01:00
})
// Overwritte initial service agreement conditions
2019-03-14 21:28:51 +01:00
const rawConditions = await templates.escrowAccessSecretStoreTemplate.getServiceAgreementTemplateConditions()
const conditions = fillConditionsWithDDO(rawConditions, ddo)
serviceAgreementTemplate.conditions = conditions
ddo.addChecksum()
await ddo.addProof(this.ocean, publisher.getId(), publisher.getPassword())
const storedDdo = await this.ocean.aquarius.storeDDO(ddo)
2019-01-21 17:48:40 +01:00
await didRegistry.registerAttribute(
did.getId(),
2019-02-06 12:54:06 +01:00
ddo.getChecksum(),
2019-03-25 13:47:21 +01:00
[this.config.brizoAddress],
2019-01-21 17:48:40 +01:00
serviceEndpoint,
publisher.getId(),
)
2019-01-21 17:48:40 +01:00
return storedDdo
}
2019-02-21 18:14:07 +01:00
// tslint:disable-next-line
public async consume(agreementId: string, did: string, serviceDefinitionId: string, consumerAccount: Account, resultPath: string, index?: number): Promise<string>
// tslint:disable-next-line
public async consume(agreementId: string, did: string, serviceDefinitionId: string, consumerAccount: Account, resultPath?: undefined | null, index?: number): Promise<true>
2019-02-21 18:14:07 +01:00
public async consume(
2019-02-21 17:58:54 +01:00
agreementId: string,
did: string,
serviceDefinitionId: string,
consumerAccount: Account,
resultPath?: string,
index: number = -1,
2019-02-21 17:58:54 +01:00
): Promise<string | true> {
const ddo = await this.resolve(did)
2019-02-21 18:14:07 +01:00
const {metadata} = ddo.findServiceByType("Metadata")
2019-02-21 17:58:54 +01:00
const accessService = ddo.findServiceById(serviceDefinitionId)
const files = metadata.base.files
2019-02-21 17:58:54 +01:00
const {serviceEndpoint} = accessService
if (!serviceEndpoint) {
2019-02-21 18:14:07 +01:00
throw new Error("Consume asset failed, service definition is missing the `serviceEndpoint`.")
2019-02-21 17:58:54 +01:00
}
this.logger.log("Consuming files")
2019-02-21 17:58:54 +01:00
resultPath = resultPath ? `${resultPath}/datafile.${ddo.shortId()}.${agreementId}/` : undefined
await this.ocean.brizo.consumeService(
2019-02-21 17:58:54 +01:00
agreementId,
serviceEndpoint,
consumerAccount,
files,
2019-02-21 17:58:54 +01:00
resultPath,
index,
2019-02-21 17:58:54 +01:00
)
this.logger.log("Files consumed")
2019-02-21 17:58:54 +01:00
if (resultPath) {
return resultPath
}
return true
}
2019-01-21 17:48:40 +01:00
/**
2019-02-13 21:28:42 +01:00
* Start the purchase/order of an asset's service. Starts by signing the service agreement
* then sends the request to the publisher via the service endpoint (Brizo http service).
2019-01-21 17:48:40 +01:00
* @param {string} did Decentralized ID.
* @param {string} serviceDefinitionId Service definition ID.
* @param {Account} consumer Consumer account.
2019-02-13 13:05:08 +01:00
* @return {Promise<string>} Returns Agreement ID
2019-01-21 17:48:40 +01:00
*/
public async order(
did: string,
serviceDefinitionId: string,
consumer: Account,
2019-02-13 13:05:08 +01:00
): Promise<string> {
2019-01-21 17:48:40 +01:00
const oceanAgreements = this.ocean.agreements
2019-01-21 17:48:40 +01:00
this.logger.log("Asking for agreement signature")
2019-02-25 14:06:48 +01:00
const {agreementId, signature} = await oceanAgreements.prepare(did, serviceDefinitionId, consumer)
this.logger.log(`Agreement ${agreementId} signed`)
2019-02-21 17:58:54 +01:00
const ddo = await this.resolve(did)
const keeper = this.ocean.keeper
const templateName = ddo.findServiceByType("Access").serviceAgreementTemplate.contractName
2019-03-15 15:29:47 +01:00
const template = keeper.getTemplateByName(templateName)
const accessCondition = keeper.conditions.accessSecretStoreCondition
const paymentFlow = new Promise(async (resolve, reject) => {
await template.getAgreementCreatedEvent(agreementId).once()
this.logger.log("Agreement initialized")
const {metadata} = ddo.findServiceByType("Metadata")
this.logger.log("Locking payment")
const paid = await oceanAgreements.conditions.lockReward(agreementId, metadata.base.price, consumer)
if (paid) {
this.logger.log("Payment was OK")
} else {
this.logger.error("Payment was KO")
this.logger.error("Agreement ID: ", agreementId)
this.logger.error("DID: ", ddo.id)
reject("Error on payment")
}
await accessCondition.getConditionFulfilledEvent(agreementId).once()
this.logger.log("Access granted")
resolve()
2019-02-21 17:58:54 +01:00
})
this.logger.log("Sending agreement request")
2019-02-25 14:06:48 +01:00
await oceanAgreements.send(did, agreementId, serviceDefinitionId, signature, consumer)
this.logger.log("Agreement request sent")
2019-01-21 17:48:40 +01:00
try {
await paymentFlow
2019-03-21 03:17:36 +01:00
} catch (e) {
throw new Error("Error paying the asset.")
}
2019-02-21 17:58:54 +01:00
2019-02-13 21:28:42 +01:00
return agreementId
2019-01-21 17:48:40 +01:00
}
/**
* Search over the assets using a query.
* @param {SearchQuery} query Query to filter the assets.
* @return {Promise<DDO[]>}
*/
2019-04-05 12:20:42 +02:00
public async query(query: SearchQuery) {
2019-03-26 10:53:22 +01:00
return this.ocean.aquarius.queryMetadata(query)
2019-01-21 17:48:40 +01:00
}
/**
* Search over the assets using a keyword.
* @param {SearchQuery} text Text to filter the assets.
* @return {Promise<DDO[]>}
*/
2019-04-05 12:20:42 +02:00
public async search(text: string) {
return this.ocean.aquarius.queryMetadataByText({
2019-01-21 17:48:40 +01:00
text,
page: 0,
offset: 100,
query: {
value: 1,
},
sort: {
value: 1,
},
} as SearchQuery)
}
}