diff options
author | John Christopher Anderson <jchris@apache.org> | 2009-06-14 18:45:49 +0000 |
---|---|---|
committer | John Christopher Anderson <jchris@apache.org> | 2009-06-14 18:45:49 +0000 |
commit | cd39ebe7d12d999324ff2cc9842567b34dc4d4c7 (patch) | |
tree | 00bde7d855ba9cd07c2e5d0463dfd32c4f0badcc /share/server | |
parent | 88fcbd2cdd14fedab900fbf3af3deb5fe15f4390 (diff) |
merge list-iterator branch to trunk. changes JavaScript _list API
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@784601 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'share/server')
-rw-r--r-- | share/server/loop.js | 25 | ||||
-rw-r--r-- | share/server/render.js | 183 | ||||
-rw-r--r-- | share/server/util.js | 5 |
3 files changed, 151 insertions, 62 deletions
diff --git a/share/server/loop.js b/share/server/loop.js index db6a9702..188692ba 100644 --- a/share/server/loop.js +++ b/share/server/loop.js @@ -21,6 +21,9 @@ try { sandbox.toJSON = toJSON; sandbox.respondWith = respondWith; sandbox.registerType = registerType; + sandbox.start = start; + sandbox.send = send; + sandbox.getRow = getRow; } catch (e) {} // Commands are in the form of json arrays: @@ -31,21 +34,19 @@ try { var line, cmd, cmdkey; var dispatch = { - "reset" : State.reset, - "add_fun" : State.addFun, - "map_doc" : Views.mapDoc, - "reduce" : Views.reduce, - "rereduce" : Views.rereduce, - "validate" : Validate.validate, - "show_doc" : Render.showDoc, - "list_begin" : Render.listBegin, - "list_row" : Render.listRow, - "list_tail" : Render.listTail + "reset" : State.reset, + "add_fun" : State.addFun, + "map_doc" : Views.mapDoc, + "reduce" : Views.reduce, + "rereduce" : Views.rereduce, + "validate" : Validate.validate, + "show" : Render.show, + "list" : Render.list }; while (line = eval(readline())) { - cmd = eval(line) - line_length = line.length + cmd = eval(line); + line_length = line.length; try { cmdkey = cmd.shift(); if (dispatch[cmdkey]) { diff --git a/share/server/render.js b/share/server/render.js index 13ef1322..99541eab 100644 --- a/share/server/render.js +++ b/share/server/render.js @@ -12,9 +12,10 @@ // mimeparse.js // http://code.google.com/p/mimeparse/ +// MIT Licensed http://www.opensource.org/licenses/mit-license.php // Code with comments: http://mimeparse.googlecode.com/svn/trunk/mimeparse.js // Tests: http://mimeparse.googlecode.com/svn/trunk/mimeparse-js-test.html -// Ported from version 0.1.2 +// Ported by Chris Anderson from version 0.1.2 var Mimeparse = (function() { function strip(string) { @@ -111,6 +112,8 @@ var Mimeparse = (function() { return publicMethods; })(); +var respCT; +var respTail; // this function provides a shortcut for managing responses by Accept header respondWith = function(req, responders) { var bestKey = null, accept = req.headers["Accept"]; @@ -127,11 +130,16 @@ respondWith = function(req, responders) { bestKey = req.query.format; } var rFunc = responders[bestKey || responders.fallback || "html"]; - if (rFunc) { - var resp = maybeWrapResponse(rFunc()); - resp["headers"] = resp["headers"] || {}; - resp["headers"]["Content-Type"] = bestMime; - respond(resp); + if (rFunc) { + if (isShow) { + var resp = maybeWrapResponse(rFunc()); + resp["headers"] = resp["headers"] || {}; + resp["headers"]["Content-Type"] = bestMime; + respond(["resp", resp]); + } else { + respCT = bestMime; + respTail = rFunc(); + } } else { throw({code:406, body:"Not Acceptable: "+accept}); } @@ -162,8 +170,6 @@ registerType("text", "text/plain", "txt"); registerType("html", "text/html"); registerType("xhtml", "application/xhtml+xml", "xhtml"); registerType("xml", "application/xml", "text/xml", "application/x-xml"); -// http://www.ietf.org/rfc/rfc4627.txt -registerType("json", "application/json", "text/x-json"); registerType("js", "text/javascript", "application/javascript", "application/x-javascript"); registerType("css", "text/css"); registerType("ics", "text/calendar"); @@ -171,57 +177,148 @@ registerType("csv", "text/csv"); registerType("rss", "application/rss+xml"); registerType("atom", "application/atom+xml"); registerType("yaml", "application/x-yaml", "text/yaml"); + // just like Rails registerType("multipart_form", "multipart/form-data"); registerType("url_encoded_form", "application/x-www-form-urlencoded"); +// http://www.ietf.org/rfc/rfc4627.txt +registerType("json", "application/json", "text/x-json"); + + + +// Start chunks +var startResp = {}; +function start(resp) { + startResp = resp || {}; +}; + +function sendStart(label) { + startResp = startResp || {}; + startResp["headers"] = startResp["headers"] || {}; + startResp["headers"]["Content-Type"] = startResp["headers"]["Content-Type"] || respCT; + + respond(["start", chunks, startResp]); + chunks = []; + startResp = {}; +} +// Send chunk +var chunks = []; +function send(chunk) { + chunks.push(chunk.toString()); +}; + +function blowChunks(label) { + respond([label||"chunks", chunks]); + chunks = []; +}; + +var gotRow = false, lastRow = false; +function getRow() { + if (lastRow) return null; + if (!gotRow) { + gotRow = true; + sendStart(); + } else { + blowChunks() + } + var line = readline(); + var json = eval(line); + if (json[0] == "list_end") { + lastRow = true + return null; + } + if (json[0] != "list_row") { + respond({ + error: "query_server_error", + reason: "not a row '" + json[0] + "'"}); + quit(); + } + return json[1]; +}; + +//// +//// Render dispatcher +//// +//// +//// +//// +var isShow = false; var Render = (function() { var row_info; + return { - showDoc : function(funSrc, doc, req) { + show : function(funSrc, doc, req) { + isShow = true; var formFun = compileFunction(funSrc); - runRenderFunction(formFun, [doc, req], funSrc); - }, - listBegin : function(head, req) { - row_info = { first_key: null, row_number: 0, prev_key: null }; - runRenderFunction(funs[0], [head, null, req, null], funsrc[0]); - }, - listRow : function(row, req) { - if (row_info.first_key == null) { - row_info.first_key = row.key; - } - runRenderFunction(funs[0], [null, row, req, row_info], funsrc[0], true); - row_info.prev_key = row.key; - row_info.row_number++; + runShowRenderFunction(formFun, [doc, req], funSrc, true); }, - listTail : function(req) { - runRenderFunction(funs[0], [null, null, req, row_info], funsrc[0]); + list : function(head, req) { + isShow = false; + runListRenderFunction(funs[0], [head, req], funsrc[0], false); } } })(); -function runRenderFunction(renderFun, args, funSrc, htmlErrors) { - responseSent = false; +function maybeWrapResponse(resp) { + var type = typeof resp; + if ((type == "string") || (type == "xml")) { + return {body:resp}; + } else { + return resp; + } +}; + +function runShowRenderFunction(renderFun, args, funSrc, htmlErrors) { try { var resp = renderFun.apply(null, args); - if (!responseSent) { - if (resp) { - respond(maybeWrapResponse(resp)); - } else { - respond({error:"render_error",reason:"undefined response from render function"}); - } + if (resp) { + respond(["resp", maybeWrapResponse(resp)]); + } else { + renderError("undefined response from render function"); } } catch(e) { - var logMessage = "function raised error: "+e.toString(); - log(logMessage); - // log("stacktrace: "+e.stack); - var errorMessage = htmlErrors ? htmlRenderError(e, funSrc) : logMessage; - respond({ - error:"render_error", - reason:errorMessage}); + respondError(e, funSrc, htmlErrors); } }; +function runListRenderFunction(renderFun, args, funSrc, htmlErrors) { + try { + gotRow = false; + lastRow = false; + respTail = ""; + if (renderFun.arity > 2) { + throw("the list API has changed for CouchDB 0.10, please upgrade your code"); + } + var resp = renderFun.apply(null, args); + if (!gotRow) { + getRow(); + } + if (typeof resp != "undefined") { + chunks.push(resp); + } else if (respTail) { + chunks.push(respTail); + } + blowChunks("end"); + } catch(e) { + respondError(e, funSrc, htmlErrors); + } +}; + +function renderError(m) { + respond({error : "render_error", reason : m}); +} + + +function respondError(e, funSrc, htmlErrors) { + var logMessage = "function raised error: "+e.toString(); + log(logMessage); + log("stacktrace: "+e.stack); + var errorMessage = htmlErrors ? htmlRenderError(e, funSrc) : logMessage; + respond({ + error:"render_error", + reason:errorMessage}); +} function escapeHTML(string) { return string.replace(/&/g, "&") @@ -241,11 +338,3 @@ function htmlRenderError(e, funSrc) { return {body:msg}; }; -function maybeWrapResponse(resp) { - var type = typeof resp; - if ((type == "string") || (type == "xml")) { - return {body:resp}; - } else { - return resp; - } -}; diff --git a/share/server/util.js b/share/server/util.js index 7faf2f0b..13b8a779 100644 --- a/share/server/util.js +++ b/share/server/util.js @@ -91,10 +91,8 @@ function recursivelySeal(obj) { } } -var responseSent; // prints the object as JSON, and rescues and logs any toJSON() related errors function respond(obj) { - responseSent = true; try { print(toJSON(obj)); } catch(e) { @@ -103,10 +101,11 @@ function respond(obj) { }; log = function(message) { + // return; if (typeof message == "undefined") { message = "Error: attempting to log message of 'undefined'."; } else if (typeof message != "string") { message = toJSON(message); } - print(toJSON({log: message})); + respond(["log", message]); }; |