-
Notifications
You must be signed in to change notification settings - Fork 316
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
1,426 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# `storage` | ||
|
||
> TODO: description | ||
## Usage | ||
|
||
``` | ||
const storage = require('storage'); | ||
// TODO: DEMONSTRATE API | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
|
||
const storage = require('..'); | ||
|
||
describe('storage', () => { | ||
it('needs tests'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"name": "@stacks/storage", | ||
"version": "1.0.0", | ||
"description": "Blockstack storage library", | ||
"author": "yknl <yukanliao@gmail.com>", | ||
"homepage": "https://blockstack.org", | ||
"license": "GPL-3.0-or-later", | ||
"main": "lib/index.js", | ||
"directories": { | ||
"lib": "lib", | ||
"test": "__tests__" | ||
}, | ||
"files": [ | ||
"lib" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/blockstack/blockstack.js.git" | ||
}, | ||
"scripts": { | ||
"build": "rimraf lib && tsc -b tsconfig.build.json", | ||
"test": "echo \"Error: run tests from root\" && exit 1" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/blockstack/blockstack.js/issues" | ||
}, | ||
"dependencies": { | ||
"@stacks/auth": "^1.0.0", | ||
"@stacks/common": "^1.0.0", | ||
"@stacks/encryption": "^1.0.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
/** | ||
* Retrieves the specified file from the app's data store. | ||
* @param {String} path - the path to the file to read | ||
* @returns {Promise} that resolves to the raw data in the file | ||
* or rejects with an error | ||
*/ | ||
export | ||
|
||
/** @ignore */ | ||
type PutFileContent = string | Buffer | ArrayBufferView | ArrayBufferLike | Blob | ||
|
||
/** @ignore */ | ||
export class FileContentLoader { | ||
readonly content: Buffer | Blob | ||
|
||
readonly wasString: boolean | ||
|
||
readonly contentType: string | ||
|
||
readonly contentByteLength: number | ||
|
||
private loadedData?: Promise<Buffer> | ||
|
||
static readonly supportedTypesMsg = 'Supported types are: `string` (to be UTF8 encoded), ' | ||
+ '`Buffer`, `Blob`, `File`, `ArrayBuffer`, `UInt8Array` or any other typed array buffer. ' | ||
|
||
constructor(content: PutFileContent, contentType: string) { | ||
this.wasString = typeof content === 'string' | ||
this.content = FileContentLoader.normalizeContentDataType(content, contentType) | ||
this.contentType = contentType || this.detectContentType() | ||
this.contentByteLength = this.detectContentLength() | ||
} | ||
|
||
private static normalizeContentDataType(content: PutFileContent, | ||
contentType: string): Buffer | Blob { | ||
try { | ||
if (typeof content === 'string') { | ||
// If a charset is specified it must be either utf8 or ascii, otherwise the encoded content | ||
// length cannot be reliably detected. If no charset specified it will be treated as utf8. | ||
const charset = (contentType || '').toLowerCase().replace('-', '') | ||
if (charset.includes('charset') && !charset.includes('charset=utf8') && !charset.includes('charset=ascii')) { | ||
throw new Error(`Unable to determine byte length with charset: ${contentType}`) | ||
} | ||
if (typeof TextEncoder !== 'undefined') { | ||
const encodedString = new TextEncoder().encode(content) | ||
return Buffer.from(encodedString.buffer) | ||
} | ||
return Buffer.from(content) | ||
} else if (Buffer.isBuffer(content)) { | ||
return content | ||
} else if (ArrayBuffer.isView(content)) { | ||
return Buffer.from(content.buffer, content.byteOffset, content.byteLength) | ||
} else if (typeof Blob !== 'undefined' && content instanceof Blob) { | ||
return content | ||
} else if (typeof ArrayBuffer !== 'undefined' && content instanceof ArrayBuffer) { | ||
return Buffer.from(content) | ||
} else if (Array.isArray(content)) { | ||
// Provided with a regular number `Array` -- this is either an (old) method | ||
// of representing an octet array, or a dev error. Perform basic check for octet array. | ||
if (content.length > 0 | ||
&& (!Number.isInteger(content[0]) || content[0] < 0 || content[0] > 255)) { | ||
throw new Error(`Unexpected array values provided as file data: value "${content[0]}" at index 0 is not an octet number. ${this.supportedTypesMsg}`) | ||
} | ||
return Buffer.from(content) | ||
} else { | ||
const typeName = Object.prototype.toString.call(content) | ||
throw new Error(`Unexpected type provided as file data: ${typeName}. ${this.supportedTypesMsg}`) | ||
} | ||
} catch (error) { | ||
console.error(error) | ||
throw new Error(`Error processing data: ${error}`) | ||
} | ||
} | ||
|
||
private detectContentType(): string { | ||
if (this.wasString) { | ||
return 'text/plain; charset=utf-8' | ||
} else if (typeof Blob !== 'undefined' && this.content instanceof Blob && this.content.type) { | ||
return this.content.type | ||
} else { | ||
return 'application/octet-stream' | ||
} | ||
} | ||
|
||
private detectContentLength(): number { | ||
if (ArrayBuffer.isView(this.content) || Buffer.isBuffer(this.content)) { | ||
return this.content.byteLength | ||
} else if (typeof Blob !== 'undefined' && this.content instanceof Blob) { | ||
return this.content.size | ||
} | ||
const typeName = Object.prototype.toString.call(this.content) | ||
const error = new Error(`Unexpected type "${typeName}" while detecting content length`) | ||
console.error(error) | ||
throw error | ||
} | ||
|
||
private async loadContent(): Promise<Buffer> { | ||
try { | ||
if (Buffer.isBuffer(this.content)) { | ||
return this.content | ||
} else if (ArrayBuffer.isView(this.content)) { | ||
return Buffer.from(this.content.buffer, this.content.byteOffset, this.content.byteLength) | ||
} else if (typeof Blob !== 'undefined' && this.content instanceof Blob) { | ||
const reader = new FileReader() | ||
const readPromise = new Promise<Buffer>((resolve, reject) => { | ||
reader.onerror = (err) => { | ||
reject(err) | ||
} | ||
reader.onload = () => { | ||
const arrayBuffer = reader.result as ArrayBuffer | ||
resolve(Buffer.from(arrayBuffer)) | ||
} | ||
reader.readAsArrayBuffer(this.content as Blob) | ||
}) | ||
const result = await readPromise | ||
return result | ||
} else { | ||
const typeName = Object.prototype.toString.call(this.content) | ||
throw new Error(`Unexpected type ${typeName}`) | ||
} | ||
} catch (error) { | ||
console.error(error) | ||
const loadContentError = new Error(`Error loading content: ${error}`) | ||
console.error(loadContentError) | ||
throw loadContentError | ||
} | ||
} | ||
|
||
load(): Promise<Buffer | string> { | ||
if (this.loadedData === undefined) { | ||
this.loadedData = this.loadContent() | ||
} | ||
return this.loadedData | ||
} | ||
} |
Oops, something went wrong.