forked from eclipse-vertx/vert.x
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mods_manual.html
841 lines (826 loc) · 42.8 KB
/
mods_manual.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link rel="stylesheet/less" href="bootstrap/less/bootstrap.less">
<script src="less-1.2.1.min.js"></script>
<link href="google-code-prettify/prettify.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src="google-code-prettify/prettify.js"></script>
<link href="css/vertx.css" type="text/css" rel="stylesheet"/>
<link href="css/sunburst.css" type="text/css" rel="stylesheet"/>
<title>Vert.x Modules Manual</title>
<script>
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-30144458-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body onload="prettyPrint()">
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse"
data-target=".nav-collapse">
<span class="i-bar"></span>
<span class="i-bar"></span>
<span class="i-bar"></span>
</a>
<a class="brand" href="/">vert.x</a>
<div class="nav-collapse">
<ul class="nav">
<li class="active"><a href="/">Home</a></li>
<li><a href="https://github.com/purplefox/vert.x/downloads">Download</a></li>
<li><a href="install.html">Install</a></li>
<li><a href="tutorials.html">Tutorials</a></li>
<li><a href="examples.html">Examples</a></li>
<li><a href="docs.html">Documentation</a></li>
<li><a href="https://github.com/purplefox/vert.x">Source</a></li>
<li><a href="http://groups.google.com/group/vertx">Google Group</a></li>
<li><a href="community.html">Community</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="span12">
<div class="well">
<h1 style="font-size: 35px;">Modules Manual</h1>
</div>
</div>
</div>
<div class="row">
<div class="span12">
<div class="well">
<div>
<div class="toc">
<ul>
<li><a href="#modules">Modules</a><ul>
<li><a href="#what-is-a-module-mod">What is a Module (mod) ?</a><ul>
<li><a href="#modules-location">Modules location</a></li>
<li><a href="#module-directory-structure">Module directory structure</a><ul>
<li><a href="#module-descriptor">Module descriptor</a><ul>
<li><a href="#worker-modules">Worker modules</a></li>
<li><a href="#preserving-working-directory">Preserving working directory</a></li>
</ul>
</li>
<li><a href="#module-path">Module path</a></li>
</ul>
</li>
<li><a href="#running-a-module-from-the-command-line">Running a module from the command line</a></li>
<li><a href="#running-a-module-programmatically">Running a module programmatically</a></li>
<li><a href="#module-working-directory">Module working directory</a></li>
<li><a href="#creating-and-installing-your-own-module">Creating and installing your own module</a></li>
<li><a href="#what-is-a-bus-module-busmod">What is a Bus Module (busmod) ?</a></li>
<li><a href="#configuration">Configuration</a></li>
</ul>
</li>
<li><a href="#out-of-the-box-busmods">Out of the box busmods</a><ul>
<li><a href="#instantiating-out-of-the-box-modules">Instantiating out-of-the-box modules</a></li>
<li><a href="#web-server">Web Server</a><ul>
<li><a href="#name">Name</a></li>
<li><a href="#configuration_1">Configuration</a><ul>
<li><a href="#examples">Examples</a></li>
<li><a href="#simple-static-file-web-server">Simple static file web server</a></li>
<li><a href="#simple-https-server">Simple https server</a></li>
<li><a href="#event-bus-bridge">Event bus bridge</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#mongodb-persistor">MongoDB Persistor</a><ul>
<li><a href="#dependencies">Dependencies</a></li>
<li><a href="#name_1">Name</a></li>
<li><a href="#configuration_2">Configuration</a></li>
<li><a href="#operations">Operations</a><ul>
<li><a href="#save">Save</a></li>
<li><a href="#find">Find</a><ul>
<li><a href="#batching">Batching</a></li>
</ul>
</li>
<li><a href="#find-one">Find One</a></li>
<li><a href="#delete">Delete</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#mailer">Mailer</a><ul>
<li><a href="#dependencies_1">Dependencies</a></li>
<li><a href="#name_2">Name</a></li>
<li><a href="#configuration_3">Configuration</a></li>
<li><a href="#sending-emails">Sending Emails</a></li>
</ul>
</li>
<li><a href="#authentication-manager">Authentication Manager</a><ul>
<li><a href="#dependencies_2">Dependencies</a></li>
<li><a href="#name_3">Name</a></li>
<li><a href="#configuration_4">Configuration</a></li>
<li><a href="#operations_1">Operations</a><ul>
<li><a href="#login">Login</a></li>
<li><a href="#logout">Logout</a></li>
<li><a href="#validate">Validate</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#work-queue">Work Queue</a><ul>
<li><a href="#dependencies_3">Dependencies</a></li>
<li><a href="#name_4">Name</a></li>
<li><a href="#configuration_5">Configuration</a></li>
<li><a href="#operations_2">Operations</a><ul>
<li><a href="#send">Send</a></li>
<li><a href="#register">Register</a></li>
<li><a href="#unregister">Unregister</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<h1 id="modules">Modules</h1><br/>
<h2 id="what-is-a-module-mod">What is a Module (mod) ?</h2><br/>
<p>Vert.x allows you to package up your applications or re-usable functionality into modules which can then be referenced by other applications or modules.</p>
<p>For example, vert.x ships with several out of the box modules including a web server, a mailer and a MongoDB persistor. You can also easily create your own modules.</p>
<h3 id="modules-location">Modules location</h3><br/>
<p>Modules, by default, live in the <code>mods</code> directory in the vert.x installation directory. Vert.x comes with several modules pre-installed and they reside here.</p>
<p>Vert.x always first searches for modules in the <code>mods</code> directory of the installation followed by the directory given by the environment variable <code>VERTX_MODS</code>, if specified.</p>
<p>You can put your own modules in the <code>mods</code> directory if you like, but it is highly recommended you put them in some other directory (e.g. <code>~/vertx-mods</code>) so that you don't overwrite them when you upgrade vert.x.</p>
<p>If you do decide to put them somewhere else, make sure <code>VERTX_MODS</code> points to that directory.</p>
<p>Each module lives in its own child directory of the module directory. The name of the directory is the name of the module. Modules must not share a directory.</p>
<p>If you have more than one version of the same module, you should suffix the name and with a hash sign <code>#</code> followed by the version number. For example, here we have two versions of the widget module:</p>
<pre class="prettyprint">mods/some-module
mods/widget#v1.0
mods/widget#v1.1
</pre>
<h3 id="module-directory-structure">Module directory structure</h3><br/>
<h4 id="module-descriptor">Module descriptor</h4><br/>
<p>Inside the module directory you must provide a file called <code>mod.json</code> which contains some JSON which describes the module, for example:</p>
<pre class="prettyprint">{
"main": "mailer.js"
}
</pre>
<p>At minimum <code>mod.json</code> must contain a field <code>main</code> which specifies the main verticle to start the module. Main would be something like <code>myscript.groovy</code>, <code>app.rb</code>, <code>foo.js</code> or <code>org.acme.MyApp</code>. (See the chapter on "running vert.x" in the main manual for a description of what a main is.)</p>
<h5 id="worker-modules">Worker modules</h5><br/>
<p>If your main verticle is a worker verticle you must also specify the <code>worker</code> field with value <code>true</code>, otherwise it will be assumed it is not a worker.</p>
<h5 id="preserving-working-directory">Preserving working directory</h5><br/>
<p>By default when you're module is executing it will see its working directory as the module directory when using the Vert.x API. This is useful if you want to package up an application which contains its own static resources into a module.</p>
<p>However in some cases, you don't want this behaviour, you want the module to see its working directory as the working directory of whoever started the module.</p>
<p>An example of this would be the <code>web-server</code> module. With the web server, you use it to serve your own static files which exist either outside of a module or in your own module, they do not exist inside the <code>web-server</code> module itself.</p>
<p>If you want to preserve current working directory, set the field <code>preserve-cwd</code> to <code>true</code> in <code>mod.json</code>. The default value is <code>false</code>.</p>
<h4 id="module-path">Module path</h4><br/>
<p>Any scripts or classes you place in the module directory will be available to the module (placed on the module path). If you have any jar dependencies you can also place these in a directory called <code>lib</code> and these will be added to the module path.</p>
<p>Here's an example JS module:</p>
<pre class="prettyprint">my-mod/mod.json
my-mod/app.js
my-mod/other-script.js
my-mod/foo.json
</pre>
<p>In the above <code>app.js</code> is the main for the module. <code>other-script.js</code> and <code>foo.json</code> are scripts/resources used by the module.</p>
<pre class="prettyprint">java-mod/mod.json
java-mod/org/acme/MyMain.class
java-mod/lib/other-jar.jar
</pre>
<p>The above is an example Java mod where <code>org/acme/MyMain.class</code> is the main, and <code>other-jar.jar</code> is a jar dependency of the module.</p>
<p>You can of course mix and match multiple languages in a single module.</p>
<h3 id="running-a-module-from-the-command-line">Running a module from the command line</h3><br/>
<p>Modules are run like any other verticle - i.e. using the <code>vertx run</code> or <code>vertx deploy</code> commands. Please see the main manual for a full description of this.</p>
<p>E.g.</p>
<pre class="prettyprint">vertx run my-mod
</pre>
<p>Will run a module called <code>my-mod</code> <br/>
</p>
<h3 id="running-a-module-programmatically">Running a module programmatically</h3><br/>
<p>You run a module programmatically in the same way as you run any verticle programmatically. Please see the core manual for the appropriate language for a full description on how to do this.</p>
<h3 id="module-working-directory">Module working directory</h3><br/>
<p>When you run a module using <code>vertx run</code> or <code>vertx deploy</code> your actual process working directory is wherever you were when you executed the command.</p>
<p>However the module will be located in the <code>mods</code> (or <code>VERTX_MODS</code>) directory. Consequently if your module contains static files - e.g. your module might be a web application that serves static files from the file system, then if your module expects the working directory to be set to module directory it won't find them!</p>
<p>For example, let's say you have a simple webapp that has an HTTP server that serves an index.html which is packaged as a module:</p>
<pre class="prettyprint">mods/my-web-app/server.js
mods/my-web-app/web-root/index.html
</pre>
<p>And server.js serves the file with:</p>
<pre class="prettyprint">req.response.sendFile('web-root/index.html');
</pre>
<p>In the above case the web server expects the working directory to be the module directory.</p>
<p>To solve this we internally adjust all paths such that, if you use the vert.x API for all file access then it will appear as if your working directory is the module directory. I.e. your web app will just work irrespective of where the module is actually installed :) </p>
<p>If you don't want this behaviour you can set the field <code>preserve-cwd</code> to <code>true</code> in <code>mod.json</code>. See above for a description of this field. <br/>
</p>
<h3 id="creating-and-installing-your-own-module">Creating and installing your own module</h3><br/>
<p>Creating your own module is simple, simply create your vert.x application as normal, then put it all in a directory whose name is the module name, and provide a <code>mod.json</code> file as described above.</p>
<p>Then copy the entire directory to the module root directory (i.e. the <code>mods</code> directory in the install or your own module root given by <code>VERTX_MODS</code>)</p>
<h3 id="what-is-a-bus-module-busmod">What is a Bus Module (busmod) ?</h3><br/>
<p>A <em>busmod</em> is a specific type of module that communicates on the event bus with over verticles by sending JSON messages.</p>
<p>Since it communicates only with JSON messages then the busmod is instantly usable by other verticles irrespective of which language they are written in, since all the supported languages allow sending and receiving JSON messages from the event bus. </p>
<p>JSON is the <em>lingua franca</em> of vert.x</p>
<p>You don't have to write your application modules as busmods but it's highly recommended you do since it will make them easily and consistently usable from other verticles.</p>
<h3 id="configuration">Configuration</h3><br/>
<p>Configuration for a module (if any) should be specified using a JSON configuration file when deploying from the command line using <code>vertx run</code> or <code>vertx deploy</code> or passed in when deploying a busmod programmatically.</p>
<p>Applying configuration this way allows it to be easily and consistently configured irrespective of the language.</p>
<h2 id="out-of-the-box-busmods">Out of the box busmods</h2><br/>
<p>The vert.x distribution contains several out-of-the-box modules that you can use in your applications. These modules are designed to handle common things that you might want to do in applications.</p>
<h4 id="instantiating-out-of-the-box-modules">Instantiating out-of-the-box modules</h4><br/>
<p>You can instantiate any out of the box module from the command line using <code>vertx run</code> or <code>vertx deploy</code> like any other verticle, i.e.</p>
<pre class="prettyprint">vertx run <bus_mode_name> -conf <config_file>
</pre>
<p>For example:</p>
<pre class="prettyprint">vertx run mongo-persistor -conf my_conf.json
</pre>
<p>Or programmatically (e.g. in JavaScript)</p>
<pre class="prettyprint">vertx.deployVerticle(<bus_mode_name>, <config>);
</pre>
<p>For example:</p>
<pre class="prettyprint">vertx.deployVerticle('mongo-persistor', {address: 'test.mypersistor', db_name: 'mydb'});
</pre>
<h3 id="web-server">Web Server</h3><br/>
<p>This is a simple web server which efficiently serves files from the file system.</p>
<p>It can also be configured to act as an event bus bridge - bridging the server side event bus to client side JavaScript.</p>
<h4 id="name">Name</h4><br/>
<p>The module name is <code>web-server</code>.</p>
<h4 id="configuration_1">Configuration</h4><br/>
<p>The web-server configuration is as follows:</p>
<pre class="prettyprint">{
"web_root": <web_root>,
"index_page": <index_page>,
"host", <host>,
"port", <port>
"static_files": <static_files>,
"ssl": <ssl>,
"key_store_password": <key_store_password>,
"key_store_path": <key_store_path>,
"bridge": <bridge>,
"permitted": <permitted>,
"sjs_config": <sjs_config>,
"users_collection": <users_collection>,
"persistor_address": <persistor_address>
}
</pre>
<ul>
<li><code>web-root</code>. This is the root directory from where files will be served. <em>Anything that you place here or in sub directories will be externally accessible</em>. Default is <code>web</code>.</li>
<li><code>index_page</code>. The page to serve when the root <code>/</code> is requested. Default is <code>index.html</code>.</li>
<li><code>host</code>. The host or ip address to listen at for connections. <code>0.0.0.0</code> means listen at all available addresses. Default is <code>0.0.0.0</code>.</li>
<li><code>port</code>. The port to listen at for connections. Default is <code>80</code>.</li>
<li><code>static_files</code>. Should the server serve static files? Default is <code>true</code>. </li>
<li><code>ssl</code>. Should the server use <code>https</code> as a protocol? Default is <code>false</code>.</li>
<li><code>key_store_password</code>. Password of Java keystore which holds the server certificate. Only used if <code>ssl</code> is <code>true</code>. Default is <code>wibble</code>.</li>
<li><code>key_store_path</code>. Path to keystore which holds the server certificate. Default is <code>server-keystore.jks</code>. Only used if <code>ssl</code> is <code>true</code>. <em>Don't put the keystore under your webroot!</em>.</li>
<li><code>bridge</code>. Should the server also act as an event bus bridge. This is used when you want to bridge the event bus into client side JavaScript. Default is <code>false</code>.</li>
<li><code>permitted</code>. This is an array of JSON objects representing the permitted matches on the bridge. Only used if <code>bridge</code> is <code>true</code>. See the core manual for a full description of what these are. Defaults to <code>[]</code>.</li>
<li><code>sjs_config</code>. This is a JSON object representing the configuration of the SockJS bridging application. You'd normally use this for specifying the url at which SockJS will connect to bridge from client side JS to the server. Only used if <code>bridge</code> is <code>true</code>. Default to <code>{"prefix": "/eventbus"}</code>.</li>
<li><code>users_collection</code>. The bridge can also handle login for any client side JS applications that use the event bus. This parameter represents the collection in the MongoDB database that will be used for looking up usernames and passwords. Only used if <code>bridge</code> is <code>true</code>. Default value is <code>users</code>. </li>
<li><code>persistor_address</code>. The bridge can also handle login for any client side JS applications that use the event bus. This parameter represents the address on the event bus of the <code>mongo-persistor</code> module that will be used for looking up usernames and passwords. Only used if <code>bridge</code> is <code>true</code>. Default value is <code>vertx.mongopersistor</code>. <br/>
</li>
</ul>
<h5 id="examples">Examples</h5><br/>
<p>Here are some example:</p>
<h5 id="simple-static-file-web-server">Simple static file web server</h5><br/>
<p>This serves files from the web directory </p>
<pre class="prettyprint">{
"host": mycompany.com
{
</pre>
<h5 id="simple-https-server">Simple https server</h5><br/>
<pre class="prettyprint">{
"host": mycompany.com,
"ssl": true,
"key_store_path": "mycert.jks",
"key_store_password": "sausages"
}
</pre>
<h5 id="event-bus-bridge">Event bus bridge</h5><br/>
<p>Pure event bus bridge that doesn't serve static files</p>
<pre class="prettyprint">{
"host": "bridgeserver.mycompany.com",
"static_files": false,
"bridge": true,
"permitted": [{"address":"myservice"}]
}
</pre>
<h3 id="mongodb-persistor">MongoDB Persistor</h3><br/>
<p>This busmod allows data to be saved, retrieved, searched for, and deleted in a MongoDB instance. MongoDB is a great match for persisting vert.x data since it natively handles JSON (BSON) documents. To use this busmod you must be have a MongoDB instance running on your network.</p>
<p>This is a worker busmod and must be started as a worker verticle.</p>
<h4 id="dependencies">Dependencies</h4><br/>
<p>This busmod requires a MongoDB server to be available on the network.</p>
<h4 id="name_1">Name</h4><br/>
<p>The module name is <code>mongo-persistor</code>.</p>
<h4 id="configuration_2">Configuration</h4><br/>
<p>The mongo-persistor busmod takes the following configuration:</p>
<pre class="prettyprint">{
"address": <address>,
"host": <host>,
"port": <port>
"db_name": <db_name>
}
</pre>
<p>For example:</p>
<pre class="prettyprint">{
"address": "test.my_persistor",
"host": "192.168.1.100",
"port": 27000
"db_name": "my_db"
}
</pre>
<p>Let's take a look at each field in turn:</p>
<ul>
<li><code>address</code> The main address for the busmod. Every busmod has a main address. Defaults to <code>vertx.mongopersistor</code>.</li>
<li><code>host</code> Host name or ip address of the MongoDB instance. Defaults to <code>localhost</code>.</li>
<li><code>port</code> Port at which the MongoDB instance is listening. Defaults to <code>27017</code>.</li>
<li><code>db_name</code> Name of the database in the MongoDB instance to use. Defaults to <code>default_db</code>.</li>
</ul>
<h4 id="operations">Operations</h4><br/>
<p>The busmod supports the following operations</p>
<h5 id="save">Save</h5><br/>
<p>Saves a document in the database.</p>
<p>To save a document send a JSON message to the busmod main address:</p>
<pre class="prettyprint">{
"action": "save",
"collection": <collection>,
"document": <document>
}
</pre>
<p>Where:
<em> <code>collection</code> is the name of the MongoDB collection that you wish to save the document in. This field is mandatory.
</em> <code>document</code> is the JSON document that you wish to save.</p>
<p>An example would be:</p>
<pre class="prettyprint">{
"action": "save",
"collection": "users",
"document": {
"name": "tim",
"age": 1000,
"shoesize", 3.14159,
"username", "tim",
"password", "wibble"
}
}
</pre>
<p>When the save complete successfully, a reply message is sent back to the sender with the following data:</p>
<pre class="prettyprint">{
"status": "ok"
}
</pre>
<p>The reply will also contain a field <code>_id</code> if the document that was saved didn't specifiy an id, this will be an automatically generated UUID, for example:</p>
<pre class="prettyprint">{
"status": "ok"
"_id": "ffeef2a7-5658-4905-a37c-cfb19f70471d"
}
</pre>
<p>If you save a document which already possesses an <code>_id</code> field, and a document with the same id already exists in the database, then the document will be updated. </p>
<p>If an error occurs in saving the document a reply is returned:</p>
<pre class="prettyprint">{
"status": "error",
"message": <message>
}
</pre>
<p>Where <code>message</code> is an error message. <br/>
</p>
<h5 id="find">Find</h5><br/>
<p>Finds matching documents in the database.</p>
<p>To find documents send a JSON message to the busmod main address:</p>
<pre class="prettyprint">{
"action": "find",
"collection": <collection>,
"match": <match>,
"limit": <limit>,
"batch_size": <batch_size>
}
</pre>
<p>Where:
<em> <code>collection</code> is the name of the MongoDB collection that you wish to search in in. This field is mandatory.
</em> <code>match</code> is a JSON object that you want to match against to find matching documents. This obeys the normal MongoDB matching rues.
<em> <code>limit</code> is a number which determines the maximum total number of documents to return. This is optional. By default all documents are returned.
</em> <code>batch_size</code> is a number which determines how many documents to return in each reply JSON message. It's optional and the default value is <code>100</code>. Batching is discussed in more detail below.</p>
<p>An example would be:</p>
<pre class="prettyprint">{
"action": "find",
"collection": "orders",
"match": {
"item": "cheese"
}
}
</pre>
<p>This would return all orders where the <code>item</code> field has the value <code>cheese</code>. </p>
<p>When the find complete successfully, a reply message is sent back to the sender with the following data:</p>
<pre class="prettyprint">{
"status": "ok",
"results": <results>
}
</pre>
<p>Where <code>results</code> is a JSON array containing the results of the find operation. For example:</p>
<pre class="prettyprint">{
"status": "ok",
"results": [
{
"user": "tim",
"item": "cheese",
"total": 123.45
},
{
"user": "bob",
"item": "cheese",
"total": 12.23
},
{
"user": "jane",
"item": "cheese",
"total": 50.05
}
]
}
</pre>
<p>If an error occurs in finding the documents a reply is returned:</p>
<pre class="prettyprint">{
"status": "error",
"message": <message>
}
</pre>
<p>Where <code>message</code> is an error message. </p>
<h6 id="batching">Batching</h6><br/>
<p>If a find returns many documents we do not want to load them all up into memory at once and send them in a single JSON message since this could result in the server running out of RAM.</p>
<p>Instead, if there are more than <code>batch_size</code> documents to be found, the busmod will send a maxium of <code>batch_size</code> documents in each reply, and send multiple replies.</p>
<p>When you receive a reply to the find message containing <code>batch_size</code> documents the <code>status</code> field of the reply will be set to <code>more-exist</code> if there are more documents available.</p>
<p>To get the next batch of documents you just reply to the reply with an empty JSON message, and specify a reply handler in which to receive the next batch.</p>
<p>For instance, in JavaScript you might do something like:</p>
<pre class="prettyprint">function processResults(results) {
// Process the data
}
function createReplyHandler() {
return new function(reply, replier) {
// Got some results - process them
processResults(reply.results);
if (reply.status === 'more-exist') {
// Get next batch
replier({}, createReplyHandler());
}
}
}
// Send the find request
eb.send('foo.myPersistor', {
action: 'find',
collection: 'items',
matcher: {}
}, createReplyHandler());
</pre>
<p>If there is more data to be requested and you do not reply to get the next batch within a timeout (10 seconds), then the underlying MongoDB cursor will be closed, and any further attempts to request more will fail. <br/>
</p>
<h5 id="find-one">Find One</h5><br/>
<p>Finds a single matching document in the database.</p>
<p>To find a document send a JSON message to the busmod main address:</p>
<pre class="prettyprint">{
"action": "findone",
"collection": <collection>,
"match": <match>
}
</pre>
<p>Where:
<em> <code>collection</code> is the name of the MongoDB collection that you wish to search in in. This field is mandatory.
</em> <code>match</code> is a JSON object that you want to match against to find a matching document. This obeys the normal MongoDB matching rues.</p>
<p>If more than one document matches, just the first one will be returned.</p>
<p>An example would be:</p>
<pre class="prettyprint">{
"action": "findone",
"collection": "items",
"match": {
"_id": "ffeef2a7-5658-4905-a37c-cfb19f70471d"
}
}
</pre>
<p>This would return the item with the specified id.</p>
<p>When the find complete successfully, a reply message is sent back to the sender with the following data:</p>
<pre class="prettyprint">{
"status": "ok",
"result": <result>
}
</pre>
<p>If an error occurs in finding the documents a reply is returned:</p>
<pre class="prettyprint">{
"status": "error",
"message": <message>
}
</pre>
<p>Where <code>message</code> is an error message. </p>
<h5 id="delete">Delete</h5><br/>
<p>Deletes a matching documents in the database.</p>
<p>To delete documents send a JSON message to the busmod main address:</p>
<pre class="prettyprint">{
"action": "delete",
"collection": <collection>,
"match": <match>
}
</pre>
<p>Where:
<em> <code>collection</code> is the name of the MongoDB collection that you wish to delete from. This field is mandatory.
</em> <code>match</code> is a JSON object that you want to match against to delete matching documents. This obeys the normal MongoDB matching rues.</p>
<p>All documents that match will be deleted.</p>
<p>An example would be:</p>
<pre class="prettyprint">{
"action": "delete",
"collection": "items",
"match": {
"_id": "ffeef2a7-5658-4905-a37c-cfb19f70471d"
}
}
</pre>
<p>This would delete the item with the specified id.</p>
<p>When the find complete successfully, a reply message is sent back to the sender with the following data:</p>
<pre class="prettyprint">{
"status": "ok",
"number": <number>
}
</pre>
<p>Where <code>number</code> is the number of documents deleted. <br/>
</p>
<p>If an error occurs in finding the documents a reply is returned:</p>
<pre class="prettyprint">{
"status": "error",
"message": <message>
}
</pre>
<p>Where <code>message</code> is an error message. </p>
<h3 id="mailer">Mailer</h3><br/>
<p>This busmod allows emails to be sent via SMTP.</p>
<h4 id="dependencies_1">Dependencies</h4><br/>
<p>This busmod requires a mail server to be available.</p>
<h4 id="name_2">Name</h4><br/>
<p>The module name is <code>mailer</code>.</p>
<h4 id="configuration_3">Configuration</h4><br/>
<p>The mailer busmod requires the following configuration:</p>
<pre class="prettyprint">{
"address": <address>,
"host": <host>,
"port": <port>,
"ssl": <ssl>,
"auth": <auth>,
"username": <username>,
"password": <password>
}
</pre>
<p>Let's take a look at each field in turn:</p>
<ul>
<li><code>address</code> The main address for the busmod. Every busmod has a main address.</li>
<li><code>host</code> Host name or ip address of the maile server instance. Defaults to <code>localhost</code>.</li>
<li><code>port</code> Port at which the mail server is listening. Defaults to <code>25</code>.</li>
<li><code>ssl</code> If <code>true</code> then use ssl, otherwise don't use ssl. Default is <code>false</code>.</li>
<li><code>auth</code> If <code>true</code> use authentication, otherwise don't use authentication. Default is <code>false</code>.</li>
<li><code>username</code> If using authentication, the username. Default is <code>null</code>.</li>
<li><code>password</code> If using authentication, the password. Default is <code>null</code>.</li>
</ul>
<p>For example, to send to a local server on port 25:</p>
<pre class="prettyprint">{
"address": "test.my_mailer"
}
</pre>
<p>Or to a gmail account:</p>
<pre class="prettyprint">{
"address": "test.my_mailer"
"host": "smtp.googlemail.com",
"port": 465,
"ssl": true,
"auth": true,
"username": "tim",
"password": "password"
}
</pre>
<h4 id="sending-emails">Sending Emails</h4><br/>
<p>To send an email just send a JSON message to the main address of the mailer. The JSON message representing the email should have the following structure:</p>
<pre class="prettyprint">{
"from": <from>,
"to": <to|to_list>,
"cc": <cc|cc_list>
"bcc": <bcc|bcc_list>
"subject": <subject>
"body": <body>
}
</pre>
<p>Where:</p>
<ul>
<li><code>from</code> is the sender address of the email. Must be a well-formed email address.</li>
<li><code>to</code> to is either a single well formed email address representing the recipient or a JSON array of email addresses representing the recipients. This field is mandatory.</li>
<li><code>cc</code> to is either a single well formed email address representing a cc recipient or a JSON array of email addresses representing the cc list. This field is optional.</li>
<li><code>bcc</code> to is either a single well formed email address representing a bcc recipient or a JSON array of email addresses representing the bcc list. This field is optional.</li>
<li><code>subject</code> is the subject of the email. This field is mandatory.</li>
<li><code>body</code> is the body of the email. This field is mandatory.</li>
</ul>
<p>For example, to send a mail to a single recipient:</p>
<pre class="prettyprint">{
"from": "tim@wibble.com",
"to": "bob@wobble.com",
"subject": "Congratulations on your new armadillo!",
"body": "Dear Bob, great to here you have purchased......"
}
</pre>
<p>Or to send to multiple recipients:</p>
<pre class="prettyprint">{
"from": "tim@wibble.com",
"to": ["bob@wobble.com", "jane@tribble.com"],
"subject": "Sadly, my aardvark George, has been arrested.",
"body": "All, I'm afraid George was found...."
}
</pre>
<h3 id="authentication-manager">Authentication Manager</h3><br/>
<p>This busmod verifies usernames and passwords in a MongoDB database and generates time-limited session ids. These session ids can be passed around the event bus.</p>
<p>The authentication manager can also verify a session id. This allows session ids to be passed around the event bus and validated if particular busmods want to find out if the user is logged in.</p>
<p>A typical usage would be:</p>
<ul>
<li>Login with username and password. Obtain session id.</li>
<li>Do something (e.g. place an order). Pass session id with order message.</li>
<li>Order busmod verifies session id before placing order. If verifies ok, then order is allowed to be placed.</li>
</ul>
<p>Sessions time out after a certain amount of time. After that time, they will not verify as ok.</p>
<p>This busmod should not be run as a worker.</p>
<h4 id="dependencies_2">Dependencies</h4><br/>
<p>This busmod requires a MongoDB persistor busmod to be running to allow searching for usernames and passwords.</p>
<h4 id="name_3">Name</h4><br/>
<p>The module name is <code>auth-mgr</code>.</p>
<h4 id="configuration_4">Configuration</h4><br/>
<p>This busmod requires the following configuration:</p>
<pre class="prettyprint">{
"address": <address>,
"user_collection": <user_collection>,
"persistor_address": <persistor_address>,
"session_timeout": <session_timeout>
}
</pre>
<p>For example:</p>
<pre class="prettyprint">{
"address": "test.my_authmgr",
"user_collection": "users",
"persistor_address": "test.my_persistor",
"session_timeout": 900000
}
</pre>
<p>Let's take a look at each field in turn:</p>
<ul>
<li><code>address</code> The main address for the busmod. Every busmod has a main address.</li>
<li><code>user_collection</code> The MongoDB collection in which to search for usernames and passwords. This field is mandatory.</li>
<li><code>persistor_address</code> Address of the persistor busmod to use for usernames and passwords. This field is mandatory.</li>
<li><code>session_timeout</code> Timeout of a session, in milliseconds. This field is optional. Default value is <code>1800000</code> (30 minutes).</li>
</ul>
<h4 id="operations_1">Operations</h4><br/>
<h5 id="login">Login</h5><br/>
<p>Login with a username and password and obtain a session id if successful.</p>
<p>To login, send a JSON message to the address given by the main address of the busmod + <code>.login</code>. For example if the main address is <code>test.authManager</code>, you send the message to <code>test.authManager.login</code>.</p>
<p>The JSON message should have the following structure:</p>
<pre class="prettyprint">{
"username": <username>,
"password": <password>
}
</pre>
<p>If login is successful a reply will be returned:</p>
<pre class="prettyprint">{
"status": "ok",
"sessionID": <sesson_id>
}
</pre>
<p>Where <code>session_id</code> is a unique session id.</p>
<p>If login is unsuccessful the following reply will be returned:</p>
<pre class="prettyprint">{
"status": "denied"
}
</pre>
<h5 id="logout">Logout</h5><br/>
<p>Logout and close a session. Any subsequent attempts to validate the session id will fail.</p>
<p>To login, send a JSON message to the address given by the main address of the busmod + <code>.logout</code>. For example if the main address is <code>test.authManager</code>, you send the message to <code>test.authManager.logout</code>.</p>
<p>The JSON message should have the following structure:</p>
<pre class="prettyprint">{
"sessionID": <session_id>
}
</pre>
<p>Where <code>session_id</code> is a unique session id. </p>
<p>If logout is successful the following reply will be returned:</p>
<pre class="prettyprint">{
"status": "ok"
}
</pre>
<p>Otherwise, if the session id is not known about:</p>
<pre class="prettyprint">{
"status": "error"
}
</pre>
<h5 id="validate">Validate</h5><br/>
<p>Validates a session id.</p>
<p>To validate, send a JSON message to the address given by the main address of the busmod + <code>.validate</code>. For example if the main address is <code>test.authManager</code>, you send the message to <code>test.authManager.validate</code>.</p>
<p>The JSON message should have the following structure:</p>
<pre class="prettyprint">{
"sessionID": <session_id>
}
</pre>
<p>Where <code>session_id</code> is a unique session id. </p>
<p>If the session is valid the following reply will be returned:</p>
<pre class="prettyprint">{
"status": "ok",
"username": <username>
}
</pre>
<p>Where <code>username</code> is the username of the user. <br/>
</p>
<p>Otherwise, if the session is not valid. I.e. it has expired or never existed in the first place.</p>
<pre class="prettyprint">{
"status": "denied"
}
</pre>
<h3 id="work-queue">Work Queue</h3><br/>
<p>This busmod queues messages (work) sent to it, and then forwards the work to one of many processors that may be attached to it, if available.</p>
<p>Once a processor has processed the work, it replies to the message and when the work queue receives the reply it removes the work from the queue. The processor can time out in processing a message, in which case the message becomes available again for other processors to consume.</p>
<p>Multiple processors can register for work with the work queue.</p>
<p>The work queue is useful for use cases where you have a lot of work to process and want to share this work out amongst many processors.</p>
<p>One example would be processing an order queue - each order must only be processed once, but we can have many processors (potentially on different machines) processing each order.</p>
<p>Another example would be in computational intensive tasks where the task can be split into N pieces and processed in parallel by different nodes. In other words, a compute cluster.</p>
<p>This busmod should not be run as a worker.</p>
<h4 id="dependencies_3">Dependencies</h4><br/>
<p>If this queue is persistent, the busmod requires a MongoDB persistor busmod to be running for persisting the queue data. [WIP]</p>
<h4 id="name_4">Name</h4><br/>
<p>The module name is <code>work-queue</code>.</p>
<h4 id="configuration_5">Configuration</h4><br/>
<p>This busmod requires the following configuration:</p>
<pre class="prettyprint">{
"address": <address>,
"process_timeout": <process_timeout>,
"persistor_address": <persistor_address>,
"collection": <collection>
}
</pre>
<p>Where: <br/>
</p>
<ul>
<li><code>address</code> The main address for the busmod. Every busmod has a main address.</li>
<li><code>process_timeout</code> The processing timeout, in milliseconds for each item of work. If work is not processed before the timeout, it is returned to the queue and made available to other processors. This field is optional. Default value is <code>300000</code> (5 minutes).</li>
<li><code>persistor_address</code> If specified, this queue is persistent and this is the address of the persistor busmod to use for persistence. This field is optional.</li>
<li><code>collection</code> If persistent, the collection in the persistor where to persist the queue. This field is optional.</li>
</ul>
<p>An example, non persistent configuration would be:</p>
<pre class="prettyprint">{
"address": "test.orderQueue"
}
</pre>
<p>An example, persistent configuration would be:</p>
<pre class="prettyprint">{
"address": "test.orderQueue",
"persistor_address": "test.myPersistor",
"collection": "order_queue"
}
</pre>
<h4 id="operations_2">Operations</h4><br/>
<h5 id="send">Send</h5><br/>
<p>To send data to the work queue, just send a JSON message to the main address of the busmod. The JSON message can have any structure you like - the work queue does not look at it.</p>
<p>Once the send has been accepted, and queued a reply message will be sent:</p>
<pre class="prettyprint">{
"status": "ok"
}
</pre>
<p>If a problem occurs with the queueing, an error reply will be sent:</p>
<pre class="prettyprint">{
"status": "error"
"message": <message>
}
</pre>
<p>Where <code>message</code> is an error message. <br/>
</p>
<h5 id="register">Register</h5><br/>
<p>This is how a processor registers with the work queue. A processor is just an arbitrary handler on the event bus. To register itselfs as a processor, a JSON message is sent to the address given by the main address of the busmod + <code>.register</code>. For example if the main address is <code>test.orderQueue</code>, you send the message to <code>test.orderQueue.register</code>.</p>
<p>The message should have the following structure:</p>
<pre class="prettyprint">{
"processor": <processor>
}
</pre>
<p>Where <code>processor</code> is the address of the processors handler. For example, if the processor has registered a handler at address <code>processor1</code>, then it would send the message:</p>
<pre class="prettyprint">{
"processor": "processor1"
}
</pre>
<p>When this message is received at the work queue, the work queue registers this address as a processor interested in work. When work arrives it will send the work off to any available processors, in a round-robin fashion.</p>
<p>When a processor receives some work, and has completed its processing. It should reply to the message with an empty reply. This tells the work queue that the work has been processed and can be forgotten about. If a reply is not received within <code>process_timeout</code> milliseconds then it will be assumed that the processor failed, and the work will be made available for other processors to process.</p>
<p>Once the register is complete, a reply message will be sent:</p>
<pre class="prettyprint">{
"status": "ok"
}
</pre>
<h5 id="unregister">Unregister</h5><br/>
<p>This is how a processor unregisters with the work queue. To unregister itselfs as a processor, a JSON message is sent to the address given by the main address of the busmod + <code>.unregister</code>. For example if the main address is <code>test.orderQueue</code>, you send the message to <code>test.orderQueue.unregister</code>.</p>
<p>The message should have the following structure:</p>
<pre class="prettyprint">{
"processor": <processor>
}
</pre>
<p>Once the work queue receives the message, the processor will be unregistered and will receive no more work from the queue.</p>
<p>Once the unregister is complete, a reply message will be sent:</p>
<pre class="prettyprint">{
"status": "ok"
}
</pre>
<p><em>Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.</em></p></div>
</div>
</div>
</div>
</div>
</body>
</html>