1 #!/usr/bin/env python2.5
3 # Copyright (c) 2011 Neal H. Walfield <neal@walfield.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 logger = logging.getLogger(__name__)
24 class ProgressSocket(object):
26 Monitor what is being sent and received.
28 def __init__(self, socket, connection):
30 self.connection = connection
32 def __getattribute__(self, attr):
33 # logger.debug("%s.__getattribute__(%s)"
34 # % (self.__class__.__name__, attr))
40 while sent < len (data):
41 remaining = len (data) - sent
47 self.socket.sendall(data[sent:sent+amount])
49 self.connection.stats['sent'] += amount
50 self.connection.opener.stats['sent'] += amount
52 if self.connection.callback is not None:
53 self.connection.callback ()
55 def read(*args, **kwargs):
56 data = self.socket.read (*args, **kwargs)
57 # print "GOT: %s" % (data[0:240],)
58 self.connection.stats['received'] += len (data)
59 self.connection.opener.stats['received'] += len (data)
60 if self.connection.callback is not None:
61 self.connection.callback ()
64 if attr == 'send' or attr == 'sendall':
70 return super (ProgressSocket, self).__getattribute__(attr)
71 except AttributeError:
72 socket = super (ProgressSocket, self).__getattribute__('socket')
73 return socket.__getattribute__(attr)
75 def makefile(self, mode, bufsize):
76 return ProgressSocket (socket=self.socket.makefile(mode, bufsize),
77 connection=self.connection)
80 return self.socket.close ()
82 def HTTPProgressConnectionBuilder(callback, opener):
83 class HTTPProgressConnection(httplib.HTTPConnection):
84 def __init__(self, *args, **kwargs):
87 return httplib.HTTPConnection.__init__ (self, *args, **kwargs)
89 def putrequest(self, method, url, *args, **kwargs):
92 return httplib.HTTPConnection.putrequest (
93 self, method, url, *args, **kwargs)
96 httplib.HTTPConnection.connect(self)
98 self.sock = ProgressSocket(socket=self.sock,
101 HTTPProgressConnection.callback = callback
102 HTTPProgressConnection.opener = opener
103 HTTPProgressConnection.stats \
104 = {'sent': 0, 'received': 0, 'started':time.time()}
105 return HTTPProgressConnection
107 class HTTPProgressHandler(urllib2.HTTPHandler):
108 def __init__(self, callback):
109 self.callback = callback
110 self.stats = {'sent': 0, 'received': 0, 'started':time.time()}
111 return urllib2.HTTPHandler.__init__(self)
113 def http_open(self, request):
115 HTTPProgressConnectionBuilder(self.callback, self),
118 if __name__ == '__main__':
119 def callback(connection):
121 if connection.method:
122 req += connection.method + " "
123 req += connection.host + ':' + str (connection.port)
125 req += connection.url
127 cstats = connection.stats
128 ostats = connection.opener.stats
131 ("%s: connection: %d sent, %d received: %d kb/s; "
132 + "opener: %d sent, %d received, %d kb/s")
134 cstats['sent'], cstats['received'],
135 ((cstats['sent'] + cstats['received'])
136 / (time.time() - cstats['started']) / 1024),
137 ostats['sent'], ostats['received'],
138 ((ostats['sent'] + ostats['received'])
139 / (time.time() - ostats['started']) / 1024)))
141 opener = urllib2.build_opener(HTTPProgressHandler(callback))
143 data = opener.open ('http://google.com')
146 downloaded += len (d)
147 print "Document is %d bytes in size" % (downloaded,)