allow for cancellable request, track in tiles, and cancel when obsolete

This commit is contained in:
Justin R. Miller
2014-02-25 16:33:06 -08:00
parent 0406a82299
commit 55b28aaf65
5 changed files with 45 additions and 90 deletions

View File

@@ -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;
};
}

View File

@@ -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();

View File

@@ -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()

View File

@@ -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() {

View File

@@ -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"));
}