UNPKG

ember-websockets

Version:

EmberJS WebSockets addon for Ember-CLI apps.

400 lines (291 loc) 11.4 kB
ember-websockets ============================================================================== [![GitHub Actions CI][github-actions-badge]][github-actions-ci-url] [github-actions-badge]: https://github.com/thoov/ember-websockets/workflows/CI/badge.svg [github-actions-ci-url]: https://github.com/thoov/ember-websockets/actions?query=workflow%3ACI Compatibility ------------------------------------------------------------------------------ * Ember.js v3.24 or above * Ember CLI v3.24 or above * Node.js v12 or above Installation ------------------------------------------------------------------------------ ``` ember install ember-websockets ``` Usage ------------------------------------------------------------------------------ ## Simple example of using it in your app ```javascript import Controller from '@ember/controller'; import { inject as service } from '@ember/service'; import { action } from '@ember/object'; export default class MyController extends Controller { /* * 1. Inject the websockets service */ @service('websockets') websockets; socketRef = null, constructor() { super(...arguments); /* 2. The next step you need to do is to create your actual websocket. Calling socketFor will retrieve a cached websocket if one exists or in this case it will create a new one for us. */ const socket = this.websockets.socketFor('ws://localhost:7000/'); /* 3. The next step is to define your event handlers. All event handlers are added via the `on` method and take 3 arguments: event name, callback function, and the context in which to invoke the callback. All 3 arguments are required. */ socket.on('open', this.myOpenHandler, this); socket.on('message', this.myMessageHandler, this); socket.on('close', this.myCloseHandler, this); this.set('socketRef', socket); } myOpenHandler(event) { console.log(`On open event has been called: ${event}`); } myMessageHandler(event) { console.log(`Message: ${event.data}`); } myCloseHandler(event) { console.log(`On close event has been called: ${event}`); } @action sendButtonPressed() { this.socketRef.send('Hello Websocket World'); } } ``` ## Sending messages to the server ```javascript const socket = this.socketService.socketFor('ws://localhost:7000/'); socket.send({username: 'foo', didSomeAction: 'pressedAButton'}, true); // the above line is the same as this: socket.send(JSON.stringify({username: 'foo', didSomeAction: 'pressedAButton'})); ``` The send method takes 2 arguments. A message which is passed into the native websockets send method and an optional stringify boolean. This boolean, if set to true, will do a JSON.stringify to the message before passing it to the websocket send method. If you are sending strings it is recommended to pass true. ## Reconnecting ```javascript import Controller from '@ember/controller'; import { inject as service } from '@ember/service'; import { later } from '@ember/runloop'; export default class MyController extends Controller { @service('websockets') socketService; constructor() { super(...arguments); const socket = this.socketService.socketFor('ws://localhost:7000/'); socket.on('close', this.myOnClose, this); } myOnClose() { const socket = this.socketService.socketFor('ws://localhost:7000/'); later(this, () => { /* This will remove the old socket and try and connect to a new one on the same url. NOTE: that this does not need to be in a Ember.run.later this is just an example on how to reconnect every second. */ socket.reconnect(); }, 1000); } } ``` ## Closing the connection ```javascript import Component from '@ember/component'; import { inject as service } from '@ember/service'; export default class MyComponent extends Component { @service('websockets') socketService; /* To close a websocket connection simply call the closeSocketFor method. NOTE: it is good practice to close any connections after you are no longer in need of it. A good place for this clean up is in the willDestroyElement method of the object. */ willDestroyElement() { this.socketService.closeSocketFor('ws://localhost:7000/'); } } ``` ## Multiple Websockets ```javascript import Component from '@ember/component'; import { inject as service } from '@ember/service'; export default class MyComponent extends Component { @service('websockets') socketService; didInsertElement() { const socketOne = this.socketService.socketFor('ws://localhost:7000/'); const socketTwo = this.socketService.socketFor('ws://localhost:7001/'); socketOne.on('open', this.myOpenFirst, this); socketTwo.on('open', this.myOpenSeconds, this); } myOpenFirst(event) { console.log('Hello from socket one'); } myOpenSecond(event) { console.log('Hello from socket two'); } willDestroyElement() { const socketOne = this.socketService.socketFor('ws://localhost:7000/'); const socketTwo = this.socketService.socketFor('ws://localhost:7001/'); socketOne.off('open', this.myOpenFirst); socketTwo.off('open', this.myOpenSecond); } } ``` ## Multiple Event Handlers ```javascript import Component from '@ember/component'; import { inject as service } from '@ember/service'; export default class MyComponent extends Component { socketService: service('websockets'), didInsertElement() { const socket = this.socketService.socketFor('ws://localhost:7000/'); socket.on('open', this.myOpenFirst, this); socket.on('open', this.myOpenSecond, this); } myOpenFirst() { console.log('This will be called'); } myOpenSecond() { console.log('This will also be called'); } willDestroyElement() { const socket = this.socketService.socketFor('ws://localhost:7000/'); socket.off('open', this.myOpenFirst); socket.off('open', this.myOpenSecond); } } ``` ## Socket.IO Support First set socketIO to be true in your `config/environment.js` file: ```js var ENV = { 'ember-websockets': { socketIO: true } }; ``` ```javascript import Component from '@ember/component'; import { inject as service } from '@ember/service'; export default class MyComponent extends Component { /* 1. Inject the socketio service */ @service('socket-io') socketIOService; /* Important note: The namespace is an implementation detail of the Socket.IO protocol... http://socket.io/docs/rooms-and-namespaces/#custom-namespaces */ namespace = 'myCustomNamespace', didInsertElement() { /* 2. The next step you need to do is to create your actual socketIO. */ const socket = this.socketIOService.socketFor(`http://localhost:7000/${this.namespace}`); /* * 3. Define any event handlers */ socket.on('connect', this.onConnect, this); socket.on('message', this.onMessage, this); /* 4. It is also possible to set event handlers on specific events */ socket.on('myCustomEvent', () => { socket.emit('anotherCustomEvent', 'some data'); }); } onConnect() { const socket = this.socketIOService.socketFor(`http://localhost:7000/${this.namespace}`); /* There are 2 ways to send messages to the server: send and emit */ socket.send('Hello World'); socket.emit('Hello server'); } onMessage(data) { // This is executed within the ember run loop } myCustomEvent(data) { const socket = this.socketIOService.socketFor(`http://localhost:7000/${this.namespace}`); socket.emit('anotherCustomEvent', 'some data'); } willDestroyElement() { const socket = this.socketIOService.socketFor(`http://localhost:7000/${this.namespace}`); socket.off('connect', this.onConnect); socket.off('message', this.onMessage); socket.off('myCustomEvent', this.myCustomEvent); } } ``` **Please visit**: [socket.io docs](https://github.com/thoov/ember-websockets/blob/master/docs/socket-io.md) for more details on ember-websocket + socket.io ## Detailed explanations of the APIs ### SocketFor Example: ```javascript const socket = this.socketService.socketFor('ws://localhost:7000/', ['myOptionalProtocol']); ``` socketFor takes two arguments: **a url**, **a protocol array** (optional), and returns a socket instance from its cache or a new websocket connection if one was not found. To use a custom namespace, append the namespace to the end of the url. ```javascript const socket = this.socketService.socketFor(`ws://localhost:7000/${namespace}`); ``` ### On Example: ```javascript const socket = this.socketService.socketFor('ws://localhost:7000/'); socket.on('open', this.myOtherOpenFunction); ``` on takes 3 arguments: **event type**, **callback function**, and **context**. Event type can be one of the following: 'open', 'message', 'close', and 'error'. Callback function will be invoked when one of the event types occurs. ### Off Example: ```javascript const socket = this.socketService.socketFor('ws://localhost:7000/'); let openFunctionReference = this.myOpenFunction.bind(this); socket.on('open', openFunctionReference); socket.off('open', openFunctionReference); ``` off takes 2 arguments: **event type**, **callback function**. Event type can be one of the following: 'open', 'message', 'close', and 'error'. The callback will be removed from the event pool and will no longer be invoked. ### CloseSocketFor Example: ```javascript this.socketService.closeSocketFor('ws://localhost:7000/'); ``` closeSocketFor takes a single argument, **a url**, and closes the websocket connection. It will also remove it from the cache. In normal cases you would not have to call this method. ### Reconnect Example: ```javascript socket.on('close', event => { socket.reconnect(); }); ``` reconnect takes no arguments. It will attempt to create a new websocket connect using the previous url. If the connect is not successful the `close` event will be triggered. ## Live Example * `git clone git@github.com:thoov/ember-websockets.git` * `cd ember-websockets` * `yarn` * `ember s` * Then visit http://localhost:4200/sockets/example to view a very simple example. The source code for the live example lives in `ember-websockets/tests/dummy` ## Running tests * `git clone git@github.com:thoov/ember-websockets.git` * `cd ember-websockets` * `yarn` * `ember t` * or `ember s` then visit http://localhost:4200/tests to view the tests. **NOTE**: To get the test to run in PhantomJS I created a mocking library found here: [mocking library](https://github.com/thoov/mock-socket) Note that it is still a work in progress. ## Feedback or issues If you have any feedback, encounter any bugs, or just have a question, please feel free to create a [github issue](https://github.com/thoov/ember-websockets/issues/new) or send me a tweet at [@thoov](https://twitter.com/thoov). ## FAQ ### Recommended backend library/framework * [ws](https://github.com/einaros/ws) * [socket.io](http://socket.io) Contributing ------------------------------------------------------------------------------ See the [Contributing](CONTRIBUTING.md) guide for details. License ------------------------------------------------------------------------------ This project is licensed under the [MIT License](LICENSE.md).