Skip to content

Ddp

Distributed Data Protocol

The DDP (Distributed Data Protocol) is a WebSocket-based protocol used in Meteor to manage communication between the client and the server. It's a key component in how Meteor achieves its reactive, real-time web application capabilities. DDP is used for two primary purposes: to synchronize data between the client and server, and to remotely call server-side methods from the client.

Key Features of DDP

  1. Real-Time Data Sync: DDP keeps the client and server data in sync in real-time. When data in a server-side collection changes, the updates are pushed to the client automatically and immediately.
  2. WebSocket-Based: Being built on top of WebSockets, DDP provides a continuous connection between client and server, allowing for low-latency, bi-directional communication.
  3. Reactivity: In conjunction with Meteor’s reactive data sources, DDP enables reactive updates to the UI whenever the underlying data changes.

How DDP Works

  1. Subscription:
  2. Clients subscribe to a dataset published by the server. This subscription tells the server what data the client is interested in.
  3. Example:

    Meteor.subscribe('myData');
    

  4. Data Management and Synchronization:

  5. When a client subscribes, the server sends the current state of the requested dataset to the client. The server then sends updates as the data changes over time.
  6. These updates keep the client-side cache (MiniMongo) in sync with the server's MongoDB database.

  7. Method Calls:

  8. DDP allows clients to call methods defined on the server. This can be used for operations that should be executed server-side.
  9. Example:

    Meteor.call('updateRecord', recordId, newData, (error, result) => {
      // Handle response
    });
    

  10. Latency Compensation (Optimistic UI Updates):

  11. When a method is called on the client, Meteor can simulate the expected outcome on the client immediately, without waiting for the server's response. This is known as "optimistic UI updates" and helps in making the app feel more responsive.

Use Cases

  • Live Chat Applications: Real-time message syncing between users.
  • Collaborative Tools: Applications where multiple users interact with the same data simultaneously, like collaborative editing tools.
  • Notifications and Feeds: Real-time updates like notification feeds or live data dashboards.

Considerations

  • Performance: While DDP is efficient, managing a large number of subscriptions or frequent method calls can impact performance.
  • Security: Secure your method implementations and validate all data on the server to prevent unauthorized access or changes.
  • Fallbacks: Consider fallback mechanisms for environments where WebSockets are not supported or reliable.

Conclusion

DDP is a powerful protocol that underpins the real-time, reactive nature of Meteor applications. Its seamless handling of data synchronization and method calls between client and server makes it an essential part of developing responsive and interactive web applications with Meteor.


import { DDP } from 'meteor/ddp-client'
import { Mongo } from 'meteor/mongo'

const eCoinCore = DDP.connect('https://ecoincore.com');
const ExchangeRates = new Mongo.Collection('ExchangeRates', eCoinCore);
const SomeInmemCollection = new Mongo.Collection('ExchangeRates', { connection: null });

eCoinCore.onReconnect = function() {
  log.info("eCoinCore.onReconnect");
  log.info("eCoinCore.status()", eCoinCore.status())
};

eCoinCore._stream.on('message', function(raw_msg) {
  // log.info({raw_msg})
});

Meteor.setTimeout(() => {
  ExchangeRates.find().forEach((rate)=>{
    ingestRate(rate)
  });

  // Keep track of ExchangeRates.
  const cursor = ExchangeRates.find({});
  const handle = cursor.observeChanges({
    added(id, rate) {
      ingestRate(rate)
    },
    changed(id, rate) {
      ingestRate(rate)
    }
  });
}, 5 * 1000);


// Meteor.setTimeout(() => handle.stop(), 15 * 60 * 1000);

Router.route('/v1/price', function () {

  const req = this.request;
  const res = this.response;

  var ip = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
  log.debug(`price requested from ip:${ip}`);
  res.end(JSON.stringify(currentExchangeRates, null, 3));

}, {where: 'server'});