diff --git a/include/llmr/map/tile.hpp b/include/llmr/map/tile.hpp index 74bc1d472..d738c99bb 100644 --- a/include/llmr/map/tile.hpp +++ b/include/llmr/map/tile.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -93,8 +94,8 @@ public: private: // Source data std::string data; - const Style& style; + platform::Request req; }; } diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp index 18936a4b1..3dfbc0166 100644 --- a/include/llmr/platform/platform.hpp +++ b/include/llmr/platform/platform.hpp @@ -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 background_function, std::function 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 background_function, std::function 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 background_function, std::function 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(); diff --git a/ios/MBXViewController.mm b/ios/MBXViewController.mm index 11446f01f..26f9adf6c 100644 --- a/ios/MBXViewController.mm +++ b/ios/MBXViewController.mm @@ -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 background_function, std::function foreground_callback) + Request request_http(std::string url, std::function background_function, std::function 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 background_function, std::function 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() diff --git a/macosx/main.mm b/macosx/main.mm index 1a37419c5..dc65b7560 100644 --- a/macosx/main.mm +++ b/macosx/main.mm @@ -240,7 +240,7 @@ void restart() { [[NSApplication sharedApplication] postEvent: [NSEvent eventWithCGEvent:event] atStart:NO]; } -void request_http(std::string url, std::function background_function, std::function foreground_callback) +Request request_http(std::string url, std::function background_function, std::function 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 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 background_function, std::function 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() { diff --git a/src/map/tile.cpp b/src/map/tile.cpp index d0fd329d2..67d648f8c 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -75,7 +74,7 @@ void Tile::request() { // Note: Somehow this feels slower than the change to request_http() std::shared_ptr 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")); }