From 7bdd91bc9f0ffe03b8c003d6cbaf54a170a7cf91 Mon Sep 17 00:00:00 2001 From: ac-stef Date: Sun, 6 Sep 2015 19:17:14 +0200 Subject: [PATCH] improved timeout handling and progress bar for autodownloads http get now uses two timeout values: one for the max time since last server response, and one for total download time. When AC is waiting for a server response (before a http header was received), the progress bar will show the timeout "completion". --- source/src/autodownload.cpp | 11 ++++++----- source/src/http.cpp | 20 +++++++++++++------- source/src/protos.h | 5 +++-- source/src/serverbrowser.cpp | 5 +++-- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/source/src/autodownload.cpp b/source/src/autodownload.cpp index 7b3ad86c..d2edf99e 100644 --- a/source/src/autodownload.cpp +++ b/source/src/autodownload.cpp @@ -75,7 +75,7 @@ int pingpckserver(void *data) // fetch updates.txt from a media server, measure SDL_mutexV(pckpinglog_lock); if(s->resolved) { - int res = h.get(updatestxt, 5000, 0, true); // http HEAD request only - to get a nice ping value + int res = h.get(updatestxt, 5000, 10000, 0, true); // http HEAD request only - to get a nice ping value if(h.response > 0) { s->ping = h.elapsedtime; @@ -85,7 +85,7 @@ int pingpckserver(void *data) // fetch updates.txt from a media server, measure if(h.response == 200) { h.outvec = new vector; - res = h.get(updatestxt, 5000); // http GET + res = h.get(updatestxt, 5000, 20000); // http GET if(res >= 0 && h.response == 200) { // parse updates.txt h.outvec->add('\0'); @@ -341,9 +341,10 @@ int progress_callback_dlpackage(void *data, float progress) if(progress_of < 0) { defformatstring(txt)("downloading %s... (esc to abort)", (const char *)data); - show_out_of_renderloop_progress(min(progress, 1.0f), txt); + if(progress < 0) show_out_of_renderloop_progress(progress + 1.0f, "waiting for response (esc to abort)"); + else show_out_of_renderloop_progress(min(progress, 1.0f), txt); } - else loadingscreen("downloading package %d of %d...\n%s %d%%\n(ESC to cancel)", progress_n, progress_of, (const char *)data, int(100.0 * progress)); + else loadingscreen("downloading package %d of %d...\n%s \fs%s%d%%\fr\n(ESC to cancel)", progress_n, progress_of, (const char *)data, progress < 0 ? "\f3waiting " : "", int(100.0 * fabs(progress))); if(interceptkey(SDLK_ESCAPE)) { canceldownloads = true; @@ -361,7 +362,7 @@ bool dlpackage(httpget &h, package *pck, pckserver *s) // download one package f if(*host && h.set_host(host)) { h.outstream = openvecfile(NULL); - int got = h.get(pck->requestname, 60000); + int got = h.get(pck->requestname, 6000, 90000); if(!h.response) { if(!canceldownloads && s) s->ping = 0; // received a hard error from the server connection, better not try this one again diff --git a/source/src/http.cpp b/source/src/http.cpp index e0743d39..b8b623c9 100644 --- a/source/src/http.cpp +++ b/source/src/http.cpp @@ -86,13 +86,14 @@ bool httpget::connect(bool force) return true; } -int httpget::get(const char *url1, uint timeout, int range, bool head) +int httpget::get(const char *url1, uint timeout, uint totaltimeout, int range, bool head) { int redirects = 0, res = 0, transferred = 0; vector *content = NULL; - ASSERT(timeout); // zero is not allowed + ASSERT(timeout && totaltimeout); // zero is not allowed stopwatch to; to.start(); + uint lastresponse = 0; reset(1); // clear old response values and url url = newstring(url1); @@ -135,18 +136,20 @@ int httpget::get(const char *url1, uint timeout, int range, bool head) buf.dataLength -= sent; tcp_age.start(); traffic += sent; + lastresponse = to.elapsed(); } - float progress = ((float) to.elapsed()) / timeout; - if(progress > 1.0f) ERROR("timeout"); - if(execcallback(progress)) return -1; // show progress bar, check for user interrupt + elapsedtime = to.elapsed(); + if(elapsedtime > totaltimeout || elapsedtime > lastresponse + timeout) ERROR("timeout 1"); + if(execcallback(-float(elapsedtime - lastresponse) / timeout)) return -1; // show progress bar, check for user interrupt } // get response bool again = false, haveheader = false; if(!retry) for(;;) { - float progress = ((float) (elapsedtime = to.elapsed())) / timeout; - if(progress > 1.0f) ERROR("timeout"); + elapsedtime = to.elapsed(); + if(elapsedtime > totaltimeout || elapsedtime > lastresponse + timeout) ERROR(elapsedtime > totaltimeout ? "timeout 2" : "timeout 3"); + float progress = -float(elapsedtime - lastresponse) / timeout; enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE; if(rawrec.length() > maxsize || datarec.length() > maxsize) break; if(enet_socket_wait(tcp, &events, 250) >= 0 && events) @@ -164,6 +167,7 @@ int httpget::get(const char *url1, uint timeout, int range, bool head) tcp_age.start(); traffic += recv; if((transferred += recv) > maxtransfer) ERROR("transfer size exceeds limit"); + lastresponse = to.elapsed(); // parsing received data rawrec.add('\0'); // append '\0' to use string functions safely - will be removed again @@ -248,6 +252,7 @@ int httpget::get(const char *url1, uint timeout, int range, bool head) } else break; } + progress = float(datarec.length()) / (maxtransfer | 1); // not accurate, but moving } else { @@ -256,6 +261,7 @@ int httpget::get(const char *url1, uint timeout, int range, bool head) progress = float(rawrec.length() - 1) / contentlength; // get a real progress bar if(rawrec.length() - 1 >= contentlength) content = &rawrec; } + else progress = float(rawrec.length() - 1) / (maxtransfer | 1); // not accurate, but moving } } rawrec.drop(); diff --git a/source/src/protos.h b/source/src/protos.h index 2cd5ffb7..d3dfa1a0 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -257,7 +257,8 @@ struct httpget // result char *header; - int response, chunked, gzipped, contentlength, offset, elapsedtime, traffic; + int response, chunked, gzipped, contentlength, offset, traffic; + uint elapsedtime; vector *outvec; // receives data, if not NULL (must be set up manually) stream *outstream; // receives data, if not NULL (must be set up manually) @@ -268,7 +269,7 @@ struct httpget bool execcallback(float progress); void disconnect(); bool connect(bool force = false); - int get(const char *url1, uint timeout, int range = 0, bool head = false); // get web ressource + int get(const char *url1, uint timeout, uint totaltimeout, int range = 0, bool head = false); // get web ressource }; extern char *urlencode(const char *s, bool strict = false); diff --git a/source/src/serverbrowser.cpp b/source/src/serverbrowser.cpp index 61169fe9..99fa1484 100644 --- a/source/src/serverbrowser.cpp +++ b/source/src/serverbrowser.cpp @@ -1310,7 +1310,8 @@ bool cllock = false, clfail = false; int progress_callback_retrieveservers(void *data, float progress) { - show_out_of_renderloop_progress(min(progress, 1.0f), (const char *)data); + if(progress < 0) show_out_of_renderloop_progress(progress + 1.0f, "waiting for response (esc to abort)"); + else show_out_of_renderloop_progress(min(progress, 1.0f), (const char *)data); return interceptkey(SDLK_ESCAPE) ? 1 : 0; } @@ -1329,7 +1330,7 @@ void retrieveservers(vector &data) defformatstring(url)("/retrieve.do?action=list&name=%s&version=%d&build=%d", urlencode(global_name, true), AC_VERSION, getbuildtype()|(1<<16)); h.outvec = (vector *) &data; // ouch... show_out_of_renderloop_progress(0, progresstext); - h.get(url, RETRIEVELIMIT); + h.get(url, RETRIEVELIMIT, RETRIEVELIMIT); if(h.response != 200) data.setsize(0); h.outvec = NULL; // must not be cleaned up by httpget if(data.length()) data.add('\0');