crossfire
Version:
A simple proxy that uses DNS SRV records to dynamically update its routing table.
64 lines (56 loc) • 1.93 kB
text/coffeescript
{async} = require "fairmont"
http = require "http"
{promise} = require "when"
{liftAll} = require "when/node"
dns = liftAll require "dns"
dns.setServers [
"8.8.8.8"
"8.8.4.4"
]
parseHost = do (re=/^(\w+)(\.(\w+\.\w+))?(:(\d+))?$/) ->
(host) ->
if (match = host.match re)?
[_, name, _, domain, _, port] = match
{name, domain, port}
else
{}
Routes =
find: async (request) ->
{name, domain} = parseHost request.headers.host
console.log "finding routes with ", {name, domain}
if domain?
addresses = yield dns.resolveSrv "_#{name}._http.#{domain}"
address = addresses[Math.round(Math.random() * (addresses.length - 1))]
console.log "found route #{address.name}:#{address.port}"
address
Proxy =
log: do (n=0) ->
(next) ->
(request, response) ->
{url, method, headers} = request
host = if headers.host? then headers.host else "-"
console.log "request #{n}: #{host} #{method} #{url}"
do (n) ->
response.on "finish", ->
{statusCode} = response
console.log "response #{n}: #{statusCode}"
n++
next request, response
start: (_port) ->
http.createServer Proxy.log async (request, response) ->
{url, method, headers} = request
try
{name, port} = yield Routes.find request
# not sure we need this, but we don't want to rely
# on the OS to resolve these names since they may
# be changing pretty frequently...
[host] = yield dns.resolve name
console.log "resolved #{name} to #{host}"
request.pipe http.request {host, port, url, method, headers},
(_response) -> _response.pipe response
catch error
response.statusCode = 503
response.end()
.listen _port, ->
console.log "Listening on port #{_port}"
Proxy.start (if process.argv[2]? then process.argv[2] else 80)