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
0 parents
commit 37f76d4
Showing
19 changed files
with
821 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,6 @@ | ||
{ | ||
"presets": ["es2015-node6/object-rest"], | ||
"plugins": [ | ||
"transform-object-rest-spread" | ||
] | ||
} |
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,3 @@ | ||
{ | ||
"extends": "blockai" | ||
} |
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,40 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (http://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directory | ||
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git | ||
node_modules | ||
|
||
# Environment variable files | ||
.envrc | ||
.env | ||
|
||
# Temporary / data folders | ||
.tmp | ||
data/ | ||
|
||
# Build directory | ||
lib/ | ||
|
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,41 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (http://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Environment variable files | ||
.envrc | ||
.env | ||
|
||
# Temporary / data folders | ||
.tmp | ||
data/ | ||
|
||
# Source directory | ||
src/ | ||
|
||
# Test directory | ||
test/ | ||
|
||
.eslintrc | ||
.babelrc |
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,6 @@ | ||
sudo: false | ||
language: node_js | ||
notifications: | ||
email: false | ||
node_js: | ||
- 6 |
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,20 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2016 Olivier Lalonde <olalonde@gmail.com> | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
this software and associated documentation files (the "Software"), to deal in | ||
the Software without restriction, including without limitation the rights to | ||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
the Software, and to permit persons to whom the Software is furnished to do so, | ||
subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
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,187 @@ | ||
# cloud-cache | ||
|
||
[![Build Status](https://travis-ci.org/blockai/cloud-cache.svg?branch=master)](https://travis-ci.org/blockai/cloud-cache) | ||
|
||
Node.js caching library with pluggable backing store via | ||
[abstract-blob-store](https://github.com/maxogden/abstract-blob-store). | ||
|
||
[Streaming support](#streaming-api) makes it particularly useful for caching larger values | ||
like resized/cropped images or transcoded videos. | ||
|
||
Supported backing stores: | ||
|
||
- AWS S3 | ||
- Google Cloud Storage | ||
- Azure Storage | ||
- LevelDB | ||
- PostgreSQL | ||
- Local file system | ||
- IPFS | ||
- etc. | ||
|
||
Supports Node.js buffers or any JavaScript value that can be serialised through | ||
`JSON.stringify`: | ||
|
||
- Buffer | ||
- Number | ||
- String | ||
- Boolean | ||
- Array | ||
- Object | ||
|
||
## Install | ||
|
||
```bash | ||
npm install --save cloud-cache | ||
``` | ||
|
||
Requires Node v6+ | ||
|
||
## Usage | ||
|
||
See [./test](./test) directory for usage examples. | ||
|
||
### Setting up the client | ||
|
||
```javascript | ||
import cloudCache from 'cloud-cache' | ||
const cache = cloudCache(blobStore [, opts]) | ||
``` | ||
|
||
* `blobStore`: **blobStore** [abstract-blob-store](https://www.npmjs.com/package/abstract-blob-store) instance | ||
* `opts.keyPrefix`: **String** `cloudcache/` global key prefix that will be automatically prepended to all keys | ||
|
||
### Promise API | ||
|
||
All methods return [promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). | ||
|
||
**cache.get(key)** Get a key. | ||
|
||
* `key`: **String** the key to get | ||
|
||
Throws a `KeyNotExistsError` error if the key doesn't exist or value has | ||
expired. | ||
|
||
```javascript | ||
cache.get('key') | ||
``` | ||
|
||
**cache.set(key, value [, opts])** Stores a new value in the cache. | ||
|
||
* `key`: **String** the key to set | ||
* `value`: **Mixed** Buffer or any JSON compatible value. | ||
* `opts.ttl`: **Number**, `Infinity` how long the data needs to be stored measured in `seconds` | ||
|
||
```javascript | ||
cache.set('foo', 'bar', { ttl: 60 * 60 }) | ||
``` | ||
|
||
**cache.del(key)** Delete a key. | ||
|
||
* `key`: **String** the key to delete | ||
|
||
```javascript | ||
cache.del('key') | ||
``` | ||
|
||
**cache.getOrSet(key, getValueFn [, opts])** Returns cached value, storing and returning value on cache misses. | ||
|
||
* `key`: **String** the key to get | ||
* `getValueFn`: **Function** function to evaluate on cache misses | ||
* `opts`: **Object** same as `cache.set` | ||
* `opts.refresh`: **Boolean** `false` forces a cache miss | ||
|
||
The arguments are the same as **cache.set**, except that `value` must be | ||
a **function** or a **promise returning function** that evaluates / resolves | ||
to a valid **cache.set** value. The function will only be evaluated on cache misses. | ||
|
||
```javascript | ||
cache.getOrSet('google.com', () => ( | ||
fetch('http://google.com/').then(body => body.text()) | ||
)) | ||
``` | ||
|
||
### Streaming API | ||
|
||
**cache.getStream(key)** | ||
|
||
* `key`: **String** the key to read | ||
|
||
Returns a Readable Stream. | ||
|
||
Emits a `KeyNotExistsError` error if the key doesn't exist or value has | ||
expired. | ||
|
||
Alias: `cache.gets(key)` | ||
|
||
```javascript | ||
cache.getStream('olalonde/avatar.png').pipe(req) | ||
``` | ||
|
||
**cache.setStream(key [, opts])** | ||
|
||
* `key`: **String** the key to set | ||
* `opts`: **Object** same as `cache.set` | ||
|
||
Returns a Writable Stream. | ||
|
||
Alias: `cache.sets(key)` | ||
|
||
```javascript | ||
resizeImage('/tmp/avatar.png').pipe(cache.setStream('olalonde/avatar.png')) | ||
``` | ||
|
||
**cache.getOrSetStream(key, getStreamFn [, opts])** | ||
|
||
* `key`: **String** the key to get | ||
* `getStreamFn`: **Function** Read Stream returning function that will | ||
be called on cache misses. | ||
* `opts`: **Object** same as `cache.getOrSet` | ||
|
||
Returns a Readable Stream. | ||
|
||
*Important*: the stream returned by `getStreamFn` will not be cached | ||
unless the Readable Stream returned by `cache.getOrSetStream` is fully | ||
consumed. This can be done by piping or attaching an `.on('data', fn)` | ||
event handler. | ||
|
||
```javascript | ||
cache.getOrSetStream('olalonde/avatar.png', () => resizeImage('/tmp/avatar.png')).pipe(req) | ||
``` | ||
|
||
#### Stream Error Handling | ||
|
||
The streams returned by cache may emit `error` events. We recommend | ||
using [pipe() from the mississippi module](https://github.com/maxogden/mississippi#pipe) | ||
to avoid unhandled errors and make sure the cache stream closes properly | ||
if the destination has an error. | ||
|
||
e.g.: | ||
|
||
```javascript | ||
import { pipe } from 'mississippi' | ||
// ... | ||
pipe(cache.getOrSetStream('key', getReadStream), req, (err) => { | ||
if (err) return next(err) | ||
}) | ||
``` | ||
|
||
### Errors | ||
|
||
- `CloudCacheError` this base class is inherited by the errors below | ||
- `KeyNotExistsError` thrown/emitted when trying to get a non existent / expired key. Exposes a `key` property | ||
|
||
The error classes can be accessed through import or as a property on the cache object, | ||
e.g.: | ||
|
||
```javascript | ||
import { CloudCacheError, KeyNotExistsError } from 'cloud-cache' | ||
// ... | ||
cache.CloudCacheError === CloudCacheError // true | ||
cache.KeyNotExistsError === KeyNotExistsError // true | ||
KeyNotExistsError instanceof CloudCacheError // true | ||
``` | ||
|
||
## TODO | ||
|
||
- Detect/correct partial writes? |
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,66 @@ | ||
{ | ||
"name": "cloud-cache", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "./lib/index.js", | ||
"directories": { | ||
"test": "test" | ||
}, | ||
"scripts": { | ||
"test": "npm run test:fast", | ||
"build": "npm run clean && babel ./src --out-dir ./lib --copy-files", | ||
"clean": "rimraf ./lib", | ||
"lint": "eslint src/ test/", | ||
"pretest": "npm run lint", | ||
"test:fast": "babel-tape-runner test/*.test.js", | ||
"test:watch": "nodemon --exec npm -- run --silent test:fast || true", | ||
"semantic-release": "git push && npm test && semantic-release pre && npm run build && npm publish && semantic-release post" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/blockai/cloud-cache.git" | ||
}, | ||
"keywords": [], | ||
"author": "Oli Lalonde <olalonde@gmail.com> (https://syskall.com)", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/blockai/cloud-cache/issues" | ||
}, | ||
"homepage": "https://github.com/blockai/cloud-cache#readme", | ||
"engines": { | ||
"node": ">=6" | ||
}, | ||
"devDependencies": { | ||
"babel-cli": "^6.14.0", | ||
"babel-plugin-syntax-object-rest-spread": "^6.13.0", | ||
"babel-plugin-transform-object-rest-spread": "^6.8.0", | ||
"babel-preset-es2015-node6": "^0.3.0", | ||
"babel-tape-runner": "^2.0.1", | ||
"blue-tape": "^0.2.0", | ||
"cz-conventional-changelog": "^1.2.0", | ||
"eslint-config-blockai": "^1.0.1", | ||
"fs-blob-store": "^5.2.1", | ||
"nodemon": "^1.10.2", | ||
"randomstring": "^1.1.5", | ||
"request": "^2.74.0", | ||
"rimraf": "^2.5.4", | ||
"semantic-release": "^4.3.5" | ||
}, | ||
"release": { | ||
"debug": false, | ||
"verifyConditions": { | ||
"path": "./node_modules/semantic-release/dist/lib/plugin-noop.js" | ||
} | ||
}, | ||
"config": { | ||
"commitizen": { | ||
"path": "cz-conventional-changelog" | ||
} | ||
}, | ||
"dependencies": { | ||
"concat-stream": "^1.5.2", | ||
"debug": "^2.2.0", | ||
"duplexify": "^3.4.5", | ||
"is-stream": "^1.1.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,15 @@ | ||
export class CloudCacheError extends Error { | ||
constructor(msg) { | ||
super(msg) | ||
this.name = 'CloudCacheError' | ||
} | ||
} | ||
|
||
export class KeyNotExistsError extends CloudCacheError { | ||
constructor(key) { | ||
super(`Key ${key} does not exist`) | ||
this.name = 'KeyNotExistsError' | ||
this.key = key | ||
} | ||
} | ||
|
Oops, something went wrong.