Comparing version 0.1.3 to 0.1.4
@@ -48,2 +48,17 @@ /** | ||
this._componentInstance = componentInstance; | ||
Object.defineProperty(this, 'reply', { | ||
value : function() { | ||
if (!this.returnId) { | ||
console.warn(new Error('Host to `reply` when there was no pending request expecting a reply.').stack); | ||
return; | ||
} | ||
var args = Array.prototype.slice.call(arguments, 0); // convert arguments to array | ||
this._componentInstance.Instance.Libs.ComponentCommunications.sendReply(this.returnId, args); | ||
// unset returnId | ||
this.returnId = 0; | ||
} | ||
}); | ||
},{ | ||
@@ -124,2 +139,7 @@ logError: function(msg) { | ||
} | ||
// handle special return callback | ||
if (command.returnId) { | ||
componentInstance.client.returnId = command.returnId; | ||
} | ||
@@ -174,3 +194,3 @@ // call actual command, with arguments on the host object | ||
Instance.Libs.ComponentCommunications.sendCommandToHost(componentInstance._def.FullName, cmdName, args); | ||
return Instance.Libs.ComponentCommunications.sendCommandToHost(componentInstance._def.FullName, cmdName, args); | ||
}.bind(this); | ||
@@ -177,0 +197,0 @@ }.bind(this)); |
@@ -7,2 +7,3 @@ /** | ||
var domain = require('domain'); | ||
var url = require('url'); | ||
@@ -391,3 +392,3 @@ | ||
' -- Make sure to check (or add checks to) all calls to Tools.requestClientComponents.'); | ||
componentNames.splice(i, 1); | ||
componentDefs.splice(i, 1); | ||
} | ||
@@ -517,2 +518,6 @@ } | ||
app.get(cfg.baseUrl + "*", function(req, res, next) { | ||
// create a domain to avoid fatal catastrophe caused by a single client | ||
// see: http://clock.co.uk/blog/preventing-http-raise-hangup-error-on-destroyed-socket-write-from-crashing-your-nodejs-server | ||
var reqDomain = domain.create(); | ||
var session = req.session; | ||
@@ -519,0 +524,0 @@ var sessionId = req.sessionID; |
@@ -104,3 +104,3 @@ /** | ||
*/ | ||
executeInOrder: function(cb) { | ||
executeInOrder: function(cb, movesNext) { | ||
if (this.instance.isBuffering()) { | ||
@@ -113,2 +113,5 @@ // still executing a command: Queue the request. | ||
cb(); | ||
if (!movesNext) { | ||
this.instance.moveNext(); | ||
} | ||
} | ||
@@ -202,2 +205,3 @@ }, | ||
interceptStack: null, | ||
sendListeners: [], | ||
connectionData: {}, | ||
@@ -218,2 +222,6 @@ | ||
addSendListener: function(cb) { | ||
this.sendListeners.push(cb); | ||
}, | ||
/** | ||
@@ -227,3 +235,3 @@ * Used by endpoint implementations to execute and/or put commands. | ||
this.queue.executeInOrder(cb); | ||
this.queue.executeInOrder(cb, true); | ||
}, | ||
@@ -256,3 +264,3 @@ | ||
// put request on intercept stack, so it will be the first thing to be executed after the current thing | ||
this.interceptStack.executeInOrder(cb); | ||
this.interceptStack.executeInOrder(cb, true); | ||
}, | ||
@@ -376,2 +384,9 @@ | ||
// call send listeners | ||
for (var i = 0; i < this.sendListeners.length; ++i) { | ||
this.sendListeners[i](); | ||
} | ||
// remove listeners (they are only one-shot) | ||
this.sendListeners.length = 0; | ||
trace('finishRequest'); | ||
@@ -448,2 +463,10 @@ | ||
} | ||
}, | ||
// ############################################################################################################## | ||
// Reply to a pending `onReturn` callback on the client side. | ||
sendReply: function(returnId, args) { | ||
this.client.returnReply(returnId, args); | ||
} | ||
@@ -456,10 +479,60 @@ } | ||
Client: ComponentDef.defClient(function(Tools, Instance, Context) { | ||
return { | ||
var timer; | ||
var buffer = []; | ||
var lastReturnId = 0; | ||
var pendingCbs = {}; | ||
var sendBufferToHost = function() { | ||
// send out buffer | ||
thisInstance.getDefaultConnection().sendCommandsToHost(buffer); | ||
// clear buffer | ||
buffer.length = 0; | ||
// unset timer | ||
timer = null; | ||
}; | ||
var Packet = { | ||
onReturn: function(cb) { | ||
this.returnId = ++lastReturnId; | ||
pendingCbs[this.returnId] = cb; | ||
return this; // return self for further chaining | ||
} | ||
}; | ||
var thisInstance; | ||
return thisInstance = { | ||
sendCommandToHost: function(compName, cmdName, args) { | ||
var commands = [{ | ||
comp: compName, | ||
cmd: cmdName, | ||
args: args | ||
}]; | ||
this.getDefaultConnection().sendCommandsToHost(commands); | ||
// build packet & store in buffer | ||
var cmdPacket = Object.create(Packet); | ||
cmdPacket.comp = compName; | ||
cmdPacket.cmd = cmdName; | ||
cmdPacket.args = args; | ||
buffer.push(cmdPacket); | ||
// set a timer to send off all pending commands ASAP | ||
if (!timer) { | ||
timer = setTimeout(sendBufferToHost, 1); | ||
} | ||
return cmdPacket; | ||
}, | ||
Public: { | ||
/** | ||
* Host has replied to our pending `onReturn` request. | ||
*/ | ||
returnReply: function(returnId, args) { | ||
// get cb | ||
var cb = pendingCbs[returnId]; | ||
if (!cb) { | ||
console.warn('Host sent return reply with invalid `returnId`: ' + returnId); | ||
return; | ||
} | ||
// delete cb from set and execute it | ||
delete pendingCbs[returnId]; | ||
cb.apply(null, args); | ||
} | ||
} | ||
@@ -502,5 +575,10 @@ }; | ||
var cb = function(req, res, next) { | ||
req.on('error', function(err) { | ||
console.warn('Connection error: ' + err); | ||
}); | ||
// extract body data | ||
// see: http://stackoverflow.com/a/4310087/2228771 | ||
var session = req.session; | ||
var sessionId = req.sessionID; | ||
@@ -515,5 +593,2 @@ console.assert(session, | ||
var body = ''; | ||
req.on('error', function(err) { | ||
console.warn('Client connection error: ' + err.stack); | ||
}); | ||
req.on('data', function (data) { | ||
@@ -520,0 +595,0 @@ body += data; |
@@ -495,3 +495,4 @@ /** | ||
window.onerror = function(message, filename, lineno, colno, error) { | ||
console.error('ERROR @ ' + filename + ':' + lineno + ':' + colno + ' - ' + error); | ||
console.error('An error has occured. If you do not see a meaningful stacktrace, refresh once ' + | ||
'(the first raised error in the window usually does not stick the landing, at least in Chrome).'); | ||
}; | ||
@@ -619,4 +620,7 @@ | ||
// call initHost on all libs, with some special arguments | ||
// call initBase + initHost on all libs, with some special arguments | ||
Shared.Libs.forEach(function(component) { | ||
if (component.initBase) { | ||
component.initBase(); | ||
} | ||
if (component.initHost) { | ||
@@ -627,4 +631,7 @@ component.initHost(app, cfg); | ||
// call initHost on all other components | ||
// call initBase + initHost on all other components | ||
Shared.forEach(function(component) { | ||
if (component.initBase) { | ||
component.initBase(); | ||
} | ||
if (component.initHost) { | ||
@@ -733,6 +740,9 @@ component.initHost(app, cfg); | ||
// then, call initClient on new components | ||
// then, call initBase + initClient on new components | ||
for (var i = 0; i < defs.length; ++i) { | ||
var endpointDef = defs[i].Client; | ||
var comp = map[endpointDef.FullName]; | ||
if (comp.initBase) { | ||
comp.initBase(); | ||
} | ||
if (comp.initClient) { | ||
@@ -739,0 +749,0 @@ comp.initClient(); |
@@ -61,3 +61,6 @@ /** | ||
}, | ||
/** | ||
* Client commands can be directly called by the host | ||
*/ | ||
Public: { | ||
@@ -64,0 +67,0 @@ } |
{ | ||
"name": "nogap", | ||
"version": "0.1.3", | ||
"version": "0.1.4", | ||
"author": { | ||
@@ -5,0 +5,0 @@ "name": "Dominik Seifert", |
@@ -5,1 +5,3 @@ NoGap | ||
The NoGap framework delivers RPC + asset management + some other good stuff for Host <-> Client communication. | ||
Have a look at the <a href="https://github.com/Domiii/NoGap/tree/master/testapp">Sample App</a> for reference. |
@@ -5,3 +5,3 @@ module.exports = { | ||
"httpd": { | ||
"port" : "8080", | ||
"port" : "12345", | ||
"wikiUrl" : "http://localhost:80/wiki" | ||
@@ -8,0 +8,0 @@ }, |
@@ -15,4 +15,4 @@ /** | ||
/** | ||
* The HostComponent instance will live in the host context (here). | ||
* Functions inside HostComponent.command can be called by the client. | ||
* The `Host` endpoint of a component lives in the host context and is also returned by `ComponentDef.component`. | ||
* Methods inside the `Public` instance prototype can be called by the client. | ||
*/ | ||
@@ -19,0 +19,0 @@ Host: ComponentDef.defHost(function(SharedTools, Shared, SharedContext) { return { |
@@ -17,2 +17,6 @@ /** | ||
/** | ||
* The `Host` endpoint of a component lives in the host context and is also returned by `ComponentDef.component`. | ||
* Methods inside the `Public` instance prototype can be called by the client. | ||
*/ | ||
Host: ComponentDef.defHost(function(SharedTools, Shared, SharedContext) { | ||
@@ -19,0 +23,0 @@ return { |
@@ -17,2 +17,6 @@ /** | ||
/** | ||
* The `Host` endpoint of a component lives in the host context and is also returned by `ComponentDef.component`. | ||
* Methods inside the `Public` instance prototype can be called by the client. | ||
*/ | ||
Host: ComponentDef.defHost(function(SharedTools, Shared, SharedContext) { | ||
@@ -25,3 +29,2 @@ return { | ||
'//ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js', | ||
'//ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular-route.js', | ||
@@ -28,0 +31,0 @@ // bootstrap's logic (requires jquery) |
@@ -9,9 +9,11 @@ Components Test App | ||
* Modularity | ||
* Client + Server can be developed in unison, without having to define a complex protocol or packet routing. | ||
* Simplicity | ||
* Client + Host parts of the application can be developed in unison, without having to define a complex protocol or packet routing. | ||
* Host<->Client RPC | ||
* You can directly call methods, with arguments, on the other side. | ||
* Lazy-loading of components | ||
* But don't worry. It is also secure. The client side does not get to see any of the host code. | ||
* At the same time, the stack traces generated by client components 100% accurately report the correct line number and filename of definition (if not disabled). | ||
* Dynamic loading of client-side code | ||
* The client will only install the components that you want it to and when you want it to. | ||
* Basic asset management | ||
* You can easily get access to the contents of, or automatically-include, files from the local or a designated public folder. | ||
* You can easily get access to the contents of, or automatically include, files from the local or a designated public folder, by just naming an asset, and without having to worry about the security of other files outside the public folder. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
260222
3659
7