Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/thoov/ember-websockets

Ember.js websockets and socket.io addon
https://github.com/thoov/ember-websockets

ember ember-addon javascript socket-io websockets

Last synced: 1 day ago
JSON representation

Ember.js websockets and socket.io addon

Awesome Lists containing this project

README

        

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 [email protected]: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 [email protected]: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).