rocketchat:streamer

v1.1.0Published 5 years ago

This package has not had recent updates. Please investigate it's current state before committing to using it in your project.

RocketChat:Streamer

2 way communication over DDP with better performance.

Installation

meteor add rocketchat:streamer

Why

DDP subscriptions keeps track of all data each client has, it's called MergeBox, this is a lighter solution.

Use subscriptions to send data to client is not always easy to do, with streamer you can send data as simple as calling events.

Use case

You should use this library when you want to send data from server to client of from client to server and prevent the server to keep track off data all clients have.

You can send a lot of data without performance problems, like notifications.

Downsides

Since the library don't keep track of data, you will not receive lost data while offline after reconnection. But we have an event to notify you on reconnections passing the latest record received so you can call a method to verify and get the missing data.

Compatibility

Since streamer is based on DDP, we use subscriptions and methods to send data, it's 100% compatible with all DDP clients, more details below.

Advantages over Arunoda's stream library

  • Faster and use less memmory
    • For 2000 events and 10 messages (40 thousand operations - send and reply)
      • rocketchat:streamer: ~34 seconds, increase of ~68mb of RAM
      • arunoda:meteor-stream: ~41 seconds, increase of ~76mb of RAM
    • For 10 events and 2000 messages (40 thousand operations - send and reply)
      • rocketchat:streamer: ~32 seconds, increase of ~35mb of RAM
      • arunoda:meteor-stream: ~43 seconds, increase of ~80mb of RAM
  • Read permission cached by event name by client at subscription time
  • Don't use collection at client side (there is a compatible mode if you need)
  • Last message cache and reconnection event
    • Keep the last message on client for each event name
    • You can get the last message and send to the server to verify if you lost messages

How to use

A simple console chat

1const streamer = new Meteor.Streamer('chat');
2
3if(Meteor.isClient) {
4  sendMessage = function(message) {
5    streamer.emit('message', message);
6    console.log('me: ' + message);
7  };
8
9  streamer.on('message', function(message) {
10    console.log('user: ' + message);
11  });
12}
13
14if (Meteor.isServer) {
15  streamer.allowRead('all');
16  streamer.allowWrite('all');
17}

Now you can open 2 browser tabs/windows and chat using sendMessage("text") at your browser's console Every message will travel from your client to server and retransmited to all other clients.

new Meteor.Streamer('name')

Client

1new Meteor.Streamer(name, [options])
  • name - String REQUIRED Unique name to identify stream between server and client
  • options - Object OPTIONAL
    • useCollection - Boolean Set to true to enable the compatible mode default false
    • ddpConnection - Object The DDP connection to be used default Meteor.connection

Server

1const streamer = new Meteor.Streamer(name, [options]);
  • name - String REQUIRED Unique name to identify stream between server and client
  • options - Object OPTIONAL
    • retransmit - Boolean Set to false to prevent streaming "client to client" default true
    • retransmitToSelf - Boolean Set to true if you want to receive messages you've sent via retransmit default false

.emit('eventName', ...args)

With emit you send data from client to server or from server to clients.

1streamer.emit(eventName, arg1, arg2, ...);
  • eventName - String REQUIRED The event name to send data
  • args - Mixed OPTIONAL You can pass 0 or more arguments to your event

If you emit an event from client you will receive that event on server and if you emit an event on your server you will receive the event in all connected clients.

If retransmit is enabled, you will receive the event emited on client on your server and on all other connected clients.

The default permission deny all comunication, you should define a new permission! See allowRead and allowWrite bellow

1// Example
2streamer.emit('message', {text: 'My new message', user: 'User1'}); // Send one object
3streamer.emit('message', 'My new message', 'User1'); // Send 2 strings
4streamer.emit('message'); // Just call the event without params

.on('eventName', fn)

With on you listen for data sent from client to server or from server to clients.

1streamer.on(eventName, fn);
  • eventName - String REQUIRED The event name to receive data
  • fn - Function REQUIRED Function to receive and process the data for the event

The default permission deny all comunication, you should define a new permission! See allowRead and allowWrite bellow

1// Example
2streamer.on('message', function(message) {
3  console.log(message);
4});

.allowRead('eventName', 'all') (Server only)

This permission will be evaluate only 1 time per client, so you decide if the connections is allowed or not, you can't manage permissions based on data.

1streamer.allowRead([eventName], permission);
  • eventName - String OPTIONAL The event name to apply permissions, if not informed will apply the permission for all events
  • permission - Function/String REQUIRED
    • Function(eventName) The function should return true to allow read
      • Param eventName The event name, useful when use one function to manage permissions for all events
      • Scope this.userId The id of the logged user
      • Scope this.connection The connection between client and server
    • String There are shortcuts for permissions
      • all Allow read for everyone
      • none Deny read for everyone
      • logged Allow read for logged users
1//Examples
2
3streamer.allowRead('all'); // Everyone can read all events
4
5streamer.allowRead('chat', 'logged'); // Only logged users can read chat events
6
7streamer.allowRead('notifications', function() { // Only admin users can read notificaiton events
8  if (this.userId) {
9    const user = Meteor.users.findOne(this.userId);
10    if (user && user.admin === true) {
11      return true;
12    }
13  }
14
15  return false;
16});

.allowEmit('eventName', 'all') (Server only)

This permission will be evaluate (executed) for each data for each client subscribed, this is much more expensive than allowRead but you can manage permissions based on each data.

1streamer.allowEmit([eventName], permission);
  • eventName - String OPTIONAL The event name to apply permissions, if not informed will apply the permission for all events
  • permission - Function/String REQUIRED
    • Function(eventName, ...args) The function should return true to allow emite
      • Param eventName The event name, useful when use one function to manage permissions for all events
      • Scope this.userId The id of the logged user
      • Scope this.connection The connection between client and server
    • String There are shortcuts for permissions
      • all Allow emit for everyone [default]
      • none Deny emit for everyone
      • logged Allow emit for logged users
1//Examples
2
3streamer.allowEmit('all'); // Everyone can emit all events
4
5streamer.allowEmit('chat', 'logged'); // Only emit for logged users

.allowWrite('eventName', 'all') (Server only)

1streamer.allowWrite([eventName], permission);
  • eventName - String OPTIONAL The event name to apply permissions, if not informed will apply the permission for all events
  • permission - Function/String REQUIRED
    • Function(eventName, ...args) The function should return true to allow write
      • Param eventName The event name, useful when use one function to manage permissions for all events
      • Scope this.userId The id of the logged user
      • Scope this.connection The connection between client and server
    • String There are shortcuts for permissions
      • all Allow write for everyone
      • none Deny write for everyone
      • logged Allow write for logged users
1//Examples
2
3streamer.allowWrite('all'); // Everyone can write all events
4
5streamer.allowWrite('chat', 'logged'); // Only logged users can write chat events
6
7streamer.allowWrite('notifications', function(eventName, type) { // Only admin users can write notificaiton events
8  if (this.userId && type === 'new-message') {                   // and only if the first param is 'new-message'
9    const user = Meteor.users.findOne(this.userId);
10    if (user && user.admin === true) {
11      return true;
12    }
13  }
14
15  return false;
16});