All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cometd.server.ext.TimesyncExtension Maven / Gradle / Ivy

There is a newer version: 8.0.6
Show newest version
// ========================================================================
// Copyright 2006 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at 
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================

package org.cometd.server.ext;

import java.util.Map;

import org.cometd.Client;
import org.cometd.Extension;
import org.cometd.Message;
import org.cometd.server.ClientImpl;
import org.eclipse.jetty.util.ajax.JSON;

/* ------------------------------------------------------------ */
/**
 * Timesync extension (server side).
 * 
 * With each handshake or connect, the extension sends timestamps within the ext
 * field like:
 * {ext:{timesync:{tc:12345567890,l:23,o:4567},...},...} where:
 * 
    *
  • tc is the client timestamp in ms since 1970 of when the message was sent. *
  • l is the network lag that the client has calculated. *
  • o is the clock offset that the client has calculated. *
* *

* A cometd server that supports timesync, can respond with an ext field like: * {ext:{timesync:{tc:12345567890,ts:1234567900,p:123,a:3},...},...} * where: *

    *
  • tc is the client timestamp of when the message was sent, *
  • ts is the server timestamp of when the message was received *
  • p is the poll duration in ms - ie the time the server took before sending * the response. *
  • a is the measured accuracy of the calculated offset and lag sent by the * client *
*

* The relationship between tc, ts, o & l on the server is given by * ts=tc+o+l (the time the server received the message is the * client time plus the offset plus the network lag). Thus the accuracy of the o * and l settings can be determined with a=tc+o+l-ts. *

*

* When the client has received the response, it can make a more accurate * estimate of the lag as l2=(now-tc-p)/2 (assuming symmetric lag). * A new offset can then be calculated with the relationship on the client that * ts=tc+o2+l2, thus o2=ts-tc-l2. *

*

* Since the client also receives the a value calculated on the server, it * should be possible to analyse this and compensate for some asymmetry in the * lag. But the current client does not do this. *

*/ public class TimesyncExtension implements Extension { private int _accuracyTarget=25; public TimesyncExtension() { } /* ------------------------------------------------------------ */ /** * timesync responses are not set if the measured accuracy is less than the * accuracyTarget. * * @return accuracy target in ms (default 25ms) */ public int getAccuracyTarget() { return _accuracyTarget; } /* ------------------------------------------------------------ */ /** * timesync responses are not set if the measured accuracy is less than the * accuracyTarget. * * @param target * accuracy target in ms */ public void setAccuracyTarget(int target) { _accuracyTarget=target; } public Message rcv(Client from, Message message) { return message; } public Message rcvMeta(Client from, Message message) { Map ext=message.getExt(false); if (ext != null) { Map sync=(Map)ext.get("timesync"); if (sync != null) { sync.put("ts",new Long(System.currentTimeMillis())); Number lag=(Number)sync.get("l"); if (lag != null && from != null) ((ClientImpl)from).setLag(lag.intValue()); } } return message; } public Message send(Client from, Message message) { return message; } public Message sendMeta(Client from, Message message) { Message associated=message.getAssociated(); if (associated != null) { Map extIn=associated.getExt(false); if (extIn != null) { Map sync=(Map)extIn.get("timesync"); if (sync != null) { final long tc=((Number)sync.get("tc")).longValue(); final long ts=((Number)sync.get("ts")).longValue(); final Number lag=(Number)sync.get("l"); if (lag == null) { // old style timesync Map extOut=(Map)message.getExt(true); JSON.Literal timesync=new JSON.Literal("{\"tc\":" + tc + ",\"ts\":" + ts + ",\"p\":" + (System.currentTimeMillis() - ts) + "}"); extOut.put("timesync",timesync); } else { final int l=lag.intValue(); final int o=((Number)sync.get("o")).intValue(); final int a=(int)((tc + o + l) - ts); // is a OK ? if (l == 0 || a >= _accuracyTarget || a <= -_accuracyTarget) { Map extOut=(Map)message.getExt(true); JSON.Literal timesync=new JSON.Literal("{\"tc\":" + tc + ",\"ts\":" + ts + ",\"p\":" + (System.currentTimeMillis() - ts) + ",\"a\":" + a + "}"); extOut.put("timesync",timesync); } } } } } return message; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy