mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
Added radless leveldb adapter
This commit is contained in:
parent
05349a5c68
commit
84097d7e68
96
lib/level.js
Normal file
96
lib/level.js
Normal file
@ -0,0 +1,96 @@
|
||||
// CAUTION: This adapter does NOT handle encoding. an encoding mechanism like the encoding-down package will need to be included
|
||||
// Based on localStorage adapter in 05349a5
|
||||
|
||||
var Gun = ('undefined' !== typeof window) ? window.Gun : require('../gun');
|
||||
var debug = false;
|
||||
|
||||
Gun.on('opt', function(ctx) {
|
||||
var opt = ctx.opt;
|
||||
var ev = this.to;
|
||||
|
||||
if (debug) debug.emit('create');
|
||||
if (ctx.once) return ev.next(ctx);
|
||||
|
||||
// Check if the given 'level' argument implements all the components we need
|
||||
// Intentionally doesn't check for levelup explicitly, to allow different handlers implementing the same api
|
||||
if (
|
||||
(!opt.level) ||
|
||||
('object' !== typeof opt.level) ||
|
||||
('function' !== typeof opt.level.get) ||
|
||||
('function' !== typeof opt.level.put)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.on('put', function(msg) {
|
||||
this.to.next(msg);
|
||||
|
||||
// Extract data from message
|
||||
var put = msg.put;
|
||||
var soul = put['#'];
|
||||
var key = put['.'];
|
||||
var val = put[':'];
|
||||
var state = put['>'];
|
||||
|
||||
if (debug) debug.emit('put', soul, val);
|
||||
|
||||
// Fetch previous version
|
||||
opt.level.get(soul, function(err, data) {
|
||||
if (err && (err.name === 'NotFoundError')) err = undefined;
|
||||
if (debug && err) debug.emit('error', err);
|
||||
if (err) return;
|
||||
|
||||
// Unclear required transformation
|
||||
data = Gun.state.ify(data, key, state, val, soul);
|
||||
|
||||
// Write into storage
|
||||
opt.level.put(soul, data, function(err) {
|
||||
if (err) return;
|
||||
if (debug) debug.emit('put', soul, val);
|
||||
|
||||
// Bail if message was an ack
|
||||
if (msg['@']) return;
|
||||
|
||||
// Send ack back
|
||||
ctx.on('in', {
|
||||
'@' : msg['@'],
|
||||
ok : 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
ctx.on('get', function(msg) {
|
||||
this.to.next(msg);
|
||||
|
||||
// Extract soul from message
|
||||
var lex = msg.get;
|
||||
if (!lex || !(soul = lex['#'])) return;
|
||||
var has = lex['.'];
|
||||
|
||||
if (debug) debug.emit('get', soul);
|
||||
|
||||
// Fetch data from storage
|
||||
opt.level.get(soul, function(err, data) {
|
||||
if (err) return;
|
||||
|
||||
// Another unclear transformation
|
||||
if (data && has) {
|
||||
data = Gun.state.to(data, has);
|
||||
}
|
||||
|
||||
// Emulate incoming ack
|
||||
ctx.on('in', {
|
||||
'@' : msg['#'],
|
||||
put : Gun.graph.node(data),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Export debug interface
|
||||
if ('undefined' === typeof window) {
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
module.exports = debug = new EventEmitter();
|
||||
}
|
216
test/panic/level.js
Normal file
216
test/panic/level.js
Normal file
@ -0,0 +1,216 @@
|
||||
const panic = require('panic-server');
|
||||
const clients = panic.clients;
|
||||
const manager = require('panic-manager')();
|
||||
const opts = { radisk: false, localStorage: false, file: false };
|
||||
|
||||
require('events').EventEmitter.defaultMaxListeners = Infinity;
|
||||
|
||||
const config = {
|
||||
ip : require('ip').address(),
|
||||
port : 8765,
|
||||
servers : 3,
|
||||
route : {
|
||||
'/' : __dirname + '/index.html',
|
||||
'/gun.js' : __dirname + '/../../gun.js',
|
||||
'/jquery.js' : __dirname + '/../../examples/jquery.js'
|
||||
}
|
||||
};
|
||||
|
||||
const srv = panic.server();
|
||||
srv.on('request', (req, res) => {
|
||||
config.route[req.url] && require('fs').createReadStream(config.route[req.url]).pipe(res);
|
||||
}).listen(config.port);
|
||||
|
||||
manager.start({
|
||||
clients: Array(config.servers).fill().map((u,i) => ({
|
||||
type: 'node',
|
||||
port: config.port + i + 1,
|
||||
})),
|
||||
panic: `http://${config.ip}:${config.port}`
|
||||
});
|
||||
|
||||
const servers = clients.filter('Node.js');
|
||||
const server = servers.pluck(1);
|
||||
const alice = servers.excluding(server).pluck(1);
|
||||
const bob = servers.excluding(server).excluding(alice).pluck(1);
|
||||
|
||||
describe('Make sure the leveldb storage engine works', function() {
|
||||
this.timeout(5 * 60 * 60 * 1000);
|
||||
|
||||
it("servers have joined!", function() {
|
||||
return servers.atLeast(config.servers);
|
||||
});
|
||||
|
||||
it("GUN started!", function() {
|
||||
return server.run(function(test) {
|
||||
test.async();
|
||||
const {config,opts} = test.props;
|
||||
|
||||
const leveldown = require('leveldown');
|
||||
const encode = require('encoding-down');
|
||||
const levelup = require('levelup');
|
||||
|
||||
if (require('fs').existsSync('./lvldata')) {
|
||||
console.error('Please delete previous data first!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize leveldb
|
||||
// const level = global.level = levelup(leveldown('./lvldata'));
|
||||
const level = global.level = levelup(encode(leveldown('./lvldata'), { valueEncoding: 'json' }));
|
||||
|
||||
// Load the libraries under test
|
||||
const Gun = require('../../../index');
|
||||
const debug = require('../../../lib/level');
|
||||
|
||||
// // Add debug message
|
||||
// debug.on('create', () => console.log('LEVEL CREATE'));
|
||||
// debug.on('get' , key => console.log('LEVEL GET', key));
|
||||
// debug.on('put' , (key, value) => console.log('LEVEL PUT', key, value));
|
||||
// // debug.on('list', () => console.log('LEVEL LIST'));
|
||||
// debug.on('error' , err => console.log('LEVEL ERROR', err));
|
||||
|
||||
// Track state (so we can wait on put, it's called late by radisk)
|
||||
global.state = 0;
|
||||
debug.on('put', () => global.state++);
|
||||
|
||||
// Create server
|
||||
opts.web = require('http').createServer(function(req, res) {
|
||||
res.end("Number five is alive!");
|
||||
});
|
||||
|
||||
// Initialize gun & start server
|
||||
const gun = global.gun = Gun({ ...opts, level });
|
||||
opts.web.listen(config.port + 1, function() {
|
||||
test.done();
|
||||
});
|
||||
|
||||
}, {config,opts});
|
||||
});
|
||||
|
||||
it("Alice saves data", function() {
|
||||
return alice.run(function(test) {
|
||||
test.async();
|
||||
const {config,opts} = test.props;
|
||||
const Gun = require('../../../index');
|
||||
|
||||
// Start gun
|
||||
const gun = global.gun = Gun({
|
||||
...opts,
|
||||
peers: 'http://'+ config.ip + ':' + (config.port + 1) + '/gun',
|
||||
lack : 1000 * 60 * 60,
|
||||
});
|
||||
|
||||
// Save data
|
||||
// Timeout allows callbacks to fire before server read
|
||||
const ref = gun.get('asdf');
|
||||
ref.put({ hello: 'world' });
|
||||
setTimeout(() => {
|
||||
test.done();
|
||||
}, 1);
|
||||
}, {config,opts});
|
||||
});
|
||||
|
||||
it('Server read data', function() {
|
||||
return server.run(function(test) {
|
||||
test.async();
|
||||
|
||||
// Read data (triggers fetch from alice + write to disk)
|
||||
const ref = gun.get('asdf');
|
||||
ref.on(data => {
|
||||
if (data.hello !== 'world') {
|
||||
return test.fail('Invalid data returned');
|
||||
}
|
||||
ref.off();
|
||||
test.done();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
it('Wait for server to store', function() {
|
||||
return server.run(function(test) {
|
||||
test.async();
|
||||
setTimeout(function awaitState() {
|
||||
if (global.state < 2) return setTimeout(awaitState, 50);
|
||||
test.done();
|
||||
}, 50);
|
||||
});
|
||||
});
|
||||
|
||||
it('Close all original running nodes', function() {
|
||||
clients.pluck(2).run(function() {
|
||||
if (global.level) {
|
||||
global.level.close(function() {
|
||||
process.exit();
|
||||
});
|
||||
} else {
|
||||
process.exit();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('Start bob', function() {
|
||||
return bob.run(function(test) {
|
||||
test.async();
|
||||
const {config,opts} = test.props;
|
||||
|
||||
const leveldown = require('leveldown');
|
||||
const encode = require('encoding-down');
|
||||
const levelup = require('levelup');
|
||||
|
||||
// Initialize gun opts
|
||||
const level = global.level = levelup(encode(leveldown('./lvldata'), { valueEncoding: 'json' }));
|
||||
|
||||
// Load the libraries under test
|
||||
const Gun = require('../../../index');
|
||||
const debug = require('../../../lib/level');
|
||||
|
||||
// // Add debug messages
|
||||
// debug.on('get', key => console.log('LEVEL GET', key));
|
||||
// debug.on('put', (key, value) => console.log('LEVEL PUT', key, value));
|
||||
// // debug.on('list', () => console.log('LEVEL LIST'));
|
||||
// debug.on('error', err => console.log('LEVEL ERROR', err));
|
||||
|
||||
// Create server
|
||||
opts.web = require('http').createServer((req, res) => {
|
||||
res.end("Number five is alive!");
|
||||
});
|
||||
|
||||
// Initialize gun & start server
|
||||
const gun = global.gun = Gun({ ...opts, level });
|
||||
opts.web.listen(config.port + 1, () => {
|
||||
test.done();
|
||||
});
|
||||
}, {config,opts});
|
||||
});
|
||||
|
||||
it('Bob read', function() {
|
||||
return bob.run(function(test) {
|
||||
test.async();
|
||||
|
||||
// Read data
|
||||
const ref = gun.get('asdf');
|
||||
ref.on(data => {
|
||||
if (data.hello !== 'world') {
|
||||
return test.fail('Invalid data returned');
|
||||
}
|
||||
ref.off();
|
||||
test.done();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
it('Shutdown bob', function() {
|
||||
return clients.run(function() {
|
||||
process.exit()
|
||||
});
|
||||
});
|
||||
|
||||
it("All finished!", function(done) {
|
||||
srv.close();
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user