David Rose 23 лет назад
Родитель
Сommit
034291f780

+ 90 - 0
panda/src/downloader/httpChannel.I

@@ -166,6 +166,96 @@ get_persistent_connection() const {
   return _persistent_connection;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPChannel::set_download_throttle
+//       Access: Published
+//  Description: Specifies whether nonblocking downloads (via
+//               download_to_file() or download_to_ram()) will be
+//               limited so as not to use all available bandwidth.
+//
+//               If this is true, when a download has been started on
+//               this channel it will be invoked no more frequently
+//               than get_max_updates_per_second(), and the total
+//               bandwidth used by the download will be no more than
+//               get_max_bytes_per_second().  If this is false,
+//               downloads will proceed as fast as the server can send
+//               the data.
+//
+//               This only has effect on the nonblocking I/O methods
+//               like request_document(), etc.  The blocking methods
+//               like get_document() always use as much CPU and
+//               bandwidth as they can get.
+////////////////////////////////////////////////////////////////////
+INLINE void HTTPChannel::
+set_download_throttle(bool download_throttle) {
+  _download_throttle = download_throttle;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPChannel::get_download_throttle
+//       Access: Published
+//  Description: Returns whether the nonblocking downloads will be
+//               bandwidth-limited.  See set_download_throttle().
+////////////////////////////////////////////////////////////////////
+INLINE bool HTTPChannel::
+get_download_throttle() const {
+  return _download_throttle;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPChannel::set_max_bytes_per_second
+//       Access: Published
+//  Description: When bandwidth throttling is in effect (see
+//               set_download_throttle()), this specifies the maximum
+//               number of bytes per second that may be consumed by
+//               this channel.
+////////////////////////////////////////////////////////////////////
+INLINE void HTTPChannel::
+set_max_bytes_per_second(double max_bytes_per_second) {
+  _max_bytes_per_second = max_bytes_per_second;
+  _bytes_per_update = int(_max_bytes_per_second * _seconds_per_update);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPChannel::get_max_bytes_per_second
+//       Access: Published
+//  Description: Returns the maximum number of bytes per second that
+//               may be consumed by this channel when
+//               get_download_throttle() is true.
+////////////////////////////////////////////////////////////////////
+INLINE double HTTPChannel::
+get_max_bytes_per_second() const {
+  return _max_bytes_per_second;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPChannel::set_max_updates_per_second
+//       Access: Published
+//  Description: When bandwidth throttling is in effect (see
+//               set_download_throttle()), this specifies the maximum
+//               number of times per second that run() will attempt to
+//               do any downloading at all.
+////////////////////////////////////////////////////////////////////
+INLINE void HTTPChannel::
+set_max_updates_per_second(double max_updates_per_second) {
+  nassertv(max_updates_per_second != 0.0f);
+  _max_updates_per_second = max_updates_per_second;
+  _seconds_per_update = 1.0f / _max_updates_per_second;
+  _bytes_per_update = int(_max_bytes_per_second * _seconds_per_update);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPChannel::get_max_updates_per_second
+//       Access: Published
+//  Description: Returns the maximum number of times per second that
+//               run() will do anything at all, when
+//               get_download_throttle() is true.
+////////////////////////////////////////////////////////////////////
+INLINE double HTTPChannel::
+get_max_updates_per_second() const {
+  return _max_updates_per_second;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: HTTPChannel::get_file_size
 //       Access: Published

+ 34 - 0
panda/src/downloader/httpChannel.cxx

@@ -21,6 +21,8 @@
 #include "bioStream.h"
 #include "chunkedStream.h"
 #include "identityStream.h"
+#include "config_downloader.h"
+#include "clockObject.h"
 #include "buffer.h"  // for Ramfile
 
 #ifdef HAVE_SSL
@@ -48,6 +50,11 @@ HTTPChannel(HTTPClient *client) :
   _client(client)
 {
   _persistent_connection = false;
+  _download_throttle = false;
+  _max_bytes_per_second = downloader_byte_rate;
+  _seconds_per_update = downloader_frequency;
+  _max_updates_per_second = 1.0f / _seconds_per_update;
+  _bytes_per_update = int(_max_bytes_per_second * _seconds_per_update);
   _nonblocking = false;
   _read_index = 0;
   _file_size = 0;
@@ -63,6 +70,8 @@ HTTPChannel(HTTPClient *client) :
   _proxy_tunnel = false;
   _body_stream = NULL;
   _sbio = NULL;
+  _last_status_code = 0;
+  _last_run_time = 0.0f;
   _download_to_ramfile = NULL;
 }
 
@@ -201,6 +210,15 @@ run() {
   }
 
   if (_started_download) {
+    if (_nonblocking && _download_throttle) {
+      double now = ClockObject::get_global_clock()->get_real_time();
+      double elapsed = now - _last_run_time;
+      _last_run_time = now;
+      if (elapsed < _seconds_per_update) {
+        // Come back later.
+        return true;
+      }
+    }
     switch (_download_dest) {
     case DD_none:
       return false;  // We're done.
@@ -1102,9 +1120,17 @@ bool HTTPChannel::
 run_download_to_file() {
   nassertr(_body_stream != (ISocketStream *)NULL, false);
 
+  bool do_throttle = _nonblocking && _download_throttle;
+  int count = 0;
+
   int ch = _body_stream->get();
   while (!_body_stream->eof() && !_body_stream->fail()) {
     _download_to_file.put(ch);
+    if (do_throttle && ++count > _bytes_per_update) {
+      // That's enough for now.
+      return true;
+    }
+
     ch = _body_stream->get();
   }
 
@@ -1137,9 +1163,17 @@ run_download_to_ram() {
   nassertr(_body_stream != (ISocketStream *)NULL, false);
   nassertr(_download_to_ramfile != (Ramfile *)NULL, false);
 
+  bool do_throttle = _nonblocking && _download_throttle;
+  int count = 0;
+
   int ch = _body_stream->get();
   while (!_body_stream->eof() && !_body_stream->fail()) {
     _download_to_ramfile->_data += (char)ch;
+    if (do_throttle && ++count > _bytes_per_update) {
+      // That's enough for now.
+      return true;
+    }
+
     ch = _body_stream->get();
   }
 

+ 15 - 0
panda/src/downloader/httpChannel.h

@@ -86,6 +86,15 @@ PUBLISHED:
   INLINE void set_persistent_connection(bool persistent_connection);
   INLINE bool get_persistent_connection() const;
 
+  INLINE void set_download_throttle(bool download_throttle);
+  INLINE bool get_download_throttle() const;
+
+  INLINE void set_max_bytes_per_second(double max_bytes_per_second);
+  INLINE double get_max_bytes_per_second() const;
+
+  INLINE void set_max_updates_per_second(double max_updates_per_second);
+  INLINE double get_max_updates_per_second() const;
+
   INLINE size_t get_file_size() const;
 
   void write_headers(ostream &out) const;
@@ -165,6 +174,11 @@ private:
   PT(BioPtr) _bio;
   PT(BioStreamPtr) _source;
   bool _persistent_connection;
+  bool _download_throttle;
+  double _max_bytes_per_second;
+  double _max_updates_per_second;
+  double _seconds_per_update;
+  int _bytes_per_update;
   bool _nonblocking;
 
   URLSpec _url;
@@ -235,6 +249,7 @@ private:
   BIO *_sbio;
   pset<URLSpec> _redirect_trail;
   int _last_status_code;
+  double _last_run_time;
 
   typedef pmap<string, string> Tokens;
   typedef pmap<string, Tokens> AuthenticationSchemes;