Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

add localStorage based implementation for client

  • Loading branch information...
commit be0714e5e144df2525567121d7cdf1e54a99743a 1 parent 9496653
@dominictarr authored
Showing with 191 additions and 139 deletions.
  1. +0 −24 -
  2. +5 −0 client.js
  3. +57 −0 endpoints-client.js
  4. +7 −2 endpoints.js
  5. +3 −113 index.js
  6. +119 −0 kv.js
View
24 -
@@ -1,24 +0,0 @@
-# kv-stream
-
-super simple key-value store, intended for keeping appendable files.
-
-keeps the files in prefixed subdirectories, so that the directories do not get too large.
-
-(see ls .git/objects/\* for a similar example)
-
-## examples
-
-###create an instance
-
-```
-var kv = require('kv')('/tmp/kv')
-
-```
-### put a stream
-
-`opts` is optional. see [http://nodejs.org/api/fs.html#fs_fs_createreadstream_path_options ](fs.createWriteStream)
-
-``` js
- stream.pipe(kv.put(key, opts)) //opts
-
-```
View
5 client.js
@@ -0,0 +1,5 @@
+
+var ends = require('./endpoints-client')
+var kv = require('./kv')
+
+module.exports = kv(ends)
View
57 endpoints-client.js
@@ -0,0 +1,57 @@
+var es = require('event-stream')
+
+module.exports = function (prefix, exports) {
+
+ exports = exports || {}
+
+ //put, get, del, has
+
+ exports.put = function (key, opts) {
+ var _key = prefix+':'+key
+ opts = opts || {flags: 'w'}
+ if(opts.flags == 'w')
+ localStorage[_key] = ''
+ //else assume append.
+
+ var ws = es.through(function (data) {
+ localStorage[_key] += JSON.stringify(data) + '\n'
+ })
+
+ //remove readable api.
+ ws.readable = false
+ delete ws.pause
+ delete ws.resume
+
+ return ws
+ }
+
+ exports.get = function (key, opts) {
+ var _key = prefix+':'+key
+ var array = localStorage[_key].split('\n')
+ if(!array[array.length - 1])
+ array.pop() //expecting an empty '' at the end.
+ return es.readArray(array)
+ }
+
+ exports.del = function (key, cb) {
+ var _key = prefix+':'+key
+ process.nextTick(function () {
+ if(!localStorage[_key])
+ return cb(new Error ('no record: ' + key))
+
+ delete localStorage[prefix+':'+key]
+ cb()
+ })
+ }
+
+ exports.has = function (key, cb) {
+ var _key = prefix+':'+key
+ process.nextTick(function () {
+ if(!localStorage[_key])
+ return cb(new Error ('no record: ' + key))
+ cb()
+ })
+ }
+
+ return exports
+}
View
9 endpoints.js
@@ -22,11 +22,16 @@ module.exports = function (basedir, exports) {
var _key = hash(key)
var dir = _key.substring(0, 2)
var file = key
- var stream = es.gate(true)
+ var stream = es.gate(true), inner
mkdirP(join(basedir, dir), function (err) {
if(err)
return stream.emit('error', err)
- stream.pipe(fs.createWriteStream(join(basedir, dir, file), opts))
+ stream.pipe(
+ fs.createWriteStream(join(basedir, dir, file), opts)
+ .on('close', function () {
+ stream.emit('close')
+ })
+ )
stream.open()
})
return stream
View
116 index.js
@@ -1,115 +1,5 @@
-/*
- very simple kv store setup for to be able to append to each document.
- each value is stored in a separate file,
- put, get, return streams
-*/
-var es = require('event-stream')
-var EventEmitter = require('events').EventEmitter
-
-module.exports = kv
-
-var formats = {
- raw: function (stream) {
- return stream
- },
- json: function (stream, key) {
- /*
- if anyone ever wants to use this for something other than
- new line seperated json, this will need to be modified.
- because the __list record will still be a stream of arrays.
-
- either handle it differently, by it's key,
- or make it possible to by-pass the streamer, or add a header or something.
- hmm. or a way to force it to write a raw stream.
-
- or maybe just have a separate set of records for headers?
- or the first line?
-
- I know:
-
- you go: get[format](key) //and can add more formats. json, raw, etc.
- */
- var s
- if(stream.writable) {
- s = es.stringify()
- s.pipe(stream)
- } else
- s = stream.pipe(es.split()).pipe(es.parse())
- return s
- }
-}
-
-function mkFormat(fn, format) {
- return function () {
- return format(fn.apply(this, arguments))
- }
-}
-
-function addFormats(fn) {
- var f = mkFormat(fn, formats.json)
- for(k in formats)
- f[k] = mkFormat(fn, formats[k])
- return f
-}
-
-function kv (basedir) {
- //by default, use newline seperated json.
- var emitter = new EventEmitter()
- var ends = require('./endpoints')(basedir)
- var keys = {}
-
- function list() {
- var _keys = []
- for (var k in keys)
- _keys.push(k)
- return _keys
- }
-
- function addToKeys (data) {
- if(data[0] = 'put')
- keys[data[1]] = true
- else
- delete keys[data[1]]
- }
- //wrap formats arount get and put, so you can go get.json(key) or get.raw(key)
-
- emitter.put = addFormats(function (key, opts) {
- var s = ends.put(key, opts)
- emitter.emit('put', key, Date.now(), s, opts)
- return s
- })
- emitter.get = addFormats(ends.get)
- emitter.del = function (key, cb) {
- emitter.emit('del', key, Date.now())
- ends.del(key, cb)
- }
- emitter.has = ends.has
- emitter.list = list
-
- //TODO smarter way to compact the __list, so that can have last update.
- var ls = emitter.put.json('__list', {flags: 'a'})
- emitter
- .on('put', function (key, time) {
- if(!keys[key])
- ls.write(['put', key, time])
- })
- .on('del', function (key, time) {
- if(keys[key])
- ls.write(['del', key, time])
- })
- .on('put', addToKeys)
- .on('del', addToKeys)
-
- emitter.has('__list', function (err) {
- if(err)
- emitter.emit('sync')
- else
- emitter.get.json('__list').on('data', addToKeys).on('end', function () {
- emitter.emit('sync')
- })
- })
-
- return emitter
-}
+var ends = require('./endpoints')
+var kv = require('./kv')
+module.exports = kv(ends)
View
119 kv.js
@@ -0,0 +1,119 @@
+/*
+ very simple kv store setup for to be able to append to each document.
+ each value is stored in a separate file,
+ put, get, return streams
+*/
+
+var es = require('event-stream')
+var EventEmitter = require('events').EventEmitter
+
+var formats = {
+ raw: function (stream) {
+ return stream
+ },
+ json: function (stream, key) {
+ /*
+ if anyone ever wants to use this for something other than
+ new line seperated json, this will need to be modified.
+ because the __list record will still be a stream of arrays.
+
+ either handle it differently, by it's key,
+ or make it possible to by-pass the streamer, or add a header or something.
+ hmm. or a way to force it to write a raw stream.
+
+ or maybe just have a separate set of records for headers?
+ or the first line?
+
+ I know:
+
+ you go: get[format](key) //and can add more formats. json, raw, etc.
+ */
+ var s
+ stream.once('close', function () {
+ s.emit('close')
+ })
+ if(stream.writable) {
+ s = es.stringify()
+ s.pipe(stream)
+ } else
+ s = stream.pipe(es.split()).pipe(es.parse())
+ return s
+ }
+}
+
+function mkFormat(fn, format) {
+ return function () {
+ return format(fn.apply(this, arguments))
+ }
+}
+
+function addFormats(fn) {
+ var f = mkFormat(fn, formats.json)
+ for(k in formats)
+ f[k] = mkFormat(fn, formats[k])
+ return f
+}
+
+module.exports = function (endpoints) {
+
+ return function kv (basedir) {
+ //by default, use newline seperated json.
+ var emitter = new EventEmitter()
+ var keys = {}
+ var ends = endpoints(basedir)
+
+ function list() {
+ var _keys = []
+ for (var k in keys)
+ _keys.push(k)
+ return _keys
+ }
+
+ function addToKeys (data) {
+ if(data[0] = 'put')
+ keys[data[1]] = true
+ else
+ delete keys[data[1]]
+ }
+ //wrap formats arount get and put, so you can go get.json(key) or get.raw(key)
+
+ emitter.put = addFormats(function (key, opts) {
+ var s = ends.put(key, opts)
+ emitter.emit('put', key, Date.now(), s, opts)
+ return s
+ })
+ emitter.get = addFormats(ends.get)
+ emitter.del = function (key, cb) {
+ emitter.emit('del', key, Date.now())
+ ends.del(key, cb)
+ }
+ emitter.has = ends.has
+ emitter.list = list
+
+ //TODO smarter way to compact the __list, so that can have last update.
+ var ls = emitter.put.json('__list', {flags: 'a'})
+ emitter
+ .on('put', function (key, time) {
+ if(!keys[key])
+ ls.write(['put', key, time])
+ })
+ .on('del', function (key, time) {
+ if(keys[key])
+ ls.write(['del', key, time])
+ })
+ .on('put', addToKeys)
+ .on('del', addToKeys)
+
+ emitter.has('__list', function (err) {
+ if(err)
+ emitter.emit('sync')
+ else
+ emitter.get.json('__list').on('data', addToKeys).on('end', function () {
+ emitter.emit('sync')
+ })
+ })
+
+ return emitter
+ }
+}
+
Please sign in to comment.
Something went wrong with that request. Please try again.