-
Notifications
You must be signed in to change notification settings - Fork 11.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
500 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.build* | ||
.versions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
language: node_js | ||
node_js: | ||
- "0.10" | ||
before_install: | ||
- "curl -L http://git.io/ejPSng | /bin/sh" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
## vNEXT | ||
|
||
## v0.3.4 | ||
|
||
- Explicitly pull in client-side `check` for Meteor 1.2 apps. | ||
|
||
## v0.3.3 | ||
|
||
- Be more robust with sync url when outside of Cordova. (#30) | ||
|
||
## v0.3.2 | ||
|
||
- Fix issue when used in Cordova. (#22, #26, #27) | ||
|
||
## v0.3.1 | ||
|
||
- Fix an issue where `TimeSync.serverTime` returned an erroneous value when passed a `Date` (instead of an epoch). (#23) | ||
|
||
## v0.3.0 | ||
|
||
- `TimeSync.serverTime` now supports an optional second `updateInterval` argument, causing the reactive value to update less frequently. (#10) | ||
- `TimeSync.loggingEnabled` can be now set to false to suppress client log output. (#21) | ||
- Explicitly set MIME type on timesync endpoint. (#17, #18) | ||
|
||
## v0.2.2 | ||
|
||
- **Updated for Meteor 0.9.** | ||
- Further adjust clock watching tolerance to be less sensitive to CPU. | ||
|
||
## v0.2.1 | ||
|
||
- Re-sync automatically after a reconnection. | ||
- Adjust clock watching tolerance so as to be less sensitive to heavy client CPU usage. | ||
|
||
## v0.2.0 | ||
|
||
- Clock change watching is now on by default (it's very lightweight and only involves grabbing and checking a `Date`). | ||
- Invalidate offset value and dependent time computations when we detect a clock change. | ||
- Added a `Date.now` shim for earlier versions of IE. | ||
- Reorganized code for testing and added some basic tests. | ||
|
||
## v0.1.6 | ||
|
||
- Added the optional `TimeSync.watchClockChanges` which can resync if a client's clock is detected to have significantly changed. | ||
- Added retry attempts to syncing, making it more robust over a hot code reload among other situations. | ||
|
||
## v0.1.5 | ||
|
||
- Use `WebApp.rawConnectHandlers` as a less janky way of getting our date request handled first. | ||
- Fixed an issue where a cached reload could result in a wacky time offset due to the server time being cached. | ||
|
||
## v0.1.4 | ||
|
||
- Switch to JS at the request of @raix and @arunoda ;-) | ||
- Use a middleware handler, spliced into the top of the connect stack, instead of a Meteor method to avoid arbitrary method blocking delay. This improves accuracy significantly. | ||
- Compute a RTT value in `TimeSync.roundTripTime` as well as a time offset. | ||
|
||
## v0.1.3 | ||
|
||
- Ensure that the computed offset is always an integer number of milliseconds. | ||
|
||
## v0.1.2 | ||
|
||
- Added the `TimeSync.resync` function that triggers a resync with the server. | ||
|
||
## v0.1.1 | ||
|
||
- Added the reactive function `TimeSync.isSynced` to determine if an initial sync has taken place. | ||
|
||
## v0.1.0 | ||
|
||
- First release. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2015 Andrew Mao | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
meteor-timesync [![Build Status](https://travis-ci.org/mizzao/meteor-timesync.svg)](https://travis-ci.org/mizzao/meteor-timesync) | ||
=============== | ||
|
||
NTP-style time synchronization between server and client, and facilities to | ||
use server time reactively in Meteor applications. | ||
|
||
## What's this do? | ||
|
||
Meteor clients don't necessarily have accurate timestamps relative to your server. This package computes and maintains an offset between server and client, allowing server timestamps to be used on the client (especially for displaying time differences). It also provides facilities to use time reactively in your application. | ||
|
||
There is a demo as part of the user-status app at http://user-status.meteor.com. | ||
|
||
## Installation | ||
|
||
``` | ||
meteor add mizzao:timesync | ||
``` | ||
|
||
## Usage | ||
|
||
- `TimeSync.serverTime(clientTime, updateInterval)`: returns the server time for a given client time, as a UTC/Unix timestamp. A reactive variable which changes with the computed offset, and updates continually. Pass in `clientTime` optionally to specify a particular time on the client, instead of reactively depending on the current time. Pass in `updateInterval` to change the rate (in milliseconds) at which the reactive variable updates; the default value is 1000 (1 second). | ||
- `TimeSync.serverOffset()`: returns the current time difference between the server and the client. Reactively updates as the offset is recomputed. | ||
- `TimeSync.roundTripTime()`: The round trip ping to the server. Also reactive. | ||
- `TimeSync.isSynced()`: Reactive variable that determines if an initial sync has taken place. | ||
- `TimeSync.resync()`: Re-triggers a sync with the server. Can be useful because the initial sync often takes place during a lot of traffic with the server and could be less accurate. | ||
- `TimeSync.loggingEnabled`: defaults to `true`, set this to `false` to suppress diagnostic syncing messages on the client. | ||
|
||
To use the above functions in a non-reactive context, use [`Deps.nonreactive`](http://docs.meteor.com/#deps_nonreactive). This is useful if you are displaying a lot of timestamps or differences on a page and you don't want them to be constantly recomputed on the client. However, displaying time reactively should be pretty efficient with Meteor 0.8.0+ (Blaze). | ||
|
||
Note that `TimeSync.serverTime` returns a timestamp, not a `Date`, but you can easily construct a date with `new Date(TimeSync.serverTime(...))`. | ||
|
||
You can also use something like `TimeSync.serverTime(null, 5000)` to get a reactive time value that only updates at 5 second intervals. All reactive time variables with the same value of `updateInterval` are guaranteed to be invalidated at the same time. | ||
|
||
## Notes | ||
|
||
- This library is a crude approximation of NTP, at the moment. It's empirically shown to be accurate to under 100 ms on the meteor.com servers. | ||
- We could definitely do something smarter and more accurate, with multiple measurements and exponentially weighted updating. | ||
- Check out the moment library [packaged for meteor](https://github.com/acreeger/meteor-moment) for formatting and displaying the differences computed by this package. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
Package.describe({ | ||
name: "mizzao:timesync", | ||
summary: "NTP-style time synchronization between server and client", | ||
version: "0.3.4", | ||
git: "https://github.com/mizzao/meteor-timesync.git" | ||
}); | ||
|
||
Package.onUse(function (api) { | ||
api.versionsFrom("1.2.0.1"); | ||
|
||
api.use([ | ||
'check', | ||
'tracker', | ||
'http' | ||
], 'client'); | ||
|
||
api.use('webapp', 'server'); | ||
|
||
// Our files | ||
api.addFiles('timesync-server.js', 'server'); | ||
api.addFiles('timesync-client.js', 'client'); | ||
|
||
api.export('TimeSync', 'client'); | ||
api.export('SyncInternals', 'client', {testOnly: true} ); | ||
}); | ||
|
||
Package.onTest(function (api) { | ||
api.use([ | ||
'tinytest', | ||
'test-helpers' | ||
]); | ||
|
||
api.use(["tracker", "underscore"], 'client'); | ||
|
||
api.use("mizzao:timesync"); | ||
|
||
api.addFiles('tests/client.js', 'client'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
Tinytest.add("timesync - tick check - normal tick", function(test) { | ||
var lastTime = 5000; | ||
var currentTime = 6000; | ||
var interval = 1000; | ||
var tolerance = 1000; | ||
|
||
test.equal(SyncInternals.timeCheck(lastTime, currentTime, interval, tolerance), true); | ||
}); | ||
|
||
Tinytest.add("timesync - tick check - slightly off", function(test) { | ||
var lastTime = 5000; | ||
var currentTime = 6500; | ||
var interval = 1000; | ||
var tolerance = 1000; | ||
|
||
test.equal(SyncInternals.timeCheck(lastTime, currentTime, interval, tolerance), true); | ||
|
||
currentTime = 5500; | ||
|
||
test.equal(SyncInternals.timeCheck(lastTime, currentTime, interval, tolerance), true); | ||
}); | ||
|
||
Tinytest.add("timesync - tick check - big jump", function(test) { | ||
var lastTime = 5000; | ||
var currentTime = 0; | ||
var interval = 1000; | ||
var tolerance = 1000; | ||
|
||
test.equal(SyncInternals.timeCheck(lastTime, currentTime, interval, tolerance), false); | ||
|
||
currentTime = 10000; | ||
|
||
test.equal(SyncInternals.timeCheck(lastTime, currentTime, interval, tolerance), false); | ||
}); | ||
|
||
/* | ||
TODO: add tests for proper dependencies in reactive functions | ||
*/ | ||
|
||
Tinytest.addAsync("timesync - basic - initial sync", function(test, next) { | ||
|
||
function success() { | ||
var syncedTime = TimeSync.serverTime(); | ||
|
||
// Make sure the time exists | ||
test.isTrue(syncedTime); | ||
|
||
// Make sure it's close to the current time on the client. This should | ||
// always be true in PhantomJS tests where client/server are the same | ||
// machine, although it might fail in development environments, for example | ||
// when the server and client are different VMs. | ||
test.isTrue( Math.abs(syncedTime - Date.now()) < 1000 ); | ||
|
||
next(); | ||
} | ||
|
||
function fail() { | ||
test.fail(); | ||
next(); | ||
} | ||
|
||
simplePoll(TimeSync.isSynced, success, fail, 5000, 100); | ||
}); | ||
|
||
Tinytest.addAsync("timesync - basic - serverTime format", function(test, next) { | ||
|
||
test.isTrue(_.isNumber( TimeSync.serverTime() )); | ||
|
||
test.isTrue(_.isNumber( TimeSync.serverTime(null) )); | ||
|
||
// Accept Date as client time | ||
test.isTrue(_.isNumber( TimeSync.serverTime(new Date()) )); | ||
|
||
// Accept epoch as client time | ||
test.isTrue(_.isNumber( TimeSync.serverTime(Date.now()) )); | ||
|
||
next(); | ||
}); | ||
|
||
Tinytest.addAsync("timesync - basic - different sync intervals", function(test, next) { | ||
|
||
var aCount = 0, bCount = 0, cCount = 0; | ||
|
||
var a = Tracker.autorun(function () { | ||
TimeSync.serverTime(null, 500); | ||
aCount++; | ||
}); | ||
|
||
var b = Tracker.autorun(function () { | ||
TimeSync.serverTime(); | ||
bCount++; | ||
}); | ||
|
||
var c = Tracker.autorun(function () { | ||
TimeSync.serverTime(null, 2000); | ||
cCount++; | ||
}); | ||
|
||
var testInterval = 5000; | ||
|
||
Meteor.setTimeout(function() { | ||
|
||
test.equal(aCount, 10); // 0, 500, 1000, 1500 ... | ||
// not going to be 5 since the first tick won't generate this dep | ||
test.equal(bCount, 6); | ||
test.equal(cCount, 3); // 0, 2000, 4000 | ||
|
||
test.isTrue(SyncInternals.timeTick[500]); | ||
test.isTrue(SyncInternals.timeTick[1000]); | ||
test.isTrue(SyncInternals.timeTick[2000]); | ||
|
||
test.equal(Object.keys(SyncInternals.timeTick).length, 3); | ||
|
||
a.stop(); | ||
b.stop(); | ||
c.stop(); | ||
|
||
next() | ||
}, testInterval); | ||
|
||
}); |
Oops, something went wrong.