1
0
Fork 0

added module in database

This commit is contained in:
Frank Celler 2012-09-18 15:07:57 +02:00
parent 88b72adea4
commit 2ce0c4336a
7 changed files with 268 additions and 31 deletions

View File

@ -1550,7 +1550,7 @@ HIDE_UNDOC_RELATIONS = YES
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
HAVE_DOT = YES
HAVE_DOT = NO
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
# allowed to run in parallel. When set to 0 (the default) doxygen will

View File

@ -1550,7 +1550,7 @@ HIDE_UNDOC_RELATIONS = YES
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
HAVE_DOT = YES
HAVE_DOT = NO
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
# allowed to run in parallel. When set to 0 (the default) doxygen will

View File

@ -347,6 +347,12 @@
///
/// <ul>
/// <li>@ref UserManualActions
/// <ul>
/// <li>@ref UserManualActionsIntro</li>
/// <li>@ref UserManualActionsHelloWorld</li>
/// <li>@ref UserManualActionsHelloJson</li>
/// <li>@ref UserManualActionsEcho</li>
/// </ul>
/// </li>
/// </ul>
////////////////////////////////////////////////////////////////////////////////
@ -418,7 +424,7 @@
/// The client API or browser sends a HTTP request to the ArangoDB server and
/// the server returns a HTTP response to the client. A HTTP requests consists
/// of a method, normally @LIT{GET} or @LIT{POST} when using a browser, and a
/// request path like "/hello/world". For a real Web server there are a zillion
/// request path like @LIT{/hello/world}. For a real Web server there are a zillion
/// of other thing to consider, we will ignore this for the moment. The HTTP
/// response contains a content type, describing how to interpret the returned
/// data, and the data itself.
@ -462,7 +468,7 @@
///
/// Now use the browser and access
///
/// @LIT{http://localhost:8529/hello/world"}
/// @LIT{http://localhost:8529/hello/world}
///
/// @section UserManualActionsHelloJson A Hello World Example for JSON
//////////////////////////////////////////////////////////////////////
@ -562,6 +568,79 @@
/// "options": { }
/// }
/// @endcode
///
/// Please note that
///
/// @code
/// arangosh> db._routing.save({
/// ........> path : "/hello/echo",
/// ........> callback: "org/arangodb/actions/echoRequest" });
/// @endcode
///
/// is a short-cut for
///
/// @code
/// arangosh> db._routing.save({
/// ........> path : "/hello/echo-long",
/// ........> callback: {
/// ........> type: "function",
/// ........> module: "org/arangodb/actions",
/// ........> function: "echoRequest" }});
/// @endcode
///
/// The verbose form allows you to pass options to the called function:
///
/// @code
/// arangosh> a = db._routing.firstExample({path : "/hello/echo-long"});
/// arangosh> a.callback.options = { option: "my option1" };
/// arangosh> db._replace(a, a);
/// @endcode
///
/// You should now see the options in the result.
///
/// @code
/// {
/// "request": {
/// "prefix": "/hello/echo-long",
/// ...
/// },
/// "options": {
/// "option": "my option1"
/// }
/// }
/// @endcode
///
/// @section UserManualActionsDYO Define Your Own Callback
//////////////////////////////////////////////////////////
///
/// You can define your own callbacks by adding a new module to ArangoDB. In
/// order to avoid name clashes modules should be named
///
/// @LIT{tld/domain/modulename}
///
/// where @LIT{domain.tld} is your domain name. For development you can store
/// your code in files in the filesystem, see @ref MODULES_PATH and @MODULES.
///
/// However, when you are finished with the development you can rollout the
/// module code by storing it inside the @LIT{_modules} collection.
///
/// Create a file @LIT{hello-world.js} with the following content:
///
/// @code
/// var actions = require("org/arangodb/actions");
///
/// exports.helloWorld = function (req, res) {
/// res.contentType = "text/html";
/// res.responseCode = actions.HTTP_OK;
/// res.body = "<html><body>Hello World!</body></html>";
/// };
/// @endcode
///
/// Load this file as new module @LIT{de.triagens.hello-world} into the database
///
/// @code
/// arangosh> require("internal").defineModule("de/triagens/hello-world", "hello-world.js");
/// @endcode
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------

View File

@ -52,15 +52,9 @@ function Routing (req, res) {
console.log("request = %s", JSON.stringify(req));
callbacks = actions.routing(req.requestType, req.suffix);
for (i = 0; i < callbacks.length; ++i) {
console.log("callback %d = %s", i, callbacks[i]);
}
current = 0;
next = function () {
var options = {};
var callback;
if (callbacks.length <= current) {
@ -70,14 +64,13 @@ function Routing (req, res) {
callback = callbacks[current++];
console.error("trying callback #%d / %d: %s # %s", current, callbacks.length, typeof callback, callback);
if (callback == null) {
actions.resultNotImplemented(req, res, "not implemented '" + req.suffix.join("/") + "'");
actions.resultNotImplemented(req, res,
"not implemented '" + req.suffix.join("/") + "'");
}
else {
req.prefix = callback.path;
callback.func(req, res, next, options);
callback.func(req, res, next, callback.options);
}
}

View File

@ -11,7 +11,8 @@ static string JS_common_bootstrap_modules =
" SYS_LOAD, SYS_LOG, SYS_LOG_LEVEL, SYS_OUTPUT,\n"
" SYS_PROCESS_STAT, SYS_READ, SYS_SPRINTF, SYS_TIME,\n"
" SYS_START_PAGER, SYS_STOP_PAGER, ARANGO_QUIET, MODULES_PATH,\n"
" COLOR_OUTPUT, COLOR_OUTPUT_RESET, COLOR_BRIGHT, PRETTY_PRINT */\n"
" COLOR_OUTPUT, COLOR_OUTPUT_RESET, COLOR_BRIGHT, PRETTY_PRINT,\n"
" SYS_SHA256, SYS_WAIT, SYS_GETLINE */\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief JavaScript server functions\n"
@ -180,6 +181,20 @@ static string JS_common_bootstrap_modules =
"};\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief unloads module\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"Module.prototype.unloadAll = function () {\n"
" var path;\n"
"\n"
" for (path in ModuleCache) {\n"
" if (ModuleCache.hasOwnProperty(path)) {\n"
" this.unload(path);\n"
" }\n"
" }\n"
"};\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief top-level module\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
@ -226,7 +241,7 @@ static string JS_common_bootstrap_modules =
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief fs module\n"
"/// @brief file-system module\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"ModuleCache[\"/fs\"] = new Module(\"/fs\");\n"
@ -321,18 +336,19 @@ static string JS_common_bootstrap_modules =
" }\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief reads a file\n"
"/// @brief reads a file from the module path or the database\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
" internal.readFile = function (path) {\n"
" var i;\n"
" var mc;\n"
" var n;\n"
"\n"
" // try to load the file\n"
" var paths = internal.MODULES_PATH;\n"
"\n"
" for (i = 0; i < paths.length; ++i) {\n"
" var p = paths[i];\n"
" var n;\n"
"\n"
" if (p === \"\") {\n"
" n = \".\" + path + \".js\";\n"
@ -342,7 +358,18 @@ static string JS_common_bootstrap_modules =
" }\n"
"\n"
" if (fs.exists(n)) {\n"
" return { path : n, content : SYS_READ(n) };\n"
" return { path : n, content : internal.read(n) };\n"
" }\n"
" }\n"
"\n"
" // try to load the module from the database\n"
" mc = internal.db._collection(\"_modules\");\n"
"\n"
" if (mc !== null) {\n"
" n = mc.firstExample({ path: path });\n"
"\n"
" if (n !== null) {\n"
" return { path : \"_collection/\" + path, content : n.module };\n"
" }\n"
" }\n"
"\n"
@ -353,7 +380,7 @@ static string JS_common_bootstrap_modules =
" };\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief loads a file\n"
"/// @brief loads a file from the file-system\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
" internal.loadFile = function (path) {\n"
@ -385,6 +412,35 @@ static string JS_common_bootstrap_modules =
" };\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief defines a module\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
" internal.defineModule = function (path, file) {\n"
" var content;\n"
" var m;\n"
" var mc;\n"
"\n"
" content = internal.read(file);\n"
"\n"
" mc = internal.db._collection(\"_modules\");\n"
"\n"
" if (mc === null) {\n"
" throw \"you need to upgrade your database using 'arango-upgrade'\";\n"
" }\n"
"\n"
" path = module.normalise(path);\n"
" m = mc.firstExample({ path: path });\n"
"\n"
" if (m === null) {\n"
" mc.save({ path: path, module: content });\n"
" }\n"
" else {\n"
" m.content = content;\n"
" mc.replace(m, m);\n"
" }\n"
" };\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @}\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
@ -534,6 +590,10 @@ static string JS_common_bootstrap_modules =
"\n"
"}());\n"
"\n"
"// -----------------------------------------------------------------------------\n"
"// --SECTION-- END-OF-FILE\n"
"// -----------------------------------------------------------------------------\n"
"\n"
"// Local Variables:\n"
"// mode: outline-minor\n"
"// outline-regexp: \"^\\\\(/// @brief\\\\|/// @addtogroup\\\\|// --SECTION--\\\\|/// @page\\\\|/// @}\\\\)\"\n"

View File

@ -10,7 +10,8 @@
SYS_LOAD, SYS_LOG, SYS_LOG_LEVEL, SYS_OUTPUT,
SYS_PROCESS_STAT, SYS_READ, SYS_SPRINTF, SYS_TIME,
SYS_START_PAGER, SYS_STOP_PAGER, ARANGO_QUIET, MODULES_PATH,
COLOR_OUTPUT, COLOR_OUTPUT_RESET, COLOR_BRIGHT, PRETTY_PRINT */
COLOR_OUTPUT, COLOR_OUTPUT_RESET, COLOR_BRIGHT, PRETTY_PRINT,
SYS_SHA256, SYS_WAIT, SYS_GETLINE */
////////////////////////////////////////////////////////////////////////////////
/// @brief JavaScript server functions
@ -178,6 +179,20 @@ Module.prototype.unload = function (path) {
delete ModuleCache[norm];
};
////////////////////////////////////////////////////////////////////////////////
/// @brief unloads module
////////////////////////////////////////////////////////////////////////////////
Module.prototype.unloadAll = function () {
var path;
for (path in ModuleCache) {
if (ModuleCache.hasOwnProperty(path)) {
this.unload(path);
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief top-level module
////////////////////////////////////////////////////////////////////////////////
@ -225,7 +240,7 @@ function require (path) {
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief fs module
/// @brief file-system module
////////////////////////////////////////////////////////////////////////////////
ModuleCache["/fs"] = new Module("/fs");
@ -320,18 +335,19 @@ ModuleCache["/internal"] = new Module("/internal");
}
////////////////////////////////////////////////////////////////////////////////
/// @brief reads a file
/// @brief reads a file from the module path or the database
////////////////////////////////////////////////////////////////////////////////
internal.readFile = function (path) {
var i;
var mc;
var n;
// try to load the file
var paths = internal.MODULES_PATH;
for (i = 0; i < paths.length; ++i) {
var p = paths[i];
var n;
if (p === "") {
n = "." + path + ".js";
@ -341,7 +357,18 @@ ModuleCache["/internal"] = new Module("/internal");
}
if (fs.exists(n)) {
return { path : n, content : SYS_READ(n) };
return { path : n, content : internal.read(n) };
}
}
// try to load the module from the database
mc = internal.db._collection("_modules");
if (mc !== null) {
n = mc.firstExample({ path: path });
if (n !== null) {
return { path : "_collection/" + path, content : n.module };
}
}
@ -352,7 +379,7 @@ ModuleCache["/internal"] = new Module("/internal");
};
////////////////////////////////////////////////////////////////////////////////
/// @brief loads a file
/// @brief loads a file from the file-system
////////////////////////////////////////////////////////////////////////////////
internal.loadFile = function (path) {
@ -383,6 +410,35 @@ ModuleCache["/internal"] = new Module("/internal");
+ internal.MODULES_PATH + "'";
};
////////////////////////////////////////////////////////////////////////////////
/// @brief defines a module
////////////////////////////////////////////////////////////////////////////////
internal.defineModule = function (path, file) {
var content;
var m;
var mc;
content = internal.read(file);
mc = internal.db._collection("_modules");
if (mc === null) {
throw "you need to upgrade your database using 'arango-upgrade'";
}
path = module.normalise(path);
m = mc.firstExample({ path: path });
if (m === null) {
mc.save({ path: path, module: content });
}
else {
m.content = content;
mc.replace(m, m);
}
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
@ -533,6 +589,10 @@ ModuleCache["/console"] = new Module("/console");
}());
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"

View File

@ -92,6 +92,33 @@ function LookupCallbackString (callback) {
return undefined;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief looks up a callback for a function
////////////////////////////////////////////////////////////////////////////////
function LookupCallbackFunction (callback) {
var module;
var fn;
try {
module = require(callback.module);
}
catch (err) {
console.error("cannot load callback '%s' from module '%s': %s",
fn, callback.module, "" + err);
return undefined;
}
fn = callback.function;
if (fn in module) {
return module[fn];
}
console.error("callback '%s' is not defined in module '%s'", fn, module);
return undefined;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief looks up a callback for static data
////////////////////////////////////////////////////////////////////////////////
@ -124,6 +151,9 @@ function LookupCallback (callback) {
if (type === "static") {
return LookupCallbackStatic(callback);
}
else if (type === "function") {
return LookupCallbackFunction(callback);
}
else {
console.error("unknown callback type '%s'", type);
return undefined;
@ -431,13 +461,20 @@ function ReloadRouting () {
var cb = LookupCallback(callback[i]);
if (cb === undefined) {
console.error("route '%s' contains invalid callback '%s'", route._id, JSON.stringify(callback[i]));
console.error("route '%s' contains invalid callback '%s'",
route._id, JSON.stringify(callback[i]));
}
else if (typeof cb !== "function") {
console.error("route '%s' contains non-function callback '%s'", route._id, JSON.stringify(callback[i]));
console.error("route '%s' contains non-function callback '%s'",
route._id, JSON.stringify(callback[i]));
}
else {
tmp.push(cb);
var result = {
func: cb,
options: callback[i].options || {}
};
tmp.push(result);
}
}
@ -588,7 +625,11 @@ function Routing (method, path) {
var callback = td.callback;
for (j = 0; j < callback.length; ++j) {
result.push({ func : callback[j], path : td.path });
result.push({
func: callback[j].func,
options: callback[j].options,
path: td.path
});
}
}
@ -597,7 +638,11 @@ function Routing (method, path) {
var callback = bu.callback;
for (j = 0; j < callback.length; ++j) {
result.push({ func : callback[j], path : bu.path });
result.push({
func: callback[j].func,
options: callback[j].options,
path: bu.path
});
}
}