Update CLI repo management to use leveldb blockstore
This commit is contained in:
parent
c3b3eb473f
commit
0a2bb3b03a
@ -1,7 +1,7 @@
|
||||
import { service } from '@bluesky-demo/common'
|
||||
import * as ucan from 'ucans'
|
||||
import cmd from '../../lib/command.js'
|
||||
import { readRepo, writeRepo } from '../../lib/repo.js'
|
||||
import { Repo } from '../../lib/repo.js'
|
||||
import { REPO_PATH } from '../../lib/env.js'
|
||||
|
||||
export default cmd({
|
||||
@ -11,10 +11,11 @@ export default cmd({
|
||||
args: [{name: 'user', optional: true}],
|
||||
async command (args) {
|
||||
const user = args._[0]
|
||||
const repo = await readRepo(REPO_PATH)
|
||||
const repo = await Repo.load(REPO_PATH)
|
||||
const store = await repo.getLocalUserStore()
|
||||
|
||||
// TODO - handle per-user, handle merged feed
|
||||
// TODO - format output
|
||||
console.log(repo.store.posts)
|
||||
console.log(store.posts)
|
||||
}
|
||||
})
|
@ -1,7 +1,7 @@
|
||||
import { service } from '@bluesky-demo/common'
|
||||
import * as ucan from 'ucans'
|
||||
import cmd from '../../lib/command.js'
|
||||
import { readRepo, writeRepo } from '../../lib/repo.js'
|
||||
import { Repo } from '../../lib/repo.js'
|
||||
import { REPO_PATH } from '../../lib/env.js'
|
||||
|
||||
export default cmd({
|
||||
@ -16,15 +16,18 @@ export default cmd({
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const repo = await readRepo(REPO_PATH)
|
||||
const repo = await Repo.load(REPO_PATH)
|
||||
const store = await repo.getLocalUserStore()
|
||||
|
||||
await repo.store.addPost({
|
||||
console.log('Creating post...')
|
||||
await store.addPost({
|
||||
user: repo.account.name,
|
||||
text
|
||||
})
|
||||
await repo.rootCidFile.put(store.root)
|
||||
|
||||
console.log('Posting to server...')
|
||||
const car = await repo.store.getCarFile()
|
||||
console.log('Uploading to server...')
|
||||
const car = await store.getCarFile()
|
||||
const blueskyDid = await service.getServerDid()
|
||||
const token = await ucan.build({
|
||||
audience: blueskyDid,
|
||||
@ -35,8 +38,5 @@ export default cmd({
|
||||
}]
|
||||
})
|
||||
await service.updateUser(car, ucan.encode(token))
|
||||
|
||||
console.log('Updating local store...')
|
||||
await writeRepo(REPO_PATH, repo)
|
||||
}
|
||||
})
|
@ -1,7 +1,6 @@
|
||||
import prompt from 'prompt'
|
||||
import { promises as fsp } from 'fs'
|
||||
import { writeNewRepo } from '../../lib/repo.js'
|
||||
import { service, UserStore } from '@bluesky-demo/common'
|
||||
import { Repo } from '../../lib/repo.js'
|
||||
import { service } from '@bluesky-demo/common'
|
||||
import * as ucan from 'ucans'
|
||||
import cmd from '../../lib/command.js'
|
||||
import { REPO_PATH } from '../../lib/env.js'
|
||||
@ -53,42 +52,20 @@ export default cmd({
|
||||
})).question
|
||||
}
|
||||
|
||||
try {
|
||||
await fsp.mkdir(REPO_PATH, {recursive: true})
|
||||
} catch (e: any) {
|
||||
console.error(`Failed to create repo at ${REPO_PATH}`)
|
||||
console.error(e.toString())
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log('Generating keys...')
|
||||
const keypair = await ucan.EdKeypair.create({exportable: true})
|
||||
const userDID = keypair.did()
|
||||
const userStore = await UserStore.create(username, keypair)
|
||||
const carFileBuf = await userStore.getCarFile()
|
||||
|
||||
console.log('Writing repo...')
|
||||
await writeNewRepo(
|
||||
REPO_PATH,
|
||||
await keypair.export(),
|
||||
carFileBuf,
|
||||
{
|
||||
name: username,
|
||||
server,
|
||||
did: userDID
|
||||
}
|
||||
)
|
||||
console.log('Generating repo...')
|
||||
const repo = await Repo.createNew(REPO_PATH, username, server)
|
||||
|
||||
if (register) {
|
||||
console.log('Registering with server...')
|
||||
try {
|
||||
// TODO - service needs to use `server`
|
||||
const userStore = await repo.getLocalUserStore()
|
||||
const blueskyDid = await service.getServerDid()
|
||||
const token = await ucan.build({
|
||||
audience: blueskyDid,
|
||||
issuer: keypair
|
||||
issuer: repo.keypair
|
||||
})
|
||||
await service.register(carFileBuf, ucan.encode(token))
|
||||
await service.register(await userStore.getCarFile(), ucan.encode(token))
|
||||
} catch (e: any) {
|
||||
console.error(`Failed to register with server`)
|
||||
console.error(e.toString())
|
||||
@ -99,6 +76,6 @@ export default cmd({
|
||||
|
||||
console.log('')
|
||||
console.log(`Repo created at ${REPO_PATH}`)
|
||||
console.log(`DID: ${userDID}`)
|
||||
console.log(`DID: ${repo.account.did}`)
|
||||
}
|
||||
})
|
@ -1,6 +1,7 @@
|
||||
import path from 'path'
|
||||
import { promises as fsp } from 'fs'
|
||||
import { UserStore, MemoryDB } from '@bluesky-demo/common'
|
||||
import { UserStore, Blockstore } from '@bluesky-demo/common'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import * as ucan from 'ucans'
|
||||
|
||||
export interface AccountJson {
|
||||
@ -9,32 +10,79 @@ export interface AccountJson {
|
||||
did: string
|
||||
}
|
||||
|
||||
export interface Repo {
|
||||
keypair: ucan.EdKeypair
|
||||
account: AccountJson
|
||||
store: UserStore
|
||||
export class Repo {
|
||||
constructor(
|
||||
public keypair: ucan.EdKeypair,
|
||||
public account: AccountJson,
|
||||
public blockstore: Blockstore,
|
||||
public rootCidFile: RootCidFile
|
||||
) {}
|
||||
|
||||
static async createNew (repoPath: string, name: string, server: string): Promise<Repo> {
|
||||
try {
|
||||
await fsp.mkdir(repoPath, {recursive: true})
|
||||
} catch (e: any) {
|
||||
console.error(`Failed to create repo at ${repoPath}`)
|
||||
console.error(e.toString())
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const keypair = await ucan.EdKeypair.create({exportable: true})
|
||||
const userDID = keypair.did()
|
||||
const account: AccountJson = {
|
||||
name,
|
||||
server,
|
||||
did: userDID
|
||||
}
|
||||
|
||||
const blockstore = new Blockstore(path.join(repoPath, 'blockstore'))
|
||||
await fsp.writeFile(path.join(repoPath, 'scdp.key'), await keypair.export(), 'utf-8')
|
||||
await fsp.writeFile(path.join(repoPath, 'account.json'), JSON.stringify(account, null, 2), 'utf-8')
|
||||
const rootCidFile = new RootCidFile(path.join(repoPath, 'root.cid'))
|
||||
|
||||
const localUserStore = await UserStore.create(name, blockstore, keypair)
|
||||
await rootCidFile.put(localUserStore.root)
|
||||
|
||||
return new Repo(
|
||||
keypair,
|
||||
account,
|
||||
blockstore,
|
||||
rootCidFile
|
||||
)
|
||||
}
|
||||
|
||||
static async load (repoPath: string): Promise<Repo> {
|
||||
const secretKeyStr = await readFile(repoPath, 'scdp.key', 'utf-8') as string
|
||||
const account = await readAccountFile(repoPath, 'account.json')
|
||||
const blockstore = new Blockstore(path.join(repoPath, 'blockstore'))
|
||||
const keypair = ucan.EdKeypair.fromSecretKey(secretKeyStr)
|
||||
const rootCidFile = new RootCidFile(path.join(repoPath, 'root.cid'))
|
||||
return new Repo(
|
||||
keypair,
|
||||
account,
|
||||
blockstore,
|
||||
rootCidFile
|
||||
)
|
||||
}
|
||||
|
||||
async getLocalUserStore (): Promise<UserStore> {
|
||||
return this.getUserStore(await this.rootCidFile.get())
|
||||
}
|
||||
|
||||
async getUserStore (cid: CID): Promise<UserStore> {
|
||||
return UserStore.get(cid, this.blockstore, this.keypair) // TODO !!!! only pass in keypair if this is the local user! (waiting on PR to make keypair optional)
|
||||
}
|
||||
}
|
||||
|
||||
export async function writeNewRepo (repoPath: string, secretKeyStr: string, carFileBuf: Uint8Array, accountJson: AccountJson) {
|
||||
// TODO- correct?
|
||||
await fsp.writeFile(path.join(repoPath, 'scdp.key'), secretKeyStr, 'utf-8')
|
||||
await fsp.writeFile(path.join(repoPath, 'blocks.car'), carFileBuf)
|
||||
await fsp.writeFile(path.join(repoPath, 'account.json'), JSON.stringify(accountJson, null, 2), 'utf-8')
|
||||
}
|
||||
|
||||
export async function writeRepo (repoPath: string, repo: Repo) {
|
||||
await fsp.writeFile(path.join(repoPath, 'blocks.car'), await repo.store.getCarFile())
|
||||
}
|
||||
|
||||
export async function readRepo (repoPath: string): Promise<Repo> {
|
||||
const secretKeyStr = await readFile(repoPath, 'scdp.key', 'utf-8') as string
|
||||
const carFileBuf = await readFile(repoPath, 'blocks.car') as Uint8Array
|
||||
const account = await readAccountFile(repoPath, 'account.json')
|
||||
const keypair = ucan.EdKeypair.fromSecretKey(secretKeyStr)
|
||||
return {
|
||||
keypair,
|
||||
account,
|
||||
store: await UserStore.fromCarFile(carFileBuf, MemoryDB.getGlobal(), keypair)
|
||||
class RootCidFile {
|
||||
constructor (public path: string) {}
|
||||
async get () {
|
||||
const str = await fsp.readFile(this.path, 'utf-8')
|
||||
if (!str) throw new Error(`No root.cid file found`)
|
||||
return CID.parse(str)
|
||||
}
|
||||
async put (cid: CID) {
|
||||
await fsp.writeFile(this.path, cid.toString(), 'utf-8')
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user