allow for cancellable request, track in tiles, and cancel when obsolete
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <llmr/util/noncopyable.hpp>
|
||||
#include <llmr/geometry/debug_font_buffer.hpp>
|
||||
#include <llmr/geometry/vao.hpp>
|
||||
#include <llmr/platform/platform.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <forward_list>
|
||||
@@ -93,8 +94,8 @@ public:
|
||||
private:
|
||||
// Source data
|
||||
std::string data;
|
||||
|
||||
const Style& style;
|
||||
platform::Request req;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -19,16 +19,21 @@ namespace platform {
|
||||
// Restarts painting. This could for example trigger the event loop of the controlling application.
|
||||
void restart();
|
||||
|
||||
struct Request {
|
||||
int16_t identifier = -1;
|
||||
std::string original_url;
|
||||
};
|
||||
|
||||
struct Response {
|
||||
int16_t code = -1;
|
||||
std::string body;
|
||||
};
|
||||
|
||||
// Makes an HTTP request of a URL on a background thread, calls a function with the results on the same thread, and finally calls a callback function on the main thread.
|
||||
void request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback);
|
||||
// Makes an HTTP request of a URL on a background thread, calls a function with the results on the same thread, and finally calls a callback function on the main thread. Returns a cancellable request.
|
||||
Request request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback);
|
||||
|
||||
// Makes a tile-specific HTTP request of a URL on a background thread, calls a function with the results on the same thread, and finally calls a callback function on the main thread. Access to the tile object is provided via a shared pointer.
|
||||
void request_http_tile(std::string tile_template_url, tile_ptr tile_object, std::function<void(Response&)> background_function, std::function<void()> foreground_callback);
|
||||
// Cancels an HTTP request.
|
||||
void cancel_request_http(Request request);
|
||||
|
||||
// Returns a relative timestamp in seconds. This value must be monotonic.
|
||||
double time();
|
||||
|
||||
@@ -155,11 +155,7 @@ class MBXMapView
|
||||
{
|
||||
[[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks)
|
||||
{
|
||||
for (NSURLSessionDownloadTask *task in downloadTasks)
|
||||
if (task.taskDescription)
|
||||
return [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
|
||||
|
||||
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
|
||||
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:([downloadTasks count] > 0)];
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -404,10 +400,12 @@ namespace llmr
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil];
|
||||
}
|
||||
|
||||
void request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback)
|
||||
Request request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback)
|
||||
{
|
||||
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil];
|
||||
|
||||
Response res;
|
||||
|
||||
if ( ! error)
|
||||
@@ -425,52 +423,25 @@ namespace llmr
|
||||
}];
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
void request_http_tile(std::string url, tile_ptr tile_object, std::function<void(Response&)> background_function, std::function<void()> foreground_callback)
|
||||
{
|
||||
NSString *latestZoom = [@(tile_object->id.z) stringValue];
|
||||
|
||||
[[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks)
|
||||
{
|
||||
for (NSURLSessionDownloadTask *task in downloadTasks)
|
||||
if (task.taskDescription && ! [task.taskDescription isEqualToString:latestZoom])
|
||||
[task cancel];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil];
|
||||
}];
|
||||
|
||||
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil];
|
||||
|
||||
if (error && [[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled)
|
||||
return;
|
||||
|
||||
Response res;
|
||||
|
||||
if ( ! error)
|
||||
{
|
||||
res.code = [(NSHTTPURLResponse *)response statusCode];
|
||||
res.body = { (const char *)[data bytes], [data length] };
|
||||
}
|
||||
|
||||
background_function(res);
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void)
|
||||
{
|
||||
foreground_callback();
|
||||
});
|
||||
|
||||
if ( ! error)
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil];
|
||||
}];
|
||||
|
||||
task.taskDescription = [@(tile_object->id.z) stringValue];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MBXUpdateActivityNotification object:nil];
|
||||
|
||||
[task resume];
|
||||
Request req;
|
||||
|
||||
req.identifier = task.taskIdentifier;
|
||||
req.original_url = url;
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
void cancel_request_http(Request request)
|
||||
{
|
||||
[[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks)
|
||||
{
|
||||
for (NSURLSessionDownloadTask *task in downloadTasks)
|
||||
if (task.taskIdentifier == request.identifier)
|
||||
return [task cancel];
|
||||
}];
|
||||
}
|
||||
|
||||
double time()
|
||||
|
||||
@@ -240,7 +240,7 @@ void restart() {
|
||||
[[NSApplication sharedApplication] postEvent: [NSEvent eventWithCGEvent:event] atStart:NO];
|
||||
}
|
||||
|
||||
void request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback)
|
||||
Request request_http(std::string url, std::function<void(Response&)> background_function, std::function<void()> foreground_callback)
|
||||
{
|
||||
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
|
||||
{
|
||||
@@ -261,46 +261,23 @@ void request_http(std::string url, std::function<void(Response&)> background_fun
|
||||
}];
|
||||
|
||||
[task resume];
|
||||
|
||||
Request req;
|
||||
|
||||
req.identifier = task.taskIdentifier;
|
||||
req.original_url = url;
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
void request_http_tile(std::string url, tile_ptr tile_object, std::function<void(Response&)> background_function, std::function<void()> foreground_callback)
|
||||
void cancel_request_http(Request request)
|
||||
{
|
||||
NSString *latestZoom = [@(tile_object->id.z) stringValue];
|
||||
|
||||
[[NSURLSession sharedSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks)
|
||||
{
|
||||
for (NSURLSessionDownloadTask *task in downloadTasks)
|
||||
if (task.taskDescription && ! [task.taskDescription isEqualToString:latestZoom])
|
||||
[task cancel];
|
||||
if (task.taskIdentifier == request.identifier)
|
||||
return [task cancel];
|
||||
}];
|
||||
|
||||
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@(url.c_str())] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
|
||||
{
|
||||
if (error && [[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled)
|
||||
return;
|
||||
|
||||
Response res;
|
||||
|
||||
if ( ! error)
|
||||
{
|
||||
res.code = [(NSHTTPURLResponse *)response statusCode];
|
||||
res.body = { (const char *)[data bytes], [data length] };
|
||||
}
|
||||
|
||||
background_function(res);
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void)
|
||||
{
|
||||
foreground_callback();
|
||||
});
|
||||
|
||||
if ( ! error)
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MBXNeedsRenderNotification object:nil];
|
||||
}];
|
||||
|
||||
task.taskDescription = [@(tile_object->id.z) stringValue];
|
||||
|
||||
[task resume];
|
||||
}
|
||||
|
||||
double time() {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <llmr/renderer/fill_bucket.hpp>
|
||||
#include <llmr/renderer/line_bucket.hpp>
|
||||
#include <llmr/renderer/point_bucket.hpp>
|
||||
#include <llmr/platform/platform.hpp>
|
||||
#include <llmr/util/pbf.hpp>
|
||||
#include <llmr/util/string.hpp>
|
||||
|
||||
@@ -75,7 +74,7 @@ void Tile::request() {
|
||||
|
||||
// Note: Somehow this feels slower than the change to request_http()
|
||||
std::shared_ptr<Tile> tile = shared_from_this();
|
||||
platform::request_http_tile(url, tile, [=](platform::Response& res) {
|
||||
platform::Request request = platform::request_http(url, [=](platform::Response& res) {
|
||||
if (res.code == 200 && tile->state != obsolete) {
|
||||
tile->state = Tile::loaded;
|
||||
tile->data.swap(res.body);
|
||||
@@ -86,12 +85,14 @@ void Tile::request() {
|
||||
}, []() {
|
||||
platform::restart();
|
||||
});
|
||||
req = request;
|
||||
}
|
||||
|
||||
void Tile::cancel() {
|
||||
// TODO: thread safety
|
||||
if (state != obsolete) {
|
||||
state = obsolete;
|
||||
platform::cancel_request_http(req);
|
||||
} else {
|
||||
assert((!"logic error? multiple cancelleations"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user