angoose
Version:
Angoose is a Remote Method Invocation module that comes with built-in mongoose/angular support. Now you can call server side module in browser just like you're in the server side!
667 lines (558 loc) • 39.9 kB
HTML
<html>
<head>
<title>angoose.js</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
<link rel="stylesheet" media="all" href="docco.css" />
</head>
<body>
<div id="container">
<div id="background"></div>
<ul id="jump_to">
<li>
<a class="large" href="javascript:void(0);">Jump To …</a>
<a class="small" href="javascript:void(0);">+</a>
<div id="jump_wrapper">
<div id="jump_page">
<a class="source" href="Context.html">
Context.js
</a>
<a class="source" href="Model.html">
Model.js
</a>
<a class="source" href="Principal.html">
Principal.js
</a>
<a class="source" href="Remotable.html">
Remotable.js
</a>
<a class="source" href="Schema.html">
Schema.js
</a>
<a class="source" href="Service.html">
Service.js
</a>
<a class="source" href="angoose.html">
angoose.js
</a>
</div>
</li>
</ul>
<ul class="sections">
<li id="title">
<div class="annotation">
<h1>angoose.js</h1>
</div>
</li>
<li id="section-1">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-1">¶</a>
</div>
<p>Angoose main module</p>
<pre><code> var angoose = require("angoose");
angoose.init(expressApp, { })</code></pre>
</div>
<div class="content"><div class='highlight'><pre><span class="keyword">var</span> path= require(<span class="string">"path"</span>);
<span class="keyword">var</span> Q = require(<span class="string">"q"</span>);
<span class="keyword">var</span> fs = require(<span class="string">"fs"</span>);
<span class="keyword">var</span> logging = require(<span class="string">"log4js"</span>);
<span class="keyword">var</span> _ =require(<span class="string">"underscore"</span>);
<span class="keyword">var</span> storageFactory = require(<span class="string">'continuation-local-storage'</span>);
<span class="keyword">var</span> schemaUtil = require(<span class="string">"./Schema"</span>);
<span class="keyword">var</span> pjson = require(<span class="string">'../package.json'</span>);
<span class="keyword">var</span> DEFAULT_OPTIONS = {
urlPrefix:<span class="string">'/angoose'</span>,
clientFile: path.resolve( require(<span class="string">"os"</span>).tmpdir(), <span class="string">'angoose-client-generated.js'</span>),
modelDir: <span class="string">'./models'</span>,
serviceDir: <span class="string">'./services'</span>,
mongo_opts: <span class="string">'localhost:27017/test'</span>
}
<span class="comment">/** Variables */</span>
<span class="keyword">var</span> options = DEFAULT_OPTIONS;
<span class="keyword">var</span> logger = logging.getLogger(<span class="string">'angoose'</span>);
<span class="keyword">var</span> beans = {}; <span class="comment">/** this holds all Angoose classes*/</span>
<span class="keyword">var</span> angoose = {};
logger.debug(<span class="string">"====== Bootstraping Angoose"</span>, pjson.version);
<span class="comment">/** statics */</span>
angoose.Remotable = require(<span class="string">"./Remotable"</span>);
angoose.Principal = require(<span class="string">"./Principal"</span>);
angoose.Context = require(<span class="string">"./Context"</span>);
angoose.Model = require(<span class="string">"./Model"</span>);
angoose.Service = require(<span class="string">"./Service"</span>);</pre></div></div>
</li>
<li id="section-2">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-2">¶</a>
</div>
<h3 id="api-references">API References</h3>
<p><strong> init(app, options) </strong></p>
<p>Initialize Angoose. This function should be called in the express app</p>
<ul>
<li>@app: Express app, for now</li>
<li>@options: Angoose settings:<ul>
<li>modelDir, optional, default to ./models</li>
<li>serviceDir, optional, default to ./services</li>
<li>urlPrefix, optional, default to /angoose</li>
<li>mongo_opts, optional. Provide this if you want Angoose to make the connection </li>
</ul>
</li>
</ul>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">init</span><span class="params">(app, conf)</span> {</span>
<span class="comment">/**@todo: middleware*/</span>
<span class="comment">/** overrite default configurations */</span>
_.extend(options, conf );
logger.debug(<span class="string">"Initializing Angoose "</span>, options);
<span class="comment">/** connect to Mongo if necessary */</span>
connectMongo(options);
<span class="comment">/** pre-load models/services from directories */</span>
harvestBeans(options);
<span class="comment">/** build client side schemas */</span>
generateClient();
<span class="comment">/** configure the routes for handling RMI and client loading*/</span>
configureRoutes(app, options);
}</pre></div></div>
</li>
<li id="section-3">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-3">¶</a>
</div>
<p><strong> getClass(name) </strong></p>
<p>Get the model or service class so you can instantiate it or call methods on them.</p>
<p>The return value is either a <a href="Model.html">Model</a> class or <a href="Service.html">Service</a> class</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">getClass</span><span class="params">(name)</span>{</span>
<span class="keyword">if</span>(!beans)
harvestBeans(options);
<span class="keyword">if</span>(!beans[name]) <span class="keyword">throw</span> <span class="string">"Class '"</span>+ name+<span class="string">"' is not found. Check log to see if class is loaded successfully "</span>
<span class="keyword">return</span> beans[name];
}</pre></div></div>
</li>
<li id="section-4">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-4">¶</a>
</div>
<p><strong> getContext() </strong></p>
<p>Returns the current execution context. </p>
<p>This methods returns a Context object which allows you to get a reference to the current request object
and/or login user's Principal object. If the callee isn't inside Angoose execution context, an error will
be thrown. See <a href="Context.html">Context</a> for more.</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">getContext</span><span class="params">()</span>{</span>
<span class="keyword">var</span> storage = storageFactory.getNamespace(<span class="string">'angoose'</span>);
<span class="keyword">var</span> ctx = storage.get(<span class="string">"context"</span>);
<span class="keyword">if</span>(!ctx) <span class="keyword">throw</span> <span class="string">"Context is not available. This may happen if the execution was not orginated by Angoose"</span>
<span class="keyword">return</span> ctx;
}</pre></div></div>
</li>
<li id="section-5">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-5">¶</a>
</div>
<p><strong> defer() </strong></p>
<p>Convenience wrapper for <code>Q.defer()</code>, returns a deferred object</p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">defer</span><span class="params">()</span>{</span>
<span class="keyword">return</span> Q.defer();
}</pre></div></div>
</li>
<li id="section-6">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-6">¶</a>
</div>
<p><strong> registerClass(className, claz) </strong></p>
<p>Register a Remotable class with Angoose. Used internally</p>
<p>Parameters:</p>
<ul>
<li>className: name to register the class under</li>
<li>claz: the class to register, must be Model or Service</li>
</ul>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">registerClass</span><span class="params">(className, claz)</span>{</span>
<span class="keyword">if</span>(beans[className]){
logger.warn(<span class="string">"Overriding existing bean: "</span>, className);
}
<span class="keyword">if</span>(claz._angoosemeta && (claz._angoosemeta.baseClass == <span class="string">'Service'</span> || claz._angoosemeta.baseClass == <span class="string">'Model'</span>) ){
beans[className] = claz;
logger.info(<span class="string">"===== Registered "</span>, claz._angoosemeta.baseClass, className);
}
<span class="keyword">else</span>{
<span class="keyword">throw</span> <span class="string">"Invalid class: must be a Model or Service class: "</span> + claz;
}
}
<span class="function"><span class="keyword">function</span> <span class="title">configureRoutes</span><span class="params">(app, options)</span>{</span>
<span class="keyword">if</span>(!app){
logger.warn(<span class="string">"app not provided, RMI functionality is disabled"</span>);
<span class="keyword">return</span>;
}
<span class="comment">/** this is the main RMI endpoint */</span>
app.post(options.urlPrefix+<span class="string">"/rmi/:model/:method"</span>, rmiAccept);
<span class="comment">/** @todo: use static serving to enable cache //app.get("/angoose/AngooseClient.js", express.static(options.clientFile)); */</span>
app.get(options.urlPrefix+<span class="string">"/angoose-client.js"</span>, <span class="function"><span class="keyword">function</span><span class="params">(req, res)</span>{</span>
logger.debug(<span class="string">"Handling AngooseClinet.js load request"</span>);
<span class="keyword">var</span> filename = options.clientFile ;
<span class="keyword">var</span> content = fs.readFileSync(filename , <span class="string">'ascii'</span>);
res.set(<span class="string">'Content-Type'</span>, <span class="string">'application/javascript'</span>);
res.send(<span class="number">200</span>, content );
});
}
<span class="function"><span class="keyword">function</span> <span class="title">decode</span><span class="params">(obj)</span>{</span>
<span class="comment">/** due to Angular HTTP library's stupidity, keys starting with $ are ignored. hence _mongo_$ to work around this*/</span>
<span class="keyword">if</span>(!obj || <span class="keyword">typeof</span> obj != <span class="string">'object'</span>) <span class="keyword">return</span> obj;
<span class="keyword">if</span>(Array.isArray(obj)){
<span class="keyword">for</span>(<span class="keyword">var</span> i=<span class="number">0</span>;i<obj.length;i++){
obj[i] = decode(obj[i]);
};
}
<span class="keyword">else</span>{
Object.keys(obj).forEach(<span class="function"><span class="keyword">function</span><span class="params">(key)</span>{</span>
<span class="keyword">var</span> val = decode(obj[key]);
<span class="keyword">if</span>(key.indexOf(<span class="string">'_mongo_$'</span>)==<span class="number">0</span>){
<span class="keyword">delete</span> obj[key];
key = key.substring(<span class="number">7</span>)
}
obj[key] = val;
})
}
<span class="keyword">return</span> obj;
}
<span class="function"><span class="keyword">function</span> <span class="title">getValueType</span><span class="params">(obj)</span>{</span>
<span class="keyword">if</span>(!obj || <span class="keyword">typeof</span>(obj) == <span class="string">'string'</span>) <span class="keyword">return</span> <span class="string">'string'</span>;
<span class="keyword">if</span>( obj.schema && obj.schema.paths && obj.schema.methods ) <span class="keyword">return</span> <span class="string">'model'</span>;
<span class="keyword">if</span>( obj.length ){
<span class="keyword">for</span>(<span class="keyword">var</span> i =<span class="number">0</span>; obj && obj.length>i; i++){
<span class="keyword">var</span> retval = getValueType(obj[i]);
<span class="keyword">if</span>(retval != <span class="string">'model'</span>) <span class="keyword">return</span> <span class="string">'object'</span>
}
<span class="keyword">return</span> <span class="string">'models'</span>;
}
<span class="keyword">return</span> <span class="string">'object'</span>;
}
<span class="function"><span class="keyword">function</span> <span class="title">formatError</span> <span class="params">(ex, seqnumber)</span>{</span>
logger.debug(<span class="string">"====== END RMI with Error #"</span>, seqnumber, ex);
<span class="keyword">return</span> {success:<span class="literal">false</span>, exception:ex, seqnumber: seqnumber };
}
<span class="function"><span class="keyword">function</span> <span class="title">injectDependencies</span><span class="params">(func, args, ctx, callback )</span>{</span>
<span class="keyword">var</span> declaredArguments = schemaUtil.parseDeclaredArguments(func);
declaredArguments = declaredArguments.replace(<span class="regexp">/\s+/g</span>, <span class="string">""</span>).split(<span class="string">","</span>);
logger.trace(<span class="string">"injectDependencies() declaredArguments: "</span>, declaredArguments, <span class="string">"provided args:"</span>, args);
<span class="keyword">var</span> useCallback = <span class="literal">false</span>;
<span class="keyword">for</span>(<span class="keyword">var</span> i=<span class="number">0</span>;i<declaredArguments.length;i++){
<span class="comment">/** if client did not provide enough number of arguments, we fill it with null*/</span>
<span class="keyword">if</span>(<span class="keyword">typeof</span>( args[i]) == <span class="string">'undefined'</span>)
args[i] = <span class="literal">undefined</span>;
<span class="keyword">else</span>
<span class="keyword">continue</span>;
<span class="keyword">switch</span>(declaredArguments[i]){
<span class="keyword">case</span> <span class="string">'$callback'</span>:
logger.debug(<span class="string">"Injecting callback handler"</span>);
args[i] = callback;
useCallback = <span class="literal">true</span>;
<span class="keyword">break</span>;
<span class="keyword">case</span> <span class="string">'$context'</span>:
logger.debug(<span class="string">"Injecting context"</span>);
args[i] = ctx;
<span class="keyword">break</span>;
<span class="keyword">default</span>:
<span class="keyword">break</span>;
}
}
<span class="keyword">return</span> useCallback;
}
<span class="function"><span class="keyword">function</span> <span class="title">rmiAccept</span><span class="params">(req,res)</span>{</span>
<span class="keyword">var</span> invocation = decode(req.body);
invocation.method = req.params.method; <span class="comment">/** method must be part of the path for routes permission etc */</span>
<span class="comment">/** setting execution context */</span>
<span class="keyword">var</span> ctx = <span class="keyword">new</span> angoose.Context({request:req, response:res, session:req.session});
<span class="keyword">var</span> excutionStorage = storageFactory.createNamespace(<span class="string">"angoose"</span>);
excutionStorage.run(<span class="function"><span class="keyword">function</span><span class="params">()</span>{</span>
logger.debug(<span class="string">"Setting execution context"</span>);
<span class="keyword">var</span> sent = <span class="literal">false</span>;
excutionStorage.set(<span class="string">"context"</span>, ctx);
<span class="keyword">try</span> {
processInvocation(invocation, ctx, <span class="function"><span class="keyword">function</span><span class="params">(ex, data)</span>{</span>
<span class="keyword">if</span>(ex)
data = data || formatError({message:ex.toString(), value:ex, code:<span class="number">500</span>}, invocation.seqnumber ) ;
res.send(<span class="number">200</span>, data);
sent = <span class="literal">true</span>;
});
}
<span class="keyword">catch</span>(err){
res.send(<span class="number">200</span>, formatError( {message: err.toString(), value:err, code:<span class="number">500</span> }, invocation.seqnumber ));
sent = <span class="literal">true</span>;
}
<span class="comment">/** catch the strayed handling, returns error in 5 seconds if response not sent */</span>
setTimeout(<span class="function"><span class="keyword">function</span><span class="params">()</span>{</span>
<span class="keyword">if</span>(sent) <span class="keyword">return</span>;
<span class="keyword">var</span> msg =<span class="string">"Timeout occurred when processing call "</span>+invocation.clazz +<span class="string">"."</span> + invocation.method;
logger.error(msg, invocation.seqnumber);
res.send(<span class="number">200</span>, formatError( {message: msg, value: msg, code:<span class="number">500</span> }, invocation.seqnumber ));
}, options.request_timeout || <span class="number">5000</span>);
});<span class="comment">/** end context closure */</span>
}
<span class="function"><span class="keyword">function</span> <span class="title">processInvocation</span><span class="params">(invocation, ctx, sendResponse)</span>{</span>
<span class="keyword">var</span> modelName = invocation.clazz;
<span class="keyword">var</span> method = invocation.method;
<span class="keyword">var</span> seqnum = invocation.seqnumber;
logger.debug(<span class="string">"====== BEGIN RMI #"</span>, seqnum, modelName, invocation );
<span class="keyword">var</span> callbackDeferred= Q.defer();
<span class="keyword">var</span> useCallback = <span class="literal">false</span>;
<span class="function"><span class="keyword">function</span> <span class="title">callbackHandler</span><span class="params">(err, result)</span>{</span>
<span class="comment">/** converting to Q promise */</span>
logger.trace(<span class="string">"In callback handler #"</span>+seqnum, err, result);
<span class="keyword">if</span>(err) callbackDeferred.reject(err);
<span class="keyword">else</span> callbackDeferred.resolve(result);
}
<span class="keyword">var</span> args = _.map(invocation.args || [], <span class="function"><span class="keyword">function</span><span class="params">(item)</span>{</span>
<span class="keyword">if</span>(item === <span class="string">"$callback"</span>){
useCallback = <span class="literal">true</span>;
<span class="keyword">return</span> callbackHandler;
}
<span class="keyword">return</span> item;
});
<span class="keyword">var</span> modelClass = getClass(modelName);
<span class="keyword">var</span> modelError = <span class="literal">null</span>;
prepareTarget(invocation, <span class="function"><span class="keyword">function</span><span class="params">(target)</span>{</span>
<span class="keyword">if</span>(<span class="keyword">typeof</span>(target) == <span class="string">'string'</span>) <span class="comment">/** error */</span>
<span class="keyword">return</span> sendResponse( formatError( {message: err.toString(), value:err, code:<span class="number">500</span> }, seqnum ) );
invokeMethod(target);
})
<span class="function"><span class="keyword">function</span> <span class="title">invokeMethod</span><span class="params">(target)</span>{</span>
<span class="keyword">try</span>{
useCallback = useCallback || injectDependencies(target[method], args, ctx, callbackHandler);
logger.trace(<span class="string">"invoking method "</span>, method.toUpperCase() , <span class="string">" with arguments"</span>, args, <span class="string">" on target "</span>, target)
<span class="keyword">var</span> ret = target[method].apply(target, args);
<span class="keyword">if</span>(ret && ret.exec){ <span class="comment">// mongoose promise</span>
logger.debug(<span class="string">"Return value is mongoose query, call exec()"</span> );
<span class="keyword">var</span> deferred = Q.defer();
ret.exec(<span class="function"><span class="keyword">function</span><span class="params">(err, data)</span>{</span>
<span class="keyword">if</span>(err){
logger.error(<span class="string">"error exuecuting Model method"</span>, err);
<span class="keyword">return</span> deferred.reject(err);
}
logger.debug(<span class="string">"Model method res"</span>, data)
deferred.resolve( data);
});
ret = deferred.promise;
}
<span class="keyword">else</span> <span class="keyword">if</span>(useCallback){
<span class="comment">/** method requested callback handler*/</span>
ret = callbackDeferred.promise;
}
<span class="keyword">else</span> {
<span class="comment">/** if method returns data directly or returned undefined */</span>
ret = Q(ret);
}
<span class="function"><span class="keyword">function</span> <span class="title">checkForModelError</span><span class="params">(result, target )</span>{</span>
<span class="keyword">var</span> err = ( target && target.errors) || (result && result.errors);
<span class="keyword">if</span>(err)
{
<span class="keyword">var</span> ex = { value: err, code:<span class="number">500</span>, message:<span class="string">""</span>};
Object.keys(err).forEach(<span class="function"><span class="keyword">function</span> <span class="params">(errItem)</span> {</span>
ex.message += ex.message?<span class="string">";"</span>:<span class="string">""</span>;
ex.message += err[errItem].message;
})
ex.message = ex.message || err.toString();
<span class="keyword">return</span> ex;
}
}
ret.done(<span class="function"><span class="keyword">function</span><span class="params">(result)</span>{</span>
<span class="keyword">var</span> ex = checkForModelError(result, (invocation.isStaitc?<span class="literal">null</span>:target) );
<span class="keyword">if</span>(ex) <span class="keyword">return</span> sendResponse ( ex );
<span class="keyword">var</span> valueType = getValueType(result); <span class="comment">/** model, models, object, string*/</span>
<span class="keyword">var</span> retdata = { success:<span class="literal">true</span>,
exception:<span class="literal">null</span>,
retval:result,
datatype: valueType,
seqnumber:seqnum
};
<span class="keyword">if</span>( !invocation.static && (! _.isEqual(target.toJSON(), invocation.target)))
{
<span class="comment">/** return the instance data if it has changed */</span>
retdata.instance = target.toJSON();
}
sendResponse(<span class="literal">false</span>, retdata);
logger.debug(<span class="string">"====== END RMI Success Result #"</span>, seqnum, <span class="string">" DONE: "</span>, retdata);
}, <span class="function"><span class="keyword">function</span><span class="params">(err)</span>{</span>
sendResponse( err );
});
}
<span class="keyword">catch</span>(err){
logger.error(<span class="string">"Unhandled server error"</span>, err)
sendResponse(<span class="literal">true</span>, formatError( {message: err.toString(), value:err, code:<span class="number">501</span> }, seqnum ));
}
};
}; <span class="comment">/** end processRMI */</span>
<span class="function"><span class="keyword">function</span> <span class="title">prepareTarget</span><span class="params">(invocation, targetCallback)</span>{</span>
logger.debug(<span class="string">"Preparing target from JSON"</span>);
<span class="keyword">var</span> modelClass = getClass( invocation.clazz );
<span class="keyword">if</span>(invocation.static)
<span class="keyword">return</span> targetCallback(modelClass);
<span class="keyword">if</span>( <span class="keyword">typeof</span>(invocation.instance) != <span class="string">'object'</span>)
<span class="keyword">return</span> targetCallback( <span class="string">"Missing invocation instance property"</span> );
<span class="keyword">if</span>(modelClass <span class="keyword">instanceof</span> angoose.Service || !invocation.instance._id)
<span class="keyword">return</span> targetCallback(<span class="keyword">new</span> modelClass(invocation.instance));
<span class="keyword">var</span> _id = invocation.instance._id;
logger.debug(<span class="string">"Loading pristine instance as base"</span>,invocation.clazz, _id)
modelClass.findById(_id, <span class="function"><span class="keyword">function</span><span class="params">(err, pristineInstance)</span>{</span>
<span class="keyword">if</span>(err || !pristineInstance){
logger.error(<span class="string">"Failed to load model by id"</span>, _id);
<span class="keyword">return</span> targetCallback(err);
}
<span class="keyword">var</span> pristineObject = pristineInstance.toObject();
<span class="keyword">var</span> schema = modelClass.schema;
Object.keys(schema.paths).forEach(<span class="function"><span class="keyword">function</span><span class="params">(path)</span>{</span></pre></div></div>
</li>
<li id="section-7">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-7">¶</a>
</div>
<p>var pathSchema = schema.paths[path];
var ref = schemaUtil.getReference(pathSchema);</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="keyword">var</span> newVal = modelClass.getData(invocation.instance, path);
<span class="keyword">var</span> oldVal = modelClass.getData(pristineObject, path);
<span class="keyword">if</span>(!_.isEqual(oldVal, newVal)){
pristineInstance.set(path,newVal);
logger.trace(<span class="string">"seting"</span>, path, <span class="string">": "</span>,oldVal, <span class="string">" --> "</span>, newVal, <span class="string">" NOW dirty? "</span>, pristineInstance.isModified(path));
}
});
targetCallback(pristineInstance);
});
}
<span class="function"><span class="keyword">function</span> <span class="title">scanModelFiles</span><span class="params">(dirs)</span>{</span>
<span class="keyword">var</span> dirs = _.isArray(dirs)? dirs: [dirs];
<span class="keyword">var</span> files = [];
files.push(path.resolve( __dirname , <span class="string">'../models/SampleUser.js'</span>)); <span class="comment">// sample model</span>
<span class="function"><span class="keyword">function</span> <span class="title">scanDir</span><span class="params">(dirname)</span>{</span>
logger.debug(<span class="string">"Scanning directory for models: "</span>, dirname);
fs.readdirSync( dirname ).forEach(<span class="function"><span class="keyword">function</span><span class="params">(file)</span> {</span>
<span class="keyword">var</span> fullpath = path.resolve(dirname,file);
<span class="keyword">if</span>(! fs.statSync(fullpath).isFile()) scanDir( fullpath );
<span class="keyword">else</span> <span class="keyword">if</span> (file.match(<span class="regexp">/.+\.js/g</span>) !== <span class="literal">null</span> && file !== <span class="string">'index.js'</span>) {
files.push(fullpath);
}
});
}
dirs.forEach(<span class="function"><span class="keyword">function</span><span class="params">(dirname)</span>{</span>
scanDir(dirname);
});
<span class="keyword">return</span> files;
}
<span class="function"><span class="keyword">function</span> <span class="title">harvestBeans</span><span class="params">(options)</span>{</span>
logger.debug(<span class="string">"Initialzing models"</span>)
<span class="keyword">var</span> files = scanModelFiles( options.modelDir);
files.forEach(<span class="function"><span class="keyword">function</span><span class="params">(file)</span> {</span>
<span class="keyword">var</span> filename = file.replace(<span class="regexp">/.*[\/\\]([a-z0-9_]+)\.js/i</span>, <span class="string">"$1"</span>);
<span class="keyword">try</span>{
<span class="keyword">var</span> modelClaz = require( file );
<span class="keyword">if</span>(modelClaz && modelClaz._angoosemeta){
<span class="comment">/** Angoose classes */</span>
<span class="keyword">var</span> name = modelClaz._angoosemeta.name || filename;
registerClass(name, modelClaz)
}
<span class="keyword">else</span> <span class="keyword">if</span>(<span class="keyword">typeof</span>(modelClaz) === <span class="string">'function'</span> && modelClaz.schema && modelClaz.modelName ){
<span class="comment">/** mongoose model */</span>
logger.debug(<span class="string">"Adpating mongoose model to Angoose model"</span>, modelClaz.modelName)
modelClaz = angoose.Model.extend(modelClaz)
registerClass(modelClaz.modelName, modelClaz);
<span class="keyword">var</span> clz = getClass(modelClaz.modelName);
<span class="keyword">if</span>(!clz || clz !== modelClaz){
<span class="comment">/** only register once */</span>
modelClaz.on(<span class="string">'error'</span>, modelErrorHandler);
}
}
<span class="keyword">else</span>{
logger.debug(<span class="string">"Skip non-Angoose class file"</span>, filename)
}
}
<span class="keyword">catch</span>(ex){
logger.debug(<span class="string">"Skipping file "</span>, filename, <span class="string">".js due to error: "</span>, ex);
}
});
};</pre></div></div>
</li>
<li id="section-8">
<div class="annotation">
<div class="pilwrap ">
<a class="pilcrow" href="#section-8">¶</a>
</div>
<p><strong> geneateClient() </strong></p>
<p>Generates the client file to be served as the contents of resource <code>/angoose/angoose-client.js</code> </p>
</div>
<div class="content"><div class='highlight'><pre><span class="function"><span class="keyword">function</span> <span class="title">generateClient</span><span class="params">()</span>{</span>
<span class="keyword">var</span> schemas = <span class="string">''</span>
<span class="comment">/** generate client side schemas*/</span>
_.each(beans, <span class="function"><span class="keyword">function</span><span class="params">(model, modelName)</span>{</span>
logger.debug(<span class="string">"Generating client schema for model "</span>, modelName);
<span class="keyword">var</span> tmp = modelName + <span class="string">":"</span> + schemaUtil.stringify( modelName, model );
schemas = (schemas? (schemas+<span class="string">","</span>):<span class="string">""</span>) + tmp;
});
<span class="keyword">var</span> template = require(<span class="string">"path"</span>).resolve(__dirname , <span class="string">"client/angoose-client.js"</span>);
<span class="keyword">var</span> output = options.clientFile ;
<span class="keyword">var</span> content = fs.readFileSync(template , <span class="string">'ascii'</span>);
content = content.replace(<span class="string">"/**SCHEMA_PLACEHOLDER*/"</span>, schemas);
<span class="comment">/** angoose options */</span>
content = content.replace(<span class="string">"/**CONFIG_PLACEHOLDER*/"</span>, <span class="string">'"urlPrefix":"'</span>+ options.urlPrefix+<span class="string">'"'</span>);
<span class="comment">/** include client specific extensions*/</span>
<span class="keyword">var</span> clientModuleFile = require(<span class="string">"path"</span>).resolve(__dirname , <span class="string">"client/angoose-angular.js"</span>);
content += fs.readFileSync(clientModuleFile, <span class="string">'ascii'</span>);
clientModuleFile = require(<span class="string">"path"</span>).resolve(__dirname , <span class="string">"client/angoose-jquery.js"</span>);
content += fs.readFileSync(clientModuleFile, <span class="string">'ascii'</span>);
clientModuleFile = require(<span class="string">"path"</span>).resolve(__dirname , <span class="string">"client/angoose-node.js"</span>);
content += fs.readFileSync(clientModuleFile, <span class="string">'ascii'</span>);
fs.writeFileSync(output, content);
logger.debug(<span class="string">"Generated the client file: "</span>+ options.clientFile);
<span class="keyword">return</span> content;
}
<span class="function"><span class="keyword">function</span> <span class="title">connectMongo</span><span class="params">(options)</span>{</span>
<span class="keyword">var</span> mongoose = getMongoose();
<span class="keyword">try</span>{
logger.debug(<span class="string">"Connecting to mongodb"</span>, options.mongo_opts)
mongoose.connect( options.mongo_opts , <span class="function"><span class="keyword">function</span><span class="params">(err)</span>{</span>
logger.debug(<span class="string">"Mongoose connection"</span>, arguments);
}); <span class="comment">/**@todo: handle complex connection options*/</span>
mongoose.connection.on(<span class="string">'error'</span>, console.error.bind(console, <span class="string">'connection error:'</span>));
}
<span class="keyword">catch</span>(err){
logger.debug(<span class="string">"mngoose connection error"</span>, err)
}
}
<span class="function"><span class="keyword">function</span> <span class="title">modelErrorHandler</span><span class="params">(err, obj)</span>{</span>
logger.trace(<span class="string">"Dummy Model.on() error handler"</span>, err, obj);
}
<span class="function"><span class="keyword">function</span> <span class="title">service</span><span class="params">(nameOpts, proto)</span>{</span>
logger.debug(<span class="string">"creating service "</span>, nameOpts);
<span class="keyword">var</span> opts = <span class="keyword">typeof</span>(nameOpts) == <span class="string">'string'</span>? {name: nameOpts}: nameOpts;
<span class="keyword">if</span>(!opts.name) <span class="keyword">throw</span> <span class="string">"Service name must be provided."</span>;
proto = proto || {};
<span class="keyword">return</span> angoose.Service.extend(proto, opts );
}
<span class="function"><span class="keyword">function</span> <span class="title">getMongoose</span><span class="params">()</span>{</span>
angoose.mongoose = angoose.mongoose || options.mongoose || require(<span class="string">"mongoose"</span>);
<span class="keyword">return</span> angoose.mongoose;
}
<span class="function"><span class="keyword">function</span> <span class="title">noop</span><span class="params">()</span>{</span>};
angoose.init = init;
angoose.getClass = getClass;
angoose.getContext = getContext;
angoose.registerClass = registerClass;
angoose.generateClient = generateClient;
angoose.service = service;
angoose.getMongoose = getMongoose;
angoose.rmiAccept = rmiAccept; <span class="comment">/** for unit test purpose*/</span>
angoose.defer = defer;
module.exports = angoose;</pre></div></div>
</li>
</ul>
</div>
</body>
</html>