lots of work so far-- mostly tidying

This commit is contained in:
2013-01-05 15:07:07 -05:00
parent 3726488bcc
commit 29873db3cf
968 changed files with 307391 additions and 0 deletions

67
node_modules/dateformat/Readme.md generated vendored Normal file
View File

@@ -0,0 +1,67 @@
# dateformat
A node.js package for Steven Levithan's excellent [dateFormat()][dateformat] function.
## Modifications
* Removed the `Date.prototype.format` method. Sorry folks, but extending native prototypes is for suckers.
* Added a `module.exports = dateFormat;` statement at the bottom
## Usage
As taken from Steven's post, modified to match the Modifications listed above:
var dateFormat = require('dateformat');
var now = new Date();
// Basic usage
dateFormat(now, "dddd, mmmm dS, yyyy, h:MM:ss TT");
// Saturday, June 9th, 2007, 5:46:21 PM
// You can use one of several named masks
dateFormat(now, "isoDateTime");
// 2007-06-09T17:46:21
// ...Or add your own
dateFormat.masks.hammerTime = 'HH:MM! "Can\'t touch this!"';
dateFormat(now, "hammerTime");
// 17:46! Can't touch this!
// When using the standalone dateFormat function,
// you can also provide the date as a string
dateFormat("Jun 9 2007", "fullDate");
// Saturday, June 9, 2007
// Note that if you don't include the mask argument,
// dateFormat.masks.default is used
dateFormat(now);
// Sat Jun 09 2007 17:46:21
// And if you don't include the date argument,
// the current date and time is used
dateFormat();
// Sat Jun 09 2007 17:46:22
// You can also skip the date argument (as long as your mask doesn't
// contain any numbers), in which case the current date/time is used
dateFormat("longTime");
// 5:46:22 PM EST
// And finally, you can convert local time to UTC time. Simply pass in
// true as an additional argument (no argument skipping allowed in this case):
dateFormat(now, "longTime", true);
// 10:46:21 PM UTC
// ...Or add the prefix "UTC:" to your mask.
dateFormat(now, "UTC:h:MM:ss TT Z");
// 10:46:21 PM UTC
// You can also get the ISO 8601 week of the year:
dateFormat(now, "W");
// 42
## License
(c) 2007-2009 Steven Levithan [stevenlevithan.com][stevenlevithan], MIT license.
[dateformat]: http://blog.stevenlevithan.com/archives/date-time-format
[stevenlevithan]: http://stevenlevithan.com/

165
node_modules/dateformat/lib/dateformat.js generated vendored Normal file
View File

@@ -0,0 +1,165 @@
/*
* Date Format 1.2.3
* (c) 2007-2009 Steven Levithan <stevenlevithan.com>
* MIT license
*
* Includes enhancements by Scott Trenda <scott.trenda.net>
* and Kris Kowal <cixar.com/~kris.kowal/>
*
* Accepts a date, a mask, or a date and a mask.
* Returns a formatted version of the given date.
* The date defaults to the current date/time.
* The mask defaults to dateFormat.masks.default.
*/
var dateFormat = function () {
var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZW]|"[^"]*"|'[^']*'/g,
timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
timezoneClip = /[^-+\dA-Z]/g,
pad = function (val, len) {
val = String(val);
len = len || 2;
while (val.length < len) val = "0" + val;
return val;
},
/**
* Get the ISO 8601 week number
* Based on comments from
* http://techblog.procurios.nl/k/n618/news/view/33796/14863/Calculate-ISO-8601-week-and-year-in-javascript.html
*/
getWeek = function (date) {
// Remove time components of date
var targetThursday = new Date(date.getFullYear(), date.getMonth(), date.getDate());
// Change date to Thursday same week
targetThursday.setDate(targetThursday.getDate() - ((targetThursday.getDay() + 6) % 7) + 3);
// Take January 4th as it is always in week 1 (see ISO 8601)
var firstThursday = new Date(targetThursday.getFullYear(), 0, 4);
// Change date to Thursday same week
firstThursday.setDate(firstThursday.getDate() - ((firstThursday.getDay() + 6) % 7) + 3);
// Check if daylight-saving-time-switch occured and correct for it
var ds = targetThursday.getTimezoneOffset() - firstThursday.getTimezoneOffset();
targetThursday.setHours(targetThursday.getHours() - ds);
// Number of weeks between target Thursday and first Thursday
var weekDiff = (targetThursday - firstThursday) / (86400000*7);
return 1 + weekDiff;
};
// Regexes and supporting functions are cached through closure
return function (date, mask, utc) {
var dF = dateFormat;
// You can't provide utc if you skip other args (use the "UTC:" mask prefix)
if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
mask = date;
date = undefined;
}
date = date || new Date;
if(!(date instanceof Date)) {
date = new Date(date);
}
if (isNaN(date)) {
throw TypeError("Invalid date");
}
mask = String(dF.masks[mask] || mask || dF.masks["default"]);
// Allow setting the utc argument via the mask
if (mask.slice(0, 4) == "UTC:") {
mask = mask.slice(4);
utc = true;
}
var _ = utc ? "getUTC" : "get",
d = date[_ + "Date"](),
D = date[_ + "Day"](),
m = date[_ + "Month"](),
y = date[_ + "FullYear"](),
H = date[_ + "Hours"](),
M = date[_ + "Minutes"](),
s = date[_ + "Seconds"](),
L = date[_ + "Milliseconds"](),
o = utc ? 0 : date.getTimezoneOffset(),
W = getWeek(date),
flags = {
d: d,
dd: pad(d),
ddd: dF.i18n.dayNames[D],
dddd: dF.i18n.dayNames[D + 7],
m: m + 1,
mm: pad(m + 1),
mmm: dF.i18n.monthNames[m],
mmmm: dF.i18n.monthNames[m + 12],
yy: String(y).slice(2),
yyyy: y,
h: H % 12 || 12,
hh: pad(H % 12 || 12),
H: H,
HH: pad(H),
M: M,
MM: pad(M),
s: s,
ss: pad(s),
l: pad(L, 3),
L: pad(L > 99 ? Math.round(L / 10) : L),
t: H < 12 ? "a" : "p",
tt: H < 12 ? "am" : "pm",
T: H < 12 ? "A" : "P",
TT: H < 12 ? "AM" : "PM",
Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10],
W: W
};
return mask.replace(token, function ($0) {
return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
});
};
}();
// Some common format strings
dateFormat.masks = {
"default": "ddd mmm dd yyyy HH:MM:ss",
shortDate: "m/d/yy",
mediumDate: "mmm d, yyyy",
longDate: "mmmm d, yyyy",
fullDate: "dddd, mmmm d, yyyy",
shortTime: "h:MM TT",
mediumTime: "h:MM:ss TT",
longTime: "h:MM:ss TT Z",
isoDate: "yyyy-mm-dd",
isoTime: "HH:MM:ss",
isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
};
// Internationalization strings
dateFormat.i18n = {
dayNames: [
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
],
monthNames: [
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
]
};
/*
// For convenience...
Date.prototype.format = function (mask, utc) {
return dateFormat(this, mask, utc);
};
*/
if (typeof exports !== "undefined") {
module.exports = dateFormat;
}

33
node_modules/dateformat/package.json generated vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"name": "dateformat",
"description": "A node.js package for Steven Levithan's excellent dateFormat() function.",
"maintainers": "Felix Geisendörfer <felix@debuggable.com>",
"homepage": "https://github.com/felixge/node-dateformat",
"author": {
"name": "Steven Levithan"
},
"contributors": [
{
"name": "Steven Levithan"
},
{
"name": "Felix Geisendörfer",
"email": "felix@debuggable.com"
},
{
"name": "Christoph Tavan",
"email": "dev@tavan.de"
}
],
"version": "1.0.4-1.2.3",
"main": "./lib/dateformat",
"dependencies": {},
"devDependencies": {},
"engines": {
"node": "*"
},
"readme": "# dateformat\n\nA node.js package for Steven Levithan's excellent [dateFormat()][dateformat] function.\n\n## Modifications\n\n* Removed the `Date.prototype.format` method. Sorry folks, but extending native prototypes is for suckers.\n* Added a `module.exports = dateFormat;` statement at the bottom\n\n## Usage\n\nAs taken from Steven's post, modified to match the Modifications listed above:\n\n var dateFormat = require('dateformat');\n var now = new Date();\n\n // Basic usage\n dateFormat(now, \"dddd, mmmm dS, yyyy, h:MM:ss TT\");\n // Saturday, June 9th, 2007, 5:46:21 PM\n\n // You can use one of several named masks\n dateFormat(now, \"isoDateTime\");\n // 2007-06-09T17:46:21\n\n // ...Or add your own\n dateFormat.masks.hammerTime = 'HH:MM! \"Can\\'t touch this!\"';\n dateFormat(now, \"hammerTime\");\n // 17:46! Can't touch this!\n\n // When using the standalone dateFormat function,\n // you can also provide the date as a string\n dateFormat(\"Jun 9 2007\", \"fullDate\");\n // Saturday, June 9, 2007\n\n // Note that if you don't include the mask argument,\n // dateFormat.masks.default is used\n dateFormat(now);\n // Sat Jun 09 2007 17:46:21\n\n // And if you don't include the date argument,\n // the current date and time is used\n dateFormat();\n // Sat Jun 09 2007 17:46:22\n\n // You can also skip the date argument (as long as your mask doesn't\n // contain any numbers), in which case the current date/time is used\n dateFormat(\"longTime\");\n // 5:46:22 PM EST\n\n // And finally, you can convert local time to UTC time. Simply pass in\n // true as an additional argument (no argument skipping allowed in this case):\n dateFormat(now, \"longTime\", true);\n // 10:46:21 PM UTC\n\n // ...Or add the prefix \"UTC:\" to your mask.\n dateFormat(now, \"UTC:h:MM:ss TT Z\");\n // 10:46:21 PM UTC\n\n // You can also get the ISO 8601 week of the year:\n dateFormat(now, \"W\");\n // 42\n## License\n\n(c) 2007-2009 Steven Levithan [stevenlevithan.com][stevenlevithan], MIT license.\n\n[dateformat]: http://blog.stevenlevithan.com/archives/date-time-format\n[stevenlevithan]: http://stevenlevithan.com/\n",
"readmeFilename": "Readme.md",
"_id": "dateformat@1.0.4-1.2.3",
"_from": "dateformat@>= 0.0.1"
}

45
node_modules/dateformat/test/basic.js generated vendored Normal file
View File

@@ -0,0 +1,45 @@
var dateFormat = require('./lib/dateformat.js');
var now = new Date();
// Basic usage
console.log(dateFormat(now, "dddd, mmmm dS, yyyy, h:MM:ss TT"));
// Saturday, June 9th, 2007, 5:46:21 PM
// You can use one of several named masks
console.log(dateFormat(now, "isoDateTime"));
// 2007-06-09T17:46:21
// ...Or add your own
dateFormat.masks.hammerTime = 'HH:MM! "Can\'t touch this!"';
console.log(dateFormat(now, "hammerTime"));
// 17:46! Can't touch this!
// When using the standalone dateFormat function,
// you can also provide the date as a string
console.log(dateFormat("Jun 9 2007", "fullDate"));
// Saturday, June 9, 2007
// Note that if you don't include the mask argument,
// dateFormat.masks.default is used
console.log(dateFormat(now));
// Sat Jun 09 2007 17:46:21
// And if you don't include the date argument,
// the current date and time is used
console.log(dateFormat());
// Sat Jun 09 2007 17:46:22
// You can also skip the date argument (as long as your mask doesn't
// contain any numbers), in which case the current date/time is used
console.log(dateFormat("longTime"));
// 5:46:22 PM EST
// And finally, you can convert local time to UTC time. Simply pass in
// true as an additional argument (no argument skipping allowed in this case):
console.log(dateFormat(now, "longTime", true));
// 10:46:21 PM UTC
// ...Or add the prefix "UTC:" to your mask.
console.log(dateFormat(now, "UTC:h:MM:ss TT Z"));
// 10:46:21 PM UTC

4
node_modules/dateformat/test/test_weekofyear.js generated vendored Normal file
View File

@@ -0,0 +1,4 @@
var dateFormat = require('../lib/dateformat.js');
var val = process.argv[2] || new Date();
console.log(dateFormat(val, 'W'));

27
node_modules/dateformat/test/test_weekofyear.sh generated vendored Normal file
View File

@@ -0,0 +1,27 @@
#!/bin/bash
# this just takes php's date() function as a reference to check if week of year
# is calculated correctly in the range from 1970 .. 2038 by brute force...
SEQ="seq"
SYSTEM=`uname`
if [ "$SYSTEM" = "Darwin" ]; then
SEQ="jot"
fi
for YEAR in {1970..2038}; do
for MONTH in {1..12}; do
DAYS=$(cal $MONTH $YEAR | egrep "28|29|30|31" |tail -1 |awk '{print $NF}')
for DAY in $( $SEQ $DAYS ); do
DATE=$YEAR-$MONTH-$DAY
echo -n $DATE ...
NODEVAL=$(node test_weekofyear.js $DATE)
PHPVAL=$(php -r "echo intval(date('W', strtotime('$DATE')));")
if [ "$NODEVAL" -ne "$PHPVAL" ]; then
echo "MISMATCH: node: $NODEVAL vs php: $PHPVAL for date $DATE"
else
echo " OK"
fi
done
done
done

4
node_modules/formidable/.npmignore generated vendored Normal file
View File

@@ -0,0 +1,4 @@
/test/tmp/
*.upload
*.un~
*.http

4
node_modules/formidable/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,4 @@
language: node_js
node_js:
- 0.4
- 0.6

14
node_modules/formidable/Makefile generated vendored Normal file
View File

@@ -0,0 +1,14 @@
SHELL := /bin/bash
test:
@./test/run.js
build: npm test
npm:
npm install .
clean:
rm test/tmp/*
.PHONY: test clean build

311
node_modules/formidable/Readme.md generated vendored Normal file
View File

@@ -0,0 +1,311 @@
# Formidable
[![Build Status](https://secure.travis-ci.org/felixge/node-formidable.png?branch=master)](http://travis-ci.org/felixge/node-formidable)
## Purpose
A node.js module for parsing form data, especially file uploads.
## Current status
This module was developed for [Transloadit](http://transloadit.com/), a service focused on uploading
and encoding images and videos. It has been battle-tested against hundreds of GB of file uploads from
a large variety of clients and is considered production-ready.
## Features
* Fast (~500mb/sec), non-buffering multipart parser
* Automatically writing file uploads to disk
* Low memory footprint
* Graceful error handling
* Very high test coverage
## Changelog
### v1.0.9
* Emit progress when content length header parsed (Tim Koschützki)
* Fix Readme syntax due to GitHub changes (goob)
* Replace references to old 'sys' module in Readme with 'util' (Peter Sugihara)
### v1.0.8
* Strip potentially unsafe characters when using `keepExtensions: true`.
* Switch to utest / urun for testing
* Add travis build
### v1.0.7
* Remove file from package that was causing problems when installing on windows. (#102)
* Fix typos in Readme (Jason Davies).
### v1.0.6
* Do not default to the default to the field name for file uploads where
filename="".
### v1.0.5
* Support filename="" in multipart parts
* Explain unexpected end() errors in parser better
**Note:** Starting with this version, formidable emits 'file' events for empty
file input fields. Previously those were incorrectly emitted as regular file
input fields with value = "".
### v1.0.4
* Detect a good default tmp directory regardless of platform. (#88)
### v1.0.3
* Fix problems with utf8 characters (#84) / semicolons in filenames (#58)
* Small performance improvements
* New test suite and fixture system
### v1.0.2
* Exclude node\_modules folder from git
* Implement new `'aborted'` event
* Fix files in example folder to work with recent node versions
* Make gently a devDependency
[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.1...v1.0.2)
### v1.0.1
* Fix package.json to refer to proper main directory. (#68, Dean Landolt)
[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.0...v1.0.1)
### v1.0.0
* Add support for multipart boundaries that are quoted strings. (Jeff Craig)
This marks the beginning of development on version 2.0 which will include
several architectural improvements.
[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.11...v1.0.0)
### v0.9.11
* Emit `'progress'` event when receiving data, regardless of parsing it. (Tim Koschützki)
* Use [W3C FileAPI Draft](http://dev.w3.org/2006/webapi/FileAPI/) properties for File class
**Important:** The old property names of the File class will be removed in a
future release.
[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.10...v0.9.11)
### Older releases
These releases were done before starting to maintain the above Changelog:
* [v0.9.10](https://github.com/felixge/node-formidable/compare/v0.9.9...v0.9.10)
* [v0.9.9](https://github.com/felixge/node-formidable/compare/v0.9.8...v0.9.9)
* [v0.9.8](https://github.com/felixge/node-formidable/compare/v0.9.7...v0.9.8)
* [v0.9.7](https://github.com/felixge/node-formidable/compare/v0.9.6...v0.9.7)
* [v0.9.6](https://github.com/felixge/node-formidable/compare/v0.9.5...v0.9.6)
* [v0.9.5](https://github.com/felixge/node-formidable/compare/v0.9.4...v0.9.5)
* [v0.9.4](https://github.com/felixge/node-formidable/compare/v0.9.3...v0.9.4)
* [v0.9.3](https://github.com/felixge/node-formidable/compare/v0.9.2...v0.9.3)
* [v0.9.2](https://github.com/felixge/node-formidable/compare/v0.9.1...v0.9.2)
* [v0.9.1](https://github.com/felixge/node-formidable/compare/v0.9.0...v0.9.1)
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
* [v0.1.0](https://github.com/felixge/node-formidable/commits/v0.1.0)
## Installation
Via [npm](http://github.com/isaacs/npm):
npm install formidable@latest
Manually:
git clone git://github.com/felixge/node-formidable.git formidable
vim my.js
# var formidable = require('./formidable');
Note: Formidable requires [gently](http://github.com/felixge/node-gently) to run the unit tests, but you won't need it for just using the library.
## Example
Parse an incoming file upload.
var formidable = require('formidable'),
http = require('http'),
util = require('util');
http.createServer(function(req, res) {
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
// parse a file upload
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
return;
}
// show a file upload form
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/upload" enctype="multipart/form-data" method="post">'+
'<input type="text" name="title"><br>'+
'<input type="file" name="upload" multiple="multiple"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
}).listen(80);
## API
### formidable.IncomingForm
__new formidable.IncomingForm()__
Creates a new incoming form.
__incomingForm.encoding = 'utf-8'__
The encoding to use for incoming form fields.
__incomingForm.uploadDir = process.env.TMP || '/tmp' || process.cwd()__
The directory for placing file uploads in. You can move them later on using
`fs.rename()`. The default directory is picked at module load time depending on
the first existing directory from those listed above.
__incomingForm.keepExtensions = false__
If you want the files written to `incomingForm.uploadDir` to include the extensions of the original files, set this property to `true`.
__incomingForm.type__
Either 'multipart' or 'urlencoded' depending on the incoming request.
__incomingForm.maxFieldsSize = 2 * 1024 * 1024__
Limits the amount of memory a field (not file) can allocate in bytes.
If this value is exceeded, an `'error'` event is emitted. The default
size is 2MB.
__incomingForm.hash = false__
If you want checksums calculated for incoming files, set this to either `'sha1'` or `'md5'`.
__incomingForm.bytesReceived__
The amount of bytes received for this form so far.
__incomingForm.bytesExpected__
The expected number of bytes in this form.
__incomingForm.parse(request, [cb])__
Parses an incoming node.js `request` containing form data. If `cb` is provided, all fields an files are collected and passed to the callback:
incomingForm.parse(req, function(err, fields, files) {
// ...
});
__incomingForm.onPart(part)__
You may overwrite this method if you are interested in directly accessing the multipart stream. Doing so will disable any `'field'` / `'file'` events processing which would occur otherwise, making you fully responsible for handling the processing.
incomingForm.onPart = function(part) {
part.addListener('data', function() {
// ...
});
}
If you want to use formidable to only handle certain parts for you, you can do so:
incomingForm.onPart = function(part) {
if (!part.filename) {
// let formidable handle all non-file parts
incomingForm.handlePart(part);
}
}
Check the code in this method for further inspiration.
__Event: 'progress' (bytesReceived, bytesExpected)__
Emitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar.
__Event: 'field' (name, value)__
Emitted whenever a field / value pair has been received.
__Event: 'fileBegin' (name, file)__
Emitted whenever a new file is detected in the upload stream. Use this even if
you want to stream the file to somewhere else while buffering the upload on
the file system.
__Event: 'file' (name, file)__
Emitted whenever a field / file pair has been received. `file` is an instance of `File`.
__Event: 'error' (err)__
Emitted when there is an error processing the incoming form. A request that experiences an error is automatically paused, you will have to manually call `request.resume()` if you want the request to continue firing `'data'` events.
__Event: 'aborted'__
Emitted when the request was aborted by the user. Right now this can be due to a 'timeout' or 'close' event on the socket. In the future there will be a separate 'timeout' event (needs a change in the node core).
__Event: 'end' ()__
Emitted when the entire request has been received, and all contained files have finished flushing to disk. This is a great place for you to send your response.
### formidable.File
__file.size = 0__
The size of the uploaded file in bytes. If the file is still being uploaded (see `'fileBegin'` event), this property says how many bytes of the file have been written to disk yet.
__file.path = null__
The path this file is being written to. You can modify this in the `'fileBegin'` event in
case you are unhappy with the way formidable generates a temporary path for your files.
__file.name = null__
The name this file had according to the uploading client.
__file.type = null__
The mime type of this file, according to the uploading client.
__file.lastModifiedDate = null__
A date object (or `null`) containing the time this file was last written to. Mostly
here for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/).
__file.hash = null__
If hash calculation was set, you can read the hex digest out of this var.
## License
Formidable is licensed under the MIT license.
## Ports
* [multipart-parser](http://github.com/FooBarWidget/multipart-parser): a C++ parser based on formidable
## Credits
* [Ryan Dahl](http://twitter.com/ryah) for his work on [http-parser](http://github.com/ry/http-parser) which heavily inspired multipart_parser.js

3
node_modules/formidable/TODO generated vendored Normal file
View File

@@ -0,0 +1,3 @@
- Better bufferMaxSize handling approach
- Add tests for JSON parser pull request and merge it
- Implement QuerystringParser the same way as MultipartParser

View File

@@ -0,0 +1,70 @@
require('../test/common');
var multipartParser = require('../lib/multipart_parser'),
MultipartParser = multipartParser.MultipartParser,
parser = new MultipartParser(),
Buffer = require('buffer').Buffer,
boundary = '-----------------------------168072824752491622650073',
mb = 100,
buffer = createMultipartBuffer(boundary, mb * 1024 * 1024),
callbacks =
{ partBegin: -1,
partEnd: -1,
headerField: -1,
headerValue: -1,
partData: -1,
end: -1,
};
parser.initWithBoundary(boundary);
parser.onHeaderField = function() {
callbacks.headerField++;
};
parser.onHeaderValue = function() {
callbacks.headerValue++;
};
parser.onPartBegin = function() {
callbacks.partBegin++;
};
parser.onPartData = function() {
callbacks.partData++;
};
parser.onPartEnd = function() {
callbacks.partEnd++;
};
parser.onEnd = function() {
callbacks.end++;
};
var start = +new Date(),
nparsed = parser.write(buffer),
duration = +new Date - start,
mbPerSec = (mb / (duration / 1000)).toFixed(2);
console.log(mbPerSec+' mb/sec');
assert.equal(nparsed, buffer.length);
function createMultipartBuffer(boundary, size) {
var head =
'--'+boundary+'\r\n'
+ 'content-disposition: form-data; name="field1"\r\n'
+ '\r\n'
, tail = '\r\n--'+boundary+'--\r\n'
, buffer = new Buffer(size);
buffer.write(head, 'ascii', 0);
buffer.write(tail, 'ascii', buffer.length - tail.length);
return buffer;
}
process.on('exit', function() {
for (var k in callbacks) {
assert.equal(0, callbacks[k], k+' count off by '+callbacks[k]);
}
});

43
node_modules/formidable/example/post.js generated vendored Normal file
View File

@@ -0,0 +1,43 @@
require('../test/common');
var http = require('http'),
util = require('util'),
formidable = require('formidable'),
server;
server = http.createServer(function(req, res) {
if (req.url == '/') {
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/post" method="post">'+
'<input type="text" name="title"><br>'+
'<input type="text" name="data[foo][]"><br>'+
'<input type="submit" value="Submit">'+
'</form>'
);
} else if (req.url == '/post') {
var form = new formidable.IncomingForm(),
fields = [];
form
.on('error', function(err) {
res.writeHead(200, {'content-type': 'text/plain'});
res.end('error:\n\n'+util.inspect(err));
})
.on('field', function(field, value) {
console.log(field, value);
fields.push([field, value]);
})
.on('end', function() {
console.log('-> post done');
res.writeHead(200, {'content-type': 'text/plain'});
res.end('received fields:\n\n '+util.inspect(fields));
});
form.parse(req);
} else {
res.writeHead(404, {'content-type': 'text/plain'});
res.end('404');
}
});
server.listen(TEST_PORT);
console.log('listening on http://localhost:'+TEST_PORT+'/');

48
node_modules/formidable/example/upload.js generated vendored Normal file
View File

@@ -0,0 +1,48 @@
require('../test/common');
var http = require('http'),
util = require('util'),
formidable = require('formidable'),
server;
server = http.createServer(function(req, res) {
if (req.url == '/') {
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/upload" enctype="multipart/form-data" method="post">'+
'<input type="text" name="title"><br>'+
'<input type="file" name="upload" multiple="multiple"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
} else if (req.url == '/upload') {
var form = new formidable.IncomingForm(),
files = [],
fields = [];
form.uploadDir = TEST_TMP;
form
.on('field', function(field, value) {
console.log(field, value);
fields.push([field, value]);
})
.on('file', function(field, file) {
console.log(field, file);
files.push([field, file]);
})
.on('end', function() {
console.log('-> upload done');
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received fields:\n\n '+util.inspect(fields));
res.write('\n\n');
res.end('received files:\n\n '+util.inspect(files));
});
form.parse(req);
} else {
res.writeHead(404, {'content-type': 'text/plain'});
res.end('404');
}
});
server.listen(TEST_PORT);
console.log('listening on http://localhost:'+TEST_PORT+'/');

1
node_modules/formidable/index.js generated vendored Normal file
View File

@@ -0,0 +1 @@
module.exports = require('./lib/formidable');

73
node_modules/formidable/lib/file.js generated vendored Normal file
View File

@@ -0,0 +1,73 @@
if (global.GENTLY) require = GENTLY.hijack(require);
var util = require('./util'),
WriteStream = require('fs').WriteStream,
EventEmitter = require('events').EventEmitter,
crypto = require('crypto');
function File(properties) {
EventEmitter.call(this);
this.size = 0;
this.path = null;
this.name = null;
this.type = null;
this.hash = null;
this.lastModifiedDate = null;
this._writeStream = null;
for (var key in properties) {
this[key] = properties[key];
}
if(typeof this.hash === 'string') {
this.hash = crypto.createHash(properties.hash);
}
this._backwardsCompatibility();
}
module.exports = File;
util.inherits(File, EventEmitter);
// @todo Next release: Show error messages when accessing these
File.prototype._backwardsCompatibility = function() {
var self = this;
this.__defineGetter__('length', function() {
return self.size;
});
this.__defineGetter__('filename', function() {
return self.name;
});
this.__defineGetter__('mime', function() {
return self.type;
});
};
File.prototype.open = function() {
this._writeStream = new WriteStream(this.path);
};
File.prototype.write = function(buffer, cb) {
var self = this;
this._writeStream.write(buffer, function() {
if(self.hash) {
self.hash.update(buffer);
}
self.lastModifiedDate = new Date();
self.size += buffer.length;
self.emit('progress', self.size);
cb();
});
};
File.prototype.end = function(cb) {
var self = this;
this._writeStream.end(function() {
if(self.hash) {
self.hash = self.hash.digest('hex');
}
self.emit('end');
cb();
});
};

384
node_modules/formidable/lib/incoming_form.js generated vendored Normal file
View File

@@ -0,0 +1,384 @@
if (global.GENTLY) require = GENTLY.hijack(require);
var fs = require('fs');
var util = require('./util'),
path = require('path'),
File = require('./file'),
MultipartParser = require('./multipart_parser').MultipartParser,
QuerystringParser = require('./querystring_parser').QuerystringParser,
StringDecoder = require('string_decoder').StringDecoder,
EventEmitter = require('events').EventEmitter,
Stream = require('stream').Stream;
function IncomingForm(opts) {
if (!(this instanceof IncomingForm)) return new IncomingForm;
EventEmitter.call(this);
opts=opts||{};
this.error = null;
this.ended = false;
this.maxFieldsSize = opts.maxFieldsSize || 2 * 1024 * 1024;
this.keepExtensions = opts.keepExtensions || false;
this.uploadDir = opts.uploadDir || IncomingForm.UPLOAD_DIR;
this.encoding = opts.encoding || 'utf-8';
this.headers = null;
this.type = null;
this.hash = false;
this.bytesReceived = null;
this.bytesExpected = null;
this._parser = null;
this._flushing = 0;
this._fieldsSize = 0;
};
util.inherits(IncomingForm, EventEmitter);
exports.IncomingForm = IncomingForm;
IncomingForm.UPLOAD_DIR = (function() {
var dirs = [process.env.TMP, '/tmp', process.cwd()];
for (var i = 0; i < dirs.length; i++) {
var dir = dirs[i];
var isDirectory = false;
try {
isDirectory = fs.statSync(dir).isDirectory();
} catch (e) {}
if (isDirectory) return dir;
}
})();
IncomingForm.prototype.parse = function(req, cb) {
this.pause = function() {
try {
req.pause();
} catch (err) {
// the stream was destroyed
if (!this.ended) {
// before it was completed, crash & burn
this._error(err);
}
return false;
}
return true;
};
this.resume = function() {
try {
req.resume();
} catch (err) {
// the stream was destroyed
if (!this.ended) {
// before it was completed, crash & burn
this._error(err);
}
return false;
}
return true;
};
this.writeHeaders(req.headers);
var self = this;
req
.on('error', function(err) {
self._error(err);
})
.on('aborted', function() {
self.emit('aborted');
})
.on('data', function(buffer) {
self.write(buffer);
})
.on('end', function() {
if (self.error) {
return;
}
var err = self._parser.end();
if (err) {
self._error(err);
}
});
if (cb) {
var fields = {}, files = {};
this
.on('field', function(name, value) {
fields[name] = value;
})
.on('file', function(name, file) {
files[name] = file;
})
.on('error', function(err) {
cb(err, fields, files);
})
.on('end', function() {
cb(null, fields, files);
});
}
return this;
};
IncomingForm.prototype.writeHeaders = function(headers) {
this.headers = headers;
this._parseContentLength();
this._parseContentType();
};
IncomingForm.prototype.write = function(buffer) {
if (!this._parser) {
this._error(new Error('unintialized parser'));
return;
}
this.bytesReceived += buffer.length;
this.emit('progress', this.bytesReceived, this.bytesExpected);
var bytesParsed = this._parser.write(buffer);
if (bytesParsed !== buffer.length) {
this._error(new Error('parser error, '+bytesParsed+' of '+buffer.length+' bytes parsed'));
}
return bytesParsed;
};
IncomingForm.prototype.pause = function() {
// this does nothing, unless overwritten in IncomingForm.parse
return false;
};
IncomingForm.prototype.resume = function() {
// this does nothing, unless overwritten in IncomingForm.parse
return false;
};
IncomingForm.prototype.onPart = function(part) {
// this method can be overwritten by the user
this.handlePart(part);
};
IncomingForm.prototype.handlePart = function(part) {
var self = this;
if (part.filename === undefined) {
var value = ''
, decoder = new StringDecoder(this.encoding);
part.on('data', function(buffer) {
self._fieldsSize += buffer.length;
if (self._fieldsSize > self.maxFieldsSize) {
self._error(new Error('maxFieldsSize exceeded, received '+self._fieldsSize+' bytes of field data'));
return;
}
value += decoder.write(buffer);
});
part.on('end', function() {
self.emit('field', part.name, value);
});
return;
}
this._flushing++;
var file = new File({
path: this._uploadPath(part.filename),
name: part.filename,
type: part.mime,
hash: self.hash
});
this.emit('fileBegin', part.name, file);
file.open();
part.on('data', function(buffer) {
self.pause();
file.write(buffer, function() {
self.resume();
});
});
part.on('end', function() {
file.end(function() {
self._flushing--;
self.emit('file', part.name, file);
self._maybeEnd();
});
});
};
IncomingForm.prototype._parseContentType = function() {
if (!this.headers['content-type']) {
this._error(new Error('bad content-type header, no content-type'));
return;
}
if (this.headers['content-type'].match(/urlencoded/i)) {
this._initUrlencoded();
return;
}
if (this.headers['content-type'].match(/multipart/i)) {
var m;
if (m = this.headers['content-type'].match(/boundary=(?:"([^"]+)"|([^;]+))/i)) {
this._initMultipart(m[1] || m[2]);
} else {
this._error(new Error('bad content-type header, no multipart boundary'));
}
return;
}
this._error(new Error('bad content-type header, unknown content-type: '+this.headers['content-type']));
};
IncomingForm.prototype._error = function(err) {
if (this.error) {
return;
}
this.error = err;
this.pause();
this.emit('error', err);
};
IncomingForm.prototype._parseContentLength = function() {
if (this.headers['content-length']) {
this.bytesReceived = 0;
this.bytesExpected = parseInt(this.headers['content-length'], 10);
this.emit('progress', this.bytesReceived, this.bytesExpected);
}
};
IncomingForm.prototype._newParser = function() {
return new MultipartParser();
};
IncomingForm.prototype._initMultipart = function(boundary) {
this.type = 'multipart';
var parser = new MultipartParser(),
self = this,
headerField,
headerValue,
part;
parser.initWithBoundary(boundary);
parser.onPartBegin = function() {
part = new Stream();
part.readable = true;
part.headers = {};
part.name = null;
part.filename = null;
part.mime = null;
headerField = '';
headerValue = '';
};
parser.onHeaderField = function(b, start, end) {
headerField += b.toString(self.encoding, start, end);
};
parser.onHeaderValue = function(b, start, end) {
headerValue += b.toString(self.encoding, start, end);
};
parser.onHeaderEnd = function() {
headerField = headerField.toLowerCase();
part.headers[headerField] = headerValue;
var m;
if (headerField == 'content-disposition') {
if (m = headerValue.match(/name="([^"]+)"/i)) {
part.name = m[1];
}
part.filename = self._fileName(headerValue);
} else if (headerField == 'content-type') {
part.mime = headerValue;
}
headerField = '';
headerValue = '';
};
parser.onHeadersEnd = function() {
self.onPart(part);
};
parser.onPartData = function(b, start, end) {
part.emit('data', b.slice(start, end));
};
parser.onPartEnd = function() {
part.emit('end');
};
parser.onEnd = function() {
self.ended = true;
self._maybeEnd();
};
this._parser = parser;
};
IncomingForm.prototype._fileName = function(headerValue) {
var m = headerValue.match(/filename="(.*?)"($|; )/i)
if (!m) return;
var filename = m[1].substr(m[1].lastIndexOf('\\') + 1);
filename = filename.replace(/%22/g, '"');
filename = filename.replace(/&#([\d]{4});/g, function(m, code) {
return String.fromCharCode(code);
});
return filename;
};
IncomingForm.prototype._initUrlencoded = function() {
this.type = 'urlencoded';
var parser = new QuerystringParser()
, self = this;
parser.onField = function(key, val) {
self.emit('field', key, val);
};
parser.onEnd = function() {
self.ended = true;
self._maybeEnd();
};
this._parser = parser;
};
IncomingForm.prototype._uploadPath = function(filename) {
var name = '';
for (var i = 0; i < 32; i++) {
name += Math.floor(Math.random() * 16).toString(16);
}
if (this.keepExtensions) {
var ext = path.extname(filename);
ext = ext.replace(/(\.[a-z0-9]+).*/, '$1')
name += ext;
}
return path.join(this.uploadDir, name);
};
IncomingForm.prototype._maybeEnd = function() {
if (!this.ended || this._flushing) {
return;
}
this.emit('end');
};

3
node_modules/formidable/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,3 @@
var IncomingForm = require('./incoming_form').IncomingForm;
IncomingForm.IncomingForm = IncomingForm;
module.exports = IncomingForm;

312
node_modules/formidable/lib/multipart_parser.js generated vendored Normal file
View File

@@ -0,0 +1,312 @@
var Buffer = require('buffer').Buffer,
s = 0,
S =
{ PARSER_UNINITIALIZED: s++,
START: s++,
START_BOUNDARY: s++,
HEADER_FIELD_START: s++,
HEADER_FIELD: s++,
HEADER_VALUE_START: s++,
HEADER_VALUE: s++,
HEADER_VALUE_ALMOST_DONE: s++,
HEADERS_ALMOST_DONE: s++,
PART_DATA_START: s++,
PART_DATA: s++,
PART_END: s++,
END: s++,
},
f = 1,
F =
{ PART_BOUNDARY: f,
LAST_BOUNDARY: f *= 2,
},
LF = 10,
CR = 13,
SPACE = 32,
HYPHEN = 45,
COLON = 58,
A = 97,
Z = 122,
lower = function(c) {
return c | 0x20;
};
for (var s in S) {
exports[s] = S[s];
}
function MultipartParser() {
this.boundary = null;
this.boundaryChars = null;
this.lookbehind = null;
this.state = S.PARSER_UNINITIALIZED;
this.index = null;
this.flags = 0;
};
exports.MultipartParser = MultipartParser;
MultipartParser.stateToString = function(stateNumber) {
for (var state in S) {
var number = S[state];
if (number === stateNumber) return state;
}
};
MultipartParser.prototype.initWithBoundary = function(str) {
this.boundary = new Buffer(str.length+4);
this.boundary.write('\r\n--', 'ascii', 0);
this.boundary.write(str, 'ascii', 4);
this.lookbehind = new Buffer(this.boundary.length+8);
this.state = S.START;
this.boundaryChars = {};
for (var i = 0; i < this.boundary.length; i++) {
this.boundaryChars[this.boundary[i]] = true;
}
};
MultipartParser.prototype.write = function(buffer) {
var self = this,
i = 0,
len = buffer.length,
prevIndex = this.index,
index = this.index,
state = this.state,
flags = this.flags,
lookbehind = this.lookbehind,
boundary = this.boundary,
boundaryChars = this.boundaryChars,
boundaryLength = this.boundary.length,
boundaryEnd = boundaryLength - 1,
bufferLength = buffer.length,
c,
cl,
mark = function(name) {
self[name+'Mark'] = i;
},
clear = function(name) {
delete self[name+'Mark'];
},
callback = function(name, buffer, start, end) {
if (start !== undefined && start === end) {
return;
}
var callbackSymbol = 'on'+name.substr(0, 1).toUpperCase()+name.substr(1);
if (callbackSymbol in self) {
self[callbackSymbol](buffer, start, end);
}
},
dataCallback = function(name, clear) {
var markSymbol = name+'Mark';
if (!(markSymbol in self)) {
return;
}
if (!clear) {
callback(name, buffer, self[markSymbol], buffer.length);
self[markSymbol] = 0;
} else {
callback(name, buffer, self[markSymbol], i);
delete self[markSymbol];
}
};
for (i = 0; i < len; i++) {
c = buffer[i];
switch (state) {
case S.PARSER_UNINITIALIZED:
return i;
case S.START:
index = 0;
state = S.START_BOUNDARY;
case S.START_BOUNDARY:
if (index == boundary.length - 2) {
if (c != CR) {
return i;
}
index++;
break;
} else if (index - 1 == boundary.length - 2) {
if (c != LF) {
return i;
}
index = 0;
callback('partBegin');
state = S.HEADER_FIELD_START;
break;
}
if (c != boundary[index+2]) {
return i;
}
index++;
break;
case S.HEADER_FIELD_START:
state = S.HEADER_FIELD;
mark('headerField');
index = 0;
case S.HEADER_FIELD:
if (c == CR) {
clear('headerField');
state = S.HEADERS_ALMOST_DONE;
break;
}
index++;
if (c == HYPHEN) {
break;
}
if (c == COLON) {
if (index == 1) {
// empty header field
return i;
}
dataCallback('headerField', true);
state = S.HEADER_VALUE_START;
break;
}
cl = lower(c);
if (cl < A || cl > Z) {
return i;
}
break;
case S.HEADER_VALUE_START:
if (c == SPACE) {
break;
}
mark('headerValue');
state = S.HEADER_VALUE;
case S.HEADER_VALUE:
if (c == CR) {
dataCallback('headerValue', true);
callback('headerEnd');
state = S.HEADER_VALUE_ALMOST_DONE;
}
break;
case S.HEADER_VALUE_ALMOST_DONE:
if (c != LF) {
return i;
}
state = S.HEADER_FIELD_START;
break;
case S.HEADERS_ALMOST_DONE:
if (c != LF) {
return i;
}
callback('headersEnd');
state = S.PART_DATA_START;
break;
case S.PART_DATA_START:
state = S.PART_DATA
mark('partData');
case S.PART_DATA:
prevIndex = index;
if (index == 0) {
// boyer-moore derrived algorithm to safely skip non-boundary data
i += boundaryEnd;
while (i < bufferLength && !(buffer[i] in boundaryChars)) {
i += boundaryLength;
}
i -= boundaryEnd;
c = buffer[i];
}
if (index < boundary.length) {
if (boundary[index] == c) {
if (index == 0) {
dataCallback('partData', true);
}
index++;
} else {
index = 0;
}
} else if (index == boundary.length) {
index++;
if (c == CR) {
// CR = part boundary
flags |= F.PART_BOUNDARY;
} else if (c == HYPHEN) {
// HYPHEN = end boundary
flags |= F.LAST_BOUNDARY;
} else {
index = 0;
}
} else if (index - 1 == boundary.length) {
if (flags & F.PART_BOUNDARY) {
index = 0;
if (c == LF) {
// unset the PART_BOUNDARY flag
flags &= ~F.PART_BOUNDARY;
callback('partEnd');
callback('partBegin');
state = S.HEADER_FIELD_START;
break;
}
} else if (flags & F.LAST_BOUNDARY) {
if (c == HYPHEN) {
callback('partEnd');
callback('end');
state = S.END;
} else {
index = 0;
}
} else {
index = 0;
}
}
if (index > 0) {
// when matching a possible boundary, keep a lookbehind reference
// in case it turns out to be a false lead
lookbehind[index-1] = c;
} else if (prevIndex > 0) {
// if our boundary turned out to be rubbish, the captured lookbehind
// belongs to partData
callback('partData', lookbehind, 0, prevIndex);
prevIndex = 0;
mark('partData');
// reconsider the current character even so it interrupted the sequence
// it could be the beginning of a new sequence
i--;
}
break;
case S.END:
break;
default:
return i;
}
}
dataCallback('headerField');
dataCallback('headerValue');
dataCallback('partData');
this.index = index;
this.state = state;
this.flags = flags;
return len;
};
MultipartParser.prototype.end = function() {
if (this.state != S.END) {
return new Error('MultipartParser.end(): stream ended unexpectedly: ' + this.explain());
}
};
MultipartParser.prototype.explain = function() {
return 'state = ' + MultipartParser.stateToString(this.state);
};

25
node_modules/formidable/lib/querystring_parser.js generated vendored Normal file
View File

@@ -0,0 +1,25 @@
if (global.GENTLY) require = GENTLY.hijack(require);
// This is a buffering parser, not quite as nice as the multipart one.
// If I find time I'll rewrite this to be fully streaming as well
var querystring = require('querystring');
function QuerystringParser() {
this.buffer = '';
};
exports.QuerystringParser = QuerystringParser;
QuerystringParser.prototype.write = function(buffer) {
this.buffer += buffer.toString('ascii');
return buffer.length;
};
QuerystringParser.prototype.end = function() {
var fields = querystring.parse(this.buffer);
for (var field in fields) {
this.onField(field, fields[field]);
}
this.buffer = '';
this.onEnd();
};

6
node_modules/formidable/lib/util.js generated vendored Normal file
View File

@@ -0,0 +1,6 @@
// Backwards compatibility ...
try {
module.exports = require('util');
} catch (e) {
module.exports = require('sys');
}

4
node_modules/formidable/node-gently/Makefile generated vendored Normal file
View File

@@ -0,0 +1,4 @@
test:
@find test/simple/test-*.js | xargs -n 1 -t node
.PHONY: test

167
node_modules/formidable/node-gently/Readme.md generated vendored Normal file
View File

@@ -0,0 +1,167 @@
# Gently
## Purpose
A node.js module that helps with stubbing and behavior verification. It allows you to test the most remote and nested corners of your code while keeping being fully unobtrusive.
## Features
* Overwrite and stub individual object functions
* Verify that all expected calls have been made in the expected order
* Restore stubbed functions to their original behavior
* Detect object / class names from obj.constructor.name and obj.toString()
* Hijack any required module function or class constructor
## Installation
Via [npm](http://github.com/isaacs/npm):
npm install gently@latest
## Example
Make sure your dog is working properly:
function Dog() {}
Dog.prototype.seeCat = function() {
this.bark('whuf, whuf');
this.run();
}
Dog.prototype.bark = function(bark) {
require('sys').puts(bark);
}
var gently = new (require('gently'))
, assert = require('assert')
, dog = new Dog();
gently.expect(dog, 'bark', function(bark) {
assert.equal(bark, 'whuf, whuf');
});
gently.expect(dog, 'run');
dog.seeCat();
You can also easily test event emitters with this, for example a simple sequence of 2 events emitted by `fs.WriteStream`:
var gently = new (require('gently'))
, stream = new (require('fs').WriteStream)('my_file.txt');
gently.expect(stream, 'emit', function(event) {
assert.equal(event, 'open');
});
gently.expect(stream, 'emit', function(event) {
assert.equal(event, 'drain');
});
For a full read world example, check out this test case: [test-incoming-form.js](http://github.com/felixge/node-formidable/blob/master/test/simple/test-incoming-form.js) (in [node-formdiable](http://github.com/felixge/node-formidable)).
## API
### Gently
#### new Gently()
Creates a new gently instance. It listens to the process `'exit'` event to make sure all expectations have been verified.
#### gently.expect(obj, method, [[count], stubFn])
Creates an expectation for an objects method to be called. You can optionally specify the call `count` you are expecting, as well as `stubFn` function that will run instead of the original function.
Returns a reference to the function that is getting overwritten.
#### gently.expect([count], stubFn)
Returns a function that is supposed to be executed `count` times, delegating any calls to the provided `stubFn` function. Naming your stubFn closure will help to properly diagnose errors that are being thrown:
childProcess.exec('ls', gently.expect(function lsCallback(code) {
assert.equal(0, code);
}));
#### gently.restore(obj, method)
Restores an object method that has been previously overwritten using `gently.expect()`.
#### gently.hijack(realRequire)
Returns a new require functions that catches a reference to all required modules into `gently.hijacked`.
To use this function, include a line like this in your `'my-module.js'`.
if (global.GENTLY) require = GENTLY.hijack(require);
var sys = require('sys');
exports.hello = function() {
sys.log('world');
};
Now you can write a test for the module above:
var gently = global.GENTLY = new (require('gently'))
, myModule = require('./my-module');
gently.expect(gently.hijacked.sys, 'log', function(str) {
assert.equal(str, 'world');
});
myModule.hello();
#### gently.stub(location, [exportsName])
Returns a stub class that will be used instead of the real class from the module at `location` with the given `exportsName`.
This allows to test an OOP version of the previous example, where `'my-module.js'`.
if (global.GENTLY) require = GENTLY.hijack(require);
var World = require('./world');
exports.hello = function() {
var world = new World();
world.hello();
}
And `world.js` looks like this:
var sys = require('sys');
function World() {
}
module.exports = World;
World.prototype.hello = function() {
sys.log('world');
};
Testing `'my-module.js'` can now easily be accomplished:
var gently = global.GENTLY = new (require('gently'))
, WorldStub = gently.stub('./world')
, myModule = require('./my-module')
, WORLD;
gently.expect(WorldStub, 'new', function() {
WORLD = this;
});
gently.expect(WORLD, 'hello');
myModule.hello();
#### gently.hijacked
An object that holds the references to all hijacked modules.
#### gently.verify([msg])
Verifies that all expectations of this gently instance have been satisfied. If not called manually, this method is called when the process `'exit'` event is fired.
If `msg` is given, it will appear in any error that might be thrown.
## License
Gently is licensed under the MIT license.

22
node_modules/formidable/node-gently/example/dog.js generated vendored Normal file
View File

@@ -0,0 +1,22 @@
require('../test/common');
function Dog() {}
Dog.prototype.seeCat = function() {
this.bark('whuf, whuf');
this.run();
}
Dog.prototype.bark = function(bark) {
require('sys').puts(bark);
}
var gently = new (require('gently'))
, assert = require('assert')
, dog = new Dog();
gently.expect(dog, 'bark', function(bark) {
assert.equal(bark, 'whuf, whuf');
});
gently.expect(dog, 'run');
dog.seeCat();

View File

@@ -0,0 +1,11 @@
require('../test/common');
var gently = new (require('gently'))
, stream = new (require('fs').WriteStream)('my_file.txt');
gently.expect(stream, 'emit', function(event) {
assert.equal(event, 'open');
});
gently.expect(stream, 'emit', function(event) {
assert.equal(event, 'drain');
});

1
node_modules/formidable/node-gently/index.js generated vendored Normal file
View File

@@ -0,0 +1 @@
module.exports = require('./lib/gently');

View File

@@ -0,0 +1,184 @@
var path = require('path');
function Gently() {
this.expectations = [];
this.hijacked = {};
var self = this;
process.addListener('exit', function() {
self.verify('process exit');
});
};
module.exports = Gently;
Gently.prototype.stub = function(location, exportsName) {
function Stub() {
return Stub['new'].apply(this, arguments);
};
Stub['new'] = function () {};
var stubName = 'require('+JSON.stringify(location)+')';
if (exportsName) {
stubName += '.'+exportsName;
}
Stub.prototype.toString = Stub.toString = function() {
return stubName;
};
var exports = this.hijacked[location] || {};
if (exportsName) {
exports[exportsName] = Stub;
} else {
exports = Stub;
}
this.hijacked[location] = exports;
return Stub;
};
Gently.prototype.hijack = function(realRequire) {
var self = this;
return function(location) {
return self.hijacked[location] = (self.hijacked[location])
? self.hijacked[location]
: realRequire(location);
};
};
Gently.prototype.expect = function(obj, method, count, stubFn) {
if (typeof obj != 'function' && typeof obj != 'object' && typeof obj != 'number') {
throw new Error
( 'Bad 1st argument for gently.expect(), '
+ 'object, function, or number expected, got: '+(typeof obj)
);
} else if (typeof obj == 'function' && (typeof method != 'string')) {
// expect(stubFn) interface
stubFn = obj;
obj = null;
method = null;
count = 1;
} else if (typeof method == 'function') {
// expect(count, stubFn) interface
count = obj;
stubFn = method;
obj = null;
method = null;
} else if (typeof count == 'function') {
// expect(obj, method, stubFn) interface
stubFn = count;
count = 1;
} else if (count === undefined) {
// expect(obj, method) interface
count = 1;
}
var name = this._name(obj, method, stubFn);
this.expectations.push({obj: obj, method: method, stubFn: stubFn, name: name, count: count});
var self = this;
function delegate() {
return self._stubFn(this, obj, method, name, Array.prototype.slice.call(arguments));
}
if (!obj) {
return delegate;
}
var original = (obj[method])
? obj[method]._original || obj[method]
: undefined;
obj[method] = delegate;
return obj[method]._original = original;
};
Gently.prototype.restore = function(obj, method) {
if (!obj[method] || !obj[method]._original) {
throw new Error(this._name(obj, method)+' is not gently stubbed');
}
obj[method] = obj[method]._original;
};
Gently.prototype.verify = function(msg) {
if (!this.expectations.length) {
return;
}
var validExpectations = [];
for (var i = 0, l = this.expectations.length; i < l; i++) {
var expectation = this.expectations[i];
if (expectation.count > 0) {
validExpectations.push(expectation);
}
}
this.expectations = []; // reset so that no duplicate verification attempts are made
if (!validExpectations.length) {
return;
}
var expectation = validExpectations[0];
throw new Error
( 'Expected call to '+expectation.name+' did not happen'
+ ( (msg)
? ' ('+msg+')'
: ''
)
);
};
Gently.prototype._stubFn = function(self, obj, method, name, args) {
var expectation = this.expectations[0], obj, method;
if (!expectation) {
throw new Error('Unexpected call to '+name+', no call was expected');
}
if (expectation.obj !== obj || expectation.method !== method) {
throw new Error('Unexpected call to '+name+', expected call to '+ expectation.name);
}
expectation.count -= 1;
if (expectation.count === 0) {
this.expectations.shift();
// autorestore original if its not a closure
// and no more expectations on that object
var has_more_expectations = this.expectations.reduce(function (memo, expectation) {
return memo || (expectation.obj === obj && expectation.method === method);
}, false);
if (obj !== null && method !== null && !has_more_expectations) {
if (typeof obj[method]._original !== 'undefined') {
obj[method] = obj[method]._original;
delete obj[method]._original;
} else {
delete obj[method];
}
}
}
if (expectation.stubFn) {
return expectation.stubFn.apply(self, args);
}
};
Gently.prototype._name = function(obj, method, stubFn) {
if (obj) {
var objectName = obj.toString();
if (objectName == '[object Object]' && obj.constructor.name) {
objectName = '['+obj.constructor.name+']';
}
return (objectName)+'.'+method+'()';
}
if (stubFn.name) {
return stubFn.name+'()';
}
return '>> '+stubFn.toString()+' <<';
};

View File

@@ -0,0 +1 @@
module.exports = require('./gently');

14
node_modules/formidable/node-gently/package.json generated vendored Normal file
View File

@@ -0,0 +1,14 @@
{
"name": "gently",
"version": "0.9.2",
"directories": {
"lib": "./lib/gently"
},
"main": "./lib/gently/index",
"dependencies": {},
"devDependencies": {},
"engines": {
"node": "*"
},
"optionalDependencies": {}
}

8
node_modules/formidable/node-gently/test/common.js generated vendored Normal file
View File

@@ -0,0 +1,8 @@
var path = require('path')
, sys = require('sys');
require.paths.unshift(path.dirname(__dirname)+'/lib');
global.puts = sys.puts;
global.p = function() {sys.error(sys.inspect.apply(null, arguments))};;
global.assert = require('assert');

View File

@@ -0,0 +1,348 @@
require('../common');
var Gently = require('gently')
, gently;
function test(test) {
process.removeAllListeners('exit');
gently = new Gently();
test();
}
test(function constructor() {
assert.deepEqual(gently.expectations, []);
assert.deepEqual(gently.hijacked, {});
assert.equal(gently.constructor.name, 'Gently');
});
test(function expectBadArgs() {
var BAD_ARG = 'oh no';
try {
gently.expect(BAD_ARG);
assert.ok(false, 'throw needs to happen');
} catch (e) {
assert.equal(e.message, 'Bad 1st argument for gently.expect(), object, function, or number expected, got: '+(typeof BAD_ARG));
}
});
test(function expectObjMethod() {
var OBJ = {}, NAME = 'foobar';
OBJ.foo = function(x) {
return x;
};
gently._name = function() {
return NAME;
};
var original = OBJ.foo
, stubFn = function() {};
(function testAddOne() {
assert.strictEqual(gently.expect(OBJ, 'foo', stubFn), original);
assert.equal(gently.expectations.length, 1);
var expectation = gently.expectations[0];
assert.strictEqual(expectation.obj, OBJ);
assert.strictEqual(expectation.method, 'foo');
assert.strictEqual(expectation.stubFn, stubFn);
assert.strictEqual(expectation.name, NAME);
assert.strictEqual(OBJ.foo._original, original);
})();
(function testAddTwo() {
gently.expect(OBJ, 'foo', 2, stubFn);
assert.equal(gently.expectations.length, 2);
assert.strictEqual(OBJ.foo._original, original);
})();
(function testAddOneWithoutMock() {
gently.expect(OBJ, 'foo');
assert.equal(gently.expectations.length, 3);
})();
var stubFnCalled = 0, SELF = {};
gently._stubFn = function(self, obj, method, name, args) {
stubFnCalled++;
assert.strictEqual(self, SELF);
assert.strictEqual(obj, OBJ);
assert.strictEqual(method, 'foo');
assert.strictEqual(name, NAME);
assert.deepEqual(args, [1, 2]);
return 23;
};
assert.equal(OBJ.foo.apply(SELF, [1, 2]), 23);
assert.equal(stubFnCalled, 1);
});
test(function expectClosure() {
var NAME = 'MY CLOSURE';
function closureFn() {};
gently._name = function() {
return NAME;
};
var fn = gently.expect(closureFn);
assert.equal(gently.expectations.length, 1);
var expectation = gently.expectations[0];
assert.strictEqual(expectation.obj, null);
assert.strictEqual(expectation.method, null);
assert.strictEqual(expectation.stubFn, closureFn);
assert.strictEqual(expectation.name, NAME);
var stubFnCalled = 0, SELF = {};
gently._stubFn = function(self, obj, method, name, args) {
stubFnCalled++;
assert.strictEqual(self, SELF);
assert.strictEqual(obj, null);
assert.strictEqual(method, null);
assert.strictEqual(name, NAME);
assert.deepEqual(args, [1, 2]);
return 23;
};
assert.equal(fn.apply(SELF, [1, 2]), 23);
assert.equal(stubFnCalled, 1);
});
test(function expectClosureCount() {
var stubFnCalled = 0;
function closureFn() {stubFnCalled++};
var fn = gently.expect(2, closureFn);
assert.equal(gently.expectations.length, 1);
fn();
assert.equal(gently.expectations.length, 1);
fn();
assert.equal(stubFnCalled, 2);
});
test(function restore() {
var OBJ = {}, NAME = '[my object].myFn()';
OBJ.foo = function(x) {
return x;
};
gently._name = function() {
return NAME;
};
var original = OBJ.foo;
gently.expect(OBJ, 'foo');
gently.restore(OBJ, 'foo');
assert.strictEqual(OBJ.foo, original);
(function testError() {
try {
gently.restore(OBJ, 'foo');
assert.ok(false, 'throw needs to happen');
} catch (e) {
assert.equal(e.message, NAME+' is not gently stubbed');
}
})();
});
test(function _stubFn() {
var OBJ1 = {toString: function() {return '[OBJ 1]'}}
, OBJ2 = {toString: function() {return '[OBJ 2]'}, foo: function () {return 'bar';}}
, SELF = {};
gently.expect(OBJ1, 'foo', function(x) {
assert.strictEqual(this, SELF);
return x * 2;
});
assert.equal(gently._stubFn(SELF, OBJ1, 'foo', 'dummy_name', [5]), 10);
(function testAutorestore() {
assert.equal(OBJ2.foo(), 'bar');
gently.expect(OBJ2, 'foo', function() {
return 'stubbed foo';
});
gently.expect(OBJ2, 'foo', function() {
return "didn't restore yet";
});
assert.equal(gently._stubFn(SELF, OBJ2, 'foo', 'dummy_name', []), 'stubbed foo');
assert.equal(gently._stubFn(SELF, OBJ2, 'foo', 'dummy_name', []), "didn't restore yet");
assert.equal(OBJ2.foo(), 'bar');
assert.deepEqual(gently.expectations, []);
})();
(function testNoMoreCallExpected() {
try {
gently._stubFn(SELF, OBJ1, 'foo', 'dummy_name', [5]);
assert.ok(false, 'throw needs to happen');
} catch (e) {
assert.equal(e.message, 'Unexpected call to dummy_name, no call was expected');
}
})();
(function testDifferentCallExpected() {
gently.expect(OBJ2, 'bar');
try {
gently._stubFn(SELF, OBJ1, 'foo', 'dummy_name', [5]);
assert.ok(false, 'throw needs to happen');
} catch (e) {
assert.equal(e.message, 'Unexpected call to dummy_name, expected call to '+gently._name(OBJ2, 'bar'));
}
assert.equal(gently.expectations.length, 1);
})();
(function testNoMockCallback() {
OBJ2.bar();
assert.equal(gently.expectations.length, 0);
})();
});
test(function stub() {
var LOCATION = './my_class';
(function testRegular() {
var Stub = gently.stub(LOCATION);
assert.ok(Stub instanceof Function);
assert.strictEqual(gently.hijacked[LOCATION], Stub);
assert.ok(Stub['new'] instanceof Function);
assert.equal(Stub.toString(), 'require('+JSON.stringify(LOCATION)+')');
(function testConstructor() {
var newCalled = 0
, STUB
, ARGS = ['foo', 'bar'];
Stub['new'] = function(a, b) {
assert.equal(a, ARGS[0]);
assert.equal(b, ARGS[1]);
newCalled++;
STUB = this;
};
var stub = new Stub(ARGS[0], ARGS[1]);
assert.strictEqual(stub, STUB);
assert.equal(newCalled, 1);
assert.equal(stub.toString(), 'require('+JSON.stringify(LOCATION)+')');
})();
(function testUseReturnValueAsInstance() {
var R = {};
Stub['new'] = function() {
return R;
};
var stub = new Stub();
assert.strictEqual(stub, R);
})();
})();
var EXPORTS_NAME = 'MyClass';
test(function testExportsName() {
var Stub = gently.stub(LOCATION, EXPORTS_NAME);
assert.strictEqual(gently.hijacked[LOCATION][EXPORTS_NAME], Stub);
assert.equal(Stub.toString(), 'require('+JSON.stringify(LOCATION)+').'+EXPORTS_NAME);
(function testConstructor() {
var stub = new Stub();
assert.equal(Stub.toString(), 'require('+JSON.stringify(LOCATION)+').'+EXPORTS_NAME);
})();
});
});
test(function hijack() {
var LOCATION = './foo'
, REQUIRE_CALLS = 0
, EXPORTS = {}
, REQUIRE = function() {
REQUIRE_CALLS++;
return EXPORTS;
};
var hijackedRequire = gently.hijack(REQUIRE);
hijackedRequire(LOCATION);
assert.strictEqual(gently.hijacked[LOCATION], EXPORTS);
assert.equal(REQUIRE_CALLS, 1);
// make sure we are caching the hijacked module
hijackedRequire(LOCATION);
assert.equal(REQUIRE_CALLS, 1);
});
test(function verify() {
var OBJ = {toString: function() {return '[OBJ]'}};
gently.verify();
gently.expect(OBJ, 'foo');
try {
gently.verify();
assert.ok(false, 'throw needs to happen');
} catch (e) {
assert.equal(e.message, 'Expected call to [OBJ].foo() did not happen');
}
try {
gently.verify('foo');
assert.ok(false, 'throw needs to happen');
} catch (e) {
assert.equal(e.message, 'Expected call to [OBJ].foo() did not happen (foo)');
}
});
test(function processExit() {
var verifyCalled = 0;
gently.verify = function(msg) {
verifyCalled++;
assert.equal(msg, 'process exit');
};
process.emit('exit');
assert.equal(verifyCalled, 1);
});
test(function _name() {
(function testNamedClass() {
function Foo() {};
var foo = new Foo();
assert.equal(gently._name(foo, 'bar'), '[Foo].bar()');
})();
(function testToStringPreference() {
function Foo() {};
Foo.prototype.toString = function() {
return '[Superman 123]';
};
var foo = new Foo();
assert.equal(gently._name(foo, 'bar'), '[Superman 123].bar()');
})();
(function testUnamedClass() {
var Foo = function() {};
var foo = new Foo();
assert.equal(gently._name(foo, 'bar'), foo.toString()+'.bar()');
})();
(function testNamedClosure() {
function myClosure() {};
assert.equal(gently._name(null, null, myClosure), myClosure.name+'()');
})();
(function testUnamedClosure() {
var myClosure = function() {2+2 == 5};
assert.equal(gently._name(null, null, myClosure), '>> '+myClosure.toString()+' <<');
})();
});
test(function verifyExpectNone() {
var OBJ = {toString: function() {return '[OBJ]'}};
gently.verify();
gently.expect(OBJ, 'foo', 0);
try {
gently.verify();
} catch (e) {
assert.fail('Exception should not have been thrown');
}
});

28
node_modules/formidable/package.json generated vendored Normal file

File diff suppressed because one or more lines are too long

19
node_modules/formidable/test/common.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
var mysql = require('..');
var path = require('path');
var root = path.join(__dirname, '../');
exports.dir = {
root : root,
lib : root + '/lib',
fixture : root + '/test/fixture',
tmp : root + '/test/tmp',
};
exports.port = 13532;
exports.formidable = require('..');
exports.assert = require('assert');
exports.require = function(lib) {
return require(exports.dir.lib + '/' + lib);
};

View File

@@ -0,0 +1 @@
I am a text file with a funky name!

1
node_modules/formidable/test/fixture/file/plain.txt generated vendored Normal file
View File

@@ -0,0 +1 @@
I am a plain text file

View File

@@ -0,0 +1,3 @@
* Opera does not allow submitting this file, it shows a warning to the
user that the file could not be found instead. Tested in 9.8, 11.51 on OSX.
Reported to Opera on 08.09.2011 (tracking email DSK-346009@bugs.opera.com).

View File

@@ -0,0 +1,3 @@
module.exports['generic.http'] = [
{type: 'file', name: 'upload', filename: '', fixture: 'plain.txt'},
];

View File

@@ -0,0 +1,21 @@
var properFilename = 'funkyfilename.txt';
function expect(filename) {
return [
{type: 'field', name: 'title', value: 'Weird filename'},
{type: 'file', name: 'upload', filename: filename, fixture: properFilename},
];
};
var webkit = " ? % * | \" < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt";
var ffOrIe = " ? % * | \" < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt";
module.exports = {
'osx-chrome-13.http' : expect(webkit),
'osx-firefox-3.6.http' : expect(ffOrIe),
'osx-safari-5.http' : expect(webkit),
'xp-chrome-12.http' : expect(webkit),
'xp-ie-7.http' : expect(ffOrIe),
'xp-ie-8.http' : expect(ffOrIe),
'xp-safari-5.http' : expect(webkit),
};

72
node_modules/formidable/test/fixture/multipart.js generated vendored Normal file
View File

@@ -0,0 +1,72 @@
exports['rfc1867'] =
{ boundary: 'AaB03x',
raw:
'--AaB03x\r\n'+
'content-disposition: form-data; name="field1"\r\n'+
'\r\n'+
'Joe Blow\r\nalmost tricked you!\r\n'+
'--AaB03x\r\n'+
'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+
'Content-Type: text/plain\r\n'+
'\r\n'+
'... contents of file1.txt ...\r\r\n'+
'--AaB03x--\r\n',
parts:
[ { headers: {
'content-disposition': 'form-data; name="field1"',
},
data: 'Joe Blow\r\nalmost tricked you!',
},
{ headers: {
'content-disposition': 'form-data; name="pics"; filename="file1.txt"',
'Content-Type': 'text/plain',
},
data: '... contents of file1.txt ...\r',
}
]
};
exports['noTrailing\r\n'] =
{ boundary: 'AaB03x',
raw:
'--AaB03x\r\n'+
'content-disposition: form-data; name="field1"\r\n'+
'\r\n'+
'Joe Blow\r\nalmost tricked you!\r\n'+
'--AaB03x\r\n'+
'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+
'Content-Type: text/plain\r\n'+
'\r\n'+
'... contents of file1.txt ...\r\r\n'+
'--AaB03x--',
parts:
[ { headers: {
'content-disposition': 'form-data; name="field1"',
},
data: 'Joe Blow\r\nalmost tricked you!',
},
{ headers: {
'content-disposition': 'form-data; name="pics"; filename="file1.txt"',
'Content-Type': 'text/plain',
},
data: '... contents of file1.txt ...\r',
}
]
};
exports['emptyHeader'] =
{ boundary: 'AaB03x',
raw:
'--AaB03x\r\n'+
'content-disposition: form-data; name="field1"\r\n'+
': foo\r\n'+
'\r\n'+
'Joe Blow\r\nalmost tricked you!\r\n'+
'--AaB03x\r\n'+
'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+
'Content-Type: text/plain\r\n'+
'\r\n'+
'... contents of file1.txt ...\r\r\n'+
'--AaB03x--\r\n',
expectError: true,
};

View File

@@ -0,0 +1,89 @@
var hashish = require('hashish');
var fs = require('fs');
var findit = require('findit');
var path = require('path');
var http = require('http');
var net = require('net');
var assert = require('assert');
var common = require('../common');
var formidable = common.formidable;
var server = http.createServer();
server.listen(common.port, findFixtures);
function findFixtures() {
var fixtures = [];
findit
.sync(common.dir.fixture + '/js')
.forEach(function(jsPath) {
if (!/\.js$/.test(jsPath)) return;
var group = path.basename(jsPath, '.js');
hashish.forEach(require(jsPath), function(fixture, name) {
fixtures.push({
name : group + '/' + name,
fixture : fixture,
});
});
});
testNext(fixtures);
}
function testNext(fixtures) {
var fixture = fixtures.shift();
if (!fixture) return server.close();
var name = fixture.name;
var fixture = fixture.fixture;
uploadFixture(name, function(err, parts) {
if (err) throw err;
fixture.forEach(function(expectedPart, i) {
var parsedPart = parts[i];
assert.equal(parsedPart.type, expectedPart.type);
assert.equal(parsedPart.name, expectedPart.name);
if (parsedPart.type === 'file') {
var filename = parsedPart.value.name;
assert.equal(filename, expectedPart.filename);
}
});
testNext(fixtures);
});
};
function uploadFixture(name, cb) {
server.once('request', function(req, res) {
var form = new formidable.IncomingForm();
form.uploadDir = common.dir.tmp;
form.parse(req);
function callback() {
var realCallback = cb;
cb = function() {};
realCallback.apply(null, arguments);
}
var parts = [];
form
.on('error', callback)
.on('fileBegin', function(name, value) {
parts.push({type: 'file', name: name, value: value});
})
.on('field', function(name, value) {
parts.push({type: 'field', name: name, value: value});
})
.on('end', function() {
callback(null, parts);
});
});
var socket = net.createConnection(common.port);
var file = fs.createReadStream(common.dir.fixture + '/http/' + name);
file.pipe(socket);
}

24
node_modules/formidable/test/legacy/common.js generated vendored Normal file
View File

@@ -0,0 +1,24 @@
var path = require('path'),
fs = require('fs');
try {
global.Gently = require('gently');
} catch (e) {
throw new Error('this test suite requires node-gently');
}
exports.lib = path.join(__dirname, '../../lib');
global.GENTLY = new Gently();
global.assert = require('assert');
global.TEST_PORT = 13532;
global.TEST_FIXTURES = path.join(__dirname, '../fixture');
global.TEST_TMP = path.join(__dirname, '../tmp');
// Stupid new feature in node that complains about gently attaching too many
// listeners to process 'exit'. This is a workaround until I can think of a
// better way to deal with this.
if (process.setMaxListeners) {
process.setMaxListeners(10000);
}

View File

@@ -0,0 +1,80 @@
var common = require('../common');
var CHUNK_LENGTH = 10,
multipartParser = require(common.lib + '/multipart_parser'),
MultipartParser = multipartParser.MultipartParser,
parser = new MultipartParser(),
fixtures = require(TEST_FIXTURES + '/multipart'),
Buffer = require('buffer').Buffer;
Object.keys(fixtures).forEach(function(name) {
var fixture = fixtures[name],
buffer = new Buffer(Buffer.byteLength(fixture.raw, 'binary')),
offset = 0,
chunk,
nparsed,
parts = [],
part = null,
headerField,
headerValue,
endCalled = '';
parser.initWithBoundary(fixture.boundary);
parser.onPartBegin = function() {
part = {headers: {}, data: ''};
parts.push(part);
headerField = '';
headerValue = '';
};
parser.onHeaderField = function(b, start, end) {
headerField += b.toString('ascii', start, end);
};
parser.onHeaderValue = function(b, start, end) {
headerValue += b.toString('ascii', start, end);
}
parser.onHeaderEnd = function() {
part.headers[headerField] = headerValue;
headerField = '';
headerValue = '';
};
parser.onPartData = function(b, start, end) {
var str = b.toString('ascii', start, end);
part.data += b.slice(start, end);
}
parser.onEnd = function() {
endCalled = true;
}
buffer.write(fixture.raw, 'binary', 0);
while (offset < buffer.length) {
if (offset + CHUNK_LENGTH < buffer.length) {
chunk = buffer.slice(offset, offset+CHUNK_LENGTH);
} else {
chunk = buffer.slice(offset, buffer.length);
}
offset = offset + CHUNK_LENGTH;
nparsed = parser.write(chunk);
if (nparsed != chunk.length) {
if (fixture.expectError) {
return;
}
puts('-- ERROR --');
p(chunk.toString('ascii'));
throw new Error(chunk.length+' bytes written, but only '+nparsed+' bytes parsed!');
}
}
if (fixture.expectError) {
throw new Error('expected parse error did not happen');
}
assert.ok(endCalled);
assert.deepEqual(parts, fixture.parts);
});

104
node_modules/formidable/test/legacy/simple/test-file.js generated vendored Normal file
View File

@@ -0,0 +1,104 @@
var common = require('../common');
var WriteStreamStub = GENTLY.stub('fs', 'WriteStream');
var File = require(common.lib + '/file'),
EventEmitter = require('events').EventEmitter,
file,
gently;
function test(test) {
gently = new Gently();
file = new File();
test();
gently.verify(test.name);
}
test(function constructor() {
assert.ok(file instanceof EventEmitter);
assert.strictEqual(file.size, 0);
assert.strictEqual(file.path, null);
assert.strictEqual(file.name, null);
assert.strictEqual(file.type, null);
assert.strictEqual(file.lastModifiedDate, null);
assert.strictEqual(file._writeStream, null);
(function testSetProperties() {
var file2 = new File({foo: 'bar'});
assert.equal(file2.foo, 'bar');
})();
});
test(function open() {
var WRITE_STREAM;
file.path = '/foo';
gently.expect(WriteStreamStub, 'new', function (path) {
WRITE_STREAM = this;
assert.strictEqual(path, file.path);
});
file.open();
assert.strictEqual(file._writeStream, WRITE_STREAM);
});
test(function write() {
var BUFFER = {length: 10},
CB_STUB,
CB = function() {
CB_STUB.apply(this, arguments);
};
file._writeStream = {};
gently.expect(file._writeStream, 'write', function (buffer, cb) {
assert.strictEqual(buffer, BUFFER);
gently.expect(file, 'emit', function (event, bytesWritten) {
assert.ok(file.lastModifiedDate instanceof Date);
assert.equal(event, 'progress');
assert.equal(bytesWritten, file.size);
});
CB_STUB = gently.expect(function writeCb() {
assert.equal(file.size, 10);
});
cb();
gently.expect(file, 'emit', function (event, bytesWritten) {
assert.equal(event, 'progress');
assert.equal(bytesWritten, file.size);
});
CB_STUB = gently.expect(function writeCb() {
assert.equal(file.size, 20);
});
cb();
});
file.write(BUFFER, CB);
});
test(function end() {
var CB_STUB,
CB = function() {
CB_STUB.apply(this, arguments);
};
file._writeStream = {};
gently.expect(file._writeStream, 'end', function (cb) {
gently.expect(file, 'emit', function (event) {
assert.equal(event, 'end');
});
CB_STUB = gently.expect(function endCb() {
});
cb();
});
file.end(CB);
});

View File

@@ -0,0 +1,727 @@
var common = require('../common');
var MultipartParserStub = GENTLY.stub('./multipart_parser', 'MultipartParser'),
QuerystringParserStub = GENTLY.stub('./querystring_parser', 'QuerystringParser'),
EventEmitterStub = GENTLY.stub('events', 'EventEmitter'),
StreamStub = GENTLY.stub('stream', 'Stream'),
FileStub = GENTLY.stub('./file');
var formidable = require(common.lib + '/index'),
IncomingForm = formidable.IncomingForm,
events = require('events'),
fs = require('fs'),
path = require('path'),
Buffer = require('buffer').Buffer,
fixtures = require(TEST_FIXTURES + '/multipart'),
form,
gently;
function test(test) {
gently = new Gently();
gently.expect(EventEmitterStub, 'call');
form = new IncomingForm();
test();
gently.verify(test.name);
}
test(function constructor() {
assert.strictEqual(form.error, null);
assert.strictEqual(form.ended, false);
assert.strictEqual(form.type, null);
assert.strictEqual(form.headers, null);
assert.strictEqual(form.keepExtensions, false);
assert.strictEqual(form.uploadDir, '/tmp');
assert.strictEqual(form.encoding, 'utf-8');
assert.strictEqual(form.bytesReceived, null);
assert.strictEqual(form.bytesExpected, null);
assert.strictEqual(form.maxFieldsSize, 2 * 1024 * 1024);
assert.strictEqual(form._parser, null);
assert.strictEqual(form._flushing, 0);
assert.strictEqual(form._fieldsSize, 0);
assert.ok(form instanceof EventEmitterStub);
assert.equal(form.constructor.name, 'IncomingForm');
(function testSimpleConstructor() {
gently.expect(EventEmitterStub, 'call');
var form = IncomingForm();
assert.ok(form instanceof IncomingForm);
})();
(function testSimpleConstructorShortcut() {
gently.expect(EventEmitterStub, 'call');
var form = formidable();
assert.ok(form instanceof IncomingForm);
})();
});
test(function parse() {
var REQ = {headers: {}}
, emit = {};
gently.expect(form, 'writeHeaders', function(headers) {
assert.strictEqual(headers, REQ.headers);
});
var events = ['error', 'aborted', 'data', 'end'];
gently.expect(REQ, 'on', events.length, function(event, fn) {
assert.equal(event, events.shift());
emit[event] = fn;
return this;
});
form.parse(REQ);
(function testPause() {
gently.expect(REQ, 'pause');
assert.strictEqual(form.pause(), true);
})();
(function testPauseCriticalException() {
form.ended = false;
var ERR = new Error('dasdsa');
gently.expect(REQ, 'pause', function() {
throw ERR;
});
gently.expect(form, '_error', function(err) {
assert.strictEqual(err, ERR);
});
assert.strictEqual(form.pause(), false);
})();
(function testPauseHarmlessException() {
form.ended = true;
var ERR = new Error('dasdsa');
gently.expect(REQ, 'pause', function() {
throw ERR;
});
assert.strictEqual(form.pause(), false);
})();
(function testResume() {
gently.expect(REQ, 'resume');
assert.strictEqual(form.resume(), true);
})();
(function testResumeCriticalException() {
form.ended = false;
var ERR = new Error('dasdsa');
gently.expect(REQ, 'resume', function() {
throw ERR;
});
gently.expect(form, '_error', function(err) {
assert.strictEqual(err, ERR);
});
assert.strictEqual(form.resume(), false);
})();
(function testResumeHarmlessException() {
form.ended = true;
var ERR = new Error('dasdsa');
gently.expect(REQ, 'resume', function() {
throw ERR;
});
assert.strictEqual(form.resume(), false);
})();
(function testEmitError() {
var ERR = new Error('something bad happened');
gently.expect(form, '_error',function(err) {
assert.strictEqual(err, ERR);
});
emit.error(ERR);
})();
(function testEmitAborted() {
gently.expect(form, 'emit',function(event) {
assert.equal(event, 'aborted');
});
emit.aborted();
})();
(function testEmitData() {
var BUFFER = [1, 2, 3];
gently.expect(form, 'write', function(buffer) {
assert.strictEqual(buffer, BUFFER);
});
emit.data(BUFFER);
})();
(function testEmitEnd() {
form._parser = {};
(function testWithError() {
var ERR = new Error('haha');
gently.expect(form._parser, 'end', function() {
return ERR;
});
gently.expect(form, '_error', function(err) {
assert.strictEqual(err, ERR);
});
emit.end();
})();
(function testWithoutError() {
gently.expect(form._parser, 'end');
emit.end();
})();
(function testAfterError() {
form.error = true;
emit.end();
})();
})();
(function testWithCallback() {
gently.expect(EventEmitterStub, 'call');
var form = new IncomingForm(),
REQ = {headers: {}},
parseCalled = 0;
gently.expect(form, 'writeHeaders');
gently.expect(REQ, 'on', 4, function() {
return this;
});
gently.expect(form, 'on', 4, function(event, fn) {
if (event == 'field') {
fn('field1', 'foo');
fn('field1', 'bar');
fn('field2', 'nice');
}
if (event == 'file') {
fn('file1', '1');
fn('file1', '2');
fn('file2', '3');
}
if (event == 'end') {
fn();
}
return this;
});
form.parse(REQ, gently.expect(function parseCbOk(err, fields, files) {
assert.deepEqual(fields, {field1: 'bar', field2: 'nice'});
assert.deepEqual(files, {file1: '2', file2: '3'});
}));
gently.expect(form, 'writeHeaders');
gently.expect(REQ, 'on', 4, function() {
return this;
});
var ERR = new Error('test');
gently.expect(form, 'on', 3, function(event, fn) {
if (event == 'field') {
fn('foo', 'bar');
}
if (event == 'error') {
fn(ERR);
gently.expect(form, 'on');
}
return this;
});
form.parse(REQ, gently.expect(function parseCbErr(err, fields, files) {
assert.strictEqual(err, ERR);
assert.deepEqual(fields, {foo: 'bar'});
}));
})();
});
test(function pause() {
assert.strictEqual(form.pause(), false);
});
test(function resume() {
assert.strictEqual(form.resume(), false);
});
test(function writeHeaders() {
var HEADERS = {};
gently.expect(form, '_parseContentLength');
gently.expect(form, '_parseContentType');
form.writeHeaders(HEADERS);
assert.strictEqual(form.headers, HEADERS);
});
test(function write() {
var parser = {},
BUFFER = [1, 2, 3];
form._parser = parser;
form.bytesExpected = 523423;
(function testBasic() {
gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {
assert.equal(event, 'progress');
assert.equal(bytesReceived, BUFFER.length);
assert.equal(bytesExpected, form.bytesExpected);
});
gently.expect(parser, 'write', function(buffer) {
assert.strictEqual(buffer, BUFFER);
return buffer.length;
});
assert.equal(form.write(BUFFER), BUFFER.length);
assert.equal(form.bytesReceived, BUFFER.length);
})();
(function testParserError() {
gently.expect(form, 'emit');
gently.expect(parser, 'write', function(buffer) {
assert.strictEqual(buffer, BUFFER);
return buffer.length - 1;
});
gently.expect(form, '_error', function(err) {
assert.ok(err.message.match(/parser error/i));
});
assert.equal(form.write(BUFFER), BUFFER.length - 1);
assert.equal(form.bytesReceived, BUFFER.length + BUFFER.length);
})();
(function testUninitialized() {
delete form._parser;
gently.expect(form, '_error', function(err) {
assert.ok(err.message.match(/unintialized parser/i));
});
form.write(BUFFER);
})();
});
test(function parseContentType() {
var HEADERS = {};
form.headers = {'content-type': 'application/x-www-form-urlencoded'};
gently.expect(form, '_initUrlencoded');
form._parseContentType();
// accept anything that has 'urlencoded' in it
form.headers = {'content-type': 'broken-client/urlencoded-stupid'};
gently.expect(form, '_initUrlencoded');
form._parseContentType();
var BOUNDARY = '---------------------------57814261102167618332366269';
form.headers = {'content-type': 'multipart/form-data; boundary='+BOUNDARY};
gently.expect(form, '_initMultipart', function(boundary) {
assert.equal(boundary, BOUNDARY);
});
form._parseContentType();
(function testQuotedBoundary() {
form.headers = {'content-type': 'multipart/form-data; boundary="' + BOUNDARY + '"'};
gently.expect(form, '_initMultipart', function(boundary) {
assert.equal(boundary, BOUNDARY);
});
form._parseContentType();
})();
(function testNoBoundary() {
form.headers = {'content-type': 'multipart/form-data'};
gently.expect(form, '_error', function(err) {
assert.ok(err.message.match(/no multipart boundary/i));
});
form._parseContentType();
})();
(function testNoContentType() {
form.headers = {};
gently.expect(form, '_error', function(err) {
assert.ok(err.message.match(/no content-type/i));
});
form._parseContentType();
})();
(function testUnknownContentType() {
form.headers = {'content-type': 'invalid'};
gently.expect(form, '_error', function(err) {
assert.ok(err.message.match(/unknown content-type/i));
});
form._parseContentType();
})();
});
test(function parseContentLength() {
var HEADERS = {};
form.headers = {};
form._parseContentLength();
assert.strictEqual(form.bytesReceived, null);
assert.strictEqual(form.bytesExpected, null);
form.headers['content-length'] = '8';
gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {
assert.equal(event, 'progress');
assert.equal(bytesReceived, 0);
assert.equal(bytesExpected, 8);
});
form._parseContentLength();
assert.strictEqual(form.bytesReceived, 0);
assert.strictEqual(form.bytesExpected, 8);
// JS can be evil, lets make sure we are not
form.headers['content-length'] = '08';
gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {
assert.equal(event, 'progress');
assert.equal(bytesReceived, 0);
assert.equal(bytesExpected, 8);
});
form._parseContentLength();
assert.strictEqual(form.bytesExpected, 8);
});
test(function _initMultipart() {
var BOUNDARY = '123',
PARSER;
gently.expect(MultipartParserStub, 'new', function() {
PARSER = this;
});
gently.expect(MultipartParserStub.prototype, 'initWithBoundary', function(boundary) {
assert.equal(boundary, BOUNDARY);
});
form._initMultipart(BOUNDARY);
assert.equal(form.type, 'multipart');
assert.strictEqual(form._parser, PARSER);
(function testRegularField() {
var PART;
gently.expect(StreamStub, 'new', function() {
PART = this;
});
gently.expect(form, 'onPart', function(part) {
assert.strictEqual(part, PART);
assert.deepEqual
( part.headers
, { 'content-disposition': 'form-data; name="field1"'
, 'foo': 'bar'
}
);
assert.equal(part.name, 'field1');
var strings = ['hello', ' world'];
gently.expect(part, 'emit', 2, function(event, b) {
assert.equal(event, 'data');
assert.equal(b.toString(), strings.shift());
});
gently.expect(part, 'emit', function(event, b) {
assert.equal(event, 'end');
});
});
PARSER.onPartBegin();
PARSER.onHeaderField(new Buffer('content-disposition'), 0, 10);
PARSER.onHeaderField(new Buffer('content-disposition'), 10, 19);
PARSER.onHeaderValue(new Buffer('form-data; name="field1"'), 0, 14);
PARSER.onHeaderValue(new Buffer('form-data; name="field1"'), 14, 24);
PARSER.onHeaderEnd();
PARSER.onHeaderField(new Buffer('foo'), 0, 3);
PARSER.onHeaderValue(new Buffer('bar'), 0, 3);
PARSER.onHeaderEnd();
PARSER.onHeadersEnd();
PARSER.onPartData(new Buffer('hello world'), 0, 5);
PARSER.onPartData(new Buffer('hello world'), 5, 11);
PARSER.onPartEnd();
})();
(function testFileField() {
var PART;
gently.expect(StreamStub, 'new', function() {
PART = this;
});
gently.expect(form, 'onPart', function(part) {
assert.deepEqual
( part.headers
, { 'content-disposition': 'form-data; name="field2"; filename="C:\\Documents and Settings\\IE\\Must\\Die\\Sun"et.jpg"'
, 'content-type': 'text/plain'
}
);
assert.equal(part.name, 'field2');
assert.equal(part.filename, 'Sun"et.jpg');
assert.equal(part.mime, 'text/plain');
gently.expect(part, 'emit', function(event, b) {
assert.equal(event, 'data');
assert.equal(b.toString(), '... contents of file1.txt ...');
});
gently.expect(part, 'emit', function(event, b) {
assert.equal(event, 'end');
});
});
PARSER.onPartBegin();
PARSER.onHeaderField(new Buffer('content-disposition'), 0, 19);
PARSER.onHeaderValue(new Buffer('form-data; name="field2"; filename="C:\\Documents and Settings\\IE\\Must\\Die\\Sun"et.jpg"'), 0, 85);
PARSER.onHeaderEnd();
PARSER.onHeaderField(new Buffer('Content-Type'), 0, 12);
PARSER.onHeaderValue(new Buffer('text/plain'), 0, 10);
PARSER.onHeaderEnd();
PARSER.onHeadersEnd();
PARSER.onPartData(new Buffer('... contents of file1.txt ...'), 0, 29);
PARSER.onPartEnd();
})();
(function testEnd() {
gently.expect(form, '_maybeEnd');
PARSER.onEnd();
assert.ok(form.ended);
})();
});
test(function _fileName() {
// TODO
return;
});
test(function _initUrlencoded() {
var PARSER;
gently.expect(QuerystringParserStub, 'new', function() {
PARSER = this;
});
form._initUrlencoded();
assert.equal(form.type, 'urlencoded');
assert.strictEqual(form._parser, PARSER);
(function testOnField() {
var KEY = 'KEY', VAL = 'VAL';
gently.expect(form, 'emit', function(field, key, val) {
assert.equal(field, 'field');
assert.equal(key, KEY);
assert.equal(val, VAL);
});
PARSER.onField(KEY, VAL);
})();
(function testOnEnd() {
gently.expect(form, '_maybeEnd');
PARSER.onEnd();
assert.equal(form.ended, true);
})();
});
test(function _error() {
var ERR = new Error('bla');
gently.expect(form, 'pause');
gently.expect(form, 'emit', function(event, err) {
assert.equal(event, 'error');
assert.strictEqual(err, ERR);
});
form._error(ERR);
assert.strictEqual(form.error, ERR);
// make sure _error only does its thing once
form._error(ERR);
});
test(function onPart() {
var PART = {};
gently.expect(form, 'handlePart', function(part) {
assert.strictEqual(part, PART);
});
form.onPart(PART);
});
test(function handlePart() {
(function testUtf8Field() {
var PART = new events.EventEmitter();
PART.name = 'my_field';
gently.expect(form, 'emit', function(event, field, value) {
assert.equal(event, 'field');
assert.equal(field, 'my_field');
assert.equal(value, 'hello world: €');
});
form.handlePart(PART);
PART.emit('data', new Buffer('hello'));
PART.emit('data', new Buffer(' world: '));
PART.emit('data', new Buffer([0xE2]));
PART.emit('data', new Buffer([0x82, 0xAC]));
PART.emit('end');
})();
(function testBinaryField() {
var PART = new events.EventEmitter();
PART.name = 'my_field2';
gently.expect(form, 'emit', function(event, field, value) {
assert.equal(event, 'field');
assert.equal(field, 'my_field2');
assert.equal(value, 'hello world: '+new Buffer([0xE2, 0x82, 0xAC]).toString('binary'));
});
form.encoding = 'binary';
form.handlePart(PART);
PART.emit('data', new Buffer('hello'));
PART.emit('data', new Buffer(' world: '));
PART.emit('data', new Buffer([0xE2]));
PART.emit('data', new Buffer([0x82, 0xAC]));
PART.emit('end');
})();
(function testFieldSize() {
form.maxFieldsSize = 8;
var PART = new events.EventEmitter();
PART.name = 'my_field';
gently.expect(form, '_error', function(err) {
assert.equal(err.message, 'maxFieldsSize exceeded, received 9 bytes of field data');
});
form.handlePart(PART);
form._fieldsSize = 1;
PART.emit('data', new Buffer(7));
PART.emit('data', new Buffer(1));
})();
(function testFilePart() {
var PART = new events.EventEmitter(),
FILE = new events.EventEmitter(),
PATH = '/foo/bar';
PART.name = 'my_file';
PART.filename = 'sweet.txt';
PART.mime = 'sweet.txt';
gently.expect(form, '_uploadPath', function(filename) {
assert.equal(filename, PART.filename);
return PATH;
});
gently.expect(FileStub, 'new', function(properties) {
assert.equal(properties.path, PATH);
assert.equal(properties.name, PART.filename);
assert.equal(properties.type, PART.mime);
FILE = this;
gently.expect(form, 'emit', function (event, field, file) {
assert.equal(event, 'fileBegin');
assert.strictEqual(field, PART.name);
assert.strictEqual(file, FILE);
});
gently.expect(FILE, 'open');
});
form.handlePart(PART);
assert.equal(form._flushing, 1);
var BUFFER;
gently.expect(form, 'pause');
gently.expect(FILE, 'write', function(buffer, cb) {
assert.strictEqual(buffer, BUFFER);
gently.expect(form, 'resume');
// @todo handle cb(new Err)
cb();
});
PART.emit('data', BUFFER = new Buffer('test'));
gently.expect(FILE, 'end', function(cb) {
gently.expect(form, 'emit', function(event, field, file) {
assert.equal(event, 'file');
assert.strictEqual(file, FILE);
});
gently.expect(form, '_maybeEnd');
cb();
assert.equal(form._flushing, 0);
});
PART.emit('end');
})();
});
test(function _uploadPath() {
(function testUniqueId() {
var UUID_A, UUID_B;
gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, uuid) {
assert.equal(uploadDir, form.uploadDir);
UUID_A = uuid;
});
form._uploadPath();
gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, uuid) {
UUID_B = uuid;
});
form._uploadPath();
assert.notEqual(UUID_A, UUID_B);
})();
(function testFileExtension() {
form.keepExtensions = true;
var FILENAME = 'foo.jpg',
EXT = '.bar';
gently.expect(GENTLY.hijacked.path, 'extname', function(filename) {
assert.equal(filename, FILENAME);
gently.restore(path, 'extname');
return EXT;
});
gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, name) {
assert.equal(path.extname(name), EXT);
});
form._uploadPath(FILENAME);
})();
});
test(function _maybeEnd() {
gently.expect(form, 'emit', 0);
form._maybeEnd();
form.ended = true;
form._flushing = 1;
form._maybeEnd();
gently.expect(form, 'emit', function(event) {
assert.equal(event, 'end');
});
form.ended = true;
form._flushing = 0;
form._maybeEnd();
});

View File

@@ -0,0 +1,50 @@
var common = require('../common');
var multipartParser = require(common.lib + '/multipart_parser'),
MultipartParser = multipartParser.MultipartParser,
events = require('events'),
Buffer = require('buffer').Buffer,
parser;
function test(test) {
parser = new MultipartParser();
test();
}
test(function constructor() {
assert.equal(parser.boundary, null);
assert.equal(parser.state, 0);
assert.equal(parser.flags, 0);
assert.equal(parser.boundaryChars, null);
assert.equal(parser.index, null);
assert.equal(parser.lookbehind, null);
assert.equal(parser.constructor.name, 'MultipartParser');
});
test(function initWithBoundary() {
var boundary = 'abc';
parser.initWithBoundary(boundary);
assert.deepEqual(Array.prototype.slice.call(parser.boundary), [13, 10, 45, 45, 97, 98, 99]);
assert.equal(parser.state, multipartParser.START);
assert.deepEqual(parser.boundaryChars, {10: true, 13: true, 45: true, 97: true, 98: true, 99: true});
});
test(function parserError() {
var boundary = 'abc',
buffer = new Buffer(5);
parser.initWithBoundary(boundary);
buffer.write('--ad', 'ascii', 0);
assert.equal(parser.write(buffer), 3);
});
test(function end() {
(function testError() {
assert.equal(parser.end().message, 'MultipartParser.end(): stream ended unexpectedly: ' + parser.explain());
})();
(function testRegular() {
parser.state = multipartParser.END;
assert.strictEqual(parser.end(), undefined);
})();
});

View File

@@ -0,0 +1,45 @@
var common = require('../common');
var QuerystringParser = require(common.lib + '/querystring_parser').QuerystringParser,
Buffer = require('buffer').Buffer,
gently,
parser;
function test(test) {
gently = new Gently();
parser = new QuerystringParser();
test();
gently.verify(test.name);
}
test(function constructor() {
assert.equal(parser.buffer, '');
assert.equal(parser.constructor.name, 'QuerystringParser');
});
test(function write() {
var a = new Buffer('a=1');
assert.equal(parser.write(a), a.length);
var b = new Buffer('&b=2');
parser.write(b);
assert.equal(parser.buffer, a + b);
});
test(function end() {
var FIELDS = {a: ['b', {c: 'd'}], e: 'f'};
gently.expect(GENTLY.hijacked.querystring, 'parse', function(str) {
assert.equal(str, parser.buffer);
return FIELDS;
});
gently.expect(parser, 'onField', Object.keys(FIELDS).length, function(key, val) {
assert.deepEqual(FIELDS[key], val);
});
gently.expect(parser, 'onEnd');
parser.buffer = 'my buffer';
parser.end();
assert.equal(parser.buffer, '');
});

View File

@@ -0,0 +1,75 @@
var common = require('../common');
var BOUNDARY = '---------------------------10102754414578508781458777923',
FIXTURE = TEST_FIXTURES+'/multi_video.upload',
fs = require('fs'),
util = require(common.lib + '/util'),
http = require('http'),
formidable = require(common.lib + '/index'),
server = http.createServer();
server.on('request', function(req, res) {
var form = new formidable.IncomingForm(),
uploads = {};
form.uploadDir = TEST_TMP;
form.hash = 'sha1';
form.parse(req);
form
.on('fileBegin', function(field, file) {
assert.equal(field, 'upload');
var tracker = {file: file, progress: [], ended: false};
uploads[file.filename] = tracker;
file
.on('progress', function(bytesReceived) {
tracker.progress.push(bytesReceived);
assert.equal(bytesReceived, file.length);
})
.on('end', function() {
tracker.ended = true;
});
})
.on('field', function(field, value) {
assert.equal(field, 'title');
assert.equal(value, '');
})
.on('file', function(field, file) {
assert.equal(field, 'upload');
assert.strictEqual(uploads[file.filename].file, file);
})
.on('end', function() {
assert.ok(uploads['shortest_video.flv']);
assert.ok(uploads['shortest_video.flv'].ended);
assert.ok(uploads['shortest_video.flv'].progress.length > 3);
assert.equal(uploads['shortest_video.flv'].file.hash, 'd6a17616c7143d1b1438ceeef6836d1a09186b3a');
assert.equal(uploads['shortest_video.flv'].progress.slice(-1), uploads['shortest_video.flv'].file.length);
assert.ok(uploads['shortest_video.mp4']);
assert.ok(uploads['shortest_video.mp4'].ended);
assert.ok(uploads['shortest_video.mp4'].progress.length > 3);
assert.equal(uploads['shortest_video.mp4'].file.hash, '937dfd4db263f4887ceae19341dcc8d63bcd557f');
server.close();
res.writeHead(200);
res.end('good');
});
});
server.listen(TEST_PORT, function() {
var client = http.createClient(TEST_PORT),
stat = fs.statSync(FIXTURE),
headers = {
'content-type': 'multipart/form-data; boundary='+BOUNDARY,
'content-length': stat.size,
}
request = client.request('POST', '/', headers),
fixture = new fs.ReadStream(FIXTURE);
fixture
.on('data', function(b) {
request.write(b);
})
.on('end', function() {
request.end();
});
});

2
node_modules/formidable/test/run.js generated vendored Normal file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/env node
require('urun')(__dirname)

View File

@@ -0,0 +1,63 @@
var common = require('../common');
var test = require('utest');
var assert = common.assert;
var IncomingForm = common.require('incoming_form').IncomingForm;
var path = require('path');
var form;
test('IncomingForm', {
before: function() {
form = new IncomingForm();
},
'#_fileName with regular characters': function() {
var filename = 'foo.txt';
assert.equal(form._fileName(makeHeader(filename)), 'foo.txt');
},
'#_fileName with unescaped quote': function() {
var filename = 'my".txt';
assert.equal(form._fileName(makeHeader(filename)), 'my".txt');
},
'#_fileName with escaped quote': function() {
var filename = 'my%22.txt';
assert.equal(form._fileName(makeHeader(filename)), 'my".txt');
},
'#_fileName with bad quote and additional sub-header': function() {
var filename = 'my".txt';
var header = makeHeader(filename) + '; foo="bar"';
assert.equal(form._fileName(header), filename);
},
'#_fileName with semicolon': function() {
var filename = 'my;.txt';
assert.equal(form._fileName(makeHeader(filename)), 'my;.txt');
},
'#_fileName with utf8 character': function() {
var filename = 'my&#9731;.txt';
assert.equal(form._fileName(makeHeader(filename)), 'my☃.txt');
},
'#_uploadPath strips harmful characters from extension when keepExtensions': function() {
form.keepExtensions = true;
var ext = path.extname(form._uploadPath('fine.jpg?foo=bar'));
assert.equal(ext, '.jpg');
var ext = path.extname(form._uploadPath('fine?foo=bar'));
assert.equal(ext, '');
var ext = path.extname(form._uploadPath('super.cr2+dsad'));
assert.equal(ext, '.cr2');
var ext = path.extname(form._uploadPath('super.bar'));
assert.equal(ext, '.bar');
},
});
function makeHeader(filename) {
return 'Content-Disposition: form-data; name="upload"; filename="' + filename + '"';
}

47
node_modules/formidable/tool/record.js generated vendored Normal file
View File

@@ -0,0 +1,47 @@
var http = require('http');
var fs = require('fs');
var connections = 0;
var server = http.createServer(function(req, res) {
var socket = req.socket;
console.log('Request: %s %s -> %s', req.method, req.url, socket.filename);
req.on('end', function() {
if (req.url !== '/') {
res.end(JSON.stringify({
method: req.method,
url: req.url,
filename: socket.filename,
}));
return;
}
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/upload" enctype="multipart/form-data" method="post">'+
'<input type="text" name="title"><br>'+
'<input type="file" name="upload" multiple="multiple"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
});
});
server.on('connection', function(socket) {
connections++;
socket.id = connections;
socket.filename = 'connection-' + socket.id + '.http';
socket.file = fs.createWriteStream(socket.filename);
socket.pipe(socket.file);
console.log('--> %s', socket.filename);
socket.on('close', function() {
console.log('<-- %s', socket.filename);
});
});
var port = process.env.PORT || 8080;
server.listen(port, function() {
console.log('Recording connections on port %s', port);
});

5
node_modules/mongodb/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,5 @@
language: node_js
node_js:
- 0.6
- 0.8
- 0.9 # development version of 0.8, may be unstable

23
node_modules/mongodb/CONTRIBUTING.md generated vendored Normal file
View File

@@ -0,0 +1,23 @@
## Contributing to the driver
### Bugfixes
- Before starting to write code, look for existing [tickets](https://github.com/mongodb/node-mongodb-native/issues) or [create one](https://github.com/mongodb/node-mongodb-native/issues/new) for your specific issue. That way you avoid working on something that might not be of interest or that has been addressed already in a different branch.
- Fork the [repo](https://github.com/mongodb/node-mongodb-native) _or_ for small documentation changes, navigate to the source on github and click the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button.
- Follow the general coding style of the rest of the project:
- 2 space tabs
- no trailing whitespace
- comma last
- inline documentation for new methods, class members, etc
- 0 space between conditionals/functions, and their parenthesis and curly braces
- `if(..) {`
- `for(..) {`
- `while(..) {`
- `function(err) {`
- Write tests and make sure they pass (execute `make test` from the cmd line to run the test suite).
### Documentation
To contribute to the [API documentation](http://mongodb.github.com/node-mongodb-native/) just make your changes to the inline documentation of the appropriate [source code](https://github.com/mongodb/node-mongodb-native/tree/master/docs) in the master branch and submit a [pull request](https://help.github.com/articles/using-pull-requests/). You might also use the github [Edit](https://github.com/blog/844-forking-with-the-edit-button) button.
If you'd like to preview your documentation changes, first commit your changes to your local master branch, then execute `make generate_docs`. Make sure you have the python documentation framework sphinx installed `easy_install sphinx`. The docs are generated under `docs/build'. If all looks good, submit a [pull request](https://help.github.com/articles/using-pull-requests/) to the master branch with your changes.

64
node_modules/mongodb/Makefile generated vendored Normal file
View File

@@ -0,0 +1,64 @@
NODE = node
NPM = npm
NODEUNIT = node_modules/nodeunit/bin/nodeunit
DOX = node_modules/dox/bin/dox
name = all
total: build_native
test-coverage:
rm -rf lib-cov/
jscoverage lib/ lib-cov/
@TEST_COVERAGE=true nodeunit test/ test/gridstore test/connection
build_native:
test: build_native
@echo "\n == Run All tests minus replicaset tests=="
$(NODE) dev/tools/test_all.js --noreplicaset --boot
test_pure: build_native
@echo "\n == Run All tests minus replicaset tests=="
$(NODE) dev/tools/test_all.js --noreplicaset --boot --nonative
test_junit: build_native
@echo "\n == Run All tests minus replicaset tests=="
$(NODE) dev/tools/test_all.js --junit --noreplicaset --nokill
jenkins: build_native
@echo "\n == Run All tests minus replicaset tests=="
$(NODE) dev/tools/test_all.js --junit --noreplicaset --nokill
test_nodeunit_pure:
@echo "\n == Execute Test Suite using Pure JS BSON Parser == "
@$(NODEUNIT) test/ test/gridstore test/bson
test_nodeunit_replicaset_pure:
@echo "\n == Execute Test Suite using Pure JS BSON Parser == "
@$(NODEUNIT) test/replicaset
test_nodeunit_native:
@echo "\n == Execute Test Suite using Native BSON Parser == "
@TEST_NATIVE=TRUE $(NODEUNIT) test/ test/gridstore test/bson
test_nodeunit_replicaset_native:
@echo "\n == Execute Test Suite using Native BSON Parser == "
@TEST_NATIVE=TRUE $(NODEUNIT) test/replicaset
test_all: build_native
@echo "\n == Run All tests =="
$(NODE) dev/tools/test_all.js --boot
test_all_junit: build_native
@echo "\n == Run All tests =="
$(NODE) dev/tools/test_all.js --junit --boot
clean:
rm ./external-libs/bson/bson.node
rm -r ./external-libs/bson/build
generate_docs:
$(NODE) dev/tools/build-docs.js
make --directory=./docs/sphinx-docs --file=Makefile html
.PHONY: total

442
node_modules/mongodb/Readme.md generated vendored Normal file
View File

@@ -0,0 +1,442 @@
Up to date documentation
========================
[Documentation](http://mongodb.github.com/node-mongodb-native/)
Install
=======
To install the most recent release from npm, run:
npm install mongodb
That may give you a warning telling you that bugs['web'] should be bugs['url'], it would be safe to ignore it (this has been fixed in the development version)
To install the latest from the repository, run::
npm install path/to/node-mongodb-native
Community
=========
Check out the google group [node-mongodb-native](http://groups.google.com/group/node-mongodb-native) for questions/answers from users of the driver.
Try it live
============
<a href="https://runnable.com/#mongodb/node-mongodb-native/server.js/launch" target="_blank"><img src="https://runnable.com/external/styles/assets/runnablebtn.png" style="width:67px;height:25px;"></a>
Introduction
============
This is a node.js driver for MongoDB. It's a port (or close to a port) of the library for ruby at http://github.com/mongodb/mongo-ruby-driver/.
A simple example of inserting a document.
```javascript
var client = new Db('test', new Server("127.0.0.1", 27017, {}), {w: 1}),
test = function (err, collection) {
collection.insert({a:2}, function(err, docs) {
collection.count(function(err, count) {
test.assertEquals(1, count);
});
// Locate all the entries using find
collection.find().toArray(function(err, results) {
test.assertEquals(1, results.length);
test.assertTrue(results[0].a === 2);
// Let's close the db
client.close();
});
});
};
client.open(function(err, p_client) {
client.collection('test_insert', test);
});
```
Data types
==========
To store and retrieve the non-JSON MongoDb primitives ([ObjectID](http://www.mongodb.org/display/DOCS/Object+IDs), Long, Binary, [Timestamp](http://www.mongodb.org/display/DOCS/Timestamp+data+type), [DBRef](http://www.mongodb.org/display/DOCS/Database+References#DatabaseReferences-DBRef), Code).
In particular, every document has a unique `_id` which can be almost any type, and by default a 12-byte ObjectID is created. ObjectIDs can be represented as 24-digit hexadecimal strings, but you must convert the string back into an ObjectID before you can use it in the database. For example:
```javascript
// Get the objectID type
var ObjectID = require('mongodb').ObjectID;
var idString = '4e4e1638c85e808431000003';
collection.findOne({_id: new ObjectID(idString)}, console.log) // ok
collection.findOne({_id: idString}, console.log) // wrong! callback gets undefined
```
Here are the constructors the non-Javascript BSON primitive types:
```javascript
// Fetch the library
var mongo = require('mongodb');
// Create new instances of BSON types
new mongo.Long(numberString)
new mongo.ObjectID(hexString)
new mongo.Timestamp() // the actual unique number is generated on insert.
new mongo.DBRef(collectionName, id, dbName)
new mongo.Binary(buffer) // takes a string or Buffer
new mongo.Code(code, [context])
new mongo.Symbol(string)
new mongo.MinKey()
new mongo.MaxKey()
new mongo.Double(number) // Force double storage
```
The C/C++ bson parser/serializer
--------------------------------
If you are running a version of this library has the C/C++ parser compiled, to enable the driver to use the C/C++ bson parser pass it the option native_parser:true like below
```javascript
// using native_parser:
var client = new Db('integration_tests_20',
new Server("127.0.0.1", 27017),
{native_parser:true});
```
The C++ parser uses the js objects both for serialization and deserialization.
GitHub information
==================
The source code is available at http://github.com/mongodb/node-mongodb-native.
You can either clone the repository or download a tarball of the latest release.
Once you have the source you can test the driver by running
$ make test
in the main directory. You will need to have a mongo instance running on localhost for the integration tests to pass.
Examples
========
For examples look in the examples/ directory. You can execute the examples using node.
$ cd examples
$ node queries.js
GridStore
=========
The GridStore class allows for storage of binary files in mongoDB using the mongoDB defined files and chunks collection definition.
For more information have a look at [Gridstore](https://github.com/mongodb/node-mongodb-native/blob/master/docs/gridfs.md)
Replicasets
===========
For more information about how to connect to a replicaset have a look at [Replicasets](https://github.com/mongodb/node-mongodb-native/blob/master/docs/replicaset.md)
Primary Key Factories
---------------------
Defining your own primary key factory allows you to generate your own series of id's
(this could f.ex be to use something like ISBN numbers). The generated the id needs to be a 12 byte long "string".
Simple example below
```javascript
// Custom factory (need to provide a 12 byte array);
CustomPKFactory = function() {}
CustomPKFactory.prototype = new Object();
CustomPKFactory.createPk = function() {
return new ObjectID("aaaaaaaaaaaa");
}
var p_client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {}), {'pk':CustomPKFactory});
p_client.open(function(err, p_client) {
p_client.dropDatabase(function(err, done) {
p_client.createCollection('test_custom_key', function(err, collection) {
collection.insert({'a':1}, function(err, docs) {
collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) {
cursor.toArray(function(err, items) {
test.assertEquals(1, items.length);
// Let's close the db
p_client.close();
});
});
});
});
});
});
```
Strict mode
-----------
Each database has an optional strict mode. If it is set then asking for a collection
that does not exist will return an Error object in the callback. Similarly if you
attempt to create a collection that already exists. Strict is provided for convenience.
```javascript
var error_client = new Db('integration_tests_', new Server("127.0.0.1", 27017, {auto_reconnect: false}), {strict:true});
test.assertEquals(true, error_client.strict);
error_client.open(function(err, error_client) {
error_client.collection('does-not-exist', function(err, collection) {
test.assertTrue(err instanceof Error);
test.assertEquals("Collection does-not-exist does not exist. Currently in strict mode.", err.message);
});
error_client.createCollection('test_strict_access_collection', function(err, collection) {
error_client.collection('test_strict_access_collection', function(err, collection) {
test.assertTrue(collection instanceof Collection);
// Let's close the db
error_client.close();
});
});
});
```
Documentation
=============
If this document doesn't answer your questions, see the source of
[Collection](https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/collection.js)
or [Cursor](https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/cursor.js),
or the documentation at MongoDB for query and update formats.
Find
----
The find method is actually a factory method to create
Cursor objects. A Cursor lazily uses the connection the first time
you call `nextObject`, `each`, or `toArray`.
The basic operation on a cursor is the `nextObject` method
that fetches the next matching document from the database. The convenience
methods `each` and `toArray` call `nextObject` until the cursor is exhausted.
Signatures:
```javascript
var cursor = collection.find(query, [fields], options);
cursor.sort(fields).limit(n).skip(m).
cursor.nextObject(function(err, doc) {});
cursor.each(function(err, doc) {});
cursor.toArray(function(err, docs) {});
cursor.rewind() // reset the cursor to its initial state.
```
Useful chainable methods of cursor. These can optionally be options of `find` instead of method calls:
* `.limit(n).skip(m)` to control paging.
* `.sort(fields)` Order by the given fields. There are several equivalent syntaxes:
* `.sort({field1: -1, field2: 1})` descending by field1, then ascending by field2.
* `.sort([['field1', 'desc'], ['field2', 'asc']])` same as above
* `.sort([['field1', 'desc'], 'field2'])` same as above
* `.sort('field1')` ascending by field1
Other options of `find`:
* `fields` the fields to fetch (to avoid transferring the entire document)
* `tailable` if true, makes the cursor [tailable](http://www.mongodb.org/display/DOCS/Tailable+Cursors).
* `batchSize` The number of the subset of results to request the database
to return for every request. This should initially be greater than 1 otherwise
the database will automatically close the cursor. The batch size can be set to 1
with `batchSize(n, function(err){})` after performing the initial query to the database.
* `hint` See [Optimization: hint](http://www.mongodb.org/display/DOCS/Optimization#Optimization-Hint).
* `explain` turns this into an explain query. You can also call
`explain()` on any cursor to fetch the explanation.
* `snapshot` prevents documents that are updated while the query is active
from being returned multiple times. See more
[details about query snapshots](http://www.mongodb.org/display/DOCS/How+to+do+Snapshotted+Queries+in+the+Mongo+Database).
* `timeout` if false, asks MongoDb not to time out this cursor after an
inactivity period.
For information on how to create queries, see the
[MongoDB section on querying](http://www.mongodb.org/display/DOCS/Querying).
```javascript
var mongodb = require('mongodb');
var server = new mongodb.Server("127.0.0.1", 27017, {});
new mongodb.Db('test', server, {}).open(function (error, client) {
if (error) throw error;
var collection = new mongodb.Collection(client, 'test_collection');
collection.find({}, {limit:10}).toArray(function(err, docs) {
console.dir(docs);
});
});
```
Insert
------
Signature:
```javascript
collection.insert(docs, options, [callback]);
```
where `docs` can be a single document or an array of documents.
Useful options:
* `safe:true` Should always set if you have a callback.
See also: [MongoDB docs for insert](http://www.mongodb.org/display/DOCS/Inserting).
```javascript
var mongodb = require('mongodb');
var server = new mongodb.Server("127.0.0.1", 27017, {});
new mongodb.Db('test', server, {w: 1}).open(function (error, client) {
if (error) throw error;
var collection = new mongodb.Collection(client, 'test_collection');
collection.insert({hello: 'world'}, {safe:true},
function(err, objects) {
if (err) console.warn(err.message);
if (err && err.message.indexOf('E11000 ') !== -1) {
// this _id was already inserted in the database
}
});
});
```
Note that there's no reason to pass a callback to the insert or update commands
unless you use the `safe:true` option. If you don't specify `safe:true`, then
your callback will be called immediately.
Update; update and insert (upsert)
----------------------------------
The update operation will update the first document that matches your query
(or all documents that match if you use `multi:true`).
If `safe:true`, `upsert` is not set, and no documents match, your callback will return 0 documents updated.
See the [MongoDB docs](http://www.mongodb.org/display/DOCS/Updating) for
the modifier (`$inc`, `$set`, `$push`, etc.) formats.
Signature:
```javascript
collection.update(criteria, objNew, options, [callback]);
```
Useful options:
* `safe:true` Should always set if you have a callback.
* `multi:true` If set, all matching documents are updated, not just the first.
* `upsert:true` Atomically inserts the document if no documents matched.
Example for `update`:
```javascript
var mongodb = require('mongodb');
var server = new mongodb.Server("127.0.0.1", 27017, {});
new mongodb.Db('test', server, {w: 1}).open(function (error, client) {
if (error) throw error;
var collection = new mongodb.Collection(client, 'test_collection');
collection.update({hi: 'here'}, {$set: {hi: 'there'}}, {safe:true},
function(err) {
if (err) console.warn(err.message);
else console.log('successfully updated');
});
});
```
Find and modify
---------------
`findAndModify` is like `update`, but it also gives the updated document to
your callback. But there are a few key differences between findAndModify and
update:
1. The signatures differ.
2. You can only findAndModify a single item, not multiple items.
Signature:
```javascript
collection.findAndModify(query, sort, update, options, callback)
```
The sort parameter is used to specify which object to operate on, if more than
one document matches. It takes the same format as the cursor sort (see
Connection.find above).
See the
[MongoDB docs for findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command)
for more details.
Useful options:
* `remove:true` set to a true to remove the object before returning
* `new:true` set to true if you want to return the modified object rather than the original. Ignored for remove.
* `upsert:true` Atomically inserts the document if no documents matched.
Example for `findAndModify`:
```javascript
var mongodb = require('mongodb');
var server = new mongodb.Server("127.0.0.1", 27017, {});
new mongodb.Db('test', server, {w: 1}).open(function (error, client) {
if (error) throw error;
var collection = new mongodb.Collection(client, 'test_collection');
collection.findAndModify({hello: 'world'}, [['_id','asc']], {$set: {hi: 'there'}}, {},
function(err, object) {
if (err) console.warn(err.message);
else console.dir(object); // undefined if no matching object exists.
});
});
```
Save
----
The `save` method is a shorthand for upsert if the document contains an
`_id`, or an insert if there is no `_id`.
Sponsors
========
Just as Felix Geisendörfer I'm also working on the driver for my own startup and this driver is a big project that also benefits other companies who are using MongoDB.
If your company could benefit from a even better-engineered node.js mongodb driver I would appreciate any type of sponsorship you may be able to provide. All the sponsors will get a lifetime display in this readme, priority support and help on problems and votes on the roadmap decisions for the driver. If you are interested contact me on [christkv AT g m a i l.com](mailto:christkv@gmail.com) for details.
And I'm very thankful for code contributions. If you are interested in working on features please contact me so we can discuss API design and testing.
Release Notes
=============
See HISTORY
Credits
=======
1. [10gen](http://github.com/mongodb/mongo-ruby-driver/)
2. [Google Closure Library](http://code.google.com/closure/library/)
3. [Jonas Raoni Soares Silva](http://jsfromhell.com/classes/binary-parser)
Contributors
============
Aaron Heckmann, Christoph Pojer, Pau Ramon Revilla, Nathan White, Emmerman, Seth LaForge, Boris Filipov, Stefan Schärmeli, Tedde Lundgren, renctan, Sergey Ukustov, Ciaran Jessup, kuno, srimonti, Erik Abele, Pratik Daga, Slobodan Utvic, Kristina Chodorow, Yonathan Randolph, Brian Noguchi, Sam Epstein, James Harrison Fisher, Vladimir Dronnikov, Ben Hockey, Henrik Johansson, Simon Weare, Alex Gorbatchev, Shimon Doodkin, Kyle Mueller, Eran Hammer-Lahav, Marcin Ciszak, François de Metz, Vinay Pulim, nstielau, Adam Wiggins, entrinzikyl, Jeremy Selier, Ian Millington, Public Keating, andrewjstone, Christopher Stott, Corey Jewett, brettkiefer, Rob Holland, Senmiao Liu, heroic, gitfy
License
=======
Copyright 2009 - 2012 Christian Amor Kvalheim.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

1
node_modules/mongodb/index.js generated vendored Normal file
View File

@@ -0,0 +1 @@
module.exports = require('./lib/mongodb');

40
node_modules/mongodb/install.js generated vendored Normal file
View File

@@ -0,0 +1,40 @@
var spawn = require('child_process').spawn,
exec = require('child_process').exec;
process.stdout.write("================================================================================\n");
process.stdout.write("= =\n");
process.stdout.write("= To install with C++ bson parser do <npm install mongodb --mongodb:native> =\n");
process.stdout.write("= =\n");
process.stdout.write("================================================================================\n");
// Check if we want to build the native code
var build_native = process.env['npm_package_config_native'] != null ? process.env['npm_package_config_native'] : 'false';
build_native = build_native == 'true' ? true : false;
// If we are building the native bson extension ensure we use gmake if available
if(build_native) {
// Check if we need to use gmake
exec('which gmake', function(err, stdout, stderr) {
// Set up spawn command
var make = null;
// No gmake build using make
if(err != null) {
make = spawn('make', ['total']);
} else {
make = spawn('gmake', ['total']);
}
// Execute spawn
make.stdout.on('data', function(data) {
process.stdout.write(data);
})
make.stderr.on('data', function(data) {
process.stdout.write(data);
})
make.on('exit', function(code) {
process.stdout.write('child process exited with code ' + code + "\n");
})
});
}

338
node_modules/mongodb/lib/mongodb/admin.js generated vendored Normal file
View File

@@ -0,0 +1,338 @@
/*!
* Module dependencies.
*/
var Collection = require('./collection').Collection,
Cursor = require('./cursor').Cursor,
DbCommand = require('./commands/db_command').DbCommand;
/**
* Allows the user to access the admin functionality of MongoDB
*
* @class Represents the Admin methods of MongoDB.
* @param {Object} db Current db instance we wish to perform Admin operations on.
* @return {Function} Constructor for Admin type.
*/
function Admin(db) {
if(!(this instanceof Admin)) return new Admin(db);
this.db = db;
};
/**
* Retrieve the server information for the current
* instance of the db client
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from buildInfo or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.buildInfo = function(callback) {
this.serverInfo(callback);
}
/**
* Retrieve the server information for the current
* instance of the db client
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from serverInfo or null if an error occured.
* @return {null} Returns no result
* @api private
*/
Admin.prototype.serverInfo = function(callback) {
this.db.executeDbAdminCommand({buildinfo:1}, function(err, doc) {
if(err != null) return callback(err, null);
return callback(null, doc.documents[0]);
});
}
/**
* Retrieve this db's server status.
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from serverStatus or null if an error occured.
* @return {null}
* @api public
*/
Admin.prototype.serverStatus = function(callback) {
var self = this;
this.db.executeDbAdminCommand({serverStatus: 1}, function(err, doc) {
if(err == null && doc.documents[0].ok === 1) {
callback(null, doc.documents[0]);
} else {
if(err) return callback(err, false);
return callback(self.db.wrap(doc.documents[0]), false);
}
});
};
/**
* Retrieve the current profiling Level for MongoDB
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from profilingLevel or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.profilingLevel = function(callback) {
var self = this;
this.db.executeDbAdminCommand({profile:-1}, function(err, doc) {
doc = doc.documents[0];
if(err == null && doc.ok === 1) {
var was = doc.was;
if(was == 0) return callback(null, "off");
if(was == 1) return callback(null, "slow_only");
if(was == 2) return callback(null, "all");
return callback(new Error("Error: illegal profiling level value " + was), null);
} else {
err != null ? callback(err, null) : callback(new Error("Error with profile command"), null);
}
});
};
/**
* Ping the MongoDB server and retrieve results
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from ping or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.ping = function(options, callback) {
// Unpack calls
var args = Array.prototype.slice.call(arguments, 0);
callback = args.pop();
this.db.executeDbAdminCommand({ping: 1}, callback);
}
/**
* Authenticate against MongoDB
*
* @param {String} username The user name for the authentication.
* @param {String} password The password for the authentication.
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from authenticate or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.authenticate = function(username, password, callback) {
this.db.authenticate(username, password, {authdb: 'admin'}, function(err, doc) {
return callback(err, doc);
})
}
/**
* Logout current authenticated user
*
* @param {Object} [options] Optional parameters to the command.
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from logout or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.logout = function(callback) {
this.db.logout({authdb: 'admin'}, function(err, doc) {
return callback(err, doc);
})
}
/**
* Add a user to the MongoDB server, if the user exists it will
* overwrite the current password
*
* Options
* - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
*
* @param {String} username The user name for the authentication.
* @param {String} password The password for the authentication.
* @param {Object} [options] additional options during update.
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from addUser or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.addUser = function(username, password, options, callback) {
var args = Array.prototype.slice.call(arguments, 2);
callback = args.pop();
options = args.length ? args.shift() : {};
options.dbName = 'admin';
// Add user
this.db.addUser(username, password, options, function(err, doc) {
return callback(err, doc);
})
}
/**
* Remove a user from the MongoDB server
*
* Options
* - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
*
* @param {String} username The user name for the authentication.
* @param {Object} [options] additional options during update.
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from removeUser or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.removeUser = function(username, options, callback) {
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
options = args.length ? args.shift() : {};
options.dbName = 'admin';
this.db.removeUser(username, options, function(err, doc) {
return callback(err, doc);
})
}
/**
* Set the current profiling level of MongoDB
*
* @param {String} level The new profiling level (off, slow_only, all)
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from setProfilingLevel or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.setProfilingLevel = function(level, callback) {
var self = this;
var command = {};
var profile = 0;
if(level == "off") {
profile = 0;
} else if(level == "slow_only") {
profile = 1;
} else if(level == "all") {
profile = 2;
} else {
return callback(new Error("Error: illegal profiling level value " + level));
}
// Set up the profile number
command['profile'] = profile;
this.db.executeDbAdminCommand(command, function(err, doc) {
doc = doc.documents[0];
if(err == null && doc.ok === 1)
return callback(null, level);
return err != null ? callback(err, null) : callback(new Error("Error with profile command"), null);
});
};
/**
* Retrive the current profiling information for MongoDB
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from profilingInfo or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.profilingInfo = function(callback) {
try {
new Cursor(this.db, new Collection(this.db, DbCommand.SYSTEM_PROFILE_COLLECTION), {}, {}, {dbName: 'admin'}).toArray(function(err, items) {
return callback(err, items);
});
} catch (err) {
return callback(err, null);
}
};
/**
* Execute a db command against the Admin database
*
* @param {Object} command A command object `{ping:1}`.
* @param {Object} [options] Optional parameters to the command.
* @param {Function} callback this will be called after executing this method. The command always return the whole result of the command as the second parameter.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.command = function(command, options, callback) {
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
options = args.length ? args.shift() : {};
// Execute a command
this.db.executeDbAdminCommand(command, options, function(err, doc) {
// Ensure change before event loop executes
return callback != null ? callback(err, doc) : null;
});
}
/**
* Validate an existing collection
*
* @param {String} collectionName The name of the collection to validate.
* @param {Object} [options] Optional parameters to the command.
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from validateCollection or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.validateCollection = function(collectionName, options, callback) {
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
options = args.length ? args.shift() : {};
var self = this;
var command = {validate: collectionName};
var keys = Object.keys(options);
// Decorate command with extra options
for(var i = 0; i < keys.length; i++) {
if(options.hasOwnProperty(keys[i])) {
command[keys[i]] = options[keys[i]];
}
}
this.db.executeDbCommand(command, function(err, doc) {
if(err != null) return callback(err, null);
doc = doc.documents[0];
if(doc.ok === 0)
return callback(new Error("Error with validate command"), null);
if(doc.result != null && doc.result.constructor != String)
return callback(new Error("Error with validation data"), null);
if(doc.result != null && doc.result.match(/exception|corrupt/) != null)
return callback(new Error("Error: invalid collection " + collectionName), null);
if(doc.valid != null && !doc.valid)
return callback(new Error("Error: invalid collection " + collectionName), null);
return callback(null, doc);
});
};
/**
* List the available databases
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from listDatabases or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.listDatabases = function(callback) {
// Execute the listAllDatabases command
this.db.executeDbAdminCommand({listDatabases:1}, {}, function(err, doc) {
if(err != null) return callback(err, null);
return callback(null, doc.documents[0]);
});
}
/**
* Get ReplicaSet status
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from replSetGetStatus or null if an error occured.
* @return {null}
* @api public
*/
Admin.prototype.replSetGetStatus = function(callback) {
var self = this;
this.db.executeDbAdminCommand({replSetGetStatus:1}, function(err, doc) {
if(err == null && doc.documents[0].ok === 1)
return callback(null, doc.documents[0]);
if(err) return callback(err, false);
return callback(self.db.wrap(doc.documents[0]), false);
});
};
/**
* @ignore
*/
exports.Admin = Admin;

1699
node_modules/mongodb/lib/mongodb/collection.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
/**
Base object used for common functionality
**/
var BaseCommand = exports.BaseCommand = function BaseCommand() {
};
var id = 1;
BaseCommand.prototype.getRequestId = function getRequestId() {
if (!this.requestId) this.requestId = id++;
return this.requestId;
};
BaseCommand.prototype.setMongosReadPreference = function setMongosReadPreference(readPreference, tags) {}
BaseCommand.prototype.updateRequestId = function() {
this.requestId = id++;
return this.requestId;
};
// OpCodes
BaseCommand.OP_REPLY = 1;
BaseCommand.OP_MSG = 1000;
BaseCommand.OP_UPDATE = 2001;
BaseCommand.OP_INSERT = 2002;
BaseCommand.OP_GET_BY_OID = 2003;
BaseCommand.OP_QUERY = 2004;
BaseCommand.OP_GET_MORE = 2005;
BaseCommand.OP_DELETE = 2006;
BaseCommand.OP_KILL_CURSORS = 2007;

240
node_modules/mongodb/lib/mongodb/commands/db_command.js generated vendored Normal file
View File

@@ -0,0 +1,240 @@
var QueryCommand = require('./query_command').QueryCommand,
InsertCommand = require('./insert_command').InsertCommand,
inherits = require('util').inherits,
utils = require('../utils'),
crypto = require('crypto');
/**
Db Command
**/
var DbCommand = exports.DbCommand = function(dbInstance, collectionName, queryOptions, numberToSkip, numberToReturn, query, returnFieldSelector, options) {
QueryCommand.call(this);
this.collectionName = collectionName;
this.queryOptions = queryOptions;
this.numberToSkip = numberToSkip;
this.numberToReturn = numberToReturn;
this.query = query;
this.returnFieldSelector = returnFieldSelector;
this.db = dbInstance;
// Make sure we don't get a null exception
options = options == null ? {} : options;
// Let us defined on a command basis if we want functions to be serialized or not
if(options['serializeFunctions'] != null && options['serializeFunctions']) {
this.serializeFunctions = true;
}
};
inherits(DbCommand, QueryCommand);
// Constants
DbCommand.SYSTEM_NAMESPACE_COLLECTION = "system.namespaces";
DbCommand.SYSTEM_INDEX_COLLECTION = "system.indexes";
DbCommand.SYSTEM_PROFILE_COLLECTION = "system.profile";
DbCommand.SYSTEM_USER_COLLECTION = "system.users";
DbCommand.SYSTEM_COMMAND_COLLECTION = "$cmd";
DbCommand.SYSTEM_JS_COLLECTION = "system.js";
// New commands
DbCommand.NcreateIsMasterCommand = function(db, databaseName) {
return new DbCommand(db, databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'ismaster':1}, null);
};
// Provide constructors for different db commands
DbCommand.createIsMasterCommand = function(db) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'ismaster':1}, null);
};
DbCommand.createCollectionInfoCommand = function(db, selector) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_NAMESPACE_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, 0, selector, null);
};
DbCommand.createGetNonceCommand = function(db, options) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getnonce':1}, null);
};
DbCommand.createAuthenticationCommand = function(db, username, password, nonce, authdb) {
// Use node md5 generator
var md5 = crypto.createHash('md5');
// Generate keys used for authentication
md5.update(username + ":mongo:" + password);
var hash_password = md5.digest('hex');
// Final key
md5 = crypto.createHash('md5');
md5.update(nonce + username + hash_password);
var key = md5.digest('hex');
// Creat selector
var selector = {'authenticate':1, 'user':username, 'nonce':nonce, 'key':key};
// Create db command
return new DbCommand(db, authdb + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NONE, 0, -1, selector, null);
};
DbCommand.createLogoutCommand = function(db) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'logout':1}, null);
};
DbCommand.createCreateCollectionCommand = function(db, collectionName, options) {
var selector = {'create':collectionName};
// Modify the options to ensure correct behaviour
for(var name in options) {
if(options[name] != null && options[name].constructor != Function) selector[name] = options[name];
}
// Execute the command
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, selector, null);
};
DbCommand.createDropCollectionCommand = function(db, collectionName) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'drop':collectionName}, null);
};
DbCommand.createRenameCollectionCommand = function(db, fromCollectionName, toCollectionName) {
var renameCollection = db.databaseName + "." + fromCollectionName;
var toCollection = db.databaseName + "." + toCollectionName;
return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'renameCollection':renameCollection, 'to':toCollection}, null);
};
DbCommand.createGetLastErrorCommand = function(options, db) {
if (typeof db === 'undefined') {
db = options;
options = {};
}
// Final command
var command = {'getlasterror':1};
// If we have an options Object let's merge in the fields (fsync/wtimeout/w)
if('object' === typeof options) {
for(var name in options) {
command[name] = options[name]
}
}
// Special case for w == 1, remove the w
if(1 == command.w) {
delete command.w;
}
// Execute command
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command, null);
};
DbCommand.createGetLastStatusCommand = DbCommand.createGetLastErrorCommand;
DbCommand.createGetPreviousErrorsCommand = function(db) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getpreverror':1}, null);
};
DbCommand.createResetErrorHistoryCommand = function(db) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'reseterror':1}, null);
};
DbCommand.createCreateIndexCommand = function(db, collectionName, fieldOrSpec, options) {
var fieldHash = {};
var indexes = [];
var keys;
// Get all the fields accordingly
if('string' == typeof fieldOrSpec) {
// 'type'
indexes.push(fieldOrSpec + '_' + 1);
fieldHash[fieldOrSpec] = 1;
} else if(utils.isArray(fieldOrSpec)) {
fieldOrSpec.forEach(function(f) {
if('string' == typeof f) {
// [{location:'2d'}, 'type']
indexes.push(f + '_' + 1);
fieldHash[f] = 1;
} else if(utils.isArray(f)) {
// [['location', '2d'],['type', 1]]
indexes.push(f[0] + '_' + (f[1] || 1));
fieldHash[f[0]] = f[1] || 1;
} else if(utils.isObject(f)) {
// [{location:'2d'}, {type:1}]
keys = Object.keys(f);
keys.forEach(function(k) {
indexes.push(k + '_' + f[k]);
fieldHash[k] = f[k];
});
} else {
// undefined (ignore)
}
});
} else if(utils.isObject(fieldOrSpec)) {
// {location:'2d', type:1}
keys = Object.keys(fieldOrSpec);
keys.forEach(function(key) {
indexes.push(key + '_' + fieldOrSpec[key]);
fieldHash[key] = fieldOrSpec[key];
});
}
// Generate the index name
var indexName = typeof options.name == 'string'
? options.name
: indexes.join("_");
var selector = {
'ns': db.databaseName + "." + collectionName,
'key': fieldHash,
'name': indexName
}
// Ensure we have a correct finalUnique
var finalUnique = options == null || 'object' === typeof options
? false
: options;
// Set up options
options = options == null || typeof options == 'boolean'
? {}
: options;
// Add all the options
var keys = Object.keys(options);
for(var i = 0; i < keys.length; i++) {
selector[keys[i]] = options[keys[i]];
}
if(selector['unique'] == null)
selector['unique'] = finalUnique;
var name = db.databaseName + "." + DbCommand.SYSTEM_INDEX_COLLECTION;
var cmd = new InsertCommand(db, name, false);
return cmd.add(selector);
};
DbCommand.logoutCommand = function(db, command_hash, options) {
var dbName = options != null && options['authdb'] != null ? options['authdb'] : db.databaseName;
// Create logout command
return new DbCommand(db, dbName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null);
}
DbCommand.createDropIndexCommand = function(db, collectionName, indexName) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'deleteIndexes':collectionName, 'index':indexName}, null);
};
DbCommand.createReIndexCommand = function(db, collectionName) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'reIndex':collectionName}, null);
};
DbCommand.createDropDatabaseCommand = function(db) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'dropDatabase':1}, null);
};
DbCommand.createDbCommand = function(db, command_hash, options) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null, options);
};
DbCommand.createAdminDbCommand = function(db, command_hash) {
return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null);
};
DbCommand.createAdminDbCommandSlaveOk = function(db, command_hash) {
return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT | QueryCommand.OPTS_SLAVE, 0, -1, command_hash, null);
};
DbCommand.createDbSlaveOkCommand = function(db, command_hash, options) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT | QueryCommand.OPTS_SLAVE, 0, -1, command_hash, null, options);
};

View File

@@ -0,0 +1,114 @@
var BaseCommand = require('./base_command').BaseCommand,
inherits = require('util').inherits;
/**
Insert Document Command
**/
var DeleteCommand = exports.DeleteCommand = function(db, collectionName, selector, flags) {
BaseCommand.call(this);
// Validate correctness off the selector
var object = selector;
if(Buffer.isBuffer(object)) {
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) {
var error = new Error("delete raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
error.name = 'MongoError';
throw error;
}
}
this.flags = flags;
this.collectionName = collectionName;
this.selector = selector;
this.db = db;
};
inherits(DeleteCommand, BaseCommand);
DeleteCommand.OP_DELETE = 2006;
/*
struct {
MsgHeader header; // standard message header
int32 ZERO; // 0 - reserved for future use
cstring fullCollectionName; // "dbname.collectionname"
int32 ZERO; // 0 - reserved for future use
mongo.BSON selector; // query object. See below for details.
}
*/
DeleteCommand.prototype.toBinary = function() {
// Calculate total length of the document
var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + this.db.bson.calculateObjectSize(this.selector, false, true) + (4 * 4);
// Let's build the single pass buffer command
var _index = 0;
var _command = new Buffer(totalLengthOfCommand);
// Write the header information to the buffer
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
_command[_index] = totalLengthOfCommand & 0xff;
// Adjust index
_index = _index + 4;
// Write the request ID
_command[_index + 3] = (this.requestId >> 24) & 0xff;
_command[_index + 2] = (this.requestId >> 16) & 0xff;
_command[_index + 1] = (this.requestId >> 8) & 0xff;
_command[_index] = this.requestId & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the op_code for the command
_command[_index + 3] = (DeleteCommand.OP_DELETE >> 24) & 0xff;
_command[_index + 2] = (DeleteCommand.OP_DELETE >> 16) & 0xff;
_command[_index + 1] = (DeleteCommand.OP_DELETE >> 8) & 0xff;
_command[_index] = DeleteCommand.OP_DELETE & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the collection name to the command
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
_command[_index - 1] = 0;
// Write the flags
_command[_index + 3] = (this.flags >> 24) & 0xff;
_command[_index + 2] = (this.flags >> 16) & 0xff;
_command[_index + 1] = (this.flags >> 8) & 0xff;
_command[_index] = this.flags & 0xff;
// Adjust index
_index = _index + 4;
// Document binary length
var documentLength = 0
// Serialize the selector
// If we are passing a raw buffer, do minimal validation
if(Buffer.isBuffer(this.selector)) {
documentLength = this.selector.length;
// Copy the data into the current buffer
this.selector.copy(_command, _index);
} else {
documentLength = this.db.bson.serializeWithBufferAndIndex(this.selector, this.checkKeys, _command, _index) - _index + 1;
}
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
return _command;
};

View File

@@ -0,0 +1,83 @@
var BaseCommand = require('./base_command').BaseCommand,
inherits = require('util').inherits,
binaryutils = require('../utils');
/**
Get More Document Command
**/
var GetMoreCommand = exports.GetMoreCommand = function(db, collectionName, numberToReturn, cursorId) {
BaseCommand.call(this);
this.collectionName = collectionName;
this.numberToReturn = numberToReturn;
this.cursorId = cursorId;
this.db = db;
};
inherits(GetMoreCommand, BaseCommand);
GetMoreCommand.OP_GET_MORE = 2005;
GetMoreCommand.prototype.toBinary = function() {
// Calculate total length of the document
var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 8 + (4 * 4);
// Let's build the single pass buffer command
var _index = 0;
var _command = new Buffer(totalLengthOfCommand);
// Write the header information to the buffer
_command[_index++] = totalLengthOfCommand & 0xff;
_command[_index++] = (totalLengthOfCommand >> 8) & 0xff;
_command[_index++] = (totalLengthOfCommand >> 16) & 0xff;
_command[_index++] = (totalLengthOfCommand >> 24) & 0xff;
// Write the request ID
_command[_index++] = this.requestId & 0xff;
_command[_index++] = (this.requestId >> 8) & 0xff;
_command[_index++] = (this.requestId >> 16) & 0xff;
_command[_index++] = (this.requestId >> 24) & 0xff;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the op_code for the command
_command[_index++] = GetMoreCommand.OP_GET_MORE & 0xff;
_command[_index++] = (GetMoreCommand.OP_GET_MORE >> 8) & 0xff;
_command[_index++] = (GetMoreCommand.OP_GET_MORE >> 16) & 0xff;
_command[_index++] = (GetMoreCommand.OP_GET_MORE >> 24) & 0xff;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the collection name to the command
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
_command[_index - 1] = 0;
// Number of documents to return
_command[_index++] = this.numberToReturn & 0xff;
_command[_index++] = (this.numberToReturn >> 8) & 0xff;
_command[_index++] = (this.numberToReturn >> 16) & 0xff;
_command[_index++] = (this.numberToReturn >> 24) & 0xff;
// Encode the cursor id
var low_bits = this.cursorId.getLowBits();
// Encode low bits
_command[_index++] = low_bits & 0xff;
_command[_index++] = (low_bits >> 8) & 0xff;
_command[_index++] = (low_bits >> 16) & 0xff;
_command[_index++] = (low_bits >> 24) & 0xff;
var high_bits = this.cursorId.getHighBits();
// Encode high bits
_command[_index++] = high_bits & 0xff;
_command[_index++] = (high_bits >> 8) & 0xff;
_command[_index++] = (high_bits >> 16) & 0xff;
_command[_index++] = (high_bits >> 24) & 0xff;
// Return command
return _command;
};

View File

@@ -0,0 +1,147 @@
var BaseCommand = require('./base_command').BaseCommand,
inherits = require('util').inherits;
/**
Insert Document Command
**/
var InsertCommand = exports.InsertCommand = function(db, collectionName, checkKeys, options) {
BaseCommand.call(this);
this.collectionName = collectionName;
this.documents = [];
this.checkKeys = checkKeys == null ? true : checkKeys;
this.db = db;
this.flags = 0;
this.serializeFunctions = false;
// Ensure valid options hash
options = options == null ? {} : options;
// Check if we have keepGoing set -> set flag if it's the case
if(options['keepGoing'] != null && options['keepGoing']) {
// This will finish inserting all non-index violating documents even if it returns an error
this.flags = 1;
}
// Check if we have keepGoing set -> set flag if it's the case
if(options['continueOnError'] != null && options['continueOnError']) {
// This will finish inserting all non-index violating documents even if it returns an error
this.flags = 1;
}
// Let us defined on a command basis if we want functions to be serialized or not
if(options['serializeFunctions'] != null && options['serializeFunctions']) {
this.serializeFunctions = true;
}
};
inherits(InsertCommand, BaseCommand);
// OpCodes
InsertCommand.OP_INSERT = 2002;
InsertCommand.prototype.add = function(document) {
if(Buffer.isBuffer(document)) {
var object_size = document[0] | document[1] << 8 | document[2] << 16 | document[3] << 24;
if(object_size != document.length) {
var error = new Error("insert raw message size does not match message header size [" + document.length + "] != [" + object_size + "]");
error.name = 'MongoError';
throw error;
}
}
this.documents.push(document);
return this;
};
/*
struct {
MsgHeader header; // standard message header
int32 ZERO; // 0 - reserved for future use
cstring fullCollectionName; // "dbname.collectionname"
BSON[] documents; // one or more documents to insert into the collection
}
*/
InsertCommand.prototype.toBinary = function() {
// Calculate total length of the document
var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + (4 * 4);
// var docLength = 0
for(var i = 0; i < this.documents.length; i++) {
if(Buffer.isBuffer(this.documents[i])) {
totalLengthOfCommand += this.documents[i].length;
} else {
// Calculate size of document
totalLengthOfCommand += this.db.bson.calculateObjectSize(this.documents[i], this.serializeFunctions, true);
}
}
// Let's build the single pass buffer command
var _index = 0;
var _command = new Buffer(totalLengthOfCommand);
// Write the header information to the buffer
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
_command[_index] = totalLengthOfCommand & 0xff;
// Adjust index
_index = _index + 4;
// Write the request ID
_command[_index + 3] = (this.requestId >> 24) & 0xff;
_command[_index + 2] = (this.requestId >> 16) & 0xff;
_command[_index + 1] = (this.requestId >> 8) & 0xff;
_command[_index] = this.requestId & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the op_code for the command
_command[_index + 3] = (InsertCommand.OP_INSERT >> 24) & 0xff;
_command[_index + 2] = (InsertCommand.OP_INSERT >> 16) & 0xff;
_command[_index + 1] = (InsertCommand.OP_INSERT >> 8) & 0xff;
_command[_index] = InsertCommand.OP_INSERT & 0xff;
// Adjust index
_index = _index + 4;
// Write flags if any
_command[_index + 3] = (this.flags >> 24) & 0xff;
_command[_index + 2] = (this.flags >> 16) & 0xff;
_command[_index + 1] = (this.flags >> 8) & 0xff;
_command[_index] = this.flags & 0xff;
// Adjust index
_index = _index + 4;
// Write the collection name to the command
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
_command[_index - 1] = 0;
// Write all the bson documents to the buffer at the index offset
for(var i = 0; i < this.documents.length; i++) {
// Document binary length
var documentLength = 0
var object = this.documents[i];
// Serialize the selector
// If we are passing a raw buffer, do minimal validation
if(Buffer.isBuffer(object)) {
documentLength = object.length;
// Copy the data into the current buffer
object.copy(_command, _index);
} else {
// Serialize the document straight to the buffer
documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
}
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
}
return _command;
};

View File

@@ -0,0 +1,98 @@
var BaseCommand = require('./base_command').BaseCommand,
inherits = require('util').inherits,
binaryutils = require('../utils');
/**
Insert Document Command
**/
var KillCursorCommand = exports.KillCursorCommand = function(db, cursorIds) {
BaseCommand.call(this);
this.cursorIds = cursorIds;
this.db = db;
};
inherits(KillCursorCommand, BaseCommand);
KillCursorCommand.OP_KILL_CURSORS = 2007;
/*
struct {
MsgHeader header; // standard message header
int32 ZERO; // 0 - reserved for future use
int32 numberOfCursorIDs; // number of cursorIDs in message
int64[] cursorIDs; // array of cursorIDs to close
}
*/
KillCursorCommand.prototype.toBinary = function() {
// Calculate total length of the document
var totalLengthOfCommand = 4 + 4 + (4 * 4) + (this.cursorIds.length * 8);
// Let's build the single pass buffer command
var _index = 0;
var _command = new Buffer(totalLengthOfCommand);
// Write the header information to the buffer
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
_command[_index] = totalLengthOfCommand & 0xff;
// Adjust index
_index = _index + 4;
// Write the request ID
_command[_index + 3] = (this.requestId >> 24) & 0xff;
_command[_index + 2] = (this.requestId >> 16) & 0xff;
_command[_index + 1] = (this.requestId >> 8) & 0xff;
_command[_index] = this.requestId & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the op_code for the command
_command[_index + 3] = (KillCursorCommand.OP_KILL_CURSORS >> 24) & 0xff;
_command[_index + 2] = (KillCursorCommand.OP_KILL_CURSORS >> 16) & 0xff;
_command[_index + 1] = (KillCursorCommand.OP_KILL_CURSORS >> 8) & 0xff;
_command[_index] = KillCursorCommand.OP_KILL_CURSORS & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Number of cursors to kill
var numberOfCursors = this.cursorIds.length;
_command[_index + 3] = (numberOfCursors >> 24) & 0xff;
_command[_index + 2] = (numberOfCursors >> 16) & 0xff;
_command[_index + 1] = (numberOfCursors >> 8) & 0xff;
_command[_index] = numberOfCursors & 0xff;
// Adjust index
_index = _index + 4;
// Encode all the cursors
for(var i = 0; i < this.cursorIds.length; i++) {
// Encode the cursor id
var low_bits = this.cursorIds[i].getLowBits();
// Encode low bits
_command[_index + 3] = (low_bits >> 24) & 0xff;
_command[_index + 2] = (low_bits >> 16) & 0xff;
_command[_index + 1] = (low_bits >> 8) & 0xff;
_command[_index] = low_bits & 0xff;
// Adjust index
_index = _index + 4;
var high_bits = this.cursorIds[i].getHighBits();
// Encode high bits
_command[_index + 3] = (high_bits >> 24) & 0xff;
_command[_index + 2] = (high_bits >> 16) & 0xff;
_command[_index + 1] = (high_bits >> 8) & 0xff;
_command[_index] = high_bits & 0xff;
// Adjust index
_index = _index + 4;
}
return _command;
};

View File

@@ -0,0 +1,261 @@
var BaseCommand = require('./base_command').BaseCommand,
inherits = require('util').inherits;
/**
Insert Document Command
**/
var QueryCommand = exports.QueryCommand = function(db, collectionName, queryOptions, numberToSkip, numberToReturn, query, returnFieldSelector, options) {
BaseCommand.call(this);
// Validate correctness off the selector
var object = query,
object_size;
if(Buffer.isBuffer(object)) {
object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) {
var error = new Error("query selector raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
error.name = 'MongoError';
throw error;
}
}
object = returnFieldSelector;
if(Buffer.isBuffer(object)) {
object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) {
var error = new Error("query fields raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
error.name = 'MongoError';
throw error;
}
}
// Make sure we don't get a null exception
options = options == null ? {} : options;
// Set up options
this.collectionName = collectionName;
this.queryOptions = queryOptions;
this.numberToSkip = numberToSkip;
this.numberToReturn = numberToReturn;
// Ensure we have no null query
query = query == null ? {} : query;
// Wrap query in the $query parameter so we can add read preferences for mongos
this.query = query;
this.returnFieldSelector = returnFieldSelector;
this.db = db;
// Let us defined on a command basis if we want functions to be serialized or not
if(options['serializeFunctions'] != null && options['serializeFunctions']) {
this.serializeFunctions = true;
}
};
inherits(QueryCommand, BaseCommand);
QueryCommand.OP_QUERY = 2004;
/*
* Adds the read prefrence to the current command
*/
QueryCommand.prototype.setMongosReadPreference = function(readPreference, tags) {
// If we have readPreference set to true set to secondary prefered
if(readPreference == true) {
readPreference = 'secondaryPreferred';
} else if(readPreference == 'false') {
readPreference = 'primary';
}
// Force the slave ok flag to be set if we are not using primary read preference
if(readPreference != false && readPreference != 'primary') {
this.queryOptions |= QueryCommand.OPTS_SLAVE;
}
// Backward compatibility, ensure $query only set on read preference so 1.8.X works
if((readPreference != null || tags != null) && this.query['$query'] == null) {
this.query = {'$query': this.query};
}
// If we have no readPreference set and no tags, check if the slaveOk bit is set
if(readPreference == null && tags == null) {
// If we have a slaveOk bit set the read preference for MongoS
if(this.queryOptions & QueryCommand.OPTS_SLAVE) {
this.query['$readPreference'] = {mode: 'secondary'}
} else {
this.query['$readPreference'] = {mode: 'primary'}
}
}
// Build read preference object
if(typeof readPreference == 'object' && readPreference['_type'] == 'ReadPreference') {
this.query['$readPreference'] = readPreference.toObject();
} else if(readPreference != null) {
// Add the read preference
this.query['$readPreference'] = {mode: readPreference};
// If we have tags let's add them
if(tags != null) {
this.query['$readPreference']['tags'] = tags;
}
}
}
/*
struct {
MsgHeader header; // standard message header
int32 opts; // query options. See below for details.
cstring fullCollectionName; // "dbname.collectionname"
int32 numberToSkip; // number of documents to skip when returning results
int32 numberToReturn; // number of documents to return in the first OP_REPLY
BSON query ; // query object. See below for details.
[ BSON returnFieldSelector; ] // OPTIONAL : selector indicating the fields to return. See below for details.
}
*/
QueryCommand.prototype.toBinary = function() {
// Total length of the command
var totalLengthOfCommand = 0;
// Calculate total length of the document
if(Buffer.isBuffer(this.query)) {
totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 4 + this.query.length + (4 * 4);
} else {
totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 4 + this.db.bson.calculateObjectSize(this.query, this.serializeFunctions, true) + (4 * 4);
}
// Calculate extra fields size
if(this.returnFieldSelector != null && !(Buffer.isBuffer(this.returnFieldSelector))) {
if(Object.keys(this.returnFieldSelector).length > 0) {
totalLengthOfCommand += this.db.bson.calculateObjectSize(this.returnFieldSelector, this.serializeFunctions, true);
}
} else if(Buffer.isBuffer(this.returnFieldSelector)) {
totalLengthOfCommand += this.returnFieldSelector.length;
}
// Let's build the single pass buffer command
var _index = 0;
var _command = new Buffer(totalLengthOfCommand);
// Write the header information to the buffer
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
_command[_index] = totalLengthOfCommand & 0xff;
// Adjust index
_index = _index + 4;
// Write the request ID
_command[_index + 3] = (this.requestId >> 24) & 0xff;
_command[_index + 2] = (this.requestId >> 16) & 0xff;
_command[_index + 1] = (this.requestId >> 8) & 0xff;
_command[_index] = this.requestId & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the op_code for the command
_command[_index + 3] = (QueryCommand.OP_QUERY >> 24) & 0xff;
_command[_index + 2] = (QueryCommand.OP_QUERY >> 16) & 0xff;
_command[_index + 1] = (QueryCommand.OP_QUERY >> 8) & 0xff;
_command[_index] = QueryCommand.OP_QUERY & 0xff;
// Adjust index
_index = _index + 4;
// Write the query options
_command[_index + 3] = (this.queryOptions >> 24) & 0xff;
_command[_index + 2] = (this.queryOptions >> 16) & 0xff;
_command[_index + 1] = (this.queryOptions >> 8) & 0xff;
_command[_index] = this.queryOptions & 0xff;
// Adjust index
_index = _index + 4;
// Write the collection name to the command
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
_command[_index - 1] = 0;
// Write the number of documents to skip
_command[_index + 3] = (this.numberToSkip >> 24) & 0xff;
_command[_index + 2] = (this.numberToSkip >> 16) & 0xff;
_command[_index + 1] = (this.numberToSkip >> 8) & 0xff;
_command[_index] = this.numberToSkip & 0xff;
// Adjust index
_index = _index + 4;
// Write the number of documents to return
_command[_index + 3] = (this.numberToReturn >> 24) & 0xff;
_command[_index + 2] = (this.numberToReturn >> 16) & 0xff;
_command[_index + 1] = (this.numberToReturn >> 8) & 0xff;
_command[_index] = this.numberToReturn & 0xff;
// Adjust index
_index = _index + 4;
// Document binary length
var documentLength = 0
var object = this.query;
// Serialize the selector
if(Buffer.isBuffer(object)) {
documentLength = object.length;
// Copy the data into the current buffer
object.copy(_command, _index);
} else {
// Serialize the document straight to the buffer
documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
}
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
// Push field selector if available
if(this.returnFieldSelector != null && !(Buffer.isBuffer(this.returnFieldSelector))) {
if(Object.keys(this.returnFieldSelector).length > 0) {
var documentLength = this.db.bson.serializeWithBufferAndIndex(this.returnFieldSelector, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
}
} if(this.returnFieldSelector != null && Buffer.isBuffer(this.returnFieldSelector)) {
// Document binary length
var documentLength = 0
var object = this.returnFieldSelector;
// Serialize the selector
documentLength = object.length;
// Copy the data into the current buffer
object.copy(_command, _index);
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
}
// Return finished command
return _command;
};
// Constants
QueryCommand.OPTS_NONE = 0;
QueryCommand.OPTS_TAILABLE_CURSOR = 2;
QueryCommand.OPTS_SLAVE = 4;
QueryCommand.OPTS_OPLOG_REPLY = 8;
QueryCommand.OPTS_NO_CURSOR_TIMEOUT = 16;
QueryCommand.OPTS_AWAIT_DATA = 32;
QueryCommand.OPTS_EXHAUST = 64;
QueryCommand.OPTS_PARTIAL = 128;

View File

@@ -0,0 +1,174 @@
var BaseCommand = require('./base_command').BaseCommand,
inherits = require('util').inherits;
/**
Update Document Command
**/
var UpdateCommand = exports.UpdateCommand = function(db, collectionName, spec, document, options) {
BaseCommand.call(this);
var object = spec;
if(Buffer.isBuffer(object)) {
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) {
var error = new Error("update spec raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
error.name = 'MongoError';
throw error;
}
}
var object = document;
if(Buffer.isBuffer(object)) {
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) {
var error = new Error("update document raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
error.name = 'MongoError';
throw error;
}
}
this.collectionName = collectionName;
this.spec = spec;
this.document = document;
this.db = db;
this.serializeFunctions = false;
// Generate correct flags
var db_upsert = 0;
var db_multi_update = 0;
db_upsert = options != null && options['upsert'] != null ? (options['upsert'] == true ? 1 : 0) : db_upsert;
db_multi_update = options != null && options['multi'] != null ? (options['multi'] == true ? 1 : 0) : db_multi_update;
// Flags
this.flags = parseInt(db_multi_update.toString() + db_upsert.toString(), 2);
// Let us defined on a command basis if we want functions to be serialized or not
if(options['serializeFunctions'] != null && options['serializeFunctions']) {
this.serializeFunctions = true;
}
};
inherits(UpdateCommand, BaseCommand);
UpdateCommand.OP_UPDATE = 2001;
/*
struct {
MsgHeader header; // standard message header
int32 ZERO; // 0 - reserved for future use
cstring fullCollectionName; // "dbname.collectionname"
int32 flags; // bit vector. see below
BSON spec; // the query to select the document
BSON document; // the document data to update with or insert
}
*/
UpdateCommand.prototype.toBinary = function() {
// Calculate total length of the document
var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + this.db.bson.calculateObjectSize(this.spec, false, true) +
this.db.bson.calculateObjectSize(this.document, this.serializeFunctions, true) + (4 * 4);
// Let's build the single pass buffer command
var _index = 0;
var _command = new Buffer(totalLengthOfCommand);
// Write the header information to the buffer
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
_command[_index] = totalLengthOfCommand & 0xff;
// Adjust index
_index = _index + 4;
// Write the request ID
_command[_index + 3] = (this.requestId >> 24) & 0xff;
_command[_index + 2] = (this.requestId >> 16) & 0xff;
_command[_index + 1] = (this.requestId >> 8) & 0xff;
_command[_index] = this.requestId & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the op_code for the command
_command[_index + 3] = (UpdateCommand.OP_UPDATE >> 24) & 0xff;
_command[_index + 2] = (UpdateCommand.OP_UPDATE >> 16) & 0xff;
_command[_index + 1] = (UpdateCommand.OP_UPDATE >> 8) & 0xff;
_command[_index] = UpdateCommand.OP_UPDATE & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the collection name to the command
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
_command[_index - 1] = 0;
// Write the update flags
_command[_index + 3] = (this.flags >> 24) & 0xff;
_command[_index + 2] = (this.flags >> 16) & 0xff;
_command[_index + 1] = (this.flags >> 8) & 0xff;
_command[_index] = this.flags & 0xff;
// Adjust index
_index = _index + 4;
// Document binary length
var documentLength = 0
var object = this.spec;
// Serialize the selector
// If we are passing a raw buffer, do minimal validation
if(Buffer.isBuffer(object)) {
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) throw new Error("raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
documentLength = object.length;
// Copy the data into the current buffer
object.copy(_command, _index);
} else {
documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, false) - _index + 1;
}
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
// Document binary length
var documentLength = 0
var object = this.document;
// Serialize the document
// If we are passing a raw buffer, do minimal validation
if(Buffer.isBuffer(object)) {
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) throw new Error("raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
documentLength = object.length;
// Copy the data into the current buffer
object.copy(_command, _index);
} else {
documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
}
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
return _command;
};
// Constants
UpdateCommand.DB_UPSERT = 0;
UpdateCommand.DB_MULTI_UPDATE = 1;

50
node_modules/mongodb/lib/mongodb/connection/base.js generated vendored Normal file
View File

@@ -0,0 +1,50 @@
var EventEmitter = require('events').EventEmitter
, inherits = require('util').inherits;
var Base = function Base() {
EventEmitter.call(this);
}
/**
* @ignore
*/
inherits(Base, EventEmitter);
/**
* Fire all the errors
* @ignore
*/
Base.prototype.__executeAllCallbacksWithError = function(err) {
// Locate all the possible callbacks that need to return
for(var i = 0; i < this.dbInstances.length; i++) {
// Fetch the db Instance
var dbInstance = this.dbInstances[i];
// Check all callbacks
var keys = Object.keys(dbInstance._callBackStore._notReplied);
// For each key check if it's a callback that needs to be returned
for(var j = 0; j < keys.length; j++) {
var info = dbInstance._callBackStore._notReplied[keys[j]];
// Check if we have a chained command (findAndModify)
if(info && info['chained'] && Array.isArray(info['chained']) && info['chained'].length > 0) {
var chained = info['chained'];
// Only callback once and the last one is the right one
var finalCallback = chained.pop();
// Emit only the last event
dbInstance._callBackStore.emit(finalCallback, err, null);
// Put back the final callback to ensure we don't call all commands in the chain
chained.push(finalCallback);
// Remove all chained callbacks
for(var i = 0; i < chained.length; i++) {
delete dbInstance._callBackStore._notReplied[chained[i]];
}
} else {
dbInstance._callBackStore.emit(keys[j], err, null);
}
}
}
}
exports.Base = Base;

View File

@@ -0,0 +1,440 @@
var utils = require('./connection_utils'),
inherits = require('util').inherits,
net = require('net'),
EventEmitter = require('events').EventEmitter,
inherits = require('util').inherits,
binaryutils = require('../utils'),
tls = require('tls');
var Connection = exports.Connection = function(id, socketOptions) {
// Set up event emitter
EventEmitter.call(this);
// Store all socket options
this.socketOptions = socketOptions ? socketOptions : {host:'localhost', port:27017, domainSocket:false};
// Set keep alive default if not overriden
if(this.socketOptions.keepAlive == null && (process.platform !== "sunos" || process.platform !== "win32")) this.socketOptions.keepAlive = 100;
// Id for the connection
this.id = id;
// State of the connection
this.connected = false;
// Set if this is a domain socket
this.domainSocket = this.socketOptions.domainSocket;
//
// Connection parsing state
//
this.maxBsonSize = socketOptions.maxBsonSize ? socketOptions.maxBsonSize : Connection.DEFAULT_MAX_BSON_SIZE;
// Contains the current message bytes
this.buffer = null;
// Contains the current message size
this.sizeOfMessage = 0;
// Contains the readIndex for the messaage
this.bytesRead = 0;
// Contains spill over bytes from additional messages
this.stubBuffer = 0;
// Just keeps list of events we allow
this.eventHandlers = {error:[], parseError:[], poolReady:[], message:[], close:[], timeout:[], end:[]};
// Just keeps list of events we allow
resetHandlers(this, false);
}
// Set max bson size
Connection.DEFAULT_MAX_BSON_SIZE = 1024 * 1024 * 4;
// Inherit event emitter so we can emit stuff wohoo
inherits(Connection, EventEmitter);
Connection.prototype.start = function() {
// If we have a normal connection
if(this.socketOptions.ssl) {
// Create a new stream
this.connection = new net.Socket();
// Set timeout allowing backward compatibility to timeout if no connectTimeoutMS is set
this.connection.setTimeout(this.socketOptions.connectTimeoutMS != null ? this.socketOptions.connectTimeoutMS : this.socketOptions.timeout);
// Work around for 0.4.X
if(process.version.indexOf("v0.4") == -1) this.connection.setNoDelay(this.socketOptions.noDelay);
// Set keep alive if defined
if(process.version.indexOf("v0.4") == -1) {
if(this.socketOptions.keepAlive > 0) {
this.connection.setKeepAlive(true, this.socketOptions.keepAlive);
} else {
this.connection.setKeepAlive(false);
}
}
// Set up pair for tls with server, accept self-signed certificates as well
var pair = this.pair = tls.createSecurePair(false);
// Set up encrypted streams
this.pair.encrypted.pipe(this.connection);
this.connection.pipe(this.pair.encrypted);
// Setup clearText stream
this.writeSteam = this.pair.cleartext;
// Add all handlers to the socket to manage it
this.pair.on("secure", connectHandler(this));
this.pair.cleartext.on("data", createDataHandler(this));
// Add handlers
this.connection.on("error", errorHandler(this));
// this.connection.on("connect", connectHandler(this));
this.connection.on("end", endHandler(this));
this.connection.on("timeout", timeoutHandler(this));
this.connection.on("drain", drainHandler(this));
this.writeSteam.on("close", closeHandler(this));
// Start socket
this.connection.connect(this.socketOptions.port, this.socketOptions.host);
if(this.logger != null && this.logger.doDebug){
this.logger.debug("opened connection", this.socketOptions);
}
} else {
// Create new connection instance
if(this.domainSocket) {
this.connection = net.createConnection(this.socketOptions.host);
} else {
this.connection = net.createConnection(this.socketOptions.port, this.socketOptions.host);
}
if(this.logger != null && this.logger.doDebug){
this.logger.debug("opened connection", this.socketOptions);
}
// Set options on the socket
this.connection.setTimeout(this.socketOptions.connectTimeoutMS != null ? this.socketOptions.connectTimeoutMS : this.socketOptions.timeout);
// Work around for 0.4.X
if(process.version.indexOf("v0.4") == -1) this.connection.setNoDelay(this.socketOptions.noDelay);
// Set keep alive if defined
if(process.version.indexOf("v0.4") == -1) {
if(this.socketOptions.keepAlive > 0) {
this.connection.setKeepAlive(true, this.socketOptions.keepAlive);
} else {
this.connection.setKeepAlive(false);
}
}
// Set up write stream
this.writeSteam = this.connection;
// Add handlers
this.connection.on("error", errorHandler(this));
// Add all handlers to the socket to manage it
this.connection.on("connect", connectHandler(this));
// this.connection.on("end", endHandler(this));
this.connection.on("data", createDataHandler(this));
this.connection.on("timeout", timeoutHandler(this));
this.connection.on("drain", drainHandler(this));
this.connection.on("close", closeHandler(this));
}
}
// Check if the sockets are live
Connection.prototype.isConnected = function() {
return this.connected && !this.connection.destroyed && this.connection.writable && this.connection.readable;
}
// Write the data out to the socket
Connection.prototype.write = function(command, callback) {
try {
// If we have a list off commands to be executed on the same socket
if(Array.isArray(command)) {
for(var i = 0; i < command.length; i++) {
var binaryCommand = command[i].toBinary()
if(!this.socketOptions['disableDriverBSONSizeCheck'] && binaryCommand.length > this.maxBsonSize)
return callback(new Error("Document exceeds maximal allowed bson size of " + this.maxBsonSize + " bytes"));
if(this.logger != null && this.logger.doDebug)
this.logger.debug("writing command to mongodb", {binary: binaryCommand, json: command[i]});
var r = this.writeSteam.write(binaryCommand);
}
} else {
var binaryCommand = command.toBinary()
if(!this.socketOptions['disableDriverBSONSizeCheck'] && binaryCommand.length > this.maxBsonSize)
return callback(new Error("Document exceeds maximal allowed bson size of " + this.maxBsonSize + " bytes"));
if(this.logger != null && this.logger.doDebug)
this.logger.debug("writing command to mongodb", {binary: binaryCommand, json: command});
var r = this.writeSteam.write(binaryCommand);
}
} catch (err) {
if(typeof callback === 'function') callback(err);
}
}
// Force the closure of the connection
Connection.prototype.close = function() {
// clear out all the listeners
resetHandlers(this, true);
// Add a dummy error listener to catch any weird last moment errors (and ignore them)
this.connection.on("error", function() {})
// destroy connection
this.connection.destroy();
if(this.logger != null && this.logger.doDebug){
this.logger.debug("closed connection", this.connection);
}
}
// Reset all handlers
var resetHandlers = function(self, clearListeners) {
self.eventHandlers = {error:[], connect:[], close:[], end:[], timeout:[], parseError:[], message:[]};
// If we want to clear all the listeners
if(clearListeners && self.connection != null) {
var keys = Object.keys(self.eventHandlers);
// Remove all listeners
for(var i = 0; i < keys.length; i++) {
self.connection.removeAllListeners(keys[i]);
}
}
}
//
// Handlers
//
// Connect handler
var connectHandler = function(self) {
return function() {
// Set connected
self.connected = true;
// Now that we are connected set the socket timeout
self.connection.setTimeout(self.socketOptions.socketTimeoutMS != null ? self.socketOptions.socketTimeoutMS : self.socketOptions.timeout);
// Emit the connect event with no error
self.emit("connect", null, self);
}
}
var createDataHandler = exports.Connection.createDataHandler = function(self) {
// We need to handle the parsing of the data
// and emit the messages when there is a complete one
return function(data) {
// Parse until we are done with the data
while(data.length > 0) {
// If we still have bytes to read on the current message
if(self.bytesRead > 0 && self.sizeOfMessage > 0) {
// Calculate the amount of remaining bytes
var remainingBytesToRead = self.sizeOfMessage - self.bytesRead;
// Check if the current chunk contains the rest of the message
if(remainingBytesToRead > data.length) {
// Copy the new data into the exiting buffer (should have been allocated when we know the message size)
data.copy(self.buffer, self.bytesRead);
// Adjust the number of bytes read so it point to the correct index in the buffer
self.bytesRead = self.bytesRead + data.length;
// Reset state of buffer
data = new Buffer(0);
} else {
// Copy the missing part of the data into our current buffer
data.copy(self.buffer, self.bytesRead, 0, remainingBytesToRead);
// Slice the overflow into a new buffer that we will then re-parse
data = data.slice(remainingBytesToRead);
// Emit current complete message
try {
var emitBuffer = self.buffer;
// Reset state of buffer
self.buffer = null;
self.sizeOfMessage = 0;
self.bytesRead = 0;
self.stubBuffer = null;
// Emit the buffer
self.emit("message", emitBuffer, self);
} catch(err) {
var errorObject = {err:"socketHandler", trace:err, bin:buffer, parseState:{
sizeOfMessage:self.sizeOfMessage,
bytesRead:self.bytesRead,
stubBuffer:self.stubBuffer}};
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
// We got a parse Error fire it off then keep going
self.emit("parseError", errorObject, self);
}
}
} else {
// Stub buffer is kept in case we don't get enough bytes to determine the
// size of the message (< 4 bytes)
if(self.stubBuffer != null && self.stubBuffer.length > 0) {
// If we have enough bytes to determine the message size let's do it
if(self.stubBuffer.length + data.length > 4) {
// Prepad the data
var newData = new Buffer(self.stubBuffer.length + data.length);
self.stubBuffer.copy(newData, 0);
data.copy(newData, self.stubBuffer.length);
// Reassign for parsing
data = newData;
// Reset state of buffer
self.buffer = null;
self.sizeOfMessage = 0;
self.bytesRead = 0;
self.stubBuffer = null;
} else {
// Add the the bytes to the stub buffer
var newStubBuffer = new Buffer(self.stubBuffer.length + data.length);
// Copy existing stub buffer
self.stubBuffer.copy(newStubBuffer, 0);
// Copy missing part of the data
data.copy(newStubBuffer, self.stubBuffer.length);
// Exit parsing loop
data = new Buffer(0);
}
} else {
if(data.length > 4) {
// Retrieve the message size
var sizeOfMessage = binaryutils.decodeUInt32(data, 0);
// If we have a negative sizeOfMessage emit error and return
if(sizeOfMessage < 0 || sizeOfMessage > self.maxBsonSize) {
var errorObject = {err:"socketHandler", trace:'', bin:self.buffer, parseState:{
sizeOfMessage: sizeOfMessage,
bytesRead: self.bytesRead,
stubBuffer: self.stubBuffer}};
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
// We got a parse Error fire it off then keep going
self.emit("parseError", errorObject, self);
return;
}
// Ensure that the size of message is larger than 0 and less than the max allowed
if(sizeOfMessage > 4 && sizeOfMessage < self.maxBsonSize && sizeOfMessage > data.length) {
self.buffer = new Buffer(sizeOfMessage);
// Copy all the data into the buffer
data.copy(self.buffer, 0);
// Update bytes read
self.bytesRead = data.length;
// Update sizeOfMessage
self.sizeOfMessage = sizeOfMessage;
// Ensure stub buffer is null
self.stubBuffer = null;
// Exit parsing loop
data = new Buffer(0);
} else if(sizeOfMessage > 4 && sizeOfMessage < self.maxBsonSize && sizeOfMessage == data.length) {
try {
var emitBuffer = data;
// Reset state of buffer
self.buffer = null;
self.sizeOfMessage = 0;
self.bytesRead = 0;
self.stubBuffer = null;
// Exit parsing loop
data = new Buffer(0);
// Emit the message
self.emit("message", emitBuffer, self);
} catch (err) {
var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{
sizeOfMessage:self.sizeOfMessage,
bytesRead:self.bytesRead,
stubBuffer:self.stubBuffer}};
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
// We got a parse Error fire it off then keep going
self.emit("parseError", errorObject, self);
}
} else if(sizeOfMessage <= 4 || sizeOfMessage > self.maxBsonSize) {
var errorObject = {err:"socketHandler", trace:null, bin:data, parseState:{
sizeOfMessage:sizeOfMessage,
bytesRead:0,
buffer:null,
stubBuffer:null}};
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
// We got a parse Error fire it off then keep going
self.emit("parseError", errorObject, self);
// Clear out the state of the parser
self.buffer = null;
self.sizeOfMessage = 0;
self.bytesRead = 0;
self.stubBuffer = null;
// Exit parsing loop
data = new Buffer(0);
} else {
try {
var emitBuffer = data.slice(0, sizeOfMessage);
// Reset state of buffer
self.buffer = null;
self.sizeOfMessage = 0;
self.bytesRead = 0;
self.stubBuffer = null;
// Copy rest of message
data = data.slice(sizeOfMessage);
// Emit the message
self.emit("message", emitBuffer, self);
} catch (err) {
var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{
sizeOfMessage:sizeOfMessage,
bytesRead:self.bytesRead,
stubBuffer:self.stubBuffer}};
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
// We got a parse Error fire it off then keep going
self.emit("parseError", errorObject, self);
}
}
} else {
// Create a buffer that contains the space for the non-complete message
self.stubBuffer = new Buffer(data.length)
// Copy the data to the stub buffer
data.copy(self.stubBuffer, 0);
// Exit parsing loop
data = new Buffer(0);
}
}
}
}
}
}
var endHandler = function(self) {
return function() {
// Set connected to false
self.connected = false;
// Emit end event
self.emit("end", {err: 'connection received Fin packet from [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
}
}
var timeoutHandler = function(self) {
return function() {
self.emit("timeout", {err: 'connection to [' + self.socketOptions.host + ':' + self.socketOptions.port + '] timed out'}, self);
}
}
var drainHandler = function(self) {
return function() {
}
}
var errorHandler = function(self) {
return function(err) {
// Set connected to false
self.connected = false;
// Emit error
self.emit("error", {err: 'failed to connect to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
}
}
var closeHandler = function(self) {
return function(hadError) {
// If we have an error during the connection phase
if(hadError && !self.connected) {
// Set disconnected
self.connected = false;
// Emit error
self.emit("error", {err: 'failed to connect to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
} else {
// Set disconnected
self.connected = false;
// Emit close
self.emit("close", {err: 'connection closed to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
}
}
}
// Some basic defaults
Connection.DEFAULT_PORT = 27017;

View File

@@ -0,0 +1,251 @@
var utils = require('./connection_utils'),
inherits = require('util').inherits,
net = require('net'),
EventEmitter = require('events').EventEmitter,
inherits = require('util').inherits,
MongoReply = require("../responses/mongo_reply").MongoReply,
Connection = require("./connection").Connection;
var ConnectionPool = exports.ConnectionPool = function(host, port, poolSize, bson, socketOptions) {
if(typeof host !== 'string') {
throw new Error("host must be specified [" + host + "]");
}
// Set up event emitter
EventEmitter.call(this);
// Keep all options for the socket in a specific collection allowing the user to specify the
// Wished upon socket connection parameters
this.socketOptions = typeof socketOptions === 'object' ? socketOptions : {};
this.socketOptions.host = host;
this.socketOptions.port = port;
this.socketOptions.domainSocket = false;
this.bson = bson;
// PoolSize is always + 1 for special reserved "measurment" socket (like ping, stats etc)
this.poolSize = poolSize;
this.minPoolSize = Math.floor(this.poolSize / 2) + 1;
// Check if the host is a socket
if(host.match(/^\//)) {
this.socketOptions.domainSocket = true;
} else if(typeof port !== 'number') {
throw new Error("port must be specified [" + port + "]");
}
// Set default settings for the socket options
utils.setIntegerParameter(this.socketOptions, 'timeout', 0);
// Delay before writing out the data to the server
utils.setBooleanParameter(this.socketOptions, 'noDelay', true);
// Delay before writing out the data to the server
utils.setIntegerParameter(this.socketOptions, 'keepAlive', 0);
// Set the encoding of the data read, default is binary == null
utils.setStringParameter(this.socketOptions, 'encoding', null);
// Allows you to set a throttling bufferSize if you need to stop overflows
utils.setIntegerParameter(this.socketOptions, 'bufferSize', 0);
// Internal structures
this.openConnections = [];
// Assign connection id's
this.connectionId = 0;
// Current index for selection of pool connection
this.currentConnectionIndex = 0;
// The pool state
this._poolState = 'disconnected';
// timeout control
this._timeout = false;
}
inherits(ConnectionPool, EventEmitter);
ConnectionPool.prototype.setMaxBsonSize = function(maxBsonSize) {
if(maxBsonSize == null){
maxBsonSize = Connection.DEFAULT_MAX_BSON_SIZE;
}
for(var i = 0; i < this.openConnections.length; i++) {
this.openConnections[i].maxBsonSize = maxBsonSize;
}
}
// Start a function
var _connect = function(_self) {
return new function() {
// Create a new connection instance
var connection = new Connection(_self.connectionId++, _self.socketOptions);
// Set logger on pool
connection.logger = _self.logger;
// Connect handler
connection.on("connect", function(err, connection) {
// Add connection to list of open connections
_self.openConnections.push(connection);
// If the number of open connections is equal to the poolSize signal ready pool
if(_self.openConnections.length === _self.poolSize && _self._poolState !== 'disconnected') {
// Set connected
_self._poolState = 'connected';
// Emit pool ready
_self.emit("poolReady");
} else if(_self.openConnections.length < _self.poolSize) {
// We need to open another connection, make sure it's in the next
// tick so we don't get a cascade of errors
process.nextTick(function() {
_connect(_self);
});
}
});
var numberOfErrors = 0
// Error handler
connection.on("error", function(err, connection) {
numberOfErrors++;
// If we are already disconnected ignore the event
if(_self._poolState != 'disconnected' && _self.listeners("error").length > 0) {
_self.emit("error", err);
}
// Set disconnected
_self._poolState = 'disconnected';
// Stop
_self.stop();
});
// Close handler
connection.on("close", function() {
// If we are already disconnected ignore the event
if(_self._poolState !== 'disconnected' && _self.listeners("close").length > 0) {
_self.emit("close");
}
// Set disconnected
_self._poolState = 'disconnected';
// Stop
_self.stop();
});
// Timeout handler
connection.on("timeout", function(err, connection) {
// If we are already disconnected ignore the event
if(_self._poolState !== 'disconnected' && _self.listeners("timeout").length > 0) {
_self.emit("timeout", err);
}
// Set disconnected
_self._poolState = 'disconnected';
// Stop
_self.stop();
});
// Parse error, needs a complete shutdown of the pool
connection.on("parseError", function() {
// If we are already disconnected ignore the event
if(_self._poolState !== 'disconnected' && _self.listeners("parseError").length > 0) {
_self.emit("parseError", new Error("parseError occured"));
}
_self.stop();
});
connection.on("message", function(message) {
_self.emit("message", message);
});
// Start connection in the next tick
connection.start();
}();
}
// Start method, will throw error if no listeners are available
// Pass in an instance of the listener that contains the api for
// finding callbacks for a given message etc.
ConnectionPool.prototype.start = function() {
var markerDate = new Date().getTime();
var self = this;
if(this.listeners("poolReady").length == 0) {
throw "pool must have at least one listener ready that responds to the [poolReady] event";
}
// Set pool state to connecting
this._poolState = 'connecting';
this._timeout = false;
_connect(self);
}
// Restart a connection pool (on a close the pool might be in a wrong state)
ConnectionPool.prototype.restart = function() {
// Close all connections
this.stop(false);
// Now restart the pool
this.start();
}
// Stop the connections in the pool
ConnectionPool.prototype.stop = function(removeListeners) {
removeListeners = removeListeners == null ? true : removeListeners;
// Set disconnected
this._poolState = 'disconnected';
// Clear all listeners if specified
if(removeListeners) {
this.removeAllEventListeners();
}
// Close all connections
for(var i = 0; i < this.openConnections.length; i++) {
this.openConnections[i].close();
}
// Clean up
this.openConnections = [];
}
// Check the status of the connection
ConnectionPool.prototype.isConnected = function() {
return this._poolState === 'connected';
}
// Checkout a connection from the pool for usage, or grab a specific pool instance
ConnectionPool.prototype.checkoutConnection = function(id) {
var index = (this.currentConnectionIndex++ % (this.openConnections.length));
var connection = this.openConnections[index];
return connection;
}
ConnectionPool.prototype.getAllConnections = function() {
return this.openConnections;
}
// Remove all non-needed event listeners
ConnectionPool.prototype.removeAllEventListeners = function() {
this.removeAllListeners("close");
this.removeAllListeners("error");
this.removeAllListeners("timeout");
this.removeAllListeners("connect");
this.removeAllListeners("end");
this.removeAllListeners("parseError");
this.removeAllListeners("message");
this.removeAllListeners("poolReady");
}

View File

@@ -0,0 +1,23 @@
exports.setIntegerParameter = function(object, field, defaultValue) {
if(object[field] == null) {
object[field] = defaultValue;
} else if(typeof object[field] !== "number" && object[field] !== parseInt(object[field], 10)) {
throw "object field [" + field + "] must be a numeric integer value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]";
}
}
exports.setBooleanParameter = function(object, field, defaultValue) {
if(object[field] == null) {
object[field] = defaultValue;
} else if(typeof object[field] !== "boolean") {
throw "object field [" + field + "] must be a boolean value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]";
}
}
exports.setStringParameter = function(object, field, defaultValue) {
if(object[field] == null) {
object[field] = defaultValue;
} else if(typeof object[field] !== "string") {
throw "object field [" + field + "] must be a string value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]";
}
}

333
node_modules/mongodb/lib/mongodb/connection/mongos.js generated vendored Normal file
View File

@@ -0,0 +1,333 @@
var ReadPreference = require('./read_preference').ReadPreference
, Base = require('./base').Base
, inherits = require('util').inherits;
/**
* Mongos constructor provides a connection to a mongos proxy including failover to additional servers
*
* Options
* - **socketOptions** {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), connectTimeoutMS:(number), socketTimeoutMS:(number))
* - **ha** {Boolean, default:true}, turn on high availability, attempts to reconnect to down proxies
* - **haInterval** {Number, default:2000}, time between each replicaset status check.
*
* @class Represents a Mongos connection with failover to backup proxies
* @param {Array} list of mongos server objects
* @param {Object} [options] additional options for the mongos connection
*/
var Mongos = function Mongos(servers, options) {
// Set up basic
if(!(this instanceof Mongos))
return new Mongos(servers, options);
// Set up event emitter
Base.call(this);
// Throw error on wrong setup
if(servers == null || !Array.isArray(servers) || servers.length == 0)
throw new Error("At least one mongos proxy must be in the array");
// Ensure we have at least an empty options object
this.options = options == null ? {} : options;
// Set default connection pool options
this.socketOptions = this.options.socketOptions != null ? this.options.socketOptions : {};
// Enabled ha
this.haEnabled = this.options['ha'] == null ? true : this.options['ha'];
// How often are we checking for new servers in the replicaset
this.mongosStatusCheckInterval = this.options['haInterval'] == null ? 2000 : this.options['haInterval'];
// Save all the server connections
this.servers = servers;
// Servers we need to attempt reconnect with
this.downServers = [];
// Just contains the current lowest ping time and server
this.lowestPingTimeServer = null;
this.lowestPingTime = 0;
// Add options to servers
for(var i = 0; i < this.servers.length; i++) {
var server = this.servers[i];
// Default empty socket options object
var socketOptions = {host: server.host, port: server.port};
// If a socket option object exists clone it
if(this.socketOptions != null) {
var keys = Object.keys(this.socketOptions);
for(var k = 0; k < keys.length;k++) socketOptions[keys[i]] = this.socketOptions[keys[i]];
}
// Set socket options
server.socketOptions = socketOptions;
}
}
/**
* @ignore
*/
inherits(Mongos, Base);
/**
* @ignore
*/
Mongos.prototype.isMongos = function() {
return true;
}
/**
* @ignore
*/
Mongos.prototype.connect = function(db, options, callback) {
if('function' === typeof options) callback = options, options = {};
if(options == null) options = {};
if(!('function' === typeof callback)) callback = null;
var self = this;
// Keep reference to parent
this.db = db;
// Set server state to connecting
this._serverState = 'connecting';
// Number of total servers that need to initialized (known servers)
this._numberOfServersLeftToInitialize = this.servers.length;
// Default to the first proxy server as the first one to use
this._currentMongos = this.servers[0];
// Connect handler
var connectHandler = function(_server) {
return function(err, result) {
self._numberOfServersLeftToInitialize = self._numberOfServersLeftToInitialize - 1;
if(self._numberOfServersLeftToInitialize == 0) {
// Start ha function if it exists
if(self.haEnabled) {
// Setup the ha process
self._replicasetTimeoutId = setTimeout(self.mongosCheckFunction, self.mongosStatusCheckInterval);
}
// Set the mongos to connected
self._serverState = "connected";
// Emit the open event
self.db.emit("open", null, self.db);
// Callback
callback(null, self.db);
}
}
};
// Error handler
var errorOrCloseHandler = function(_server) {
return function(err, result) {
// Create current mongos comparision
var currentUrl = self._currentMongos.host + ":" + self._currentMongos.port;
var serverUrl = this.host + ":" + this.port;
// We need to check if the server that closed is the actual current proxy we are using, otherwise
// just ignore
if(currentUrl == serverUrl) {
// Remove the server from the list
if(self.servers.indexOf(_server) != -1) {
self.servers.splice(self.servers.indexOf(_server), 1);
}
// Pick the next one on the list if there is one
for(var i = 0; i < self.servers.length; i++) {
// Grab the server out of the array (making sure there is no servers in the list if none available)
var server = self.servers[i];
// Generate url for comparision
var serverUrl = server.host + ":" + server.port;
// It's not the current one and connected set it as the current db
if(currentUrl != serverUrl && server.isConnected()) {
self._currentMongos = server;
break;
}
}
}
// Ensure we don't store the _server twice
if(self.downServers.indexOf(_server) == -1) {
// Add the server instances
self.downServers.push(_server);
}
}
}
// Mongo function
this.mongosCheckFunction = function() {
// If we have down servers let's attempt a reconnect
if(self.downServers.length > 0) {
var numberOfServersLeft = self.downServers.length;
// Attempt to reconnect
for(var i = 0; i < self.downServers.length; i++) {
var downServer = self.downServers.pop();
// Attemp to reconnect
downServer.connect(self.db, {returnIsMasterResults: true}, function(_server) {
// Return a function to check for the values
return function(err, result) {
// Adjust the number of servers left
numberOfServersLeft = numberOfServersLeft - 1;
if(err != null) {
self.downServers.push(_server);
} else {
// Add server event handlers
_server.on("close", errorOrCloseHandler(_server));
_server.on("error", errorOrCloseHandler(_server));
// Add to list of servers
self.servers.push(_server);
}
if(numberOfServersLeft <= 0) {
// Perfom another ha
self._replicasetTimeoutId = setTimeout(self.mongosCheckFunction, self.mongosStatusCheckInterval);
}
}
}(downServer));
}
} else if(self.servers.length > 0) {
var numberOfServersLeft = self.servers.length;
var _s = new Date().getTime()
// Else let's perform a ping command
for(var i = 0; i < self.servers.length; i++) {
var executePing = function(_server) {
// Get a read connection
var _connection = _server.checkoutReader();
// Execute ping command
self.db.command({ping:1}, {connection:_connection}, function(err, result) {
var pingTime = new Date().getTime() - _s;
// If no server set set the first one, otherwise check
// the lowest ping time and assign the server if it's got a lower ping time
if(self.lowestPingTimeServer == null) {
self.lowestPingTimeServer = _server;
self.lowestPingTime = pingTime;
self._currentMongos = _server;
} else if(self.lowestPingTime > pingTime
&& (_server.host != self.lowestPingTimeServer.host || _server.port != self.lowestPingTimeServer.port)) {
self.lowestPingTimeServer = _server;
self.lowestPingTime = pingTime;
self._currentMongos = _server;
}
// Number of servers left
numberOfServersLeft = numberOfServersLeft - 1;
// All active mongos's pinged
if(numberOfServersLeft == 0) {
// Perfom another ha
self._replicasetTimeoutId = setTimeout(self.mongosCheckFunction, self.mongosStatusCheckInterval);
}
})
}
// Execute the function
executePing(self.servers[i]);
}
} else {
self._replicasetTimeoutId = setTimeout(self.mongosCheckFunction, self.mongosStatusCheckInterval);
}
}
// Connect all the server instances
for(var i = 0; i < this.servers.length; i++) {
// Get the connection
var server = this.servers[i];
server.mongosInstance = this;
// Add server event handlers
server.on("close", errorOrCloseHandler(server));
server.on("timeout", errorOrCloseHandler(server));
server.on("error", errorOrCloseHandler(server));
// Connect the instance
server.connect(self.db, {returnIsMasterResults: true}, connectHandler(server));
}
}
/**
* @ignore
* Just return the currently picked active connection
*/
Mongos.prototype.allServerInstances = function() {
return this.servers;
}
/**
* Always ourselves
* @ignore
*/
Mongos.prototype.setReadPreference = function() {}
/**
* @ignore
*/
Mongos.prototype.allRawConnections = function() {
// Neeed to build a complete list of all raw connections, start with master server
var allConnections = [];
// Add all connections
for(var i = 0; i < this.servers.length; i++) {
allConnections = allConnections.concat(this.servers[i].allRawConnections());
}
// Return all the conections
return allConnections;
}
/**
* @ignore
*/
Mongos.prototype.isConnected = function() {
return this._serverState == "connected";
}
/**
* @ignore
*/
Mongos.prototype.checkoutWriter = function() {
// No current mongo, just pick first server
if(this._currentMongos == null && this.servers.length > 0) {
return this.servers[0].checkoutWriter();
}
return this._currentMongos.checkoutWriter();
}
/**
* @ignore
*/
Mongos.prototype.checkoutReader = function(read) {
// If we have a read preference object unpack it
if(typeof read == 'object' && read['_type'] == 'ReadPreference') {
// Validate if the object is using a valid mode
if(!read.isValid()) throw new Error("Illegal readPreference mode specified, " + read.mode);
} else if(!ReadPreference.isValid(read)) {
throw new Error("Illegal readPreference mode specified, " + read);
}
// No current mongo, just pick first server
if(this._currentMongos == null && this.servers.length > 0) {
return this.servers[0].checkoutReader();
}
return this._currentMongos.checkoutReader();
}
/**
* @ignore
*/
Mongos.prototype.close = function(callback) {
var self = this;
// Set server status as disconnected
this._serverState = 'disconnected';
// Number of connections to close
var numberOfConnectionsToClose = self.servers.length;
// If we have a ha process running kill it
if(self._replicasetTimeoutId != null) clearTimeout(self._replicasetTimeoutId);
// Close all proxy connections
for(var i = 0; i < self.servers.length; i++) {
self.servers[i].close(function(err, result) {
numberOfConnectionsToClose = numberOfConnectionsToClose - 1;
// Callback if we have one defined
if(numberOfConnectionsToClose == 0 && typeof callback == 'function') {
callback(null);
}
});
}
}
/**
* @ignore
* Return the used state
*/
Mongos.prototype._isUsed = function() {
return this._used;
}
exports.Mongos = Mongos;

View File

@@ -0,0 +1,66 @@
/**
* A class representation of the Read Preference.
*
* Read Preferences
* - **ReadPreference.PRIMARY**, Read from primary only. All operations produce an error (throw an exception where applicable) if primary is unavailable. Cannot be combined with tags (This is the default.).
* - **ReadPreference.PRIMARY_PREFERRED**, Read from primary if available, otherwise a secondary.
* - **ReadPreference.SECONDARY**, Read from secondary if available, otherwise error.
* - **ReadPreference.SECONDARY_PREFERRED**, Read from a secondary if available, otherwise read from the primary.
* - **ReadPreference.NEAREST**, All modes read from among the nearest candidates, but unlike other modes, NEAREST will include both the primary and all secondaries in the random selection.
*
* @class Represents a Read Preference.
* @param {String} the read preference type
* @param {Object} tags
* @return {ReadPreference}
*/
var ReadPreference = function(mode, tags) {
if(!(this instanceof ReadPreference))
return new ReadPreference(mode, tags);
this._type = 'ReadPreference';
this.mode = mode;
this.tags = tags;
}
/**
* @ignore
*/
ReadPreference.isValid = function(_mode) {
return (_mode == ReadPreference.PRIMARY || _mode == ReadPreference.PRIMARY_PREFERRED
|| _mode == ReadPreference.SECONDARY || _mode == ReadPreference.SECONDARY_PREFERRED
|| _mode == ReadPreference.NEAREST);
}
/**
* @ignore
*/
ReadPreference.prototype.isValid = function(mode) {
var _mode = typeof mode == 'string' ? mode : this.mode;
return ReadPreference.isValid(_mode);
}
/**
* @ignore
*/
ReadPreference.prototype.toObject = function() {
var object = {mode:this.mode};
if(this.tags != null) {
object['tags'] = this.tags;
}
return object;
}
/**
* @ignore
*/
ReadPreference.PRIMARY = 'primary';
ReadPreference.PRIMARY_PREFERRED = 'primaryPreferred';
ReadPreference.SECONDARY = 'secondary';
ReadPreference.SECONDARY_PREFERRED = 'secondaryPreferred';
ReadPreference.NEAREST = 'nearest'
/**
* @ignore
*/
exports.ReadPreference = ReadPreference;

1311
node_modules/mongodb/lib/mongodb/connection/repl_set.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

860
node_modules/mongodb/lib/mongodb/connection/server.js generated vendored Normal file
View File

@@ -0,0 +1,860 @@
var Connection = require('./connection').Connection,
ReadPreference = require('./read_preference').ReadPreference,
DbCommand = require('../commands/db_command').DbCommand,
MongoReply = require('../responses/mongo_reply').MongoReply,
ConnectionPool = require('./connection_pool').ConnectionPool,
EventEmitter = require('events').EventEmitter,
Base = require('./base').Base,
utils = require('../utils'),
inherits = require('util').inherits;
/**
* Class representing a single MongoDB Server connection
*
* Options
* - **readPreference** {String, default:null}, set's the read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
* - **ssl** {Boolean, default:false}, use ssl connection (needs to have a mongod server with ssl support)
* - **slaveOk** {Boolean, default:false}, legacy option allowing reads from secondary, use **readPrefrence** instead.
* - **poolSize** {Number, default:5}, number of connections in the connection pool, set to 5 as default for legacy reasons.
* - **socketOptions** {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), connectTimeoutMS:(number), socketTimeoutMS:(number))
* - **logger** {Object, default:null}, an object representing a logger that you want to use, needs to support functions debug, log, error **({error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}})**.
* - **auto_reconnect** {Boolean, default:false}, reconnect on error.
* - **disableDriverBSONSizeCheck** {Boolean, default:false}, force the server to error if the BSON message is to big
*
* @class Represents a Server connection.
* @param {String} host the server host
* @param {Number} port the server port
* @param {Object} [options] optional options for insert command
*/
function Server(host, port, options) {
// Set up Server instance
if(!(this instanceof Server)) return new Server(host, port, options);
// Set up event emitter
Base.call(this);
// Ensure correct values
if(port != null && typeof port == 'object') {
options = port;
port = Connection.DEFAULT_PORT;
}
var self = this;
this.host = host;
this.port = port;
this.options = options == null ? {} : options;
this.internalConnection;
this.internalMaster = false;
this.connected = false;
this.poolSize = this.options.poolSize == null ? 5 : this.options.poolSize;
this.disableDriverBSONSizeCheck = this.options.disableDriverBSONSizeCheck != null ? this.options.disableDriverBSONSizeCheck : false;
this.ssl = this.options.ssl == null ? false : this.options.ssl;
this.slaveOk = this.options["slave_ok"] ? this.options["slave_ok"] : this.options["slaveOk"];
this._used = false;
this.replicasetInstance = null;
// Get the readPreference
var readPreference = this.options['readPreference'];
// If readPreference is an object get the mode string
var validateReadPreference = readPreference != null && typeof readPreference == 'object' ? readPreference.mode : readPreference;
// Read preference setting
if(validateReadPreference != null) {
if(validateReadPreference != ReadPreference.PRIMARY && validateReadPreference != ReadPreference.SECONDARY && validateReadPreference != ReadPreference.NEAREST
&& validateReadPreference != ReadPreference.SECONDARY_PREFERRED && validateReadPreference != ReadPreference.PRIMARY_PREFERRED) {
throw new Error("Illegal readPreference mode specified, " + validateReadPreference);
}
// Set read Preference
this._readPreference = readPreference;
} else {
this._readPreference = null;
}
// Contains the isMaster information returned from the server
this.isMasterDoc;
// Set default connection pool options
this.socketOptions = this.options.socketOptions != null ? this.options.socketOptions : {};
if(this.disableDriverBSONSizeCheck) this.socketOptions.disableDriverBSONSizeCheck = this.disableDriverBSONSizeCheck;
// Set ssl up if it's defined
if(this.ssl) {
this.socketOptions.ssl = true;
}
// Set up logger if any set
this.logger = this.options.logger != null
&& (typeof this.options.logger.debug == 'function')
&& (typeof this.options.logger.error == 'function')
&& (typeof this.options.logger.log == 'function')
? this.options.logger : {error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}};
// Just keeps list of events we allow
this.eventHandlers = {error:[], parseError:[], poolReady:[], message:[], close:[], timeout:[]};
// Internal state of server connection
this._serverState = 'disconnected';
// this._timeout = false;
// Contains state information about server connection
this._state = {'runtimeStats': {'queryStats':new RunningStats()}};
// Do we record server stats or not
this.recordQueryStats = false;
};
/**
* @ignore
*/
inherits(Server, Base);
//
// Deprecated, USE ReadPreferences class
//
Server.READ_PRIMARY = ReadPreference.PRIMARY;
Server.READ_SECONDARY = ReadPreference.SECONDARY_PREFERRED;
Server.READ_SECONDARY_ONLY = ReadPreference.SECONDARY;
/**
* Always ourselves
* @ignore
*/
Server.prototype.setReadPreference = function() {}
/**
* @ignore
*/
Server.prototype.isMongos = function() {
return this.isMasterDoc != null && this.isMasterDoc['msg'] == "isdbgrid" ? true : false;
}
/**
* @ignore
*/
Server.prototype._isUsed = function() {
return this._used;
}
/**
* @ignore
*/
Server.prototype.close = function(callback) {
// Remove all local listeners
this.removeAllListeners();
if(this.connectionPool != null) {
// Remove all the listeners on the pool so it does not fire messages all over the place
this.connectionPool.removeAllEventListeners();
// Close the connection if it's open
this.connectionPool.stop(true);
}
// Set server status as disconnected
this._serverState = 'disconnected';
// Peform callback if present
if(typeof callback === 'function') callback();
};
/**
* @ignore
*/
Server.prototype.isConnected = function() {
return this._serverState == 'connected';
}
/**
* @ignore
*/
Server.prototype.allServerInstances = function() {
return [this];
}
/**
* @ignore
*/
Server.prototype.isSetMember = function() {
return this.replicasetInstance != null || this.mongosInstance != null;
}
/**
* Assigns a replica set to this `server`.
*
* @param {ReplSet} replset
* @ignore
*/
Server.prototype.assignReplicaSet = function (replset) {
this.replicasetInstance = replset;
this.inheritReplSetOptionsFrom(replset);
this.enableRecordQueryStats(replset.recordQueryStats);
}
/**
* Takes needed options from `replset` and overwrites
* our own options.
*
* @param {ReplSet} replset
* @ignore
*/
Server.prototype.inheritReplSetOptionsFrom = function (replset) {
this.socketOptions = {};
this.socketOptions.connectTimeoutMS = replset._connectTimeoutMS;
if(replset.ssl)
this.socketOptions.ssl = true;
// If a socket option object exists clone it
if(utils.isObject(replset.socketOptions)) {
var keys = Object.keys(replset.socketOptions);
for(var i = 0; i < keys.length; i++)
this.socketOptions[keys[i]] = replset.socketOptions[keys[i]];
}
}
/**
* Opens this server connection.
*
* @ignore
*/
Server.prototype.connect = function(dbInstance, options, callback) {
if('function' === typeof options) callback = options, options = {};
if(options == null) options = {};
if(!('function' === typeof callback)) callback = null;
// Currently needed to work around problems with multiple connections in a pool with ssl
// TODO fix if possible
if(this.ssl == true) {
// Set up socket options for ssl
this.socketOptions.ssl = true;
}
// Let's connect
var server = this;
// Let's us override the main receiver of events
var eventReceiver = options.eventReceiver != null ? options.eventReceiver : this;
// Creating dbInstance
this.dbInstance = dbInstance;
// Save reference to dbInstance
this.dbInstances = [dbInstance];
// Force connection pool if there is one
if(server.connectionPool) server.connectionPool.stop();
// Set server state to connecting
this._serverState = 'connecting';
// Ensure dbInstance can do a slave query if it's set
dbInstance.slaveOk = this.slaveOk ? this.slaveOk : dbInstance.slaveOk;
// Create connection Pool instance with the current BSON serializer
var connectionPool = new ConnectionPool(this.host, this.port, this.poolSize, dbInstance.bson, this.socketOptions);
// Set logger on pool
connectionPool.logger = this.logger;
// Set up a new pool using default settings
server.connectionPool = connectionPool;
// Set basic parameters passed in
var returnIsMasterResults = options.returnIsMasterResults == null ? false : options.returnIsMasterResults;
// Create a default connect handler, overriden when using replicasets
var connectCallback = function(err, reply) {
// ensure no callbacks get called twice
var internalCallback = callback;
callback = null;
// If something close down the connection and removed the callback before
// proxy killed connection etc, ignore the erorr as close event was isssued
if(err != null && internalCallback == null) return;
// Internal callback
if(err != null) return internalCallback(err, null);
server.master = reply.documents[0].ismaster == 1 ? true : false;
server.connectionPool.setMaxBsonSize(reply.documents[0].maxBsonObjectSize);
// Set server as connected
server.connected = true;
// Save document returned so we can query it
server.isMasterDoc = reply.documents[0];
// Emit open event
_emitAcrossAllDbInstances(server, eventReceiver, "open", null, returnIsMasterResults ? reply : dbInstance, null);
// If we have it set to returnIsMasterResults
if(returnIsMasterResults) {
internalCallback(null, reply, server);
} else {
internalCallback(null, dbInstance, server);
}
};
// Let's us override the main connect callback
var connectHandler = options.connectHandler == null ? connectCallback : options.connectHandler;
// Set up on connect method
connectionPool.on("poolReady", function() {
// Create db command and Add the callback to the list of callbacks by the request id (mapping outgoing messages to correct callbacks)
var db_command = DbCommand.NcreateIsMasterCommand(dbInstance, dbInstance.databaseName);
// Check out a reader from the pool
var connection = connectionPool.checkoutConnection();
// Set server state to connEcted
server._serverState = 'connected';
// Register handler for messages
dbInstance._registerHandler(db_command, false, connection, connectHandler);
// Write the command out
connection.write(db_command);
})
// Set up item connection
connectionPool.on("message", function(message) {
// Attempt to parse the message
try {
// Create a new mongo reply
var mongoReply = new MongoReply()
// Parse the header
mongoReply.parseHeader(message, connectionPool.bson)
// If message size is not the same as the buffer size
// something went terribly wrong somewhere
if(mongoReply.messageLength != message.length) {
// Emit the error
if(eventReceiver.listeners("error") && eventReceiver.listeners("error").length > 0) eventReceiver.emit("error", new Error("bson length is different from message length"), server);
// Remove all listeners
server.removeAllListeners();
} else {
var startDate = new Date().getTime();
// Callback instance
var callbackInfo = null;
var dbInstanceObject = null;
// Locate a callback instance and remove any additional ones
for(var i = 0; i < server.dbInstances.length; i++) {
var dbInstanceObjectTemp = server.dbInstances[i];
var hasHandler = dbInstanceObjectTemp._hasHandler(mongoReply.responseTo.toString());
// Assign the first one we find and remove any duplicate ones
if(hasHandler && callbackInfo == null) {
callbackInfo = dbInstanceObjectTemp._findHandler(mongoReply.responseTo.toString());
dbInstanceObject = dbInstanceObjectTemp;
} else if(hasHandler) {
dbInstanceObjectTemp._removeHandler(mongoReply.responseTo.toString());
}
}
// The command executed another request, log the handler again under that request id
if(mongoReply.requestId > 0 && mongoReply.cursorId.toString() != "0"
&& callbackInfo && callbackInfo.info && callbackInfo.info.exhaust) {
dbInstance._reRegisterHandler(mongoReply.requestId, callbackInfo);
}
// Only execute callback if we have a caller
// chained is for findAndModify as it does not respect write concerns
if(callbackInfo && callbackInfo.callback && callbackInfo.info && Array.isArray(callbackInfo.info.chained)) {
// Check if callback has already been fired (missing chain command)
var chained = callbackInfo.info.chained;
var numberOfFoundCallbacks = 0;
for(var i = 0; i < chained.length; i++) {
if(dbInstanceObject._hasHandler(chained[i])) numberOfFoundCallbacks++;
}
// If we have already fired then clean up rest of chain and move on
if(numberOfFoundCallbacks != chained.length) {
for(var i = 0; i < chained.length; i++) {
dbInstanceObject._removeHandler(chained[i]);
}
// Just return from function
return;
}
// Parse the body
mongoReply.parseBody(message, connectionPool.bson, callbackInfo.info.raw, function(err) {
// console.log("+++++++++++++++++++++++++++++++++++++++ recieved message")
// console.dir(message)
if(err != null) {
// If pool connection is already closed
if(server._serverState === 'disconnected') return;
// Set server state to disconnected
server._serverState = 'disconnected';
// Remove all listeners and close the connection pool
server.removeAllListeners();
connectionPool.stop(true);
// If we have a callback return the error
if(typeof callback === 'function') {
// ensure no callbacks get called twice
var internalCallback = callback;
callback = null;
// Perform callback
internalCallback(new Error("connection closed due to parseError"), null, server);
} else if(server.isSetMember()) {
if(server.listeners("parseError") && server.listeners("parseError").length > 0) server.emit("parseError", new Error("connection closed due to parseError"), server);
} else {
if(eventReceiver.listeners("parseError") && eventReceiver.listeners("parseError").length > 0) eventReceiver.emit("parseError", new Error("connection closed due to parseError"), server);
}
// If we are a single server connection fire errors correctly
if(!server.isSetMember()) {
// Fire all callback errors
server.__executeAllCallbacksWithError(new Error("connection closed due to parseError"));
// Emit error
_emitAcrossAllDbInstances(server, eventReceiver, "parseError", server, null, true);
}
// Short cut
return;
}
// Fetch the callback
var callbackInfo = dbInstanceObject._findHandler(mongoReply.responseTo.toString());
// If we have an error let's execute the callback and clean up all other
// chained commands
var firstResult = mongoReply && mongoReply.documents;
// Check for an error, if we have one let's trigger the callback and clean up
// The chained callbacks
if(firstResult[0].err != null || firstResult[0].errmsg != null) {
// Trigger the callback for the error
dbInstanceObject._callHandler(mongoReply.responseTo, mongoReply, null);
} else {
var chainedIds = callbackInfo.info.chained;
if(chainedIds.length > 0 && chainedIds[chainedIds.length - 1] == mongoReply.responseTo) {
// Cleanup all other chained calls
chainedIds.pop();
// Remove listeners
for(var i = 0; i < chainedIds.length; i++) dbInstanceObject._removeHandler(chainedIds[i]);
// Call the handler
dbInstanceObject._callHandler(mongoReply.responseTo, callbackInfo.info.results.shift(), null);
} else{
// Add the results to all the results
for(var i = 0; i < chainedIds.length; i++) {
var handler = dbInstanceObject._findHandler(chainedIds[i]);
// Check if we have an object, if it's the case take the current object commands and
// and add this one
if(handler.info != null) {
handler.info.results = Array.isArray(callbackInfo.info.results) ? callbackInfo.info.results : [];
handler.info.results.push(mongoReply);
}
}
}
}
});
} else if(callbackInfo && callbackInfo.callback && callbackInfo.info) {
// Parse the body
mongoReply.parseBody(message, connectionPool.bson, callbackInfo.info.raw, function(err) {
// console.log("+++++++++++++++++++++++++++++++++++++++ recieved message")
// console.dir(message)
if(err != null) {
// If pool connection is already closed
if(server._serverState === 'disconnected') return;
// Set server state to disconnected
server._serverState = 'disconnected';
// Remove all listeners and close the connection pool
server.removeAllListeners();
connectionPool.stop(true);
// If we have a callback return the error
if(typeof callback === 'function') {
// ensure no callbacks get called twice
var internalCallback = callback;
callback = null;
// Perform callback
internalCallback(new Error("connection closed due to parseError"), null, server);
} else if(server.isSetMember()) {
if(server.listeners("parseError") && server.listeners("parseError").length > 0) server.emit("parseError", new Error("connection closed due to parseError"), server);
} else {
if(eventReceiver.listeners("parseError") && eventReceiver.listeners("parseError").length > 0) eventReceiver.emit("parseError", new Error("connection closed due to parseError"), server);
}
// If we are a single server connection fire errors correctly
if(!server.isSetMember()) {
// Fire all callback errors
server.__executeAllCallbacksWithError(new Error("connection closed due to parseError"));
// Emit error
_emitAcrossAllDbInstances(server, eventReceiver, "parseError", server, null, true);
}
// Short cut
return;
}
// Let's record the stats info if it's enabled
if(server.recordQueryStats == true && server._state['runtimeStats'] != null
&& server._state.runtimeStats['queryStats'] instanceof RunningStats) {
// Add data point to the running statistics object
server._state.runtimeStats.queryStats.push(new Date().getTime() - callbackInfo.info.start);
}
dbInstanceObject._callHandler(mongoReply.responseTo, mongoReply, null);
});
}
}
} catch (err) {
// Throw error in next tick
process.nextTick(function() {
throw err;
})
}
});
// Handle timeout
connectionPool.on("timeout", function(err) {
// If pool connection is already closed
if(server._serverState === 'disconnected') return;
// Set server state to disconnected
server._serverState = 'disconnected';
// If we have a callback return the error
if(typeof callback === 'function') {
// ensure no callbacks get called twice
var internalCallback = callback;
callback = null;
// Perform callback
internalCallback(err, null, server);
} else if(server.isSetMember()) {
if(server.listeners("timeout") && server.listeners("timeout").length > 0) server.emit("timeout", err, server);
} else {
if(eventReceiver.listeners("timeout") && eventReceiver.listeners("timeout").length > 0) eventReceiver.emit("timeout", err, server);
}
// If we are a single server connection fire errors correctly
if(!server.isSetMember()) {
// Fire all callback errors
server.__executeAllCallbacksWithError(err);
// Emit error
_emitAcrossAllDbInstances(server, eventReceiver, "timeout", err, server, true);
}
});
// Handle errors
connectionPool.on("error", function(message) {
// If pool connection is already closed
if(server._serverState === 'disconnected') return;
// Set server state to disconnected
server._serverState = 'disconnected';
// If we have a callback return the error
if(typeof callback === 'function') {
// ensure no callbacks get called twice
var internalCallback = callback;
callback = null;
// Perform callback
internalCallback(new Error(message && message.err ? message.err : message), null, server);
} else if(server.isSetMember()) {
if(server.listeners("error") && server.listeners("error").length > 0) server.emit("error", new Error(message && message.err ? message.err : message), server);
} else {
if(eventReceiver.listeners("error") && eventReceiver.listeners("error").length > 0) eventReceiver.emit("error", new Error(message && message.err ? message.err : message), server);
}
// If we are a single server connection fire errors correctly
if(!server.isSetMember()) {
// Fire all callback errors
server.__executeAllCallbacksWithError(new Error(message && message.err ? message.err : message));
// Emit error
_emitAcrossAllDbInstances(server, eventReceiver, "error", new Error(message && message.err ? message.err : message), server, true);
}
});
// Handle close events
connectionPool.on("close", function() {
// If pool connection is already closed
if(server._serverState === 'disconnected') return;
// Set server state to disconnected
server._serverState = 'disconnected';
// If we have a callback return the error
if(typeof callback == 'function') {
// ensure no callbacks get called twice
var internalCallback = callback;
callback = null;
// Perform callback
internalCallback(new Error("connection closed"), null, server);
} else if(server.isSetMember()) {
if(server.listeners("close") && server.listeners("close").length > 0) server.emit("close", new Error("connection closed"), server);
} else {
if(eventReceiver.listeners("close") && eventReceiver.listeners("close").length > 0) eventReceiver.emit("close", new Error("connection closed"), server);
}
// If we are a single server connection fire errors correctly
if(!server.isSetMember()) {
// Fire all callback errors
server.__executeAllCallbacksWithError(new Error("connection closed"));
// Emit error
_emitAcrossAllDbInstances(server, eventReceiver, "close", server, null, true);
}
});
// If we have a parser error we are in an unknown state, close everything and emit
// error
connectionPool.on("parseError", function(message) {
// If pool connection is already closed
if(server._serverState === 'disconnected') return;
// Set server state to disconnected
server._serverState = 'disconnected';
// If we have a callback return the error
if(typeof callback === 'function') {
// ensure no callbacks get called twice
var internalCallback = callback;
callback = null;
// Perform callback
internalCallback(new Error("connection closed due to parseError"), null, server);
} else if(server.isSetMember()) {
if(server.listeners("parseError") && server.listeners("parseError").length > 0) server.emit("parseError", new Error("connection closed due to parseError"), server);
} else {
if(eventReceiver.listeners("parseError") && eventReceiver.listeners("parseError").length > 0) eventReceiver.emit("parseError", new Error("connection closed due to parseError"), server);
}
// If we are a single server connection fire errors correctly
if(!server.isSetMember()) {
// Fire all callback errors
server.__executeAllCallbacksWithError(new Error("connection closed due to parseError"));
// Emit error
_emitAcrossAllDbInstances(server, eventReceiver, "parseError", server, null, true);
}
});
// Boot up connection poole, pass in a locator of callbacks
connectionPool.start();
}
/**
* @ignore
*/
var _emitAcrossAllDbInstances = function(server, filterDb, event, message, object, resetConnection) {
// Emit close event across all db instances sharing the sockets
var allServerInstances = server.allServerInstances();
// Fetch the first server instance
var serverInstance = allServerInstances[0];
// For all db instances signal all db instances
if(Array.isArray(serverInstance.dbInstances) && serverInstance.dbInstances.length >= 1) {
for(var i = 0; i < serverInstance.dbInstances.length; i++) {
var dbInstance = serverInstance.dbInstances[i];
// Set the parent
if(resetConnection && typeof dbInstance.openCalled != 'undefined')
dbInstance.openCalled = false;
// Check if it's our current db instance and skip if it is
if(filterDb == null || filterDb.databaseName !== dbInstance.databaseName || filterDb.tag !== dbInstance.tag) {
// Only emit if there is a listener
if(dbInstance.listeners(event).length > 0)
dbInstance.emit(event, message, object);
}
}
}
}
/**
* @ignore
*/
Server.prototype.allRawConnections = function() {
return this.connectionPool.getAllConnections();
}
/**
* Check if a writer can be provided
* @ignore
*/
var canCheckoutWriter = function(self, read) {
// We cannot write to an arbiter or secondary server
if(self.isMasterDoc['arbiterOnly'] == true) {
return new Error("Cannot write to an arbiter");
} if(self.isMasterDoc['secondary'] == true) {
return new Error("Cannot write to a secondary");
} else if(read == true && self._readPreference == ReadPreference.SECONDARY && self.isMasterDoc['ismaster'] == true) {
return new Error("Cannot read from primary when secondary only specified");
}
// Return no error
return null;
}
/**
* @ignore
*/
Server.prototype.checkoutWriter = function(read) {
// console.log("===================== checkoutWriter :: " + read)
// console.dir(this.isMasterDoc)
if(read == true) return this.connectionPool.checkoutConnection();
// Check if are allowed to do a checkout (if we try to use an arbiter f.ex)
var result = canCheckoutWriter(this, read);
// If the result is null check out a writer
if(result == null && this.connectionPool != null) {
return this.connectionPool.checkoutConnection();
} else if(result == null) {
return null;
} else {
return result;
}
}
/**
* Check if a reader can be provided
* @ignore
*/
var canCheckoutReader = function(self) {
// We cannot write to an arbiter or secondary server
if(self.isMasterDoc && self.isMasterDoc['arbiterOnly'] == true) {
return new Error("Cannot write to an arbiter");
} else if(self._readPreference != null) {
// If the read preference is Primary and the instance is not a master return an error
if((self._readPreference == ReadPreference.PRIMARY) && self.isMasterDoc['ismaster'] != true) {
return new Error("Read preference is Server.PRIMARY and server is not master");
} else if(self._readPreference == ReadPreference.SECONDARY && self.isMasterDoc['ismaster'] == true) {
return new Error("Cannot read from primary when secondary only specified");
}
}
// Return no error
return null;
}
/**
* @ignore
*/
Server.prototype.checkoutReader = function() {
// console.log("===================== checkoutReader")
// Check if are allowed to do a checkout (if we try to use an arbiter f.ex)
var result = canCheckoutReader(this);
// If the result is null check out a writer
if(result == null && this.connectionPool != null) {
return this.connectionPool.checkoutConnection();
} else if(result == null) {
return null;
} else {
return result;
}
}
/**
* @ignore
*/
Server.prototype.enableRecordQueryStats = function(enable) {
this.recordQueryStats = enable;
}
/**
* Internal statistics object used for calculating average and standard devitation on
* running queries
* @ignore
*/
var RunningStats = function() {
var self = this;
this.m_n = 0;
this.m_oldM = 0.0;
this.m_oldS = 0.0;
this.m_newM = 0.0;
this.m_newS = 0.0;
// Define getters
Object.defineProperty(this, "numDataValues", { enumerable: true
, get: function () { return this.m_n; }
});
Object.defineProperty(this, "mean", { enumerable: true
, get: function () { return (this.m_n > 0) ? this.m_newM : 0.0; }
});
Object.defineProperty(this, "variance", { enumerable: true
, get: function () { return ((this.m_n > 1) ? this.m_newS/(this.m_n - 1) : 0.0); }
});
Object.defineProperty(this, "standardDeviation", { enumerable: true
, get: function () { return Math.sqrt(this.variance); }
});
Object.defineProperty(this, "sScore", { enumerable: true
, get: function () {
var bottom = this.mean + this.standardDeviation;
if(bottom == 0) return 0;
return ((2 * this.mean * this.standardDeviation)/(bottom));
}
});
}
/**
* @ignore
*/
RunningStats.prototype.push = function(x) {
// Update the number of samples
this.m_n = this.m_n + 1;
// See Knuth TAOCP vol 2, 3rd edition, page 232
if(this.m_n == 1) {
this.m_oldM = this.m_newM = x;
this.m_oldS = 0.0;
} else {
this.m_newM = this.m_oldM + (x - this.m_oldM) / this.m_n;
this.m_newS = this.m_oldS + (x - this.m_oldM) * (x - this.m_newM);
// set up for next iteration
this.m_oldM = this.m_newM;
this.m_oldS = this.m_newS;
}
}
/**
* @ignore
*/
Object.defineProperty(Server.prototype, "autoReconnect", { enumerable: true
, get: function () {
return this.options['auto_reconnect'] == null ? false : this.options['auto_reconnect'];
}
});
/**
* @ignore
*/
Object.defineProperty(Server.prototype, "connection", { enumerable: true
, get: function () {
return this.internalConnection;
}
, set: function(connection) {
this.internalConnection = connection;
}
});
/**
* @ignore
*/
Object.defineProperty(Server.prototype, "master", { enumerable: true
, get: function () {
return this.internalMaster;
}
, set: function(value) {
this.internalMaster = value;
}
});
/**
* @ignore
*/
Object.defineProperty(Server.prototype, "primary", { enumerable: true
, get: function () {
return this;
}
});
/**
* Getter for query Stats
* @ignore
*/
Object.defineProperty(Server.prototype, "queryStats", { enumerable: true
, get: function () {
return this._state.runtimeStats.queryStats;
}
});
/**
* @ignore
*/
Object.defineProperty(Server.prototype, "runtimeStats", { enumerable: true
, get: function () {
return this._state.runtimeStats;
}
});
/**
* Get Read Preference method
* @ignore
*/
Object.defineProperty(Server.prototype, "readPreference", { enumerable: true
, get: function () {
if(this._readPreference == null && this.readSecondary) {
return Server.READ_SECONDARY;
} else if(this._readPreference == null && !this.readSecondary) {
return Server.READ_PRIMARY;
} else {
return this._readPreference;
}
}
});
/**
* @ignore
*/
exports.Server = Server;

View File

@@ -0,0 +1,188 @@
var Server = require("../server").Server;
// The ping strategy uses pings each server and records the
// elapsed time for the server so it can pick a server based on lowest
// return time for the db command {ping:true}
var PingStrategy = exports.PingStrategy = function(replicaset, secondaryAcceptableLatencyMS) {
this.replicaset = replicaset;
this.secondaryAcceptableLatencyMS = secondaryAcceptableLatencyMS;
this.state = 'disconnected';
this.pingInterval = 5000;
// Class instance
this.Db = require("../../db").Db;
}
// Starts any needed code
PingStrategy.prototype.start = function(callback) {
// already running?
if ('connected' == this.state) return;
this.state = 'connected';
// Start ping server
this._pingServer(callback);
}
// Stops and kills any processes running
PingStrategy.prototype.stop = function(callback) {
// Stop the ping process
this.state = 'disconnected';
// optional callback
callback && callback(null, null);
}
PingStrategy.prototype.checkoutSecondary = function(tags, secondaryCandidates) {
// Servers are picked based on the lowest ping time and then servers that lower than that + secondaryAcceptableLatencyMS
// Create a list of candidat servers, containing the primary if available
var candidateServers = [];
// If we have not provided a list of candidate servers use the default setup
if(!Array.isArray(secondaryCandidates)) {
candidateServers = this.replicaset._state.master != null ? [this.replicaset._state.master] : [];
// Add all the secondaries
var keys = Object.keys(this.replicaset._state.secondaries);
for(var i = 0; i < keys.length; i++) {
candidateServers.push(this.replicaset._state.secondaries[keys[i]])
}
} else {
candidateServers = secondaryCandidates;
}
// Final list of eligable server
var finalCandidates = [];
// If we have tags filter by tags
if(tags != null && typeof tags == 'object') {
// If we have an array or single tag selection
var tagObjects = Array.isArray(tags) ? tags : [tags];
// Iterate over all tags until we find a candidate server
for(var _i = 0; _i < tagObjects.length; _i++) {
// Grab a tag object
var tagObject = tagObjects[_i];
// Matching keys
var matchingKeys = Object.keys(tagObject);
// Remove any that are not tagged correctly
for(var i = 0; i < candidateServers.length; i++) {
var server = candidateServers[i];
// If we have tags match
if(server.tags != null) {
var matching = true;
// Ensure we have all the values
for(var j = 0; j < matchingKeys.length; j++) {
if(server.tags[matchingKeys[j]] != tagObject[matchingKeys[j]]) {
matching = false;
break;
}
}
// If we have a match add it to the list of matching servers
if(matching) {
finalCandidates.push(server);
}
}
}
}
} else {
// Final array candidates
var finalCandidates = candidateServers;
}
// Sort by ping time
finalCandidates.sort(function(a, b) {
return a.runtimeStats['pingMs'] > b.runtimeStats['pingMs'];
});
if(0 === finalCandidates.length)
return new Error("No replica set members available for query");
// handle undefined pingMs
var lowestPing = finalCandidates[0].runtimeStats['pingMs'] | 0;
// determine acceptable latency
var acceptable = lowestPing + this.secondaryAcceptableLatencyMS;
// remove any server responding slower than acceptable
var len = finalCandidates.length;
while(len--) {
if(finalCandidates[len].runtimeStats['pingMs'] > acceptable) {
finalCandidates.splice(len, 1);
}
}
// If no candidates available return an error
if(finalCandidates.length == 0)
return new Error("No replica set members available for query");
// Pick a random acceptable server
return finalCandidates[Math.round(Math.random(1000000) * (finalCandidates.length - 1))].checkoutReader();
}
PingStrategy.prototype._pingServer = function(callback) {
var self = this;
// Ping server function
var pingFunction = function() {
if(self.state == 'disconnected') return;
var addresses = self.replicaset._state.addresses;
// Grab all servers
var serverKeys = Object.keys(addresses);
// Number of server entries
var numberOfEntries = serverKeys.length;
// We got keys
for(var i = 0; i < serverKeys.length; i++) {
// We got a server instance
var server = addresses[serverKeys[i]];
// Create a new server object, avoid using internal connections as they might
// be in an illegal state
new function(serverInstance) {
var options = { poolSize: 1, timeout: 500, auto_reconnect: false };
var server = new Server(serverInstance.host, serverInstance.port, options);
var db = new self.Db(self.replicaset.db.databaseName, server, { safe: true });
db.on("error", done);
// Open the db instance
db.open(function(err, _db) {
if(err) return done(err, _db);
// Startup time of the command
var startTime = Date.now();
// Execute ping on this connection
db.executeDbCommand({ping:1}, {failFast:true}, function() {
if(null != serverInstance.runtimeStats && serverInstance.isConnected()) {
serverInstance.runtimeStats['pingMs'] = Date.now() - startTime;
}
done(null, _db);
})
})
function done (err, _db) {
// Close connection
if (_db) _db.close(true);
// Adjust the number of checks
numberOfEntries--;
// If we are done with all results coming back trigger ping again
if(0 === numberOfEntries && 'connected' == self.state) {
setTimeout(pingFunction, self.pingInterval);
}
}
}(server);
}
}
// Start pingFunction
setTimeout(pingFunction, 1000);
callback && callback(null);
}

View File

@@ -0,0 +1,78 @@
// The Statistics strategy uses the measure of each end-start time for each
// query executed against the db to calculate the mean, variance and standard deviation
// and pick the server which the lowest mean and deviation
var StatisticsStrategy = exports.StatisticsStrategy = function(replicaset) {
this.replicaset = replicaset;
}
// Starts any needed code
StatisticsStrategy.prototype.start = function(callback) {
callback && callback(null, null);
}
StatisticsStrategy.prototype.stop = function(callback) {
callback && callback(null, null);
}
StatisticsStrategy.prototype.checkoutSecondary = function(tags, secondaryCandidates) {
// Servers are picked based on the lowest ping time and then servers that lower than that + secondaryAcceptableLatencyMS
// Create a list of candidat servers, containing the primary if available
var candidateServers = [];
// If we have not provided a list of candidate servers use the default setup
if(!Array.isArray(secondaryCandidates)) {
candidateServers = this.replicaset._state.master != null ? [this.replicaset._state.master] : [];
// Add all the secondaries
var keys = Object.keys(this.replicaset._state.secondaries);
for(var i = 0; i < keys.length; i++) {
candidateServers.push(this.replicaset._state.secondaries[keys[i]])
}
} else {
candidateServers = secondaryCandidates;
}
// Final list of eligable server
var finalCandidates = [];
// If we have tags filter by tags
if(tags != null && typeof tags == 'object') {
// If we have an array or single tag selection
var tagObjects = Array.isArray(tags) ? tags : [tags];
// Iterate over all tags until we find a candidate server
for(var _i = 0; _i < tagObjects.length; _i++) {
// Grab a tag object
var tagObject = tagObjects[_i];
// Matching keys
var matchingKeys = Object.keys(tagObject);
// Remove any that are not tagged correctly
for(var i = 0; i < candidateServers.length; i++) {
var server = candidateServers[i];
// If we have tags match
if(server.tags != null) {
var matching = true;
// Ensure we have all the values
for(var j = 0; j < matchingKeys.length; j++) {
if(server.tags[matchingKeys[j]] != tagObject[matchingKeys[j]]) {
matching = false;
break;
}
}
// If we have a match add it to the list of matching servers
if(matching) {
finalCandidates.push(server);
}
}
}
}
} else {
// Final array candidates
var finalCandidates = candidateServers;
}
// If no candidates available return an error
if(finalCandidates.length == 0) return new Error("No replica set members available for query");
// Pick a random server
return finalCandidates[Math.round(Math.random(1000000) * (finalCandidates.length - 1))].checkoutReader();
}

View File

@@ -0,0 +1,223 @@
var fs = require('fs'),
ReadPreference = require('./read_preference').ReadPreference;
exports.parse = function(url, options) {
// Ensure we have a default options object if none set
options = options || {};
// Variables
var connection_part = '';
var auth_part = '';
var query_string_part = '';
var dbName = 'default';
// Must start with mongodb
if(url.indexOf("mongodb://") != 0)
throw Error("URL must be in the format mongodb://user:pass@host:port/dbname");
// If we have a ? mark cut the query elements off
if(url.indexOf("?") != -1) {
query_string_part = url.substr(url.indexOf("?") + 1);
connection_part = url.substring("mongodb://".length, url.indexOf("?"))
} else {
connection_part = url.substring("mongodb://".length);
}
// Check if we have auth params
if(connection_part.indexOf("@") != -1) {
auth_part = connection_part.split("@")[0];
connection_part = connection_part.split("@")[1];
}
// Check if the connection string has a db
if(connection_part.indexOf(".sock") != -1) {
if(connection_part.indexOf(".sock/") != -1) {
dbName = connection_part.split(".sock/")[1];
connection_part = connection_part.split("/", connection_part.indexOf(".sock") + ".sock".length);
}
} else if(connection_part.indexOf("/") != -1) {
dbName = connection_part.split("/")[1];
connection_part = connection_part.split("/")[0];
}
// Result object
var object = {};
// Pick apart the authentication part of the string
var authPart = auth_part || '';
var auth = authPart.split(':', 2);
if(options['uri_decode_auth']){
auth[0] = decodeURIComponent(auth[0]);
if(auth[1]){
auth[1] = decodeURIComponent(auth[1]);
}
}
// Add auth to final object if we have 2 elements
if(auth.length == 2) object.auth = {user: auth[0], password: auth[1]};
// Variables used for temporary storage
var hostPart;
var urlOptions;
var servers;
var serverOptions = {socketOptions: {}};
var dbOptions = {read_preference_tags: []};
var replSetServersOptions = {socketOptions: {}};
// Add server options to final object
object.server_options = serverOptions;
object.db_options = dbOptions;
object.rs_options = replSetServersOptions;
object.mongos_options = {};
// Let's check if we are using a domain socket
if(url.match(/\.sock/)) {
// Split out the socket part
var domainSocket = url.substring(
url.indexOf("mongodb://") + "mongodb://".length
, url.lastIndexOf(".sock") + ".sock".length);
// Clean out any auth stuff if any
if(domainSocket.indexOf("@") != -1) domainSocket = domainSocket.split("@")[1];
servers = [{domain_socket: domainSocket}];
} else {
// Split up the db
hostPart = connection_part;
// Parse all server results
servers = hostPart.split(',').map(function(h) {
var hostPort = h.split(':', 2);
var _host = hostPort[0] || 'localhost';
var _port = hostPort[1] != null ? parseInt(hostPort[1], 10) : 27017;
// Check for localhost?safe=true style case
if(_host.indexOf("?") != -1) _host = _host.split(/\?/)[0];
// Return the mapped object
return {host: _host, port: _port};
});
}
// Get the db name
object.dbName = dbName || 'default';
// Split up all the options
urlOptions = (query_string_part || '').split(/[&;]/);
// Ugh, we have to figure out which options go to which constructor manually.
urlOptions.forEach(function(opt) {
if(!opt) return;
var splitOpt = opt.split('='), name = splitOpt[0], value = splitOpt[1];
// Options implementations
switch(name) {
case 'slaveOk':
case 'slave_ok':
serverOptions.slave_ok = (value == 'true');
break;
case 'maxPoolSize':
case 'poolSize':
serverOptions.poolSize = parseInt(value, 10);
replSetServersOptions.poolSize = parseInt(value, 10);
break;
case 'autoReconnect':
case 'auto_reconnect':
serverOptions.auto_reconnect = (value == 'true');
break;
case 'minPoolSize':
throw new Error("minPoolSize not supported");
case 'maxIdleTimeMS':
throw new Error("maxIdleTimeMS not supported");
case 'waitQueueMultiple':
throw new Error("waitQueueMultiple not supported");
case 'waitQueueTimeoutMS':
throw new Error("waitQueueTimeoutMS not supported");
case 'uuidRepresentation':
throw new Error("uuidRepresentation not supported");
case 'ssl':
if(value == 'prefer') {
serverOptions.socketOptions.ssl = value;
replSetServersOptions.socketOptions.ssl = value;
break;
}
serverOptions.socketOptions.ssl = (value == 'true');
replSetServersOptions.socketOptions.ssl = (value == 'true');
break;
case 'replicaSet':
case 'rs_name':
replSetServersOptions.rs_name = value;
break;
case 'reconnectWait':
replSetServersOptions.reconnectWait = parseInt(value, 10);
break;
case 'retries':
replSetServersOptions.retries = parseInt(value, 10);
break;
case 'readSecondary':
case 'read_secondary':
replSetServersOptions.read_secondary = (value == 'true');
break;
case 'fsync':
dbOptions.fsync = (value == 'true');
break;
case 'journal':
dbOptions.journal = (value == 'true');
break;
case 'safe':
dbOptions.safe = (value == 'true');
break;
case 'nativeParser':
case 'native_parser':
dbOptions.native_parser = (value == 'true');
break;
case 'connectTimeoutMS':
serverOptions.socketOptions.connectTimeoutMS = parseInt(value, 10);
replSetServersOptions.socketOptions.connectTimeoutMS = parseInt(value, 10);
break;
case 'socketTimeoutMS':
serverOptions.socketOptions.socketTimeoutMS = parseInt(value, 10);
replSetServersOptions.socketOptions.socketTimeoutMS = parseInt(value, 10);
break;
case 'w':
dbOptions.w = parseInt(value, 10);
break;
case 'wtimeoutMS':
dbOptions.wtimeoutMS = parseInt(value, 10);
break;
case 'readPreference':
if(!ReadPreference.isValid(value)) throw new Error("readPreference must be either primary/primaryPreferred/secondary/secondaryPreferred/nearest");
dbOptions.read_preference = value;
break;
case 'readPreferenceTags':
// Contains the tag object
var tagObject = {};
if(value == null || value == '') {
dbOptions.read_preference_tags.push(tagObject);
break;
}
// Split up the tags
var tags = value.split(/\,/);
for(var i = 0; i < tags.length; i++) {
var parts = tags[i].trim().split(/\:/);
tagObject[parts[0]] = parts[1];
}
// Set the preferences tags
dbOptions.read_preference_tags.push(tagObject);
break;
default:
break;
}
});
// No tags: should be null (not [])
if(dbOptions.read_preference_tags.length === 0) {
dbOptions.read_preference_tags = null;
}
// Validate if there are an invalid write concern combinations
if((dbOptions.w == -1 || dbOptions.w == 0) && (
dbOptions.journal == true
|| dbOptions.fsync == true
|| dbOptions.safe == true)) throw new Error("w set to -1 or 0 cannot be combined with safe/w/journal/fsync")
// If no read preference set it to primary
if(!dbOptions.read_preference) dbOptions.read_preference = 'primary';
// Add servers to result
object.servers = servers;
// Returned parsed object
return object;
}

881
node_modules/mongodb/lib/mongodb/cursor.js generated vendored Normal file
View File

@@ -0,0 +1,881 @@
var QueryCommand = require('./commands/query_command').QueryCommand,
GetMoreCommand = require('./commands/get_more_command').GetMoreCommand,
KillCursorCommand = require('./commands/kill_cursor_command').KillCursorCommand,
Long = require('bson').Long,
ReadPreference = require('./connection/read_preference').ReadPreference,
CursorStream = require('./cursorstream'),
utils = require('./utils');
/**
* Constructor for a cursor object that handles all the operations on query result
* using find. This cursor object is unidirectional and cannot traverse backwards. Clients should not be creating a cursor directly,
* but use find to acquire a cursor.
*
* Options
* - **skip** {Number} skip number of documents to skip.
* - **limit** {Number}, limit the number of results to return. -1 has a special meaning and is used by Db.eval. A value of 1 will also be treated as if it were -1.
* - **sort** {Array | Object}, set to sort the documents coming back from the query. Array of indexes, [['a', 1]] etc.
* - **hint** {Object}, hint force the query to use a specific index.
* - **explain** {Boolean}, explain return the explaination of the query.
* - **snapshot** {Boolean}, snapshot Snapshot mode assures no duplicates are returned.
* - **timeout** {Boolean}, timeout allow the query to timeout.
* - **tailable** {Boolean}, tailable allow the cursor to be tailable.
* - **awaitdata** {Boolean}, awaitdata allow the cursor to wait for data, only applicable for tailable cursor.
* - **batchSize** {Number}, batchSize the number of the subset of results to request the database to return for every request. This should initially be greater than 1 otherwise the database will automatically close the cursor. The batch size can be set to 1 with cursorInstance.batchSize after performing the initial query to the database.
* - **raw** {Boolean}, raw return all query documents as raw buffers (default false).
* - **read** {Boolean}, read specify override of read from source (primary/secondary).
* - **slaveOk** {Boolean}, slaveOk, sets the slaveOk flag on the query wire protocol for secondaries.
* - **returnKey** {Boolean}, returnKey only return the index key.
* - **maxScan** {Number}, maxScan limit the number of items to scan.
* - **min** {Number}, min set index bounds.
* - **max** {Number}, max set index bounds.
* - **showDiskLoc** {Boolean}, showDiskLoc show disk location of results.
* - **comment** {String}, comment you can put a $comment field on a query to make looking in the profiler logs simpler.
* - **numberOfRetries** {Number}, numberOfRetries if using awaidata specifies the number of times to retry on timeout.
* - **dbName** {String}, dbName override the default dbName.
* - **tailableRetryInterval** {Number}, tailableRetryInterval specify the miliseconds between getMores on tailable cursor.
* - **exhaust** {Boolean}, exhaust have the server send all the documents at once as getMore packets.
* - **partial** {Boolean}, partial have the sharded system return a partial result from mongos.
*
* @class Represents a Cursor.
* @param {Db} db the database object to work with.
* @param {Collection} collection the collection to query.
* @param {Object} selector the query selector.
* @param {Object} fields an object containing what fields to include or exclude from objects returned.
* @param {Object} [options] additional options for the collection.
*/
function Cursor(db, collection, selector, fields, options) {
this.db = db;
this.collection = collection;
this.selector = selector;
this.fields = fields;
options = !options ? {} : options;
this.skipValue = options.skip == null ? 0 : options.skip;
this.limitValue = options.limit == null ? 0 : options.limit;
this.sortValue = options.sort;
this.hint = options.hint;
this.explainValue = options.explain;
this.snapshot = options.snapshot;
this.timeout = options.timeout == null ? true : options.timeout;
this.tailable = options.tailable;
this.awaitdata = options.awaitdata;
this.numberOfRetries = options.numberOfRetries == null ? 5 : options.numberOfRetries;
this.currentNumberOfRetries = this.numberOfRetries;
this.batchSizeValue = options.batchSize == null ? 0 : options.batchSize;
this.slaveOk = options.slaveOk == null ? collection.slaveOk : options.slaveOk;
this.raw = options.raw == null ? false : options.raw;
this.read = options.read == null ? ReadPreference.PRIMARY : options.read;
this.returnKey = options.returnKey;
this.maxScan = options.maxScan;
this.min = options.min;
this.max = options.max;
this.showDiskLoc = options.showDiskLoc;
this.comment = options.comment;
this.tailableRetryInterval = options.tailableRetryInterval || 100;
this.exhaust = options.exhaust || false;
this.partial = options.partial || false;
this.totalNumberOfRecords = 0;
this.items = [];
this.cursorId = Long.fromInt(0);
// This name
this.dbName = options.dbName;
// State variables for the cursor
this.state = Cursor.INIT;
// Keep track of the current query run
this.queryRun = false;
this.getMoreTimer = false;
// If we are using a specific db execute against it
if(this.dbName != null) {
this.collectionName = this.dbName + "." + this.collection.collectionName;
} else {
this.collectionName = (this.db.databaseName ? this.db.databaseName + "." : '') + this.collection.collectionName;
}
};
/**
* Resets this cursor to its initial state. All settings like the query string,
* tailable, batchSizeValue, skipValue and limits are preserved.
*
* @return {Cursor} returns itself with rewind applied.
* @api public
*/
Cursor.prototype.rewind = function() {
var self = this;
if (self.state != Cursor.INIT) {
if (self.state != Cursor.CLOSED) {
self.close(function() {});
}
self.numberOfReturned = 0;
self.totalNumberOfRecords = 0;
self.items = [];
self.cursorId = Long.fromInt(0);
self.state = Cursor.INIT;
self.queryRun = false;
}
return self;
};
/**
* Returns an array of documents. The caller is responsible for making sure that there
* is enough memory to store the results. Note that the array only contain partial
* results when this cursor had been previouly accessed. In that case,
* cursor.rewind() can be used to reset the cursor.
*
* @param {Function} callback This will be called after executing this method successfully. The first parameter will contain the Error object if an error occured, or null otherwise. The second parameter will contain an array of BSON deserialized objects as a result of the query.
* @return {null}
* @api public
*/
Cursor.prototype.toArray = function(callback) {
var self = this;
if(!callback) {
throw new Error('callback is mandatory');
}
if(this.tailable) {
callback(new Error("Tailable cursor cannot be converted to array"), null);
} else if(this.state != Cursor.CLOSED) {
var items = [];
this.each(function(err, item) {
if(err != null) return callback(err, null);
if(item != null && Array.isArray(items)) {
items.push(item);
} else {
var resultItems = items;
items = null;
self.items = [];
// Returns items
callback(err, resultItems);
}
});
} else {
callback(new Error("Cursor is closed"), null);
}
};
/**
* Iterates over all the documents for this cursor. As with **{cursor.toArray}**,
* not all of the elements will be iterated if this cursor had been previouly accessed.
* In that case, **{cursor.rewind}** can be used to reset the cursor. However, unlike
* **{cursor.toArray}**, the cursor will only hold a maximum of batch size elements
* at any given time if batch size is specified. Otherwise, the caller is responsible
* for making sure that the entire result can fit the memory.
*
* @param {Function} callback this will be called for while iterating every document of the query result. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the document.
* @return {null}
* @api public
*/
Cursor.prototype.each = function(callback) {
var self = this;
if (!callback) {
throw new Error('callback is mandatory');
}
if(this.state != Cursor.CLOSED) {
//FIX: stack overflow (on deep callback) (cred: https://github.com/limp/node-mongodb-native/commit/27da7e4b2af02035847f262b29837a94bbbf6ce2)
process.nextTick(function(){
var s = new Date()
// Fetch the next object until there is no more objects
self.nextObject(function(err, item) {
if(err != null) return callback(err, null);
if(item != null) {
callback(null, item);
self.each(callback);
} else {
// Close the cursor if done
self.state = Cursor.CLOSED;
callback(err, null);
}
});
});
} else {
callback(new Error("Cursor is closed"), null);
}
};
/**
* Determines how many result the query for this cursor will return
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the number of results or null if an error occured.
* @return {null}
* @api public
*/
Cursor.prototype.count = function(callback) {
this.collection.count(this.selector, callback);
};
/**
* Sets the sort parameter of this cursor to the given value.
*
* This method has the following method signatures:
* (keyOrList, callback)
* (keyOrList, direction, callback)
*
* @param {String|Array|Object} keyOrList This can be a string or an array. If passed as a string, the string will be the field to sort. If passed an array, each element will represent a field to be sorted and should be an array that contains the format [string, direction].
* @param {String|Number} direction this determines how the results are sorted. "asc", "ascending" or 1 for asceding order while "desc", "desceding or -1 for descending order. Note that the strings are case insensitive.
* @param {Function} callback this will be called after executing this method. The first parameter will contain an error object when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
* @return {Cursor} an instance of this object.
* @api public
*/
Cursor.prototype.sort = function(keyOrList, direction, callback) {
callback = callback || function(){};
if(typeof direction === "function") { callback = direction; direction = null; }
if(this.tailable) {
callback(new Error("Tailable cursor doesn't support sorting"), null);
} else if(this.queryRun == true || this.state == Cursor.CLOSED) {
callback(new Error("Cursor is closed"), null);
} else {
var order = keyOrList;
if(direction != null) {
order = [[keyOrList, direction]];
}
this.sortValue = order;
callback(null, this);
}
return this;
};
/**
* Sets the limit parameter of this cursor to the given value.
*
* @param {Number} limit the new limit.
* @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the limit given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
* @return {Cursor} an instance of this object.
* @api public
*/
Cursor.prototype.limit = function(limit, callback) {
if(this.tailable) {
if(callback) {
callback(new Error("Tailable cursor doesn't support limit"), null);
} else {
throw new Error("Tailable cursor doesn't support limit");
}
} else if(this.queryRun == true || this.state == Cursor.CLOSED) {
if(callback) {
callback(new Error("Cursor is closed"), null);
} else {
throw new Error("Cursor is closed");
}
} else {
if(limit != null && limit.constructor != Number) {
if(callback) {
callback(new Error("limit requires an integer"), null);
} else {
throw new Error("limit requires an integer");
}
} else {
this.limitValue = limit;
if(callback) return callback(null, this);
}
}
return this;
};
/**
* Sets the read preference for the cursor
*
* @param {String} the read preference for the cursor, one of Server.READ_PRIMARY, Server.READ_SECONDARY, Server.READ_SECONDARY_ONLY
* @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the read preference given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
* @return {Cursor} an instance of this object.
* @api public
*/
Cursor.prototype.setReadPreference = function(readPreference, tags, callback) {
if(typeof tags == 'function') callback = tags;
var _mode = readPreference != null && typeof readPreference == 'object' ? readPreference.mode : readPreference;
if(this.queryRun == true || this.state == Cursor.CLOSED) {
if(callback == null) throw new Error("Cannot change read preference on executed query or closed cursor");
callback(new Error("Cannot change read preference on executed query or closed cursor"));
} else if(_mode != null && _mode != 'primary'
&& _mode != 'secondaryOnly' && _mode != 'secondary'
&& _mode != 'nearest' && _mode != 'primaryPreferred' && _mode != 'secondaryPreferred') {
if(callback == null) throw new Error("only readPreference of primary, secondary, secondaryPreferred, primaryPreferred or nearest supported");
callback(new Error("only readPreference of primary, secondary, secondaryPreferred, primaryPreferred or nearest supported"));
} else {
this.read = readPreference;
if(callback != null) callback(null, this);
}
return this;
}
/**
* Sets the skip parameter of this cursor to the given value.
*
* @param {Number} skip the new skip value.
* @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the skip value given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
* @return {Cursor} an instance of this object.
* @api public
*/
Cursor.prototype.skip = function(skip, callback) {
callback = callback || function(){};
if(this.tailable) {
callback(new Error("Tailable cursor doesn't support skip"), null);
} else if(this.queryRun == true || this.state == Cursor.CLOSED) {
callback(new Error("Cursor is closed"), null);
} else {
if(skip != null && skip.constructor != Number) {
callback(new Error("skip requires an integer"), null);
} else {
this.skipValue = skip;
callback(null, this);
}
}
return this;
};
/**
* Sets the batch size parameter of this cursor to the given value.
*
* @param {Number} batchSize the new batch size.
* @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the batchSize given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
* @return {Cursor} an instance of this object.
* @api public
*/
Cursor.prototype.batchSize = function(batchSize, callback) {
if(this.state == Cursor.CLOSED) {
if(callback != null) {
return callback(new Error("Cursor is closed"), null);
} else {
throw new Error("Cursor is closed");
}
} else if(batchSize != null && batchSize.constructor != Number) {
if(callback != null) {
return callback(new Error("batchSize requires an integer"), null);
} else {
throw new Error("batchSize requires an integer");
}
} else {
this.batchSizeValue = batchSize;
if(callback != null) return callback(null, this);
}
return this;
};
/**
* The limit used for the getMore command
*
* @return {Number} The number of records to request per batch.
* @ignore
* @api private
*/
var limitRequest = function(self) {
var requestedLimit = self.limitValue;
var absLimitValue = Math.abs(self.limitValue);
var absBatchValue = Math.abs(self.batchSizeValue);
if(absLimitValue > 0) {
if (absBatchValue > 0) {
requestedLimit = Math.min(absLimitValue, absBatchValue);
}
} else {
requestedLimit = self.batchSizeValue;
}
return requestedLimit;
};
/**
* Generates a QueryCommand object using the parameters of this cursor.
*
* @return {QueryCommand} The command object
* @ignore
* @api private
*/
var generateQueryCommand = function(self) {
// Unpack the options
var queryOptions = QueryCommand.OPTS_NONE;
if(!self.timeout) {
queryOptions |= QueryCommand.OPTS_NO_CURSOR_TIMEOUT;
}
if(self.tailable != null) {
queryOptions |= QueryCommand.OPTS_TAILABLE_CURSOR;
self.skipValue = self.limitValue = 0;
// if awaitdata is set
if(self.awaitdata != null) {
queryOptions |= QueryCommand.OPTS_AWAIT_DATA;
}
}
if(self.exhaust) {
queryOptions |= QueryCommand.OPTS_EXHAUST;
}
if(self.slaveOk) {
queryOptions |= QueryCommand.OPTS_SLAVE;
}
if(self.partial) {
queryOptions |= QueryCommand.OPTS_PARTIAL;
}
// limitValue of -1 is a special case used by Db#eval
var numberToReturn = self.limitValue == -1 ? -1 : limitRequest(self);
// Check if we need a special selector
if(self.sortValue != null || self.explainValue != null || self.hint != null || self.snapshot != null
|| self.returnKey != null || self.maxScan != null || self.min != null || self.max != null
|| self.showDiskLoc != null || self.comment != null) {
// Build special selector
var specialSelector = {'$query':self.selector};
if(self.sortValue != null) specialSelector['orderby'] = utils.formattedOrderClause(self.sortValue);
if(self.hint != null && self.hint.constructor == Object) specialSelector['$hint'] = self.hint;
if(self.snapshot != null) specialSelector['$snapshot'] = true;
if(self.returnKey != null) specialSelector['$returnKey'] = self.returnKey;
if(self.maxScan != null) specialSelector['$maxScan'] = self.maxScan;
if(self.min != null) specialSelector['$min'] = self.min;
if(self.max != null) specialSelector['$max'] = self.max;
if(self.showDiskLoc != null) specialSelector['$showDiskLoc'] = self.showDiskLoc;
if(self.comment != null) specialSelector['$comment'] = self.comment;
// If we have explain set only return a single document with automatic cursor close
if(self.explainValue != null) {
numberToReturn = (-1)*Math.abs(numberToReturn);
specialSelector['$explain'] = true;
}
// Return the query
return new QueryCommand(self.db, self.collectionName, queryOptions, self.skipValue, numberToReturn, specialSelector, self.fields);
} else {
return new QueryCommand(self.db, self.collectionName, queryOptions, self.skipValue, numberToReturn, self.selector, self.fields);
}
};
/**
* @return {Object} Returns an object containing the sort value of this cursor with
* the proper formatting that can be used internally in this cursor.
* @ignore
* @api private
*/
Cursor.prototype.formattedOrderClause = function() {
return utils.formattedOrderClause(this.sortValue);
};
/**
* Converts the value of the sort direction into its equivalent numerical value.
*
* @param sortDirection {String|number} Range of acceptable values:
* 'ascending', 'descending', 'asc', 'desc', 1, -1
*
* @return {number} The equivalent numerical value
* @throws Error if the given sortDirection is invalid
* @ignore
* @api private
*/
Cursor.prototype.formatSortValue = function(sortDirection) {
return utils.formatSortValue(sortDirection);
};
/**
* Gets the next document from the cursor.
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain an error object on error while the second parameter will contain a document from the returned result or null if there are no more results.
* @api public
*/
Cursor.prototype.nextObject = function(callback) {
var self = this;
if(self.state == Cursor.INIT) {
var cmd;
try {
cmd = generateQueryCommand(self);
} catch (err) {
return callback(err, null);
}
var commandHandler = function(err, result) {
// console.log("=========================================== QUERY NEXT OBJECT")
// console.dir(err)
if(err != null && result == null) return callback(err, null);
if(!err && result.documents[0] && result.documents[0]['$err']) {
return self.close(function() {callback(result.documents[0]['$err'], null);});
}
self.queryRun = true;
self.state = Cursor.OPEN; // Adjust the state of the cursor
self.cursorId = result.cursorId;
self.totalNumberOfRecords = result.numberReturned;
// Add the new documents to the list of items, using forloop to avoid
// new array allocations and copying
for(var i = 0; i < result.documents.length; i++) {
self.items.push(result.documents[i]);
}
// Ignore callbacks until the cursor is dead for exhausted
if(self.exhaust && result.cursorId.toString() == "0") {
self.nextObject(callback);
} else if(self.exhaust == false || self.exhaust == null) {
self.nextObject(callback);
}
};
// If we have no connection set on this cursor check one out
if(self.connection == null) {
try {
self.connection = this.read == null ? self.db.serverConfig.checkoutWriter() : self.db.serverConfig.checkoutReader(this.read);
} catch(err) {
return callback(err, null);
}
}
// Execute the command
self.db._executeQueryCommand(cmd, {exhaust: self.exhaust, raw:self.raw, read:this.read, connection:self.connection}, commandHandler);
// Set the command handler to null
commandHandler = null;
} else if(self.items.length) {
callback(null, self.items.shift());
} else if(self.cursorId.greaterThan(Long.fromInt(0))) {
getMore(self, callback);
} else {
// Force cursor to stay open
return self.close(function() {callback(null, null);});
}
}
/**
* Gets more results from the database if any.
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain an error object on error while the second parameter will contain a document from the returned result or null if there are no more results.
* @ignore
* @api private
*/
var getMore = function(self, callback) {
var limit = 0;
if (!self.tailable && self.limitValue > 0) {
limit = self.limitValue - self.totalNumberOfRecords;
if (limit < 1) {
self.close(function() {callback(null, null);});
return;
}
}
try {
var getMoreCommand = new GetMoreCommand(
self.db
, self.collectionName
, limitRequest(self)
, self.cursorId
);
// Set up options
var options = {read: self.read, raw: self.raw, connection:self.connection };
// Execute the command
self.db._executeQueryCommand(getMoreCommand, options, function(err, result) {
try {
if(err != null) {
return callback(err, null);
}
var isDead = 1 === result.responseFlag && result.cursorId.isZero();
self.cursorId = result.cursorId;
self.totalNumberOfRecords += result.numberReturned;
// Determine if there's more documents to fetch
if(result.numberReturned > 0) {
if (self.limitValue > 0) {
var excessResult = self.totalNumberOfRecords - self.limitValue;
if (excessResult > 0) {
result.documents.splice(-1 * excessResult, excessResult);
}
}
// Reset the tries for awaitdata if we are using it
self.currentNumberOfRetries = self.numberOfRetries;
// Get the documents
for(var i = 0; i < result.documents.length; i++) {
self.items.push(result.documents[i]);
}
// result = null;
callback(null, self.items.shift());
} else if(self.tailable && !isDead && self.awaitdata) {
// Excute the tailable cursor once more, will timeout after ~4 sec if awaitdata used
self.currentNumberOfRetries = self.currentNumberOfRetries - 1;
if(self.currentNumberOfRetries == 0) {
self.close(function() {
callback(new Error("tailable cursor timed out"), null);
});
} else {
process.nextTick(function() { getMore(self, callback); });
}
} else if(self.tailable && !isDead) {
self.getMoreTimer = setTimeout(function() { getMore(self, callback); }, self.tailableRetryInterval);
} else {
self.close(function() {callback(null, null); });
}
result = null;
} catch(err) {
callback(err, null);
}
});
getMoreCommand = null;
} catch(err) {
var handleClose = function() {
callback(err, null);
};
self.close(handleClose);
handleClose = null;
}
}
/**
* Gets a detailed information about how the query is performed on this cursor and how
* long it took the database to process it.
*
* @param {Function} callback this will be called after executing this method. The first parameter will always be null while the second parameter will be an object containing the details.
* @api public
*/
Cursor.prototype.explain = function(callback) {
var limit = (-1)*Math.abs(this.limitValue);
// * - **skip** {Number} skip number of documents to skip.
// * - **limit** {Number}, limit the number of results to return. -1 has a special meaning and is used by Db.eval. A value of 1 will also be treated as if it were -1.
// * - **hint** {Object}, hint force the query to use a specific index.
// * - **explain** {Boolean}, explain return the explaination of the query.
// * - **slaveOk** {Boolean}, slaveOk, sets the slaveOk flag on the query wire protocol for secondaries.
// * - **snapshot** {Boolean}, snapshot Snapshot mode assures no duplicates are returned.
// * - **timeout** {Boolean}, timeout allow the query to timeout.
// * - **tailable** {Boolean}, tailable allow the cursor to be tailable.
// * - **awaitdata** {Boolean}, awaitdata allow the cursor to wait for data, only applicable for tailable cursor.
// * - **batchSize** {Number}, batchSize the number of the subset of results to request the database to return for every request. This should initially be greater than 1 otherwise the database will automatically close the cursor. The batch size can be set to 1 with cursorInstance.batchSize after performing the initial query to the database.
// * - **raw** {Boolean}, raw return all query documents as raw buffers (default false).
// * - **read** {Boolean}, read specify override of read from source (primary/secondary).
// * - **returnKey** {Boolean}, returnKey only return the index key.
// * - **maxScan** {Number}, maxScan limit the number of items to scan.
// * - **min** {Number}, min set index bounds.
// * - **max** {Number}, max set index bounds.
// * - **showDiskLoc** {Boolean}, showDiskLoc show disk location of results.
// * - **comment** {String}, comment you can put a $comment field on a query to make looking in the profiler logs simpler.
// * - **numberOfRetries** {Number}, numberOfRetries if using awaidata specifies the number of times to retry on timeout.
// * - **dbName** {String}, dbName override the default dbName.
// * - **tailableRetryInterval** {Number}, tailableRetryInterval specify the miliseconds between getMores on tailable cursor.
// * - **exhaust** {Boolean}, exhaust have the server send all the documents at once as getMore packets.
// * - **partial** {Boolean}, partial have the sharded system return a partial result from mongos.
// * - **sort** {Array | Object}, set to sort the documents coming back from the query. Array of indexes, [['a', 1]] etc.
// function Cursor(db, collection, selector, fields, skip, limit
// - , sort, hint, explain, snapshot, timeout, tailable, batchSize, slaveOk, raw, read
// - , returnKey, maxScan, min, max, showDiskLoc, comment, awaitdata, numberOfRetries, dbName, tailableRetry
// Create a new cursor and fetch the plan
var cursor = new Cursor(this.db, this.collection, this.selector, this.fields, {
skip: this.skipValue
, limit:limit
, sort: this.sortValue
, hint: this.hint
, explain: true
, snapshot: this.snapshot
, timeout: this.timeout
, tailable: this.tailable
, batchSize: this.batchSizeValue
, slaveOk: this.slaveOk
, raw: this.raw
, read: this.read
, returnKey: this.returnKey
, maxScan: this.maxScan
, min: this.min
, max: this.max
, showDiskLoc: this.showDiskLoc
, comment: this.comment
, awaitdata: this.awaitdata
, numberOfRetries: this.numberOfRetries
, dbName: this.dbName
});
// Fetch the explaination document
cursor.nextObject(function(err, item) {
if(err != null) return callback(err, null);
// close the cursor
cursor.close(function(err, result) {
if(err != null) return callback(err, null);
callback(null, item);
});
});
};
/**
* @ignore
*/
Cursor.prototype.streamRecords = function(options) {
console.log("[WARNING] streamRecords method is deprecated, please use stream method which is much faster");
var args = Array.prototype.slice.call(arguments, 0);
options = args.length ? args.shift() : {};
var
self = this,
stream = new process.EventEmitter(),
recordLimitValue = this.limitValue || 0,
emittedRecordCount = 0,
queryCommand = generateQueryCommand(self);
// see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol
queryCommand.numberToReturn = options.fetchSize ? options.fetchSize : 500;
// Execute the query
execute(queryCommand);
function execute(command) {
self.db._executeQueryCommand(command, {exhaust: self.exhaust, read:self.read, raw:self.raw, connection:self.connection}, function(err,result) {
if(err) {
stream.emit('error', err);
self.close(function(){});
return;
}
if (!self.queryRun && result) {
self.queryRun = true;
self.cursorId = result.cursorId;
self.state = Cursor.OPEN;
self.getMoreCommand = new GetMoreCommand(self.db, self.collectionName, queryCommand.numberToReturn, result.cursorId);
}
var resflagsMap = {
CursorNotFound:1<<0,
QueryFailure:1<<1,
ShardConfigStale:1<<2,
AwaitCapable:1<<3
};
if(result.documents && result.documents.length && !(result.responseFlag & resflagsMap.QueryFailure)) {
try {
result.documents.forEach(function(doc){
if(recordLimitValue && emittedRecordCount>=recordLimitValue) {
throw("done");
}
emittedRecordCount++;
stream.emit('data', doc);
});
} catch(err) {
if (err != "done") { throw err; }
else {
self.close(function(){
stream.emit('end', recordLimitValue);
});
self.close(function(){});
return;
}
}
// rinse & repeat
execute(self.getMoreCommand);
} else {
self.close(function(){
stream.emit('end', recordLimitValue);
});
}
});
}
return stream;
};
/**
* Returns a Node ReadStream interface for this cursor.
*
* @return {CursorStream} returns a stream object.
* @api public
*/
Cursor.prototype.stream = function stream () {
return new CursorStream(this);
}
/**
* Close the cursor.
*
* @param {Function} callback this will be called after executing this method. The first parameter will always contain null while the second parameter will contain a reference to this cursor.
* @return {null}
* @api public
*/
Cursor.prototype.close = function(callback) {
var self = this
this.getMoreTimer && clearTimeout(this.getMoreTimer);
// Close the cursor if not needed
if(this.cursorId instanceof Long && this.cursorId.greaterThan(Long.fromInt(0))) {
try {
var command = new KillCursorCommand(this.db, [this.cursorId]);
// Added an empty callback to ensure we don't throw any null exceptions
this.db._executeQueryCommand(command, {read:self.read, raw:self.raw, connection:self.connection}, function() {});
} catch(err) {}
}
// Null out the connection
self.connection = null;
// Reset cursor id
this.cursorId = Long.fromInt(0);
// Set to closed status
this.state = Cursor.CLOSED;
if(callback) {
callback(null, self);
self.items = [];
}
return this;
};
/**
* Check if the cursor is closed or open.
*
* @return {Boolean} returns the state of the cursor.
* @api public
*/
Cursor.prototype.isClosed = function() {
return this.state == Cursor.CLOSED ? true : false;
};
/**
* Init state
*
* @classconstant INIT
**/
Cursor.INIT = 0;
/**
* Cursor open
*
* @classconstant OPEN
**/
Cursor.OPEN = 1;
/**
* Cursor closed
*
* @classconstant CLOSED
**/
Cursor.CLOSED = 2;
/**
* @ignore
* @api private
*/
exports.Cursor = Cursor;

151
node_modules/mongodb/lib/mongodb/cursorstream.js generated vendored Normal file
View File

@@ -0,0 +1,151 @@
/**
* Module dependecies.
*/
var Stream = require('stream').Stream;
/**
* CursorStream
*
* Returns a stream interface for the **cursor**.
*
* Events
* - **data** {function(item) {}} the data event triggers when a document is ready.
* - **error** {function(err) {}} the error event triggers if an error happens.
* - **close** {function() {}} the end event triggers when there is no more documents available.
*
* @class Represents a CursorStream.
* @param {Cursor} cursor a cursor object that the stream wraps.
* @return {Stream}
*/
function CursorStream(cursor) {
if(!(this instanceof CursorStream)) return new CursorStream(cursor);
Stream.call(this);
this.readable = true;
this.paused = false;
this._cursor = cursor;
this._destroyed = null;
// give time to hook up events
var self = this;
process.nextTick(function () {
self._init();
});
}
/**
* Inherit from Stream
* @ignore
* @api private
*/
CursorStream.prototype.__proto__ = Stream.prototype;
/**
* Flag stating whether or not this stream is readable.
*/
CursorStream.prototype.readable;
/**
* Flag stating whether or not this stream is paused.
*/
CursorStream.prototype.paused;
/**
* Initialize the cursor.
* @ignore
* @api private
*/
CursorStream.prototype._init = function () {
if (this._destroyed) return;
this._next();
}
/**
* Pull the next document from the cursor.
* @ignore
* @api private
*/
CursorStream.prototype._next = function () {
if (this.paused || this._destroyed) return;
var self = this;
// nextTick is necessary to avoid stack overflows when
// dealing with large result sets.
process.nextTick(function () {
self._cursor.nextObject(function (err, doc) {
self._onNextObject(err, doc);
});
});
}
/**
* Handle each document as its returned from the cursor.
* @ignore
* @api private
*/
CursorStream.prototype._onNextObject = function (err, doc) {
if (err) return this.destroy(err);
// when doc is null we hit the end of the cursor
if (!doc) {
this.emit('end')
return this.destroy();
}
this.emit('data', doc);
this._next();
}
/**
* Pauses the stream.
*
* @api public
*/
CursorStream.prototype.pause = function () {
this.paused = true;
}
/**
* Resumes the stream.
*
* @api public
*/
CursorStream.prototype.resume = function () {
var self = this;
// Don't do anything if we are not paused
if(!this.paused) return;
process.nextTick(function() {
self.paused = false;
self._next();
})
}
/**
* Destroys the stream, closing the underlying
* cursor. No more events will be emitted.
*
* @api public
*/
CursorStream.prototype.destroy = function (err) {
if (this._destroyed) return;
this._destroyed = true;
this.readable = false;
this._cursor.close();
if (err) {
this.emit('error', err);
}
this.emit('close');
}
// TODO - maybe implement the raw option to pass binary?
//CursorStream.prototype.setEncoding = function () {
//}
module.exports = exports = CursorStream;

2205
node_modules/mongodb/lib/mongodb/db.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

213
node_modules/mongodb/lib/mongodb/gridfs/chunk.js generated vendored Normal file
View File

@@ -0,0 +1,213 @@
var Binary = require('bson').Binary,
ObjectID = require('bson').ObjectID;
/**
* Class for representing a single chunk in GridFS.
*
* @class
*
* @param file {GridStore} The {@link GridStore} object holding this chunk.
* @param mongoObject {object} The mongo object representation of this chunk.
*
* @throws Error when the type of data field for {@link mongoObject} is not
* supported. Currently supported types for data field are instances of
* {@link String}, {@link Array}, {@link Binary} and {@link Binary}
* from the bson module
*
* @see Chunk#buildMongoObject
*/
var Chunk = exports.Chunk = function(file, mongoObject) {
if(!(this instanceof Chunk)) return new Chunk(file, mongoObject);
this.file = file;
var self = this;
var mongoObjectFinal = mongoObject == null ? {} : mongoObject;
this.objectId = mongoObjectFinal._id == null ? new ObjectID() : mongoObjectFinal._id;
this.chunkNumber = mongoObjectFinal.n == null ? 0 : mongoObjectFinal.n;
this.data = new Binary();
if(mongoObjectFinal.data == null) {
} else if(typeof mongoObjectFinal.data == "string") {
var buffer = new Buffer(mongoObjectFinal.data.length);
buffer.write(mongoObjectFinal.data, 'binary', 0);
this.data = new Binary(buffer);
} else if(Array.isArray(mongoObjectFinal.data)) {
var buffer = new Buffer(mongoObjectFinal.data.length);
buffer.write(mongoObjectFinal.data.join(''), 'binary', 0);
this.data = new Binary(buffer);
} else if(mongoObjectFinal.data instanceof Binary || Object.prototype.toString.call(mongoObjectFinal.data) == "[object Binary]") {
this.data = mongoObjectFinal.data;
} else if(Buffer.isBuffer(mongoObjectFinal.data)) {
} else {
throw Error("Illegal chunk format");
}
// Update position
this.internalPosition = 0;
};
/**
* Writes a data to this object and advance the read/write head.
*
* @param data {string} the data to write
* @param callback {function(*, GridStore)} This will be called after executing
* this method. The first parameter will contain null and the second one
* will contain a reference to this object.
*/
Chunk.prototype.write = function(data, callback) {
this.data.write(data, this.internalPosition);
this.internalPosition = this.data.length();
if(callback != null) return callback(null, this);
return this;
};
/**
* Reads data and advances the read/write head.
*
* @param length {number} The length of data to read.
*
* @return {string} The data read if the given length will not exceed the end of
* the chunk. Returns an empty String otherwise.
*/
Chunk.prototype.read = function(length) {
// Default to full read if no index defined
length = length == null || length == 0 ? this.length() : length;
if(this.length() - this.internalPosition + 1 >= length) {
var data = this.data.read(this.internalPosition, length);
this.internalPosition = this.internalPosition + length;
return data;
} else {
return '';
}
};
Chunk.prototype.readSlice = function(length) {
if ((this.length() - this.internalPosition) >= length) {
var data = null;
if (this.data.buffer != null) { //Pure BSON
data = this.data.buffer.slice(this.internalPosition, this.internalPosition + length);
} else { //Native BSON
data = new Buffer(length);
length = this.data.readInto(data, this.internalPosition);
}
this.internalPosition = this.internalPosition + length;
return data;
} else {
return null;
}
};
/**
* Checks if the read/write head is at the end.
*
* @return {boolean} Whether the read/write head has reached the end of this
* chunk.
*/
Chunk.prototype.eof = function() {
return this.internalPosition == this.length() ? true : false;
};
/**
* Reads one character from the data of this chunk and advances the read/write
* head.
*
* @return {string} a single character data read if the the read/write head is
* not at the end of the chunk. Returns an empty String otherwise.
*/
Chunk.prototype.getc = function() {
return this.read(1);
};
/**
* Clears the contents of the data in this chunk and resets the read/write head
* to the initial position.
*/
Chunk.prototype.rewind = function() {
this.internalPosition = 0;
this.data = new Binary();
};
/**
* Saves this chunk to the database. Also overwrites existing entries having the
* same id as this chunk.
*
* @param callback {function(*, GridStore)} This will be called after executing
* this method. The first parameter will contain null and the second one
* will contain a reference to this object.
*/
Chunk.prototype.save = function(callback) {
var self = this;
self.file.chunkCollection(function(err, collection) {
if(err) return callback(err);
collection.remove({'_id':self.objectId}, {safe:true}, function(err, result) {
if(err) return callback(err);
if(self.data.length() > 0) {
self.buildMongoObject(function(mongoObject) {
collection.insert(mongoObject, {safe:true}, function(err, collection) {
callback(err, self);
});
});
} else {
callback(null, self);
}
});
});
};
/**
* Creates a mongoDB object representation of this chunk.
*
* @param callback {function(Object)} This will be called after executing this
* method. The object will be passed to the first parameter and will have
* the structure:
*
* <pre><code>
* {
* '_id' : , // {number} id for this chunk
* 'files_id' : , // {number} foreign key to the file collection
* 'n' : , // {number} chunk number
* 'data' : , // {bson#Binary} the chunk data itself
* }
* </code></pre>
*
* @see <a href="http://www.mongodb.org/display/DOCS/GridFS+Specification#GridFSSpecification-{{chunks}}">MongoDB GridFS Chunk Object Structure</a>
*/
Chunk.prototype.buildMongoObject = function(callback) {
var mongoObject = {'_id': this.objectId,
'files_id': this.file.fileId,
'n': this.chunkNumber,
'data': this.data};
callback(mongoObject);
};
/**
* @return {number} the length of the data
*/
Chunk.prototype.length = function() {
return this.data.length();
};
/**
* The position of the read/write head
* @name position
* @lends Chunk#
* @field
*/
Object.defineProperty(Chunk.prototype, "position", { enumerable: true
, get: function () {
return this.internalPosition;
}
, set: function(value) {
this.internalPosition = value;
}
});
/**
* The default chunk size
* @constant
*/
Chunk.DEFAULT_CHUNK_SIZE = 1024 * 256;

98
node_modules/mongodb/lib/mongodb/gridfs/grid.js generated vendored Normal file
View File

@@ -0,0 +1,98 @@
var GridStore = require('./gridstore').GridStore,
ObjectID = require('bson').ObjectID;
/**
* A class representation of a simple Grid interface.
*
* @class Represents the Grid.
* @param {Db} db A database instance to interact with.
* @param {String} [fsName] optional different root collection for GridFS.
* @return {Grid}
*/
function Grid(db, fsName) {
if(!(this instanceof Grid)) return new Grid(db, fsName);
this.db = db;
this.fsName = fsName == null ? GridStore.DEFAULT_ROOT_COLLECTION : fsName;
}
/**
* Puts binary data to the grid
*
* @param {Buffer} data buffer with Binary Data.
* @param {Object} [options] the options for the files.
* @param {Function} callback this will be called after this method is executed. The first parameter will contain an Error object if an error occured or null otherwise. The second parameter will contain a reference to this object.
* @return {null}
* @api public
*/
Grid.prototype.put = function(data, options, callback) {
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
options = args.length ? args.shift() : {};
// If root is not defined add our default one
options['root'] = options['root'] == null ? this.fsName : options['root'];
// Return if we don't have a buffer object as data
if(!(Buffer.isBuffer(data))) return callback(new Error("Data object must be a buffer object"), null);
// Get filename if we are using it
var filename = options['filename'];
// Create gridstore
var gridStore = new GridStore(this.db, filename, "w", options);
gridStore.open(function(err, gridStore) {
if(err) return callback(err, null);
gridStore.write(data, function(err, result) {
if(err) return callback(err, null);
gridStore.close(function(err, result) {
if(err) return callback(err, null);
callback(null, result);
})
})
})
}
/**
* Get binary data to the grid
*
* @param {ObjectID} id ObjectID for file.
* @param {Function} callback this will be called after this method is executed. The first parameter will contain an Error object if an error occured or null otherwise. The second parameter will contain a reference to this object.
* @return {null}
* @api public
*/
Grid.prototype.get = function(id, callback) {
// Validate that we have a valid ObjectId
if(!(id instanceof ObjectID)) return callback(new Error("Not a valid ObjectID", null));
// Create gridstore
var gridStore = new GridStore(this.db, id, "r", {root:this.fsName});
gridStore.open(function(err, gridStore) {
if(err) return callback(err, null);
// Return the data
gridStore.read(function(err, data) {
return callback(err, data)
});
})
}
/**
* Delete file from grid
*
* @param {ObjectID} id ObjectID for file.
* @param {Function} callback this will be called after this method is executed. The first parameter will contain an Error object if an error occured or null otherwise. The second parameter will contain a reference to this object.
* @return {null}
* @api public
*/
Grid.prototype.delete = function(id, callback) {
// Validate that we have a valid ObjectId
if(!(id instanceof ObjectID)) return callback(new Error("Not a valid ObjectID", null));
// Create gridstore
GridStore.unlink(this.db, id, {root:this.fsName}, function(err, result) {
if(err) return callback(err, false);
return callback(null, true);
});
}
exports.Grid = Grid;

1467
node_modules/mongodb/lib/mongodb/gridfs/gridstore.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

188
node_modules/mongodb/lib/mongodb/gridfs/readstream.js generated vendored Normal file
View File

@@ -0,0 +1,188 @@
var Stream = require('stream').Stream,
util = require('util');
/**
* ReadStream
*
* Returns a stream interface for the **file**.
*
* Events
* - **data** {function(item) {}} the data event triggers when a document is ready.
* - **end** {function() {}} the end event triggers when there is no more documents available.
* - **close** {function() {}} the close event triggers when the stream is closed.
* - **error** {function(err) {}} the error event triggers if an error happens.
*
* @class Represents a GridFS File Stream.
* @param {Boolean} autoclose automatically close file when the stream reaches the end.
* @param {GridStore} cursor a cursor object that the stream wraps.
* @return {ReadStream}
*/
function ReadStream(autoclose, gstore) {
if (!(this instanceof ReadStream)) return new ReadStream(autoclose, gstore);
Stream.call(this);
this.autoclose = !!autoclose;
this.gstore = gstore;
this.finalLength = gstore.length - gstore.position;
this.completedLength = 0;
this.currentChunkNumber = gstore.currentChunk.chunkNumber;
this.paused = false;
this.readable = true;
this.pendingChunk = null;
this.executing = false;
// Calculate the number of chunks
this.numberOfChunks = Math.ceil(gstore.length/gstore.chunkSize);
// This seek start position inside the current chunk
this.seekStartPosition = gstore.position - (this.currentChunkNumber * gstore.chunkSize);
var self = this;
process.nextTick(function() {
self._execute();
});
};
/**
* Inherit from Stream
* @ignore
* @api private
*/
ReadStream.prototype.__proto__ = Stream.prototype;
/**
* Flag stating whether or not this stream is readable.
*/
ReadStream.prototype.readable;
/**
* Flag stating whether or not this stream is paused.
*/
ReadStream.prototype.paused;
/**
* @ignore
* @api private
*/
ReadStream.prototype._execute = function() {
if(this.paused === true || this.readable === false) {
return;
}
var gstore = this.gstore;
var self = this;
// Set that we are executing
this.executing = true;
var last = false;
var toRead = 0;
if(gstore.currentChunk.chunkNumber >= (this.numberOfChunks - 1)) {
self.executing = false;
last = true;
}
// Data setup
var data = null;
// Read a slice (with seek set if none)
if(this.seekStartPosition > 0 && (gstore.currentChunk.length() - this.seekStartPosition) > 0) {
data = gstore.currentChunk.readSlice(gstore.currentChunk.length() - this.seekStartPosition);
this.seekStartPosition = 0;
} else {
data = gstore.currentChunk.readSlice(gstore.currentChunk.length());
}
// Return the data
if(data != null && gstore.currentChunk.chunkNumber == self.currentChunkNumber) {
self.currentChunkNumber = self.currentChunkNumber + 1;
self.completedLength += data.length;
self.pendingChunk = null;
self.emit("data", data);
}
if(last === true) {
self.readable = false;
self.emit("end");
if(self.autoclose === true) {
if(gstore.mode[0] == "w") {
gstore.close(function(err, doc) {
if (err) {
self.emit("error", err);
return;
}
self.readable = false;
self.emit("close", doc);
});
} else {
self.readable = false;
self.emit("close");
}
}
} else {
gstore._nthChunk(gstore.currentChunk.chunkNumber + 1, function(err, chunk) {
if(err) {
self.readable = false;
self.emit("error", err);
self.executing = false;
return;
}
self.pendingChunk = chunk;
if(self.paused === true) {
self.executing = false;
return;
}
gstore.currentChunk = self.pendingChunk;
self._execute();
});
}
};
/**
* Pauses this stream, then no farther events will be fired.
*
* @ignore
* @api public
*/
ReadStream.prototype.pause = function() {
if(!this.executing) {
this.paused = true;
}
};
/**
* Destroys the stream, then no farther events will be fired.
*
* @ignore
* @api public
*/
ReadStream.prototype.destroy = function() {
this.readable = false;
// Emit close event
this.emit("close");
};
/**
* Resumes this stream.
*
* @ignore
* @api public
*/
ReadStream.prototype.resume = function() {
if(this.paused === false || !this.readable) {
return;
}
this.paused = false;
var self = this;
process.nextTick(function() {
self._execute();
});
};
exports.ReadStream = ReadStream;

69
node_modules/mongodb/lib/mongodb/index.js generated vendored Normal file
View File

@@ -0,0 +1,69 @@
try {
exports.BSONPure = require('bson').BSONPure;
exports.BSONNative = require('bson').BSONNative;
} catch(err) {
// do nothing
}
[ 'commands/base_command'
, 'admin'
, 'collection'
, 'connection/read_preference'
, 'connection/connection'
, 'connection/server'
, 'connection/mongos'
, 'connection/repl_set'
, 'mongo_client'
, 'cursor'
, 'db'
, 'mongo_client'
, 'gridfs/grid'
, 'gridfs/chunk'
, 'gridfs/gridstore'].forEach(function (path) {
var module = require('./' + path);
for (var i in module) {
exports[i] = module[i];
}
// backwards compat
exports.ReplSetServers = exports.ReplSet;
// Add BSON Classes
exports.Binary = require('bson').Binary;
exports.Code = require('bson').Code;
exports.DBRef = require('bson').DBRef;
exports.Double = require('bson').Double;
exports.Long = require('bson').Long;
exports.MinKey = require('bson').MinKey;
exports.MaxKey = require('bson').MaxKey;
exports.ObjectID = require('bson').ObjectID;
exports.Symbol = require('bson').Symbol;
exports.Timestamp = require('bson').Timestamp;
// Add BSON Parser
exports.BSON = require('bson').BSONPure.BSON;
});
// Get the Db object
var Db = require('./db').Db;
// Set up the connect function
var connect = Db.connect;
var obj = connect;
// Map all values to the exports value
for(var name in exports) {
obj[name] = exports[name];
}
// Add the pure and native backward compatible functions
exports.pure = exports.native = function() {
return obj;
}
// Map all values to the exports value
for(var name in exports) {
connect[name] = exports[name];
}
// Set our exports to be the connect function
module.exports = connect;

116
node_modules/mongodb/lib/mongodb/mongo_client.js generated vendored Normal file
View File

@@ -0,0 +1,116 @@
var Db = require('./db').Db;
/**
* Create a new MongoClient instance.
*
* Options
* - **w**, {Number/String, > -1 || 'majority' || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = 'majority' or tag acknowledges the write
* - **wtimeout**, {Number, 0} set the timeout for waiting for write concern to finish (combines with w option)
* - **fsync**, (Boolean, default:false) write waits for fsync before returning
* - **journal**, (Boolean, default:false) write waits for journal sync before returning
* - **readPreference** {String}, the prefered read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
* - **native_parser** {Boolean, default:false}, use c++ bson parser.
* - **forceServerObjectId** {Boolean, default:false}, force server to create _id fields instead of client.
* - **pkFactory** {Object}, object overriding the basic ObjectID primary key generation.
* - **serializeFunctions** {Boolean, default:false}, serialize functions.
* - **raw** {Boolean, default:false}, peform operations using raw bson buffers.
* - **recordQueryStats** {Boolean, default:false}, record query statistics during execution.
* - **retryMiliSeconds** {Number, default:5000}, number of miliseconds between retries.
* - **numberOfRetries** {Number, default:5}, number of retries off connection.
*
* Deprecated Options
* - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
*
* @class Represents a MongoClient
* @param {Object} serverConfig server config object.
* @param {Object} [options] additional options for the collection.
*/
function MongoClient(serverConfig, options) {
options = options == null ? {} : options;
// If no write concern is set set the default to w:1
if(options != null && !options.journal && !options.w && !options.fsync) {
options.w = 1;
}
// The internal db instance we are wrapping
this._db = new Db('test', serverConfig, options);
}
/**
* Initialize the database connection.
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the connected mongoclient or null if an error occured.
* @return {null}
* @api public
*/
MongoClient.prototype.open = function(callback) {
// Self reference
var self = this;
this._db.open(function(err, db) {
if(err) return callback(err, null);
callback(null, self);
})
}
/**
* Close the current db connection, including all the child db instances. Emits close event if no callback is provided.
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from the close method or null if an error occured.
* @return {null}
* @api public
*/
MongoClient.prototype.close = function(callback) {
this._db.close(callback);
}
/**
* Create a new Db instance sharing the current socket connections.
*
* @param {String} dbName the name of the database we want to use.
* @return {Db} a db instance using the new database.
* @api public
*/
MongoClient.prototype.db = function(dbName) {
return this._db.db(dbName);
}
/**
* Connect to MongoDB using a url as documented at
*
* www.mongodb.org/display/DOCS/Connections
*
* Options
* - **uri_decode_auth** {Boolean, default:false} uri decode the user name and password for authentication
* - **db** {Object, default: null} a hash off options to set on the db object, see **Db constructor**
* - **server** {Object, default: null} a hash off options to set on the server objects, see **Server** constructor**
* - **replSet** {Object, default: null} a hash off options to set on the replSet object, see **ReplSet** constructor**
* - **mongos** {Object, default: null} a hash off options to set on the mongos object, see **Mongos** constructor**
*
* @param {String} url connection url for MongoDB.
* @param {Object} [options] optional options for insert command
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the initialized db object or null if an error occured.
* @return {null}
* @api public
*/
MongoClient.connect = function(url, options, callback) {
if(typeof options == 'function') {
callback = options;
options = {};
}
Db.connect(url, options, function(err, db) {
if(err) return callback(err, null);
if(db.options !== null && !db.options.safe && !db.options.journal
&& !db.options.w && !db.options.fsync && typeof db.options.w != 'number'
&& (db.options.safe == false && url.indexOf("safe=") == -1)) {
db.options.w = 1;
}
// Return the db
callback(null, db);
});
}
exports.MongoClient = MongoClient;

View File

@@ -0,0 +1,140 @@
var Long = require('bson').Long;
/**
Reply message from mongo db
**/
var MongoReply = exports.MongoReply = function() {
this.documents = [];
this.index = 0;
};
MongoReply.prototype.parseHeader = function(binary_reply, bson) {
// Unpack the standard header first
this.messageLength = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
this.index = this.index + 4;
// Fetch the request id for this reply
this.requestId = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
this.index = this.index + 4;
// Fetch the id of the request that triggered the response
this.responseTo = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
// Skip op-code field
this.index = this.index + 4 + 4;
// Unpack the reply message
this.responseFlag = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
this.index = this.index + 4;
// Unpack the cursor id (a 64 bit long integer)
var low_bits = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
this.index = this.index + 4;
var high_bits = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
this.index = this.index + 4;
this.cursorId = new Long(low_bits, high_bits);
// Unpack the starting from
this.startingFrom = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
this.index = this.index + 4;
// Unpack the number of objects returned
this.numberReturned = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
this.index = this.index + 4;
}
MongoReply.prototype.parseBody = function(binary_reply, bson, raw, callback) {
raw = raw == null ? false : raw;
// Just set a doc limit for deserializing
var docLimitSize = 1024*20;
// If our message length is very long, let's switch to process.nextTick for messages
if(this.messageLength > docLimitSize) {
var batchSize = this.numberReturned;
this.documents = new Array(this.numberReturned);
// Just walk down until we get a positive number >= 1
for(var i = 50; i > 0; i--) {
if((this.numberReturned/i) >= 1) {
batchSize = i;
break;
}
}
// Actual main creator of the processFunction setting internal state to control the flow
var parseFunction = function(_self, _binary_reply, _batchSize, _numberReturned) {
var object_index = 0;
// Internal loop process that will use nextTick to ensure we yield some time
var processFunction = function() {
// Adjust batchSize if we have less results left than batchsize
if((_numberReturned - object_index) < _batchSize) {
_batchSize = _numberReturned - object_index;
}
// If raw just process the entries
if(raw) {
// Iterate over the batch
for(var i = 0; i < _batchSize; i++) {
// Are we done ?
if(object_index <= _numberReturned) {
// Read the size of the bson object
var bsonObjectSize = _binary_reply[_self.index] | _binary_reply[_self.index + 1] << 8 | _binary_reply[_self.index + 2] << 16 | _binary_reply[_self.index + 3] << 24;
// If we are storing the raw responses to pipe straight through
_self.documents[object_index] = binary_reply.slice(_self.index, _self.index + bsonObjectSize);
// Adjust binary index to point to next block of binary bson data
_self.index = _self.index + bsonObjectSize;
// Update number of docs parsed
object_index = object_index + 1;
}
}
} else {
try {
// Parse documents
_self.index = bson.deserializeStream(binary_reply, _self.index, _batchSize, _self.documents, object_index);
// Adjust index
object_index = object_index + _batchSize;
} catch (err) {
return callback(err);
}
}
// If we hav more documents process NextTick
if(object_index < _numberReturned) {
process.nextTick(processFunction);
} else {
callback(null);
}
}
// Return the process function
return processFunction;
}(this, binary_reply, batchSize, this.numberReturned)();
} else {
try {
// Let's unpack all the bson documents, deserialize them and store them
for(var object_index = 0; object_index < this.numberReturned; object_index++) {
// Read the size of the bson object
var bsonObjectSize = binary_reply[this.index] | binary_reply[this.index + 1] << 8 | binary_reply[this.index + 2] << 16 | binary_reply[this.index + 3] << 24;
// If we are storing the raw responses to pipe straight through
if(raw) {
// Deserialize the object and add to the documents array
this.documents.push(binary_reply.slice(this.index, this.index + bsonObjectSize));
} else {
// Deserialize the object and add to the documents array
this.documents.push(bson.deserialize(binary_reply.slice(this.index, this.index + bsonObjectSize)));
}
// Adjust binary index to point to next block of binary bson data
this.index = this.index + bsonObjectSize;
}
} catch(err) {
return callback(err);
}
// No error return
callback(null);
}
}
MongoReply.prototype.is_error = function(){
if(this.documents.length == 1) {
return this.documents[0].ok == 1 ? false : true;
}
return false;
};
MongoReply.prototype.error_message = function() {
return this.documents.length == 1 && this.documents[0].ok == 1 ? '' : this.documents[0].errmsg;
};

97
node_modules/mongodb/lib/mongodb/utils.js generated vendored Normal file
View File

@@ -0,0 +1,97 @@
/**
* Sort functions, Normalize and prepare sort parameters
*/
var formatSortValue = exports.formatSortValue = function(sortDirection) {
var value = ("" + sortDirection).toLowerCase();
switch (value) {
case 'ascending':
case 'asc':
case '1':
return 1;
case 'descending':
case 'desc':
case '-1':
return -1;
default:
throw new Error("Illegal sort clause, must be of the form "
+ "[['field1', '(ascending|descending)'], "
+ "['field2', '(ascending|descending)']]");
}
};
var formattedOrderClause = exports.formattedOrderClause = function(sortValue) {
var orderBy = {};
if (Array.isArray(sortValue)) {
for(var i = 0; i < sortValue.length; i++) {
if(sortValue[i].constructor == String) {
orderBy[sortValue[i]] = 1;
} else {
orderBy[sortValue[i][0]] = formatSortValue(sortValue[i][1]);
}
}
} else if(Object.prototype.toString.call(sortValue) === '[object Object]') {
orderBy = sortValue;
} else if (sortValue.constructor == String) {
orderBy[sortValue] = 1;
} else {
throw new Error("Illegal sort clause, must be of the form " +
"[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]");
}
return orderBy;
};
exports.encodeInt = function(value) {
var buffer = new Buffer(4);
buffer[3] = (value >> 24) & 0xff;
buffer[2] = (value >> 16) & 0xff;
buffer[1] = (value >> 8) & 0xff;
buffer[0] = value & 0xff;
return buffer;
}
exports.encodeIntInPlace = function(value, buffer, index) {
buffer[index + 3] = (value >> 24) & 0xff;
buffer[index + 2] = (value >> 16) & 0xff;
buffer[index + 1] = (value >> 8) & 0xff;
buffer[index] = value & 0xff;
}
exports.encodeCString = function(string) {
var buf = new Buffer(string, 'utf8');
return [buf, new Buffer([0])];
}
exports.decodeUInt32 = function(array, index) {
return array[index] | array[index + 1] << 8 | array[index + 2] << 16 | array[index + 3] << 24;
}
// Decode the int
exports.decodeUInt8 = function(array, index) {
return array[index];
}
/**
* Context insensitive type checks
*/
var toString = Object.prototype.toString;
exports.isObject = function (arg) {
return '[object Object]' == toString.call(arg)
}
exports.isArray = function (arg) {
return Array.isArray(arg) ||
'object' == typeof arg && '[object Array]' == toString.call(arg)
}
exports.isDate = function (arg) {
return 'object' == typeof arg && '[object Date]' == toString.call(arg)
}
exports.isRegExp = function (arg) {
return 'object' == typeof arg && '[object RegExp]' == toString.call(arg)
}

5
node_modules/mongodb/node_modules/bson/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,5 @@
language: node_js
node_js:
- 0.6
- 0.8
- 0.9 # development version of 0.8, may be unstable

16
node_modules/mongodb/node_modules/bson/Makefile generated vendored Normal file
View File

@@ -0,0 +1,16 @@
NODE = node
NPM = npm
NODEUNIT = node_modules/nodeunit/bin/nodeunit
all: clean node_gyp
test: clean node_gyp
npm test
node_gyp: clean
node-gyp configure build
clean:
node-gyp clean
.PHONY: all

1
node_modules/mongodb/node_modules/bson/README.md generated vendored Normal file
View File

@@ -0,0 +1 @@
A JS/C++ Bson parser for node, used in the MongoDB Native driver

View File

@@ -0,0 +1,130 @@
// var BSON = require('../../lib/mongodb').BSONNative.BSON,
// ObjectID = require('../../lib/mongodb').BSONNative.ObjectID,
// Code = require('../../lib/mongodb').BSONNative.Code,
// Long = require('../../lib/mongodb').BSONNative.Long,
// Binary = require('../../lib/mongodb').BSONNative.Binary,
// debug = require('util').debug,
// inspect = require('util').inspect,
//
// Long = require('../../lib/mongodb').Long,
// ObjectID = require('../../lib/mongodb').ObjectID,
// Binary = require('../../lib/mongodb').Binary,
// Code = require('../../lib/mongodb').Code,
// DBRef = require('../../lib/mongodb').DBRef,
// Symbol = require('../../lib/mongodb').Symbol,
// Double = require('../../lib/mongodb').Double,
// MaxKey = require('../../lib/mongodb').MaxKey,
// MinKey = require('../../lib/mongodb').MinKey,
// Timestamp = require('../../lib/mongodb').Timestamp;
// var BSON = require('../../lib/mongodb').BSONPure.BSON,
// ObjectID = require('../../lib/mongodb').BSONPure.ObjectID,
// Code = require('../../lib/mongodb').BSONPure.Code,
// Long = require('../../lib/mongodb').BSONPure.Long,
// Binary = require('../../lib/mongodb').BSONPure.Binary;
var BSON = require('../lib/bson').BSONNative.BSON,
Long = require('../lib/bson').Long,
ObjectID = require('../lib/bson').ObjectID,
Binary = require('../lib/bson').Binary,
Code = require('../lib/bson').Code,
DBRef = require('../lib/bson').DBRef,
Symbol = require('../lib/bson').Symbol,
Double = require('../lib/bson').Double,
MaxKey = require('../lib/bson').MaxKey,
MinKey = require('../lib/bson').MinKey,
Timestamp = require('../lib/bson').Timestamp;
// console.dir(require('../lib/bson'))
var COUNT = 1000;
var COUNT = 100;
var object = {
string: "Strings are great",
decimal: 3.14159265,
bool: true,
integer: 5,
date: new Date(),
double: new Double(1.4),
id: new ObjectID(),
min: new MinKey(),
max: new MaxKey(),
symbol: new Symbol('hello'),
long: Long.fromNumber(100),
bin: new Binary(new Buffer(100)),
subObject: {
moreText: "Bacon ipsum dolor sit amet cow pork belly rump ribeye pastrami andouille. Tail hamburger pork belly, drumstick flank salami t-bone sirloin pork chop ribeye ham chuck pork loin shankle. Ham fatback pork swine, sirloin shankle short loin andouille shank sausage meatloaf drumstick. Pig chicken cow bresaola, pork loin jerky meatball tenderloin brisket strip steak jowl spare ribs. Biltong sirloin pork belly boudin, bacon pastrami rump chicken. Jowl rump fatback, biltong bacon t-bone turkey. Turkey pork loin boudin, tenderloin jerky beef ribs pastrami spare ribs biltong pork chop beef.",
longKeylongKeylongKeylongKeylongKeylongKey: "Pork belly boudin shoulder ribeye pork chop brisket biltong short ribs. Salami beef pork belly, t-bone sirloin meatloaf tail jowl spare ribs. Sirloin biltong bresaola cow turkey. Biltong fatback meatball, bresaola tail shankle turkey pancetta ham ribeye flank bacon jerky pork chop. Boudin sirloin shoulder, salami swine flank jerky t-bone pork chop pork beef tongue. Bresaola ribeye jerky andouille. Ribeye ground round sausage biltong beef ribs chuck, shank hamburger chicken short ribs spare ribs tenderloin meatloaf pork loin."
},
subArray: [1,2,3,4,5,6,7,8,9,10],
anotherString: "another string",
code: new Code("function() {}", {i:1})
}
// Number of objects
var numberOfObjects = 10000;
var bson = new BSON([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
console.log("---------------------- 1")
var s = new Date()
// Object serialized
for(var i = 0; i < numberOfObjects; i++) {
objectBSON = bson.serialize(object, null, true)
}
console.log("====================== " + (new Date().getTime() - s.getTime()) + " :: " + ((new Date().getTime() - s.getTime()))/numberOfObjects)
console.log("---------------------- 2")
var s = new Date()
// Object serialized
for(var i = 0; i < numberOfObjects; i++) {
bson.deserialize(objectBSON);
}
console.log("====================== " + (new Date().getTime() - s.getTime()) + " :: " + ((new Date().getTime() - s.getTime()))/numberOfObjects)
// // Buffer With copies of the objectBSON
// var data = new Buffer(objectBSON.length * numberOfObjects);
// var index = 0;
//
// // Copy the buffer 1000 times to create a strea m of objects
// for(var i = 0; i < numberOfObjects; i++) {
// // Copy data
// objectBSON.copy(data, index);
// // Adjust index
// index = index + objectBSON.length;
// }
//
// // console.log("-----------------------------------------------------------------------------------")
// // console.dir(objectBSON)
//
// var x, start, end, j
// var objectBSON, objectJSON
//
// // Allocate the return array (avoid concatinating everything)
// var results = new Array(numberOfObjects);
//
// console.log(COUNT + "x (objectBSON = BSON.serialize(object))")
// start = new Date
//
// // var objects = BSON.deserializeStream(data, 0, numberOfObjects);
// // console.log("----------------------------------------------------------------------------------- 0")
// // var objects = BSON.deserialize(data);
// // console.log("----------------------------------------------------------------------------------- 1")
// // console.dir(objects)
//
// for (j=COUNT; --j>=0; ) {
// var nextIndex = BSON.deserializeStream(data, 0, numberOfObjects, results, 0);
// }
//
// end = new Date
// var opsprsecond = COUNT / ((end - start)/1000);
// console.log("bson size (bytes): ", objectBSON.length);
// console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
// console.log("MB/s = " + ((opsprsecond*objectBSON.length)/1024));
//
// // console.dir(nextIndex)
// // console.dir(results)

17
node_modules/mongodb/node_modules/bson/binding.gyp generated vendored Normal file
View File

@@ -0,0 +1,17 @@
{
'targets': [
{
'target_name': 'bson',
'sources': [ 'ext/bson.cc' ],
'cflags!': [ '-fno-exceptions' ],
'cflags_cc!': [ '-fno-exceptions' ],
'conditions': [
['OS=="mac"', {
'xcode_settings': {
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES'
}
}]
]
}
]
}

359
node_modules/mongodb/node_modules/bson/build/Makefile generated vendored Normal file
View File

@@ -0,0 +1,359 @@
# We borrow heavily from the kernel build setup, though we are simpler since
# we don't have Kconfig tweaking settings on us.
# The implicit make rules have it looking for RCS files, among other things.
# We instead explicitly write all the rules we care about.
# It's even quicker (saves ~200ms) to pass -r on the command line.
MAKEFLAGS=-r
# The source directory tree.
srcdir := ..
abs_srcdir := $(abspath $(srcdir))
# The name of the builddir.
builddir_name ?= .
# The V=1 flag on command line makes us verbosely print command lines.
ifdef V
quiet=
else
quiet=quiet_
endif
# Specify BUILDTYPE=Release on the command line for a release build.
BUILDTYPE ?= Release
# Directory all our build output goes into.
# Note that this must be two directories beneath src/ for unit tests to pass,
# as they reach into the src/ directory for data with relative paths.
builddir ?= $(builddir_name)/$(BUILDTYPE)
abs_builddir := $(abspath $(builddir))
depsdir := $(builddir)/.deps
# Object output directory.
obj := $(builddir)/obj
abs_obj := $(abspath $(obj))
# We build up a list of every single one of the targets so we can slurp in the
# generated dependency rule Makefiles in one pass.
all_deps :=
# C++ apps need to be linked with g++.
#
# Note: flock is used to seralize linking. Linking is a memory-intensive
# process so running parallel links can often lead to thrashing. To disable
# the serialization, override LINK via an envrionment variable as follows:
#
# export LINK=g++
#
# This will allow make to invoke N linker processes as specified in -jN.
LINK ?= ./gyp-mac-tool flock $(builddir)/linker.lock $(CXX)
CC.target ?= $(CC)
CFLAGS.target ?= $(CFLAGS)
CXX.target ?= $(CXX)
CXXFLAGS.target ?= $(CXXFLAGS)
LINK.target ?= $(LINK)
LDFLAGS.target ?= $(LDFLAGS)
AR.target ?= $(AR)
ARFLAGS.target ?= crs
# N.B.: the logic of which commands to run should match the computation done
# in gyp's make.py where ARFLAGS.host etc. is computed.
# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
# to replicate this environment fallback in make as well.
CC.host ?= gcc
CFLAGS.host ?=
CXX.host ?= g++
CXXFLAGS.host ?=
LINK.host ?= g++
LDFLAGS.host ?=
AR.host ?= ar
ARFLAGS.host := crs
# Define a dir function that can handle spaces.
# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
# "leading spaces cannot appear in the text of the first argument as written.
# These characters can be put into the argument value by variable substitution."
empty :=
space := $(empty) $(empty)
# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
replace_spaces = $(subst $(space),?,$1)
unreplace_spaces = $(subst ?,$(space),$1)
dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
# Flags to make gcc output dependency info. Note that you need to be
# careful here to use the flags that ccache and distcc can understand.
# We write to a dep file on the side first and then rename at the end
# so we can't end up with a broken dep file.
depfile = $(depsdir)/$(call replace_spaces,$@).d
DEPFLAGS = -MMD -MF $(depfile).raw
# We have to fixup the deps output in a few ways.
# (1) the file output should mention the proper .o file.
# ccache or distcc lose the path to the target, so we convert a rule of
# the form:
# foobar.o: DEP1 DEP2
# into
# path/to/foobar.o: DEP1 DEP2
# (2) we want missing files not to cause us to fail to build.
# We want to rewrite
# foobar.o: DEP1 DEP2 \
# DEP3
# to
# DEP1:
# DEP2:
# DEP3:
# so if the files are missing, they're just considered phony rules.
# We have to do some pretty insane escaping to get those backslashes
# and dollar signs past make, the shell, and sed at the same time.
# Doesn't work with spaces, but that's fine: .d files have spaces in
# their names replaced with other characters.
define fixup_dep
# The depfile may not exist if the input file didn't have any #includes.
touch $(depfile).raw
# Fixup path as in (1).
sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
# Add extra rules as in (2).
# We remove slashes and replace spaces with new lines;
# remove blank lines;
# delete the first line and append a colon to the remaining lines.
sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
grep -v '^$$' |\
sed -e 1d -e 's|$$|:|' \
>> $(depfile)
rm $(depfile).raw
endef
# Command definitions:
# - cmd_foo is the actual command to run;
# - quiet_cmd_foo is the brief-output summary of the command.
quiet_cmd_cc = CC($(TOOLSET)) $@
cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
quiet_cmd_cxx = CXX($(TOOLSET)) $@
cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
quiet_cmd_objc = CXX($(TOOLSET)) $@
cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
quiet_cmd_objcxx = CXX($(TOOLSET)) $@
cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
# Commands for precompiled header files.
quiet_cmd_pch_c = CXX($(TOOLSET)) $@
cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
quiet_cmd_pch_cc = CXX($(TOOLSET)) $@
cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
quiet_cmd_pch_m = CXX($(TOOLSET)) $@
cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
quiet_cmd_pch_mm = CXX($(TOOLSET)) $@
cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
# gyp-mac-tool is written next to the root Makefile by gyp.
# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd
# already.
quiet_cmd_mac_tool = MACTOOL $(4) $<
cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@"
quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@
cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4)
quiet_cmd_infoplist = INFOPLIST $@
cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@"
quiet_cmd_touch = TOUCH $@
cmd_touch = touch $@
quiet_cmd_copy = COPY $@
# send stderr to /dev/null to ignore messages when linking directories.
cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
quiet_cmd_alink = LIBTOOL-STATIC $@
cmd_alink = rm -f $@ && ./gyp-mac-tool filter-libtool libtool -static -o $@ $(filter %.o,$^)
quiet_cmd_link = LINK($(TOOLSET)) $@
cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
# TODO(thakis): Find out and document the difference between shared_library and
# loadable_module on mac.
quiet_cmd_solink = SOLINK($(TOOLSET)) $@
cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
# TODO(thakis): The solink_module rule is likely wrong. Xcode seems to pass
# -bundle -single_module here (for osmesa.so).
quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
# Define an escape_quotes function to escape single quotes.
# This allows us to handle quotes properly as long as we always use
# use single quotes and escape_quotes.
escape_quotes = $(subst ','\'',$(1))
# This comment is here just to include a ' to unconfuse syntax highlighting.
# Define an escape_vars function to escape '$' variable syntax.
# This allows us to read/write command lines with shell variables (e.g.
# $LD_LIBRARY_PATH), without triggering make substitution.
escape_vars = $(subst $$,$$$$,$(1))
# Helper that expands to a shell command to echo a string exactly as it is in
# make. This uses printf instead of echo because printf's behaviour with respect
# to escape sequences is more portable than echo's across different shells
# (e.g., dash, bash).
exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
# Helper to compare the command we're about to run against the command
# we logged the last time we ran the command. Produces an empty
# string (false) when the commands match.
# Tricky point: Make has no string-equality test function.
# The kernel uses the following, but it seems like it would have false
# positives, where one string reordered its arguments.
# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
# $(filter-out $(cmd_$@), $(cmd_$(1))))
# We instead substitute each for the empty string into the other, and
# say they're equal if both substitutions produce the empty string.
# .d files contain ? instead of spaces, take that into account.
command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
$(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
# Helper that is non-empty when a prerequisite changes.
# Normally make does this implicitly, but we force rules to always run
# so we can check their command lines.
# $? -- new prerequisites
# $| -- order-only dependencies
prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
# Helper that executes all postbuilds, and deletes the output file when done
# if any of the postbuilds failed.
define do_postbuilds
@E=0;\
for p in $(POSTBUILDS); do\
eval $$p;\
F=$$?;\
if [ $$F -ne 0 ]; then\
E=$$F;\
fi;\
done;\
if [ $$E -ne 0 ]; then\
rm -rf "$@";\
exit $$E;\
fi
endef
# do_cmd: run a command via the above cmd_foo names, if necessary.
# Should always run for a given target to handle command-line changes.
# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
# Third argument, if non-zero, makes it do POSTBUILDS processing.
# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
# spaces already and dirx strips the ? characters.
define do_cmd
$(if $(or $(command_changed),$(prereq_changed)),
@$(call exact_echo, $($(quiet)cmd_$(1)))
@mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
$(if $(findstring flock,$(word 2,$(cmd_$1))),
@$(cmd_$(1))
@echo " $(quiet_cmd_$(1)): Finished",
@$(cmd_$(1))
)
@$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
@$(if $(2),$(fixup_dep))
$(if $(and $(3), $(POSTBUILDS)),
$(call do_postbuilds)
)
)
endef
# Declare the "all" target first so it is the default,
# even though we don't have the deps yet.
.PHONY: all
all:
# make looks for ways to re-generate included makefiles, but in our case, we
# don't have a direct way. Explicitly telling make that it has nothing to do
# for them makes it go faster.
%.d: ;
# Use FORCE_DO_CMD to force a target to run. Should be coupled with
# do_cmd.
.PHONY: FORCE_DO_CMD
FORCE_DO_CMD:
TOOLSET := target
# Suffix rules, putting all outputs into $(obj).
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD
@$(call do_cmd,objc,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD
@$(call do_cmd,objcxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
@$(call do_cmd,cc,1)
# Try building from generated source, too.
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD
@$(call do_cmd,objc,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD
@$(call do_cmd,objcxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD
@$(call do_cmd,objc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD
@$(call do_cmd,objcxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
@$(call do_cmd,cc,1)
ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
$(findstring $(join ^,$(prefix)),\
$(join ^,bson.target.mk)))),)
include bson.target.mk
endif
quiet_cmd_regen_makefile = ACTION Regenerating $@
cmd_regen_makefile = /Users/ck/.node-gyp/0.8.11/tools/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -I/Users/ck/coding/projects/js-bson/build/config.gypi -I/usr/local/lib/node_modules/node-gyp/addon.gypi -I/Users/ck/.node-gyp/0.8.11/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/ck/.node-gyp/0.8.11" "-Dmodule_root_dir=/Users/ck/coding/projects/js-bson" binding.gyp
Makefile: $(srcdir)/../../../.node-gyp/0.8.11/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp $(srcdir)/../../../../../usr/local/lib/node_modules/node-gyp/addon.gypi
$(call do_cmd,regen_makefile)
# "all" is a concatenation of the "all" targets from all the included
# sub-makefiles. This is just here to clarify.
all:
# Add in dependency-tracking rules. $(all_deps) is the list of every single
# target in our tree. Only consider the ones with .d (dependency) info:
d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
ifneq ($(d_files),)
include $(d_files)
endif

View File

@@ -0,0 +1 @@
cmd_Release/bson.node := ./gyp-mac-tool flock ./Release/linker.lock c++ -shared -Wl,-search_paths_first -mmacosx-version-min=10.5 -arch x86_64 -L./Release -install_name /usr/local/lib/bson.node -o Release/bson.node Release/obj.target/bson/ext/bson.o -undefined dynamic_lookup

View File

@@ -0,0 +1,34 @@
cmd_Release/obj.target/bson/ext/bson.o := c++ '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-D_DARWIN_USE_64_BIT_INODE=1' -I/Users/ck/.node-gyp/0.8.11/src -I/Users/ck/.node-gyp/0.8.11/deps/uv/include -I/Users/ck/.node-gyp/0.8.11/deps/v8/include -Os -gdwarf-2 -mmacosx-version-min=10.5 -arch x86_64 -Wall -Wendif-labels -W -Wno-unused-parameter -fno-rtti -fno-threadsafe-statics -fno-strict-aliasing -MMD -MF ./Release/.deps/Release/obj.target/bson/ext/bson.o.d.raw -c -o Release/obj.target/bson/ext/bson.o ../ext/bson.cc
Release/obj.target/bson/ext/bson.o: ../ext/bson.cc \
/Users/ck/.node-gyp/0.8.11/deps/v8/include/v8.h \
/Users/ck/.node-gyp/0.8.11/deps/v8/include/v8stdint.h \
/Users/ck/.node-gyp/0.8.11/src/node.h \
/Users/ck/.node-gyp/0.8.11/deps/uv/include/uv.h \
/Users/ck/.node-gyp/0.8.11/deps/uv/include/ares.h \
/Users/ck/.node-gyp/0.8.11/deps/uv/include/ares_version.h \
/Users/ck/.node-gyp/0.8.11/deps/uv/include/uv-private/uv-unix.h \
/Users/ck/.node-gyp/0.8.11/deps/uv/include/uv-private/ngx-queue.h \
/Users/ck/.node-gyp/0.8.11/deps/uv/include/uv-private/ev.h \
/Users/ck/.node-gyp/0.8.11/deps/uv/include/uv-private/eio.h \
/Users/ck/.node-gyp/0.8.11/src/node_object_wrap.h \
/Users/ck/.node-gyp/0.8.11/src/ev-emul.h \
/Users/ck/.node-gyp/0.8.11/src/eio-emul.h \
/Users/ck/.node-gyp/0.8.11/src/node_version.h \
/Users/ck/.node-gyp/0.8.11/src/node_buffer.h ../ext/bson.h
../ext/bson.cc:
/Users/ck/.node-gyp/0.8.11/deps/v8/include/v8.h:
/Users/ck/.node-gyp/0.8.11/deps/v8/include/v8stdint.h:
/Users/ck/.node-gyp/0.8.11/src/node.h:
/Users/ck/.node-gyp/0.8.11/deps/uv/include/uv.h:
/Users/ck/.node-gyp/0.8.11/deps/uv/include/ares.h:
/Users/ck/.node-gyp/0.8.11/deps/uv/include/ares_version.h:
/Users/ck/.node-gyp/0.8.11/deps/uv/include/uv-private/uv-unix.h:
/Users/ck/.node-gyp/0.8.11/deps/uv/include/uv-private/ngx-queue.h:
/Users/ck/.node-gyp/0.8.11/deps/uv/include/uv-private/ev.h:
/Users/ck/.node-gyp/0.8.11/deps/uv/include/uv-private/eio.h:
/Users/ck/.node-gyp/0.8.11/src/node_object_wrap.h:
/Users/ck/.node-gyp/0.8.11/src/ev-emul.h:
/Users/ck/.node-gyp/0.8.11/src/eio-emul.h:
/Users/ck/.node-gyp/0.8.11/src/node_version.h:
/Users/ck/.node-gyp/0.8.11/src/node_buffer.h:
../ext/bson.h:

Binary file not shown.

View File

Binary file not shown.

View File

@@ -0,0 +1,6 @@
# This file is generated by gyp; do not edit.
export builddir_name ?= build/./.
.PHONY: all
all:
$(MAKE) bson

Some files were not shown because too many files have changed in this diff Show More