Skip to content

Instantly share code, notes, and snippets.

@mfbx9da4
Last active December 15, 2020 14:38
Show Gist options
  • Save mfbx9da4/27613da25ac7ba5c4118 to your computer and use it in GitHub Desktop.
Save mfbx9da4/27613da25ac7ba5c4118 to your computer and use it in GitHub Desktop.
Angular Clock Synchronization using websockets between browser and server (similar to NTP).
/**
* Synchronizes local system time with server time
* using clock synchronization algorithm, similar to
* NTP.
*
* Pings server every half second for server time.
* Calculates offset as difference between server time
* and browser time before and after socket request.
*
* Keeps track of last 5 offsets and calculates current
* offset as average of middle 3 offsets.
*
* @module server-date
* author David Alberto Adler github.com/mfbx9da4
*/
angular.module('server-date', []).factory('ServerDate', ['socket','$interval', function(socket,$interval) {
var self = {
/**
* Last five offsets.
*
*/
last_five_offsets: [],
/**
* When true prints offset on update.
*
*/
verbose: false,
/**
* Ping the server with current date
*
*/
ping: function () {
socket.emit('date now', Date.now());
},
/**
* Get offset between client and server in milliseconds
*
* @return {Number} How many milliseconds the browser is behind the server.
*/
getOffset: function () {
return self.offset;
},
/**
* Correct now
*
*/
now: function () {
return Date.now() + self.offset;
},
/**
* Corrected now in new date form
*
*/
new: function () {
return new Date(self.now());
},
/**
* On socket from server. Updates offset.
*
* @param {Number} data.server Server timestamp
* @param {Number} data.sender Client timestamp
*/
onServerDate: function(data){
var offset1 = data.server_transmission_time - Date.now();
var offset2 = data.server_transmission_time - data.sender_transmission_time;
var offset = (offset1 + offset2) / 2.0;
// keep last 5 values
self.last_five_offsets.push(offset);
while(self.last_five_offsets.length > 5) {
self.last_five_offsets.shift();
}
// copy
var values = self.last_five_offsets.slice();
// sort
values.sort(function(a, b) {return b - a;});
// take middle three
if (values.length > 3) {
values = values.slice(1,4);
}
// find average
var sum = 0
for (var i = 0; i < values.length; i ++) {
sum += values[i];
}
var average = Math.floor(sum / values.length);
self.offset = average;
if (self.verbose) {
console.log(values, 'offset', self.offset);
}
},
/**
* Init starts interval and listens
* on sockets.
*
*/
init: function () {
socket.on('date now', self.onServerDate);
// Ping server regularly
self.ping();
self.pingInterval = $interval(self.ping, 500);
}
};
window.serverdateself = self;
self.init();
return {
now: self.now,
new: self.new,
ping: self.ping,
getOffset: self.getOffset
};
}]);
@RafiyYassine
Copy link

SsS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment