Skip to content

Commit

Permalink
implemented suggested changes
Browse files Browse the repository at this point in the history
  • Loading branch information
fforbeck committed Oct 24, 2024
1 parent 9b535e0 commit 0b1ed9a
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 30 deletions.
10 changes: 7 additions & 3 deletions packages/capabilities/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export type UsageReportFailure = Ucanto.Failure

export type EgressRecord = InferInvokedCapability<typeof UsageCaps.record>
export type EgressRecordSuccess = Unit
export type EgressRecordFailure = Ucanto.Failure
export type EgressRecordFailure = ConsumerNotFound | Ucanto.Failure

export interface UsageData {
/** Provider the report concerns, e.g. `did:web:web3.storage` */
Expand Down Expand Up @@ -166,14 +166,18 @@ export interface UsageData {
}

export interface EgressData {
/** Id of the customer that is being billed. */
/** The space which contains the resource that was served. */
space: SpaceDID
/** The customer that is being billed for the egress traffic. */
customer: AccountDID
/** CID of the resource that was served. */
/** CID of the resource that was served it's the CID of some gateway accessible content. It is not the CID of a blob/shard.*/
resource: UnknownLink
/** Amount of bytes served. */
bytes: number
/** ISO datetime that the bytes were served at. */
servedAt: ISO8601Date
/** Identifier of the invocation that caused the egress traffic. */
cause: UnknownLink
}

// Provider
Expand Down
4 changes: 1 addition & 3 deletions packages/capabilities/src/usage.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { capability, ok, Schema } from '@ucanto/validator'
import { AccountDID, and, equal, equalWith, SpaceDID } from './utils.js'
import { and, equal, equalWith, SpaceDID } from './utils.js'

/**
* Capability can only be delegated (but not invoked) allowing audience to
Expand Down Expand Up @@ -48,8 +48,6 @@ export const record = capability({
can: 'usage/record',
with: SpaceDID,
nb: Schema.struct({
/** MailTo DID of the customer that is being billed. */
customer: AccountDID,
/** CID of the resource that was served. */
resource: Schema.link(),
/** Amount of bytes served. */
Expand Down
12 changes: 10 additions & 2 deletions packages/upload-api/src/types/usage.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Failure, Result, UnknownLink } from '@ucanto/interface'
import {
AccountDID,
ProviderDID,
SpaceDID,
UsageData,
EgressData,
AccountDID,
} from '@web3-storage/capabilities/types'

export type { UsageData }
Expand All @@ -16,9 +16,17 @@ export interface UsageStorage {
period: { from: Date; to: Date }
) => Promise<Result<UsageData, Failure>>
record: (
/** The space which contains the resource that was served. */
space: SpaceDID,
/** The customer that is being billed for the egress traffic. */
customer: AccountDID,
/** The resource that was served to the customer through the gateway. */
resource: UnknownLink,
/** The number of bytes that were served. */
bytes: number,
servedAt: Date
/** The date and time when the resource was served. */
servedAt: Date,
/** Identifier of the invocation that caused the egress traffic. */
cause: UnknownLink,
) => Promise<Result<EgressData, Failure>>
}
19 changes: 10 additions & 9 deletions packages/upload-api/src/usage/record.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,22 @@ const record = async ({ capability, invocation }, context) => {
capability.with
)
if (consumerResponse.error) {
return {
error: {
name: 'EgressRecordFailure',
message: `Failed to get consumer`,
},
}
return consumerResponse
}
const consumer = consumerResponse.ok
const res = await context.usageStorage.record(
// The space which contains the resource that was served.
capability.with,
// The customer that is being billed for the egress traffic.
consumer.customer,
// CID of the resource that was served.
capability.nb.resource,
// Number of bytes that were served.
capability.nb.bytes,
new Date(capability.nb.servedAt * 1000)
// Date and time when the resource was served.
new Date(capability.nb.servedAt * 1000),
// Link to the invocation that caused the egress traffic.
invocation.cid
)
if (res.error) return res

return res
}
6 changes: 5 additions & 1 deletion packages/upload-api/test/storage/usage-storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,21 @@ export class UsageStorage {
/**
* Simulate a record of egress data for a customer.
*
* @param {import('../types.js').SpaceDID} space
* @param {import('../types.js').AccountDID} customer
* @param {import('../types.js').UnknownLink} resource
* @param {number} bytes
* @param {Date} servedAt
* @param {import('../types.js').UnknownLink} cause
*/
async record(customer, resource, bytes, servedAt) {
async record(space, customer, resource, bytes, servedAt, cause) {
const egressData = {
space,
customer,
resource,
bytes,
servedAt: servedAt.toISOString(),
cause,
}
this._egressRecords[customer] = egressData
return Promise.resolve({
Expand Down
30 changes: 19 additions & 11 deletions packages/w3up-client/src/capability/usage.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,25 @@ export class UsageClient extends Base {
}

/**
* Record egress data for the customer and served resource.
* Record egress data for a served resource.
* It will execute the capability invocation to find the customer and then record the egress data for the resource.
*
* Required delegated capabilities:
* - `usage/record`
*
* @param {import('../types.js').SpaceDID} space
* @param {API.EgressData} egressData
* @param {object} egressData
* @param {API.UnknownLink} egressData.resource
* @param {number} egressData.bytes
* @param {string} egressData.servedAt
* @param {object} [options]
* @param {string} [options.nonce]
*/
async record(space, egressData, options) {
const out = await record(
{ agent: this.agent },
{ ...options, space, egressData }
{ space, ...egressData },
{ ...options }
)
/* c8 ignore next 5 */
if (!out.ok) {
Expand Down Expand Up @@ -89,29 +94,32 @@ export const report = async (
}

/**
* Record egress data for the customer and served resource.
* Record egress data for a resource from a given space.
*
* @param {{agent: API.Agent}} client
* @param {object} egressData
* @param {API.SpaceDID} egressData.space
* @param {API.UnknownLink} egressData.resource
* @param {number} egressData.bytes
* @param {string} egressData.servedAt
* @param {object} options
* @param {API.SpaceDID} options.space
* @param {API.EgressData} options.egressData -
* @param {string} [options.nonce]
* @param {API.Delegation[]} [options.proofs]
* @returns {Promise<API.Result<API.Unit, API.EgressRecordFailure>>}
*/
export const record = async (
{ agent },
{ space, egressData, nonce, proofs = [] }
{ space, resource, bytes, servedAt },
{ nonce, proofs = [] }
) => {
const receipt = await agent.invokeAndExecute(UsageCapabilities.record, {
with: space,
proofs,
nonce,
nb: {
customer: egressData.customer,
resource: egressData.resource,
bytes: egressData.bytes,
servedAt: Math.floor(new Date(egressData.servedAt).getTime() / 1000),
resource,
bytes,
servedAt: Math.floor(new Date(servedAt).getTime() / 1000),
},
})
return receipt.out
Expand Down
1 change: 0 additions & 1 deletion packages/w3up-client/test/capability/usage.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ export const UsageClient = Test.withContext({
assert.ok(result)

const record = await alice.capability.usage.record(space.did(), {
customer: 'did:mailto:alice@web.mail',
resource: resource.link(),
bytes: car.size,
servedAt: new Date().toISOString(),
Expand Down

0 comments on commit 0b1ed9a

Please sign in to comment.