Permalink
Browse files

rewrote axle to use coupler

  • Loading branch information...
1 parent f876977 commit 5f8f6d81e6dd024b4c1e5d9fd8cda80c4b1baca9 @mattinsler committed Jan 8, 2013
Showing with 128 additions and 165 deletions.
  1. +42 −38 index.coffee
  2. +31 −16 lib/{axle_server.coffee → axle.coffee}
  3. +0 −57 lib/axle_client.coffee
  4. +36 −0 lib/client.coffee
  5. +0 −24 lib/net_client.coffee
  6. +0 −28 lib/net_server.coffee
  7. +16 −0 lib/service.coffee
  8. +3 −2 package.json
View
@@ -1,42 +1,46 @@
+exports.Axle = require './lib/axle'
+exports.Client = require './lib/client'
+exports.Service = require './lib/service'
-
+exports.start_server = ->
+ require 'colors'
+ coupler = require 'coupler'
+
+ log = -> console.log '[' + 'axle'.cyan + '] ' + arguments[0]
+
+ axle = new exports.Axle(process.env.PORT || 3000)
+ coupler.accept(tcp: 1313).provide(axle: (connection) -> new exports.Service(axle, connection))
+
+ axle.on 'listening', (address) -> log 'Listening on port ' + address.port.toString().green
+ axle.on 'route:add', (route) -> log 'Added'.green + ' route ' + route.host + ' => ' + route.endpoint
+ axle.on 'route:remove', (route) -> log 'Removed'.red + ' route ' + route.host + ' => ' + route.endpoint
+ axle.on 'route:match', (from, to) -> log 'Routing ' + from.yellow + ' to ' + "#{to.host}:#{to.port}".green
+ axle.on 'route:miss', (host) -> log 'No route for ' + host.red
+
+ axle.start()
+
exports.start_client = ->
- domains = []
+ require 'colors'
+ coupler = require 'coupler'
+
+ log = -> console.log '[' + 'axle'.cyan + '] ' + arguments[0]
+
if process.env.AXLE_DOMAINS?
- Array::push.apply(domains, process.env.AXLE_DOMAINS.split(','))
- try
- name = require(process.cwd() + '/package').name
- domains.push("#{name}.localhost.dev") if name?
+ domains = process.env.AXLE_DOMAINS.split(',')
+ else
+ try
+ pkg = require(process.cwd() + '/package')
+ domains ?= pkg.axle_domains
+ domains ?= "#{pkg.name}.localhost.dev"
+ domains ?= []
+ domains = [domains] unless Array.isArray(domains)
- AxleClient = require './lib/axle_client'
- AxleClient.DOMAINS = domains
-
-exports.start_server = ->
- AxleServer = require './lib/axle_server'
- NetServer = require './lib/net_server'
- NetClient = require './lib/net_client'
-
- class AxleProtocol
- constructor: (@axle, socket) ->
- @client = new NetClient(socket)
- @client.on 'message', (command, data) =>
- @['on_' + command](data) if @['on_' + command]?
-
- on_connected: ->
-
-
- on_disconnected: ->
- if @routes?
- @axle.remove(r) for r in @routes
-
- on_register: (data) ->
- @routes = if Array.isArray(data) then data else [data]
-
- for r in @routes
- @axle.serve(r.host, r.endpoint)
-
- on_routes: ->
- @client.socket.write(JSON.stringify(@axle.routes))
-
- axle = new AxleServer(process.env.PORT || 3000)
- tcp_server = new NetServer(client_factory: (socket) -> new AxleProtocol(axle, socket)).listen(1313)
+ axle_service = coupler.connect(tcp: 1313).consume('axle')
+ client = new exports.Client(axle_service, domains)
+
+ client.on 'listening', (server) -> log 'Listening on port ' + server.address().port.toString().green
+ client.on 'connected', -> log 'Listening on ' + client.domains.map((d) -> d.green).join(', ')
+ client.on 'reconnected', -> log 'Reconnected'.green + ' to axle service'
+ client.on 'disconnected', -> log 'Lost Connection'.yellow + ' to axle service'
+
+ client.start()
@@ -1,4 +1,4 @@
-require 'colors'
+events = require 'events'
parse_endpoint = (endpoint) ->
if parseInt(endpoint).toString() is endpoint.toString()
@@ -25,33 +25,48 @@ class WildcardRoutePredicate extends RoutePredicate
matches: (host) ->
@rx.test(host)
-class Axle
- constructor: (port) ->
+class Axle extends events.EventEmitter
+ constructor: (@port) ->
throw new Error('Axle must take a port that is a number') unless port? and parseInt(port).toString() is port.toString()
@log = -> console.log '[' + 'axle'.cyan + '] ' + arguments[0]
+
+ initialize: ->
+ return if @server?
- @server = require('http').createServer().listen port, =>
- @log 'Running on port ' + @server.address().port.toString().green
+ @server = require('http').createServer()
+ @server.on 'listening', => @emit('listening', @server.address())
+ @server.on 'error', (err) => @emit('error', err)
@routes = []
@distribute = require('distribute')(@server)
-
@distribute.use (req, res, next) =>
- [host, _x] = req.headers.host.split(':')
-
- for e in @routes
- if e.matches(host)
- console.log '[' + 'axle'.cyan + '] Routing ' + host.yellow + ' to ' + "#{e.target.host}:#{e.target.port}".green
- return next(e.target.port, e.target.host)
+ try
+ [host, _x] = req.headers.host.split(':')
- @log 'No route for ' + host.red
- next()
+ for e in @routes
+ if e.matches(host)
+ @emit('route:match', host, e.target)
+ return next(e.target.port, e.target.host)
+
+ @emit('route:miss', host)
+ next()
+ catch e
+ next(e)
+
+ start: ->
+ return if @server?
+ @initialize()
+ @server.listen(@port)
+
+ stop: ->
+ @server.close()
+ delete @server
remove: (route) ->
@routes = @routes.filter (r) =>
if r.host is route.host and r.endpoint is route.endpoint
- @log 'Removed'.red + ' route ' + r.host + ' => ' + r.endpoint
+ @emit('route:remove', r)
return false
true
@@ -60,6 +75,6 @@ class Axle
@routes.push(new WildcardRoutePredicate(host, endpoint))
else
@routes.push(new RoutePredicate(host, endpoint))
- @log 'Added'.green + ' route ' + host + ' => ' + endpoint
+ @emit('route:add', {host: host, endpoint: endpoint})
module.exports = Axle
View
@@ -1,57 +0,0 @@
-require 'colors'
-
-net = require 'net'
-http = require 'http'
-portfinder = require 'portfinder'
-
-class AxleClient
- constructor: (@server) ->
- @log = -> console.log '[' + 'axle'.cyan + '] ' + arguments[0]
-
- @server.once('listening', => @on_server_listening())
- @server.on('error', => @on_server_error(arguments...))
-
- send: (command, data) ->
- @client.write(JSON.stringify($c: command, $d: data))
-
- connect: ->
- @client = net.connect(port: 1313)
- ['connect', 'end', 'close', 'data', 'error'].forEach (event) =>
- @client.on(event, => @['on_' + event](arguments...))
-
- on_server_listening: ->
- @log 'Listening on port ' + @server.address().port.toString().green
- @connect()
-
- on_server_error: (err) ->
- console.log 'SERVER ERROR ======'
- if err.code is 'EADDRINUSE'
- portfinder.getPort (e, port) =>
- return console.error(e.stack) if e?
- @server.listen(port)
-
- on_connect: ->
- @send('register', AxleClient.DOMAINS.map (d) => {host: d, endpoint: @server.address().port})
- @log 'Listening on ' + AxleClient.DOMAINS.map((d) -> d.green).join(', ')
-
- on_end: ->
-
-
- on_close: ->
- setTimeout (=> @connect()), 1000
-
- on_error: (err) ->
- @log 'Error connecting to axle: ' + err.code.red
-
- on_data: ->
- console.log 'data'
- console.log arguments
-
-
-_createServer = http.createServer
-http.createServer = ->
- server = _createServer.apply(http, arguments)
- new AxleClient(server)
- server
-
-module.exports = AxleClient
View
@@ -0,0 +1,36 @@
+net = require 'net'
+http = require 'http'
+portfinder = require 'portfinder'
+EventEmitter = require('events').EventEmitter
+
+class Client extends EventEmitter
+ constructor: (@axle_service, @domains) ->
+
+ start: ->
+ createServer = http.createServer
+ http.createServer = =>
+ server = createServer.apply(http, arguments)
+ server.on 'error', => @on_server_error(server, arguments...)
+ server.on 'listening', => @on_server_listening(server, arguments...)
+ server
+
+ on_server_error: (server, err) ->
+ if err.code is 'EADDRINUSE'
+ portfinder.getPort (e, port) =>
+ return @emit('error', e) if e?
+ server.listen(port)
+
+ on_server_listening: (server) ->
+ @emit('listening', server)
+
+ @axle_service.on 'coupler:connected', =>
+ @axle_service.register(@domains.map (d) -> {host: d, endpoint: server.address().port})
+ @emit('connected', server)
+
+ @axle_service.on 'coupler:reconnected', =>
+ @emit('reconnected', server)
+
+ @axle_service.on 'coupler:disconnected', =>
+ @emit('disconnected', server)
+
+module.exports = Client
View
@@ -1,24 +0,0 @@
-class NetClient extends require('events').EventEmitter
- constructor: (@socket) ->
- @id = "#{@socket.remoteAddress}:#{@socket.remotePort}"
- @log = => console.log '[' + @id.green + '] ' + arguments[0]
-
- ['data', 'close', 'end', 'error'].forEach (event) =>
- @socket.on(event, => @['on_' + event](arguments...))
-
- process.nextTick => @emit('message', 'connected')
-
- on_data: (data) ->
- data = JSON.parse(data.toString())
- @emit('message', data.$c, data.$d)
-
- on_close: ->
-
- on_end: (had_error) ->
- @emit('message', 'disconnected')
-
- on_error: ->
- @log 'error'
- console.log arguments
-
-module.exports = NetClient
View
@@ -1,28 +0,0 @@
-net = require 'net'
-
-class NetServer
- constructor: (opts) ->
- @clients = {}
-
- if opts.client?
- @client_factory = (socket) =>
- new opts.client(socket)
- else if opts.client_factory?
- @client_factory = opts.client_factory
- else
- throw new Error('NetServer constructor takes either a client or client_factory')
-
- @server = net.createServer (s) => @on_connection(s)
-
- on_connection: (socket) ->
- client = @client_factory(socket)
- @clients[client.id] = client
- socket.on 'close', => @on_close(client)
-
- on_close: (client) ->
- delete @clients[client.id]
-
- listen: ->
- @server.listen(arguments...)
-
-module.exports = NetServer
View
@@ -0,0 +1,16 @@
+class Service
+ constructor: (@axle, @connection) ->
+ @connection.on 'coupler:connected', =>
+ @domains = []
+ @connection.on 'coupler:disconnected', =>
+ @axle.remove(d) for d in @domains
+
+ register: (domains) ->
+ domains = [domains] unless Array.isArray(domains)
+ Array::push.apply(@domains, domains)
+ @axle.serve(d.host, d.endpoint) for d in domains
+
+ routes: (callback) ->
+ callback(null, @axle.routes)
+
+module.exports = Service
View
@@ -1,7 +1,7 @@
{
"name": "axle",
"description": "",
- "version": "0.0.3",
+ "version": "0.0.6",
"homepage": "https://github.com/mattinsler/axle",
"author": {
"name": "Matt Insler",
@@ -30,7 +30,8 @@
"coffee-script": "latest",
"distribute": "latest",
"portfinder": "latest",
- "colors": "latest"
+ "colors": "latest",
+ "coupler": "latest"
},
"devDependencies": {
},

0 comments on commit 5f8f6d8

Please sign in to comment.