rename to catalyst-proxy, add a CLI utility

This commit is contained in:
Morhaus 2014-01-06 21:22:59 +01:00
commit 9a9bd308ce
7 changed files with 86 additions and 26 deletions

View file

@ -1,3 +1,28 @@
multipart-proxy
catalyst-proxy
==============
A proxy that accelerates requests via multipart downloading. Very much WIP.
A proxy that silently accelerates requests via multipart downloading. Officially the best thing ever.
`catalyst-proxy` establishes multiples connections to download a single resource from a web server, potentially increasing the download speed.
Only supports "streaming" acceleration for now: resources are cut into parts of equal length (`--partSize` CLI option) that are downloaded concurrently (`--threads` CLI option) and served sequentially. This behavior differs from most download managers and allows to consume the resource while downloading it.
Use-cases
---------
* Speed up video streaming websites, such as YouTube.
* Speed up software and game downloaders/installers.
* Speed up everything.
Installation
------------
You need to have Node.JS >= 0.10.0 installed on your system.
```$ npm install -g catalyst-proxy```
To update:
```$ npm update -g catalyst-proxy```
Usage
-----
```$ catalyst start``` to boot up the proxy. Simply add the printed address and port as an HTTP proxy in your system settings and you're set.
```$ catalyst start -h``` to list all available options.

2
bin/catalyst.js Executable file
View file

@ -0,0 +1,2 @@
#!/usr/bin/env node
require(__dirname + '/../lib/cli');

View file

@ -1,5 +1,5 @@
{
"name": "multipart-proxy",
"name": "catalyst-proxy",
"description": "A proxy that accelerates requests via multipart downloading",
"author": "Alexandre Kirszenberg <a.kirszenberg@gmail.com>",
"version": "0.1.0",
@ -12,7 +12,11 @@
"repository": {
"type": "git",
"url": "git@github.com:morhaus/multipart-proxy.git"
"url": "git@github.com:morhaus/catalyst-proxy.git"
},
"bin": {
"catalyst": "./bin/catalyst.js"
},
"scripts": {
@ -26,9 +30,8 @@
"engineStrict": true,
"dependencies": {
"commander": "2.0.0",
"commander": "2.*",
"lodash": "*",
"async": "*",
"multisource-stream": "0.0.*",
"tmpl-log": "0.0.*"
},

33
src/cli.coffee Normal file
View file

@ -0,0 +1,33 @@
http = require 'http'
program = require 'commander'
Logger = require 'tmpl-log'
Proxy = require './proxy'
logr = new Logger
program
.version('0.1.0')
program
.command('start')
.option('-p, --port <p>', 'port on which to listen', Number, 8080)
.option('-H, --host <h>', 'host on which to start the proxy', String, 'localhost')
.option('-t, --threads <t>', 'max concurrent threads', Number, 12)
.option('-s, --partSize <p>', 'thread part size', Number, 1024 * 1024 * 2)
.option('-l, --contentLength <l>', 'min content length for threaded downloading', Number, 1024 * 1024 * 4)
.action (args..., { port, host, threads, partSize, contentLength }) ->
proxy = new Proxy { threads, partSize, contentLength }
proxy.on 'error', (e) ->
if e.syscall is 'listen'
switch e.code
when 'EADDRNOTAVAIL' then logr.log "<underline><red>Error:</></> address or port not available (<bold>http://<underline>#{host}</>:#{port}</>)"
when 'EACCES' then logr.log "<underline><red>Error:</></> reserved address or port (<bold>http://<underline>#{host}</>:#{port}</>)"
throw e
proxy.listen port, host, ->
logr.log """
Proxy started on <bold>http://<underline>#{host}</>:#{port}</>. Press CTRL+C to stop it.
"""
program.parse process.argv

View file

@ -1,6 +0,0 @@
http = require 'http'
Proxy = require './proxy'
http.globalAgent.maxSockets = Infinity
new Proxy 8080

View file

@ -1,34 +1,34 @@
http = require 'http'
url = require 'url'
{ EventEmitter } = require 'events'
_ = require 'lodash'
Request = require './request'
module.exports = class Proxy
constructor: (listenPort, listenHost, opts = {}) ->
if typeof listenHost is 'object'
opts = listenHost
listenHost = undefined
module.exports = class Proxy extends EventEmitter
constructor: (opts = {}) ->
super()
@opts = _.clone opts
_.defaults @opts,
maxConcurrent: 12
threads: 12
partSize: 1024 * 1024 / 4
minContentLength: 1024 * 1024
contentLength: 1024 * 1024
http.createServer()
.on('request', @request)
.listen(listenPort, listenHost)
@server = http.createServer()
@server.on 'request', @request
@server.on 'error', (e) =>
@emit 'error', e
_isDownloadable: (res) ->
res.statusCode in [200, 206] and (parseInt res.headers['content-length']) >= @opts.minContentLength
res.statusCode in [200, 206] and (parseInt res.headers['content-length']) >= @opts.contentLength
request: (clientReq, clientRes) =>
reqOpts = url.parse clientReq.url
reqOpts.method = clientReq.method
reqOpts.headers = clientReq.headers
reqOpts.agent = new http.Agent maxSockets: @opts.maxConcurrent
reqOpts.agent = new http.Agent maxSockets: @opts.threads
# Create new request
request = new Request reqOpts, @opts
@ -48,3 +48,6 @@ module.exports = class Proxy
# Stop the request whether or not it has completed
clientRes.on 'close', ->
request.stop()
listen: (port, host, callback) ->
@server.listen port, host, callback

View file

@ -224,8 +224,8 @@ module.exports = class Request extends Duplex
# Fills the running thread pool
_fill: ->
console.log "FILL #{@runningPool.length}/#{@opts.maxConcurrent}, #{@offset}/#{@range[1]}, #{@pool.indexOf @runningPool[0]}"
if @runningPool.length < @opts.maxConcurrent and @offset isnt @range[1]
console.log "FILL #{@runningPool.length}/#{@opts.threads}, #{@offset}/#{@range[1]}, #{@pool.indexOf @runningPool[0]}"
if @runningPool.length < @opts.threads and @offset isnt @range[1]
# Calculate correct thread length
length = @range[1] - @offset
length = @opts.partSize if length > @opts.partSize