Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

rolled back up

  • Loading branch information...
commit e288ca2df2fd5841e2133ed3af1fc3cc54ab8e18 1 parent 02047a8
@mattinsler authored
View
11 bin/axle
@@ -80,20 +80,13 @@ function start_script(original_script, args) {
require(script_file);
}
-require('coffee-script');
-var Axle = require('../index');
-
-if (process.argv.length === 2) {
- // Server
- return Axle.start_server();
-}
-
// Client
var cmd = process.argv[2]
, args = process.argv.slice(3);
-Axle.start_client();
+require('coffee-script');
+require('../lib/cli').run_client();
if (cmd === 'node') { return start_node(args); }
if (cmd === 'coffee') { return start_coffee(args); }
View
14 bin/axle-server
@@ -0,0 +1,14 @@
+#!/usr/bin/env node
+
+var program = require('commander');
+
+program
+ .version(require('../package').version)
+
+ .command('run', 'Run the axle server')
+ .command('install', 'Install the axle services to run all the time')
+ .command('uninstall', 'Remove the axle services (you should be ashamed)')
+ // .command('status', 'Check on the ')
+ // .command('daemon', 'Run the axle-server daemon')
+
+ .parse(process.argv);
View
4 bin/axle-server-daemon
@@ -0,0 +1,4 @@
+#!/usr/bin/env node
+
+require('coffee-script');
+require('../lib/cli').daemon();
View
4 bin/axle-server-install
@@ -0,0 +1,4 @@
+#!/usr/bin/env node
+
+require('coffee-script');
+require('../lib/cli').install();
View
4 bin/axle-server-run
@@ -0,0 +1,4 @@
+#!/usr/bin/env node
+
+require('coffee-script');
+require('../lib/cli').run_server();
View
4 bin/axle-server-uninstall
@@ -0,0 +1,4 @@
+#!/usr/bin/env node
+
+require('coffee-script');
+require('../lib/cli').uninstall();
View
55 index.coffee
@@ -1,50 +1,11 @@
+exports.version = require('./package').version
+
+exports.Configuration = require './lib/configuration'
+
exports.Axle = require './lib/axle'
+exports.Logger = require './lib/logger'
exports.Client = require './lib/client'
+exports.Server = require './lib/server'
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()
- axle
-
-exports.start_client = ->
- require 'colors'
- coupler = require 'coupler'
-
- log = -> console.log '[' + 'axle'.cyan + '] ' + arguments[0]
-
- if process.env.AXLE_DOMAINS?
- 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)
-
- return null unless domains?
-
- 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()
- client
+exports.Dns = require './lib/dns'
+exports.OsxResolverManager = require './lib/osx_resolver_manager'
View
59 lib/axle.coffee
@@ -1,4 +1,5 @@
-events = require 'events'
+{EventEmitter} = require 'events'
+Logger = require './logger'
parse_endpoint = (endpoint) ->
if parseInt(endpoint).toString() is endpoint.toString()
@@ -13,7 +14,7 @@ parse_endpoint = (endpoint) ->
class RoutePredicate
constructor: (@host, @endpoint) ->
@target = parse_endpoint(@endpoint)
-
+
matches: (host) ->
@host is host
@@ -25,43 +26,16 @@ class WildcardRoutePredicate extends RoutePredicate
matches: (host) ->
@rx.test(host)
-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]
+class Axle extends EventEmitter
+ config: require './configuration'
- initialize: ->
- return if @server?
-
- @server = require('http').createServer()
- @server.on 'listening', => @emit('listening', @server.address())
- @server.on 'error', (err) => @emit('error', err)
-
+ constructor: ->
@routes = []
- @distribute = require('distribute')(@server)
- @distribute.use (req, res, next) =>
- try
- [host, _x] = req.headers.host.split(':')
-
- 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
+
+ @on 'route:add', (route) -> Logger.info Logger.green('Added') + ' route ' + route.host + ' => ' + route.endpoint
+ @on 'route:remove', (route) -> Logger.info Logger.red('Removed') + ' route ' + route.host + ' => ' + route.endpoint
+ @on 'route:match', (from, to) -> Logger.debug 'Matched route for ' + Logger.yellow(from) + ' to ' + Logger.green("#{to.host}:#{to.port}")
+ @on 'route:miss', (host) -> Logger.debug 'No route for ' + Logger.red(host)
remove: (route) ->
@routes = @routes.filter (r) =>
@@ -69,12 +43,21 @@ class Axle extends events.EventEmitter
@emit('route:remove', r)
return false
true
-
+
serve: (host, endpoint) ->
if host.indexOf('*') isnt -1
@routes.push(new WildcardRoutePredicate(host, endpoint))
else
@routes.push(new RoutePredicate(host, endpoint))
@emit('route:add', {host: host, endpoint: endpoint})
+
+ match: (host) ->
+ for e in @routes
+ if e.matches(host)
+ @emit('route:match', host, e.target)
+ return e.target
+
+ @emit('route:miss', host)
+ null
module.exports = Axle
View
120 lib/cli.coffee
@@ -0,0 +1,120 @@
+# - axle registry
+# - tcp service
+# - dns server
+# - proxy
+# - web server for status
+
+os = require 'os'
+axle = require '../index'
+walkabout = require 'walkabout'
+exec = require('child_process').exec
+
+Logger = axle.Logger
+
+AXLE_RESOLVER = """
+# Resolver for axle
+nameserver 127.0.0.1
+port #{axle.Configuration.dns.port}
+"""
+
+AXLE_PLIST_FILE = walkabout('/Library/LaunchAgents/com.mattinsler.axle.plist')
+AXLE_DAEMON_PLIST = """
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.mattinsler.axle</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>#{process.execPath}</string>
+ <string>#{walkabout(__dirname).join('../bin/axle-server-run').absolute_path}</string>
+ </array>
+ <key>KeepAlive</key>
+ <true/>
+ <key>RunAtLoad</key>
+ <true/>
+ <key>Debug</key>
+ <true/>
+ <key>StandardOutPath</key>
+ <string>/var/log/com.mattinsler.axle.log</string>
+ <key>StandardErrorPath</key>
+ <string>/var/log/com.mattinsler.axle.log</string>
+</dict>
+</plist>
+"""
+
+exports.install = ->
+ Logger.info 'install'
+
+ return Logger.error('Try running with sudo') unless process.getuid() is 0
+
+ Logger.info 'mkdirp /etc/resolver'
+ walkabout('/etc/resolver').mkdirp_sync()
+ # Logger.info 'write /etc/resolver/axle'
+ # walkabout('/etc/resolver/axle').write_file_sync(AXLE_RESOLVER)
+
+ Logger.info 'write', AXLE_PLIST_FILE.absolute_path
+ walkabout(AXLE_PLIST_FILE.dirname).mkdirp_sync()
+ AXLE_PLIST_FILE.write_file_sync(AXLE_DAEMON_PLIST)
+
+ Logger.info 'launch axle server'
+ exec "launchctl unload #{AXLE_PLIST_FILE.absolute_path}", ->
+ exec "launchctl load #{AXLE_PLIST_FILE.absolute_path}", ->
+ Logger.info 'ok'
+
+exports.uninstall = ->
+ Logger.info 'uninstall'
+
+ return Logger.error('Try running with sudo') unless process.getuid() is 0
+
+ # Logger.info 'rm /etc/resolver/axle'
+ # walkabout('/etc/resolver/axle').unlink_sync() if walkabout('/etc/resolver/axle').exists_sync()
+
+ Logger.info 'stop axle server'
+ exec "launchctl unload #{AXLE_PLIST_FILE.absolute_path}", ->
+ Logger.info 'rm', AXLE_PLIST_FILE.absolute_path
+ AXLE_PLIST_FILE.unlink_sync() if AXLE_PLIST_FILE.exists_sync()
+
+ Logger.info 'ok'
+
+exports.run_client = ->
+ client = new axle.Client()
+
+ if process.env.AXLE_DOMAINS?
+ client.domains = process.env.AXLE_DOMAINS.split(',')
+ else
+ try
+ pkg = require(process.cwd() + '/package')
+ client.domains ?= pkg['axle-domains']
+ client.domains ?= ["#{pkg.name}.localhost.dev"]
+ client.domains ?= []
+ client.domains = [domains] unless Array.isArray(domains)
+
+ client.start()
+
+exports.run_server = ->
+ Logger.info 'server'
+
+ return Logger.error('Try running with sudo') unless process.getuid() is 0
+
+ instance = new axle.Axle()
+
+ servers = []
+ servers.push(new axle.Server(instance)) if instance.config.server.enabled
+ servers.push(new axle.Service(instance)) if instance.config.service.enabled
+ servers.push(new axle.Dns(instance)) if instance.config.dns.enabled
+
+ servers.push(new axle.OsxResolverManager(instance)) if os.platform() is 'darwin'
+
+ servers.forEach (s) -> s.start()
+
+ process.on 'SIGTERM', ->
+ servers.forEach (s) -> s.stop()
+ Logger.info 'bye bye'
+ process.exit(0)
+
+ Logger.info 'started'
+
+exports.daemon = ->
+
View
52 lib/client.coffee
@@ -1,20 +1,19 @@
net = require 'net'
http = require 'http'
+coupler = require 'coupler'
+Logger = require './logger'
+Configuration = require './configuration'
portfinder = require 'portfinder'
-EventEmitter = require('events').EventEmitter
+{EventEmitter} = require 'events'
class Client extends EventEmitter
- constructor: (@axle_service, @domains) ->
-
- start: ->
- createServer = http.createServer
- http.createServer = =>
- server = createServer.apply(http, arguments)
- return server if @intercepted
- @intercepted = true
- server.on 'error', => @on_server_error(server, arguments...)
- server.on 'listening', => @on_server_listening(server, arguments...)
- server
+ constructor: ->
+ @on 'listening', (server) -> Logger.info 'Listening on port ' + Logger.green(server.address().port)
+ @on 'connected', => Logger.info 'Listening on ' + @domains.map((d) -> Logger.green(d)).join(', ')
+ @on 'reconnected', -> Logger.info Logger.green('Reconnected') + ' to axle service'
+ @on 'disconnected', -> Logger.info Logger.yellow('Lost Connection') + ' to axle service'
+
+ @axle_service = coupler.connect(tcp: Configuration.service.port).consume('axle')
on_server_error: (server, err) ->
if err.code is 'EADDRINUSE'
@@ -35,4 +34,33 @@ class Client extends EventEmitter
@axle_service.on 'coupler:disconnected', =>
@emit('disconnected', server)
+ start: ->
+ createServer = http.createServer
+ http.createServer = =>
+ server_args = Array::slice.call(arguments)
+ server = createServer.apply(http, server_args)
+ return server if @intercepted
+ @intercepted = true
+ server.on 'error', => @on_server_error(server, server_args...)
+ server.on 'listening', => @on_server_listening(server, server_args...)
+
+ serverListen = server.listen
+ server.listen = ->
+ listen_args = Array::slice.call(arguments)
+ callback = listen_args[listen_args.length - 1] if listen_args.length > 0 and typeof listen_args[listen_args.length - 1] is 'function'
+
+ portfinder.getPort (err, port) =>
+ if err?
+ @emit('error', err)
+ callback?(err)
+ return
+ serverListen.call(server, port, callback)
+
+ server
+
+ server
+
+ stop: ->
+
+
module.exports = Client
View
12 lib/configuration.coffee
@@ -0,0 +1,12 @@
+Configuration =
+ server:
+ port: 80
+ enabled: true
+ service:
+ port: 1313
+ enabled: true
+ dns:
+ port: 53
+ enabled: true
+
+module.exports = Configuration
View
203 lib/dns.coffee
@@ -0,0 +1,203 @@
+dgram = require 'dgram'
+packed = require 'packed'
+walkabout = require 'walkabout'
+
+REQUEST_TYPES =
+ A: 1
+ AAAA: 28
+ CNAME: 5
+ MX: 15
+ NS: 2
+REQUEST_TYPES[v] = k for k, v of REQUEST_TYPES
+
+domain_string = {
+ unpack: (buffer) ->
+ o = @byte_offset
+ str = (while (len = buffer.readUInt8(o)) isnt 0
+ buffer.slice(o + 1, o += 1 + len).toString('ascii')
+ ).join('.')
+ [str, o + 1]
+ pack: (buffer, value) ->
+ return [@byte_offset] unless value?
+ o = @byte_offset
+ for v in value.split('.')
+ buffer.writeUInt8(v.length, o++)
+ new Buffer(v, 'ascii').copy(buffer, o)
+ o += v.length
+ buffer.writeUInt8(0, o)
+ [o + 1]
+}
+
+ip_address = {
+ unpack: (buffer) ->
+ ['', @byte_offset + 4]
+ pack: (buffer, value) ->
+ return [@byte_offset] unless value?
+ i = value.split('.')
+ buffer.writeUInt8(parseInt(i[0]), @byte_offset)
+ buffer.writeUInt8(parseInt(i[1]), @byte_offset + 1)
+ buffer.writeUInt8(parseInt(i[2]), @byte_offset + 2)
+ buffer.writeUInt8(parseInt(i[3]), @byte_offset + 3)
+ [@byte_offset + 4]
+}
+
+DnsRequest = packed
+ header:
+ qid: packed.uint16
+ flags:
+ qr: packed.bits(1)
+ opcode: packed.bits(4)
+ aa: packed.bits(1)
+ tc: packed.bits(1)
+ rd: packed.bits(1)
+ ra: packed.bits(1)
+ z: packed.bits(3)
+ rcode: packed.bits(4)
+ qcount: packed.uint16
+ acount: packed.uint16
+ auth_count: packed.uint16
+ addl_count: packed.uint16
+ question:
+ domain: domain_string
+ qtype: packed.uint16
+ qclass: packed.uint16
+
+DnsResponse = packed
+ header:
+ qid: packed.uint16
+ flags:
+ qr: packed.bits(1)
+ opcode: packed.bits(4)
+ aa: packed.bits(1)
+ tc: packed.bits(1)
+ rd: packed.bits(1)
+ ra: packed.bits(1)
+ z: packed.bits(3)
+ rcode: packed.bits(4)
+ qcount: packed.uint16
+ acount: packed.uint16
+ auth_count: packed.uint16
+ addl_count: packed.uint16
+ question:
+ domain: domain_string
+ qtype: packed.uint16
+ qclass: packed.uint16
+ answer:
+ name: packed.uint16
+ qtype: packed.uint16
+ qclass: packed.uint16
+ ttl: packed.uint32
+ data_length: packed.uint16
+ data: ip_address
+
+class Dns
+ constructor: (@axle) ->
+ @read_nameservers()
+
+ @server = dgram.createSocket('udp4')
+ @server.on('message', @on_message.bind(@))
+
+ read_nameservers: ->
+ @nameservers = walkabout('/etc/resolv.conf').read_file_sync()
+ .split('\n')
+ .filter((line) -> line[0] isnt '#')
+ .map((line) -> /nameserver[ \t]+(.+)\b/.exec(line))
+ .filter((match) -> match?)
+ .map((match) -> match[1])
+ .filter((ip) -> ip not in ['0.0.0.0', '127.0.0.1', 'localhost'])
+
+ parse: (msg) ->
+ DnsRequest.unpack(msg)
+
+ adjust_response_ttl: (response, ttl) ->
+ questions = response.readUInt16BE(4)
+ answers = response.readUInt16BE(6)
+
+ answer_offset = question_offset = 12
+ for x in [0...questions]
+ ++answer_offset while response.readUInt8(answer_offset) isnt 0
+ answer_offset += 5
+
+ for x in [0...answers]
+ ttl_offset = answer_offset + 6
+
+ old_ttl = response.readUInt32BE(ttl_offset)
+ response.writeUInt32BE(ttl, ttl_offset)
+
+ ip_length_offset = ttl_offset + 4
+ ip_length = response.readUInt16BE(ip_length_offset)
+ answer_offset = ip_length_offset + 2 + ip_length
+
+ response
+
+ forward_dns: (remote_info, msg) ->
+ client = dgram.createSocket('udp4')
+
+ client.on 'message', (data, rinfo) =>
+ client.close()
+ @server.send(@adjust_response_ttl(data, 1), 0, data.length, remote_info.port, remote_info.address)
+
+ client.send(msg, 0, msg.length, 53, @nameservers[0])
+
+ respond_with: (ip_address, remote_info, req) ->
+ res = DnsResponse.pack(
+ header:
+ qid: req.header.qid
+ flags:
+ qr: 1
+ rd: 1
+ ra: 1
+ qcount: 1
+ acount: 1
+ auth_count: 0
+ addl_count: 0
+ question:
+ domain: req.question.domain
+ qtype: req.question.qtype
+ qclass: req.question.qclass
+ answer:
+ name: 0xc00c
+ qtype: req.question.qtype
+ qclass: req.question.qclass
+ ttl: 1
+ data_length: 4
+ data: '127.0.0.1'
+ )
+
+ @server.send(res, 0, res.length, remote_info.port, remote_info.address)
+
+ fail_dns: (remote_info, req) ->
+ res = DnsResponse.pack(
+ header:
+ qid: req.header.qid
+ flags:
+ qr: 1
+ rd: 1
+ ra: 1
+ rcode: 3
+ qcount: 1
+ acount: 1
+ auth_count: 0
+ addl_count: 0
+ question:
+ domain: req.question.domain
+ qtype: req.question.qtype
+ qclass: req.question.qclass
+ )
+
+ @server.send(res, 0, res.length, remote_info.port, remote_info.address)
+
+ on_message: (msg, remote_info) ->
+ req = @parse(msg)
+ console.log "#{REQUEST_TYPES[req.question.qtype]} #{req.question.domain}"
+
+ return @respond_with('127.0.0.1', remote_info, req) if req.question.qtype in [REQUEST_TYPES.A, REQUEST_TYPES.AAAA, REQUEST_TYPES.CNAME] and @axle.match(req.question.domain)?
+ @fail_dns(remote_info, req)
+
+ start: ->
+ @server.bind(53)
+
+ stop: ->
+ @server.close()
+
+module.exports = Dns
View
35 lib/logger.coffee
@@ -0,0 +1,35 @@
+require 'colors'
+
+LEVELS = [
+ 'debug'
+ 'info'
+ 'notice'
+ 'warning'
+ 'error'
+ 'critical'
+ 'alert'
+ 'emergency'
+]
+LEVEL_COLORS = {
+ debug: 'magenta'
+ info: 'green'
+ notice: 'green'
+ warning: 'yellow'
+ error: 'red'
+ critical: 'red'
+ alert: 'red'
+ emergency: 'red'
+}
+
+exports.log = (level) ->
+ level = level.toLowerCase()
+
+ args = Array::slice.call(arguments, 1)
+ args[0] = '[' + 'axle'.cyan + '] ' + level[LEVEL_COLORS[level]] + ' ' + args[0]
+ console.log.apply(console, args)
+
+LEVELS.forEach (level) ->
+ exports[level] = -> exports.log.apply(null, [level].concat(Array::slice.call(arguments)))
+
+['grey', 'black', 'yellow', 'red', 'green', 'blue', 'white', 'cyan', 'magenta'].forEach (color) ->
+ exports[color] = (value) -> value.toString()[color]
View
67 lib/osx_resolver_manager.coffee
@@ -0,0 +1,67 @@
+walkabout = require 'walkabout'
+Logger = require './logger'
+Configuration = require './configuration'
+
+AXLE_RESOLVER = """
+# Resolver for axle
+nameserver 127.0.0.1
+port #{Configuration.dns.port}
+"""
+
+class OsxResolverManager
+ constructor: (@axle) ->
+ @domains = {}
+ @files_created = {}
+ process.on 'exit', =>
+ walkabout(f).unlink_sync() for f, x of @files_created
+
+ @axle.routes.forEach (d) => @add_domain(d)
+
+ @axle.on 'route:add', (route) =>
+ @add_domain(route.host)
+
+ @axle.on 'route:remove', (route) =>
+ @remove_domain(route.host)
+
+ add_domain: (domain) ->
+ domain = domain.split('.').slice(-1)[0]
+ return @domains[domain] if domain is '*'
+ @domains[domain] ?= 0
+ @create_resolver(domain) if @domains[domain] is 0
+ ++@domains[domain]
+
+ remove_domain: (domain) ->
+ domain = domain.split('.').slice(-1)[0]
+ return @domains[domain] if domain is '*'
+ @domains[domain] ?= 0
+ @remove_resolver(domain) if --@domains[domain] is 0
+ @domains[domain]
+
+ create_resolver: (domain) ->
+ return unless @running is true
+
+ file = walkabout("/etc/resolver/#{domain}")
+
+ Logger.info "write #{file.absolute_path}"
+ unless file.exists_sync()
+ file.directory().mkdirp_sync()
+ file.write_file_sync(AXLE_RESOLVER)
+ @files_created[file.absolute_path] = 1
+ @
+
+ remove_resolver: (domain) ->
+ return unless @running is true
+
+ file = walkabout("/etc/resolver/#{domain}")
+
+ Logger.info "rm #{file.absolute_path}"
+ file.unlink_sync() if file.exists_sync()
+ delete @files_created[file.absolute_path]
+
+ start: ->
+ @running = true
+
+ stop: ->
+ @running = false
+
+module.exports = OsxResolverManager
View
32 lib/server.coffee
@@ -0,0 +1,32 @@
+http = require 'http'
+distribute = require 'distribute'
+Logger = require './logger'
+{EventEmitter} = require 'events'
+
+class Server extends EventEmitter
+ constructor: (@axle) ->
+ @on 'listening', (address) -> Logger.info 'Listening on port ' + Logger.green(address.port)
+ @on 'forward', (from, to) -> Logger.info 'Forwarding ' + Logger.yellow(from) + ' to ' + Logger.green("#{to.host}:#{to.port}")
+
+ @server = http.createServer()
+ @server.on 'listening', => @emit('listening', @server.address())
+ @server.on 'error', (err) => @emit('error', err)
+
+ @distribute = distribute(@server)
+ @distribute.use (req, res, next) =>
+ try
+ host = req.headers.host.split(':')[0]
+ match = @axle.match(host)
+ return next() unless match?
+ @emit('forward', host, match)
+ next(match.port, match.host)
+ catch e
+ next(e)
+
+ start: ->
+ @server.listen(@axle.config.server.port)
+
+ stop: ->
+ @server.close()
+
+module.exports = Server
View
19 lib/service.coffee
@@ -1,4 +1,6 @@
-class Service
+coupler = require 'coupler'
+
+class Client
constructor: (@axle, @connection) ->
@connection.on 'coupler:connected', =>
@domains = []
@@ -13,4 +15,19 @@ class Service
routes: (callback) ->
callback?(null, @axle.routes)
+
+class Service
+ constructor: (@axle) ->
+
+ start: ->
+ @service = coupler
+ .accept(tcp: @axle.config.service.port)
+ .provide(
+ axle: (connection) =>
+ new Client(@axle, connection)
+ )
+
+ stop: ->
+
+
module.exports = Service
View
15 package.json
@@ -1,7 +1,7 @@
{
"name": "axle",
- "description": "",
- "version": "0.0.6",
+ "description": "An effortless HTTP reverse proxy for node",
+ "version": "0.1.1",
"homepage": "https://github.com/mattinsler/axle",
"author": {
"name": "Matt Insler",
@@ -21,7 +21,11 @@
}],
"main": "index",
"bin": {
- "axle": "./bin/axle"
+ "axle": "./bin/axle",
+ "axle-server": "./bin/axle-server",
+ "axle-server-install": "./bin/axle-server-install",
+ "axle-server-uninstall": "./bin/axle-server-uninstall",
+ "axle-server-run": "./bin/axle-server-run"
},
"engines": {
"node": ">= 0.8.0"
@@ -31,7 +35,10 @@
"distribute": "latest",
"portfinder": "latest",
"colors": "latest",
- "coupler": "latest"
+ "coupler": "latest",
+ "packed": "latest",
+ "commander": "latest",
+ "walkabout": "latest"
},
"devDependencies": {
},
View
1  test/test_client.coffee
@@ -1,6 +1,7 @@
http = require 'http'
server = require('http').createServer (req, res) ->
+ console.log 'REQUEST'
res.writeHead(200, 'Content-Type': 'text/plain')
res.end('Hello World')
.listen(process.env.PORT || 3000)
Please sign in to comment.
Something went wrong with that request. Please try again.