summaryrefslogtreecommitdiff
path: root/platform/default/online_file_source.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/default/online_file_source.cpp')
-rw-r--r--platform/default/online_file_source.cpp156
1 files changed, 71 insertions, 85 deletions
diff --git a/platform/default/online_file_source.cpp b/platform/default/online_file_source.cpp
index 944bcd56d5..a4ac2c2b2b 100644
--- a/platform/default/online_file_source.cpp
+++ b/platform/default/online_file_source.cpp
@@ -1,5 +1,5 @@
#include <mbgl/storage/online_file_source.hpp>
-#include <mbgl/storage/http_context_base.hpp>
+#include <mbgl/storage/http_file_source.hpp>
#include <mbgl/storage/network_status.hpp>
#include <mbgl/storage/response.hpp>
@@ -22,20 +22,20 @@
namespace mbgl {
-class OnlineFileRequestImpl : public util::noncopyable {
+class OnlineFileRequest : public AsyncRequest {
public:
using Callback = std::function<void (Response)>;
- OnlineFileRequestImpl(FileRequest*, const Resource&, Callback, OnlineFileSource::Impl&);
- ~OnlineFileRequestImpl();
+ OnlineFileRequest(const Resource&, Callback, OnlineFileSource::Impl&);
+ ~OnlineFileRequest();
- void networkIsReachableAgain(OnlineFileSource::Impl&);
- void schedule(OnlineFileSource::Impl&, optional<SystemTimePoint> expires);
- void completed(OnlineFileSource::Impl&, Response);
+ void networkIsReachableAgain();
+ void schedule(optional<Timestamp> expires);
+ void completed(Response);
- FileRequest* key;
+ OnlineFileSource::Impl& impl;
Resource resource;
- HTTPRequestBase* request = nullptr;
+ std::unique_ptr<AsyncRequest> request;
util::Timer timer;
Callback callback;
@@ -52,8 +52,7 @@ public:
class OnlineFileSource::Impl {
public:
- // Dummy parameter is a workaround for a gcc 4.9 bug.
- Impl(int) {
+ Impl() {
NetworkStatus::Subscribe(&reachability);
}
@@ -61,16 +60,16 @@ public:
NetworkStatus::Unsubscribe(&reachability);
}
- void request(FileRequest* key, Resource resource, Callback callback) {
- allRequests[key] = std::make_unique<OnlineFileRequestImpl>(key, resource, callback, *this);
+ void add(OnlineFileRequest* request) {
+ allRequests.insert(request);
}
- void cancel(FileRequest* key) {
- allRequests.erase(key);
- if (activeRequests.erase(key)) {
+ void remove(OnlineFileRequest* request) {
+ allRequests.erase(request);
+ if (activeRequests.erase(request)) {
activatePendingRequest();
} else {
- auto it = pendingRequestsMap.find(key);
+ auto it = pendingRequestsMap.find(request);
if (it != pendingRequestsMap.end()) {
pendingRequestsList.erase(it->second);
pendingRequestsMap.erase(it);
@@ -78,30 +77,30 @@ public:
}
}
- void activateOrQueueRequest(OnlineFileRequestImpl* impl) {
- assert(allRequests.find(impl->key) != allRequests.end());
- assert(activeRequests.find(impl->key) == activeRequests.end());
- assert(!impl->request);
+ void activateOrQueueRequest(OnlineFileRequest* request) {
+ assert(allRequests.find(request) != allRequests.end());
+ assert(activeRequests.find(request) == activeRequests.end());
+ assert(!request->request);
- if (activeRequests.size() >= HTTPContextBase::maximumConcurrentRequests()) {
- queueRequest(impl);
+ if (activeRequests.size() >= HTTPFileSource::maximumConcurrentRequests()) {
+ queueRequest(request);
} else {
- activateRequest(impl);
+ activateRequest(request);
}
}
- void queueRequest(OnlineFileRequestImpl* impl) {
- auto it = pendingRequestsList.insert(pendingRequestsList.end(), impl->key);
- pendingRequestsMap.emplace(impl->key, std::move(it));
+ void queueRequest(OnlineFileRequest* request) {
+ auto it = pendingRequestsList.insert(pendingRequestsList.end(), request);
+ pendingRequestsMap.emplace(request, std::move(it));
}
- void activateRequest(OnlineFileRequestImpl* impl) {
- activeRequests.insert(impl->key);
- impl->request = httpContext->createRequest(impl->resource, [=] (Response response) {
- impl->request = nullptr;
- activeRequests.erase(impl->key);
+ void activateRequest(OnlineFileRequest* request) {
+ activeRequests.insert(request);
+ request->request = httpFileSource.request(request->resource, [=] (Response response) {
+ activeRequests.erase(request);
activatePendingRequest();
- impl->completed(*this, response);
+ request->request.reset();
+ request->completed(response);
});
}
@@ -110,20 +109,18 @@ public:
return;
}
- FileRequest* key = pendingRequestsList.front();
+ OnlineFileRequest* request = pendingRequestsList.front();
pendingRequestsList.pop_front();
- pendingRequestsMap.erase(key);
+ pendingRequestsMap.erase(request);
- auto it = allRequests.find(key);
- assert(it != allRequests.end());
- activateRequest(it->second.get());
+ activateRequest(request);
}
private:
void networkIsReachableAgain() {
- for (auto& req : allRequests) {
- req.second->networkIsReachableAgain(*this);
+ for (auto& request : allRequests) {
+ request->networkIsReachableAgain();
}
}
@@ -138,23 +135,22 @@ private:
* Requests in any state are in `allRequests`. Requests in the pending state are in
* `pendingRequests`. Requests in the active state are in `activeRequests`.
*/
- std::unordered_map<FileRequest*, std::unique_ptr<OnlineFileRequestImpl>> allRequests;
- std::list<FileRequest*> pendingRequestsList;
- std::unordered_map<FileRequest*, std::list<FileRequest*>::iterator> pendingRequestsMap;
- std::unordered_set<FileRequest*> activeRequests;
+ std::unordered_set<OnlineFileRequest*> allRequests;
+ std::list<OnlineFileRequest*> pendingRequestsList;
+ std::unordered_map<OnlineFileRequest*, std::list<OnlineFileRequest*>::iterator> pendingRequestsMap;
+ std::unordered_set<OnlineFileRequest*> activeRequests;
- const std::unique_ptr<HTTPContextBase> httpContext { HTTPContextBase::createContext() };
+ HTTPFileSource httpFileSource;
util::AsyncTask reachability { std::bind(&Impl::networkIsReachableAgain, this) };
};
OnlineFileSource::OnlineFileSource()
- : thread(std::make_unique<util::Thread<Impl>>(
- util::ThreadContext{ "OnlineFileSource", util::ThreadType::Unknown, util::ThreadPriority::Low }, 0)) {
+ : impl(std::make_unique<Impl>()) {
}
OnlineFileSource::~OnlineFileSource() = default;
-std::unique_ptr<FileRequest> OnlineFileSource::request(const Resource& resource, Callback callback) {
+std::unique_ptr<AsyncRequest> OnlineFileSource::request(const Resource& resource, Callback callback) {
Resource res = resource;
switch (resource.kind) {
@@ -183,40 +179,25 @@ std::unique_ptr<FileRequest> OnlineFileSource::request(const Resource& resource,
break;
}
- class OnlineFileRequest : public FileRequest {
- public:
- OnlineFileRequest(Resource resource_, FileSource::Callback callback_, util::Thread<OnlineFileSource::Impl>& thread_)
- : thread(thread_),
- workRequest(thread.invokeWithCallback(&OnlineFileSource::Impl::request, callback_, this, resource_)) {
- }
-
- ~OnlineFileRequest() {
- thread.invoke(&OnlineFileSource::Impl::cancel, this);
- }
-
- util::Thread<OnlineFileSource::Impl>& thread;
- std::unique_ptr<WorkRequest> workRequest;
- };
-
- return std::make_unique<OnlineFileRequest>(res, callback, *thread);
+ return std::make_unique<OnlineFileRequest>(res, callback, *impl);
}
-OnlineFileRequestImpl::OnlineFileRequestImpl(FileRequest* key_, const Resource& resource_, Callback callback_, OnlineFileSource::Impl& impl)
- : key(key_),
+OnlineFileRequest::OnlineFileRequest(const Resource& resource_, Callback callback_, OnlineFileSource::Impl& impl_)
+ : impl(impl_),
resource(resource_),
callback(std::move(callback_)) {
+ impl.add(this);
+
// Force an immediate first request if we don't have an expiration time.
if (resource.priorExpires) {
- schedule(impl, resource.priorExpires);
+ schedule(resource.priorExpires);
} else {
- schedule(impl, SystemClock::now());
+ schedule(util::now());
}
}
-OnlineFileRequestImpl::~OnlineFileRequestImpl() {
- if (request) {
- request->cancel();
- }
+OnlineFileRequest::~OnlineFileRequest() {
+ impl.remove(this);
}
static Duration errorRetryTimeout(Response::Error::Reason failedRequestReason, uint32_t failedRequests) {
@@ -233,20 +214,20 @@ static Duration errorRetryTimeout(Response::Error::Reason failedRequestReason, u
}
}
-static Duration expirationTimeout(optional<SystemTimePoint> expires, uint32_t expiredRequests) {
+static Duration expirationTimeout(optional<Timestamp> expires, uint32_t expiredRequests) {
if (expiredRequests) {
return Seconds(1 << std::min(expiredRequests - 1, 31u));
} else if (expires) {
- return std::max(SystemDuration::zero(), *expires - SystemClock::now());
+ return std::max(Seconds::zero(), *expires - util::now());
} else {
return Duration::max();
}
}
-SystemTimePoint interpolateExpiration(const SystemTimePoint& current,
- optional<SystemTimePoint> prior,
- bool& expired) {
- auto now = SystemClock::now();
+Timestamp interpolateExpiration(const Timestamp& current,
+ optional<Timestamp> prior,
+ bool& expired) {
+ auto now = util::now();
if (current > now) {
return current;
}
@@ -275,10 +256,10 @@ SystemTimePoint interpolateExpiration(const SystemTimePoint& current,
// Assume that either the client or server clock is wrong and
// try to interpolate a valid expiration date (from the client POV)
// observing a minimum timeout.
- return now + std::max<SystemDuration>(delta, util::CLOCK_SKEW_RETRY_TIMEOUT);
+ return now + std::max<Seconds>(delta, util::CLOCK_SKEW_RETRY_TIMEOUT);
}
-void OnlineFileRequestImpl::schedule(OnlineFileSource::Impl& impl, optional<SystemTimePoint> expires) {
+void OnlineFileRequest::schedule(optional<Timestamp> expires) {
if (request) {
// There's already a request in progress; don't start another one.
return;
@@ -307,7 +288,7 @@ void OnlineFileRequestImpl::schedule(OnlineFileSource::Impl& impl, optional<Syst
});
}
-void OnlineFileRequestImpl::completed(OnlineFileSource::Impl& impl, Response response) {
+void OnlineFileRequest::completed(Response response) {
// If we didn't get various caching headers in the response, continue using the
// previous values. Otherwise, update the previous values to the new values.
@@ -345,15 +326,20 @@ void OnlineFileRequestImpl::completed(OnlineFileSource::Impl& impl, Response res
failedRequestReason = Response::Error::Reason::Success;
}
- callback(response);
- schedule(impl, response.expires);
+ schedule(response.expires);
+
+ // Calling the callback may result in `this` being deleted. It needs to be done last,
+ // and needs to make a local copy of the callback to ensure that it remains valid for
+ // the duration of the call.
+ auto callback_ = callback;
+ callback_(response);
}
-void OnlineFileRequestImpl::networkIsReachableAgain(OnlineFileSource::Impl& impl) {
+void OnlineFileRequest::networkIsReachableAgain() {
// We need all requests to fail at least once before we are going to start retrying
// them, and we only immediately restart request that failed due to connection issues.
if (failedRequestReason == Response::Error::Reason::Connection) {
- schedule(impl, SystemClock::now());
+ schedule(util::now());
}
}