Skip to content

Commit

Permalink
update everything
Browse files Browse the repository at this point in the history
  • Loading branch information
dominictarr committed May 30, 2013
1 parent 1d03d80 commit 0515c72
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 88 deletions.
59 changes: 37 additions & 22 deletions db.js
@@ -1,8 +1,10 @@
var levelup = require('levelup')
var levelup = require('level')
var config = require('./config')
var securify = require('securify')
var bundle = require('securify/bundle')
var path = require('path')
var EventEmitter
= require('events').EventEmitter

// (update closing update* closed updated)*
// update can be a new bundle, or stop.
Expand All @@ -13,45 +15,58 @@ var path = require('path')
// make a simple app, and update it.
module.exports =
function Db(id) {
var db = levelup(path.join(config.root, id))
var db, _cb
var state = 'ready'
var bundle, current

var domain

function start () {
var emitter = new EventEmitter()

function close (cb) {
var n = 1

db.on('closed', function () {
if(--n) return
domain.dispose()
cb()
})

db.on('error', function (err) {
if(--n) return
domain.dispose()
cb(err)
})

db.close()
}

function start (bundle, cb) {
//EVENT: updated
state = 'running'
current = bundle
db = levelup(path.join(config.root, id))
domain = securify(bundle)(db)
emitter.db = db
emitter.domain = domain
cb(null, db, domain)
}

db.on('closed', function () {
//EVENT: closed
//was closing the database...
domain && domain.dispose()
if(bundle == current) {
//EVENT: stopped
return
}
start()
})

db.update = function (_bundle) {
//update wasn't a change, do nothing...
if(current == _bundle) return
emitter.update = function (_bundle, cb) {

//EVENT: update
bundle = _bundle
if(state == 'ready') {
start()
start(_bundle, cb)
}
else if (state == 'running') {
//EVENT: closing
state = 'closing'
db.close()
close(function (err) {
if(err) return cb(err)
state = 'ready'
start(bundle, cb)
})
}
}

return db
return emitter
}
22 changes: 2 additions & 20 deletions master-db.js
@@ -1,5 +1,5 @@

var levelup = require('levelup')
var levelup = require('level')
var sublevel = require('level-sublevel')
var config = require('./config')
var securify = require('securify')
Expand All @@ -9,22 +9,4 @@ var DB = require('./db')
var db = sublevel(levelup(config.path))
var dbs = {}

db.sublevel('bundles').post(function (op) {
// either start the server, or destroy the current server,
// and then create a new server...
//
// when a bundle is pushed, destroy the current server,
// and start a new one...
//
// this will close the current database,
// and cleanup the domain it runs in.
//
// so, the user can decide whether they want to cleanup
// or just crash - but I recommend having a crashable design.

var db = dbs[op.key] || dbs[op.key] = DB(op.key)
// Turn op.value into a function...
db.update(op.value)
})


module.exports = db
146 changes: 100 additions & 46 deletions server.js
@@ -1,72 +1,126 @@

var http = require('http')
var shoe = require('shoe')

var levelup = require('levelup')
var sublevel = require('level-sublevel')
//fix this
var levelup = require('level')
var sublevel = require('level-sublevel')
var master = sublevel(levelup('/tmp/tacodb'))
var static = require('level-static')
var sublevel = require('level-sublevel')

var master = require('./master-db')
var stack = require('stack')

var stack = requrie('stack')

var prefix = '/db/(\\w+)'
var rx = new RegExp('^'+prefix)
var prefix = '/ws/([\\w-\\d]+)'
var rxWs = new RegExp('^'+prefix)
var rxHttp = /^\/http\/([\w-\d]+)/

var dbs = {}
var servers = {}

function prefix(url, handler) {
var createDb = require('./db')

function applyPrefix(url, handler) {
return function (req, res, next) {
if(url !== req.url.substring(0, url.length))
return next()
req.url = substring(url.length)
req.url = req.url.substring(url.length)
handler(req, res, next)
}
}

function getId(string) {
function getId(rx, string) {
var id
var m = rx.exec(stream.pathname)
if(m) id m[1]
return id && servers[id] ? id : null
var m = rx.exec(string)
if(m) id = m[1]
return id && dbs[id] ? id : null
}

shoe(function (stream) {
var id = getId(stream.pathname)
if(!id || !servers[id].listeners('connection').length) {
//abort this stream
stream.end()
} else {
//connect to the db...
servers[id].emit('connection', stream)
var bundles = master.sublevel('bundles')

var wrapped = {
put: function (key, value, cb) {
master.put(key, value, function (err) {
if(err) return cb(err)
var db = dbs[key] = dbs[key] || createDb(key)
db.update(value, function (err) {
cb(err)
})
})
},
del: function (key, cb) {
master.del(key, function (err) {
if(err) return cb(err)
var db = dbs[key]
//this should error as above, but anyway...
if(!db) return cb(new Error('db does not exist'))
db.once('closed', cb)
db.close()
})
},
get: function (key, cb) {
master.get(key, cb)
}
}).install(
http.createServer(stack(
//if POST /master/USER
// update this database.
// ... hmm, this is a value.
// when the value updates,
// update server.
//... but we need an up and a down update...
//which will be async...
prefix('/db', static(master.sublevel('bundles'))), //add auth!
function (req, res, next) {
var id = getId(stream.url)
if(!id || !servers[id].listeners('http_connection').length) //404
return next(new Error('no handler'))
servers[id].emit('http_connection', req, res)
},
function (error, req, res, next) {
res.writeHead(error.status || 404)
res.end(JSON.stringify({
error: true,
message: err.message,
code: err.code
}, null, 2)
}

function log(req, res, next) {
console.error(
req.method, req.url, Date.now()
)
next()
}

module.exports = function (config, cb) {
var server
shoe(function (stream) {
var id = getId(rxWs, stream.pathname)
if(!id || !dbs[id].db.listeners('connection').length) {
//abort this stream
stream.end()
} else {
//connect to the db...
dbs[id].db.emit('connection', stream)
}
)).listen(config.port)
), prefix)
}).install(
server = http.createServer(stack(
//if POST /master/USER
// update this database.
// ... hmm, this is a value.
// when the value updates,
// update server.
//... but we need an up and a down update...
//which will be async...
log,
applyPrefix('/data', static(wrapped)), //TODO: add auth!
function (req, res, next) {
var id = getId(rxHttp, req.url)
console.log('MATCH?', rxHttp, req.url, id)
if(!id)
return next(new Error('no service at '+req.url))

if(!dbs[id].db.listeners('http_connection').length) //404
return next(new Error('no handler for "http_connection"'))
dbs[id].db.emit('http_connection', req, res)
},
function (error, req, res, next) {
res.writeHead(error.status || 404)
res.end(JSON.stringify({
error: true,
message: err.message,
code: err.code
}, null, 2))
}
)).listen(config.port, function () {
if(cb) cb(null, server)
})
, prefix)

return server
}

if(!module.parent) {
var config = require('./config')
module.exports(config, function (_, server) {
console.log('listening on', config.port)
})
}

0 comments on commit 0515c72

Please sign in to comment.