├── .editorconfig
├── .github
└── FUNDING.yml
├── .gitignore
├── .vscode
├── settings.json
└── tasks.json
├── Gruntfile.js
├── README.md
├── bower.json
├── lib
├── browser.js
├── emitter.d.ts
├── emitter.js
├── emitter.js.map
└── emitter.ts
├── package-lock.json
├── package.json
├── sample
├── emitter.js
└── index.html
├── tsconfig.json
├── tsd.json
└── typings
├── node
└── node.d.ts
└── tsd.d.ts
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 | root = true
3 |
4 | [*]
5 | end_of_line = lf
6 | insert_final_newline = false
7 | charset = utf-8
8 | indent_style = space
9 | indent_size = 4
10 |
11 | [*.json]
12 | indent_size = 2
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [kelindar]
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directory
27 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
28 | node_modules
29 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.exclude": {
3 | "**/.git": true,
4 | "conf": true,
5 | "gulp_tasks": true,
6 | "**/gulpfile.js": true,
7 | "**/index.spec.js": true,
8 | "tslint.json": true,
9 | "**/.DS_Store": true,
10 | "**/*.js.map": true,
11 | "**/.*": true,
12 | "node_modules": true,
13 | "**/*.js": {
14 | "when": "$(basename).ts"
15 | },
16 | "**/*?.js": {
17 | "when": "$(basename).tsx"
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.1.0",
3 | "command": "tsc",
4 | "isShellCommand": true,
5 | "showOutput": "silent",
6 | "args": [],
7 | "problemMatcher": "$tsc"
8 | }
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | // Project configuration.
4 | grunt.initConfig({
5 | browserify: {
6 | options: {
7 | alias: {
8 | 'emitter': '.'
9 | }
10 | },
11 | js: {
12 | src: '.',
13 | dest: 'build/emitter.js',
14 | }
15 | },
16 |
17 | concat: {
18 | dist: {
19 | src: ['build/emitter.js', 'lib/browser.js'],
20 | dest: 'build/emitter.js',
21 | },
22 | },
23 |
24 |
25 | uglify: {
26 | options: {
27 | mangle: true,
28 | compress: {
29 | sequences: true,
30 | dead_code: true,
31 | conditionals: true,
32 | booleans: true,
33 | unused: true,
34 | if_return: true,
35 | join_vars: true,
36 | drop_console: true
37 | }
38 |
39 | },
40 | js: {
41 | files: { 'build/emitter.min.js': ['build/emitter.js'] }
42 | }
43 | },
44 |
45 | watch: {
46 | scripts: {
47 | files: ['lib/*.js'],
48 | tasks: ['default'],
49 | options: { spawn: false },
50 | },
51 | },
52 |
53 | compress: {
54 | main: {
55 | options: {
56 | mode: 'gzip'
57 | },
58 | files: [
59 |
60 | { expand: true, src: ['build/*.min.js'], dest: '', ext: '.gz.js' }
61 | ]
62 | }
63 | },
64 |
65 | copy: {
66 | js: {
67 | files: [
68 | {
69 | cwd: 'build/',
70 | src: 'emitter.js',
71 | dest: 'sample/',
72 | expand: true }
73 | ]
74 | }
75 | }
76 |
77 | });
78 |
79 | grunt.loadNpmTasks('grunt-browserify');
80 | grunt.loadNpmTasks('grunt-contrib-uglify');
81 | grunt.loadNpmTasks('grunt-contrib-watch');
82 | grunt.loadNpmTasks('grunt-contrib-compress');
83 | grunt.loadNpmTasks('grunt-contrib-concat');
84 | grunt.loadNpmTasks('grunt-contrib-copy');
85 |
86 | grunt.registerTask('default', ['browserify', 'concat', 'uglify', 'compress', 'copy:js']);
87 | };
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://nodei.co/npm/emitter-io/)
2 | [](https://nodei.co/npm/emitter-io/)
3 |
4 | This repository contains JavaScript client for both NodeJS and the Browser for [Emitter](https://emitter.io) (see also on [Emitter GitHub](https://github.com/emitter-io/emitter)). Emitter is an **open-source** real-time communication service for connecting online devices. At its core, emitter.io is a distributed, scalable and fault-tolerant publish-subscribe messaging platform based on MQTT protocol and featuring message storage.
5 |
6 | * [Installation](#install)
7 | * [Example](#example)
8 | * [API](#api)
9 | * [License](#license)
10 |
11 |
12 | ## Installation
13 |
14 | Emitter for NodeJS:
15 | ```
16 | npm install emitter-io --save
17 | ```
18 |
19 | Emitter for the Browser:
20 | * [http://cdn.emitter.io/js/emitter.js](http://cdn.emitter.io/js/emitter.js)
21 | * [http://cdn.emitter.io/js/emitter.min.js](http://cdn.emitter.io/js/emitter.min.js)
22 |
23 |
24 | ## Example
25 |
26 | ```
27 | // connect to emitter.io and get the client
28 | var client = emitter.connect(); // or: require('emitter-io') on NodeJS
29 |
30 | // once we're connected, subscribe to the 'chat' channel
31 | client.subscribe({
32 | key: "",
33 | channel: "chat"
34 | });
35 |
36 | // on every message, print it out
37 | client.on('message', function(msg){
38 | console.log( msg.asString() );
39 | });
40 |
41 | // publish a message to the chat channel
42 | client.publish({
43 | key: "",
44 | channel: "chat/my_name",
45 | message: "hello, emitter!"
46 | });
47 | ```
48 |
49 | ## API
50 | * connect()
51 | * Emitter()
52 | * Emitter#disconnect()
53 | * Emitter#publish()
54 | * Emitter#subscribe()
55 | * Emitter#unsubscribe()
56 | * Emitter#keygen()
57 | * Emitter#link()
58 | * Emitter#me()
59 | * Emitter#presence()
60 | * EmitterMessage()
61 | * EmitterMessage#asString()
62 | * EmitterMessage#asBinary()
63 | * EmitterMessage#asObject()
64 |
65 | -------------------------------------------------------
66 |
67 | ### connect(host: string, port: number)
68 |
69 | Connects to the emitter api broker specified by the given url and options and returns an [Emitter](#emitter) instance. The URL can be on the following protocols: 'mqtt', 'mqtts', 'tcp', 'tls', 'ws', 'wss'. The URL can also be an object as returned by [`URL.parse()`](http://nodejs.org/api/url.html#url_url_parse_urlstr_parsequerystring_slashesdenotehost), in that case the two objects are merged, i.e. you can pass a single object with both the URL and the connect options.
70 |
71 | -------------------------------------------------------
72 |
73 | ### Emitter()
74 |
75 | The `Emitter` class wraps a client connection to an emitter.io MQTT broker over an arbitrary transport method (TCP, TLS, WebSocket, ecc). It automatically handles the following by with help of MQTT.js client:
76 | * Regular server pings
77 | * QoS flow
78 | * Automatic reconnections
79 | * Start publishing before being connected
80 |
81 |
82 | #### Event `'connect'`
83 |
84 | `function(connack) {}`
85 |
86 | Emitted on successful (re)connection (i.e. connack rc=0).
87 | * `connack` received connack packet. When `clean` connection option is `false` and server has a previous session
88 | for `clientId` connection option, then `connack.sessionPresent` flag is `true`. When that is the case,
89 | you may rely on stored session and prefer not to send subscribe commands for the client.
90 |
91 | #### Event `'disconnect'`
92 |
93 | `function() {}`
94 |
95 | Emitted after a disconnection.
96 |
97 | #### Event `'offline'`
98 |
99 | `function() {}`
100 |
101 | Emitted when the client goes offline.
102 |
103 | #### Event `'error'`
104 |
105 | `function(error) {}`
106 |
107 | Emitted when the client cannot connect (i.e. connack rc != 0) or when a parsing error occurs.
108 |
109 | #### Event `'keygen'`
110 |
111 | `function(keyJson) {}`
112 |
113 | Emitted when the client generate a key to a channel using Emitter#keygen()
function.
114 |
115 | ### Event `'message'`
116 |
117 | `function(message) {}`
118 |
119 | Emitted when the client receives a message packet. The message object will be of [EmitterMessage](#message) class, encapsulating the channel and the payload.
120 |
121 | -------------------------------------------------------
122 |
123 | ### Emitter#disconnect()
124 |
125 | Disconnects from the remote broker
126 |
127 | -------------------------------------------------------
128 |
129 | ### Emitter#link({ key: string; channel: string; name: string; private: boolean; message: any; ttl?: number; me?: boolean; })
130 |
131 | Creates a 2-character link to a channel. The channel may be private. For more information about this feature, see [Emitter: Simplify Client/Server and IoT Apps with Links and Private Links (on YouTube)](https://youtu.be/_FgKiUlEb_s) and the [Emitter Pull Request (on GitHub)](https://github.com/emitter-io/emitter/pull/183).
132 |
133 | * `key` is security key to use for the operation, `String`
134 | * `channel` is the channel string to publish to, `String`
135 | * `name` is the 2-character name of the link, `String`
136 | * `private` requests the creation of a private channel, `Boolean`
137 | * `message` is the message to publish, `Buffer` or `String`
138 | * `ttl` is the time to live of the messages that will be sent through the link, `Number`.
139 | * `me` tells whether the messages sent through the link should be also sent to the publisher, `Boolean`. By default it is set to `true`.
140 |
141 | See also `publishWithLink()`.
142 |
143 | -------------------------------------------------------
144 |
145 | ### Emitter#publish({ key: string; channel: string; message: any; ttl?: number; me?: boolean; })
146 |
147 | Publishes a message to a channel
148 | * `key` is security key to use for the operation, `String`
149 | * `channel` is the channel string to publish to, `String`
150 | * `message` is the message to publish, `Buffer` or `String`
151 | * `ttl` is the time to live of the message, `Number`
152 | * `me` tells whether the messages should be also sent to the publisher, `Boolean`. By default it is set to `true`.
153 |
154 | -------------------------------------------------------
155 |
156 | ### Emitter#publishWithLink({ link: string; message: any; })
157 |
158 | Publishes a message to a link.
159 | * `link` is the name of the link, `String`
160 | * `message` is the message to publish, `Buffer` or `String`
161 |
162 | See also `link()`.
163 |
164 | -------------------------------------------------------
165 |
166 | ### Emitter#subscribe({ key: string; channel: string; })
167 |
168 | Subscribes to a channel
169 | * `key` is security key to use for the operation, `String`
170 | * `channel` is the channel string to subscribe to, `String`
171 |
172 | -------------------------------------------------------
173 |
174 | ### Emitter#unsubscribe({ key: string; channel: string; })
175 |
176 | Unsubscribes from a channel
177 | * `key` is security key to use for the operation, `String`
178 | * `channel` is the channel string to unsubscribe from, `String`
179 |
180 | -------------------------------------------------------
181 |
182 | ### Emitter#keygen({ key: string; channel: string; type: string; ttl: number; })
183 |
184 | Sends a key generation request to the server.
185 | * `key` is **master/secret key** to use for the operation, `String`
186 | * `channel` is the channel string to generate a key for, `String`
187 | * `type` the type of the key to generate. Possible options include `r` for read-only, `w` for write-only, `p` for presence only and `rw` for read-write keys (In addition to `rw`, you can use any combination of `r`, `w` and `p` for key generation), `String`
188 | * `ttl` is the time-to-live of the key, in seconds.
189 |
190 | -------------------------------------------------------
191 |
192 | ### Emitter#me()
193 |
194 | Retrieves information about the underlying client connection. Information includes the client ID and the links created by the client.
195 |
196 | -------------------------------------------------------
197 |
198 | ### Emitter#presence({ key: string; channel: string; status: boolean; changes: boolean; })
199 |
200 | Requests the presence for a particular channel.
201 | * `key` is **master/secret key** to use for the operation, `String`
202 | * `channel` is the channel string to generate a key for, `String`
203 | * `status` whether the current state should be retrieved or not
204 | * `changes` whether the future changes should be received or not
205 |
206 | -------------------------------------------------------
207 |
208 | ### EmitterMessage()
209 |
210 | The `EmitterMessage` class wraps a message received from the broker. It contains several properties:
211 | * `channel` is channel the message was published to, `String`
212 | * `binary` is the buffer associated with the payload, `Buffer`
213 |
214 | -------------------------------------------------------
215 |
216 | ### EmitterMessage#asString()
217 |
218 | Returns the payload as a utf-8 `String`.
219 |
220 | -------------------------------------------------------
221 |
222 | ### EmitterMessage#asBinary()
223 |
224 | Returns the payload as the `Buffer`.
225 |
226 | -------------------------------------------------------
227 |
228 | ### EmitterMessage#asObject()
229 |
230 | Returns the payload as JSON-deserialized `Object`.
231 |
232 |
233 | ## License
234 |
235 | The MIT License (MIT)
236 | Copyright (c) 2016 Misakai Ltd.
237 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "emitter-io",
3 | "description": "NodeJS MQTT client to use with emitter.io platform",
4 | "main": "lib/emitter.js",
5 | "authors": [
6 | "Misakai Ltd."
7 | ],
8 | "license": "MIT",
9 | "homepage": "https://github.com/emitter-io/javascript.git",
10 | "ignore": [
11 | "**/.*",
12 | "node_modules",
13 | "bower_components",
14 | "test",
15 | "tests"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/lib/browser.js:
--------------------------------------------------------------------------------
1 | var emitter = require('emitter');
--------------------------------------------------------------------------------
/lib/emitter.d.ts:
--------------------------------------------------------------------------------
1 | export declare class Emitter {
2 | private _mqtt;
3 | private _callbacks;
4 | /**
5 | * Connects to the emitter service.
6 | */
7 | connect(request?: ConnectRequest, handler?: () => void): Emitter;
8 | /**
9 | * Disconnects the client.
10 | */
11 | disconnect(): Emitter;
12 | /**
13 | * Publishes a message to the currently opened endpoint.
14 | */
15 | publish(request: PublishRequest): Emitter;
16 | /**
17 | * Publishes a message througth a link.
18 | */
19 | publishWithLink(request: PublishWithLinkRequest): Emitter;
20 | /**
21 | * Subscribes to a particular channel.
22 | */
23 | subscribe(request: SubscribeRequest): Emitter;
24 | /**
25 | * Create a link to a particular channel.
26 | */
27 | link(request: LinkRequest): Emitter;
28 | /**
29 | * Unsubscribes from a particular channel.
30 | */
31 | unsubscribe(request: UnsubscribeRequest): Emitter;
32 | /**
33 | * Sends a key generation request to the server.
34 | */
35 | keygen(request: KeyGenRequest): Emitter;
36 | /**
37 | * Sends a presence request to the server.
38 | */
39 | presence(request: PresenceRequest): Emitter;
40 | /**
41 | * Request information about the connection to the server.
42 | */
43 | me(): Emitter;
44 | /**
45 | * Hooks an event to the client.
46 | */
47 | on(event: K, callback: (args: EmitterEventsArgsMap[K]) => void): Emitter;
48 | /**
49 | * Unhooks an event from the client.
50 | */
51 | off(event: K, callback: (args: EmitterEventsArgsMap[K]) => void): Emitter;
52 | private _checkEvent;
53 | /**
54 | * Invokes the callback with a specific name.
55 | */
56 | private _tryInvoke;
57 | /**
58 | * Formats a channel for emitter.io protocol.
59 | *
60 | * @private
61 | * @param {string} key The key to use.
62 | * @param {string} channel The channel name.
63 | * @param {...Option[]} options The list of options to apply.
64 | * @returns
65 | */
66 | private _formatChannel;
67 | /**
68 | * Checks if a string starts with a prefix.
69 | */
70 | private _startsWith;
71 | /**
72 | * Checks whether a string ends with a suffix.
73 | */
74 | private _endsWith;
75 | /**
76 | * Logs the error and throws it
77 | */
78 | private _throwError;
79 | }
80 | /**
81 | * Represents a message send througn emitter.io
82 | *
83 | * @class EmitterMessage
84 | */
85 | export declare class EmitterMessage {
86 | channel: string;
87 | binary: any;
88 | /**
89 | * Creates an instance of EmitterMessage.
90 | *
91 | * @param {*} m The message
92 | */
93 | constructor(m: IMqttMessage);
94 | /**
95 | * Returns the payload as string.
96 | */
97 | asString(): string;
98 | /**
99 | * Returns the payload as binary.
100 | */
101 | asBinary(): any;
102 | /**
103 | * Returns the payload as JSON-deserialized object.
104 | */
105 | asObject(): any;
106 | }
107 | /**
108 | * Represents the available events.
109 | */
110 | export declare enum EmitterEvents {
111 | connect = "connect",
112 | disconnect = "disconnect",
113 | message = "message",
114 | offline = "offline",
115 | error = "error",
116 | keygen = "keygen",
117 | presence = "presence",
118 | me = "me"
119 | }
120 | /**
121 | * Represents the argument type of each event callback.
122 | */
123 | export declare interface EmitterEventsArgsMap {
124 | [EmitterEvents.connect]: Emitter,
125 | [EmitterEvents.disconnect]: Emitter,
126 | [EmitterEvents.message]: EmitterMessage,
127 | [EmitterEvents.offline]: Emitter,
128 | [EmitterEvents.error]: unknown,
129 | [EmitterEvents.keygen]: KeyGenEvent,
130 | [EmitterEvents.presence]: PresenceEvent,
131 | [EmitterEvents.me]: MeEvent
132 | }
133 | /**
134 | * Represents connection options.
135 | *
136 | * @interface IConnectOptions
137 | */
138 | export interface ConnectRequest {
139 | /**
140 | * Whether the connection should be MQTT over TLS or not.
141 | *
142 | * @type {boolean}
143 | */
144 | secure?: boolean;
145 | /**
146 | * The hostname to connect to.
147 | *
148 | * @type {string}
149 | */
150 | host?: string;
151 | /**
152 | * The port number to connect to.
153 | *
154 | * @type {number}
155 | */
156 | port?: number;
157 | /**
158 | * The number of seconts to wait between keepalive packets. Set to 0 to disable.
159 | *
160 | * @type {number} Keepalive in seconds.
161 | */
162 | keepalive?: number;
163 | /**
164 | * The username required by your broker, if any
165 | *
166 | * @type {string}
167 | */
168 | username?: string;
169 | /**
170 | * The password required by your broker, if any
171 | *
172 | * @type {string}
173 | */
174 | password?: string;
175 | }
176 | export interface PublishRequest {
177 | key: string;
178 | channel: string;
179 | message: any;
180 | ttl?: number;
181 | me?: boolean;
182 | }
183 | export interface PublishWithLinkRequest {
184 | link: string;
185 | message: any;
186 | }
187 | export interface SubscribeRequest {
188 | key: string;
189 | channel: string;
190 | last?: number;
191 | }
192 | export interface LinkRequest {
193 | key: string;
194 | channel: string;
195 | name: string;
196 | private: boolean;
197 | subscribe: boolean;
198 | ttl?: number;
199 | me?: boolean;
200 | }
201 | export interface UnsubscribeRequest {
202 | key: string;
203 | channel: string;
204 | }
205 | export interface KeyGenRequest {
206 | key: string;
207 | channel: string;
208 | type: string;
209 | ttl: number;
210 | }
211 | /**
212 | * Represents a presence request.
213 | *
214 | * @interface PresenceRequest
215 | */
216 | export interface PresenceRequest {
217 | /**
218 | * The key to use for this request. The key should match the channel and have presence flag associated.
219 | *
220 | * @type {string}
221 | */
222 | key: string;
223 | /**
224 | * The target channel for the presence request.
225 | *
226 | * @type {string}
227 | */
228 | channel: string;
229 | /**
230 | * Whether a full status should be sent back in the response.
231 | *
232 | * @type {boolean}
233 | */
234 | status?: boolean;
235 | /**
236 | * Whether we should subscribe this client to presence notification events.
237 | *
238 | * @type {boolean}
239 | */
240 | changes?: boolean;
241 | }
242 | /**
243 | * Represents a presence response message or a join/leave notification.
244 | *
245 | * @interface PresenceEvent
246 | */
247 | export interface PresenceEvent {
248 | /**
249 | * The event, can be "status", "join" or "leave".
250 | *
251 | * @type {string}
252 | */
253 | event: string;
254 | /**
255 | * The channel for this event.
256 | *
257 | * @type {string}
258 | */
259 | channel: string;
260 | /**
261 | * The current channel occupancy (the number of subscribers).
262 | *
263 | * @type {number}
264 | */
265 | occupancy: number;
266 | /**
267 | * The UNIX timestamp of this event.
268 | *
269 | * @type {number}
270 | */
271 | time: number;
272 | /**
273 | * The list of clients or the client id.
274 | *
275 | * @type {(Array | PresenceInfo)}
276 | */
277 | who: Array | PresenceInfo;
278 | }
279 | export interface PresenceInfo {
280 | /**
281 | * The id of the connection.
282 | *
283 | * @type {string}
284 | */
285 | id: string;
286 | /**
287 | * The MQTT username associated with the connection.
288 | *
289 | * @type {string}
290 | */
291 | username: string;
292 | }
293 | export interface UnsubscribeRequest {
294 | key: string;
295 | channel: string;
296 | }
297 | export interface KeyGenEvent {
298 | key: string;
299 | channel: string;
300 | status: number;
301 | }
302 | export interface MeEvent {
303 | id: string;
304 | username: string;
305 | }
306 | /**
307 | * Represents an MQTT message.
308 | *
309 | * @interface IMqttMessage
310 | */
311 | export interface IMqttMessage {
312 | topic: string;
313 | payload: any;
314 | }
315 | /**
316 | * Represents an option (key/value pair) for a subscribe or publish operation.
317 | */
318 | export interface Option {
319 | key: string;
320 | value: string;
321 | }
322 | /**
323 | * Connect creates a new instance of emitter client and connects to it.
324 | */
325 | export declare function connect(request?: ConnectRequest, connectCallback?: any): Emitter;
326 |
--------------------------------------------------------------------------------
/lib/emitter.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | var mqtt = require('mqtt');
4 | var Emitter = /** @class */ (function () {
5 | function Emitter() {
6 | }
7 | /**
8 | * Connects to the emitter service.
9 | */
10 | Emitter.prototype.connect = function (request, handler) {
11 | var _this = this;
12 | request = request || {};
13 | // auto-resolve the security level
14 | if (request.secure == null) {
15 | if (typeof window !== "undefined" && window != null && window.location != null && window.location.protocol != null) {
16 | request.secure = window.location.protocol == "https:";
17 | }
18 | else {
19 | request.secure = false;
20 | }
21 | }
22 | // default options
23 | var defaultConnectOptions = {
24 | host: "api.emitter.io",
25 | port: request.secure ? 443 : 8080,
26 | keepalive: 30,
27 | secure: false
28 | };
29 | // apply defaults
30 | for (var k in defaultConnectOptions) {
31 | request[k] = "undefined" === typeof request[k] ? defaultConnectOptions[k] : request[k];
32 | }
33 | request.host = request.host.replace(/.*?:\/\//g, "");
34 | var brokerUrl = "" + (request.secure ? "wss://" : "ws://") + request.host + ":" + request.port;
35 | this._callbacks = { "connect": [handler] };
36 | this._mqtt = mqtt.connect(brokerUrl, request);
37 | this._mqtt.on(EmitterEvents.connect, function () { return _this._tryInvoke(EmitterEvents.connect, _this); });
38 | this._mqtt.on("close", function () { return _this._tryInvoke(EmitterEvents.disconnect, _this); });
39 | this._mqtt.on("offline", function () { return _this._tryInvoke(EmitterEvents.offline, _this); });
40 | this._mqtt.on("error", function (error) { return _this._tryInvoke(EmitterEvents.error, error); });
41 | this._mqtt.on("message", function (topic, msg, packet) {
42 | var message = new EmitterMessage(packet);
43 | if (_this._startsWith(message.channel, "emitter/keygen")) {
44 | // This is keygen message.
45 | _this._tryInvoke(EmitterEvents.keygen, message.asObject());
46 | }
47 | else if (_this._startsWith(message.channel, "emitter/presence")) {
48 | // This is presence message.
49 | _this._tryInvoke(EmitterEvents.presence, message.asObject());
50 | }
51 | else if (_this._startsWith(message.channel, "emitter/me")) {
52 | // This is a message requesting info on the connection.
53 | _this._tryInvoke(EmitterEvents.me, message.asObject());
54 | }
55 | else {
56 | // Do we have a message callback?
57 | _this._tryInvoke(EmitterEvents.message, message);
58 | }
59 | });
60 | return this;
61 | };
62 | /**
63 | * Disconnects the client.
64 | */
65 | Emitter.prototype.disconnect = function () {
66 | this._mqtt.end();
67 | return this;
68 | };
69 | /**
70 | * Publishes a message to the currently opened endpoint.
71 | */
72 | Emitter.prototype.publish = function (request) {
73 | if (typeof request.key !== "string")
74 | this._throwError("emitter.publish: request object does not contain a 'key' string.");
75 | if (typeof request.channel !== "string")
76 | this._throwError("emitter.publish: request object does not contain a 'channel' string.");
77 | if (typeof request.message !== "object" && typeof request.message !== "string")
78 | this._throwError("emitter.publish: request object does not contain a 'message' object.");
79 | var options = new Array();
80 | // The default server's behavior when 'me' is absent, is to send the publisher its own messages.
81 | // To avoid any ambiguity, this parameter is always set here.
82 | if (request.me == null || request.me == true) {
83 | options.push({ key: "me", value: '1' });
84 | }
85 | else {
86 | options.push({ key: "me", value: '0' });
87 | }
88 | if (request.ttl) {
89 | options.push({ key: "ttl", value: request.ttl.toString() });
90 | }
91 | var topic = this._formatChannel(request.key, request.channel, options);
92 | this._mqtt.publish(topic, request.message);
93 | return this;
94 | };
95 | /**
96 | * Publishes a message througth a link.
97 | */
98 | Emitter.prototype.publishWithLink = function (request) {
99 | if (typeof request.link !== "string")
100 | this._throwError("emitter.publishWithLink: request object does not contain a 'link' string.");
101 | if (typeof request.message !== "object" && typeof request.message !== "string")
102 | this._throwError("emitter.publishWithLink: request object does not contain a 'message' object.");
103 | this._mqtt.publish(request.link, request.message);
104 | return this;
105 | };
106 | /**
107 | * Subscribes to a particular channel.
108 | */
109 | Emitter.prototype.subscribe = function (request) {
110 | if (typeof request.key !== "string")
111 | this._throwError("emitter.subscribe: request object does not contain a 'key' string.");
112 | if (typeof request.channel !== "string")
113 | this._throwError("emitter.subscribe: request object does not contain a 'channel' string.");
114 | var options = new Array();
115 | if (request.last != null) {
116 | options.push({ key: "last", value: request.last.toString() });
117 | }
118 | // Send MQTT subscribe
119 | var topic = this._formatChannel(request.key, request.channel, options);
120 | this._mqtt.subscribe(topic);
121 | return this;
122 | };
123 | /**
124 | * Create a link to a particular channel.
125 | */
126 | Emitter.prototype.link = function (request) {
127 | if (typeof request.key !== "string")
128 | this._throwError("emitter.link: request object does not contain a 'key' string.");
129 | if (typeof request.channel !== "string")
130 | this._throwError("emitter.link: request object does not contain a 'channel' string.");
131 | if (typeof request.name !== "string")
132 | this._throwError("emitter.link: request object does not contain a 'name' string.");
133 | if (typeof request.private !== "boolean")
134 | this._throwError("emitter.link: request object does not contain 'private'.");
135 | if (typeof request.subscribe !== "boolean")
136 | this._throwError("emitter.link: request object does not contain 'subscribe'.");
137 | var options = new Array();
138 | // The default server's behavior when 'me' is absent, is to send the publisher its own messages.
139 | // To avoid any ambiguity, this parameter is always set here.
140 | if (request.me == null || request.me == true) {
141 | options.push({ key: "me", value: '1' });
142 | }
143 | else {
144 | options.push({ key: "me", value: '0' });
145 | }
146 | if (request.ttl != null) {
147 | options.push({ key: "ttl", value: request.ttl.toString() });
148 | }
149 | var formattedChannel = this._formatChannel(null, request.channel, options);
150 | request = {
151 | "key": request.key,
152 | "channel": formattedChannel,
153 | "name": request.name,
154 | "private": request.private,
155 | "subscribe": request.subscribe
156 | };
157 | console.log(JSON.stringify(request));
158 | this._mqtt.publish('emitter/link/', JSON.stringify(request));
159 | return this;
160 | };
161 | /**
162 | * Unsubscribes from a particular channel.
163 | */
164 | Emitter.prototype.unsubscribe = function (request) {
165 | if (typeof request.key !== "string")
166 | this._throwError("emitter.unsubscribe: request object does not contain a 'key' string.");
167 | if (typeof request.channel !== "string")
168 | this._throwError("emitter.unsubscribe: request object does not contain a 'channel' string.");
169 | // Send MQTT unsubscribe
170 | var topic = this._formatChannel(request.key, request.channel, []);
171 | this._mqtt.unsubscribe(topic);
172 | return this;
173 | };
174 | /**
175 | * Sends a key generation request to the server.
176 | */
177 | Emitter.prototype.keygen = function (request) {
178 | if (typeof request.key !== "string")
179 | this._throwError("emitter.keygen: request object does not contain a 'key' string.");
180 | if (typeof request.channel !== "string")
181 | this._throwError("emitter.keygen: request object does not contain a 'channel' string.");
182 | // Publish the request
183 | this._mqtt.publish("emitter/keygen/", JSON.stringify(request));
184 | return this;
185 | };
186 | /**
187 | * Sends a presence request to the server.
188 | */
189 | Emitter.prototype.presence = function (request) {
190 | if (typeof request.key !== "string")
191 | this._throwError("emitter.presence: request object does not contain a 'key' string.");
192 | if (typeof request.channel !== "string")
193 | this._throwError("emitter.presence: request object does not contain a 'channel' string.");
194 | // Publish the request
195 | this._mqtt.publish("emitter/presence/", JSON.stringify(request));
196 | return this;
197 | };
198 | /**
199 | * Request information about the connection to the server.
200 | */
201 | Emitter.prototype.me = function () {
202 | // Publish the request
203 | this._mqtt.publish("emitter/me/", "");
204 | return this;
205 | };
206 | /**
207 | * Hooks an event to the client.
208 | */
209 | Emitter.prototype.on = function (event, callback) {
210 | this._checkEvent('off', event);
211 | if (!this._callbacks) {
212 | this._throwError("emitter.on: called before connecting");
213 | }
214 | // Set the callback
215 | if (!this._callbacks[event]) {
216 | this._callbacks[event] = [];
217 | }
218 | if (this._callbacks[event].indexOf(callback) === -1) {
219 | this._callbacks[event].push(callback);
220 | }
221 | return this;
222 | };
223 | /**
224 | * Unhooks an event from the client.
225 | */
226 | Emitter.prototype.off = function (event, callback) {
227 | this._checkEvent('off', event);
228 | if (!this._callbacks) {
229 | this._throwError("emitter.off: called before connecting");
230 | }
231 | var eventCallbacks = this._callbacks[event];
232 | if (eventCallbacks) {
233 | var index = eventCallbacks.indexOf(callback);
234 | if (index >= 0) {
235 | eventCallbacks.splice(index, 1);
236 | }
237 | }
238 | return this;
239 | };
240 | Emitter.prototype._checkEvent = function (method, event) {
241 | if (!EmitterEvents[event]) {
242 | var names = Object.keys(EmitterEvents);
243 | var values = names
244 | .map(function (name, index) { return (index === names.length - 1 ? 'or ' : '') + "'" + name + "'"; })
245 | .join(", ");
246 | this._throwError("emitter." + method + ": unknown event type, supported values are " + values + ".");
247 | }
248 | };
249 | /**
250 | * Invokes the callback with a specific name.
251 | */
252 | Emitter.prototype._tryInvoke = function (name, args) {
253 | var callbacks = this._callbacks[name];
254 | if (callbacks) {
255 | callbacks
256 | .filter(function (callback) { return callback; })
257 | .forEach(function (callback) { return callback(args); });
258 | }
259 | };
260 | /**
261 | * Formats a channel for emitter.io protocol.
262 | *
263 | * @private
264 | * @param {string} key The key to use.
265 | * @param {string} channel The channel name.
266 | * @param {...Option[]} options The list of options to apply.
267 | * @returns
268 | */
269 | Emitter.prototype._formatChannel = function (key, channel, options) {
270 | // Prefix with the key if any
271 | var formatted = channel;
272 | if (key && key.length > 0)
273 | formatted = this._endsWith(key, "/") ? key + channel : key + "/" + channel;
274 | // Add trailing slash
275 | if (!this._endsWith(formatted, "/"))
276 | formatted += "/";
277 | // Add options
278 | if (options != null && options.length > 0) {
279 | formatted += "?";
280 | for (var i = 0; i < options.length; ++i) {
281 | formatted += options[i].key + "=" + options[i].value;
282 | if (i + 1 < options.length)
283 | formatted += "&";
284 | }
285 | }
286 | // We're done compiling the channel name
287 | return formatted;
288 | };
289 | /**
290 | * Checks if a string starts with a prefix.
291 | */
292 | Emitter.prototype._startsWith = function (text, prefix) {
293 | return text.slice(0, prefix.length) == prefix;
294 | };
295 | /**
296 | * Checks whether a string ends with a suffix.
297 | */
298 | Emitter.prototype._endsWith = function (text, suffix) {
299 | return text.indexOf(suffix, text.length - suffix.length) !== -1;
300 | };
301 | /**
302 | * Logs the error and throws it
303 | */
304 | Emitter.prototype._throwError = function (message) {
305 | console.error(message);
306 | throw new Error(message);
307 | };
308 | return Emitter;
309 | }());
310 | exports.Emitter = Emitter;
311 | /**
312 | * Represents a message send througn emitter.io
313 | *
314 | * @class EmitterMessage
315 | */
316 | var EmitterMessage = /** @class */ (function () {
317 | /**
318 | * Creates an instance of EmitterMessage.
319 | *
320 | * @param {*} m The message
321 | */
322 | function EmitterMessage(m) {
323 | this.channel = m.topic;
324 | this.binary = m.payload;
325 | }
326 | /**
327 | * Returns the payload as string.
328 | */
329 | EmitterMessage.prototype.asString = function () {
330 | return this.binary.toString();
331 | };
332 | /**
333 | * Returns the payload as binary.
334 | */
335 | EmitterMessage.prototype.asBinary = function () {
336 | return this.binary;
337 | };
338 | /**
339 | * Returns the payload as JSON-deserialized object.
340 | */
341 | EmitterMessage.prototype.asObject = function () {
342 | var object = {};
343 | try {
344 | object = JSON.parse(this.asString());
345 | }
346 | catch (err) {
347 | console.error(err);
348 | }
349 | return object;
350 | };
351 | return EmitterMessage;
352 | }());
353 | exports.EmitterMessage = EmitterMessage;
354 | /**
355 | * Represents the available events.
356 | */
357 | var EmitterEvents;
358 | (function (EmitterEvents) {
359 | EmitterEvents["connect"] = "connect";
360 | EmitterEvents["disconnect"] = "disconnect";
361 | EmitterEvents["message"] = "message";
362 | EmitterEvents["offline"] = "offline";
363 | EmitterEvents["error"] = "error";
364 | EmitterEvents["keygen"] = "keygen";
365 | EmitterEvents["presence"] = "presence";
366 | EmitterEvents["me"] = "me";
367 | })(EmitterEvents = exports.EmitterEvents || (exports.EmitterEvents = {}));
368 | /**
369 | * Connect creates a new instance of emitter client and connects to it.
370 | */
371 | function connect(request, connectCallback) {
372 | var client = new Emitter();
373 | client.connect(request, connectCallback);
374 | return client;
375 | }
376 | exports.connect = connect;
377 | //# sourceMappingURL=emitter.js.map
--------------------------------------------------------------------------------
/lib/emitter.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"emitter.js","sourceRoot":"","sources":["emitter.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/lib/emitter.ts:
--------------------------------------------------------------------------------
1 | const mqtt = require('mqtt');
2 |
3 | export class Emitter {
4 |
5 | private _mqtt: any;
6 | private _callbacks: { [key: string]: ((args?: any) => void)[] };
7 |
8 | /**
9 | * Connects to the emitter service.
10 | */
11 | public connect(request?: ConnectRequest, handler?: () => void): Emitter {
12 | request = request || {};
13 |
14 | // auto-resolve the security level
15 | if (request.secure == null) {
16 | if (typeof window !== "undefined" && window != null && window.location != null && window.location.protocol != null) {
17 | request.secure = window.location.protocol == "https:";
18 | } else {
19 | request.secure = false;
20 | }
21 | }
22 |
23 | // default options
24 | var defaultConnectOptions = {
25 | host: "api.emitter.io",
26 | port: request.secure ? 443 : 8080,
27 | keepalive: 30,
28 | secure: false
29 | };
30 |
31 | // apply defaults
32 | for (var k in defaultConnectOptions) {
33 | request[k] = "undefined" === typeof request[k] ? defaultConnectOptions[k] : request[k];
34 | }
35 |
36 | request.host = request.host.replace(/.*?:\/\//g, "");
37 | var brokerUrl = `${request.secure ? "wss://" : "ws://"}${request.host}:${request.port}`;
38 |
39 | this._callbacks = {"connect": [handler]};
40 | this._mqtt = mqtt.connect(brokerUrl, request);
41 |
42 | this._mqtt.on("connect", () => this._tryInvoke(EmitterEvents.connect, this));
43 | this._mqtt.on("close", () => this._tryInvoke(EmitterEvents.disconnect, this));
44 | this._mqtt.on("offline", () => this._tryInvoke(EmitterEvents.offline, this));
45 | this._mqtt.on("error", error => this._tryInvoke(EmitterEvents.error, error));
46 | this._mqtt.on("message", (topic, msg, packet) => {
47 | var message = new EmitterMessage(packet);
48 | if (this._startsWith(message.channel, "emitter/keygen")) {
49 | // This is keygen message.
50 | this._tryInvoke(EmitterEvents.keygen, message.asObject())
51 | } else if (this._startsWith(message.channel, "emitter/presence")) {
52 | // This is presence message.
53 | this._tryInvoke(EmitterEvents.presence, message.asObject())
54 | } else if (this._startsWith(message.channel, "emitter/me")) {
55 | // This is a message requesting info on the connection.
56 | this._tryInvoke(EmitterEvents.me, message.asObject());
57 | } else {
58 | // Do we have a message callback?
59 | this._tryInvoke(EmitterEvents.message, message);
60 | }
61 | });
62 | return this;
63 | }
64 |
65 | /**
66 | * Disconnects the client.
67 | */
68 | public disconnect(): Emitter {
69 | this._mqtt.end();
70 | return this;
71 | }
72 |
73 | /**
74 | * Publishes a message to the currently opened endpoint.
75 | */
76 | public publish(request: PublishRequest): Emitter {
77 | if (typeof request.key !== "string")
78 | this._throwError("emitter.publish: request object does not contain a 'key' string.");
79 | if (typeof request.channel !== "string")
80 | this._throwError("emitter.publish: request object does not contain a 'channel' string.");
81 | if (typeof request.message !== "object" && typeof request.message !== "string")
82 | this._throwError("emitter.publish: request object does not contain a 'message' object.");
83 |
84 | var options = new Array