From 9a9bd308cedf0b8f975f5f9f2a8e347a77a81a0d Mon Sep 17 00:00:00 2001 From: Morhaus Date: Mon, 6 Jan 2014 21:22:59 +0100 Subject: [PATCH] rename to catalyst-proxy, add a CLI utility --- README.md | 29 +++++++++++++++++++++++++++-- bin/catalyst.js | 2 ++ package.json | 11 +++++++---- src/cli.coffee | 33 +++++++++++++++++++++++++++++++++ src/index.coffee | 6 ------ src/proxy.coffee | 27 +++++++++++++++------------ src/request.coffee | 4 ++-- 7 files changed, 86 insertions(+), 26 deletions(-) create mode 100755 bin/catalyst.js create mode 100644 src/cli.coffee diff --git a/README.md b/README.md index 0353b52..35bfed9 100644 --- a/README.md +++ b/README.md @@ -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. + diff --git a/bin/catalyst.js b/bin/catalyst.js new file mode 100755 index 0000000..407ffd3 --- /dev/null +++ b/bin/catalyst.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require(__dirname + '/../lib/cli'); diff --git a/package.json b/package.json index a8b6923..b1302fc 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "multipart-proxy", + "name": "catalyst-proxy", "description": "A proxy that accelerates requests via multipart downloading", "author": "Alexandre Kirszenberg ", "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.*" }, diff --git a/src/cli.coffee b/src/cli.coffee new file mode 100644 index 0000000..e0dd69a --- /dev/null +++ b/src/cli.coffee @@ -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

', 'port on which to listen', Number, 8080) + .option('-H, --host ', 'host on which to start the proxy', String, 'localhost') + .option('-t, --threads ', 'max concurrent threads', Number, 12) + .option('-s, --partSize

', 'thread part size', Number, 1024 * 1024 * 2) + .option('-l, --contentLength ', '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 "Error: address or port not available (http://#{host}:#{port})" + when 'EACCES' then logr.log "Error: reserved address or port (http://#{host}:#{port})" + throw e + proxy.listen port, host, -> + logr.log """ + Proxy started on http://#{host}:#{port}. Press CTRL+C to stop it. + """ + +program.parse process.argv diff --git a/src/index.coffee b/src/index.coffee index bf225f1..e69de29 100644 --- a/src/index.coffee +++ b/src/index.coffee @@ -1,6 +0,0 @@ -http = require 'http' -Proxy = require './proxy' - -http.globalAgent.maxSockets = Infinity - -new Proxy 8080 diff --git a/src/proxy.coffee b/src/proxy.coffee index 2bddd76..804c0a1 100644 --- a/src/proxy.coffee +++ b/src/proxy.coffee @@ -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 diff --git a/src/request.coffee b/src/request.coffee index 044a16d..633ece8 100644 --- a/src/request.coffee +++ b/src/request.coffee @@ -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