blob: dd9a729e5a395f63b57bb7e876d325255228836b [file] [log] [blame]
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +00001#!/usr/bin/env python
2#-*- coding: utf-8 -*-
3# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
4#
5# Use of this source code is governed by a BSD-style license
6# that can be found in the LICENSE file in the root of the source
7# tree. An additional intellectual property rights grant can be found
8# in the file PATENTS. All contributing project authors may
9# be found in the AUTHORS file in the root of the source tree.
10
11"""Contains utilities for communicating with the dashboard."""
12
13__author__ = 'phoglund@webrtc.org (Patrik Höglund)'
14
15import httplib
16import shelve
17import oauth.oauth as oauth
18
19import constants
20
21
22class FailedToReadRequiredInputFile(Exception):
23 pass
24
25
26class FailedToReportToDashboard(Exception):
27 pass
28
29
30class DashboardConnection:
31 """Helper class for pushing data to the dashboard.
32
33 This class deals with most of details for accessing protected resources
34 (i.e. data-writing operations) on the dashboard. Such operations are
35 authenticated using OAuth. This class requires a consumer secret and a
36 access token.
37
38 The consumer secret is created manually on the machine running the script
39 (only authorized users should be able to log into the machine and see the
40 secret though). The access token is generated by the
41 request_oauth_permission.py script. Both these values are stored as files
42 on disk, in the scripts' working directory, according to the formats
43 prescribed in the read_required_files method.
44 """
45
46 def __init__(self, consumer_key):
47 self.consumer_key_ = consumer_key
48
49 def read_required_files(self, consumer_secret_file, access_token_file):
50 """Reads required data for making OAuth requests.
51
52 Args:
53 consumer_secret_file: A plain text file with a single line containing
54 the consumer secret string.
55 access_token_file: A shelve file with an entry access_token
56 containing the access token in string form.
57 """
58 self.access_token_ = self._read_access_token(access_token_file)
59 self.consumer_secret_ = self._read_consumer_secret(consumer_secret_file)
60
61 def send_post_request(self, sub_url, parameters):
62 """Sends an OAuth request for a protected resource in the dashboard.
63
64 Use this when you want to report new data to the dashboard. You must have
65 called the read_required_files method prior to calling this method, since
66 that method will read in the consumer secret and access token we need to
67 make the OAuth request. These concepts are described in the class
68 description.
69
70 Args:
71 sub_url: A relative url within the dashboard domain, for example
72 /add_coverage_data.
73 parameters: A dict which maps from POST parameter names to values.
74
75 Returns:
76 A httplib response object.
77
78 Raises:
79 FailedToReportToDashboard: If the dashboard didn't respond
80 with HTTP 200 to our request.
81 """
82 consumer = oauth.OAuthConsumer(self.consumer_key_, self.consumer_secret_)
83 create_oauth_request = oauth.OAuthRequest.from_consumer_and_token
84 oauth_request = create_oauth_request(consumer,
85 token=self.access_token_,
86 http_method='POST',
87 http_url=sub_url,
88 parameters=parameters)
89
90 signature_method_hmac_sha1 = oauth.OAuthSignatureMethod_HMAC_SHA1()
91 oauth_request.sign_request(signature_method_hmac_sha1, consumer,
92 self.access_token_)
93
94 connection = httplib.HTTPConnection(constants.DASHBOARD_SERVER)
95
96 headers = {'Content-Type': 'application/x-www-form-urlencoded'}
97 connection.request('POST', sub_url, body=oauth_request.to_postdata(),
98 headers=headers)
99
100 response = connection.getresponse()
101 connection.close()
102
103 if response.status != 200:
104 message = ('Error: Failed to report to %s%s: got response %d (%s)' %
105 (constants.DASHBOARD_SERVER, sub_url, response.status,
106 response.reason))
107 raise FailedToReportToDashboard(message)
108
109 return response
110
111 def _read_access_token(self, filename):
112 input_file = shelve.open(filename)
113
114 if not input_file.has_key('access_token'):
115 raise FailedToReadRequiredInputFile('Missing correct %s file in current '
116 'directory. You may have to run '
117 'request_oauth_permission.py.' %
118 filename)
119
120 token = input_file['access_token']
121 input_file.close()
122
123 return oauth.OAuthToken.from_string(token)
124
125 def _read_consumer_secret(self, filename):
126 try:
127 input_file = open(filename, 'r')
128 except IOError as error:
129 raise FailedToReadRequiredInputFile(error)
130
131 whole_file = input_file.read()
132 if whole_file.count('\n') > 1 or not whole_file.strip():
133 raise FailedToReadRequiredInputFile('Expected a single line with the '
134 'consumer secret in file %s.' %
135 filename)
136 return whole_file
137