Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT]feat: use arfs-js as filesystems for repositories #125

Draft
wants to merge 4 commits into
base: development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@uiw/react-codemirror": "^4.21.11",
"@uiw/react-md-editor": "^3.23.5",
"ardb": "^1.1.10",
"arfs-js": "^1.2.7",
"arweave": "^1.14.4",
"clsx": "^2.0.0",
"date-fns": "^2.30.0",
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const CONTRACT_TX_ID = 'w5ZU15Y2cLzZlu3jewauIlnzbKw-OAxbN9G5TbuuiDQ'
export const CONTRACT_TX_ID = 'NLIpqKz21gA68AQUL7zDorx7MIYHTfrrSbXDn2vhm-I'
export const VITE_GA_TRACKING_ID = 'G-L433HSR0D0'
export const AMPLITUDE_TRACKING_ID = '92a463755ed8c8b96f0f2353a37b7b2'
export const PL_REPO_ID = '6ace6247-d267-463d-b5bd-7e50d98c3693'
Expand Down
12 changes: 10 additions & 2 deletions src/helpers/getArrayBufSize.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
export function getArrayBufSize(arrayBuffer: ArrayBuffer): GetArrayBufSizeReturnType {
const byteSize = arrayBuffer.byteLength
export function getRepoSize(arrayBufferOrSize: ArrayBuffer | number): GetArrayBufSizeReturnType {
let byteSize = 0

if (arrayBufferOrSize instanceof ArrayBuffer) {
byteSize = arrayBufferOrSize.byteLength
}

if (typeof arrayBufferOrSize === 'number') {
byteSize = arrayBufferOrSize
}

if (byteSize >= 1073741824) {
return {
Expand Down
51 changes: 51 additions & 0 deletions src/lib/arfs/arfsSingleton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ArFS, BiFrost, Drive } from 'arfs-js'

let instance: ArFSSingleton
let driveInstance: Drive | null = null
let bifrostInstance: BiFrost | null = null
let arfsInstance: ArFS | null = null

class ArFSSingleton {
driveInstance: Drive | null = null
bifrostInstance: BiFrost | null = null
arfsInstance: ArFS | null = null

constructor() {
if (instance) {
throw new Error('You can only create one instance!')
}
// eslint-disable-next-line @typescript-eslint/no-this-alias
instance = this
}

getInstance() {
return this
}

getBifrostInstance() {
return bifrostInstance
}

getArfsInstance() {
return arfsInstance
}

getDriveInstance() {
return driveInstance
}

setDrive(drive: Drive) {
driveInstance = drive
}

setBifrost(bifrost: BiFrost) {
bifrostInstance = bifrost
}

setArFS(arfs: ArFS) {
arfsInstance = arfs
}
}

const singletonArfs = Object.freeze(new ArFSSingleton())
export default singletonArfs
24 changes: 24 additions & 0 deletions src/lib/arfs/arfsTxSubmissionOverride.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Transaction from 'arweave/web/lib/transaction'
import { v4 as uuidv4 } from 'uuid'

import { createSignedQueuePayload } from '../queue/helpers'
import taskQueueSingleton from '../queue/TaskQueue'

export async function arfsTxSubmissionOverride(txList: Transaction[]) {
const queueStatus = taskQueueSingleton.getTaskQueueStatus()
const txIds: string[] = []

if (queueStatus === 'Busy') throw new Error('Task Queue is busy. Try again later.')

for (const tx of txList) {
const dataItem = await createSignedQueuePayload(tx)

const token = uuidv4()
taskQueueSingleton.sendToPending(token, dataItem)

const txid = await dataItem.id
txIds.push(txid)
}

return { successTxIds: txIds, failedTxIndex: [] }
}
10 changes: 10 additions & 0 deletions src/lib/arfs/getArFS.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ArFS } from 'arfs-js'

import { arfsTxSubmissionOverride } from './arfsTxSubmissionOverride'

export function getArFS() {
const arfs = new ArFS({ wallet: 'use_wallet', appName: 'Protocol.Land' })
arfs.api.signAndSendAllTransactions = arfsTxSubmissionOverride

return arfs
}
7 changes: 7 additions & 0 deletions src/lib/arfs/getBifrost.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ArFS, BiFrost, Drive } from 'arfs-js'

export function getBifrost(drive: Drive, arfs: ArFS) {
const bifrost = new BiFrost(drive, arfs)

return bifrost
}
12 changes: 9 additions & 3 deletions src/lib/git/helpers/fsWithName.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import LightningFS from '@isomorphic-git/lightning-fs'
// import LightningFS from '@isomorphic-git/lightning-fs'

import singletonArfs from '@/lib/arfs/arfsSingleton'

export function fsWithName(name: string) {
return new LightningFS(name)
const bifrost = singletonArfs.getBifrostInstance()

if (!bifrost) throw new Error('Bifrost uninitialized.')
console.log({ name })
return bifrost.fs
}

export type FSType = ReturnType<typeof fsWithName>
export type FSType = ReturnType<typeof fsWithName>
98 changes: 49 additions & 49 deletions src/lib/git/repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,64 +33,64 @@ const arweave = new Arweave({
protocol: 'https'
})

export async function postNewRepo({ id, title, description, file, owner, visibility }: any) {
const publicKey = await getActivePublicKey()
export async function postNewRepo({ id, dataTxId, title, description, visibility }: any) {
// const publicKey = await getActivePublicKey()

const userSigner = await getSigner()

let data = (await toArrayBuffer(file)) as ArrayBuffer
// let data = (await toArrayBuffer(file)) as ArrayBuffer

const inputTags = [
{ name: 'App-Name', value: 'Protocol.Land' },
{ name: 'Content-Type', value: file.type },
{ name: 'Creator', value: owner },
{ name: 'Title', value: title },
{ name: 'Description', value: description },
{ name: 'Repo-Id', value: id },
{ name: 'Type', value: 'repo-create' },
{ name: 'Visibility', value: visibility }
] as Tag[]
// const inputTags = [
kranthicodes marked this conversation as resolved.
Show resolved Hide resolved
// { name: 'App-Name', value: 'Protocol.Land' },
// { name: 'Content-Type', value: file.type },
// { name: 'Creator', value: owner },
// { name: 'Title', value: title },
// { name: 'Description', value: description },
// { name: 'Repo-Id', value: id },
// { name: 'Type', value: 'repo-create' },
// { name: 'Visibility', value: visibility }
// ] as Tag[]

let privateStateTxId = ''
if (visibility === 'private') {
const pubKeyArray = [strToJwkPubKey(publicKey)]
// Encrypt
const { aesKey, encryptedFile, iv } = await encryptFileWithAesGcm(data)
const encryptedAesKeysArray = await encryptAesKeyWithPublicKeys(aesKey, pubKeyArray)
// // Store 'encrypted', 'iv', and 'encryptedKeyArray' securely

const privateState = {
version: '0.1',
iv,
encKeys: encryptedAesKeysArray,
pubKeys: [publicKey]
}
const privateStateTxId = ''
// if (visibility === 'private') {
// const pubKeyArray = [strToJwkPubKey(publicKey)]
// // Encrypt
// const { aesKey, encryptedFile, iv } = await encryptFileWithAesGcm(data)
// const encryptedAesKeysArray = await encryptAesKeyWithPublicKeys(aesKey, pubKeyArray)
// // // Store 'encrypted', 'iv', and 'encryptedKeyArray' securely

const privateInputTags = [
{ name: 'App-Name', value: 'Protocol.Land' },
{ name: 'Content-Type', value: 'application/json' },
{ name: 'Type', value: 'private-state' },
{ name: 'ID', value: id }
] as Tag[]
// const privateState = {
// version: '0.1',
// iv,
// encKeys: encryptedAesKeysArray,
// pubKeys: [publicKey]
// }

const privateStateTxResponse = await signAndSendTx(JSON.stringify(privateState), privateInputTags, userSigner)
// const privateInputTags = [
// { name: 'App-Name', value: 'Protocol.Land' },
// { name: 'Content-Type', value: 'application/json' },
// { name: 'Type', value: 'private-state' },
// { name: 'ID', value: id }
// ] as Tag[]

if (!privateStateTxResponse) {
throw new Error('Failed to post Private State')
}
// const privateStateTxResponse = await signAndSendTx(JSON.stringify(privateState), privateInputTags, userSigner)

privateStateTxId = privateStateTxResponse
// if (!privateStateTxResponse) {
// throw new Error('Failed to post Private State')
// }

data = encryptedFile
}
// privateStateTxId = privateStateTxResponse

await waitFor(500)
// data = encryptedFile
// }

const dataTxResponse = await signAndSendTx(data, inputTags, userSigner, true)
// await waitFor(500)

if (!dataTxResponse) {
throw new Error('Failed to post Git repository')
}
// const dataTxResponse = await signAndSendTx(data, inputTags, userSigner, true)

// if (!dataTxResponse) {
// throw new Error('Failed to post Git repository')
// }

const contract = await getWarpContract(CONTRACT_TX_ID, userSigner)

Expand All @@ -100,13 +100,13 @@ export async function postNewRepo({ id, title, description, file, owner, visibil
id,
name: title,
description,
dataTxId: dataTxResponse,
dataTxId,
visibility,
privateStateTxId
}
})

return { txResponse: dataTxResponse }
return { txResponse: id }
}

export async function updateGithubSync({ id, currentGithubSync, githubSync }: any) {
Expand Down Expand Up @@ -398,9 +398,9 @@ export async function createNewRepo(title: string, fs: FSType, owner: string, id

await waitFor(1000)

const repoBlob = await packGitRepo({ fs, dir })
// const repoBlob = await packGitRepo({ fs, dir })

return { repoBlob, commit: sha }
return { commit: sha }
} catch (error) {
console.error('failed to create repo')
}
Expand Down
52 changes: 52 additions & 0 deletions src/lib/queue/BaseQueue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { QueueObserver } from './QueueObserver'

export class BaseQueue<T> {
public list: Array<{ token: string; payload: T }> = []
protected addedList: Record<string, string> = {}
private observers: QueueObserver<T>[] = []

constructor() {}

public enqueue(token: string, payload: T) {
if (!this.isInList(token)) {
this.list.unshift({ token, payload })
this.addedList[token] = token
}
}

public dequeue(token?: string) {
// you can pass token for removing specific item
if (token) {
const itemShouldRemove = this.list.find((item) => item.token === token)
this.list = this.list.filter((item) => item.token !== token)

delete this.addedList[token]

return itemShouldRemove
} else {
const item = this.list.pop()

if (item) delete this.addedList[item?.token]

return item
}
}

public isInList(token: string) {
return token in this.addedList
}

public addObserver(observer: QueueObserver<T>) {
this.observers.push(observer)
}

public notifyObservers(item: { token: string; payload: T }) {
for (const observer of this.observers) {
observer.update(item)
}
}

public getList() {
return this.list
}
}
14 changes: 14 additions & 0 deletions src/lib/queue/PendingQueue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Transaction from 'arweave/web/lib/transaction'
import { DataItem } from 'warp-arbundles'

import { BaseQueue } from './BaseQueue'
import { QueueObserver } from './QueueObserver'

export class PendingQueue<T> extends BaseQueue<T> {}

export class PendingObserver implements QueueObserver<Transaction | DataItem> {
update(item: { token: string; payload: Transaction | DataItem }) {
console.log({ item }, "<-- added to queue")
//check for progress queue length and move items from pending to progress
}
}
3 changes: 3 additions & 0 deletions src/lib/queue/QueueObserver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export abstract class QueueObserver<T> {
abstract update(item: { token: string; payload: T }): void
}
Loading