├── .bithound ├── .eslintrc.js ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.MD ├── docs ├── StompServer.html ├── fonts │ ├── OpenSans-Bold-webfont.eot │ ├── OpenSans-Bold-webfont.svg │ ├── OpenSans-Bold-webfont.woff │ ├── OpenSans-BoldItalic-webfont.eot │ ├── OpenSans-BoldItalic-webfont.svg │ ├── OpenSans-BoldItalic-webfont.woff │ ├── OpenSans-Italic-webfont.eot │ ├── OpenSans-Italic-webfont.svg │ ├── OpenSans-Italic-webfont.woff │ ├── OpenSans-Light-webfont.eot │ ├── OpenSans-Light-webfont.svg │ ├── OpenSans-Light-webfont.woff │ ├── OpenSans-LightItalic-webfont.eot │ ├── OpenSans-LightItalic-webfont.svg │ ├── OpenSans-LightItalic-webfont.woff │ ├── OpenSans-Regular-webfont.eot │ ├── OpenSans-Regular-webfont.svg │ └── OpenSans-Regular-webfont.woff ├── global.html ├── index.html ├── scripts │ ├── linenumber.js │ └── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js ├── stompServer.js.html └── styles │ ├── jsdoc-default.css │ ├── prettify-jsdoc.css │ └── prettify-tomorrow.css ├── examples ├── default │ ├── example.js │ ├── stomp-consumer.js │ ├── stomp-producer.js │ └── test.html └── sockjs │ ├── client.js │ ├── index.html │ ├── package.json │ ├── readme.md │ └── server.js ├── jsdoc-conf.json ├── lib ├── adapter │ └── index.js ├── bytes.js ├── config.js ├── frame.js ├── stomp-utils.js └── stomp.js ├── package.json ├── stompServer.js └── test └── test.js /.bithound: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["examples/**/*.js"] 3 | } -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "commonjs": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "globals": { 9 | "Atomics": "readonly", 10 | "SharedArrayBuffer": "readonly" 11 | }, 12 | "parserOptions": { 13 | "ecmaVersion": 2018 14 | }, 15 | "rules": { 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE 2 | *.iml 3 | .idea/* 4 | .vimrc 5 | .vscode/* 6 | 7 | *.log 8 | 9 | # Directories 10 | node_modules/ 11 | 12 | # Lock files 13 | package-lock.json 14 | 15 | # OS files 16 | .DS_Store 17 | **/Thumbs.db 18 | 19 | #template for documentation 20 | template.md 21 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | - "6" 5 | - "5" 6 | - "4" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Adrian Sławiński 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # StompBrokerJS 2 | NodeJS StompBroker 3 | 4 | This is simple NodeJs STOMP 1.1 broker for embedded usage. 5 | 6 | [![build state](https://travis-ci.org/4ib3r/StompBrokerJS.svg?branch=master)](https://travis-ci.org/4ib3r/StompBrokerJS) 7 | [![Support](https://beerpay.io/4ib3r/StompBrokerJS/badge.svg?style=flat-square)](https://beerpay.io/4ib3r/StompBrokerJS) 8 | # Features 9 | * Destination wildcards 10 | * . is used to separate names in a path 11 | * \* is used to mach any name in a path 12 | * \*\* is used to recursively match path names 13 | 14 | # TODO 15 | * Authorization 16 | * Acknowledgment 17 | * Async send messages 18 | * Transactions 19 | * Composite Destinations 20 | * Message selectors 21 | 22 | # Changelog 23 | * 0.1.0 First working version. 24 | * 0.1.1 Added wildcards to destination, change subscribe method [no backward compatibility] 25 | * 0.1.2 Bug fixes, changed websocket library, updated documentation. 26 | * 0.1.3 Unsubscribe on server, updated documentation, added events. 27 | 28 | # Example 29 | ```javascript 30 | var http = require("http"); 31 | var StompServer = require('stomp-broker-js'); 32 | 33 | var server = http.createServer(); 34 | var stompServer = new StompServer({server: server}); 35 | 36 | server.listen(61614); 37 | 38 | stompServer.subscribe("/**", function(msg, headers) { 39 | var topic = headers.destination; 40 | console.log(topic, "->", msg); 41 | }); 42 | 43 | stompServer.send('/test', {}, 'testMsg'); 44 | ``` 45 | # Documentation 46 | -------------------------------------------------------------------------------- /docs/StompServer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | StompServer - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

StompServer

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 |

45 | StompServer 46 |

47 | 48 | 49 |
50 | 51 |
52 |
53 | 54 | 55 |
56 | 57 | 58 | 59 |

new StompServer(config)

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 |
Source:
97 |
100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 |
Parameters:
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 | 153 | 154 | 155 | 156 | 157 | 158 | 162 | 163 | 164 | 165 | 166 |
NameTypeDescription
config 146 | 147 | 148 | ServerConfig 149 | 150 | 151 | 152 | 159 |

Configuration for STOMP server

160 | 161 |
167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 |
184 | 185 |
186 | 187 | 188 |

Extends

189 | 190 | 191 | 192 | 193 |
    194 |
  • EventEmitter
  • 195 |
196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 |

Members

210 | 211 | 212 | 213 |
214 |

send

215 | 216 | 217 | 218 | 219 |
220 |

Send message to topic

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 |
Source:
255 |
258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 |
266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 |
274 | 275 | 276 | 277 | 278 | 279 |

Methods

280 | 281 | 282 | 283 |
284 | 285 | 286 | 287 |

(private) _checkSubMatchDest(sub, args) → {boolean}

288 | 289 | 290 | 291 | 292 | 293 |
294 |

Test if the input subscriber has subscribed to the target destination.

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 |
Source:
329 |
332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 |
340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 |
Parameters:
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 | 380 | 381 | 382 | 383 | 384 | 385 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 401 | 402 | 403 | 404 | 405 | 406 | 410 | 411 | 412 | 413 | 414 |
NameTypeDescription
sub 378 | 379 | 386 |

the subscriber

387 | 388 |
args 399 | 400 | 407 |

onSend args

408 | 409 |
415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 |
430 |
Returns:
431 | 432 | 433 | 434 |
435 |
436 | Type: 437 |
438 |
439 | 440 | boolean 441 | 442 | 443 |
444 |
445 | 446 | 447 |
448 |

true if the input subscription matches destination

449 |
450 | 451 | 452 |
453 | 454 | 455 | 456 |
457 | 458 | 459 |
460 | 461 | 462 | 463 |

(private) _sendToSubscriptions(socket, args)

464 | 465 | 466 | 467 | 468 | 469 |
470 |

Send message to matching subscribers.

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 |
Source:
505 |
508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 |
516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 |
Parameters:
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 | 561 | 562 | 563 | 564 | 565 | 566 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 587 | 588 | 589 | 590 | 591 | 592 | 596 | 597 | 598 | 599 | 600 |
NameTypeDescription
socket 554 | 555 | 556 | object 557 | 558 | 559 | 560 | 567 |

websocket to send the message on

568 | 569 |
args 580 | 581 | 582 | string 583 | 584 | 585 | 586 | 593 |

onSend args

594 | 595 |
601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 |
618 | 619 | 620 |
621 | 622 | 623 | 624 |

addMiddleware(command, handler)

625 | 626 | 627 | 628 | 629 | 630 |
631 |

Add middle-ware for specific command

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 |
Source:
666 |
669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 |
677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 |
Parameters:
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 | 734 | 735 | 736 | 737 | 738 | 739 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 760 | 761 | 762 | 763 | 764 | 765 | 769 | 770 | 771 | 772 | 773 |
NameTypeDescription
command 715 | 716 | 717 | 'connect' 718 | | 719 | 720 | 'disconnect' 721 | | 722 | 723 | 'send' 724 | | 725 | 726 | 'subscribe' 727 | | 728 | 729 | 'unsubscribe' 730 | 731 | 732 | 733 | 740 |

Command to hook

741 | 742 |
handler 753 | 754 | 755 | function 756 | 757 | 758 | 759 | 766 |

function to add in middle-ware

767 | 768 |
774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 |
791 | 792 | 793 |
794 | 795 | 796 | 797 |

afterConnectionClose(socket)

798 | 799 | 800 | 801 | 802 | 803 |
804 |

After connection close

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 |
Source:
839 |
842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 |
850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 |
Parameters:
860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 890 | 891 | 892 | 893 | 894 | 895 | 899 | 900 | 901 | 902 | 903 |
NameTypeDescription
socket 888 | 889 | 896 |

WebSocket connection that has been closed and is dying

897 | 898 |
904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 |
921 | 922 | 923 |
924 | 925 | 926 | 927 |

frameParser(frame) → {MsgFrame}

928 | 929 | 930 | 931 | 932 | 933 |
934 |

Parse frame to object for reading

935 |
936 | 937 | 938 | 939 | 940 | 941 |
942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 |
Source:
969 |
972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 |
980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 |
Parameters:
990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1034 | 1035 | 1036 | 1037 | 1038 |
NameTypeDescription
frame 1018 | 1019 | 1020 | MsgFrame 1021 | 1022 | 1023 | 1024 | 1031 |

Message frame

1032 | 1033 |
1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 |
1054 |
Returns:
1055 | 1056 | 1057 | 1058 |
1059 |
1060 | Type: 1061 |
1062 |
1063 | 1064 | MsgFrame 1065 | 1066 | 1067 |
1068 |
1069 | 1070 | 1071 |
1072 |

modified frame

1073 |
1074 | 1075 | 1076 |
1077 | 1078 | 1079 | 1080 |
1081 | 1082 | 1083 |
1084 | 1085 | 1086 | 1087 |

frameSerializer(frame) → {MsgFrame}

1088 | 1089 | 1090 | 1091 | 1092 | 1093 |
1094 |

Serialize frame to string for send

1095 |
1096 | 1097 | 1098 | 1099 | 1100 | 1101 |
1102 | 1103 | 1104 | 1105 | 1106 | 1107 | 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 |
Source:
1129 |
1132 | 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | 1139 |
1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 |
Parameters:
1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | 1174 | 1175 | 1176 | 1177 | 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1194 | 1195 | 1196 | 1197 | 1198 |
NameTypeDescription
frame 1178 | 1179 | 1180 | MsgFrame 1181 | 1182 | 1183 | 1184 | 1191 |

Message frame

1192 | 1193 |
1199 | 1200 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1213 |
1214 |
Returns:
1215 | 1216 | 1217 | 1218 |
1219 |
1220 | Type: 1221 |
1222 |
1223 | 1224 | MsgFrame 1225 | 1226 | 1227 |
1228 |
1229 | 1230 | 1231 |
1232 |

modified frame

1233 |
1234 | 1235 | 1236 |
1237 | 1238 | 1239 | 1240 |
1241 | 1242 | 1243 |
1244 | 1245 | 1246 | 1247 |

heartbeatOff(socket)

1248 | 1249 | 1250 | 1251 | 1252 | 1253 |
1254 |

Heart-beat: Turn Off for given socket

1255 |
1256 | 1257 | 1258 | 1259 | 1260 | 1261 |
1262 | 1263 | 1264 | 1265 | 1266 | 1267 | 1268 | 1269 | 1270 | 1271 | 1272 | 1273 | 1274 | 1275 | 1276 | 1277 | 1278 | 1279 | 1280 | 1281 | 1282 | 1283 | 1284 | 1285 | 1286 | 1287 | 1288 |
Source:
1289 |
1292 | 1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 |
1300 | 1301 | 1302 | 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 1309 |
Parameters:
1310 | 1311 | 1312 | 1313 | 1314 | 1315 | 1316 | 1317 | 1318 | 1319 | 1320 | 1321 | 1322 | 1323 | 1324 | 1325 | 1326 | 1327 | 1328 | 1329 | 1330 | 1331 | 1332 | 1333 | 1334 | 1335 | 1336 | 1337 | 1345 | 1346 | 1347 | 1348 | 1349 | 1350 | 1354 | 1355 | 1356 | 1357 | 1358 |
NameTypeDescription
socket 1338 | 1339 | 1340 | WebSocket 1341 | 1342 | 1343 | 1344 | 1351 |

Destination WebSocket

1352 | 1353 |
1359 | 1360 | 1361 | 1362 | 1363 | 1364 | 1365 | 1366 | 1367 | 1368 | 1369 | 1370 | 1371 | 1372 | 1373 | 1374 | 1375 |
1376 | 1377 | 1378 |
1379 | 1380 | 1381 | 1382 |

heartbeatOn(socket, interval, serverSide)

1383 | 1384 | 1385 | 1386 | 1387 | 1388 |
1389 |

Heart-beat: Turn On for given socket

1390 |
1391 | 1392 | 1393 | 1394 | 1395 | 1396 |
1397 | 1398 | 1399 | 1400 | 1401 | 1402 | 1403 | 1404 | 1405 | 1406 | 1407 | 1408 | 1409 | 1410 | 1411 | 1412 | 1413 | 1414 | 1415 | 1416 | 1417 | 1418 | 1419 | 1420 | 1421 | 1422 | 1423 |
Source:
1424 |
1427 | 1428 | 1429 | 1430 | 1431 | 1432 | 1433 | 1434 |
1435 | 1436 | 1437 | 1438 | 1439 | 1440 | 1441 | 1442 | 1443 | 1444 |
Parameters:
1445 | 1446 | 1447 | 1448 | 1449 | 1450 | 1451 | 1452 | 1453 | 1454 | 1455 | 1456 | 1457 | 1458 | 1459 | 1460 | 1461 | 1462 | 1463 | 1464 | 1465 | 1466 | 1467 | 1468 | 1469 | 1470 | 1471 | 1472 | 1480 | 1481 | 1482 | 1483 | 1484 | 1485 | 1489 | 1490 | 1491 | 1492 | 1493 | 1494 | 1495 | 1496 | 1497 | 1498 | 1506 | 1507 | 1508 | 1509 | 1510 | 1511 | 1515 | 1516 | 1517 | 1518 | 1519 | 1520 | 1521 | 1522 | 1523 | 1524 | 1532 | 1533 | 1534 | 1535 | 1536 | 1537 | 1541 | 1542 | 1543 | 1544 | 1545 |
NameTypeDescription
socket 1473 | 1474 | 1475 | WebSocket 1476 | 1477 | 1478 | 1479 | 1486 |

Destination WebSocket

1487 | 1488 |
interval 1499 | 1500 | 1501 | number 1502 | 1503 | 1504 | 1505 | 1512 |

Heart-beat interval

1513 | 1514 |
serverSide 1525 | 1526 | 1527 | boolean 1528 | 1529 | 1530 | 1531 | 1538 |

If true then server is responsible for sending pings

1539 | 1540 |
1546 | 1547 | 1548 | 1549 | 1550 | 1551 | 1552 | 1553 | 1554 | 1555 | 1556 | 1557 | 1558 | 1559 | 1560 | 1561 | 1562 |
1563 | 1564 | 1565 |
1566 | 1567 | 1568 | 1569 |

removeMiddleware(command, handler)

1570 | 1571 | 1572 | 1573 | 1574 | 1575 |
1576 |

Remove middle-ware specific for command

1577 |
1578 | 1579 | 1580 | 1581 | 1582 | 1583 |
1584 | 1585 | 1586 | 1587 | 1588 | 1589 | 1590 | 1591 | 1592 | 1593 | 1594 | 1595 | 1596 | 1597 | 1598 | 1599 | 1600 | 1601 | 1602 | 1603 | 1604 | 1605 | 1606 | 1607 | 1608 | 1609 | 1610 |
Source:
1611 |
1614 | 1615 | 1616 | 1617 | 1618 | 1619 | 1620 | 1621 |
1622 | 1623 | 1624 | 1625 | 1626 | 1627 | 1628 | 1629 | 1630 | 1631 |
Parameters:
1632 | 1633 | 1634 | 1635 | 1636 | 1637 | 1638 | 1639 | 1640 | 1641 | 1642 | 1643 | 1644 | 1645 | 1646 | 1647 | 1648 | 1649 | 1650 | 1651 | 1652 | 1653 | 1654 | 1655 | 1656 | 1657 | 1658 | 1659 | 1679 | 1680 | 1681 | 1682 | 1683 | 1684 | 1688 | 1689 | 1690 | 1691 | 1692 | 1693 | 1694 | 1695 | 1696 | 1697 | 1705 | 1706 | 1707 | 1708 | 1709 | 1710 | 1714 | 1715 | 1716 | 1717 | 1718 |
NameTypeDescription
command 1660 | 1661 | 1662 | 'connect' 1663 | | 1664 | 1665 | 'disconnect' 1666 | | 1667 | 1668 | 'send' 1669 | | 1670 | 1671 | 'subscribe' 1672 | | 1673 | 1674 | 'unsubscribe' 1675 | 1676 | 1677 | 1678 | 1685 |

Command with hook

1686 | 1687 |
handler 1698 | 1699 | 1700 | function 1701 | 1702 | 1703 | 1704 | 1711 |

function to remove from middle-ware

1712 | 1713 |
1719 | 1720 | 1721 | 1722 | 1723 | 1724 | 1725 | 1726 | 1727 | 1728 | 1729 | 1730 | 1731 | 1732 | 1733 | 1734 | 1735 |
1736 | 1737 | 1738 |
1739 | 1740 | 1741 | 1742 |

setMiddleware(command, handler)

1743 | 1744 | 1745 | 1746 | 1747 | 1748 |
1749 |

Clear and set middle-ware for specific command

1750 |
1751 | 1752 | 1753 | 1754 | 1755 | 1756 |
1757 | 1758 | 1759 | 1760 | 1761 | 1762 | 1763 | 1764 | 1765 | 1766 | 1767 | 1768 | 1769 | 1770 | 1771 | 1772 | 1773 | 1774 | 1775 | 1776 | 1777 | 1778 | 1779 | 1780 | 1781 | 1782 | 1783 |
Source:
1784 |
1787 | 1788 | 1789 | 1790 | 1791 | 1792 | 1793 | 1794 |
1795 | 1796 | 1797 | 1798 | 1799 | 1800 | 1801 | 1802 | 1803 | 1804 |
Parameters:
1805 | 1806 | 1807 | 1808 | 1809 | 1810 | 1811 | 1812 | 1813 | 1814 | 1815 | 1816 | 1817 | 1818 | 1819 | 1820 | 1821 | 1822 | 1823 | 1824 | 1825 | 1826 | 1827 | 1828 | 1829 | 1830 | 1831 | 1832 | 1852 | 1853 | 1854 | 1855 | 1856 | 1857 | 1861 | 1862 | 1863 | 1864 | 1865 | 1866 | 1867 | 1868 | 1869 | 1870 | 1878 | 1879 | 1880 | 1881 | 1882 | 1883 | 1887 | 1888 | 1889 | 1890 | 1891 |
NameTypeDescription
command 1833 | 1834 | 1835 | 'connect' 1836 | | 1837 | 1838 | 'disconnect' 1839 | | 1840 | 1841 | 'send' 1842 | | 1843 | 1844 | 'subscribe' 1845 | | 1846 | 1847 | 'unsubscribe' 1848 | 1849 | 1850 | 1851 | 1858 |

Command to hook

1859 | 1860 |
handler 1871 | 1872 | 1873 | function 1874 | 1875 | 1876 | 1877 | 1884 |

function to add in middle-ware

1885 | 1886 |
1892 | 1893 | 1894 | 1895 | 1896 | 1897 | 1898 | 1899 | 1900 | 1901 | 1902 | 1903 | 1904 | 1905 | 1906 | 1907 | 1908 |
1909 | 1910 | 1911 |
1912 | 1913 | 1914 | 1915 |

subscribe(topic, callbackopt, headers) → {string}

1916 | 1917 | 1918 | 1919 | 1920 | 1921 |
1922 |

Subscribe topic

1923 |
1924 | 1925 | 1926 | 1927 | 1928 | 1929 |
1930 | 1931 | 1932 | 1933 | 1934 | 1935 | 1936 | 1937 | 1938 | 1939 | 1940 | 1941 | 1942 | 1943 | 1944 | 1945 | 1946 | 1947 | 1948 | 1949 | 1950 | 1951 | 1952 | 1953 | 1954 | 1955 | 1956 |
Source:
1957 |
1960 | 1961 | 1962 | 1963 | 1964 | 1965 | 1966 | 1967 |
1968 | 1969 | 1970 | 1971 | 1972 | 1973 | 1974 | 1975 | 1976 | 1977 |
Parameters:
1978 | 1979 | 1980 | 1981 | 1982 | 1983 | 1984 | 1985 | 1986 | 1987 | 1988 | 1989 | 1990 | 1991 | 1992 | 1993 | 1994 | 1995 | 1996 | 1997 | 1998 | 1999 | 2000 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 | 2007 | 2015 | 2016 | 2017 | 2024 | 2025 | 2026 | 2027 | 2028 | 2032 | 2033 | 2034 | 2035 | 2036 | 2037 | 2038 | 2039 | 2040 | 2041 | 2049 | 2050 | 2051 | 2060 | 2061 | 2062 | 2063 | 2064 | 2068 | 2069 | 2070 | 2071 | 2072 | 2073 | 2074 | 2075 | 2076 | 2077 | 2085 | 2086 | 2087 | 2094 | 2095 | 2096 | 2097 | 2098 | 2102 | 2103 | 2104 | 2105 | 2106 |
NameTypeAttributesDescription
topic 2008 | 2009 | 2010 | string 2011 | 2012 | 2013 | 2014 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2029 |

Subscribed destination, wildcard is supported

2030 | 2031 |
callback 2042 | 2043 | 2044 | OnSubscribedMessageCallback 2045 | 2046 | 2047 | 2048 | 2052 | 2053 | <optional>
2054 | 2055 | 2056 | 2057 | 2058 | 2059 |
2065 |

Callback function

2066 | 2067 |
headers 2078 | 2079 | 2080 | object 2081 | 2082 | 2083 | 2084 | 2088 | 2089 | 2090 | 2091 | 2092 | 2093 | 2099 |

Optional headers, used by client to provide a subscription ID (headers.id)

2100 | 2101 |
2107 | 2108 | 2109 | 2110 | 2111 | 2112 | 2113 | 2114 | 2115 | 2116 | 2117 | 2118 | 2119 | 2120 | 2121 |
2122 |
Returns:
2123 | 2124 | 2125 | 2126 |
2127 |
2128 | Type: 2129 |
2130 |
2131 | 2132 | string 2133 | 2134 | 2135 |
2136 |
2137 | 2138 | 2139 |
2140 |

Subscription id, when message is received event with this id is emitted

2141 |
2142 | 2143 | 2144 |
2145 | 2146 | 2147 | 2148 |
2149 |
Example
2150 | 2151 |
stompServer.subscribe('/test.data', function(msg, headers) {});
2152 | //or alternative
2153 | var subs_id = stompServer.subscribe('/test.data');
2154 | stompServer.on(subs_id, function(msg, headers) {});
2155 | 2156 |
2157 | 2158 |
2159 | 2160 | 2161 |
2162 | 2163 | 2164 | 2165 |

unsubscribe(id) → {boolean}

2166 | 2167 | 2168 | 2169 | 2170 | 2171 |
2172 |

Unsubscribe topic with subscription id

2173 |
2174 | 2175 | 2176 | 2177 | 2178 | 2179 |
2180 | 2181 | 2182 | 2183 | 2184 | 2185 | 2186 | 2187 | 2188 | 2189 | 2190 | 2191 | 2192 | 2193 | 2194 | 2195 | 2196 | 2197 | 2198 | 2199 | 2200 | 2201 | 2202 | 2203 | 2204 | 2205 | 2206 |
Source:
2207 |
2210 | 2211 | 2212 | 2213 | 2214 | 2215 | 2216 | 2217 |
2218 | 2219 | 2220 | 2221 | 2222 | 2223 | 2224 | 2225 | 2226 | 2227 |
Parameters:
2228 | 2229 | 2230 | 2231 | 2232 | 2233 | 2234 | 2235 | 2236 | 2237 | 2238 | 2239 | 2240 | 2241 | 2242 | 2243 | 2244 | 2245 | 2246 | 2247 | 2248 | 2249 | 2250 | 2251 | 2252 | 2253 | 2254 | 2255 | 2263 | 2264 | 2265 | 2266 | 2267 | 2268 | 2272 | 2273 | 2274 | 2275 | 2276 |
NameTypeDescription
id 2256 | 2257 | 2258 | string 2259 | 2260 | 2261 | 2262 | 2269 |

Subscription id

2270 | 2271 |
2277 | 2278 | 2279 | 2280 | 2281 | 2282 | 2283 | 2284 | 2285 | 2286 | 2287 | 2288 | 2289 | 2290 | 2291 |
2292 |
Returns:
2293 | 2294 | 2295 | 2296 |
2297 |
2298 | Type: 2299 |
2300 |
2301 | 2302 | boolean 2303 | 2304 | 2305 |
2306 |
2307 | 2308 | 2309 |
2310 |

Subscription is deleted

2311 |
2312 | 2313 | 2314 |
2315 | 2316 | 2317 | 2318 |
2319 | 2320 | 2321 | 2322 | 2323 | 2324 | 2325 |

Events

2326 | 2327 | 2328 | 2329 |
2330 | 2331 | 2332 | 2333 |

connected

2334 | 2335 | 2336 | 2337 | 2338 | 2339 |
2340 |

Client connected event, emitted after connection established and negotiated

2341 |
2342 | 2343 | 2344 | 2345 | 2346 | 2347 |
Properties:
2348 | 2349 | 2350 | 2351 | 2352 | 2353 | 2354 | 2355 | 2356 | 2357 | 2358 | 2359 | 2360 | 2361 | 2362 | 2363 | 2364 | 2365 | 2366 | 2367 | 2368 | 2369 | 2370 | 2371 | 2372 | 2373 | 2374 | 2375 | 2376 | 2384 | 2385 | 2386 | 2387 | 2388 | 2389 | 2390 | 2391 | 2392 | 2393 | 2394 | 2395 | 2396 | 2397 | 2398 | 2399 | 2400 | 2401 | 2409 | 2410 | 2411 | 2412 | 2413 | 2414 | 2415 | 2416 | 2417 | 2418 | 2419 | 2420 | 2421 |
NameTypeDescription
sessionId 2377 | 2378 | 2379 | string 2380 | 2381 | 2382 | 2383 |
headers 2402 | 2403 | 2404 | object 2405 | 2406 | 2407 | 2408 |
2422 | 2423 | 2424 | 2425 | 2426 |
2427 | 2428 | 2429 | 2430 | 2431 | 2432 | 2433 | 2434 | 2435 | 2436 | 2437 | 2438 | 2439 | 2440 | 2441 | 2442 | 2443 | 2444 | 2445 | 2446 | 2447 | 2448 | 2449 | 2450 | 2451 | 2452 | 2453 |
Source:
2454 |
2457 | 2458 | 2459 | 2460 | 2461 | 2462 | 2463 | 2464 |
2465 | 2466 | 2467 | 2468 | 2469 | 2470 |
2471 |
Type:
2472 |
    2473 |
  • 2474 | 2475 | object 2476 | 2477 | 2478 |
  • 2479 |
2480 |
2481 | 2482 | 2483 | 2484 | 2485 | 2486 | 2487 | 2488 | 2489 | 2490 | 2491 | 2492 | 2493 | 2494 | 2495 | 2496 | 2497 | 2498 | 2499 | 2500 |
2501 | 2502 | 2503 |
2504 | 2505 | 2506 | 2507 |

connecting

2508 | 2509 | 2510 | 2511 | 2512 | 2513 |
2514 |

Client connecting event, emitted after socket is opened.

2515 |
2516 | 2517 | 2518 | 2519 | 2520 | 2521 |
Properties:
2522 | 2523 | 2524 | 2525 | 2526 | 2527 | 2528 | 2529 | 2530 | 2531 | 2532 | 2533 | 2534 | 2535 | 2536 | 2537 | 2538 | 2539 | 2540 | 2541 | 2542 | 2543 | 2544 | 2545 | 2546 | 2547 | 2548 | 2549 | 2550 | 2558 | 2559 | 2560 | 2561 | 2562 | 2563 | 2564 | 2565 | 2566 | 2567 | 2568 | 2569 | 2570 |
NameTypeDescription
sessionId 2551 | 2552 | 2553 | string 2554 | 2555 | 2556 | 2557 |
2571 | 2572 | 2573 | 2574 | 2575 |
2576 | 2577 | 2578 | 2579 | 2580 | 2581 | 2582 | 2583 | 2584 | 2585 | 2586 | 2587 | 2588 | 2589 | 2590 | 2591 | 2592 | 2593 | 2594 | 2595 | 2596 | 2597 | 2598 | 2599 | 2600 | 2601 | 2602 |
Source:
2603 |
2606 | 2607 | 2608 | 2609 | 2610 | 2611 | 2612 | 2613 |
2614 | 2615 | 2616 | 2617 | 2618 | 2619 |
2620 |
Type:
2621 |
    2622 |
  • 2623 | 2624 | object 2625 | 2626 | 2627 |
  • 2628 |
2629 |
2630 | 2631 | 2632 | 2633 | 2634 | 2635 | 2636 | 2637 | 2638 | 2639 | 2640 | 2641 | 2642 | 2643 | 2644 | 2645 | 2646 | 2647 | 2648 | 2649 |
2650 | 2651 | 2652 |
2653 | 2654 | 2655 | 2656 |

disconnected

2657 | 2658 | 2659 | 2660 | 2661 | 2662 |
2663 |

Client disconnected event

2664 |
2665 | 2666 | 2667 | 2668 | 2669 | 2670 |
Properties:
2671 | 2672 | 2673 | 2674 | 2675 | 2676 | 2677 | 2678 | 2679 | 2680 | 2681 | 2682 | 2683 | 2684 | 2685 | 2686 | 2687 | 2688 | 2689 | 2690 | 2691 | 2692 | 2693 | 2694 | 2695 | 2696 | 2697 | 2698 | 2699 | 2707 | 2708 | 2709 | 2710 | 2711 | 2712 | 2713 | 2714 | 2715 | 2716 | 2717 | 2718 | 2719 |
NameTypeDescription
sessionId 2700 | 2701 | 2702 | string 2703 | 2704 | 2705 | 2706 |
2720 | 2721 | 2722 | 2723 | 2724 |
2725 | 2726 | 2727 | 2728 | 2729 | 2730 | 2731 | 2732 | 2733 | 2734 | 2735 | 2736 | 2737 | 2738 | 2739 | 2740 | 2741 | 2742 | 2743 | 2744 | 2745 | 2746 | 2747 | 2748 | 2749 | 2750 | 2751 |
Source:
2752 |
2755 | 2756 | 2757 | 2758 | 2759 | 2760 | 2761 | 2762 |
2763 | 2764 | 2765 | 2766 | 2767 | 2768 |
2769 |
Type:
2770 |
    2771 |
  • 2772 | 2773 | object 2774 | 2775 | 2776 |
  • 2777 |
2778 |
2779 | 2780 | 2781 | 2782 | 2783 | 2784 | 2785 | 2786 | 2787 | 2788 | 2789 | 2790 | 2791 | 2792 | 2793 | 2794 | 2795 | 2796 | 2797 | 2798 |
2799 | 2800 | 2801 |
2802 | 2803 | 2804 | 2805 |

send

2806 | 2807 | 2808 | 2809 | 2810 | 2811 |
2812 |

Event emitted when broker send message to subscribers

2813 |
2814 | 2815 | 2816 | 2817 | 2818 | 2819 |
Properties:
2820 | 2821 | 2822 | 2823 | 2824 | 2825 | 2826 | 2827 | 2828 | 2829 | 2830 | 2831 | 2832 | 2833 | 2834 | 2835 | 2836 | 2837 | 2838 | 2839 | 2840 | 2841 | 2842 | 2843 | 2844 | 2845 | 2846 | 2847 | 2848 | 2856 | 2857 | 2858 | 2859 | 2860 | 2861 | 2862 | 2863 | 2864 | 2865 | 2866 | 2867 | 2868 | 2869 | 2870 | 2871 | 2872 | 2873 | 2881 | 2882 | 2883 | 2884 | 2885 | 2886 | 2887 | 2888 | 2889 | 2890 | 2891 | 2892 | 2893 |
NameTypeDescription
dest 2849 | 2850 | 2851 | string 2852 | 2853 | 2854 | 2855 |

Destination

frame 2874 | 2875 | 2876 | string 2877 | 2878 | 2879 | 2880 |

Message frame

2894 | 2895 | 2896 | 2897 | 2898 |
2899 | 2900 | 2901 | 2902 | 2903 | 2904 | 2905 | 2906 | 2907 | 2908 | 2909 | 2910 | 2911 | 2912 | 2913 | 2914 | 2915 | 2916 | 2917 | 2918 | 2919 | 2920 | 2921 | 2922 | 2923 | 2924 | 2925 |
Source:
2926 |
2929 | 2930 | 2931 | 2932 | 2933 | 2934 | 2935 | 2936 |
2937 | 2938 | 2939 | 2940 | 2941 | 2942 |
2943 |
Type:
2944 |
    2945 |
  • 2946 | 2947 | object 2948 | 2949 | 2950 |
  • 2951 |
2952 |
2953 | 2954 | 2955 | 2956 | 2957 | 2958 | 2959 | 2960 | 2961 | 2962 | 2963 | 2964 | 2965 | 2966 | 2967 | 2968 | 2969 | 2970 | 2971 | 2972 |
2973 | 2974 | 2975 |
2976 | 2977 | 2978 | 2979 |

subscribe

2980 | 2981 | 2982 | 2983 | 2984 | 2985 |
2986 |

Client subscribe event, emitted when client subscribe topic

2987 |
2988 | 2989 | 2990 | 2991 | 2992 | 2993 |
Properties:
2994 | 2995 | 2996 | 2997 | 2998 | 2999 | 3000 | 3001 | 3002 | 3003 | 3004 | 3005 | 3006 | 3007 | 3008 | 3009 | 3010 | 3011 | 3012 | 3013 | 3014 | 3015 | 3016 | 3017 | 3018 | 3019 | 3020 | 3021 | 3022 | 3030 | 3031 | 3032 | 3033 | 3034 | 3035 | 3036 | 3037 | 3038 | 3039 | 3040 | 3041 | 3042 | 3043 | 3044 | 3045 | 3046 | 3047 | 3055 | 3056 | 3057 | 3058 | 3059 | 3060 | 3061 | 3062 | 3063 | 3064 | 3065 | 3066 | 3067 | 3068 | 3069 | 3070 | 3071 | 3072 | 3080 | 3081 | 3082 | 3083 | 3084 | 3085 | 3086 | 3087 | 3088 | 3089 | 3090 | 3091 | 3092 | 3093 | 3094 | 3095 | 3096 | 3097 | 3105 | 3106 | 3107 | 3108 | 3109 | 3110 | 3111 | 3112 | 3113 | 3114 | 3115 | 3116 | 3117 | 3118 | 3119 | 3120 | 3121 | 3122 | 3130 | 3131 | 3132 | 3133 | 3134 | 3135 | 3136 | 3137 | 3138 | 3139 | 3140 | 3141 | 3142 |
NameTypeDescription
id 3023 | 3024 | 3025 | string 3026 | 3027 | 3028 | 3029 |

Subscription id

sessionId 3048 | 3049 | 3050 | string 3051 | 3052 | 3053 | 3054 |

Socket session id

topic 3073 | 3074 | 3075 | string 3076 | 3077 | 3078 | 3079 |

Destination topic

tokens 3098 | 3099 | 3100 | Array.<string> 3101 | 3102 | 3103 | 3104 |

Tokenized topic

socket 3123 | 3124 | 3125 | object 3126 | 3127 | 3128 | 3129 |

Connected socket

3143 | 3144 | 3145 | 3146 | 3147 |
3148 | 3149 | 3150 | 3151 | 3152 | 3153 | 3154 | 3155 | 3156 | 3157 | 3158 | 3159 | 3160 | 3161 | 3162 | 3163 | 3164 | 3165 | 3166 | 3167 | 3168 | 3169 | 3170 | 3171 | 3172 | 3173 | 3174 |
Source:
3175 |
3178 | 3179 | 3180 | 3181 | 3182 | 3183 | 3184 | 3185 |
3186 | 3187 | 3188 | 3189 | 3190 | 3191 |
3192 |
Type:
3193 |
    3194 |
  • 3195 | 3196 | object 3197 | 3198 | 3199 |
  • 3200 |
3201 |
3202 | 3203 | 3204 | 3205 | 3206 | 3207 | 3208 | 3209 | 3210 | 3211 | 3212 | 3213 | 3214 | 3215 | 3216 | 3217 | 3218 | 3219 | 3220 | 3221 |
3222 | 3223 | 3224 |
3225 | 3226 | 3227 | 3228 |

unsubscribe

3229 | 3230 | 3231 | 3232 | 3233 | 3234 |
3235 |

Client subscribe event, emitted when client unsubscribe topic

3236 |
3237 | 3238 | 3239 | 3240 | 3241 | 3242 |
Properties:
3243 | 3244 | 3245 | 3246 | 3247 | 3248 | 3249 | 3250 | 3251 | 3252 | 3253 | 3254 | 3255 | 3256 | 3257 | 3258 | 3259 | 3260 | 3261 | 3262 | 3263 | 3264 | 3265 | 3266 | 3267 | 3268 | 3269 | 3270 | 3271 | 3279 | 3280 | 3281 | 3282 | 3283 | 3284 | 3285 | 3286 | 3287 | 3288 | 3289 | 3290 | 3291 | 3292 | 3293 | 3294 | 3295 | 3296 | 3304 | 3305 | 3306 | 3307 | 3308 | 3309 | 3310 | 3311 | 3312 | 3313 | 3314 | 3315 | 3316 | 3317 | 3318 | 3319 | 3320 | 3321 | 3329 | 3330 | 3331 | 3332 | 3333 | 3334 | 3335 | 3336 | 3337 | 3338 | 3339 | 3340 | 3341 | 3342 | 3343 | 3344 | 3345 | 3346 | 3354 | 3355 | 3356 | 3357 | 3358 | 3359 | 3360 | 3361 | 3362 | 3363 | 3364 | 3365 | 3366 | 3367 | 3368 | 3369 | 3370 | 3371 | 3379 | 3380 | 3381 | 3382 | 3383 | 3384 | 3385 | 3386 | 3387 | 3388 | 3389 | 3390 | 3391 |
NameTypeDescription
id 3272 | 3273 | 3274 | string 3275 | 3276 | 3277 | 3278 |

Subscription id

sessionId 3297 | 3298 | 3299 | string 3300 | 3301 | 3302 | 3303 |

Socket session id

topic 3322 | 3323 | 3324 | string 3325 | 3326 | 3327 | 3328 |

Destination topic

tokens 3347 | 3348 | 3349 | Array.<string> 3350 | 3351 | 3352 | 3353 |

Tokenized topic

socket 3372 | 3373 | 3374 | object 3375 | 3376 | 3377 | 3378 |

Connected socket

3392 | 3393 | 3394 | 3395 | 3396 |
3397 | 3398 | 3399 | 3400 | 3401 | 3402 | 3403 | 3404 | 3405 | 3406 | 3407 | 3408 | 3409 | 3410 | 3411 | 3412 | 3413 | 3414 | 3415 | 3416 | 3417 | 3418 | 3419 | 3420 | 3421 | 3422 | 3423 |
Source:
3424 |
3427 | 3428 | 3429 | 3430 | 3431 | 3432 | 3433 | 3434 |
3435 | 3436 | 3437 | 3438 | 3439 | 3440 |
3441 |
Type:
3442 |
    3443 |
  • 3444 | 3445 | object 3446 | 3447 | 3448 |
  • 3449 |
3450 |
3451 | 3452 | 3453 | 3454 | 3455 | 3456 | 3457 | 3458 | 3459 | 3460 | 3461 | 3462 | 3463 | 3464 | 3465 | 3466 | 3467 | 3468 |
3469 |
Returns:
3470 | 3471 | 3472 | 3473 |
3474 |
3475 | Type: 3476 |
3477 |
3478 | 3479 | boolean 3480 | 3481 | 3482 |
3483 |
3484 | 3485 | 3486 | 3487 |
3488 | 3489 | 3490 | 3491 |
3492 | 3493 | 3494 |
3495 | 3496 |
3497 | 3498 | 3499 | 3500 | 3501 |
3502 | 3503 |
3504 | 3505 | 3508 | 3509 | 3510 | 3511 | 3512 | -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4ib3r/StompBrokerJS/04ca0d3587c75f8798a55634ec582c065bdc80ad/docs/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4ib3r/StompBrokerJS/04ca0d3587c75f8798a55634ec582c065bdc80ad/docs/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4ib3r/StompBrokerJS/04ca0d3587c75f8798a55634ec582c065bdc80ad/docs/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4ib3r/StompBrokerJS/04ca0d3587c75f8798a55634ec582c065bdc80ad/docs/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4ib3r/StompBrokerJS/04ca0d3587c75f8798a55634ec582c065bdc80ad/docs/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4ib3r/StompBrokerJS/04ca0d3587c75f8798a55634ec582c065bdc80ad/docs/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4ib3r/StompBrokerJS/04ca0d3587c75f8798a55634ec582c065bdc80ad/docs/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4ib3r/StompBrokerJS/04ca0d3587c75f8798a55634ec582c065bdc80ad/docs/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4ib3r/StompBrokerJS/04ca0d3587c75f8798a55634ec582c065bdc80ad/docs/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4ib3r/StompBrokerJS/04ca0d3587c75f8798a55634ec582c065bdc80ad/docs/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4ib3r/StompBrokerJS/04ca0d3587c75f8798a55634ec582c065bdc80ad/docs/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4ib3r/StompBrokerJS/04ca0d3587c75f8798a55634ec582c065bdc80ad/docs/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /docs/global.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Global - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

Global

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 |

Type Definitions

115 | 116 | 117 | 118 |
119 |

MsgFrame

120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 |
Properties:
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 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 |
NameTypeDescription
body 158 | 159 | 160 | string 161 | | 162 | 163 | Buffer 164 | 165 | 166 | 167 |

Message body, string or Buffer

headers 186 | 187 | 188 | object 189 | 190 | 191 | 192 |

Message headers

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 |
Source:
238 |
241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 |
249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 |
257 | 258 | 259 | 260 |
261 | 262 | 263 | 264 |

OnSubscribedMessageCallback(msg, headers)

265 | 266 | 267 | 268 | 269 | 270 |
271 |

Subscription callback method

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 |
Source:
306 |
309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 |
317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 |
Parameters:
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 | 362 | 363 | 364 | 365 | 366 | 367 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 388 | 389 | 390 | 391 | 392 | 393 | 552 | 553 | 554 | 555 | 556 |
NameTypeDescription
msg 355 | 356 | 357 | string 358 | 359 | 360 | 361 | 368 |

Message body

369 | 370 |
headers 381 | 382 | 383 | object 384 | 385 | 386 | 387 | 394 |

Message headers

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 | 431 | 432 | 433 | 434 | 435 | 436 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 457 | 458 | 459 | 460 | 461 | 462 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 483 | 484 | 485 | 486 | 487 | 488 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 509 | 510 | 511 | 512 | 513 | 514 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 535 | 536 | 537 | 538 | 539 | 540 | 544 | 545 | 546 | 547 | 548 |
NameTypeDescription
destination 424 | 425 | 426 | string 427 | 428 | 429 | 430 | 437 |

Message destination

438 | 439 |
subscription 450 | 451 | 452 | string 453 | 454 | 455 | 456 | 463 |

Id of subscription

464 | 465 |
message-id 476 | 477 | 478 | string 479 | 480 | 481 | 482 | 489 |

Id of message

490 | 491 |
content-type 502 | 503 | 504 | string 505 | 506 | 507 | 508 | 515 |

Content type

516 | 517 |
content-length 528 | 529 | 530 | string 531 | 532 | 533 | 534 | 541 |

Content length

542 | 543 |
549 | 550 | 551 |
557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 |
574 | 575 | 576 |
577 |

ServerConfig

578 | 579 | 580 | 581 | 582 |
583 |

STOMP Server configuration

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 |
Source:
618 |
621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 |
629 | 630 | 631 | 632 |
Type:
633 |
    634 |
  • 635 | 636 | object 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 | 666 | 667 | 668 | 669 | 670 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Home - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 |

StompBrokerJS

52 |

NodeJS StompBroker

53 |

This is simple NodeJs STOMP 1.1 broker for embedded usage.

54 |

Features

55 |
    56 |
  • Destination wildcards 57 |
      58 |
    • . is used to separate names in a path
    • 59 |
    • * is used to mach any name in a path
    • 60 |
    • ** is used to recursively match path names
    • 61 |
    62 |
  • 63 |
64 |

TODO

65 |
    66 |
  • Authorization
  • 67 |
  • Heartbeat
  • 68 |
  • Acknowledgment
  • 69 |
  • Async send messages
  • 70 |
  • Transactions
  • 71 |
  • Composite Destinations
  • 72 |
  • Message selectors
  • 73 |
74 |

Changelog

75 |
    76 |
  • 0.1.0 First working version.
  • 77 |
  • 0.1.1 Added wildcards to destination, change subscribe method [no backward compatibility]
  • 78 |
  • 0.1.2 Bug fixes, changed websocket library, updated documentation.
  • 79 |
  • 0.1.3 Unsubscribe on server, updated documentation, added events.
  • 80 |
81 |

Example

82 |
var http = require("http");
 83 | var StompServer = require('stompServer');
 84 | 
 85 | var server = http.createServer();
 86 | var stompServer = new StompServer({server: server});
 87 | 
 88 | server.listen(61614);
 89 | 
 90 | stompServer.subscribe("/**", function(msg, headers) {
 91 |   var topic = headers.destination;
 92 |   console.log(topic, "->", msg);
 93 | });
 94 | 
 95 | stompServer.send('/test', {}, 'testMsg');
 96 | 
97 |
98 | 99 | 100 | 101 | 102 | 103 | 104 |
105 | 106 |
107 | 108 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /docs/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/scripts/prettify/Apache-License-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/scripts/prettify/prettify.js: -------------------------------------------------------------------------------- 1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; 2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= 3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), 9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, 10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, 11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, 12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), 13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} 14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], 18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ 21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), 22 | ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", 23 | /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), 24 | ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 25 | hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= 26 | !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p 2 | 3 | 4 | 5 | 6 | stompServer.js - Documentation 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 |
31 | 32 |

stompServer.js

33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
var EventEmitter    = require('events');
 43 | var util            = require('util');
 44 | 
 45 | var stomp           = require('./lib/stomp');
 46 | var stompUtils      = require('./lib/stomp-utils');
 47 | var BYTES           = require('./lib/bytes');
 48 | 
 49 | var protocolAdapter = require('./lib/adapter');
 50 | var buildConfig     = require('./lib/config');
 51 | 
 52 | /**
 53 |  * STOMP Server configuration
 54 |  *
 55 |  * @typedef {object} ServerConfig
 56 |  * @param {http.Server} server Http server reference
 57 |  * @param {string} [serverName=STOMP-JS/VERSION] Name of STOMP server
 58 |  * @param {string} [path=/stomp] WebSocket path
 59 |  * @param {array} [heartbeat=[10000, 10000]] Heartbeat; read documentation to config according to your desire
 60 |  * @param {number} [heartbeatErrorMargin=1000] Heartbeat error margin; specify how strict server should be
 61 |  * @param {function} [debug=function(args) {}] Debug function
 62 |  * @param {string} [protocol=ws] Protocol to use ('sockjs' or 'ws')
 63 |  * @param {object} [protocolConfig={}] Protocol specific configuration
 64 |  */
 65 | 
 66 | /**
 67 |  * @typedef MsgFrame Message frame object
 68 |  * @property {string|Buffer} body Message body, string or Buffer
 69 |  * @property {object} headers Message headers
 70 |  */
 71 | 
 72 | /**
 73 |  * @class
 74 |  * @augments EventEmitter
 75 |  *
 76 |  * Create Stomp server with config
 77 |  *
 78 |  * @param {ServerConfig} config Configuration for STOMP server
 79 |  */
 80 | var StompServer = function (config) {
 81 |   EventEmitter.call(this);
 82 | 
 83 |   if (config === undefined) {
 84 |     config = {};
 85 |   }
 86 | 
 87 |   this.conf = buildConfig(config);
 88 | 
 89 |   this.subscribes = [];
 90 |   this.middleware = {};
 91 |   this.frameHandler = new stomp.FrameHandler(this);
 92 | 
 93 |   this.socket = new protocolAdapter[this.conf.protocol]({
 94 |       ...this.conf.protocolConfig,
 95 |       server: this.conf.server,
 96 |       path: this.conf.path,
 97 |       perMessageDeflate: false
 98 |     });
 99 |   /**
100 |    * Client connecting event, emitted after socket is opened.
101 |    *
102 |    * @event StompServer#connecting
103 |    * @type {object}
104 |    * @property {string} sessionId
105 |    */
106 |   this.socket.on('connection', function (ws) {
107 |     ws.sessionId = stompUtils.genId();
108 | 
109 |     this.emit('connecting', ws.sessionId);
110 |     this.conf.debug('Connect', ws.sessionId);
111 | 
112 |     ws.on('message', this.parseRequest.bind(this, ws));
113 |     ws.on('close', this.onDisconnect.bind(this, ws));
114 |     ws.on('error', function (err) {
115 |       this.conf.debug(err);
116 |       this.emit('error', err);
117 |     }.bind(this));
118 |   }.bind(this));
119 | 
120 | 
121 |   //<editor-fold defaultstate="collapsed" desc="Events">
122 | 
123 |   /**
124 |    *  Add middle-ware for specific command
125 |    *  @param {('connect'|'disconnect'|'send'|'subscribe'|'unsubscribe')} command Command to hook
126 |    *  @param {function} handler function to add in middle-ware
127 |    * */
128 |   this.addMiddleware = function (command, handler) {
129 |     command = command.toLowerCase();
130 |     if (! this.middleware[command] ) {
131 |       this.middleware[command] = [];
132 |     }
133 |     this.middleware[command].push(handler);
134 |   };
135 | 
136 |   /**
137 |    *  Clear and set middle-ware for specific command
138 |    *  @param {('connect'|'disconnect'|'send'|'subscribe'|'unsubscribe')} command Command to hook
139 |    *  @param {function} handler function to add in middle-ware
140 |    * */
141 |   this.setMiddleware = function (command, handler) {
142 |     command = command.toLowerCase();
143 |     this.middleware[command] = [handler];
144 |   };
145 | 
146 |   /**
147 |    *  Remove middle-ware specific for command
148 |    *  @param {('connect'|'disconnect'|'send'|'subscribe'|'unsubscribe')} command Command with hook
149 |    *  @param {function} handler function to remove from middle-ware
150 |    * */
151 |   this.removeMiddleware = function (command, handler) {
152 |     var handlers = this.middleware[command.toLowerCase()];
153 |     var idx = handlers.indexOf(handler);
154 |     if (idx >= 0) {
155 |       handlers.splice(idx, 1);
156 |     }
157 |   };
158 | 
159 | 
160 |   function withMiddleware(command, finalHandler) {
161 |     return function(socket, args) {
162 |       var handlers = this.middleware[command.toLowerCase()] || [];
163 |       var iter = handlers[Symbol.iterator]();
164 |       var self = this;
165 | 
166 |       function callNext() {
167 |         var iteration = iter.next();
168 |         if (iteration.done) {
169 |           return finalHandler.call(self, socket, args);
170 |         }
171 |         return iteration.value(socket, args, callNext);
172 |       }
173 |       return callNext();
174 |     }.bind(this);
175 |   }
176 | 
177 | 
178 |   /**
179 |    * Client connected event, emitted after connection established and negotiated
180 |    *
181 |    * @event StompServer#connected
182 |    * @type {object}
183 |    * @property {string} sessionId
184 |    * @property {object} headers
185 |    */
186 |   this.onClientConnected = withMiddleware('connect', function (socket, args) {
187 |     socket.clientHeartbeat = {
188 |       client: args.heartbeat[0],
189 |       server: args.heartbeat[1]
190 |     };
191 |     this.conf.debug('CONNECT', socket.sessionId, socket.clientHeartbeat, args.headers);
192 |     this.emit('connected', socket.sessionId, args.headers);
193 |     return true;
194 |   });
195 | 
196 |   /**
197 |    * Client disconnected event
198 |    *
199 |    * @event StompServer#disconnected
200 |    * @type {object}
201 |    * @property {string} sessionId
202 |    * */
203 |   this.onDisconnect = withMiddleware('disconnect', function (socket /*, receiptId*/) {
204 |     // TODO: Do we need to do anything with receiptId on disconnect?
205 |     this.afterConnectionClose(socket);
206 |     this.conf.debug('DISCONNECT', socket.sessionId);
207 |     this.emit('disconnected', socket.sessionId);
208 |     return true;
209 |   });
210 | 
211 | 
212 |   /**
213 |    * Event emitted when broker send message to subscribers
214 |    *
215 |    * @event StompServer#send
216 |    * @type {object}
217 |    * @property {string} dest Destination
218 |    * @property {string} frame Message frame
219 |    */
220 |   this.onSend = withMiddleware('send', function (socket, args, callback) {
221 |     var bodyObj = args.frame.body;
222 |     var frame = this.frameSerializer(args.frame);
223 |     var headers = {
224 |       //default headers
225 |       'message-id': stompUtils.genId('msg'),
226 |       'content-type': 'text/plain'
227 |     };
228 | 
229 |     if (frame.body !== undefined) {
230 |       if (typeof frame.body !== 'string' && !Buffer.isBuffer(frame.body)) {
231 |         throw 'Message body is not string';
232 |       }
233 |       frame.headers['content-length'] = frame.body.length;
234 |     }
235 | 
236 |     if (frame.headers) {
237 |       for (var key in frame.headers) {
238 |         headers[key] = frame.headers[key];
239 |       }
240 |     }
241 | 
242 |     args.frame = frame;
243 |     this.emit('send', {
244 |       frame: {
245 |         headers: frame.headers,
246 |         body: bodyObj
247 |       },
248 |       dest: args.dest
249 |     });
250 | 
251 |     this._sendToSubscriptions(socket, args);
252 | 
253 |     if (callback) {
254 |       callback(true);
255 |     }
256 |     return true;
257 |   });
258 | 
259 | 
260 |   /**
261 |    * Client subscribe event, emitted when client subscribe topic
262 |    *
263 |    * @event StompServer#subscribe
264 |    * @type {object}
265 |    * @property {string} id Subscription id
266 |    * @property {string} sessionId Socket session id
267 |    * @property {string} topic Destination topic
268 |    * @property {string[]} tokens Tokenized topic
269 |    * @property {object} socket Connected socket
270 |    */
271 |   this.onSubscribe = withMiddleware('subscribe', function (socket, args) {
272 |     var sub = {
273 |       id: args.id,
274 |       sessionId: socket.sessionId,
275 |       topic: args.dest,
276 |       tokens: stompUtils.tokenizeDestination(args.dest),
277 |       socket: socket
278 |     };
279 |     this.subscribes.push(sub);
280 |     this.emit('subscribe', sub);
281 |     this.conf.debug('Server subscribe', args.id, args.dest);
282 |     return true;
283 |   });
284 | 
285 | 
286 |   /**
287 |    * Client subscribe event, emitted when client unsubscribe topic
288 |    *
289 |    * @event StompServer#unsubscribe
290 |    * @type {object}
291 |    * @property {string} id Subscription id
292 |    * @property {string} sessionId Socket session id
293 |    * @property {string} topic Destination topic
294 |    * @property {string[]} tokens Tokenized topic
295 |    * @property {object} socket Connected socket
296 |    * @return {boolean}
297 |    */
298 |   this.onUnsubscribe = withMiddleware('unsubscribe', function (socket, subId) {
299 |     for (var t in this.subscribes) {
300 |       var sub = this.subscribes[t];
301 |       if (sub.id === subId && sub.sessionId === socket.sessionId) {
302 |         delete this.subscribes[t];
303 |         this.emit('unsubscribe', sub);
304 |         return true;
305 |       }
306 |     }
307 |     return false;
308 |   });
309 | 
310 |   //</editor-fold>
311 | 
312 | 
313 |   //<editor-fold defaultstate="collapsed" desc="Subscribe & Unsubscribe">
314 | 
315 |   var selfSocket = {
316 |     sessionId: 'self_1234'
317 |   };
318 | 
319 | 
320 |   /**
321 |    * Subscription callback method
322 |    *
323 |    * @callback OnSubscribedMessageCallback
324 |    * @param {string} msg Message body
325 |    * @param {object} headers Message headers
326 |    * @param {string} headers.destination Message destination
327 |    * @param {string} headers.subscription Id of subscription
328 |    * @param {string} headers.message-id Id of message
329 |    * @param {string} headers.content-type Content type
330 |    * @param {string} headers.content-length Content length
331 |    */
332 | 
333 | 
334 |   /**
335 |    * Subscribe topic
336 |    *
337 |    * @param {string} topic Subscribed destination, wildcard is supported
338 |    * @param {OnSubscribedMessageCallback=} callback Callback function
339 |    * @param {object} headers Optional headers, used by client to provide a subscription ID (headers.id)
340 |    * @return {string} Subscription id, when message is received event with this id is emitted
341 |    * @example
342 |    * stompServer.subscribe('/test.data', function(msg, headers) {});
343 |    * //or alternative
344 |    * var subs_id = stompServer.subscribe('/test.data');
345 |    * stompServer.on(subs_id, function(msg, headers) {});
346 |    */
347 |   this.subscribe = function (topic, callback, headers) {
348 |     var id;
349 |     if (!headers || !headers.id) {
350 |       id = 'self_' + Math.floor(Math.random() * 99999999999);
351 |     } else {
352 |       id = headers.id;
353 |     }
354 |     var sub = {
355 |       topic: topic,
356 |       tokens: stompUtils.tokenizeDestination(topic),
357 |       id: id,
358 |       sessionId: 'self_1234'
359 |     };
360 |     this.subscribes.push(sub);
361 |     this.emit('subscribe', sub);
362 |     if (callback) {
363 |       this.on(id, callback);
364 |     }
365 |     return id;
366 |   };
367 | 
368 | 
369 |   /** Unsubscribe topic with subscription id
370 |    *
371 |    * @param {string} id Subscription id
372 |    * @return {boolean} Subscription is deleted
373 |    */
374 |   this.unsubscribe = function (id) {
375 |     this.removeAllListeners(id);
376 |     return this.onUnsubscribe(selfSocket, id);
377 |   };
378 | 
379 |   //</editor-fold>
380 | 
381 | 
382 |   //<editor-fold defaultstate="collapsed" desc="Send">
383 | 
384 |   /**
385 |    * Send message to matching subscribers.
386 |    *
387 |    * @param {object} socket websocket to send the message on
388 |    * @param {string} args onSend args
389 |    * @private
390 |    */
391 |   this._sendToSubscriptions = function (socket, args) {
392 |     for (var i in this.subscribes) {
393 |       var sub = this.subscribes[i];
394 |       if (socket.sessionId === sub.sessionId) {
395 |         continue;
396 |       }
397 |       var match = this._checkSubMatchDest(sub, args);
398 |       if (match) {
399 |         args.frame.headers.subscription = sub.id;
400 |         args.frame.command = 'MESSAGE';
401 |         var sock = sub.socket;
402 |         if (sock !== undefined) {
403 |           stompUtils.sendFrame(sock, args.frame);
404 |         } else {
405 |           this.emit(sub.id, args.frame.body, args.frame.headers);
406 |         }
407 |       }
408 |     }
409 |   };
410 | 
411 | 
412 |   /** Send message to topic
413 |    *
414 |    * @param {string} topic Destination for message
415 |    * @param {Object.<string, string>} headers Message headers
416 |    * @param {string} body Message body
417 |    */
418 |   this.send = function (topic, headers, body) {
419 |     var _headers = {};
420 |     if (headers) {
421 |       for (var key in headers) {
422 |         _headers[key] = headers[key];
423 |       }
424 |     }
425 |     var frame = {
426 |       body: body,
427 |       headers: _headers
428 |     };
429 |     var args = {
430 |       dest: topic,
431 |       frame: this.frameParser(frame)
432 |     };
433 |     this.onSend(selfSocket, args);
434 |   }.bind(this);
435 | 
436 |   //</editor-fold>
437 | 
438 | 
439 |   //<editor-fold defaultstate="collapsed" desc="Frames">
440 | 
441 |   /**
442 |    * Serialize frame to string for send
443 |    *
444 |    * @param {MsgFrame} frame Message frame
445 |    * @return {MsgFrame} modified frame
446 |    * */
447 |   this.frameSerializer = function (frame) {
448 |     if (frame.body !== undefined && frame.headers['content-type'] === 'application/json' && !Buffer.isBuffer(frame.body)) {
449 |       frame.body = JSON.stringify(frame.body);
450 |     }
451 |     return frame;
452 |   };
453 | 
454 | 
455 |   /**
456 |    * Parse frame to object for reading
457 |    *
458 |    * @param {MsgFrame} frame Message frame
459 |    * @return {MsgFrame} modified frame
460 |    * */
461 |   this.frameParser = function (frame) {
462 |     if (frame.body !== undefined && frame.headers['content-type'] === 'application/json') {
463 |       frame.body = JSON.parse(frame.body);
464 |     }
465 |     return frame;
466 |   };
467 | 
468 |   //</editor-fold>
469 | 
470 | 
471 |   //<editor-fold defaultstate="collapsed" desc="Heartbeat">
472 | 
473 |   /**
474 |    * Heart-beat: Turn On for given socket
475 |    *
476 |    * @param {WebSocket} socket Destination WebSocket
477 |    * @param {number} interval Heart-beat interval
478 |    * @param {boolean} serverSide If true then server is responsible for sending pings
479 |    * */
480 |   this.heartbeatOn = function (socket, interval, serverSide) {
481 |     var self = this;
482 | 
483 |     if (serverSide) {
484 |       // Server takes responsibility for sending pings
485 |       // Client should close connection on timeout
486 |       socket.heartbeatClock = setInterval(function() {
487 |         if(socket.readyState === 1) {
488 |           self.conf.debug('PING');
489 |           socket.send(BYTES.LF);
490 |         }
491 |       }, interval);
492 | 
493 |     } else {
494 |       // Client takes responsibility for sending pings
495 |       // Server should close connection on timeout
496 |       socket.heartbeatTime = Date.now() + interval;
497 |       socket.heartbeatClock = setInterval(function() {
498 |         var diff = Date.now() - socket.heartbeatTime;
499 |         if (diff > interval + self.conf.heartbeatErrorMargin) {
500 |           self.conf.debug('HEALTH CHECK failed! Closing', diff, interval);
501 |           socket.close();
502 |         } else {
503 |           self.conf.debug('HEALTH CHECK ok!', diff, interval);
504 |           socket.heartbeatTime -= diff;
505 |         }
506 |       }, interval);
507 |     }
508 |   };
509 | 
510 | 
511 |   /**
512 |    * Heart-beat: Turn Off for given socket
513 |    *
514 |    * @param {WebSocket} socket Destination WebSocket
515 |    * */
516 |   this.heartbeatOff = function (socket) {
517 |     if(socket.heartbeatClock !== undefined) {
518 |       clearInterval(socket.heartbeatClock);
519 |       delete socket.heartbeatClock;
520 |     }
521 |   };
522 | 
523 |   //</editor-fold>
524 | 
525 | 
526 |   /**
527 |    * Test if the input subscriber has subscribed to the target destination.
528 |    *
529 |    * @param sub the subscriber
530 |    * @param args onSend args
531 |    * @returns {boolean} true if the input subscription matches destination
532 |    * @private
533 |    */
534 |   this._checkSubMatchDest = function (sub, args) {
535 |     var match = true;
536 |     var tokens = stompUtils.tokenizeDestination(args.dest);
537 |     for (var t in tokens) {
538 |       var token = tokens[t];
539 |       if (sub.tokens[t] === undefined || (sub.tokens[t] !== token && sub.tokens[t] !== '*' && sub.tokens[t] !== '**')) {
540 |         match = false;
541 |         break;
542 |       } else if (sub.tokens[t] === '**') {
543 |         break;
544 |       }
545 |     }
546 |     return match;
547 |   };
548 | 
549 | 
550 |   /**
551 |    * After connection close
552 |    *
553 |    * @param socket WebSocket connection that has been closed and is dying
554 |    */
555 |   this.afterConnectionClose = function (socket) {
556 |     // remove from subscribes
557 |     for (var t in this.subscribes) {
558 |       var sub = this.subscribes[t];
559 |       if (sub.sessionId === socket.sessionId) {
560 |         delete this.subscribes[t];
561 |       }
562 |     }
563 | 
564 |     // turn off server side heart-beat (if needed)
565 |     this.heartbeatOff(socket);
566 |   };
567 | 
568 | 
569 |   this.parseRequest = function(socket, data) {
570 |     // check if it's incoming heartbeat
571 |     if (socket.heartbeatClock !== undefined) {
572 |       // beat
573 |       socket.heartbeatTime = Date.now();
574 | 
575 |       // if it's ping then ignore
576 |       if(data === BYTES.LF) {
577 |         this.conf.debug('PONG');
578 |         return;
579 |       }
580 |     }
581 | 
582 |     // normal data
583 |     var frame = stompUtils.parseFrame(data);
584 |     var cmdFunc = this.frameHandler[frame.command];
585 |     if (cmdFunc) {
586 |       frame = this.frameParser(frame);
587 |       return cmdFunc(socket, frame);
588 |     }
589 | 
590 |     return 'Command not found';
591 |   };
592 | 
593 | };
594 | 
595 | util.inherits(StompServer, EventEmitter);
596 | 
597 | // Export
598 | module.exports = StompServer;
599 | 
600 |
601 |
602 | 603 | 604 | 605 | 606 |
607 | 608 |
609 | 610 |
611 | Generated by JSDoc 3.6.1 on Fri May 10 2019 11:42:45 GMT+0200 (CEST) using the Minami theme. 612 |
613 | 614 | 615 | 616 | 617 | 618 | -------------------------------------------------------------------------------- /docs/styles/jsdoc-default.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,500i,500,600,600i|Roboto); 2 | 3 | * { 4 | box-sizing: border-box 5 | } 6 | 7 | html, body { 8 | height: 100%; 9 | width: 100%; 10 | } 11 | 12 | body { 13 | color: #4d4e53; 14 | background-color: white; 15 | margin: 0 auto; 16 | padding: 0; 17 | font-family: 'Source Sans Pro', Helvetica, sans-serif; 18 | font-size: 16px; 19 | line-height: 160%; 20 | } 21 | 22 | a, 23 | a:active { 24 | color: #0095dd; 25 | text-decoration: none; 26 | } 27 | 28 | a:hover { 29 | text-decoration: underline 30 | } 31 | 32 | p, ul, ol, blockquote { 33 | margin-bottom: 1em; 34 | } 35 | 36 | h1, h2, h3, h4, h5, h6 { 37 | font-family: 'Roboto', sans-serif; 38 | } 39 | 40 | h1, h2, h3, h4, h5, h6 { 41 | color: #000; 42 | font-weight: 400; 43 | margin: 0; 44 | } 45 | 46 | h1 { 47 | font-weight: 300; 48 | font-size: 48px; 49 | margin: 1em 0 .5em; 50 | } 51 | 52 | h1.page-title {margin-bottom: 10px;font-size: 34px;font-weight: 300;border-bottom: solid 2px #ddd;padding: .5em 0 .5em;margin-top: 0;} 53 | 54 | h2 { 55 | font-size: 32px; 56 | margin: 1.2em 0 .8em; 57 | font-weight: bold; 58 | } 59 | 60 | h3 { 61 | /* margin-top: 1em; */ 62 | /* margin-bottom: 16px; */ 63 | /* font-weight: bold; */ 64 | padding: 0; 65 | margin: 1em 0 .6em; 66 | font-size: 28px; 67 | /* border-bottom: 1px solid #eee; */ 68 | /* padding-bottom: 15px; */ 69 | } 70 | 71 | h4 { 72 | font-size: 18px; 73 | margin: 1em 0 .2em; 74 | color: #4d4e53; 75 | /* border-bottom: 1px solid #eee; */ 76 | padding-bottom: 8px; 77 | } 78 | 79 | h5, .container-overview .subsection-title { 80 | font-size: 120%; 81 | /* letter-spacing: -0.01em; */ 82 | margin: 20px 0 5px; 83 | } 84 | 85 | h6 { 86 | font-size: 100%; 87 | letter-spacing: -0.01em; 88 | margin: 6px 0 3px 0; 89 | font-style: italic; 90 | } 91 | 92 | tt, code, kbd, samp { 93 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 94 | background: #f4f4f4; 95 | padding: 1px 5px; 96 | border-radius: 5px; 97 | font-size: 14px; 98 | } 99 | 100 | blockquote { 101 | display: block; 102 | border-left: 4px solid #eee; 103 | margin: 0; 104 | padding-left: 1em; 105 | color: #888; 106 | } 107 | 108 | .class-description { 109 | font-size: 130%; 110 | line-height: 140%; 111 | margin-bottom: 1em; 112 | margin-top: 1em; 113 | } 114 | 115 | .class-description:empty { 116 | margin: 0 117 | } 118 | 119 | /** Container **/ 120 | #main { 121 | float: right; 122 | min-width: 360px; 123 | width: calc(100% - 250px); 124 | padding: 0 30px 20px 30px; 125 | } 126 | 127 | header { 128 | display: block 129 | } 130 | 131 | section { 132 | display: block; 133 | background-color: #fff; 134 | padding: 0; 135 | } 136 | 137 | .variation { 138 | display: none 139 | } 140 | 141 | .signature-attributes { 142 | font-size: 60%; 143 | color: #aaa; 144 | font-style: italic; 145 | font-weight: lighter; 146 | } 147 | 148 | /** Readme **/ 149 | 150 | .readme { 151 | font-size: 16px; 152 | } 153 | 154 | .readme h1, 155 | .readme h2, 156 | .readme h3, 157 | .readme h4, 158 | .readme h5 { 159 | margin-top: 1em; 160 | margin-bottom: 16px; 161 | font-weight: bold; 162 | padding: 0; 163 | } 164 | 165 | .readme h1 { 166 | font-size: 2em; 167 | padding-bottom: 0.3em; 168 | } 169 | 170 | .readme h2 { 171 | font-size: 1.75em; 172 | padding-bottom: 0.3em; 173 | } 174 | 175 | .readme h3 { 176 | font-size: 1.5em; 177 | background-color: transparent; 178 | } 179 | 180 | .readme h4 { 181 | font-size: 1.25em; 182 | } 183 | 184 | .readme h5 { 185 | font-size: 1em; 186 | } 187 | 188 | .readme img { 189 | max-width: 100%; 190 | } 191 | 192 | .readme ul, .readme ol { 193 | padding-left: 2em; 194 | } 195 | 196 | .readme pre > code { 197 | font-size: 0.85em; 198 | } 199 | 200 | .readme table { 201 | margin-bottom: 1em; 202 | border-collapse: collapse; 203 | border-spacing: 0; 204 | } 205 | 206 | .readme table tr { 207 | background-color: #fff; 208 | border-top: 1px solid #ccc; 209 | } 210 | 211 | .readme table th, 212 | .readme table td { 213 | padding: 6px 13px; 214 | border: 1px solid #ddd; 215 | } 216 | 217 | .readme table tr:nth-child(2n) { 218 | background-color: #f8f8f8; 219 | } 220 | 221 | /** Nav **/ 222 | nav { 223 | float: left; 224 | display: block; 225 | width: 250px; 226 | background: #fff; 227 | overflow: auto; 228 | position: fixed; 229 | height: 100%; 230 | padding: 10px; 231 | border-right: 1px solid #eee; 232 | /* box-shadow: 0 0 3px rgba(0,0,0,0.1); */ 233 | } 234 | 235 | nav li { 236 | list-style: none; 237 | padding: 0; 238 | margin: 0; 239 | } 240 | 241 | .nav-heading { 242 | margin-top: 10px; 243 | font-weight: bold; 244 | } 245 | 246 | .nav-heading a { 247 | color: #888; 248 | font-size: 14px; 249 | display: inline-block; 250 | } 251 | 252 | .nav-item-type { 253 | /* margin-left: 5px; */ 254 | width: 18px; 255 | height: 18px; 256 | display: inline-block; 257 | text-align: center; 258 | border-radius: 0.2em; 259 | margin-right: 5px; 260 | font-weight: bold; 261 | line-height: 20px; 262 | font-size: 13px; 263 | } 264 | 265 | .type-function { 266 | background: #B3E5FC; 267 | color: #0288D1; 268 | } 269 | 270 | .type-class { 271 | background: #D1C4E9; 272 | color: #4527A0; 273 | } 274 | 275 | .type-member { 276 | background: #C8E6C9; 277 | color: #388E3C; 278 | } 279 | 280 | .type-module { 281 | background: #E1BEE7; 282 | color: #7B1FA2; 283 | } 284 | 285 | 286 | /** Footer **/ 287 | footer { 288 | color: hsl(0, 0%, 28%); 289 | margin-left: 250px; 290 | display: block; 291 | padding: 30px; 292 | font-style: italic; 293 | font-size: 90%; 294 | border-top: 1px solid #eee; 295 | } 296 | 297 | .ancestors { 298 | color: #999 299 | } 300 | 301 | .ancestors a { 302 | color: #999 !important; 303 | text-decoration: none; 304 | } 305 | 306 | .clear { 307 | clear: both 308 | } 309 | 310 | .important { 311 | font-weight: bold; 312 | color: #950B02; 313 | } 314 | 315 | .yes-def { 316 | text-indent: -1000px 317 | } 318 | 319 | .type-signature { 320 | color: #aaa 321 | } 322 | 323 | .name, .signature { 324 | font-family: Consolas, Monaco, 'Andale Mono', monospace 325 | } 326 | 327 | .details { 328 | margin-top: 14px; 329 | border-left: 2px solid #DDD; 330 | line-height: 30px; 331 | } 332 | 333 | .details dt { 334 | width: 120px; 335 | float: left; 336 | padding-left: 10px; 337 | } 338 | 339 | .details dd { 340 | margin-left: 70px 341 | } 342 | 343 | .details ul { 344 | margin: 0 345 | } 346 | 347 | .details ul { 348 | list-style-type: none 349 | } 350 | 351 | .details li { 352 | margin-left: 30px 353 | } 354 | 355 | .details pre.prettyprint { 356 | margin: 0 357 | } 358 | 359 | .details .object-value { 360 | padding-top: 0 361 | } 362 | 363 | .description { 364 | margin-bottom: 1em; 365 | margin-top: 1em; 366 | } 367 | 368 | .code-caption { 369 | font-style: italic; 370 | font-size: 107%; 371 | margin: 0; 372 | } 373 | 374 | .prettyprint { 375 | font-size: 13px; 376 | border: 1px solid #ddd; 377 | border-radius: 3px; 378 | box-shadow: 0 1px 3px hsla(0, 0%, 0%, 0.05); 379 | overflow: auto; 380 | } 381 | 382 | .prettyprint.source { 383 | width: inherit 384 | } 385 | 386 | .prettyprint code { 387 | font-size: 12px; 388 | line-height: 18px; 389 | display: block; 390 | background-color: #fff; 391 | color: #4D4E53; 392 | } 393 | 394 | .prettyprint code:empty:before { 395 | content: ''; 396 | } 397 | 398 | .prettyprint > code { 399 | padding: 15px 400 | } 401 | 402 | .prettyprint .linenums code { 403 | padding: 0 15px 404 | } 405 | 406 | .prettyprint .linenums li:first-of-type code { 407 | padding-top: 15px 408 | } 409 | 410 | .prettyprint code span.line { 411 | display: inline-block 412 | } 413 | 414 | .prettyprint.linenums { 415 | padding-left: 70px; 416 | -webkit-user-select: none; 417 | -moz-user-select: none; 418 | -ms-user-select: none; 419 | user-select: none; 420 | } 421 | 422 | .prettyprint.linenums ol { 423 | padding-left: 0 424 | } 425 | 426 | .prettyprint.linenums li { 427 | border-left: 3px #ddd solid 428 | } 429 | 430 | .prettyprint.linenums li.selected, .prettyprint.linenums li.selected * { 431 | background-color: lightyellow 432 | } 433 | 434 | .prettyprint.linenums li * { 435 | -webkit-user-select: text; 436 | -moz-user-select: text; 437 | -ms-user-select: text; 438 | user-select: text; 439 | } 440 | 441 | .params, .props { 442 | border-spacing: 0; 443 | border: 1px solid #ddd; 444 | border-collapse: collapse; 445 | border-radius: 3px; 446 | box-shadow: 0 1px 3px rgba(0,0,0,0.1); 447 | width: 100%; 448 | font-size: 14px; 449 | /* margin-left: 15px; */ 450 | } 451 | 452 | .params .name, .props .name, .name code { 453 | color: #4D4E53; 454 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 455 | font-size: 100%; 456 | } 457 | 458 | .params td, .params th, .props td, .props th { 459 | margin: 0px; 460 | text-align: left; 461 | vertical-align: top; 462 | padding: 10px; 463 | display: table-cell; 464 | } 465 | 466 | .params td { 467 | border-top: 1px solid #eee 468 | } 469 | 470 | .params thead tr, .props thead tr { 471 | background-color: #fff; 472 | font-weight: bold; 473 | } 474 | 475 | .params .params thead tr, .props .props thead tr { 476 | background-color: #fff; 477 | font-weight: bold; 478 | } 479 | 480 | .params td.description > p:first-child, .props td.description > p:first-child { 481 | margin-top: 0; 482 | padding-top: 0; 483 | } 484 | 485 | .params td.description > p:last-child, .props td.description > p:last-child { 486 | margin-bottom: 0; 487 | padding-bottom: 0; 488 | } 489 | 490 | dl.param-type { 491 | /* border-bottom: 1px solid hsl(0, 0%, 87%); */ 492 | margin: 0; 493 | padding: 0; 494 | font-size: 16px; 495 | } 496 | 497 | .param-type dt, .param-type dd { 498 | display: inline-block 499 | } 500 | 501 | .param-type dd { 502 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 503 | display: inline-block; 504 | padding: 0; 505 | margin: 0; 506 | font-size: 14px; 507 | } 508 | 509 | .disabled { 510 | color: #454545 511 | } 512 | 513 | /* navicon button */ 514 | .navicon-button { 515 | display: none; 516 | position: relative; 517 | padding: 2.0625rem 1.5rem; 518 | transition: 0.25s; 519 | cursor: pointer; 520 | user-select: none; 521 | opacity: .8; 522 | } 523 | .navicon-button .navicon:before, .navicon-button .navicon:after { 524 | transition: 0.25s; 525 | } 526 | .navicon-button:hover { 527 | transition: 0.5s; 528 | opacity: 1; 529 | } 530 | .navicon-button:hover .navicon:before, .navicon-button:hover .navicon:after { 531 | transition: 0.25s; 532 | } 533 | .navicon-button:hover .navicon:before { 534 | top: .825rem; 535 | } 536 | .navicon-button:hover .navicon:after { 537 | top: -.825rem; 538 | } 539 | 540 | /* navicon */ 541 | .navicon { 542 | position: relative; 543 | width: 2.5em; 544 | height: .3125rem; 545 | background: #000; 546 | transition: 0.3s; 547 | border-radius: 2.5rem; 548 | } 549 | .navicon:before, .navicon:after { 550 | display: block; 551 | content: ""; 552 | height: .3125rem; 553 | width: 2.5rem; 554 | background: #000; 555 | position: absolute; 556 | z-index: -1; 557 | transition: 0.3s 0.25s; 558 | border-radius: 1rem; 559 | } 560 | .navicon:before { 561 | top: .625rem; 562 | } 563 | .navicon:after { 564 | top: -.625rem; 565 | } 566 | 567 | /* open */ 568 | .nav-trigger:checked + label:not(.steps) .navicon:before, 569 | .nav-trigger:checked + label:not(.steps) .navicon:after { 570 | top: 0 !important; 571 | } 572 | 573 | .nav-trigger:checked + label .navicon:before, 574 | .nav-trigger:checked + label .navicon:after { 575 | transition: 0.5s; 576 | } 577 | 578 | /* Minus */ 579 | .nav-trigger:checked + label { 580 | transform: scale(0.75); 581 | } 582 | 583 | /* × and + */ 584 | .nav-trigger:checked + label.plus .navicon, 585 | .nav-trigger:checked + label.x .navicon { 586 | background: transparent; 587 | } 588 | 589 | .nav-trigger:checked + label.plus .navicon:before, 590 | .nav-trigger:checked + label.x .navicon:before { 591 | transform: rotate(-45deg); 592 | background: #FFF; 593 | } 594 | 595 | .nav-trigger:checked + label.plus .navicon:after, 596 | .nav-trigger:checked + label.x .navicon:after { 597 | transform: rotate(45deg); 598 | background: #FFF; 599 | } 600 | 601 | .nav-trigger:checked + label.plus { 602 | transform: scale(0.75) rotate(45deg); 603 | } 604 | 605 | .nav-trigger:checked ~ nav { 606 | left: 0 !important; 607 | } 608 | 609 | .nav-trigger:checked ~ .overlay { 610 | display: block; 611 | } 612 | 613 | .nav-trigger { 614 | position: fixed; 615 | top: 0; 616 | clip: rect(0, 0, 0, 0); 617 | } 618 | 619 | .overlay { 620 | display: none; 621 | position: fixed; 622 | top: 0; 623 | bottom: 0; 624 | left: 0; 625 | right: 0; 626 | width: 100%; 627 | height: 100%; 628 | background: hsla(0, 0%, 0%, 0.5); 629 | z-index: 1; 630 | } 631 | 632 | .section-method { 633 | margin-bottom: 30px; 634 | padding-bottom: 30px; 635 | border-bottom: 1px solid #eee; 636 | } 637 | 638 | @media only screen and (min-width: 320px) and (max-width: 680px) { 639 | body { 640 | overflow-x: hidden; 641 | } 642 | 643 | nav { 644 | background: #FFF; 645 | width: 250px; 646 | height: 100%; 647 | position: fixed; 648 | top: 0; 649 | right: 0; 650 | bottom: 0; 651 | left: -250px; 652 | z-index: 3; 653 | padding: 0 10px; 654 | transition: left 0.2s; 655 | } 656 | 657 | .navicon-button { 658 | display: inline-block; 659 | position: fixed; 660 | top: 1.5em; 661 | right: 0; 662 | z-index: 2; 663 | } 664 | 665 | #main { 666 | width: 100%; 667 | min-width: 360px; 668 | } 669 | 670 | #main h1.page-title { 671 | margin: 1em 0; 672 | } 673 | 674 | #main section { 675 | padding: 0; 676 | } 677 | 678 | footer { 679 | margin-left: 0; 680 | } 681 | } 682 | 683 | @media only print { 684 | nav { 685 | display: none; 686 | } 687 | 688 | #main { 689 | float: none; 690 | width: 100%; 691 | } 692 | } 693 | -------------------------------------------------------------------------------- /docs/styles/prettify-jsdoc.css: -------------------------------------------------------------------------------- 1 | /* JSDoc prettify.js theme */ 2 | 3 | /* plain text */ 4 | .pln { 5 | color: #000000; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | /* string content */ 11 | .str { 12 | color: hsl(104, 100%, 24%); 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | /* a keyword */ 18 | .kwd { 19 | color: #000000; 20 | font-weight: bold; 21 | font-style: normal; 22 | } 23 | 24 | /* a comment */ 25 | .com { 26 | font-weight: normal; 27 | font-style: italic; 28 | } 29 | 30 | /* a type name */ 31 | .typ { 32 | color: #000000; 33 | font-weight: normal; 34 | font-style: normal; 35 | } 36 | 37 | /* a literal value */ 38 | .lit { 39 | color: #006400; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | 44 | /* punctuation */ 45 | .pun { 46 | color: #000000; 47 | font-weight: bold; 48 | font-style: normal; 49 | } 50 | 51 | /* lisp open bracket */ 52 | .opn { 53 | color: #000000; 54 | font-weight: bold; 55 | font-style: normal; 56 | } 57 | 58 | /* lisp close bracket */ 59 | .clo { 60 | color: #000000; 61 | font-weight: bold; 62 | font-style: normal; 63 | } 64 | 65 | /* a markup tag name */ 66 | .tag { 67 | color: #006400; 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | 72 | /* a markup attribute name */ 73 | .atn { 74 | color: #006400; 75 | font-weight: normal; 76 | font-style: normal; 77 | } 78 | 79 | /* a markup attribute value */ 80 | .atv { 81 | color: #006400; 82 | font-weight: normal; 83 | font-style: normal; 84 | } 85 | 86 | /* a declaration */ 87 | .dec { 88 | color: #000000; 89 | font-weight: bold; 90 | font-style: normal; 91 | } 92 | 93 | /* a variable name */ 94 | .var { 95 | color: #000000; 96 | font-weight: normal; 97 | font-style: normal; 98 | } 99 | 100 | /* a function name */ 101 | .fun { 102 | color: #000000; 103 | font-weight: bold; 104 | font-style: normal; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | } 112 | -------------------------------------------------------------------------------- /docs/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: hsl(104, 100%, 24%); } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: hsl(240, 100%, 50%); } 17 | 18 | /* a comment */ 19 | .com { 20 | color: hsl(0, 0%, 60%); } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: hsl(240, 100%, 32%); } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: hsl(240, 100%, 40%); } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #000000; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #000000; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #000000; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /examples/default/example.js: -------------------------------------------------------------------------------- 1 | var http = require("http"); 2 | var StompServer = require('stomp-broker-js'); 3 | 4 | var server = http.createServer(); 5 | var stompServer = new StompServer({server: server}); 6 | 7 | server.listen(61614); 8 | 9 | stompServer.subscribe("/**", function(msg, headers) { 10 | var topic = headers.destination; 11 | console.log(topic, "->{" + (typeof msg) + "}", msg, headers); 12 | }); -------------------------------------------------------------------------------- /examples/default/stomp-consumer.js: -------------------------------------------------------------------------------- 1 | var stompjs = require('stompjs'); 2 | var client = stompjs.overWS('ws://localhost:61614/stomp'); 3 | var headers = { 4 | login: 'mylogin', 5 | passcode: 'mypasscode', 6 | // additional header 7 | 'client-id': 'my-client-id' 8 | }; 9 | client.debug = console.log; 10 | client.connect(headers, function (error) { 11 | // display the error's message header: 12 | if (error.command == "ERROR") { 13 | console.error(error.headers.message); 14 | } else { 15 | console.log("Connected"); 16 | client.subscribe("/*", function(msg) { 17 | console.log("Received", msg); 18 | }); 19 | } 20 | }); -------------------------------------------------------------------------------- /examples/default/stomp-producer.js: -------------------------------------------------------------------------------- 1 | var stompjs = require('stompjs'); 2 | var client = stompjs.overWS('ws://localhost:61614/stomp'); 3 | var headers = { 4 | login: 'mylogin', 5 | passcode: 'mypasscode', 6 | // additional header 7 | 'client-id': 'my-client-id' 8 | }; 9 | client.debug = console.log; 10 | client.connect(headers, function (error) { 11 | // display the error's message header: 12 | if (error.command == "ERROR") { 13 | console.error(error.headers.message); 14 | } else { 15 | console.log("Connected"); 16 | var quote = {symbol: 'APPL', value: 195.46}; 17 | client.send("/test", {}, JSON.stringify(quote)); 18 | } 19 | }); -------------------------------------------------------------------------------- /examples/default/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
 8 | 
 9 | 
10 | 11 | 12 | 13 | 14 | 53 | 54 | -------------------------------------------------------------------------------- /examples/sockjs/client.js: -------------------------------------------------------------------------------- 1 | const socket = new SockJS('/ws'); 2 | const stompClient = Stomp.over(socket); 3 | 4 | stompClient.connect({/*headers*/ }, 5 | function onConnect(data) { 6 | console.log('STOMP is now connected!'); 7 | 8 | // subscription 9 | stompClient.subscribe('/echo', (data) => { 10 | const ele = document.createElement('div'); 11 | ele.textContent = data.body; 12 | document.body.appendChild(ele); 13 | ele.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' }); 14 | }); 15 | 16 | // trigger some data 17 | let timer = 0; 18 | setInterval(() => { 19 | stompClient.send('/echo', {}, String(++timer)); 20 | }, 6000); 21 | }, 22 | (error) => console.error(error)); 23 | -------------------------------------------------------------------------------- /examples/sockjs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Stomp over sockjs example 8 | 9 | 10 | 11 | 12 | 13 | Open console to see the logs. 14 |
15 |         npm start
16 |     
17 | 18 | -------------------------------------------------------------------------------- /examples/sockjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "node-static": "^0.7.11", 4 | "stomp-broker-js": "file:../../" 5 | }, 6 | "scripts": { 7 | "start": "node server.js", 8 | "start-dev": "nodemon server.js" 9 | }, 10 | "devDependencies": { 11 | "nodemon": "^1.19.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/sockjs/readme.md: -------------------------------------------------------------------------------- 1 | 2 | Run this example from the current folder with 3 | 4 | ``` 5 | npm install 6 | npm start 7 | ``` 8 | 9 | Open browser pointing to http://localhost:3002 -------------------------------------------------------------------------------- /examples/sockjs/server.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const StompServer = require('stomp-broker-js'); 3 | const node_static = require('node-static'); 4 | const static_directory = new node_static.Server(__dirname); 5 | 6 | const server = http.createServer((request, response) => { 7 | console.log(request.url); 8 | static_directory.serve(request, response); 9 | 10 | }); 11 | const stompServer = new StompServer({ 12 | server: server, 13 | debug: console.log, 14 | path: '/ws', 15 | protocol: 'sockjs', 16 | heartbeat: [2000,2000] 17 | }); 18 | 19 | console.log(' [*] Listening on 0.0.0.0:3002'); 20 | server.listen(3002, 'localhost'); 21 | 22 | stompServer.subscribe("/echo", (msg, headers) => { 23 | var topic = headers.destination; 24 | console.log(`topic:${topic} messageType: ${typeof msg}`, msg, headers); 25 | stompServer.send('/echo', headers, `Hello from server! ${msg}`); 26 | }); 27 | -------------------------------------------------------------------------------- /jsdoc-conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": { 3 | "allowUnknownTags": false, 4 | "dictionaries": [ 5 | "jsdoc" 6 | ] 7 | }, 8 | "source": { 9 | "include": [ 10 | "stompServer.js", 11 | "README.md" 12 | ] 13 | }, 14 | "plugins": [ 15 | "plugins/markdown" 16 | ], 17 | "templates": { 18 | "cleverLinks": false, 19 | "monospaceLinks": true, 20 | "useLongnameInNav": false 21 | }, 22 | "opts": { 23 | "destination": "./docs/", 24 | "encoding": "utf8", 25 | "private": true, 26 | "recurse": true, 27 | "template": "./node_modules/minami" 28 | } 29 | } -------------------------------------------------------------------------------- /lib/adapter/index.js: -------------------------------------------------------------------------------- 1 | var WebSocketServer = require('ws').Server; 2 | var sockjs = require('sockjs'); 3 | 4 | /** 5 | * Instantiating WebSocketServer by default 6 | * other options provide adapters 7 | */ 8 | module.exports = { 9 | ws: WebSocketServer, 10 | sockjs: SockJsAdapter 11 | }; 12 | 13 | function SockJsAdapter(config) { 14 | var opts = Object.assign({}, config, { 15 | sockjs_url: "http://cdn.jsdelivr.net/sockjs/1.0.1/sockjs.min.js", 16 | prefix: config.path || '/ws' 17 | }); 18 | var sockjsServer = sockjs.createServer(opts); 19 | 20 | sockjsServer.installHandlers(opts.server, { 21 | prefix: opts.prefix 22 | }); 23 | 24 | return { 25 | on: function (event, config) { 26 | if (event === 'connection') { 27 | sockjsServer.on('connection', function (conn) { 28 | var websocketConnectionWrapper = { 29 | on: function (event, eventHandler) { 30 | switch (event) { 31 | case 'message': 32 | conn.on('data', eventHandler); 33 | break; 34 | default: 35 | conn.on(event, eventHandler); 36 | } 37 | }, 38 | send: function (data /*, options*/) { 39 | return conn.write(data); 40 | }, 41 | close: function () { 42 | conn.close.call(conn); 43 | conn.end.call(conn); 44 | } 45 | }; 46 | 47 | config(websocketConnectionWrapper); 48 | }); 49 | } else throw 'No such event on sockjs adapter!'; 50 | 51 | } 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /lib/bytes.js: -------------------------------------------------------------------------------- 1 | var BYTES = { 2 | NULL: '\x00', 3 | LF: '\x0A' 4 | }; 5 | 6 | module.exports = BYTES; 7 | -------------------------------------------------------------------------------- /lib/config.js: -------------------------------------------------------------------------------- 1 | const VERSION = require('../package.json').version; 2 | 3 | module.exports = function buildConfig(config) { 4 | var conf = { 5 | server: config.server, 6 | serverName: config.serverName || 'STOMP-JS/' + VERSION, 7 | path: config.path || "/stomp", 8 | heartbeat: config.heartbeat || [0, 0], 9 | heartbeatErrorMargin: config.heartbeatErrorMargin || 1000, 10 | debug: config.debug || function () {}, 11 | protocol: config.protocol || 'ws', 12 | protocolConfig: config.protocolConfig || {} 13 | }; 14 | 15 | if (conf.server === undefined) { 16 | throw "Server is required"; 17 | } 18 | return conf; 19 | }; 20 | -------------------------------------------------------------------------------- /lib/frame.js: -------------------------------------------------------------------------------- 1 | var bytes = require('./bytes'); 2 | 3 | function mkBuffer(headers, body) { 4 | var hBuf = new Buffer.from(headers); 5 | var buf = new Buffer(hBuf.length + body.length + 1); 6 | hBuf.copy(buf); 7 | body.copy(buf, hBuf.length); 8 | buf[buf.length - 1] = bytes.NULL; 9 | return buf; 10 | } 11 | 12 | function Frame(args) { 13 | this.command = null; 14 | this.headers = null; 15 | this.body = null; 16 | 17 | this.buildFrame = function (args, want_receipt) { 18 | var receipt_stamp = null; 19 | this.command = args.command; 20 | this.headers = args.headers; 21 | this.body = args.body; 22 | 23 | if (want_receipt) { 24 | var _receipt = ''; 25 | receipt_stamp = Math.floor(Math.random() * 99999999999).toString(); 26 | if (this.headers.session !== undefined) { 27 | _receipt = receipt_stamp + '-' + this.headers.session; 28 | } 29 | else { 30 | _receipt = receipt_stamp; 31 | } 32 | this.headers.receipt = _receipt; 33 | } 34 | return this; 35 | }; 36 | 37 | if (args) { 38 | this.buildFrame(args); 39 | } 40 | 41 | this.toStringOrBuffer = function () { 42 | var header_strs = [], 43 | frame = ''; 44 | 45 | for (var header in this.headers) { 46 | header_strs.push(header + ':' + this.headers[header]); 47 | } 48 | 49 | frame += this.command + "\n"; 50 | frame += header_strs.join("\n"); 51 | frame += "\n\n"; 52 | 53 | if (Buffer.isBuffer(this.body)) { 54 | return mkBuffer(frame, this.body); 55 | } 56 | 57 | if (this.body) { 58 | frame += this.body; 59 | } 60 | 61 | frame += bytes.NULL; 62 | 63 | return frame; 64 | }; 65 | } 66 | 67 | module.exports = Frame; 68 | -------------------------------------------------------------------------------- /lib/stomp-utils.js: -------------------------------------------------------------------------------- 1 | var Frame = require('./frame'); 2 | 3 | /** Unique id generator */ 4 | function genId(type) { 5 | return (type ? type : 'id') + Math.floor(Math.random() * 999999999999999999999); 6 | } 7 | 8 | /** Send frame with socket */ 9 | function sendFrame(socket, _frame) { 10 | var frame = _frame; 11 | 12 | if (!_frame.hasOwnProperty('toString')) { 13 | frame = new Frame({ 14 | 'command': _frame.command, 15 | 'headers': _frame.headers, 16 | 'body': _frame.body 17 | }); 18 | } 19 | 20 | socket.send(frame.toStringOrBuffer()); 21 | return true; 22 | } 23 | 24 | /** Parse single command */ 25 | function parseCommand(data) { 26 | var command, 27 | str = data.toString('utf8', 0, data.length); 28 | 29 | command = str.split('\n'); 30 | return command[0]; 31 | } 32 | 33 | /** Parse headers */ 34 | function parseHeaders(raw_headers) { 35 | var headers = {}, 36 | headers_split = raw_headers.split('\n'); 37 | 38 | for (var i = 0; i < headers_split.length; i++) { 39 | var header = headers_split[i].split(':'); 40 | 41 | if (header.length > 1) { 42 | var key = header.shift().trim(); 43 | headers[key] = header.join(':').trim(); 44 | continue; 45 | } 46 | 47 | if (header[1]) { 48 | headers[header[0].trim()] = header[1].trim(); 49 | } 50 | } 51 | return headers; 52 | } 53 | 54 | function trimNull(a) { 55 | var c = a.indexOf('\0'); 56 | if (c > -1) { 57 | return a.substr(0, c); 58 | } 59 | return a; 60 | } 61 | 62 | var stompUtils = { 63 | genId: genId, 64 | 65 | tokenizeDestination: function (dest) { 66 | return dest.substr(dest.indexOf('/') + 1).split('.'); 67 | }, 68 | 69 | sendCommand: function (socket, command, headers, body, want_receipt) { 70 | if (headers === undefined) { 71 | headers = {}; 72 | } 73 | 74 | if (want_receipt === true) { 75 | headers.receipt = genId('r'); 76 | } 77 | 78 | var frame = new Frame({ 79 | 'command': command, 80 | 'headers': headers, 81 | 'body': body 82 | }); 83 | 84 | sendFrame(socket, frame); 85 | return frame; 86 | }, 87 | 88 | sendFrame: sendFrame, 89 | 90 | parseFrame: function (chunk) { 91 | if (chunk === undefined) { 92 | return null; 93 | } 94 | 95 | var command = parseCommand(chunk); 96 | var data = chunk.slice(command.length + 1, chunk.length); 97 | data = data.toString('utf8', 0, data.length); 98 | 99 | var the_rest = data.split('\n\n'); 100 | var headers = parseHeaders(the_rest[0]); 101 | var body = the_rest.slice(1, the_rest.length); 102 | 103 | if ('content-length' in headers) { 104 | headers.bytes_message = true; 105 | } 106 | 107 | return new Frame({ 108 | command: command, 109 | headers: headers, 110 | body: trimNull(body.toString()) 111 | }); 112 | } 113 | }; 114 | 115 | module.exports = stompUtils; 116 | -------------------------------------------------------------------------------- /lib/stomp.js: -------------------------------------------------------------------------------- 1 | var stompUtils = require('./stomp-utils'); 2 | 3 | var ServerFrame = { 4 | CONNECTED: function (socket, heartbeat, serverName) { 5 | stompUtils.sendCommand(socket, 'CONNECTED', { 6 | session: socket.sessionId, 7 | server: serverName, 8 | 'heart-beat': heartbeat, 9 | version: '1.1' 10 | }); 11 | }, 12 | 13 | MESSAGE: function (socket, frame) { 14 | stompUtils.sendCommand(socket, 'MESSAGE', frame.header, frame.body); 15 | }, 16 | 17 | RECEIPT: function (socket, receipt) { 18 | stompUtils.sendCommand(socket, 'RECEIPT', { 19 | 'receipt-id': receipt 20 | }); 21 | }, 22 | 23 | ERROR: function (socket, message, description) { 24 | var len = description !== undefined ? description.length : 0; 25 | var headers = { 26 | message: message, 27 | 'content-type': 'text/plain', 28 | 'content-length': len 29 | }; 30 | stompUtils.sendCommand(socket, 'ERROR', headers, description); 31 | } 32 | }; 33 | 34 | function FrameHandler(stompServer) { 35 | this.CONNECT = function (socket, frame) { 36 | // setup heart-beat feature 37 | var rawHeartbeat = frame.headers['heart-beat']; 38 | var clientHeartbeat = [0, 0]; 39 | if (rawHeartbeat) { 40 | clientHeartbeat = rawHeartbeat.split(',').map(function(x) { return parseInt(x); }); 41 | } 42 | 43 | // default server heart-beat answer 44 | var serverHeartbeat = [0, 0]; 45 | 46 | // check preferred heart-beat direction: client → server 47 | if (clientHeartbeat[0] > 0 && stompServer.conf.heartbeat[1] > 0) { 48 | serverHeartbeat[1] = Math.max(clientHeartbeat[0], stompServer.conf.heartbeat[1]); 49 | stompServer.heartbeatOn(socket, serverHeartbeat[1], false); 50 | } 51 | // check non-preferred heart-beat direction: server → client 52 | else if (clientHeartbeat[1] > 0 && stompServer.conf.heartbeat[0] > 0) { 53 | serverHeartbeat[0] = Math.max(clientHeartbeat[1], stompServer.conf.heartbeat[0]); 54 | stompServer.heartbeatOn(socket, serverHeartbeat[0], true); 55 | } 56 | 57 | if (stompServer.onClientConnected(socket, { 58 | heartbeat: clientHeartbeat, 59 | headers: frame.headers 60 | })) { 61 | ServerFrame.CONNECTED(socket, serverHeartbeat.join(','), stompServer.conf.serverName); 62 | } else { 63 | ServerFrame.ERROR(socket, 'CONNECTION ERROR', 'CONNECTION ERROR'); 64 | } 65 | }; 66 | 67 | this.DISCONNECT = function (socket, frame) { 68 | var receipt = frame.headers.receipt; 69 | if (stompServer.onDisconnect(socket, receipt)) { 70 | ServerFrame.RECEIPT(socket, receipt); 71 | } else { 72 | ServerFrame.ERROR(socket, 'DISCONNECT ERROR', receipt); 73 | } 74 | }; 75 | 76 | this.SUBSCRIBE = function (socket, frame) { 77 | var dest = frame.headers.destination; 78 | var ack = 'auto' || frame.headers.ack; 79 | if (!stompServer.onSubscribe(socket, { 80 | dest: dest, 81 | ack: ack, 82 | id: frame.headers.id 83 | })) { 84 | ServerFrame.ERROR(socket, 'SUBSCRIBE ERROR', dest); 85 | } 86 | }; 87 | 88 | this.UNSUBSCRIBE = function (socket, frame) { 89 | var id = frame.headers.id; 90 | if (!stompServer.onUnsubscribe(socket, id)) { 91 | ServerFrame.ERROR(socket, 'UNSUBSCRIBE ERROR', id); 92 | } 93 | }; 94 | 95 | this.SEND = function (socket, frame) { 96 | var dest = frame.headers.destination; 97 | var receipt = frame.headers.receipt; 98 | stompServer.onSend(socket, { 99 | dest: dest, 100 | frame: frame 101 | }, function (res) { 102 | if (res && receipt) { 103 | ServerFrame.RECEIPT(socket, receipt); 104 | } else if (!res) { 105 | ServerFrame.ERROR(socket, 'Send error', frame); 106 | } 107 | }); 108 | }; 109 | } 110 | 111 | module.exports = { 112 | StompUtils: stompUtils, 113 | ServerFrame: ServerFrame, 114 | FrameHandler: FrameHandler, 115 | genId: stompUtils.genId 116 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stomp-broker-js", 3 | "version": "1.3.1", 4 | "description": "Simple STOMP 1.1 Broker for nodejs http applications.", 5 | "main": "stompServer.js", 6 | "scripts": { 7 | "jsdoc": "jsdoc -c ./jsdoc-conf.json", 8 | "preversion": "npm run lint && npm run test", 9 | "prepublishOnly": "npm run lint && npm run test", 10 | "lint": "eslint stompServer.js lib", 11 | "test": "mocha" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/4ib3r/StompBrokerJS.git" 16 | }, 17 | "keywords": [ 18 | "STOMP", 19 | "broker", 20 | "server", 21 | "websocket" 22 | ], 23 | "author": "Adrian Sławiński ", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/4ib3r/StompBrokerJS/issues" 27 | }, 28 | "homepage": "https://4ib3r.github.io/StompBrokerJS", 29 | "dependencies": { 30 | "ws": "^5.2.2", 31 | "sockjs": "^0.3.19" 32 | }, 33 | "devDependencies": { 34 | "chai": "^4.2.0", 35 | "eslint": "^5.16.0", 36 | "minami": "^1.2.3", 37 | "mocha": "^5.1.1", 38 | "stompjs": "^2.3.3" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /stompServer.js: -------------------------------------------------------------------------------- 1 | var EventEmitter = require('events'); 2 | var util = require('util'); 3 | 4 | var stomp = require('./lib/stomp'); 5 | var stompUtils = require('./lib/stomp-utils'); 6 | var BYTES = require('./lib/bytes'); 7 | 8 | var protocolAdapter = require('./lib/adapter'); 9 | var buildConfig = require('./lib/config'); 10 | 11 | /** 12 | * STOMP Server configuration 13 | * 14 | * @typedef {object} ServerConfig 15 | * @param {http.Server} server Http server reference 16 | * @param {string} [serverName=STOMP-JS/VERSION] Name of STOMP server 17 | * @param {string} [path=/stomp] WebSocket path 18 | * @param {array} [heartbeat=[10000, 10000]] Heartbeat; read documentation to config according to your desire 19 | * @param {number} [heartbeatErrorMargin=1000] Heartbeat error margin; specify how strict server should be 20 | * @param {function} [debug=function(args) {}] Debug function 21 | */ 22 | 23 | /** 24 | * @typedef MsgFrame Message frame object 25 | * @property {string|Buffer} body Message body, string or Buffer 26 | * @property {object} headers Message headers 27 | */ 28 | 29 | /** 30 | * @class 31 | * @augments EventEmitter 32 | * 33 | * Create Stomp server with config 34 | * 35 | * @param {ServerConfig} config Configuration for STOMP server 36 | */ 37 | var StompServer = function (config) { 38 | EventEmitter.call(this); 39 | 40 | if (config === undefined) { 41 | config = {}; 42 | } 43 | 44 | this.conf = buildConfig(config); 45 | 46 | this.subscribes = []; 47 | this.middleware = {}; 48 | this.frameHandler = new stomp.FrameHandler(this); 49 | 50 | this.socket = new protocolAdapter[this.conf.protocol]({ 51 | ...this.conf.protocolConfig, 52 | server: this.conf.server, 53 | path: this.conf.path, 54 | perMessageDeflate: false 55 | }); 56 | /** 57 | * Client connecting event, emitted after socket is opened. 58 | * 59 | * @event StompServer#connecting 60 | * @type {object} 61 | * @property {string} sessionId 62 | */ 63 | this.socket.on('connection', function (ws) { 64 | ws.sessionId = stompUtils.genId(); 65 | 66 | this.emit('connecting', ws.sessionId); 67 | this.conf.debug('Connect', ws.sessionId); 68 | 69 | ws.on('message', this.parseRequest.bind(this, ws)); 70 | ws.on('close', this.onDisconnect.bind(this, ws)); 71 | ws.on('error', function (err) { 72 | this.conf.debug(err); 73 | this.emit('error', err); 74 | }.bind(this)); 75 | }.bind(this)); 76 | 77 | 78 | // 79 | 80 | /** 81 | * Add middle-ware for specific command 82 | * @param {('connect'|'disconnect'|'send'|'subscribe'|'unsubscribe')} command Command to hook 83 | * @param {function} handler function to add in middle-ware 84 | * */ 85 | this.addMiddleware = function (command, handler) { 86 | command = command.toLowerCase(); 87 | if (! this.middleware[command] ) { 88 | this.middleware[command] = []; 89 | } 90 | this.middleware[command].push(handler); 91 | }; 92 | 93 | /** 94 | * Clear and set middle-ware for specific command 95 | * @param {('connect'|'disconnect'|'send'|'subscribe'|'unsubscribe')} command Command to hook 96 | * @param {function} handler function to add in middle-ware 97 | * */ 98 | this.setMiddleware = function (command, handler) { 99 | command = command.toLowerCase(); 100 | this.middleware[command] = [handler]; 101 | }; 102 | 103 | /** 104 | * Remove middle-ware specific for command 105 | * @param {('connect'|'disconnect'|'send'|'subscribe'|'unsubscribe')} command Command with hook 106 | * @param {function} handler function to remove from middle-ware 107 | * */ 108 | this.removeMiddleware = function (command, handler) { 109 | var handlers = this.middleware[command.toLowerCase()]; 110 | var idx = handlers.indexOf(handler); 111 | if (idx >= 0) { 112 | handlers.splice(idx, 1); 113 | } 114 | }; 115 | 116 | 117 | function withMiddleware(command, finalHandler) { 118 | return function(socket, args) { 119 | var handlers = this.middleware[command.toLowerCase()] || []; 120 | var iter = handlers[Symbol.iterator](); 121 | var self = this; 122 | 123 | function callNext() { 124 | var iteration = iter.next(); 125 | if (iteration.done) { 126 | return finalHandler.call(self, socket, args); 127 | } 128 | return iteration.value(socket, args, callNext); 129 | } 130 | return callNext(); 131 | }; 132 | } 133 | 134 | 135 | /** 136 | * Client connected event, emitted after connection established and negotiated 137 | * 138 | * @event StompServer#connected 139 | * @type {object} 140 | * @property {string} sessionId 141 | * @property {object} headers 142 | */ 143 | this.onClientConnected = withMiddleware('connect', function (socket, args) { 144 | socket.clientHeartbeat = { 145 | client: args.heartbeat[0], 146 | server: args.heartbeat[1] 147 | }; 148 | this.conf.debug('CONNECT', socket.sessionId, socket.clientHeartbeat, args.headers); 149 | this.emit('connected', socket.sessionId, args.headers); 150 | return true; 151 | }); 152 | 153 | /** 154 | * Client disconnected event 155 | * 156 | * @event StompServer#disconnected 157 | * @type {object} 158 | * @property {string} sessionId 159 | * */ 160 | this.onDisconnect = withMiddleware('disconnect', function (socket /*, receiptId*/) { 161 | // TODO: Do we need to do anything with receiptId on disconnect? 162 | this.afterConnectionClose(socket); 163 | this.conf.debug('DISCONNECT', socket.sessionId); 164 | this.emit('disconnected', socket.sessionId); 165 | return true; 166 | }); 167 | 168 | 169 | /** 170 | * Event emitted when broker send message to subscribers 171 | * 172 | * @event StompServer#send 173 | * @type {object} 174 | * @property {string} dest Destination 175 | * @property {string} frame Message frame 176 | */ 177 | this.onSend = withMiddleware('send', function (socket, args, callback) { 178 | var bodyObj = args.frame.body; 179 | var frame = this.frameSerializer(args.frame); 180 | var headers = { 181 | //default headers 182 | 'message-id': stompUtils.genId('msg'), 183 | 'content-type': 'text/plain' 184 | }; 185 | 186 | if (frame.body !== undefined) { 187 | if (typeof frame.body !== 'string' && !Buffer.isBuffer(frame.body)) { 188 | throw 'Message body is not string'; 189 | } 190 | frame.headers['content-length'] = frame.body.length; 191 | } 192 | 193 | if (frame.headers) { 194 | for (var key in frame.headers) { 195 | headers[key] = frame.headers[key]; 196 | } 197 | } 198 | 199 | args.frame = frame; 200 | this.emit('send', { 201 | frame: { 202 | headers: frame.headers, 203 | body: bodyObj 204 | }, 205 | dest: args.dest 206 | }); 207 | 208 | this._sendToSubscriptions(socket, args); 209 | 210 | if (callback) { 211 | callback(true); 212 | } 213 | return true; 214 | }); 215 | 216 | 217 | /** 218 | * Client subscribe event, emitted when client subscribe topic 219 | * 220 | * @event StompServer#subscribe 221 | * @type {object} 222 | * @property {string} id Subscription id 223 | * @property {string} sessionId Socket session id 224 | * @property {string} topic Destination topic 225 | * @property {string[]} tokens Tokenized topic 226 | * @property {object} socket Connected socket 227 | */ 228 | this.onSubscribe = withMiddleware('subscribe', function (socket, args) { 229 | var sub = { 230 | id: args.id, 231 | sessionId: socket.sessionId, 232 | topic: args.dest, 233 | tokens: stompUtils.tokenizeDestination(args.dest), 234 | socket: socket 235 | }; 236 | this.subscribes.push(sub); 237 | this.emit('subscribe', sub); 238 | this.conf.debug('Server subscribe', args.id, args.dest); 239 | return true; 240 | }); 241 | 242 | 243 | /** 244 | * Client subscribe event, emitted when client unsubscribe topic 245 | * 246 | * @event StompServer#unsubscribe 247 | * @type {object} 248 | * @property {string} id Subscription id 249 | * @property {string} sessionId Socket session id 250 | * @property {string} topic Destination topic 251 | * @property {string[]} tokens Tokenized topic 252 | * @property {object} socket Connected socket 253 | * @return {boolean} 254 | */ 255 | this.onUnsubscribe = withMiddleware('unsubscribe', function (socket, subId) { 256 | for (var i = 0; i < this.subscribes.length; i++) { 257 | var sub = this.subscribes[i]; 258 | if (sub.id === subId && sub.sessionId === socket.sessionId) { 259 | this.subscribes.splice(i--, 1); 260 | this.emit('unsubscribe', sub); 261 | return true; 262 | } 263 | } 264 | return false; 265 | }); 266 | 267 | // 268 | 269 | 270 | // 271 | 272 | var selfSocket = { 273 | sessionId: 'self_1234' 274 | }; 275 | 276 | 277 | /** 278 | * Subscription callback method 279 | * 280 | * @callback OnSubscribedMessageCallback 281 | * @param {string} msg Message body 282 | * @param {object} headers Message headers 283 | * @param {string} headers.destination Message destination 284 | * @param {string} headers.subscription Id of subscription 285 | * @param {string} headers.message-id Id of message 286 | * @param {string} headers.content-type Content type 287 | * @param {string} headers.content-length Content length 288 | */ 289 | 290 | 291 | /** 292 | * Subscribe topic 293 | * 294 | * @param {string} topic Subscribed destination, wildcard is supported 295 | * @param {OnSubscribedMessageCallback=} callback Callback function 296 | * @param {object} headers Optional headers, used by client to provide a subscription ID (headers.id) 297 | * @return {string} Subscription id, when message is received event with this id is emitted 298 | * @example 299 | * stompServer.subscribe('/test.data', function(msg, headers) {}); 300 | * //or alternative 301 | * var subs_id = stompServer.subscribe('/test.data'); 302 | * stompServer.on(subs_id, function(msg, headers) {}); 303 | */ 304 | this.subscribe = function (topic, callback, headers) { 305 | var id; 306 | if (!headers || !headers.id) { 307 | id = 'self_' + Math.floor(Math.random() * 99999999999); 308 | } else { 309 | id = headers.id; 310 | } 311 | var sub = { 312 | topic: topic, 313 | tokens: stompUtils.tokenizeDestination(topic), 314 | id: id, 315 | sessionId: 'self_1234' 316 | }; 317 | this.subscribes.push(sub); 318 | this.emit('subscribe', sub); 319 | if (callback) { 320 | this.on(id, callback); 321 | } 322 | return id; 323 | }; 324 | 325 | 326 | /** Unsubscribe topic with subscription id 327 | * 328 | * @param {string} id Subscription id 329 | * @return {boolean} Subscription is deleted 330 | */ 331 | this.unsubscribe = function (id) { 332 | this.removeAllListeners(id); 333 | return this.onUnsubscribe(selfSocket, id); 334 | }; 335 | 336 | // 337 | 338 | 339 | // 340 | 341 | /** 342 | * Send message to matching subscribers. 343 | * 344 | * @param {object} socket websocket to send the message on 345 | * @param {string} args onSend args 346 | * @private 347 | */ 348 | this._sendToSubscriptions = function (socket, args) { 349 | for (var i = 0; i < this.subscribes.length; i++) { 350 | var sub = this.subscribes[i]; 351 | if (socket.sessionId === sub.sessionId) { 352 | continue; 353 | } 354 | var match = this._checkSubMatchDest(sub, args); 355 | if (match) { 356 | args.frame.headers.subscription = sub.id; 357 | args.frame.command = 'MESSAGE'; 358 | var sock = sub.socket; 359 | if (sock !== undefined) { 360 | stompUtils.sendFrame(sock, args.frame); 361 | } else { 362 | this.emit(sub.id, args.frame.body, args.frame.headers); 363 | } 364 | } 365 | } 366 | }; 367 | 368 | 369 | /** Send message to topic 370 | * 371 | * @param {string} topic Destination for message 372 | * @param {Object.} headers Message headers 373 | * @param {string} body Message body 374 | */ 375 | this.send = function (topic, headers, body) { 376 | var _headers = {}; 377 | if (headers) { 378 | for (var key in headers) { 379 | _headers[key] = headers[key]; 380 | } 381 | } 382 | var frame = { 383 | body: body, 384 | headers: _headers 385 | }; 386 | var args = { 387 | dest: topic, 388 | frame: this.frameParser(frame) 389 | }; 390 | this.onSend(selfSocket, args); 391 | }.bind(this); 392 | 393 | // 394 | 395 | 396 | // 397 | 398 | /** 399 | * Serialize frame to string for send 400 | * 401 | * @param {MsgFrame} frame Message frame 402 | * @return {MsgFrame} modified frame 403 | * */ 404 | this.frameSerializer = function (frame) { 405 | if (frame.body !== undefined && frame.headers['content-type'] === 'application/json' && !Buffer.isBuffer(frame.body)) { 406 | frame.body = JSON.stringify(frame.body); 407 | } 408 | return frame; 409 | }; 410 | 411 | 412 | /** 413 | * Parse frame to object for reading 414 | * 415 | * @param {MsgFrame} frame Message frame 416 | * @return {MsgFrame} modified frame 417 | * */ 418 | this.frameParser = function (frame) { 419 | if (frame.body !== undefined && frame.headers['content-type'] === 'application/json') { 420 | frame.body = JSON.parse(frame.body); 421 | } 422 | return frame; 423 | }; 424 | 425 | // 426 | 427 | 428 | // 429 | 430 | /** 431 | * Heart-beat: Turn On for given socket 432 | * 433 | * @param {WebSocket} socket Destination WebSocket 434 | * @param {number} interval Heart-beat interval 435 | * @param {boolean} serverSide If true then server is responsible for sending pings 436 | * */ 437 | this.heartbeatOn = function (socket, interval, serverSide) { 438 | var self = this; 439 | 440 | if (serverSide) { 441 | // Server takes responsibility for sending pings 442 | // Client should close connection on timeout 443 | socket.heartbeatClock = setInterval(function() { 444 | if(socket.readyState === 1) { 445 | self.conf.debug('PING'); 446 | socket.send(BYTES.LF); 447 | } 448 | }, interval); 449 | 450 | } else { 451 | // Client takes responsibility for sending pings 452 | // Server should close connection on timeout 453 | socket.heartbeatTime = Date.now() + interval; 454 | socket.heartbeatClock = setInterval(function() { 455 | var diff = Date.now() - socket.heartbeatTime; 456 | if (diff > interval + self.conf.heartbeatErrorMargin) { 457 | self.conf.debug('HEALTH CHECK failed! Closing', diff, interval); 458 | socket.close(); 459 | } else { 460 | self.conf.debug('HEALTH CHECK ok!', diff, interval); 461 | socket.heartbeatTime -= diff; 462 | } 463 | }, interval); 464 | } 465 | }; 466 | 467 | 468 | /** 469 | * Heart-beat: Turn Off for given socket 470 | * 471 | * @param {WebSocket} socket Destination WebSocket 472 | * */ 473 | this.heartbeatOff = function (socket) { 474 | if(socket.heartbeatClock !== undefined) { 475 | clearInterval(socket.heartbeatClock); 476 | delete socket.heartbeatClock; 477 | } 478 | }; 479 | 480 | // 481 | 482 | 483 | /** 484 | * Test if the input subscriber has subscribed to the target destination. 485 | * 486 | * @param sub the subscriber 487 | * @param args onSend args 488 | * @returns {boolean} true if the input subscription matches destination 489 | * @private 490 | */ 491 | this._checkSubMatchDest = function (sub, args) { 492 | var match = true; 493 | var tokens = stompUtils.tokenizeDestination(args.dest); 494 | for (var t in tokens) { 495 | var token = tokens[t]; 496 | if (sub.tokens[t] === undefined || (sub.tokens[t] !== token && sub.tokens[t] !== '*' && sub.tokens[t] !== '**')) { 497 | match = false; 498 | break; 499 | } else if (sub.tokens[t] === '**') { 500 | break; 501 | } 502 | } 503 | return match; 504 | }; 505 | 506 | 507 | /** 508 | * After connection close 509 | * 510 | * @param socket WebSocket connection that has been closed and is dying 511 | */ 512 | this.afterConnectionClose = function (socket) { 513 | // remove from subscribes 514 | for (var i = 0; i < this.subscribes.length; i++) { 515 | var sub = this.subscribes[i]; 516 | if (sub.sessionId === socket.sessionId) { 517 | this.subscribes.splice(i--, 1); 518 | } 519 | } 520 | 521 | // turn off server side heart-beat (if needed) 522 | this.heartbeatOff(socket); 523 | }; 524 | 525 | 526 | this.parseRequest = function(socket, data) { 527 | // check if it's incoming heartbeat 528 | if (socket.heartbeatClock !== undefined) { 529 | // beat 530 | socket.heartbeatTime = Date.now(); 531 | 532 | // if it's ping then ignore 533 | if(data === BYTES.LF) { 534 | this.conf.debug('PONG'); 535 | return; 536 | } 537 | } 538 | 539 | // normal data 540 | var frame = stompUtils.parseFrame(data); 541 | var cmdFunc = this.frameHandler[frame.command]; 542 | if (cmdFunc) { 543 | frame = this.frameParser(frame); 544 | return cmdFunc(socket, frame); 545 | } 546 | 547 | return 'Command not found'; 548 | }; 549 | 550 | }; 551 | 552 | util.inherits(StompServer, EventEmitter); 553 | 554 | // Export 555 | module.exports = StompServer; 556 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var http = require("http"); 2 | var StompServer = require('../stompServer'); 3 | var WebSocket = require('ws'); 4 | var stompjs = require('stompjs'); 5 | 6 | var assert = require('chai').assert; 7 | 8 | 9 | var server; 10 | var stompServer; 11 | 12 | var socket; 13 | var client; 14 | 15 | describe('StompServer', function() { 16 | 17 | beforeEach(function(done) { 18 | server = http.createServer(); 19 | stompServer = new StompServer({server: server}); 20 | server.listen(61614, function(err) { 21 | assert.ifError(err); 22 | console.log("Server listen"); 23 | socket = new WebSocket('ws://localhost:61614/stomp'); 24 | client = stompjs.over(socket); 25 | client.connect({ 26 | login: 'mylogin', 27 | passcode: 'mypasscode', 28 | 'client-id': 'my-client-id' 29 | }, function (error) { 30 | // display the error's message header: 31 | if (error.command === "ERROR") { 32 | console.error(error.headers.message); 33 | done(error); 34 | } else { 35 | console.log("Connected"); 36 | done(); 37 | } 38 | }); 39 | }); 40 | }); 41 | 42 | afterEach(function(done) { 43 | console.log("disconnect"); 44 | client.disconnect(function() { 45 | server.close(); 46 | done(); 47 | }); 48 | }); 49 | 50 | describe('#send', function() { 51 | it('check msg and topic wildcard subscription', function(done) { 52 | var headers = {'id': 'sub-0'}; 53 | stompServer.subscribe("/**", function(msg, headers) { 54 | var topic = headers.destination; 55 | assert.equal(topic, '/data'); 56 | assert.equal(msg, 'test body'); 57 | done(); 58 | }, headers); 59 | client.send('/data', {}, 'test body'); 60 | }); 61 | 62 | it('sub-topic wildcard subscription', function(done) { 63 | var msgCnt = 0; 64 | var timer = null; 65 | function check() { 66 | assert.equal(msgCnt, 2); 67 | done(); 68 | } 69 | stompServer.subscribe("test.**", function(msg, headers) { 70 | var topic = headers.destination; 71 | //assert.equal(topic, '/data'); 72 | assert.equal(msg, 'test body'); 73 | msgCnt++; 74 | clearTimeout(timer); 75 | timer = setTimeout(check, 200); 76 | }); 77 | client.send('test.data', {}, 'test body'); 78 | client.send('test.t1', {}, 'test body'); 79 | client.send('data.t1', {}, 'fail'); 80 | }); 81 | 82 | it('specific topic subscription', function(done) { 83 | var headers = {}; 84 | stompServer.subscribe("/ok", function(msg, headers) { 85 | var topic = headers.destination; 86 | assert.equal(topic, '/ok'); 87 | assert.equal(msg, 'test body'); 88 | done(); 89 | }, headers); 90 | stompServer.subscribe("/fail", function(msg, headers) { 91 | done(new Error("incorrect subscription executed")); 92 | }, headers); 93 | client.send('/ok', {}, 'test body'); 94 | }); 95 | }); 96 | 97 | describe('#subscribe', function() { 98 | it('check binary data delivery', function(done) { 99 | function onRawMessage(msg) { 100 | assert.instanceOf(msg, ArrayBuffer); 101 | var text = Buffer.from(msg).toString(); 102 | assert.match(text, /^MESSAGE(.|\n)*\n\nbinary body\0$/); 103 | done(); 104 | } 105 | stompServer.on('subscribe', function() { 106 | var data = Buffer.from('binary body'); 107 | socket.once('message', onRawMessage); 108 | stompServer.send('/data', {'content-type': 'application/octet-stream'}, data); 109 | }); 110 | client.subscribe("/data"); 111 | }); 112 | }); 113 | 114 | describe('#unsubscribe', function() { 115 | it('check topic unsubscribe', function(done) { 116 | var isSubscribed = true; 117 | var subId = stompServer.subscribe("/**", function(msg, headers) { 118 | assert.equal(headers.destination, '/test'); 119 | assert.equal(msg, 'test'); 120 | assert.isTrue(isSubscribed); 121 | assert.isTrue(stompServer.unsubscribe(subId), 'unsubscribe fail, subId: ' + subId); 122 | isSubscribed = false; 123 | setTimeout(function () { 124 | done(); 125 | }, 200); 126 | client.send("/test", {}, "test"); //second send msg 127 | }, {}); 128 | client.send("/test", {}, "test"); 129 | }); 130 | }); 131 | }); 132 | --------------------------------------------------------------------------------