UNPKG

27.4 kBPlain TextView Raw
1import { ITransaction } from './i-transaction';
2import { StompConfig } from './stomp-config';
3import { StompHandler } from './stomp-handler';
4import { StompHeaders } from './stomp-headers';
5import { StompSubscription } from './stomp-subscription';
6import {
7 ActivationState,
8 closeEventCallbackType,
9 debugFnType,
10 frameCallbackType,
11 IPublishParams,
12 IStompSocket,
13 messageCallbackType,
14 StompSocketState,
15 wsErrorCallbackType,
16} from './types';
17import { Versions } from './versions';
18
19/**
20 * @internal
21 */
22declare const WebSocket: {
23 prototype: IStompSocket;
24 new (url: string, protocols?: string | string[]): IStompSocket;
25};
26
27/**
28 * STOMP Client Class.
29 *
30 * Part of `@stomp/stompjs`.
31 */
32export class Client {
33 /**
34 * The URL for the STOMP broker to connect to.
35 * Typically like `"ws://broker.329broker.com:15674/ws"` or `"wss://broker.329broker.com:15674/ws"`.
36 *
37 * Only one of this or [Client#webSocketFactory]{@link Client#webSocketFactory} need to be set.
38 * If both are set, [Client#webSocketFactory]{@link Client#webSocketFactory} will be used.
39 *
40 * If your environment does not support WebSockets natively, please refer to
41 * [Polyfills]{@link https://stomp-js.github.io/guide/stompjs/rx-stomp/ng2-stompjs/pollyfils-for-stompjs-v5.html}.
42 */
43 public brokerURL: string;
44
45 /**
46 * STOMP versions to attempt during STOMP handshake. By default versions `1.0`, `1.1`, and `1.2` are attempted.
47 *
48 * Example:
49 * ```javascript
50 * // Try only versions 1.0 and 1.1
51 * client.stompVersions = new Versions(['1.0', '1.1'])
52 * ```
53 */
54 public stompVersions = Versions.default;
55
56 /**
57 * This function should return a WebSocket or a similar (e.g. SockJS) object.
58 * If your environment does not support WebSockets natively, please refer to
59 * [Polyfills]{@link https://stomp-js.github.io/guide/stompjs/rx-stomp/ng2-stompjs/pollyfils-for-stompjs-v5.html}.
60 * If your STOMP Broker supports WebSockets, prefer setting [Client#brokerURL]{@link Client#brokerURL}.
61 *
62 * If both this and [Client#brokerURL]{@link Client#brokerURL} are set, this will be used.
63 *
64 * Example:
65 * ```javascript
66 * // use a WebSocket
67 * client.webSocketFactory= function () {
68 * return new WebSocket("wss://broker.329broker.com:15674/ws");
69 * };
70 *
71 * // Typical usage with SockJS
72 * client.webSocketFactory= function () {
73 * return new SockJS("http://broker.329broker.com/stomp");
74 * };
75 * ```
76 */
77 public webSocketFactory: () => IStompSocket;
78
79 /**
80 * Will retry if Stomp connection is not established in specified milliseconds.
81 * Default 0, which implies wait for ever.
82 */
83 public connectionTimeout: number = 0;
84
85 private _connectionWatcher: number; // Timer
86
87 /**
88 * automatically reconnect with delay in milliseconds, set to 0 to disable.
89 */
90 public reconnectDelay: number = 5000;
91
92 /**
93 * Incoming heartbeat interval in milliseconds. Set to 0 to disable.
94 */
95 public heartbeatIncoming: number = 10000;
96
97 /**
98 * Outgoing heartbeat interval in milliseconds. Set to 0 to disable.
99 */
100 public heartbeatOutgoing: number = 10000;
101
102 /**
103 * This switches on a non standard behavior while sending WebSocket packets.
104 * It splits larger (text) packets into chunks of [maxWebSocketChunkSize]{@link Client#maxWebSocketChunkSize}.
105 * Only Java Spring brokers seems to use this mode.
106 *
107 * WebSockets, by itself, split large (text) packets,
108 * so it is not needed with a truly compliant STOMP/WebSocket broker.
109 * Actually setting it for such broker will cause large messages to fail.
110 *
111 * `false` by default.
112 *
113 * Binary frames are never split.
114 */
115 public splitLargeFrames: boolean = false;
116
117 /**
118 * See [splitLargeFrames]{@link Client#splitLargeFrames}.
119 * This has no effect if [splitLargeFrames]{@link Client#splitLargeFrames} is `false`.
120 */
121 public maxWebSocketChunkSize: number = 8 * 1024;
122
123 /**
124 * Usually the
125 * [type of WebSocket frame]{@link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send#Parameters}
126 * is automatically decided by type of the payload.
127 * Default is `false`, which should work with all compliant brokers.
128 *
129 * Set this flag to force binary frames.
130 */
131 public forceBinaryWSFrames: boolean = false;
132
133 /**
134 * A bug in ReactNative chops a string on occurrence of a NULL.
135 * See issue [https://github.com/stomp-js/stompjs/issues/89]{@link https://github.com/stomp-js/stompjs/issues/89}.
136 * This makes incoming WebSocket messages invalid STOMP packets.
137 * Setting this flag attempts to reverse the damage by appending a NULL.
138 * If the broker splits a large message into multiple WebSocket messages,
139 * this flag will cause data loss and abnormal termination of connection.
140 *
141 * This is not an ideal solution, but a stop gap until the underlying issue is fixed at ReactNative library.
142 */
143 public appendMissingNULLonIncoming: boolean = false;
144
145 /**
146 * Underlying WebSocket instance, READONLY.
147 */
148 get webSocket(): IStompSocket {
149 return this._stompHandler ? this._stompHandler._webSocket : undefined;
150 }
151
152 /**
153 * Connection headers, important keys - `login`, `passcode`, `host`.
154 * Though STOMP 1.2 standard marks these keys to be present, check your broker documentation for
155 * details specific to your broker.
156 */
157 public connectHeaders: StompHeaders;
158
159 /**
160 * Disconnection headers.
161 */
162 get disconnectHeaders(): StompHeaders {
163 return this._disconnectHeaders;
164 }
165
166 set disconnectHeaders(value: StompHeaders) {
167 this._disconnectHeaders = value;
168 if (this._stompHandler) {
169 this._stompHandler.disconnectHeaders = this._disconnectHeaders;
170 }
171 }
172 private _disconnectHeaders: StompHeaders;
173
174 /**
175 * This function will be called for any unhandled messages.
176 * It is useful for receiving messages sent to RabbitMQ temporary queues.
177 *
178 * It can also get invoked with stray messages while the server is processing
179 * a request to [Client#unsubscribe]{@link Client#unsubscribe}
180 * from an endpoint.
181 *
182 * The actual {@link IMessage} will be passed as parameter to the callback.
183 */
184 public onUnhandledMessage: messageCallbackType;
185
186 /**
187 * STOMP brokers can be requested to notify when an operation is actually completed.
188 * Prefer using [Client#watchForReceipt]{@link Client#watchForReceipt}. See
189 * [Client#watchForReceipt]{@link Client#watchForReceipt} for examples.
190 *
191 * The actual {@link FrameImpl} will be passed as parameter to the callback.
192 */
193 public onUnhandledReceipt: frameCallbackType;
194
195 /**
196 * Will be invoked if {@link FrameImpl} of unknown type is received from the STOMP broker.
197 *
198 * The actual {@link IFrame} will be passed as parameter to the callback.
199 */
200 public onUnhandledFrame: frameCallbackType;
201
202 /**
203 * `true` if there is a active connection with STOMP Broker
204 */
205 get connected(): boolean {
206 return !!this._stompHandler && this._stompHandler.connected;
207 }
208
209 /**
210 * Callback, invoked on before a connection connection to the STOMP broker.
211 *
212 * You can change options on the client, which will impact the immediate connect.
213 * It is valid to call [Client#decativate]{@link Client#deactivate} in this callback.
214 *
215 * As of version 5.1, this callback can be
216 * [async](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)
217 * (i.e., it can return a
218 * [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)).
219 * In that case connect will be called only after the Promise is resolved.
220 * This can be used to reliably fetch credentials, access token etc. from some other service
221 * in an asynchronous way.
222 */
223 public beforeConnect: () => void | Promise<void>;
224
225 /**
226 * Callback, invoked on every successful connection to the STOMP broker.
227 *
228 * The actual {@link FrameImpl} will be passed as parameter to the callback.
229 * Sometimes clients will like to use headers from this frame.
230 */
231 public onConnect: frameCallbackType;
232
233 /**
234 * Callback, invoked on every successful disconnection from the STOMP broker. It will not be invoked if
235 * the STOMP broker disconnected due to an error.
236 *
237 * The actual Receipt {@link FrameImpl} acknowledging the DISCONNECT will be passed as parameter to the callback.
238 *
239 * The way STOMP protocol is designed, the connection may close/terminate without the client
240 * receiving the Receipt {@link FrameImpl} acknowledging the DISCONNECT.
241 * You might find [Client#onWebSocketClose]{@link Client#onWebSocketClose} more appropriate to watch
242 * STOMP broker disconnects.
243 */
244 public onDisconnect: frameCallbackType;
245
246 /**
247 * Callback, invoked on an ERROR frame received from the STOMP Broker.
248 * A compliant STOMP Broker will close the connection after this type of frame.
249 * Please check broker specific documentation for exact behavior.
250 *
251 * The actual {@link IFrame} will be passed as parameter to the callback.
252 */
253 public onStompError: frameCallbackType;
254
255 /**
256 * Callback, invoked when underlying WebSocket is closed.
257 *
258 * Actual [CloseEvent]{@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}
259 * is passed as parameter to the callback.
260 */
261 public onWebSocketClose: closeEventCallbackType;
262
263 /**
264 * Callback, invoked when underlying WebSocket raises an error.
265 *
266 * Actual [Event]{@link https://developer.mozilla.org/en-US/docs/Web/API/Event}
267 * is passed as parameter to the callback.
268 */
269 public onWebSocketError: wsErrorCallbackType;
270
271 /**
272 * Set it to log the actual raw communication with the broker.
273 * When unset, it logs headers of the parsed frames.
274 *
275 * Change in this effects from next broker reconnect.
276 *
277 * **Caution: this assumes that frames only have valid UTF8 strings.**
278 */
279 public logRawCommunication: boolean;
280
281 /**
282 * By default, debug messages are discarded. To log to `console` following can be used:
283 *
284 * ```javascript
285 * client.debug = function(str) {
286 * console.log(str);
287 * };
288 * ```
289 *
290 * Currently this method does not support levels of log. Be aware that the output can be quite verbose
291 * and may contain sensitive information (like passwords, tokens etc.).
292 */
293 public debug: debugFnType;
294
295 /**
296 * Browsers do not immediately close WebSockets when `.close` is issued.
297 * This may cause reconnection to take a longer on certain type of failures.
298 * In case of incoming heartbeat failure, this experimental flag instructs the library
299 * to discard the socket immediately (even before it is actually closed).
300 */
301 public discardWebsocketOnCommFailure: boolean;
302
303 /**
304 * version of STOMP protocol negotiated with the server, READONLY
305 */
306 get connectedVersion(): string {
307 return this._stompHandler ? this._stompHandler.connectedVersion : undefined;
308 }
309
310 private _stompHandler: StompHandler;
311
312 /**
313 * if the client is active (connected or going to reconnect)
314 */
315 get active(): boolean {
316 return this.state === ActivationState.ACTIVE;
317 }
318
319 /**
320 * It will be called on state change.
321 *
322 * When deactivating it may go from ACTIVE to INACTIVE without entering DEACTIVATING.
323 */
324 public onChangeState: (state: ActivationState) => void;
325
326 private _changeState(state: ActivationState) {
327 this.state = state;
328 this.onChangeState(state);
329 }
330
331 // This will mark deactivate to complete, to be called after Websocket is closed
332 private _resolveSocketClose: (value?: PromiseLike<void> | void) => void;
333
334 /**
335 * Activation state.
336 *
337 * It will usually be ACTIVE or INACTIVE.
338 * When deactivating it may go from ACTIVE to INACTIVE without entering DEACTIVATING.
339 */
340 public state: ActivationState = ActivationState.INACTIVE;
341
342 private _reconnector: any;
343
344 /**
345 * Create an instance.
346 */
347 constructor(conf: StompConfig = {}) {
348 // Dummy callbacks
349 const noOp = () => {};
350 this.debug = noOp;
351 this.beforeConnect = noOp;
352 this.onConnect = noOp;
353 this.onDisconnect = noOp;
354 this.onUnhandledMessage = noOp;
355 this.onUnhandledReceipt = noOp;
356 this.onUnhandledFrame = noOp;
357 this.onStompError = noOp;
358 this.onWebSocketClose = noOp;
359 this.onWebSocketError = noOp;
360 this.logRawCommunication = false;
361 this.onChangeState = noOp;
362
363 // These parameters would typically get proper values before connect is called
364 this.connectHeaders = {};
365 this._disconnectHeaders = {};
366
367 // Apply configuration
368 this.configure(conf);
369 }
370
371 /**
372 * Update configuration.
373 */
374 public configure(conf: StompConfig): void {
375 // bulk assign all properties to this
376 (Object as any).assign(this, conf);
377 }
378
379 /**
380 * Initiate the connection with the broker.
381 * If the connection breaks, as per [Client#reconnectDelay]{@link Client#reconnectDelay},
382 * it will keep trying to reconnect.
383 *
384 * Call [Client#deactivate]{@link Client#deactivate} to disconnect and stop reconnection attempts.
385 */
386 public activate(): void {
387 if (this.state === ActivationState.DEACTIVATING) {
388 this.debug(
389 'Still DEACTIVATING, please await call to deactivate before trying to re-activate'
390 );
391 throw new Error('Still DEACTIVATING, can not activate now');
392 }
393
394 if (this.active) {
395 this.debug('Already ACTIVE, ignoring request to activate');
396 return;
397 }
398
399 this._changeState(ActivationState.ACTIVE);
400
401 this._connect();
402 }
403
404 private async _connect(): Promise<void> {
405 if (this.connected) {
406 this.debug('STOMP: already connected, nothing to do');
407 return;
408 }
409
410 await this.beforeConnect();
411
412 if (!this.active) {
413 this.debug(
414 'Client has been marked inactive, will not attempt to connect'
415 );
416 return;
417 }
418
419 // setup connection watcher
420 if (this.connectionTimeout > 0) {
421 // clear first
422 if (this._connectionWatcher) {
423 clearTimeout(this._connectionWatcher);
424 }
425 this._connectionWatcher = setTimeout(() => {
426 if (this.connected) {
427 return;
428 }
429 // Connection not established, close the underlying socket
430 // a reconnection will be attempted
431 this.debug(
432 `Connection not established in ${this.connectionTimeout}ms, closing socket`
433 );
434 this.forceDisconnect();
435 }, this.connectionTimeout);
436 }
437
438 this.debug('Opening Web Socket...');
439
440 // Get the actual WebSocket (or a similar object)
441 const webSocket = this._createWebSocket();
442
443 this._stompHandler = new StompHandler(this, webSocket, {
444 debug: this.debug,
445 stompVersions: this.stompVersions,
446 connectHeaders: this.connectHeaders,
447 disconnectHeaders: this._disconnectHeaders,
448 heartbeatIncoming: this.heartbeatIncoming,
449 heartbeatOutgoing: this.heartbeatOutgoing,
450 splitLargeFrames: this.splitLargeFrames,
451 maxWebSocketChunkSize: this.maxWebSocketChunkSize,
452 forceBinaryWSFrames: this.forceBinaryWSFrames,
453 logRawCommunication: this.logRawCommunication,
454 appendMissingNULLonIncoming: this.appendMissingNULLonIncoming,
455 discardWebsocketOnCommFailure: this.discardWebsocketOnCommFailure,
456
457 onConnect: frame => {
458 // Successfully connected, stop the connection watcher
459 if (this._connectionWatcher) {
460 clearTimeout(this._connectionWatcher);
461 this._connectionWatcher = undefined;
462 }
463
464 if (!this.active) {
465 this.debug(
466 'STOMP got connected while deactivate was issued, will disconnect now'
467 );
468 this._disposeStompHandler();
469 return;
470 }
471 this.onConnect(frame);
472 },
473 onDisconnect: frame => {
474 this.onDisconnect(frame);
475 },
476 onStompError: frame => {
477 this.onStompError(frame);
478 },
479 onWebSocketClose: evt => {
480 this._stompHandler = undefined; // a new one will be created in case of a reconnect
481
482 if (this.state === ActivationState.DEACTIVATING) {
483 // Mark deactivation complete
484 this._resolveSocketClose();
485 this._resolveSocketClose = undefined;
486 this._changeState(ActivationState.INACTIVE);
487 }
488
489 this.onWebSocketClose(evt);
490 // The callback is called before attempting to reconnect, this would allow the client
491 // to be `deactivated` in the callback.
492 if (this.active) {
493 this._schedule_reconnect();
494 }
495 },
496 onWebSocketError: evt => {
497 this.onWebSocketError(evt);
498 },
499 onUnhandledMessage: message => {
500 this.onUnhandledMessage(message);
501 },
502 onUnhandledReceipt: frame => {
503 this.onUnhandledReceipt(frame);
504 },
505 onUnhandledFrame: frame => {
506 this.onUnhandledFrame(frame);
507 },
508 });
509
510 this._stompHandler.start();
511 }
512
513 private _createWebSocket(): IStompSocket {
514 let webSocket: IStompSocket;
515
516 if (this.webSocketFactory) {
517 webSocket = this.webSocketFactory();
518 } else {
519 webSocket = new WebSocket(
520 this.brokerURL,
521 this.stompVersions.protocolVersions()
522 );
523 }
524 webSocket.binaryType = 'arraybuffer';
525 return webSocket;
526 }
527
528 private _schedule_reconnect(): void {
529 if (this.reconnectDelay > 0) {
530 this.debug(`STOMP: scheduling reconnection in ${this.reconnectDelay}ms`);
531
532 this._reconnector = setTimeout(() => {
533 this._connect();
534 }, this.reconnectDelay);
535 }
536 }
537
538 /**
539 * Disconnect if connected and stop auto reconnect loop.
540 * Appropriate callbacks will be invoked if underlying STOMP connection was connected.
541 *
542 * This call is async, it will resolve immediately if there is no underlying active websocket,
543 * otherwise, it will resolve after underlying websocket is properly disposed.
544 *
545 * To reactivate you can call [Client#activate]{@link Client#activate}.
546 */
547 public async deactivate(): Promise<void> {
548 let retPromise: Promise<void>;
549
550 if (this.state !== ActivationState.ACTIVE) {
551 this.debug(
552 `Already ${ActivationState[this.state]}, ignoring call to deactivate`
553 );
554 return Promise.resolve();
555 }
556
557 this._changeState(ActivationState.DEACTIVATING);
558
559 // Clear if a reconnection was scheduled
560 if (this._reconnector) {
561 clearTimeout(this._reconnector);
562 }
563
564 if (
565 this._stompHandler &&
566 this.webSocket.readyState !== StompSocketState.CLOSED
567 ) {
568 // we need to wait for underlying websocket to close
569 retPromise = new Promise<void>((resolve, reject) => {
570 this._resolveSocketClose = resolve;
571 });
572 } else {
573 // indicate that auto reconnect loop should terminate
574 this._changeState(ActivationState.INACTIVE);
575 return Promise.resolve();
576 }
577
578 this._disposeStompHandler();
579
580 return retPromise;
581 }
582
583 /**
584 * Force disconnect if there is an active connection by directly closing the underlying WebSocket.
585 * This is different than a normal disconnect where a DISCONNECT sequence is carried out with the broker.
586 * After forcing disconnect, automatic reconnect will be attempted.
587 * To stop further reconnects call [Client#deactivate]{@link Client#deactivate} as well.
588 */
589 public forceDisconnect() {
590 if (this._stompHandler) {
591 this._stompHandler.forceDisconnect();
592 }
593 }
594
595 private _disposeStompHandler() {
596 // Dispose STOMP Handler
597 if (this._stompHandler) {
598 this._stompHandler.dispose();
599 this._stompHandler = null;
600 }
601 }
602
603 /**
604 * Send a message to a named destination. Refer to your STOMP broker documentation for types
605 * and naming of destinations.
606 *
607 * STOMP protocol specifies and suggests some headers and also allows broker specific headers.
608 *
609 * `body` must be String.
610 * You will need to covert the payload to string in case it is not string (e.g. JSON).
611 *
612 * To send a binary message body use binaryBody parameter. It should be a
613 * [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array).
614 * Sometimes brokers may not support binary frames out of the box.
615 * Please check your broker documentation.
616 *
617 * `content-length` header is automatically added to the STOMP Frame sent to the broker.
618 * Set `skipContentLengthHeader` to indicate that `content-length` header should not be added.
619 * For binary messages `content-length` header is always added.
620 *
621 * Caution: The broker will, most likely, report an error and disconnect if message body has NULL octet(s)
622 * and `content-length` header is missing.
623 *
624 * ```javascript
625 * client.publish({destination: "/queue/test", headers: {priority: 9}, body: "Hello, STOMP"});
626 *
627 * // Only destination is mandatory parameter
628 * client.publish({destination: "/queue/test", body: "Hello, STOMP"});
629 *
630 * // Skip content-length header in the frame to the broker
631 * client.publish({"/queue/test", body: "Hello, STOMP", skipContentLengthHeader: true});
632 *
633 * var binaryData = generateBinaryData(); // This need to be of type Uint8Array
634 * // setting content-type header is not mandatory, however a good practice
635 * client.publish({destination: '/topic/special', binaryBody: binaryData,
636 * headers: {'content-type': 'application/octet-stream'}});
637 * ```
638 */
639 public publish(params: IPublishParams) {
640 this._stompHandler.publish(params);
641 }
642
643 /**
644 * STOMP brokers may carry out operation asynchronously and allow requesting for acknowledgement.
645 * To request an acknowledgement, a `receipt` header needs to be sent with the actual request.
646 * The value (say receipt-id) for this header needs to be unique for each use. Typically a sequence, a UUID, a
647 * random number or a combination may be used.
648 *
649 * A complaint broker will send a RECEIPT frame when an operation has actually been completed.
650 * The operation needs to be matched based in the value of the receipt-id.
651 *
652 * This method allow watching for a receipt and invoke the callback
653 * when corresponding receipt has been received.
654 *
655 * The actual {@link FrameImpl} will be passed as parameter to the callback.
656 *
657 * Example:
658 * ```javascript
659 * // Subscribing with acknowledgement
660 * let receiptId = randomText();
661 *
662 * client.watchForReceipt(receiptId, function() {
663 * // Will be called after server acknowledges
664 * });
665 *
666 * client.subscribe(TEST.destination, onMessage, {receipt: receiptId});
667 *
668 *
669 * // Publishing with acknowledgement
670 * receiptId = randomText();
671 *
672 * client.watchForReceipt(receiptId, function() {
673 * // Will be called after server acknowledges
674 * });
675 * client.publish({destination: TEST.destination, headers: {receipt: receiptId}, body: msg});
676 * ```
677 */
678 public watchForReceipt(receiptId: string, callback: frameCallbackType): void {
679 this._stompHandler.watchForReceipt(receiptId, callback);
680 }
681
682 /**
683 * Subscribe to a STOMP Broker location. The callback will be invoked for each received message with
684 * the {@link IMessage} as argument.
685 *
686 * Note: The library will generate an unique ID if there is none provided in the headers.
687 * To use your own ID, pass it using the headers argument.
688 *
689 * ```javascript
690 * callback = function(message) {
691 * // called when the client receives a STOMP message from the server
692 * if (message.body) {
693 * alert("got message with body " + message.body)
694 * } else {
695 * alert("got empty message");
696 * }
697 * });
698 *
699 * var subscription = client.subscribe("/queue/test", callback);
700 *
701 * // Explicit subscription id
702 * var mySubId = 'my-subscription-id-001';
703 * var subscription = client.subscribe(destination, callback, { id: mySubId });
704 * ```
705 */
706 public subscribe(
707 destination: string,
708 callback: messageCallbackType,
709 headers: StompHeaders = {}
710 ): StompSubscription {
711 return this._stompHandler.subscribe(destination, callback, headers);
712 }
713
714 /**
715 * It is preferable to unsubscribe from a subscription by calling
716 * `unsubscribe()` directly on {@link StompSubscription} returned by `client.subscribe()`:
717 *
718 * ```javascript
719 * var subscription = client.subscribe(destination, onmessage);
720 * // ...
721 * subscription.unsubscribe();
722 * ```
723 *
724 * See: http://stomp.github.com/stomp-specification-1.2.html#UNSUBSCRIBE UNSUBSCRIBE Frame
725 */
726 public unsubscribe(id: string, headers: StompHeaders = {}): void {
727 this._stompHandler.unsubscribe(id, headers);
728 }
729
730 /**
731 * Start a transaction, the returned {@link ITransaction} has methods - [commit]{@link ITransaction#commit}
732 * and [abort]{@link ITransaction#abort}.
733 *
734 * `transactionId` is optional, if not passed the library will generate it internally.
735 */
736 public begin(transactionId?: string): ITransaction {
737 return this._stompHandler.begin(transactionId);
738 }
739
740 /**
741 * Commit a transaction.
742 *
743 * It is preferable to commit a transaction by calling [commit]{@link ITransaction#commit} directly on
744 * {@link ITransaction} returned by [client.begin]{@link Client#begin}.
745 *
746 * ```javascript
747 * var tx = client.begin(txId);
748 * //...
749 * tx.commit();
750 * ```
751 */
752 public commit(transactionId: string): void {
753 this._stompHandler.commit(transactionId);
754 }
755
756 /**
757 * Abort a transaction.
758 * It is preferable to abort a transaction by calling [abort]{@link ITransaction#abort} directly on
759 * {@link ITransaction} returned by [client.begin]{@link Client#begin}.
760 *
761 * ```javascript
762 * var tx = client.begin(txId);
763 * //...
764 * tx.abort();
765 * ```
766 */
767 public abort(transactionId: string): void {
768 this._stompHandler.abort(transactionId);
769 }
770
771 /**
772 * ACK a message. It is preferable to acknowledge a message by calling [ack]{@link IMessage#ack} directly
773 * on the {@link IMessage} handled by a subscription callback:
774 *
775 * ```javascript
776 * var callback = function (message) {
777 * // process the message
778 * // acknowledge it
779 * message.ack();
780 * };
781 * client.subscribe(destination, callback, {'ack': 'client'});
782 * ```
783 */
784 public ack(
785 messageId: string,
786 subscriptionId: string,
787 headers: StompHeaders = {}
788 ): void {
789 this._stompHandler.ack(messageId, subscriptionId, headers);
790 }
791
792 /**
793 * NACK a message. It is preferable to acknowledge a message by calling [nack]{@link IMessage#nack} directly
794 * on the {@link IMessage} handled by a subscription callback:
795 *
796 * ```javascript
797 * var callback = function (message) {
798 * // process the message
799 * // an error occurs, nack it
800 * message.nack();
801 * };
802 * client.subscribe(destination, callback, {'ack': 'client'});
803 * ```
804 */
805 public nack(
806 messageId: string,
807 subscriptionId: string,
808 headers: StompHeaders = {}
809 ): void {
810 this._stompHandler.nack(messageId, subscriptionId, headers);
811 }
812}
813
\No newline at end of file