summaryrefslogtreecommitdiff
path: root/src/platform/request.cpp
blob: 9382892a91bc041cb13338113d14fe98f23e2fb9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <mbgl/platform/request.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/uv.hpp>

using namespace mbgl::platform;

Request::Request(const std::string &url,
                 std::function<void(Response *)> callback,
                 std::shared_ptr<uv::loop> loop)
    : url(url),
      res(std::make_unique<Response>(callback)),
      cancelled(false),
      loop(loop) {
    if (loop) {
        // Add a check handle without a callback to keep the default loop running.
        // We don't have a real handler attached to the default loop right from the
        // beginning, because we're using asynchronous messaging to perform the actual
        // request in the request thread. Only after the request is complete, we
        // create an actual work request that is attached to the default loop.
        async = new uv_async_t();
        async->data = new std::unique_ptr<Response>();
        uv_async_init(**loop, async, complete);
    }
}

Request::~Request() {
}

void Request::complete() {
    if (loop) {
        // We're scheduling the response callback to be invoked in the event loop.
        // Since the Request object will be deleted before the callback is invoked,
        // we move over the Response object to be owned by the async handle.
        ((std::unique_ptr<Response> *)async->data)->swap(res);
        uv_async_send(async);
    } else {
        // We're calling the response callback immediately. We're currently on an
        // arbitrary thread, but that's okay.
        res->callback(res.get());
    }
}

void Request::complete(uv_async_t *async) {
    Response *res = static_cast<std::unique_ptr<Response> *>(async->data)->get();

    res->callback(res);

    // We need to remove our async handle again to allow the main event loop to exit.
    uv_close((uv_handle_t *)async, [](uv_handle_t *handle) {
        delete static_cast<std::unique_ptr<Response> *>(handle->data);
        delete (uv_async_t *)handle;
    });
}