Upgrade to Pro — share decks privately, control downloads, hide ads and more …

QEWD Training Course: Part 7

Avatar for robtweed robtweed
November 02, 2017

QEWD Training Course: Part 7

QEWD Training Course Part 7

Avatar for robtweed

robtweed

November 02, 2017

More Decks by robtweed

Other Decks in Technology

Transcript

  1. Copyright © 2016 M/Gateway Developments Ltd EWD 3 Training Course

    Part 7 Applying the QEWD Messaging Pattern Rob Tweed Director, M/Gateway Developments Ltd Twitter: @rtweed
  2. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD

    Application • Generate an event in the browser • Send a message to the QEWD back-end • At the back-end, a handler function for that message type processes the message and usually creates a response message • Response message returned to browser where a handler function processes it and usually modifies the User Interface
  3. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD

    application • Generate an event in the browser, eg: – Click a button – Change a form field value – Move the mouse over a particular area – etc… • Need to be able to trigger a handler function when the required event occurs
  4. Copyright © 2016 M/Gateway Developments Ltd Let's Create an Event

    • We'll: – Add a button to index.html – Add a click event handler for the button in app.js
  5. Copyright © 2016 M/Gateway Developments Ltd Add button to index.html

    <html> <head> <title>Demo ewd-xpress application</title> </head> <body> <script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script> <script src="/socket.io/socket.io.js"></script> <script src="/ewd-client.js"></script> <script src="app.js"></script> <button id="testBtn">Click Me</button> <div id="content"> Content goes here </div> </body> </html>
  6. Copyright © 2016 M/Gateway Developments Ltd Add click handler to

    app.js $(document).ready(function() { EWD.on('ewd-registered', function() { $('#testBtn').on('click', function(e) { console.log('button was clicked!'); }); }); EWD.start('demo1', $, io); }); jQuery event handler Initially just to make sure the click event is handled Note how we define the handler within the document.ready() function and before we start EWD
  7. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD

    application • Sending a message from the browser to the QEWD back-end: – Use the EWD.send() function – Messages must have a type property – The type property's value is up to you to define • Any string value – EWD.send() function not available for use until registration completes – EWD.send() automatically adds the session token to the message • Its behaviour is protected within a closure and cannot be modified • Note that manual socket.io messaging is unavailable to user
  8. Copyright © 2016 M/Gateway Developments Ltd Edit app.js $(document).ready(function() {

    EWD.on('ewd-registered', function() { $('#testBtn').on('click', function(e) { var message = {type: 'testButton'}; EWD.send(message); }); }); EWD.start('demo1', $, io); }); Simplest message possible for now Just a type property
  9. Copyright © 2016 M/Gateway Developments Ltd Try it out •

    Nothing appears to happen in the browser when you click the button! • But check the Command Prompt or terminal window in which you're running the QEWD Node.js process…
  10. Copyright © 2016 M/Gateway Developments Ltd Back-end log • The

    message was received by the master process and passed to a worker: • Notice that the session token has been added to the message by the EWD.send() function worker 2052 received message: {"type":"testButton", "token":"4fb0efcd-458c-4afd-a053-8a19600867c4"}
  11. Copyright © 2016 M/Gateway Developments Ltd Back-end log • Worker

    process reported an error • QEWD was unable to find and load a module containing message handlers for this application ('demo1') – That's because we haven't written one yet! Unable to load handler module for: demo1: Error: Cannot find module 'demo1'
  12. Copyright © 2016 M/Gateway Developments Ltd Back-end log • This

    error message was returned to master process by the worker • The master process will have forwarded this message to the browser – Nothing displayed in the browser though! master process received response from worker 2052: {"type":"testButton","finished":true,"message":{"error":"Unable to load handler module for: demo1","reason":{"code":"MODULE_NOT_FOUND"}}}
  13. Copyright © 2016 M/Gateway Developments Ltd Displaying messages in browser

    • Normally it's up to you to handle message responses and display them in the UI • During development it's useful to see a trace of all messages sent and received in the JavaScript console • To do this, set EWD.log = true;
  14. Copyright © 2016 M/Gateway Developments Ltd Edit app.js $(document).ready(function() {

    EWD.log = true; EWD.on('ewd-registered', function() { $('#testBtn').on('click', function(e) { var message = {type: 'testButton'}; EWD.send(message); }); }); EWD.start('demo1', $, io); });
  15. Copyright © 2016 M/Gateway Developments Ltd Fixing this error •

    EWD.send() is working fine – It's sending the message to the back-end as expected • How do we fix the error at the back-end and how do we handle the incoming message there?
  16. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD

    application • At the back-end, you must define a handler function for each of your message types • Each handler function processes the message for the specified type, and usually creates a response message • All the handler functions for any one application are defined within a single Node.js module – That module can, of course, be split into multiple sub-modules if required
  17. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD

    application • So, for each application you define a back-end module • By default, the module name is the same as the application name – Eg, in our case: demo.js • You can over-ride this and map an application name to a module name/path, if you prefer • Your application module defines a hander function for each of your application's message types – Typically a handler function will do any or all of the following: • Read from / write to a database • Read from/ write to the user's QEWD Session • Invoke legacy application functions • Invoke 3rd-party Node.js modules • Make web/REST service calls to other local or remote services – Each of your handler functions has full read/write access to your embedded Global Storage database: • Cache, GT.M or Redis
  18. Copyright © 2016 M/Gateway Developments Ltd Back-end Application module pattern

    • Default name / path: – Windows: • C:\qewd\node_modules\{applicationName}.js – Linux / Raspberry Pi • ~/qewd/node_modules/{applicationName}.js
  19. Copyright © 2016 M/Gateway Developments Ltd Back-end Application module pattern

    module.exports = { handlers: { messageType1: function(messageObj, session, send, finished) { // do something with the incoming message // create a response object // use the finished() function to end the processing and // release the worker finished(responseObj); }, messageType2: function(messageObj, session, send, finished) { // etc…. finished(responseObj); } };
  20. Copyright © 2016 M/Gateway Developments Ltd Create our back-end module

    • C:\qewd\node_modules\demo1.js or • ~/qewd/node_modules/demo1.js module.exports = { handlers: { testButton: function(messageObj, session, send, finished) { console.log('*** handling the button click message!'); finished({ ok: 'testButton message was processed successfully!' }); } } };
  21. Copyright © 2016 M/Gateway Developments Ltd Create our back-end module

    module.exports = { handlers: { testButton: function(messageObj, session, send, finished) { console.log('*** handling the button click message!'); finished({ ok: 'testButton message was processed successfully!' }); } } }; This was the value of the type property in our EWD.send() function EWD.send({type: 'testButton'});
  22. Copyright © 2016 M/Gateway Developments Ltd And check out the

    back-end log worker 2000 received message: {"type":"testButton","token":"527bd51f-7d6a-4dd7-8 27d-c1ea8dfa1f43"} *** handling the button click message! master process received response from worker 2000: {"type":"testButton","finished":true,"message":{"ok":"testButton message was processed successfully!","ewd_application":"demo1"}} *** handleMessage response {"type":"testButton","finished":true,"message":{"ok": "testButton message was processed successfully!","ewd_application":"demo1"}} sending to socket /#5NdGRfkMn17-vboPAAAC Master process has finished processing response from worker process 2000 which is back in available pool Came from this line: console.log('*** handling the button click message!'); In our handler function
  23. Copyright © 2016 M/Gateway Developments Ltd Got an error? •

    Check back-end log: – "Unable to load module" message? • Means you have a syntax error in the module • How to locate it? – Use the Node.js REPL
  24. Copyright © 2016 M/Gateway Developments Ltd Using the Node.js REPL

    C:\Users\Rob Tweed> cd \qewd C:\qewd> node > var x = require('demo1') C:\qewd\node_modules\demo1.js:6 ok: 'testButton message was processed successfully!'' ^ SyntaxError: Unexpected token ILLEGAL at exports.runInThisContext (vm.js:53:16) at Module._compile (module.js:373:25) at Object.Module._extensions..js (module.js:416:10) at Module.load (module.js:343:32) at Function.Module._load (module.js:300:12) at Module.require (module.js:353:17) at require (internal/module.js:12:17) at repl:1:9 at REPLServer.defaultEval (repl.js:262:27) at bound (domain.js:287:14) > 2 X Ctrl & C to exit from REPL
  25. Copyright © 2016 M/Gateway Developments Ltd Back-end message handler resources

    • Within a back-end message handler function you have access to everything you need: – testButton: function(messageObj, session, send, finished) {..} – Incoming message: messageObj – QEWD session: session.data (read/write access) – Global Storage database (read/write/execute access): • this.db gives access to the cache.node APIs, – eg this.db.function() to execute a function / procedure • this.documentStore gives access to ewd-document-store JavaScript / Document database abstraction of your Global Storage database
  26. Copyright © 2016 M/Gateway Developments Ltd Using the QEWD Session

    • C:\qewd\node_modules\demo1.js or • ~/qewd/node_modules/demo1.js module.exports = { handlers: { testButton: function(messageObj, session, send, finished) { console.log('*** handling the button click message!'); session.data.$('foo').value = 'bar'; finished({ ok: 'testButton message was processed successfully!' }); } } };
  27. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD

    application • At the back-end, a handler function for the specific message type processes the message and usually creates a response message – Response messages are JSON objects – If using web-sockets, you can send more than 1 message • send() function for intermediate messages. Worker remains unavailable • finished() function for final message. Worker released to available pool – Response messages have a type property • By default, the type is the same as that of the original incoming message from the browser • Optionally, when using the send() function for intermediate messages, you can over- ride the type • The type of the finished() message cannot be over-ridden – it is always the same as the incoming message – A Handler function MUST end by invoking the finished() function • Releases the ewd-qoper8 worker process back to the available pool – Response messages are automatically sent to the originating client or browser
  28. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD

    application • Response message is returned to the browser where a handler function processes it and usually modifies the User Interface – Two methods for handling responses within the browser: • Callback function as 2nd argument of EWD.send() function – EWD.send(messageObj, function(responseObj) {…}); • Pub/Sub mechanism, specific to a message type: – EWD.on(messageType, function(responseObj) {…}); – UI modification using JavaScript • Up to you which framework, if any, you use
  29. Copyright © 2016 M/Gateway Developments Ltd Edit app.js $(document).ready(function() {

    EWD.log = true; EWD.on('ewd-registered', function() { $('#testBtn').on('click', function(e) { var message = {type: 'testButton'}; EWD.send(message, function(messageObj) { console.log('Response received: ' + JSON.stringify(messageObj.message.ok)); }); }); }); EWD.start('demo1', $, io); }); Using the EWD.send() callback function to handle the response
  30. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD

    application • Response message is returned to the browser where a handler function processes it and usually modifies the User Interface – Two methods for handling responses within the browser: • Callback function as 2nd argument of EWD.send() function – EWD.send(messageObj, function(responseObj) {…}); • Pub/Sub mechanism, specific to a message type: – EWD.on(messageType, function(responseObj) {…}); – UI modification using JavaScript • Up to you which framework, if any, you use • We'll just use jQuery since it's already loaded
  31. Copyright © 2016 M/Gateway Developments Ltd Edit app.js $(document).ready(function() {

    EWD.log = true; EWD.on('ewd-registered', function() { $('#testBtn').on('click', function(e) { var message = {type: 'testButton'}; EWD.send(message, function(messageObj) { $('#content').text(messageObj.message.ok); }); }); }); EWD.start('demo1', $, io); }); Change the text inside the <div id="content"> tag
  32. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD

    application • Response message is returned to the browser where a handler function processes it and usually modifies the User Interface – Two methods for handling responses within the browser: • Callback function as 2nd argument of EWD.send() function – EWD.send(messageObj, function(responseObj) {…}); • Pub/Sub mechanism, specific to a message type: – EWD.on(messageType, function(responseObj) {…}); – Mainly used for messages you'll send frequently from back-end – Particularly intermediate messages using send() function – UI modification using JavaScript • Up to you which framework, if any, you use
  33. Copyright © 2016 M/Gateway Developments Ltd Intermediate messages • C:\qewd\node_modules\demo1.js

    or • ~/qewd/node_modules/demo1.js module.exports = { handlers: { testButton: function(messageObj, session, send, finished) { session.data.$('foo').value = 'bar'; send({ type: 'intermediate', foo: 'bar', date: new Date().toString() }); finished({ ok: 'testButton message was processed successfully!' }); } } }; Overrides the incoming message type
  34. Copyright © 2016 M/Gateway Developments Ltd Intermediate messages • C:\ewd3\node_modules\demo1.js

    or • C:\ewd3\node_modules\demo1.js module.exports = { handlers: { testButton: function(messageObj, session, send, finished) { session.data.$('foo').value = 'bar'; send({ type: 'intermediate', foo: 'bar', date: new Date().toString() }); finished({ ok: 'testButton message was processed successfully!' }); } }; Must still invoke the finished() function to tell ewd-qoper8 to release the worker back to the available pool
  35. Copyright © 2016 M/Gateway Developments Ltd Edit app.js $(document).ready(function() {

    EWD.log = true; EWD.on('ewd-registered', function() { EWD.on('intermediate', function(responseObj) { $('#content').text(responseObj.message.date); }); $('#testBtn').on('click', function(e) { var message = {type: 'testButton'}; EWD.send(message, function(messageObj) { $('#content').append('<br /> ' + messageObj.message.ok); }); }); }); EWD.start('demo1', $, io); }); Handle instances of the 'intermediate' message Using Pub/Sub handler
  36. Copyright © 2016 M/Gateway Developments Ltd Edit app.js $(document).ready(function() {

    EWD.log = true; EWD.on('ewd-registered', function() { EWD.on('intermediate', function(responseObj) { $('#content').text(responseObj.message.date); }); $('#testBtn').on('click', function(e) { var message = {type: 'testButton'}; EWD.send(message, function(messageObj) { $('#content').append('<br /> ' + messageObj.message.ok); }); }); }); EWD.start('demo1', $, io); }); Combine the responses within the <div id="content"> tag
  37. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping •

    By default, the back-end handler module for a QEWD application is named the same as the application, eg: – Our application is named demo1 – By default, QEWD will assume that the handler functions for this application are in a module named demo1.js ie: • C:\qewd\node_modules\demo1.js or • ~/qewd/node_modules/demo1.js
  38. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping •

    You can over-ride this default behaviour by defining a module map in your QEWD startup file • Application module mapping is done in your QEWD start-up file – Define a config property named moduleMap • This is an object / hash mapping one or more Application names to corresponding module names/paths
  39. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping •

    Example: var config = { managementPassword: 'keepThisSecret!', serverName: 'My QEWD Server', port: 8080, poolSize: 2, database: { type: 'gtm' }, moduleMap: { demo1: 'myDemoApp' } }; var qewd = require('qewd').master; qewd.start(config);
  40. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping •

    Example: var config = { managementPassword: 'keepThisSecret!', serverName: 'My QEWD Server', port: 8080, poolSize: 2, database: { type: 'gtm' }, moduleMap: { demo1: 'myDemoApp' } }; var qewd = require('qewd').master; qewd.start(config); This tells QEWD that in order to handle messages for the demo1 application, it must load a module using require('myDemoApp')
  41. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping •

    Example: var config = { managementPassword: 'keepThisSecret!', serverName: 'My QEWD Server', port: 8080, poolSize: 2, database: { type: 'gtm' }, moduleMap: { demo1: '/path/to/myDemoApp' } }; var qewd = require('qewd').master; qewd.start(config); This tells QEWD that in order to handle messages for the demo1 application, it must load a module using require('/path/to/myDemoApp')
  42. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping •

    Example: var config = { managementPassword: 'keepThisSecret!', serverName: 'My QEWD Server', port: 8080, poolSize: 2, database: { type: 'gtm' }, moduleMap: { demo1: '/path/to/myDemoApp', finance: 'myFinanceApp' } }; var qewd = require('qewd').master; qewd.start(config); You can map as many Applications as needed
  43. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping •

    QEWD Application back-end modules can therefore be defined as standard Node.js modules – Can be published to NPM – Can be installed from NPM