Skip to content
This repository has been archived by the owner on Jul 17, 2018. It is now read-only.

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
tbaum committed Jul 30, 2011
0 parents commit ceedb94
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 0 deletions.
69 changes: 69 additions & 0 deletions application.coffee
@@ -0,0 +1,69 @@

# $ requires npm install connect into
# require.paths [ '$HOME/.node_modules', '$HOME/.node_libraries', '/usr/lib/node' ]

fs = require 'fs'
connect = require 'connect'

process.on 'uncaughtException', (err) ->
console.log "Type: " + err.type
console.log "Message: " + err.message
console.log "Arguments: " + err.arguments
console.log err.stack

neo4jconfig = require "./neo4jconfig.coffee"
neo4jserver = require "./neo4jserver.coffee"
proxy = require "./proxy.coffee"

class ServerManager
constructor: ->
proxies = {}
auth = { user: "admin", pass: "admin"}

bringUp = (id) ->
config = neo4jconfig.parse id
neo4j = neo4jserver.create config
proxies[id] = proxy.buildFor neo4j, config

storeConfig = ->
config =
auth : auth
proxies: (key for key of proxies)
fs.writeFileSync "config.json", JSON.stringify(config)

@loadConfig = ->
try
config = JSON.parse(fs.readFileSync "config.json")
auth = config['auth']
for i in config['proxies']
try bringUp i catch e
console.log "error during startup for "+ i + " " + e
catch error
console.log error

@start = ->
connect(
connect.basicAuth (user, pass) -> auth.user == user && auth.pass == pass
connect.router (app) ->
app.get '/', (request, response) -> response.end JSON.stringify(key for key of proxies)

app.post '/:id', (request, response) ->
id = request.params.id
if (proxies[id]) then throw new Error "instance " + id + " is already registered"
bringUp id
storeConfig()
response.end "add "+request.params.id

app.delete '/:id', (request, response) ->
id = request.params.id
if (!proxies[id]) then throw new Error "instance " + id + " is not registered"
proxies[id].stop()
delete proxies[id]
storeConfig()
response.end "delete "+request.params.id

).listen(7999)

serverManager = new ServerManager()
serverManager.loadConfig()
serverManager.start()
22 changes: 22 additions & 0 deletions iptables.coffee
@@ -0,0 +1,22 @@

exec = require("child_process").exec

class IptablesRule
constructor: (rule) ->
isPresent = (condition, callback) ->
exec "iptables -tnat -S PREROUTING", (x, o) ->
if ( (o.indexOf(rule) != -1) == condition) then callback()

@addRule = ->
isPresent false, ->
exec "iptables -tnat -A PREROUTING " + rule

@removeRule = ->
isPresent true, ->
exec "iptables -tnat -D PREROUTING " + rule


exports.rule = (rule) -> new IptablesRule rule

exports.redirectRule = (port, proxyPort) ->
new IptablesRule "-i eth0 -p tcp -m tcp --dport " + port + " -j REDIRECT --to-ports " + proxyPort
16 changes: 16 additions & 0 deletions neo4jconfig.coffee
@@ -0,0 +1,16 @@
fs = require 'fs'

class Neo4JConfiguration
constructor: (@instance) ->
home = "/mnt/" + @instance
configData = fs.readFileSync home + "/conf/neo4j-server.properties", "UTF-8"
console.log "parse config for " + @instance

@port = Number /org.neo4j.server.webserver.port=(.+)/.exec(configData)[1]
@adminCredentials = /org.neo4j.server.credentials=(.+)/.exec(configData)[1]
@proxyPort = this.port + 1000
@startCmd = home + "/bin/neo4j start"
@statusCmd = home + "/bin/neo4j status"
@stopCmd = home + "/bin/neo4j stop"

exports.parse = (instance) -> new Neo4JConfiguration instance
100 changes: 100 additions & 0 deletions neo4jserver.coffee
@@ -0,0 +1,100 @@
http = require "http"
iptables = require "./iptables.coffee"

exec_org = require('child_process').exec

exec = (log, cmd, callback) ->
log "exec:"+cmd
exec_org cmd, (exit, out, err)->
if (exit) then log "exit-code: "+exit
if (out) then log " > " + line for line in out.split "\n"
if (err) then log "E> " + line for line in err.split "\n"
if (callback) then callback exit, out, err


class Neo4JServer
constructor: (@config) ->
iptRule = iptables.redirectRule config.port, config.proxyPort
running = false
starting = false
config = @config

log = (message) -> console.log config.instance + " " + message

setRunning = (r) ->
running = r
if (running)
log "remove firewall rule"
iptRule.removeRule()
else
log "add firewall rule"
iptRule.addRule()

updateStatus = @updateStatus = ->
exec log, config.statusCmd, (error, stdout) ->
setRunning(stdout.indexOf("not running") == -1)
checkIdle()

checkIdle = @checkIdle = ->
if (running)
request = http.request
port: config.port, method: 'GET', path: '/admin/statistic/', host: '127.0.0.1',
headers:
Host:'localhost', Accept:"application/json"
Authorization: 'Basic ' + new Buffer(config.adminCredentials).toString('base64'),
(response)->
now = new Date().getTime() / 1000
response.setEncoding 'utf8'
data = ""
response.on 'data', (chunk) -> data += chunk
response.on 'end', ->
requestCount = 0
period = 0
for i in JSON.parse(data)
if (i['timeStamp'] > (now - 7200))
requestCount += i['requests']
period += i['period']

log "request-count for "+ config.port + " == " + requestCount + "/" + period

request.on 'error', (e) ->
log "problem with request: " + e.message
setRunning false

request.end "\n"

startServer = @startServer = ->
log "try to start server"
if (starting || running)
log "is running(=" + running + ") or starting(=" + starting + ")"
return

starting = true
log "starting"
exec log, config.startCmd, (error, stdout, stderr) ->
starting = false
if (error == null) then setRunning true
else if (stdout.indexOf("already running with pid") != -1) then updateStatus()

@stopServer = ->
log "try to stop server"
if (!running && !starting)
log "not running(=" + running + ") or starting(=" + starting + ")"
return

starting = true
log "stopping"
exec log, config.stopCmd, (error, stdout, stderr) ->
starting = false
setRunning false

waitForServer = @waitForServer = (msg, callback) ->
if (running)
callback()
else
log "wait " + msg
if (!starting) then startServer()
setTimeout waitForServer, 2000, msg, callback


exports.create = (config) -> new Neo4JServer(config)
32 changes: 32 additions & 0 deletions proxy.coffee
@@ -0,0 +1,32 @@

net = require 'net'

class Proxy
constructor: (neo4j, config) ->
log = (message) -> console.log config.instance + " " + message

server = net.createServer (proxySocket) ->
info = proxySocket.remoteAddress + ":" + proxySocket.remotePort
log "handle connection " + info

serverSocket = new net.Socket()
proxySocket.on "data", (data) -> neo4j.waitForServer ">" + info, -> serverSocket.write data
proxySocket.on "close", -> neo4j.waitForServer ">" + info, -> serverSocket.end()

neo4j.waitForServer "<" + info, ->
serverSocket.connect config.port, "127.0.0.1"
serverSocket.on "data", (data) -> proxySocket.write data
serverSocket.on "close", (had_error) -> proxySocket.end()

log "start " + config.proxyPort + " -> " + config.port
list = server.listen config.proxyPort

updater = setInterval neo4j.checkIdle, 30000
neo4j.updateStatus()

@stop = ->
clearInterval updater
neo4j.startServer()
server.close()

exports.buildFor = (neo4j, config) -> new Proxy neo4j, config

0 comments on commit ceedb94

Please sign in to comment.