Browse Source

support unknown-sized downloads

David Rose 16 years ago
parent
commit
a7ac5345f4

+ 32 - 2
direct/src/plugin/p3dDownload.I

@@ -27,18 +27,33 @@ get_url() const {
 //     Function: P3DDownload::get_download_progress
 //       Access: Public
 //  Description: Returns an indication of the progress through the
-//               download file, 0.0 to 1.0.  Returns 0.0 if the size
+//               download file, 0.0 to 1.0.  Returns 1.0 if the size
 //               of the file is not known.
 ////////////////////////////////////////////////////////////////////
 inline double P3DDownload::
 get_download_progress() const {
   if (_total_expected_data == 0) {
-    return 0.0;
+    return 1.0;
   }
 
   return (double)_total_data / (double)_total_expected_data;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DDownload::is_download_progress_known
+//       Access: Public
+//  Description: Returns true if the download progress is known, or
+//               false if it is unknown because the server hasn't told
+//               us the total size it will be feeding us.  If this is
+//               false, get_download_progress() will generally always
+//               return 1.0; use get_total_bytes() to measure progress
+//               in this case.
+////////////////////////////////////////////////////////////////////
+inline bool P3DDownload::
+is_download_progress_known() const {
+  return _progress_known;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DDownload::get_total_data
 //       Access: Public
@@ -49,6 +64,21 @@ get_total_data() const {
   return _total_data;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DDownload::set_total_expected_data
+//       Access: Public
+//  Description: Sets the total number of bytes expected to be
+//               downloaded.  This is used to compute the progress.
+//               Normally, this can be set from the download server,
+//               but there may be cases when the download server
+//               doesn't accurately report it.
+////////////////////////////////////////////////////////////////////
+inline void P3DDownload::
+set_total_expected_data(size_t expected_data) {
+  _total_expected_data = expected_data;
+  _progress_known = true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DDownload::get_download_finished
 //       Access: Public

+ 33 - 8
direct/src/plugin/p3dDownload.cxx

@@ -26,6 +26,7 @@ P3DDownload() {
   _total_data = 0;
   _total_expected_data = 0;
   _last_reported_time = 0;
+  _progress_known = false;
   
   _canceled = false;
   _download_id = 0;
@@ -39,7 +40,8 @@ P3DDownload() {
 P3DDownload::
 P3DDownload(const P3DDownload &copy) :
   _url(copy._url),
-  _total_expected_data(copy._total_expected_data)
+  _total_expected_data(copy._total_expected_data),
+  _progress_known(copy._progress_known)
 {
   _status = P3D_RC_in_progress;
   _http_status_code = 0;
@@ -132,12 +134,27 @@ feed_url_stream(P3D_result_code result_code,
     _total_data += this_data_size;
   }
 
-  _total_expected_data = max(total_expected_data, _total_data);
+  total_expected_data = max(total_expected_data, _total_data);
+  if (total_expected_data > _total_expected_data) {
+    // If the expected data grows during the download, we don't really
+    // know how much we're getting.
+    _progress_known = false;
+    _total_expected_data = total_expected_data;
+  }
+  if (_total_expected_data > 0 && 
+      (double)_total_data / (double)_total_expected_data < 0.9) {
+    // But if we're not close to our target yet, let's say we do know
+    // (at least until we get there and the target moves again).
+    _progress_known = true;
+  }
 
   download_progress();
 
   if (_status != P3D_RC_in_progress) {
     // We're done.
+    if (get_download_success()) {
+      _progress_known = true;
+    }
     download_finished(get_download_success());
   }
 
@@ -167,9 +184,13 @@ download_progress() {
   time_t now = time(NULL);
   if (now - _last_reported_time > 10) {
     _last_reported_time = now;
-    nout << "Downloading " << get_url() << ": " 
-         << int(get_download_progress() * 1000.0) / 10.0 
-         << ", " << this << "\n";
+    nout << "Downloading " << get_url() << ": ";
+    if (_progress_known) {
+      nout << int(get_download_progress() * 1000.0) / 10.0 << "%";
+    } else {
+      nout << int((double)get_total_data() / 104857.6) / 10.0 << "M";
+    }
+    nout << ", " << this << "\n";
   }
 }
 
@@ -183,7 +204,11 @@ download_progress() {
 ////////////////////////////////////////////////////////////////////
 void P3DDownload::
 download_finished(bool success) {
-  nout << "Downloaded " << get_url() << ": " 
-       << int(get_download_progress() * 1000.0) / 10.0 
-       << ", " << this << ", success = " << success << "\n";
+  nout << "Downloaded " << get_url() << ": ";
+  if (_progress_known) {
+    nout << int(get_download_progress() * 1000.0) / 10.0 << "%";
+  } else {
+    nout << int((double)get_total_data() / 104857.6) / 10.0 << "M";
+  }
+  nout << ", " << this << ", success = " << success << "\n";
 }

+ 3 - 0
direct/src/plugin/p3dDownload.h

@@ -38,10 +38,12 @@ public:
   inline const string &get_url() const;
 
   inline double get_download_progress() const;
+  inline bool is_download_progress_known() const;
   inline bool get_download_finished() const;
   inline bool get_download_success() const;
   inline bool get_download_terminated() const;
   inline size_t get_total_data() const;
+  inline void set_total_expected_data(size_t expected_data);
 
   void cancel();
   void clear();
@@ -70,6 +72,7 @@ protected:
   size_t _total_data;
   size_t _total_expected_data;
   time_t _last_reported_time;
+  bool _progress_known;
 
 private:
   bool _canceled;

+ 18 - 10
direct/src/plugin/p3dInstance.cxx

@@ -332,6 +332,9 @@ set_p3d_url(const string &p3d_url) {
   InstanceDownload *download = new InstanceDownload(this);
   download->set_url(p3d_url);
   download->set_filename(_temp_p3d_filename->get_filename());
+  if (_fparams.has_token("p3d_size")) {
+    download->set_total_expected_data(_fparams.lookup_token_int("p3d_size"));
+  }
 
   _panda_script_object->set_string_property("status", "downloading_instance");
   start_download(download);
@@ -371,6 +374,9 @@ make_p3d_stream(const string &p3d_url) {
   InstanceDownload *download = new InstanceDownload(this);
   download->set_url(p3d_url);
   download->set_filename(_temp_p3d_filename->get_filename());
+  if (_fparams.has_token("p3d_size")) {
+    download->set_total_expected_data(_fparams.lookup_token_int("p3d_size"));
+  }
 
   _panda_script_object->set_string_property("status", "downloading_instance");
   return start_download(download, false);
@@ -2438,7 +2444,7 @@ report_package_info_ready(P3DPackage *package) {
       // put up a progress bar.
       make_splash_window();
       if (_splash_window != NULL) {
-        _splash_window->set_install_progress(0.0);
+        _splash_window->set_install_progress(0.0, true, 0);
         if (package == _certlist_package) {
           _splash_window->set_install_label("Getting Certificates");
         } else {          
@@ -2493,7 +2499,7 @@ report_package_info_ready(P3DPackage *package) {
       }
       
       if (_splash_window != NULL) {
-        _splash_window->set_install_progress(0.0);
+        _splash_window->set_install_progress(0.0, true, 0);
       }
       _panda_script_object->set_string_property("status", "downloading");
       _panda_script_object->set_int_property("numDownloadingPackages", _downloading_packages.size());
@@ -2573,7 +2579,7 @@ mark_download_complete() {
   
   // Take down the download progress bar.
   if (_splash_window != NULL) {
-    _splash_window->set_install_progress(0.0);
+    _splash_window->set_install_progress(0.0, true, 0);
     _splash_window->set_install_label("");
   }
 
@@ -2616,7 +2622,8 @@ ready_to_start() {
 //  Description: Notified as the instance file is downloaded.
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
-report_instance_progress(double progress) {
+report_instance_progress(double progress, bool is_progress_known,
+                         size_t received_data) {
   if (!_show_dl_instance_progress) {
     // If we haven't yet set the download label, set it after a full
     // second has elapsed.  We don't want to set it too soon, because
@@ -2642,7 +2649,7 @@ report_instance_progress(double progress) {
   }
 
   if (_splash_window != NULL && _show_dl_instance_progress) {
-    _splash_window->set_install_progress(progress);
+    _splash_window->set_install_progress(progress, is_progress_known, received_data);
   }
   _panda_script_object->set_float_property("instanceDownloadProgress", progress);
 }
@@ -2662,7 +2669,7 @@ report_package_progress(P3DPackage *package, double progress) {
   if (package == _certlist_package || package == _p3dcert_package) {
     // This gets its own progress bar.
     if (_splash_window != NULL) {
-      _splash_window->set_install_progress(progress);
+      _splash_window->set_install_progress(progress, true, 0);
     }
     return;
   }
@@ -2679,7 +2686,7 @@ report_package_progress(P3DPackage *package, double progress) {
   progress = min(progress, 1.0);
 
   if (_splash_window != NULL) {
-    _splash_window->set_install_progress(progress);
+    _splash_window->set_install_progress(progress, true, 0);
   }
   _panda_script_object->set_float_property("downloadProgress", progress);
 
@@ -2754,7 +2761,7 @@ report_package_done(P3DPackage *package, bool success) {
 
     // Take down the download progress.
     if (_splash_window != NULL) {
-      _splash_window->set_install_progress(0.0);
+      _splash_window->set_install_progress(0.0, true, 0);
       _splash_window->set_install_label("");
     }
 
@@ -2770,7 +2777,7 @@ report_package_done(P3DPackage *package, bool success) {
 
     // Take down the download progress.
     if (_splash_window != NULL) {
-      _splash_window->set_install_progress(0.0);
+      _splash_window->set_install_progress(0.0, true, 0);
       _splash_window->set_install_label("");
     }
 
@@ -3143,7 +3150,7 @@ InstanceDownload(P3DInstance *inst) :
 void P3DInstance::InstanceDownload::
 download_progress() {
   P3DFileDownload::download_progress();
-  _inst->report_instance_progress(get_download_progress());
+  _inst->report_instance_progress(get_download_progress(), is_download_progress_known(), get_total_data());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -3159,6 +3166,7 @@ download_finished(bool success) {
   P3DFileDownload::download_finished(success);
   if (success) {
     // We've successfully downloaded the instance data.
+    _inst->report_instance_progress(1.0, true, 0);
     _inst->priv_set_p3d_filename(get_filename());
   } else {
     // Oops, no joy on the instance data.

+ 3 - 2
direct/src/plugin/p3dInstance.h

@@ -187,9 +187,10 @@ private:
   void start_next_download();
   void mark_download_complete();
   void ready_to_start();
-  void report_instance_progress(double progress);
+  void report_instance_progress(double progress, bool is_progress_known,
+                                size_t received_data);
   void report_package_progress(P3DPackage *package, double progress);
-  void report_package_done(P3DPackage *package, bool progress);
+  void report_package_done(P3DPackage *package, bool success);
   void set_install_label(const string &install_label);
 
   void paint_window();

+ 46 - 9
direct/src/plugin/p3dOsxSplashWindow.cxx

@@ -185,12 +185,25 @@ set_install_label(const string &install_label) {
 //  Description: Moves the install progress bar from 0.0 to 1.0.
 ////////////////////////////////////////////////////////////////////
 void P3DOsxSplashWindow::
-set_install_progress(double install_progress) {
-  if ((int)(install_progress * 500.0) != (int)(_install_progress * 500.0)) {
-    // Only request a refresh if we're changing substantially.
+set_install_progress(double install_progress,
+                     bool is_progress_known, size_t received_data) {
+  // Only request a refresh if we're changing substantially.
+  if (is_progress_known != _progress_known) {
     refresh();
+  } else if (_progress_known) {
+    if ((int)(install_progress * 500.0) != (int)(_install_progress * 500.0)) {
+      refresh();
+    }
+  } else {
+    if ((int)(received_data * _unknown_progress_rate) != 
+        (int)(_received_data * _unknown_progress_rate)) {
+      refresh();
+    }
   }
+
   _install_progress = install_progress;
+  _progress_known = is_progress_known;
+  _received_data = received_data;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -343,8 +356,14 @@ paint_window() {
 
   // Draw the progress bar.  We don't draw this bar at all unless we
   // have nonzero progress.
-  if (_install_progress != 0.0) {
-    paint_progress_bar(context);
+  if (_progress_known) {
+    if (_install_progress != 0.0) {
+      paint_progress_bar(context);
+    }
+  } else {
+    if (_received_data != 0) {
+      paint_progress_bar(context);
+    }
   }
 
   CGContextSynchronize(context);
@@ -507,15 +526,33 @@ paint_progress_bar(CGContextRef context) {
   CGContextFillPath(context);
 
   // Draw the interior of the progress bar in blue (or the bar color).
-  int progress_width = (int)((bar_width - 2) * _install_progress);
-  if (progress_width != 0) {
-    CGRect prog = { { bar_xf, bar_yf }, { progress_width, bar_height } };
+  if (_progress_known) {
+    int progress_width = (int)(bar_width * _install_progress + 0.5);
+    if (progress_width != 0) {
+      CGRect prog = { { bar_xf, bar_yf }, { progress_width, bar_height } };
+      CGContextBeginPath(context);
+      CGContextSetFillColorWithColor(context, bar);
+      CGContextAddRect(context, prog);
+      CGContextFillPath(context);
+    }
+  } else {
+    // Progress is unknown.  Draw a moving block, not a progress bar
+    // filling up.
+    int block_width = (int)(bar_width * 0.1 + 0.5);
+    int block_travel = bar_width - block_width;
+    int progress = (int)(_received_data * _unknown_progress_rate);
+    progress = progress % (block_travel * 2);
+    if (progress > block_travel) {
+      progress = block_travel * 2 - progress;
+    }
+
+    CGRect prog = { { bar_xf + progress, bar_yf }, { block_width, bar_height } };
     CGContextBeginPath(context);
     CGContextSetFillColorWithColor(context, bar);
     CGContextAddRect(context, prog);
     CGContextFillPath(context);
   }
-
+    
   // Draw the black stroke around the progress bar.
   CGContextBeginPath(context);
   CGContextSetLineWidth(context, 1);

+ 4 - 1
direct/src/plugin/p3dOsxSplashWindow.h

@@ -38,7 +38,8 @@ public:
   virtual void set_image_filename(const string &image_filename,
                                   ImagePlacement image_placement);
   virtual void set_install_label(const string &install_label);
-  virtual void set_install_progress(double install_progress);
+  virtual void set_install_progress(double install_progress,
+                                    bool is_progress_known, size_t received_data);
 
   virtual bool handle_event(const P3D_event_data &event);
 
@@ -81,6 +82,8 @@ private:
 
   string _install_label;
   double _install_progress;
+  bool _progress_known;
+  size_t _received_data;
 
   // Used to track the mouse within the window in the embedded case.
   bool _mouse_active;

+ 5 - 2
direct/src/plugin/p3dSplashWindow.cxx

@@ -39,7 +39,9 @@ METHODDEF(void) my_error_exit (j_common_ptr cinfo) {
   longjmp(myerr->setjmp_buffer, 1);
 }
 
-
+// The number of pixels to move the block per byte downloaded, when we
+// don't know the actual file size we're downloading.
+const double P3DSplashWindow::_unknown_progress_rate = 1.0 / 4096;
 
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DSplashWindow::Constructor
@@ -192,7 +194,8 @@ set_install_label(const string &install_label) {
 //  Description: Moves the install progress bar from 0.0 to 1.0.
 ////////////////////////////////////////////////////////////////////
 void P3DSplashWindow::
-set_install_progress(double install_progress) {
+set_install_progress(double install_progress,
+                     bool is_progress_known, size_t received_data) {
 }
 
 ////////////////////////////////////////////////////////////////////

+ 4 - 1
direct/src/plugin/p3dSplashWindow.h

@@ -58,7 +58,8 @@ public:
   virtual void set_bgcolor(int r, int g, int b);
   virtual void set_barcolor(int r, int g, int b);
   virtual void set_install_label(const string &install_label);
-  virtual void set_install_progress(double install_progress);
+  virtual void set_install_progress(double install_progress,
+                                    bool is_progress_known, size_t received_data);
 
   virtual bool handle_event(const P3D_event_data &event);
 
@@ -120,6 +121,8 @@ protected:
   bool _mouse_down;
   bool _button_depressed;
   ButtonState _bstate;
+
+  static const double _unknown_progress_rate;
 };
 
 #include "p3dSplashWindow.I"

+ 3 - 2
direct/src/plugin/p3dWinSplashWindow.cxx

@@ -176,7 +176,8 @@ set_install_label(const string &install_label) {
 //  Description: Moves the install progress bar from 0.0 to 1.0.
 ////////////////////////////////////////////////////////////////////
 void P3DWinSplashWindow::
-set_install_progress(double install_progress) {
+set_install_progress(double install_progress,
+                     bool is_progress_known, size_t received_data) {
   ACQUIRE_LOCK(_install_lock);
   _install_progress = install_progress;
   RELEASE_LOCK(_install_lock);
@@ -776,7 +777,7 @@ paint_progress_bar(HDC dc) {
   FillRect(dc, &bar_rect, _bg_brush);
 
   // Draw the interior of the progress bar in blue (or the bar color).
-  int progress_width = (int)((bar_width - 2) * _drawn_progress);
+  int progress_width = (int)((bar_width - 2) * _drawn_progress + 0.5);
   if (progress_width != 0) {
     RECT prog_rect = { bar_x, bar_y, bar_x + progress_width, bar_y + bar_height };
     FillRect(dc, &prog_rect, _bar_brush);

+ 2 - 1
direct/src/plugin/p3dWinSplashWindow.h

@@ -40,7 +40,8 @@ public:
   virtual void set_image_filename(const string &image_filename,
                                   ImagePlacement image_placement);
   virtual void set_install_label(const string &install_label);
-  virtual void set_install_progress(double install_progress);
+  virtual void set_install_progress(double install_progress,
+                                    bool is_progress_known, size_t received_data);
   virtual void request_keyboard_focus();
 
   static void register_window_class();

+ 3 - 2
direct/src/plugin/p3dX11SplashWindow.cxx

@@ -156,7 +156,8 @@ set_install_label(const string &install_label) {
 //  Description: Moves the install progress bar from 0.0 to 1.0.
 ////////////////////////////////////////////////////////////////////
 void P3DX11SplashWindow::
-set_install_progress(double install_progress) {
+set_install_progress(double install_progress,
+                     bool is_progress_known, size_t received_data) {
   if (_subprocess_pid == -1) {
     return;
   }
@@ -611,7 +612,7 @@ subprocess_run() {
       }
       
       if (needs_update_progress) {
-        int progress_width = (int)((bar_width - 2) * _install_progress);
+        int progress_width = (int)((bar_width - 2) * _install_progress + 0.5);
         XFillRectangle(_display, _window, _bar_context, 
                        bar_x + 1, bar_y + 1,
                        progress_width + 1, bar_height - 1);

+ 2 - 1
direct/src/plugin/p3dX11SplashWindow.h

@@ -42,7 +42,8 @@ public:
   virtual void set_image_filename(const string &image_filename,
                                   ImagePlacement image_placement);
   virtual void set_install_label(const string &install_label);
-  virtual void set_install_progress(double install_progress);
+  virtual void set_install_progress(double install_progress,
+                                    bool is_progress_known, size_t received_data);
 
   virtual void set_button_active(bool flag);
 

+ 1 - 1
direct/src/plugin_npapi/startup.cxx

@@ -434,7 +434,7 @@ NPP_WriteReady_x(NPP instance, NPStream *stream) {
 int32_t
 NPP_Write_x(NPP instance, NPStream *stream, int32_t offset, 
             int32_t len, void *buffer) {
-  //  nout << "Write " << stream->url << ", " << len << " for " << instance << ", " << (PPInstance *)(instance->pdata) << "\n";
+  //  nout << "Write " << stream->url << ", " << offset << ", " << len << " for " << instance << ", " << (PPInstance *)(instance->pdata) << "\n";
   PPInstance::generic_browser_call();
   PPInstance *inst = (PPInstance *)(instance->pdata);
   assert(inst != NULL);