~ubuntuone-control-tower/ubuntu-sso-client/stable-1-0

« back to all changes in this revision

Viewing changes to ubuntu_sso/utils/__init__.py

  • Committer: Tarmac
  • Author(s): Alejandro J. Cura
  • Date: 2011-12-02 19:30:27 UTC
  • mfrom: (646.1.3 timestamp-autofix-1-0)
  • Revision ID: tarmac-20111202193027-f1u4ma2pyar42qdc
Do a HEAD request on the server to get accurate timestamp (LP: #692597 & LP: #891644)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
 
 
3
# Author: Alejandro J. Cura <alecu@canonical.com>
 
4
#
 
5
# Copyright 2010, 2011 Canonical Ltd.
 
6
#
 
7
# This program is free software: you can redistribute it and/or modify it
 
8
# under the terms of the GNU General Public License version 3, as published
 
9
# by the Free Software Foundation.
 
10
#
 
11
# This program is distributed in the hope that it will be useful, but
 
12
# WITHOUT ANY WARRANTY; without even the implied warranties of
 
13
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
14
# PURPOSE.  See the GNU General Public License for more details.
 
15
#
 
16
# You should have received a copy of the GNU General Public License along
 
17
# with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
 
 
19
"""Utility modules that may find use outside ubuntu_sso."""
 
20
import time
 
21
import urllib2
 
22
from twisted.web import http
 
23
 
 
24
from ubuntu_sso.logger import setup_logging
 
25
logger = setup_logging("ubuntu_sso.utils")
 
26
 
 
27
 
 
28
class RequestHead(urllib2.Request):
 
29
    """A request with the method set to HEAD."""
 
30
 
 
31
    _request_method = "HEAD"
 
32
 
 
33
    def get_method(self):
 
34
        """Return the desired method."""
 
35
        return self._request_method
 
36
 
 
37
 
 
38
class SyncTimestampChecker(object):
 
39
    """A timestamp that's regularly checked with a server."""
 
40
 
 
41
    CHECKING_INTERVAL = 60 * 60  # in seconds
 
42
    ERROR_INTERVAL = 30  # in seconds
 
43
    SERVER_URL = "http://one.ubuntu.com/api/time"
 
44
 
 
45
    def __init__(self):
 
46
        """Initialize this instance."""
 
47
        self.next_check = time.time()
 
48
        self.skew = 0
 
49
 
 
50
    def get_server_time(self):
 
51
        """Get the time at the server."""
 
52
        headers = {"Cache-Control": "no-cache"}
 
53
        request = RequestHead(self.SERVER_URL, headers=headers)
 
54
        response = urllib2.urlopen(request)
 
55
        date_string = response.info()["Date"]
 
56
        timestamp = http.stringToDatetime(date_string)
 
57
        return timestamp
 
58
 
 
59
    def get_faithful_time(self):
 
60
        """Get an accurate timestamp."""
 
61
        local_time = time.time()
 
62
        if local_time >= self.next_check:
 
63
            try:
 
64
                server_time = self.get_server_time()
 
65
                self.next_check = local_time + self.CHECKING_INTERVAL
 
66
                self.skew = server_time - local_time
 
67
                logger.debug("Calculated server-local time skew: %r",
 
68
                             self.skew)
 
69
            #pylint: disable=W0703
 
70
            except Exception, server_error:
 
71
                logger.debug("Error while verifying the server time skew: %r",
 
72
                             server_error)
 
73
                self.next_check = local_time + self.ERROR_INTERVAL
 
74
        logger.debug("Using corrected timestamp: %r",
 
75
                     http.datetimeToString(local_time + self.skew))
 
76
        return int(local_time + self.skew)
 
77
 
 
78
 
 
79
# pylint: disable=C0103
 
80
timestamp_checker = SyncTimestampChecker()
 
81
# pylint: enable=C0103