├── .gitignore ├── file ├── README.md ├── lib │ └── main.js ├── package.json ├── tests │ └── file_spec.js └── vendor │ └── minitest.js │ ├── README.md │ ├── colours.js │ └── minitest.js ├── package.json ├── pool ├── README.md ├── main.js └── package.json └── streams ├── README.md ├── lib └── main.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /file/README.md: -------------------------------------------------------------------------------- 1 | # File - Common higher level file and path operations 2 | 3 | ## Install 4 | 5 |
 6 |   npm install file
 7 | 
8 | 9 | ## API 10 | 11 | ### file.walk(start, callback) 12 | 13 | Navigates a file tree, calling callback for each directory, passing in (null, dirPath, dirs, files). 14 | 15 | 16 | ### file.walkSync(start, callback) 17 | 18 | Like file.walk but synchronous. 19 | 20 | 21 | ### file.mkdirs(path, callback) 22 | 23 | Makes all the directories in a path. (analgous to mkdir -P) For example given a path like "test/this/path" in an empty directory, mkdirs would make the directories "test", "this" and "path". 24 | 25 | 26 | ### file.mkdirsSync(path) 27 | 28 | Like file.mkdirs but synchronous. 29 | 30 | 31 | ### file.path.abspath(path) 32 | 33 | Expands ".", "..", "~" and non root paths to their full absolute path. Relative paths default to being children of the current working directory. 34 | 35 | 36 | ### file.path.relpath(root, fullPath) 37 | 38 | Given a root path, and a fullPath attempts to diff between the two to give us an acurate path relative to root. 39 | 40 | 41 | ### file.path.join(head, tail) 42 | 43 | Just like path.join but haves a little more sanely when give a head equal to "". file.path.join("", "tail") returns "tail", path.join("", "tail") returns "/tail" 44 | -------------------------------------------------------------------------------- /file/lib/main.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs'); 3 | 4 | exports.mkdirs = function (_path, mode, callback) { 5 | _path = exports.path.abspath(_path); 6 | 7 | var dirs = _path.split("/"); 8 | var walker = [dirs.shift()]; 9 | 10 | var walk = function (ds, acc, m, cb) { 11 | if (ds.length > 0) { 12 | var d = ds.shift(); 13 | acc.push(d); 14 | var dir = acc.join("/"); 15 | 16 | fs.stat(dir, function (err, stat) { 17 | if (err) { 18 | // file does not exist 19 | if (err.errno == 2) { 20 | fs.mkdir(dir, m, function (erro) { 21 | if (erro && erro.errno != 17) { 22 | console.error(erro); 23 | return cb(new Error("Failed to make " + dir + "\n" + erro)); 24 | } else { 25 | return walk(ds, acc, m, cb); 26 | } 27 | }); 28 | } else { 29 | return cb(err); 30 | } 31 | } else { 32 | if (stat.isDirectory()) { 33 | return walk(ds, acc, m, cb); 34 | } else { 35 | return cb(new Error("Failed to mkdir " + dir + ": File exists\n")); 36 | } 37 | } 38 | }); 39 | } else { 40 | return cb(); 41 | } 42 | }; 43 | return walk(dirs, walker, mode, callback); 44 | }; 45 | 46 | exports.mkdirsSync = function (_path, mode) { 47 | if (_path[0] !== "/") { 48 | _path = path.join(process.cwd(), _path) 49 | } 50 | 51 | var dirs = _path.split("/"); 52 | var walker = [dirs.shift()]; 53 | 54 | dirs.reduce(function (acc, d) { 55 | acc.push(d); 56 | var dir = acc.join("/"); 57 | 58 | try { 59 | var stat = fs.statSync(dir); 60 | if (!stat.isDirectory()) { 61 | throw "Failed to mkdir " + dir + ": File exists"; 62 | } 63 | } catch (err) { 64 | fs.mkdirSync(dir, mode); 65 | } 66 | return acc; 67 | }, walker); 68 | }; 69 | 70 | exports.walk = function (start, callback) { 71 | fs.lstat(start, function (err, stat) { 72 | if (err) { return callback(err) } 73 | if (stat.isDirectory()) { 74 | 75 | fs.readdir(start, function (err, files) { 76 | var coll = files.reduce(function (acc, i) { 77 | var abspath = path.join(start, i); 78 | 79 | if (fs.statSync(abspath).isDirectory()) { 80 | exports.walk(abspath, callback); 81 | acc.dirs.push(abspath); 82 | } else { 83 | acc.names.push(abspath); 84 | } 85 | 86 | return acc; 87 | }, {"names": [], "dirs": []}); 88 | 89 | return callback(null, start, coll.dirs, coll.names); 90 | }); 91 | } else { 92 | return callback(new Error("path: " + start + " is not a directory")); 93 | } 94 | }); 95 | }; 96 | 97 | exports.walkSync = function (start, callback) { 98 | var stat = fs.statSync(start); 99 | 100 | if (stat.isDirectory()) { 101 | var filenames = fs.readdirSync(start); 102 | 103 | var coll = filenames.reduce(function (acc, name) { 104 | var abspath = path.join(start, name); 105 | 106 | if (fs.statSync(abspath).isDirectory()) { 107 | acc.dirs.push(name); 108 | } else { 109 | acc.names.push(name); 110 | } 111 | 112 | return acc; 113 | }, {"names": [], "dirs": []}); 114 | 115 | callback(start, coll.dirs, coll.names); 116 | 117 | coll.dirs.forEach(function (d) { 118 | var abspath = path.join(start, d); 119 | exports.walkSync(abspath, callback); 120 | }); 121 | 122 | } else { 123 | throw new Error("path: " + start + " is not a directory"); 124 | } 125 | }; 126 | 127 | exports.path = {}; 128 | 129 | exports.path.abspath = function (to) { 130 | var from; 131 | switch (to.charAt(0)) { 132 | case "~": from = process.env.HOME; to = to.substr(1); break 133 | case "/": from = ""; break 134 | default : from = process.cwd(); break 135 | } 136 | return path.join(from, to); 137 | } 138 | 139 | exports.path.relativePath = function (base, compare) { 140 | base = base.split("/"); 141 | compare = compare.split("/"); 142 | 143 | if (base[0] == "") { 144 | base.shift(); 145 | } 146 | 147 | if (compare[0] == "") { 148 | compare.shift(); 149 | } 150 | 151 | var l = compare.length; 152 | 153 | for (var i = 0; i < l; i++) { 154 | if (!base[i] || (base[i] != compare[i])) { 155 | return compare.slice(i).join("/"); 156 | } 157 | } 158 | 159 | return "" 160 | }; 161 | 162 | exports.path.join = function (head, tail) { 163 | if (head == "") { 164 | return tail; 165 | } else { 166 | return path.join(head, tail); 167 | } 168 | }; 169 | 170 | -------------------------------------------------------------------------------- /file/package.json: -------------------------------------------------------------------------------- 1 | { "name" : "file" 2 | , "description" : "Higher level path and file manipulation functions." 3 | , "tags" : ["file", "path", "fs", "walk"] 4 | , "version" : "0.1.0" 5 | , "author" : "Anders Conbere " 6 | , "directories" : 7 | { "lib" : "lib" } 8 | , "repository" : 9 | { "type" : "git" 10 | , "url" : "http://github.com/mikeal/node-utils.git" 11 | } 12 | , "bugs" : 13 | { "web" : "http://github.com/mikeal/node-utils/issues" } 14 | , "engines" : ["node >=0.1.90"] 15 | , "main" : "./lib/main" 16 | } 17 | -------------------------------------------------------------------------------- /file/tests/file_spec.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var sys = require("sys"); 3 | var minitest = require("../vendor/minitest.js/minitest"); 4 | var file = require("../lib/main"); 5 | var fs = require("fs"); 6 | var path = require("path"); 7 | 8 | minitest.setupListeners(); 9 | 10 | var madeDirs = []; 11 | fs.mkdir = function (dir, mode, callback) { 12 | madeDirs.push(dir); 13 | callback(); 14 | }; 15 | 16 | fs.mkdirSync = function (dir, mode) { 17 | madeDirs.push(dir); 18 | }; 19 | 20 | GLOBAL.fs = fs; 21 | 22 | minitest.context("file#mkdirs", function () { 23 | this.setup(function () { 24 | madeDirs = []; 25 | }); 26 | 27 | this.assertion("it should make all the directories in the tree", function (test) { 28 | file.mkdirs("/test/test/test/test", 0755, function(err) { 29 | assert.equal(madeDirs[0], "/test"); 30 | assert.equal(madeDirs[1], "/test/test"); 31 | assert.equal(madeDirs[2], "/test/test/test"); 32 | assert.equal(madeDirs[3], "/test/test/test/test"); 33 | test.finished(); 34 | }); 35 | }); 36 | }); 37 | 38 | minitest.context("file#mkdirsSync", function () { 39 | this.setup(function () { 40 | madeDirs = []; 41 | }); 42 | 43 | this.assertion("it should make all the directories in the tree", function (test) { 44 | file.mkdirsSync("/test/test/test/test", 0755, function(err) {}); 45 | assert.equal(madeDirs[0], "/test"); 46 | assert.equal(madeDirs[1], "/test/test"); 47 | assert.equal(madeDirs[2], "/test/test/test"); 48 | assert.equal(madeDirs[3], "/test/test/test/test"); 49 | test.finished(); 50 | }); 51 | }); 52 | 53 | minitest.context("file#walk", function () { 54 | this.assertion("it should call \"callback\" for ever file in the tree", function (test) { 55 | file.walk("/test", function(start, dirs, names) {}); 56 | test.finished(); 57 | }); 58 | }); 59 | 60 | minitest.context("file#walkSync", function () { 61 | this.assertion("it should call \"callback\" for ever file in the tree", function (test) { 62 | file.walkSync("/test", function(start, dirs, names) {}); 63 | test.finished(); 64 | }); 65 | }); 66 | 67 | minitest.context("file.path#abspath", function () { 68 | this.setup(function () {}); 69 | 70 | this.assertion("it should convert . to the current directory", function (test) { 71 | assert.equal(file.path.abspath("."), process.cwd()); 72 | assert.equal(file.path.abspath("./test/dir"), file.path.join(process.cwd(), "test/dir")); 73 | test.finished(); 74 | }); 75 | 76 | this.assertion("it should convert .. to the parrent directory", function (test) { 77 | assert.equal(file.path.abspath(".."), path.dirname(process.cwd())); 78 | assert.equal(file.path.abspath("../test/dir"), file.path.join(path.dirname(process.cwd()), "test/dir")); 79 | test.finished(); 80 | }); 81 | 82 | this.assertion("it should convert ~ to the home directory", function (test) { 83 | assert.equal(file.path.abspath("~"), file.path.join(process.env.HOME, "")); 84 | assert.equal(file.path.abspath("~/test/dir"), file.path.join(process.env.HOME, "test/dir")); 85 | test.finished(); 86 | }); 87 | 88 | this.assertion("it should not convert paths begining with /", function (test) { 89 | assert.equal(file.path.abspath("/x/y/z"), "/x/y/z"); 90 | test.finished(); 91 | }); 92 | }); 93 | 94 | 95 | minitest.context("file.path#relativePath", function () { 96 | this.setup(function () {}); 97 | 98 | this.assertion("it should return the relative path", function (test) { 99 | var rel = file.path.relativePath("/", "/test.js"); 100 | assert.equal(rel, "test.js"); 101 | 102 | var rel = file.path.relativePath("/test/loc", "/test/loc/test.js"); 103 | assert.equal(rel, "test.js"); 104 | 105 | test.finished(); 106 | }); 107 | 108 | this.assertion("it should take two equal paths and return \"\"", function (test) { 109 | var rel = file.path.relativePath("/test.js", "/test.js"); 110 | assert.equal(rel, ""); 111 | test.finished(); 112 | }); 113 | }); 114 | -------------------------------------------------------------------------------- /file/vendor/minitest.js/README.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | Simple test framework for asynchronous testing in [Node.js](http://nodejs.org/). It's trying to be as simple and explicit as possible. No magic, no wheel reinventing. Just use minitest for building your tests and the [assert library](http://nodejs.org/api.html#assert-212) for the actual helpers for testing equality etc. 4 | 5 | This is how the output looks like: 6 | 7 | ![Minitest.js output](http://github.com/botanicus/minitest.js/raw/master/minitest.png) 8 | 9 | # Setup 10 | 11 | * `require()` minitest 12 | * Use `minitest.setupListeners()` for listening on the `uncaughtException` and `exit` events. 13 | * Use `minitest.context(description, block)` for defining your contexts. Context will be usually a function or object name. 14 | * Use `#.assertion(description, block)` for defining your assertions. 15 | * Use `#.finished()` to mark test as finished. All the tests has to have it. Without this you won't be able to write solid asynchronous tests, because you can't ask only "is a and b the same?", but also "did the callback run?". 16 | * Run `node foo_test.js` to get the results. 17 | 18 | # Example 19 | 20 | var minitest = require("minitest"); 21 | var assert = require("assert"); 22 | 23 | minitest.setupListeners(); 24 | 25 | minitest.context("Context#setup()", function () { 26 | this.setup(function () { 27 | this.user = {name: "Jakub"}; 28 | }); 29 | 30 | this.assertion("it should setup listeners", function (test) { 31 | // test something via the standard assert module 32 | assert.ok(this.user) 33 | 34 | // mark test as finished 35 | test.finished(); 36 | }); 37 | 38 | this.assertion("it should be able to count", function (test) { 39 | if (2 !== 4) { 40 | // manually fail the test 41 | throw new Error("You can't count, can you?"); 42 | }; 43 | }); 44 | }); 45 | 46 | ## Formatters 47 | 48 | If you don't like minitest output, you can simply override following methods: 49 | 50 | * `Context.prototype.contextHeader()` 51 | * `Test.prototype.reportSuccess()` 52 | * `Test.prototype.reportError(error)` 53 | * `Test.prototype.reportNotRun()` 54 | 55 | All this methods are supposed to return a string and all these methods have access to `this.description`. 56 | 57 | # Common Problems in Testing Asynchronous Code 58 | 59 | ## Exceptions in Callbacks 60 | 61 | Obviously you can't catch errors which occured in callbacks. Consider following: 62 | 63 | try { 64 | db.get("botanicus", function (user) { 65 | throw new Error("You can't catch me!"); 66 | }); 67 | } catch(error) { 68 | // you'll never get in here 69 | }; 70 | 71 | ## Testing Exceptions 72 | 73 | this.assertion("should throw an error", function (test) { 74 | assert.throws(function () { 75 | throw new Error("Error occured!"); 76 | test.finished(); 77 | }); 78 | }); 79 | 80 | This obviously can't work, because exception interrupts the anonymous function we are passing as an argument for `assert.throws()`. 81 | 82 | this.assertion("should throw an error", function (test) { 83 | assert.throws(function () { 84 | throw new Error("Error occured!"); 85 | }); 86 | test.finished(); 87 | }); 88 | 89 | This is better, it will at least work, but what if there will be an error in the `assert.throws()` function and it doesn't call the anonymous function? 90 | 91 | this.assertion("should throw an error", function (test) { 92 | assert.throws(function () { 93 | test.finished(); 94 | throw new Error("Error occured!"); 95 | }); 96 | }); 97 | 98 | OK, this is better, `test.finished()` doesn't jump out of the test, so in case that the assertion will fail, we will get the proper result. However it's not perfect, because I can change `test.finished()` in future to actually jump out of the function (I probably won't do that but you can't know) plus if there would be a bug, so `test.finished()` would cause an exception, it would satisfy `assert.throws()` without actually testing the code. Well, you'd probably noticed in other tests, but still. 99 | 100 | Fortunatelly you can specify error class and expected message for `assert.throws()` in this order: `assert.throws(block, error, message)`. 101 | -------------------------------------------------------------------------------- /file/vendor/minitest.js/colours.js: -------------------------------------------------------------------------------- 1 | /* 2 | Simple module for coloured output for POSIX shells. 3 | 4 | @example 5 | colours.bold.green + "OK: " + colours.reset + description 6 | */ 7 | 8 | colours = { 9 | reset: "\x1B[0m", 10 | 11 | grey: "\x1B[0;30m", 12 | red: "\x1B[0;31m", 13 | green: "\x1B[0;32m", 14 | yellow: "\x1B[0;33m", 15 | blue: "\x1B[0;34m", 16 | magenta: "\x1B[0;35m", 17 | cyan: "\x1B[0;36m", 18 | white: "\x1B[0;37m", 19 | 20 | bold: { 21 | grey: "\x1B[1;30m", 22 | red: "\x1B[1;31m", 23 | green: "\x1B[1;32m", 24 | yellow: "\x1B[1;33m", 25 | blue: "\x1B[1;34m", 26 | magenta: "\x1B[1;35m", 27 | cyan: "\x1B[1;36m", 28 | white: "\x1B[1;37m", 29 | } 30 | }; 31 | 32 | // exports 33 | for (colour in colours) { 34 | exports[colour] = colours[colour]; 35 | }; 36 | -------------------------------------------------------------------------------- /file/vendor/minitest.js/minitest.js: -------------------------------------------------------------------------------- 1 | var sys = require("sys"); 2 | var colours = require("./colours"); 3 | 4 | /* suite */ 5 | function Suite () { 6 | this.contexts = []; 7 | }; 8 | 9 | Suite.prototype.report = function () { 10 | var suite = this; 11 | this.contexts.forEach(function(context, index) { 12 | sys.puts(context.contextHeader()); 13 | context.report(); 14 | if (suite.contexts.length === index) { 15 | sys.puts(""); 16 | }; 17 | }); 18 | }; 19 | 20 | Suite.prototype.register = function (context) { 21 | this.contexts.push(context); 22 | }; 23 | 24 | // there is only one suite instance 25 | var suite = exports.suite = new Suite(); 26 | 27 | /* context */ 28 | function Context (description, block) { 29 | this.tests = []; 30 | this.block = block; 31 | this.description = description; 32 | }; 33 | 34 | Context.prototype.run = function () { 35 | this.block.call(this); 36 | }; 37 | 38 | Context.prototype.register = function (test) { 39 | this.tests.push(test); 40 | }; 41 | 42 | Context.prototype.report = function () { 43 | this.tests.forEach(function (test) { 44 | test.report(); 45 | }); 46 | }; 47 | 48 | /* test */ 49 | function Test (description, block, setupBlock) { 50 | this.description = description; 51 | this.block = block; 52 | this.setupBlock = setupBlock; 53 | }; 54 | 55 | Test.prototype.run = function () { 56 | try { 57 | if (this.setupBlock) { 58 | this.setupBlock.call(this); 59 | }; 60 | 61 | this.block.call(this, this); 62 | } catch(error) { 63 | this.failed(error); 64 | }; 65 | }; 66 | 67 | Test.prototype.finished = function () { 68 | this.result = this.reportSuccess(); 69 | }; 70 | 71 | Test.prototype.failed = function (error) { 72 | this.result = this.reportError(error); 73 | }; 74 | 75 | Test.prototype.report = function () { 76 | if (this.result) { 77 | sys.puts(this.result); 78 | } else { 79 | sys.puts(this.reportNotFinished()); 80 | }; 81 | }; 82 | 83 | /* output formatters */ 84 | Context.prototype.contextHeader = function () { 85 | return colours.bold.yellow + "[= " + this.description + " =]" + colours.reset; 86 | }; 87 | 88 | Test.prototype.reportSuccess = function () { 89 | // return colours.bold.green + " ✔ OK: " + colours.reset + this.description; 90 | return colours.bold.green + " OK: " + colours.reset + this.description; 91 | }; 92 | 93 | Test.prototype.reportError = function (error) { 94 | var stack = error.stack.replace(/^/, " "); 95 | // return colours.bold.red + " ✖ Error: " + colours.reset + this.description + "\n" + stack; 96 | return colours.bold.red + " Error: " + colours.reset + this.description + "\n" + stack; 97 | }; 98 | 99 | Test.prototype.reportNotFinished = function () { 100 | // return colours.bold.magenta + " ✖ Didn't finished: " + colours.reset + this.description; 101 | return colours.bold.magenta + " Didn't finished: " + colours.reset + this.description; 102 | }; 103 | 104 | /* DSL */ 105 | function context (description, block) { 106 | var context = new Context(description, block); 107 | suite.register(context); 108 | context.run(); 109 | }; 110 | 111 | /* 112 | Run an example and print if it was successful or not. 113 | 114 | @example 115 | minitest.context("setup()", function () { 116 | this.assertion("Default value should be 0", function (test) { 117 | assert.equal(value, 0); 118 | test.finished(); 119 | }); 120 | }); 121 | */ 122 | Context.prototype.assertion = function (description, block) { 123 | var test = new Test(description, block, this.setupBlock); 124 | this.register(test); 125 | test.run(); 126 | }; 127 | 128 | Context.prototype.setup = function (block) { 129 | this.setupBlock = block; 130 | }; 131 | 132 | function runAtExit () { 133 | process.addListener("exit", function () { 134 | suite.report(); 135 | }); 136 | }; 137 | 138 | function setupUncaughtExceptionListener () { 139 | // TODO: is there any way how to get the test instance, 140 | // so we could just set test.result, so everything would be 141 | // reported properly on the correct place, not in the middle of tests 142 | process.addListener("uncaughtException", function (error) { 143 | sys.puts(Test.prototype.reportError(error)); 144 | }); 145 | }; 146 | 147 | function setupListeners () { 148 | setupUncaughtExceptionListener(); 149 | runAtExit(); 150 | }; 151 | 152 | /* exports */ 153 | exports.Context = Context; 154 | exports.Test = Test; 155 | exports.context = context; 156 | exports.runAtExit = runAtExit; 157 | exports.setupUncaughtExceptionListener = setupUncaughtExceptionListener; 158 | exports.setupListeners = setupListeners; 159 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeal/node-utils/3ff43df540a266bebf3fd3349b35ca7f23e80b4d/package.json -------------------------------------------------------------------------------- /pool/README.md: -------------------------------------------------------------------------------- 1 | # Pool -- Simple HTTP client pooling 2 | 3 | ## Install 4 | 5 |
 6 |   npm install pool
 7 | 
8 | 9 | ## Super simple to use 10 | 11 | Pool has two core usage scenarios: creating a pool and creating a set of pools. Creating a pool is easy: 12 | 13 |
14 |   var pool = require('pool'),
15 |       sys = require('sys'),
16 |       local = pool.createPool('80', 'localhost');
17 | 
18 |   client = local.request('GET', '/', function (request) {
19 |     // You can work with the request here just as you would as if it 
20 |     // was returned from http.createClient
21 |     request.on('end', function () {
22 |       sys.puts('Request ended');
23 |     });
24 |   });
25 | 
26 | 27 | Creating a set of pools can be accomplished using a PoolManager: 28 | 29 |
30 |   var pool = require('pool'),
31 |       manager = pool.createPoolManager(),
32 |       local = manager.getPool('80', 'localhost');
33 | 
34 |   client = local.request('GET', '/', function (request) {
35 |     // You can work with the request here just as you would as if it 
36 |     // was returned from http.createClient
37 |     request.on('end', function () {
38 |       sys.puts('Request ended');
39 |     });        
40 |   });
41 | 
-------------------------------------------------------------------------------- /pool/main.js: -------------------------------------------------------------------------------- 1 | var sys = require('sys') 2 | , http = require('http') 3 | , events = require('events') 4 | ; 5 | 6 | function Pool (port, host, https, credentials) { 7 | this.port = port; 8 | this.host = host; 9 | this.https = https; 10 | this.credentials = credentials; 11 | this.clients = []; 12 | this.pending = []; 13 | this.minClients = 0; 14 | this.maxClients = 8; 15 | } 16 | sys.inherits(Pool, events.EventEmitter); 17 | Pool.prototype.getClient = function (cb) { 18 | for (var i=0;i this.maxClients) { 27 | this.clients[i].end(); 28 | this.clients.splice(i, 1); 29 | i-=1; 30 | } else { 31 | return cb(this.clients[i]); 32 | } 33 | } 34 | } 35 | if (this.clients.length >= this.maxClients) { 36 | this.pending.push(cb); 37 | } else { 38 | var client = http.createClient(this.port, this.host, this.https, this.credentials); 39 | this.clients.push(client); 40 | cb(client); 41 | } 42 | }; 43 | Pool.prototype.request = function () { 44 | // Argument parsing. This gets a little dicey with the 45 | // differences in defaults 46 | var method, url, headers, callback, args; 47 | var self = this; 48 | args = Array.prototype.slice.call(arguments); 49 | 50 | if (typeof args[args.length - 1] === 'function') { 51 | callback = args.pop(); 52 | } 53 | if (args[0]) method = args[0]; 54 | if (args[1]) url = args[1]; 55 | if (args[2]) headers = args[2]; 56 | 57 | if (!headers) headers = {}; 58 | if (!headers.Connection) headers.Connection = 'keep-alive'; 59 | 60 | self.getClient(function (client) { 61 | var request = client.request(method, url, headers); 62 | var errorListener = function (error) { 63 | self.emit("error", error); 64 | request.emit("error", error); 65 | } 66 | client.on("error", errorListener); 67 | request.on("response", function (response) { 68 | response.on("end", function () { 69 | client.removeListener("error", errorListener); 70 | client.busy = false; 71 | self.onFree(client); 72 | }) 73 | }) 74 | client.busy = true; 75 | callback(request); 76 | }); 77 | }; 78 | Pool.prototype.onFree = function (client) { 79 | if (this.pending.length > 0) this.pending.shift()(client); 80 | }; 81 | Pool.prototype.setMinClients = function (num) { 82 | this.minClients = num; 83 | if (this.clients.length < num) { 84 | for (var i=this.clients.length;i" 6 | , "repository" : 7 | { "type" : "git" 8 | , "url" : "http://github.com/mikeal/node-utils.git" 9 | } 10 | , "bugs" : 11 | { "web" : "http://github.com/mikeal/node-utils/issues" } 12 | , "engines" : ["node >=0.1.90"] 13 | , "main" : "./main" 14 | } 15 | -------------------------------------------------------------------------------- /streams/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeal/node-utils/3ff43df540a266bebf3fd3349b35ca7f23e80b4d/streams/README.md -------------------------------------------------------------------------------- /streams/lib/main.js: -------------------------------------------------------------------------------- 1 | var sys = require('sys') 2 | , events = require('events'); 3 | 4 | /* 5 | 6 | Experimental 7 | 8 | Simplified API for creating a Stream compatible object that can mutate data coming through the stream. 9 | 10 | // Write 4 chunks at a time. 11 | var b = []; 12 | var filter = sys.createFilter(function (chunk, write) { 13 | if (!chunk || b.length === 4) { 14 | b.forEach( function (c) {write(c)} ); 15 | } else { 16 | b.push(chunk); 17 | } 18 | }); 19 | sys.pump(readable, filter); 20 | sys.pump(filter, writable); 21 | */ 22 | 23 | function Filter(handler) { 24 | var self = this; 25 | var write = function(chunk) { 26 | self.emit('data', chunk) 27 | } 28 | 29 | self.write = function(chunk) { 30 | handler(chunk, write); 31 | } 32 | self.addListener("end", function() { 33 | handler(null, write) 34 | }) 35 | }; 36 | Filter.prototype.pause = function() { 37 | this.emit("pause") 38 | } 39 | Filter.prototype.resume = function() { 40 | this.emit("resume") 41 | } 42 | sys.inherits(Filter, events.EventEmitter) 43 | 44 | function createFilter (handler) { 45 | return new Filter(handler); 46 | }; 47 | 48 | function createMultiPump (readables, writables) { 49 | var mpump = new events.EventEmitter(); 50 | 51 | for (var i;i= readables.length) { 64 | mpump.emit("end", writable); 65 | return; 66 | } 67 | var readable = readables[writable.readableIndex] 68 | readable.resume(); 69 | if (readable.writers) { 70 | readable.writers += 1; 71 | readable.buffers.forEach(function(chunk){writable.write(chunk)}); 72 | if (readable.writers == writables.length) readable.removeListener("data", readable.bufferListener); 73 | } 74 | var pump = createPump(readable, writable); 75 | readable.pumps.push(pump); 76 | pump.removeDefaults(); 77 | pump.paused = false; 78 | pump.addListener('pause', function () { 79 | pump.paused = true; 80 | var pcount = 0; 81 | readable.pumps.forEach(function(p) {if (p.paused) pcount += 1;}); 82 | if (pcount == readable.pumps.length) readable.pause(); 83 | }) 84 | pump.addListener('resume', function () { 85 | pump.paused = false; 86 | pump.resumeListener() 87 | }); 88 | pump.addListener('end', function () { 89 | writable.readableIndex += 1; 90 | readables.pumps.splice(readables.pumps.indexOf(pump), 1); 91 | startPump(writable); 92 | }) 93 | mpump.emit("pump", pump); 94 | } 95 | 96 | writeables.forEach(function (writable) { 97 | var self = this; 98 | writable.readableIndex = 0; 99 | startPump(writable); 100 | }) 101 | 102 | mpump.endListener = function (writable) { writable.end(); }; 103 | mpump.addListener("end", mpump.endListener); 104 | 105 | return mpump; 106 | } 107 | 108 | exports.Filter = Filter; 109 | exports.createFilter = createFilter; 110 | exports.createMultiPump = createMultiPump; -------------------------------------------------------------------------------- /streams/package.json: -------------------------------------------------------------------------------- 1 | { "name" : "streams" 2 | , "description" : "Stream utilities." 3 | , "tags" : ["streams", "simple", "util", "utility"] 4 | , "version" : "0.3.0" 5 | , "author" : "Mikeal Rogers " 6 | , "repository" : 7 | { "type" : "git" 8 | , "url" : "http://github.com/mikeal/node-utils.git" 9 | } 10 | , "bugs" : 11 | { "web" : "http://github.com/mikeal/node-utils/issues" } 12 | , "engines" : ["node >=0.1.90"] 13 | , "main" : "./lib/main" 14 | } 15 | --------------------------------------------------------------------------------