Skip to content

Instantly share code, notes, and snippets.

@cmilfont
Created October 13, 2010 14:48
Show Gist options
  • Save cmilfont/624173 to your computer and use it in GitHub Desktop.
Save cmilfont/624173 to your computer and use it in GitHub Desktop.
/**
* Module dependencies.
*/
var express = require('express'),
connect = require('connect');
var app = module.exports = express.createServer();
var Mu = require('./vendor/mu');
//http://comments.gmane.org/gmane.comp.lang.javascript.nodejs/2378
// randomString returns a pseude-random ASCII string which contains at least the specified number of bits of entropy
// the return value is a string of length ⌈bits/6⌉ of characters from the base64 alphabet
function randomString(bits){var chars,rand,i,ret
chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
ret=''
// in v8, Math.random() yields 32 pseudo-random bits (in spidermonkey it gives 53)
while(bits > 0){
rand=Math.floor(Math.random()*0x100000000) // 32-bit integer
// base 64 means 6 bits per character, so we use the top 30 bits from rand to give 30/6=5 characters.
for(i=26; i>0 && bits>0; i-=6, bits-=6) ret+=chars[0x3F & rand >>> i]}
return ret
}
var uuid = function() {
return randomString(64);
}
// var tmpl = "Hello {{> part}}. Your name is: {{name}}!";
// var partials = {part: "World"};
// var compiled = Mu.compileText(tmpl, partials);
//
// compiled({name: "Chris"}).addListener('data', function (c) { sys.puts(c) });
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.use(connect.bodyDecoder());
app.use(connect.methodOverride());
app.use(connect.compiler({ src: __dirname + '/public', enable: ['less'] }));
app.use(app.router);
app.use(connect.staticProvider(__dirname + '/public'));
});
app.configure('development', function(){
app.use(connect.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(connect.errorHandler());
});
// Routes
app.get('/', function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
res.send('{"couchdb":"Welcome","version":"1.0.1"}');
});
app.get('/_config', function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
res.send(JSON.stringify({
httpd_design_handlers: { _info: '{couch_httpd_db, handle_design_info_req}'
, _list: '{couch_httpd_show, handle_view_list_req}'
, _rewrite: '{couch_httpd_rewrite, handle_rewrite_req}'
, _show: '{couch_httpd_show, handle_doc_show_req}'
, _update: '{couch_httpd_show, handle_doc_update_req}'
, _view: '{couch_httpd_view, handle_view_req}'
}
, uuids: { algorithm: 'sequential' }
, stats: { rate: '1000', samples: '[0, 60, 300, 900]' }
, httpd_global_handlers:
{ '/': '{couch_httpd_misc_handlers, handle_welcome_req, <<"Welcome">>}'
, _active_tasks: '{couch_httpd_misc_handlers, handle_task_status_req}'
, _all_dbs: '{couch_httpd_misc_handlers, handle_all_dbs_req}'
, _config: '{couch_httpd_misc_handlers, handle_config_req}'
, _log: '{couch_httpd_misc_handlers, handle_log_req}'
, _oauth: '{couch_httpd_oauth, handle_oauth_req}'
, _replicate: '{couch_httpd_misc_handlers, handle_replicate_req}'
, _restart: '{couch_httpd_misc_handlers, handle_restart_req}'
, _session: '{couch_httpd_auth, handle_session_req}'
, _stats: '{couch_httpd_stats_handlers, handle_stats_req}'
, _utils: '{couch_httpd_misc_handlers, handle_utils_dir_req, "/usr/local/Cellar/couchdb/1.0.1/share/couchdb/www"}'
, _uuids: '{couch_httpd_misc_handlers, handle_uuids_req}'
, 'favicon.ico': '{couch_httpd_misc_handlers, handle_favicon_req, "/usr/local/Cellar/couchdb/1.0.1/share/couchdb/www"}'
}
, attachments:
{ compressible_types: 'text/*, application/javascript, application/json, application/xml'
, compression_level: '8'
}
, query_server_config: { reduce_limit: 'true' }
, replicator:
{ max_http_pipeline_size: '10'
, max_http_sessions: '10'
}
, log:
{ file: '/usr/local/var/log/couchdb/couch.log'
, include_sasl: 'true'
, level: 'info'
}
, query_servers: { javascript: '/usr/local/Cellar/couchdb/1.0.1/bin/couchjs /usr/local/Cellar/couchdb/1.0.1/share/couchdb/server/main.js' }
, daemons:
{ auth_cache: '{couch_auth_cache, start_link, []}'
, db_update_notifier: '{couch_db_update_notifier_sup, start_link, []}'
, external_manager: '{couch_external_manager, start_link, []}'
, httpd: '{couch_httpd, start_link, []}'
, query_servers: '{couch_query_servers, start_link, []}'
, stats_aggregator: '{couch_stats_aggregator, start, []}'
, stats_collector: '{couch_stats_collector, start, []}'
, uuids: '{couch_uuids, start, []}'
, view_manager: '{couch_view, start_link, []}'
}
, httpd:
{ allow_jsonp: 'false'
, authentication_handlers: '{couch_httpd_oauth, oauth_authentication_handler}, {couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, default_authentication_handler}'
, bind_address: '127.0.0.1'
, default_handler: '{couch_httpd_db, handle_request}'
, max_connections: '2048'
, port: '5984'
, secure_rewrites: 'true'
, vhost_global_handlers: '_utils, _uuids, _session, _oauth, _users'
}
, httpd_db_handlers:
{ _changes: '{couch_httpd_db, handle_changes_req}'
, _compact: '{couch_httpd_db, handle_compact_req}'
, _design: '{couch_httpd_db, handle_design_req}'
, _temp_view: '{couch_httpd_view, handle_temp_view_req}'
, _view_cleanup: '{couch_httpd_db, handle_view_cleanup_req}'
}
, couch_httpd_auth:
{ auth_cache_size: '50'
, authentication_db: '_users'
, authentication_redirect: '/_utils/session.html'
, require_valid_user: 'false'
, timeout: '600'
}
, couchdb:
{ database_dir: '/usr/local/var/lib/couchdb'
, delayed_commits: 'true'
, max_attachment_chunk_size: '4294967296'
, max_dbs_open: '100'
, max_document_size: '4294967296'
, os_process_timeout: '5000'
, uri_file: '/usr/local/var/lib/couchdb/couch.uri'
, util_driver_dir: '/usr/local/Cellar/couchdb/1.0.1/lib/couchdb/erlang/lib/couch-1.0.1/priv/lib'
, view_index_dir: '/usr/local/var/lib/couchdb'
}
}));
});
app.get('/_config/query_servers', function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
res.send('{"javascript":"/usr/local/Cellar/couchdb/1.0.1/bin/couchjs /usr/local/Cellar/couchdb/1.0.1/share/couchdb/server/main.js"}');
});
app.get('/_config/native_query_servers', function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
res.send('{}');
});
app.get('/_stats', function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
res.send('{"couchdb":{"open_databases":{"description":"number of open databases","current":5.0,"sum":5.0,"mean":0.0,"stddev":0.021,"min":-2,"max":4},"auth_cache_hits":{"description":"number of authentication cache hits","current":null,"sum":null,"mean":null,"stddev":null,"min":null,"max":null},"auth_cache_misses":{"description":"number of authentication cache misses","current":null,"sum":null,"mean":null,"stddev":null,"min":null,"max":null},"database_reads":{"description":"number of times a document was read from a database","current":243.0,"sum":243.0,"mean":0.004,"stddev":0.345,"min":0,"max":66},"database_writes":{"description":"number of times a database was changed","current":195.0,"sum":195.0,"mean":0.003,"stddev":0.219,"min":0,"max":27},"request_time":{"description":"length of a request inside CouchDB without MochiWeb","current":6606.348,"sum":6606.348,"mean":157.294,"stddev":351.139,"min":1.0,"max":1858.0},"open_os_files":{"description":"number of file descriptors CouchDB has open","current":7.0,"sum":7.0,"mean":0.0,"stddev":0.04,"min":-3,"max":5}},"httpd":{"requests":{"description":"number of HTTP requests","current":565.0,"sum":565.0,"mean":0.008,"stddev":0.511,"min":0,"max":62},"bulk_requests":{"description":"number of bulk requests","current":10.0,"sum":10.0,"mean":0.0,"stddev":0.015,"min":0,"max":3},"view_reads":{"description":"number of view reads","current":54.0,"sum":54.0,"mean":0.001,"stddev":0.135,"min":0,"max":33},"clients_requesting_changes":{"description":"number of clients for continuous _changes","current":0,"sum":0,"mean":0.0,"stddev":0.027,"min":-5,"max":5},"temporary_view_reads":{"description":"number of temporary view reads","current":114.0,"sum":114.0,"mean":0.002,"stddev":0.216,"min":0,"max":33}},"httpd_request_methods":{"DELETE":{"description":"number of HTTP DELETE requests","current":28.0,"sum":28.0,"mean":0.0,"stddev":0.029,"min":0,"max":5},"HEAD":{"description":"number of HTTP HEAD requests","current":null,"sum":null,"mean":null,"stddev":null,"min":null,"max":null},"POST":{"description":"number of HTTP POST requests","current":183.0,"sum":183.0,"mean":0.003,"stddev":0.241,"min":0,"max":34},"PUT":{"description":"number of HTTP PUT requests","current":175.0,"sum":175.0,"mean":0.003,"stddev":0.206,"min":0,"max":27},"MOVE":{"description":"number of HTTP MOVE requests","current":null,"sum":null,"mean":null,"stddev":null,"min":null,"max":null},"GET":{"description":"number of HTTP GET requests","current":179.0,"sum":179.0,"mean":0.003,"stddev":0.22,"min":0,"max":36},"COPY":{"description":"number of HTTP COPY requests","current":null,"sum":null,"mean":null,"stddev":null,"min":null,"max":null}},"httpd_status_codes":{"400":{"description":"number of HTTP 400 Bad Request responses","current":29.0,"sum":29.0,"mean":0.0,"stddev":0.041,"min":0,"max":5},"201":{"description":"number of HTTP 201 Created responses","current":194.0,"sum":194.0,"mean":0.003,"stddev":0.214,"min":0,"max":27},"403":{"description":"number of HTTP 403 Forbidden responses","current":null,"sum":null,"mean":null,"stddev":null,"min":null,"max":null},"409":{"description":"number of HTTP 409 Conflict responses","current":2.0,"sum":2.0,"mean":0.0,"stddev":0.008,"min":0,"max":2},"200":{"description":"number of HTTP 200 OK responses","current":301.0,"sum":301.0,"mean":0.004,"stddev":0.318,"min":0,"max":35},"202":{"description":"number of HTTP 202 Accepted responses","current":4.0,"sum":4.0,"mean":0.0,"stddev":0.008,"min":0,"max":1},"404":{"description":"number of HTTP 404 Not Found responses","current":3.0,"sum":3.0,"mean":0.0,"stddev":0.009,"min":0,"max":2},"301":{"description":"number of HTTP 301 Moved Permanently responses","current":null,"sum":null,"mean":null,"stddev":null,"min":null,"max":null},"405":{"description":"number of HTTP 405 Method Not Allowed responses","current":null,"sum":null,"mean":null,"stddev":null,"min":null,"max":null},"500":{"description":"number of HTTP 500 Internal Server Error responses","current":12.0,"sum":12.0,"mean":0.0,"stddev":0.032,"min":0,"max":8},"401":{"description":"number of HTTP 401 Unauthorized responses","current":null,"sum":null,"mean":null,"stddev":null,"min":null,"max":null},"304":{"description":"number of HTTP 304 Not Modified responses","current":16.0,"sum":16.0,"mean":0.0,"stddev":0.033,"min":0,"max":7},"412":{"description":"number of HTTP 412 Precondition Failed responses","current":1.0,"sum":1.0,"mean":0.0,"stddev":0.004,"min":0,"max":1}}}');
});
app.get('/_active_tasks', function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
res.send('[]');
});
app.get('/_session', function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
res.send('{"ok":true,"userCtx":{"name":null,"roles":["_admin"]},"info":{"authentication_db":"_users","authentication_handlers":["oauth","cookie","default"],"authenticated":"default"}}');
});
app.get('/_uuids', function(req, res){
//?count=
var resp = {"uuids" : []};
for (var i = req.param("count") - 1; i >= 0; i--){
resp.uuids.push(uuid());
};
res.header("Content-Type", 'text/plain;charset=utf-8');
res.send(JSON.stringify(resp));
});
var dbs = {};
var dbsIndex = [];
var addDb = function(name) {
// console.log("----");
// console.log(name);
// console.log("----");
dbs[name] = {docs: [] };
dbs[name].indexed = dbsIndex.push(name) - 1;
}
//for test
// addDb("user");
app.get('/_all_dbs', function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var resp = [];
for (var i = dbsIndex.length - 1; i >= 0; i--){
if (dbsIndex[i]) {
resp.push(dbsIndex[i]);
}
};
res.send(JSON.stringify(resp));
});
app.put("/:database", function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var name = req.param("database");
if (!dbs[name]) {
addDb(name);
res.send(JSON.stringify({"ok" : true}), 201);
} else {
res.send('{"error":"not_found","reason":"no_db_file"}', 412);
}
});
app.del("/:database", function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var name = req.param("database");
if (!dbs[name]) {
res.send('{"error":"not_found","reason":"no_db_file"}', 404);
} else {
delete dbsIndex[dbs[name].indexed];
// dbs[name] = null;
delete dbs[name];
res.send(JSON.stringify({"ok" : true}));
}
});
app.get("/:database", function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var db = req.param("database");
if (!dbs[db]) {
res.send('{"error":"not_found","reason":"no_db_file"}', 404);
} else {
res.send('{"db_name":"'+db+'","doc_count":0,"doc_del_count":3,"update_seq":10,"purge_seq":0,"compact_running":false,"disk_size":8281,"instance_start_time":"1285991334297858","disk_format_version":5,"committed_update_seq":10}');
}
});
app.get("/:database/_changes", function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var db = req.param("database");
if (!dbs[db]) {
res.send('{"error":"not_found","reason":"no_db_file"}', 404);
} else {
res.send('{"results":[ {"seq":5,"id":"5735f9a0d32a4fb493b6fe8eef0063cf","changes":[{"rev":"3-c445f7f90c831107c3fcaef8248556df"}],"deleted":true}, {"seq":9,"id":"5e689317ae1d8aa9cf255365a867c8e7","changes":[{"rev":"3-c445f7f90c831107c3fcaef8248556df"}],"deleted":true}, {"seq":10,"id":"renato.elias","changes":[{"rev":"4-a5379906b0cc22bb4a0d1c66620b4801"}],"deleted":true}],"last_seq":10}');
}
});
app.post("/:database/_compact", function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var db = req.param("database");
if (!dbs[db]) {
res.send('{"error":"not_found","reason":"no_db_file"}', 404);
} else {
res.send(JSON.stringify({"ok" : true}));
}
});
app.get("/:database/_all_docs", function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var db = req.param("database");
if (!dbs[db]) {
res.send('{"error":"not_found","reason":"no_db_file"}', 404);
} else {
var rows = [];
var db = dbs[db].docs;
for(var k in db) {
if (db[k] != null) {
rows.push({"id" : db[k]._id , "key" : db[k]._id , "value" : {"rev" : db[k]._rev }});
}
}
res.send('{"total_rows": '+rows.length+' ,"offset":0,"rows":'+JSON.stringify(rows)+'}');
}
});
var addDoc = function(doc, db) {
if (!doc._id) {
doc._id = uuid();
}
doc._rev = "1-"+uuid();
return dbs[db].docs.push(doc);
}
var insertDoc = function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var db = req.param("database");
// console.log("----");
// console.log(dbs);
// console.log(db);
// console.log("----");
// console.log("----");
// console.log(req.url);
// console.log(req.originalUrl);
// console.log(req.params);
// console.log(req.body);
// console.log("----");
if (!dbs[db]) {
res.send('{"error":"not_found","reason":"no_db_file"}', 404);
} else {
if (req.param("id")) {
req.body._id = req.param("id");
}
var doc = addDoc(req.body , db);
res.send(JSON.stringify({"ok" : true , id : doc._id }));
}
};
app.put("/:database/:id", insertDoc) ;
app.post("/:database", insertDoc) ;
app.post("/:database/_compact/:id", function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var params = req.params;
var db = req.param("database");
if (!dbs[db]) {
res.send('{"error":"not_found","reason":"no_db_file"}', 404);
} else {
var id = "_design/"+req.param("id");
if (!dbs[db].docs[id]) {
res.send('{"error":"not_found","reason":"missing"}', 404);
} else {
res.send(JSON.stringify({"ok" : true }));
}
}
});
app.post("/:database/_bulk_docs", function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var db = req.param("database");
if (!dbs[db]) {
res.send('{"error":"not_found","reason":"no_db_file"}', 404);
} else {
var process = [];
var docs = req.body.docs;
for (var i=0; i < docs.length; i++) {
var row = addDoc(docs[i] , db);
process.push({"ok" : true , id : row._id });
};
res.send(JSON.stringify(process));
}
});
var map = function(calling, name) {
return dbs[name].docs.map(function(doc) {
var emit;
this.emit = function() {
emit = arguments;
}
console.log(calling.toString());
calling.call(this, doc);
return emit;
}).filter(function(element, index, array) {
//remove undefined elements
return element
});
}
var reduce = function(key, calling) {
return key.reduce(function(doc) {
var sum;
this.sum = function() {
return false;
}
return calling.call(this, doc._id, doc);
});
}
app.post("/:database/_temp_view", function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var db = req.param("database");
if (!dbs[db]) {
res.send('{"error":"not_found","reason":"no_db_file"}', 404);
} else {
console.log(req.param());
// var rows = map(req.param("map"), db);
rows = [];
// var db = dbs[db].docs;
// for(var k in db) {
// if (db[k] !== null && db[k]._id.substr(0,7) !== '_design') {
// rows.push({"id" : db[k]._id , "key" : db[k]._id , "value" : {"rev" : db[k]._rev }});
//
// }
// }
var resp = '{"total_rows": '+rows.length+' ,"offset":0,"rows":'+JSON.stringify(rows)+'}';
res.send(resp);
}
});
app.get("/:database/_design/:id/_info", function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var params = req.params;
var db = req.param("database");
if (!dbs[db]) {
res.send('{"error":"not_found","reason":"no_db_file"}', 404);
} else {
var id = "_design/"+req.param("id");
if (!dbs[db].docs[id]) {
res.send('{"error":"not_found","reason":"missing"}', 404);
} else {
res.send('{"name": "'+req.param("id")+'","view_index":{"signature":"73fe79b20ff06e341257fa78231ca87e","language":"javascript","disk_size":51,"updater_running":true,"compact_running":false,"waiting_commit":false,"waiting_clients":0,"update_seq":0,"purge_seq":0}}');
}
}
});
app.get("/:database/_design/:id/_view/:view", function(req, res , next){
res.header("Content-Type", 'text/plain;charset=utf-8');
var params = req.params;
var db = req.param("database");
if (!dbs[db]) {
next();
} else {
var id = "_design/"+req.param("id");
if (!dbs[db].docs[id]) {
next();
} else {
var rows = [];
var db = dbs[db].docs;
for(var k in db) {
if (db[k] !== null && db[k]._id.substr(0,7) !== '_design') {
rows.push({"id" : db[k]._id , "key" : db[k]._id , "value" : {"rev" : db[k]._rev }});
}
}
res.send('{"total_rows": '+rows.length+' ,"offset":0,"rows":'+JSON.stringify(rows)+'}');
}
}
});
app.del("/:database/:id", function(req, res){
res.header("Content-Type", 'text/plain;charset=utf-8');
var db = req.param("database");
if (!dbs[db]) {
res.send('{"error":"not_found","reason":"no_db_file"}', 404);
} else {
if (!dbs[db].docs[req.param("id")]) {
res.send('{"error":"not_found","reason":"missing"}', 404);
} else {
// dbs[db].docs[req.param("id")] = null;
delete dbs[db].docs[req.param("id")];
res.send(JSON.stringify({"ok" : true}));
}
}
//
});
app.get("/:database/*", function(req, res , next){
res.header("Content-Type", 'text/plain;charset=utf-8');
var params = req.params;
var db = req.param("database");
if (!dbs[db]) {
// res.send('{"error":"not_found","reason":"10no_db_file"}', 404);
next();
} else {
var id = req.params[0];
if (!dbs[db].docs[id]) {
next();
//res.send('{"error":"not_found","reason":"missing"}', 404);
} else {
res.send(JSON.stringify(dbs[db].docs[id]));
}
}
});
// res.send(404);
//any error: {"error":"illegal_database_name","reason":"Only lowercase characters (a-z), digits (0-9), and any of the characters _, $, (, ), +, -, and / are allowed. Must begin with a letter."}
// Only listen on $ node app.js
if (!module.parent) app.listen(3000);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment