Skip to content

Commit

Permalink
Merge pull request #194 from textileio/asutula/new-api
Browse files Browse the repository at this point in the history
New Powergate API
  • Loading branch information
asutula authored Nov 5, 2020
2 parents 223c091 + 89f2831 commit 29110f3
Show file tree
Hide file tree
Showing 40 changed files with 1,876 additions and 1,818 deletions.
86 changes: 35 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const host = "http://0.0.0.0:6002" // or whatever powergate instance you want
const pow = createPow({ host })
```

Many APIs are immediately available and don't require authorization.
Most Powergate APIs require authorization in the form of a Storage Profile auth token. Storage Profiles are created using the `admin` API. Powergate's backend may be configured to secure the `admin` API with an auth token, and in that case, you'll neeed to set the admin auth token on the client as shown below.

```typescript
import { createPow } from "@textile/powergate-client"
Expand All @@ -58,31 +58,18 @@ const host = "http://0.0.0.0:6002" // or whatever powergate instance you want

const pow = createPow({ host })

async function exampleCode () {
const { status, messagesList } = await pow.health.check()

const { peersList } = await pow.net.peers()
}
```

Other APIs require authorization. The main API you'll interact with is the Filecoin File System (FFS), and it requires authorization. First, create a new FFS instance.

```typescript
import { createPow } from "@textile/powergate-client"

const host = "http://0.0.0.0:6002" // or whatever powergate instance you want

const pow = createPow({ host })
// Set the admin auth token if required.
pow.setAdminToken("<an admin auth token>")

async function exampleCode () {
const { token } = await pow.ffs.create() // save this token for later use!
return token
const { authEntry } = await pow.admin.profiles.createStorageProfile() // save this token for later use!
return authEntry?.token
}
```

Currently, the returned auth token is the only thing that gives you access to your FFS instance at a later time, so be sure to save it securely.
The returned auth token is the only thing that gives access to the corresponding Storage Profile at a later time, so be sure to save it securely.

Once you have an auth token, either by creating a new FFS instance or by reading one you previously saved, set the auth token you'd like the Powergate client to use.
A Storage Profile auth token can later be set for the Powergate client so that the client authenticates with the Storage Profile associated with the auth token.

```typescript
import { createPow } from "@textile/powergate-client"
Expand All @@ -91,66 +78,63 @@ const host = "http://0.0.0.0:6002" // or whatever powergate instance you want

const pow = createPow({ host })

const authToken = '<generated token>'
const token = "<previously generated storage profile auth token>"

pow.setToken(authToken)
pow.setToken(token)
```

Now, the FFS API is available for you to use.
Now, all authenticated APIs are available for you to use.

```typescript
import { JobStatus } from "@textile/grpc-powergate-client/dist/ffs/rpc/rpc_pb"
import fs from "fs"
import { createPow } from "@textile/powergate-client"
import { createPow, powTypes } from "@textile/powergate-client"

const host = "http://0.0.0.0:6002" // or whatever powergate instance you want

const pow = createPow({ host })

async function exampleCode() {
// get wallet addresses associated with your FFS instance
const { addrsList } = await pow.ffs.addrs()
// get wallet addresses associated with your storage profile
const { addressesList } = await pow.wallet.addresses()

// create a new address associated with your ffs instance
const { addr } = await pow.ffs.newAddr("my new addr")
// create a new address associated with your storage profile
const { address } = await pow.wallet.newAddress("my new address")

// get general info about your ffs instance
const { info } = await pow.ffs.info()
// get build information about the powergate server
const res = await pow.buildInfo()

// cache data in IPFS in preparation to store it using FFS
// cache data in IPFS in preparation to store it
const buffer = fs.readFileSync(`path/to/a/file`)
const { cid } = await pow.ffs.stage(buffer)
const { cid } = await pow.data.stage(buffer)

// store the data in FFS using the default storage configuration
const { jobId } = await pow.ffs.pushStorageConfig(cid)
// store the data using the default storage configuration
const { jobId } = await pow.storageConfig.apply(cid)

// watch the FFS job status to see the storage process progressing
const jobsCancel = pow.ffs.watchJobs((job) => {
if (job.status === JobStatus.JOB_STATUS_CANCELED) {
// watch the job status to see the storage process progressing
const jobsCancel = pow.storageJobs.watch((job) => {
if (job.status === powTypes.JobStatus.JOB_STATUS_CANCELED) {
console.log("job canceled")
} else if (job.status === JobStatus.JOB_STATUS_FAILED) {
} else if (job.status === powTypes.JobStatus.JOB_STATUS_FAILED) {
console.log("job failed")
} else if (job.status === JobStatus.JOB_STATUS_SUCCESS) {
} else if (job.status === powTypes.JobStatus.JOB_STATUS_SUCCESS) {
console.log("job success!")
}
}, jobId)

// watch all FFS events for a cid
const logsCancel = pow.ffs.watchLogs((logEvent) => {
// watch all log events for a cid
const logsCancel = pow.data.watchLogs((logEvent) => {
console.log(`received event for cid ${logEvent.cid}`)
}, cid)

// get the current desired storage configuration for a cid (this configuration may not be realized yet)
const { config } = await pow.ffs.getStorageConfig(cid)

// get the current actual storage configuration for a cid
const { cidInfo } = await pow.ffs.show(cid)
// get information about the latest applied storage configuration,
// current storage state, and all related Powegate storage jobs
const { cidInfosList } = await pow.data.cidInfo(cid)

// retrieve data from FFS by cid
const bytes = await pow.ffs.get(cid)
// retrieve data stored in the storage profile by cid
const bytes = await pow.data.get(cid)

// send FIL from an address managed by your FFS instance to any other address
await pow.ffs.sendFil(addrsList[0].addr, "<some other address>", 1000)
// send FIL from an address managed by your storage profile to any other address
await pow.wallet.sendFil(addressesList[0].address, "<some other address>", BigInt(1000))
}
```

Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
}
},
"dependencies": {
"@textile/grpc-powergate-client": "0.6.8",
"@textile/grpc-powergate-client": "1.0.0",
"@textile/grpc-transport": "0.0.3",
"ipfs-http-client": "^47.0.1",
"it-block": "^2.0.0"
Expand Down
34 changes: 34 additions & 0 deletions src/admin/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { grpc } from "@improbable-eng/grpc-web"
import { Config } from "../types"
import { createProfiles, Profiles } from "./profiles"
import { createStorageJobs, StorageJobs } from "./storage-jobs"
import { createWallet, Wallet } from "./wallet"
export { Profiles, StorageJobs, Wallet }

export interface Admin {
/**
* The admin Profiles API.
*/
profiles: Profiles

/**
* The admin Wallet API.
*/
wallet: Wallet

/**
* The admin Storage Jobs API.
*/
storageJobs: StorageJobs
}

/**
* @ignore
*/
export const createAdmin = (config: Config, getMeta: () => grpc.Metadata): Admin => {
return {
profiles: createProfiles(config, getMeta),
wallet: createWallet(config, getMeta),
storageJobs: createStorageJobs(config, getMeta),
}
}
45 changes: 45 additions & 0 deletions src/admin/profiles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { grpc } from "@improbable-eng/grpc-web"
import {
CreateStorageProfileRequest,
CreateStorageProfileResponse,
StorageProfilesRequest,
StorageProfilesResponse,
} from "@textile/grpc-powergate-client/dist/proto/admin/v1/powergate_admin_pb"
import { PowergateAdminServiceClient } from "@textile/grpc-powergate-client/dist/proto/admin/v1/powergate_admin_pb_service"
import { Config } from "../types"
import { promise } from "../util"

export interface Profiles {
/**
* Create a new storage profile.
* @returns Information about the new storage profile.
*/
createStorageProfile: () => Promise<CreateStorageProfileResponse.AsObject>

/**
* List all storage profiles.
* @returns A list of all storage profiles.
*/
storageProfiles: () => Promise<StorageProfilesResponse.AsObject>
}

/**
* @ignore
*/
export const createProfiles = (config: Config, getMeta: () => grpc.Metadata): Profiles => {
const client = new PowergateAdminServiceClient(config.host, config)
return {
createStorageProfile: () => {
return promise(
(cb) => client.createStorageProfile(new CreateStorageProfileRequest(), getMeta(), cb),
(resp: CreateStorageProfileResponse) => resp.toObject(),
)
},

storageProfiles: () =>
promise(
(cb) => client.storageProfiles(new StorageProfilesRequest(), getMeta(), cb),
(resp: StorageProfilesResponse) => resp.toObject(),
),
}
}
125 changes: 125 additions & 0 deletions src/admin/storage-jobs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { grpc } from "@improbable-eng/grpc-web"
import {
ExecutingStorageJobsRequest,
ExecutingStorageJobsResponse,
LatestFinalStorageJobsRequest,
LatestFinalStorageJobsResponse,
LatestSuccessfulStorageJobsRequest,
LatestSuccessfulStorageJobsResponse,
QueuedStorageJobsRequest,
QueuedStorageJobsResponse,
StorageJobsSummaryRequest,
StorageJobsSummaryResponse,
} from "@textile/grpc-powergate-client/dist/proto/admin/v1/powergate_admin_pb"
import { PowergateAdminServiceClient } from "@textile/grpc-powergate-client/dist/proto/admin/v1/powergate_admin_pb_service"
import { Config } from "../types"
import { promise } from "../util"

export interface StorageJobs {
/**
* List queued storgae jobs.
* @param profileId The storage profile id to query or an empty string for all storage profiles.
* @param cids An optional list of data cids to fileter the results with.
* @returns A list of queued storage jobs.
*/
queued: (profileId: string, ...cids: string[]) => Promise<QueuedStorageJobsResponse.AsObject>

/**
* List executing storgae jobs.
* @param profileId The storage profile id to query or an empty string for all storage profiles.
* @param cids An optional list of data cids to fileter the results with.
* @returns A list of executing storage jobs.
*/
executing: (
profileId: string,
...cids: string[]
) => Promise<ExecutingStorageJobsResponse.AsObject>

/**
* List the latest final storgae jobs.
* @param profileId The storage profile id to query or an empty string for all storage profiles.
* @param cids An optional list of data cids to fileter the results with.
* @returns A list of the latest final storage jobs.
*/
latestFinal: (
profileId: string,
...cids: string[]
) => Promise<LatestFinalStorageJobsResponse.AsObject>

/**
* List the latest successful storgae jobs.
* @param profileId The storage profile id to query or an empty string for all storage profiles.
* @param cids An optional list of data cids to fileter the results with.
* @returns A list of the latest successful storage jobs.
*/
latestSuccessful: (
profileId: string,
...cids: string[]
) => Promise<LatestSuccessfulStorageJobsResponse.AsObject>

/**
* Get a summary of all jobs.
* @param profileId The storage profile id to query or an empty string for all storage profiles.
* @param cids An optional list of data cids to fileter the results with.
* @returns A summary of all jobs.
*/
summary: (profileId: string, ...cids: string[]) => Promise<StorageJobsSummaryResponse.AsObject>
}

/**
* @ignore
*/
export const createStorageJobs = (config: Config, getMeta: () => grpc.Metadata): StorageJobs => {
const client = new PowergateAdminServiceClient(config.host, config)
return {
queued: (profileId: string, ...cids: string[]) => {
const req = new QueuedStorageJobsRequest()
req.setCidsList(cids)
req.setProfileId(profileId)
return promise(
(cb) => client.queuedStorageJobs(req, getMeta(), cb),
(resp: QueuedStorageJobsResponse) => resp.toObject(),
)
},

executing: (profileId: string, ...cids: string[]) => {
const req = new ExecutingStorageJobsRequest()
req.setCidsList(cids)
req.setProfileId(profileId)
return promise(
(cb) => client.executingStorageJobs(req, getMeta(), cb),
(resp: ExecutingStorageJobsResponse) => resp.toObject(),
)
},

latestFinal: (profileId: string, ...cids: string[]) => {
const req = new LatestFinalStorageJobsRequest()
req.setCidsList(cids)
req.setProfileId(profileId)
return promise(
(cb) => client.latestFinalStorageJobs(req, getMeta(), cb),
(resp: LatestFinalStorageJobsResponse) => resp.toObject(),
)
},

latestSuccessful: (profileId: string, ...cids: string[]) => {
const req = new LatestSuccessfulStorageJobsRequest()
req.setCidsList(cids)
req.setProfileId(profileId)
return promise(
(cb) => client.latestSuccessfulStorageJobs(req, getMeta(), cb),
(resp: LatestSuccessfulStorageJobsResponse) => resp.toObject(),
)
},

summary: (profileId: string, ...cids: string[]) => {
const req = new StorageJobsSummaryRequest()
req.setCidsList(cids)
req.setProfileId(profileId)
return promise(
(cb) => client.storageJobsSummary(req, getMeta(), cb),
(resp: StorageJobsSummaryResponse) => resp.toObject(),
)
},
}
}
Loading

0 comments on commit 29110f3

Please sign in to comment.