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

refactor!: use bzz endpoint for file and dirs #280

Merged
merged 7 commits into from
May 5, 2021
Merged
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,6 @@
"engines": {
"node": ">=12.0.0",
"npm": ">=6.0.0",
"bee": "0.5.3-acbd0e2"
"bee": "0.6.0-acbd0e2"
}
}
62 changes: 15 additions & 47 deletions src/bee.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Readable } from 'stream'
import * as file from './modules/file'
import * as collection from './modules/collection'
import * as bzz from './modules/bzz'
import * as tag from './modules/tag'
import * as pinning from './modules/pinning'
import * as bytes from './modules/bytes'
Expand Down Expand Up @@ -45,6 +44,7 @@ import { EthAddress, makeEthAddress, makeHexEthAddress } from './utils/eth'
import { wrapBytesWithHelpers } from './utils/bytes'
import { assertReference } from './utils/type'
import { setJsonData, getJsonData } from './feed/json'
import { makeCollectionFromFS, makeCollectionFromFileList } from './utils/collection'

/**
* The Bee class provides a way of interacting with the Bee APIs based on the provided url
Expand Down Expand Up @@ -126,32 +126,34 @@ export class Bee {
const contentType = data.type
const fileOptions = options !== undefined ? { contentType, ...options } : { contentType }

return file.upload(this.url, fileData, fileName, fileOptions)
return bzz.uploadFile(this.url, fileData, fileName, fileOptions)
} else {
return file.upload(this.url, data, name, options)
return bzz.uploadFile(this.url, data, name, options)
}
}

/**
* Download single file as a byte array
*
* @param reference Bee file reference
* @param path If reference points to manifest, then this parameter defines path to the file
*/
downloadFile(reference: Reference | string): Promise<FileData<Data>> {
downloadFile(reference: Reference | string, path = ''): Promise<FileData<Data>> {
assertReference(reference)

return file.download(this.url, reference)
return bzz.downloadFile(this.url, reference, path)
}

/**
* Download single file as a readable stream
*
* @param reference Bee file reference
* @param path If reference points to manifest, then this parameter defines path to the file
*/
downloadReadableFile(reference: Reference | string): Promise<FileData<Readable>> {
downloadReadableFile(reference: Reference | string, path = ''): Promise<FileData<Readable>> {
assertReference(reference)

return file.downloadReadable(this.url, reference)
return bzz.downloadFileReadable(this.url, reference, path)
}

/**
Expand All @@ -165,9 +167,9 @@ export class Bee {
* @returns reference of the collection of files
*/
async uploadFiles(fileList: FileList | File[], options?: CollectionUploadOptions): Promise<Reference> {
const data = await collection.buildFileListCollection(fileList)
const data = await makeCollectionFromFileList(fileList)

return collection.upload(this.url, data, options)
return bzz.uploadCollection(this.url, data, options)
}

/**
Expand All @@ -176,48 +178,14 @@ export class Bee {
* Uses the `fs` module of Node.js
*
* @param dir the path of the files to be uploaded
* @param recursive specifies if the directory should be recursively uploaded
* @param options Additional options like tag, encryption, pinning
*
* @returns reference of the collection of files
*/
async uploadFilesFromDirectory(dir: string, recursive = true, options?: CollectionUploadOptions): Promise<Reference> {
const data = await collection.buildCollection(dir, recursive)
async uploadFilesFromDirectory(dir: string, options?: CollectionUploadOptions): Promise<Reference> {
const data = await makeCollectionFromFS(dir)

return collection.upload(this.url, data, options)
}

/**
* Download single file as a byte array from collection given using the path
*
* @param reference Bee collection reference
* @param path Path of the requested file in the collection
*
* @returns file in byte array with metadata
*/
downloadFileFromCollection(reference: Reference | string, path = ''): Promise<FileData<Data>> {
assertReference(reference)

return collection.download(this.url, reference, path)
}

/**
* Download single file as a readable stream from collection given using the path
*
* @param reference Bee collection reference
* @param path Path of the requested file in the collection
* @param axiosOptions optional - alter default options of axios HTTP client
*
* @returns file in readable stream with metadata
*/
downloadReadableFileFromCollection(
reference: Reference | string,
path = '',
axiosOptions?: AxiosRequestConfig,
): Promise<FileData<Readable>> {
assertReference(reference)

return collection.downloadReadable(this.url, reference, path, axiosOptions)
return bzz.uploadCollection(this.url, data, options)
}

/**
Expand Down
161 changes: 161 additions & 0 deletions src/modules/bzz.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import {
Collection,
CollectionUploadOptions,
Data,
FileData,
FileUploadOptions,
Reference,
UploadHeaders,
} from '../types'
import { extractUploadHeaders, readFileHeaders } from '../utils/headers'
import { safeAxios } from '../utils/safeAxios'
import { prepareData } from '../utils/data'
import { BeeArgumentError } from '../utils/error'
import { makeTar } from '../utils/tar'
import { assertCollection } from '../utils/collection'
import { AxiosRequestConfig } from 'axios'
import { wrapBytesWithHelpers } from '../utils/bytes'
import { Readable } from 'stream'

const bzzEndpoint = '/bzz'

interface FileUploadHeaders extends UploadHeaders {
'content-length'?: string
'content-type'?: string
}

function extractFileUploadHeaders(options?: FileUploadOptions): FileUploadHeaders {
const headers: FileUploadHeaders = extractUploadHeaders(options)

if (options?.size) headers['content-length'] = String(options.size)

if (options?.contentType) headers['content-type'] = options.contentType

return headers
}
export async function uploadFile(
url: string,
data: string | Uint8Array | Readable | ArrayBuffer,
name?: string,
options?: FileUploadOptions,
): Promise<Reference> {
if (!url) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is not strictly necessary because uploadFile is not exposed to the public API, therefore it's always called with the inputs already validated.

We also doesn't check the inputs or the url in other functions. If you want stronger guarantees it's possible to create a BeeURL type which is already validated and have the type system enforce its validity.

throw new BeeArgumentError('url parameter is required and cannot be empty', url)
}

const response = await safeAxios<{ reference: Reference }>({
...options?.axiosOptions,
method: 'post',
url: url + bzzEndpoint,
data: prepareData(data),
headers: {
...extractFileUploadHeaders(options),
},
params: { name },
responseType: 'json',
})

return response.data.reference
}

/**
* Download single file as a buffer
*
* @param url Bee URL
* @param hash Bee file or collection hash
* @param path If hash is collection then this defines path to a single file in the collection
* @param axiosOptions optional - alter default options of axios HTTP client
*/
export async function downloadFile(
url: string,
hash: string,
path = '',
axiosOptions?: AxiosRequestConfig,
): Promise<FileData<Data>> {
const response = await safeAxios<ArrayBuffer>({
...axiosOptions,
method: 'GET',
responseType: 'arraybuffer',
url: `${url}${bzzEndpoint}/${hash}/${path}`,
})
const file = {
...readFileHeaders(response.headers),
data: wrapBytesWithHelpers(new Uint8Array(response.data)),
}

return file
}

/**
* Download single file as a readable stream
*
* @param url Bee URL
* @param hash Bee file or collection hash
* @param path If hash is collection then this defines path to a single file in the collection
* @param axiosOptions optional - alter default options of axios HTTP client
*/
export async function downloadFileReadable(
url: string,
hash: string,
path = '',
axiosOptions?: AxiosRequestConfig,
): Promise<FileData<Readable>> {
const response = await safeAxios<Readable>({
...axiosOptions,
method: 'GET',
responseType: 'stream',
url: `${url}${bzzEndpoint}/${hash}/${path}`,
})
const file = {
...readFileHeaders(response.headers),
data: response.data,
}

return file
}

/*******************************************************************************************************************/
// Collections

interface CollectionUploadHeaders extends UploadHeaders {
'swarm-index-document'?: string
'swarm-error-document'?: string
}

function extractCollectionUploadHeaders(options?: CollectionUploadOptions): CollectionUploadHeaders {
const headers: CollectionUploadHeaders = extractUploadHeaders(options)

if (options?.indexDocument) headers['swarm-index-document'] = options.indexDocument

if (options?.errorDocument) headers['swarm-error-document'] = options.errorDocument

return headers
}

export async function uploadCollection(
url: string,
collection: Collection<Uint8Array>,
options?: CollectionUploadOptions,
): Promise<Reference> {
if (!url) {
throw new BeeArgumentError('url parameter is required and cannot be empty', url)
}

assertCollection(collection)
const tarData = makeTar(collection)

const response = await safeAxios<{ reference: Reference }>({
...options?.axiosOptions,
method: 'post',
url: url + bzzEndpoint,
data: tarData,
responseType: 'json',
headers: {
'content-type': 'application/x-tar',
'swarm-collection': 'true',
...extractCollectionUploadHeaders(options),
},
})

return response.data.reference
}
Loading