summaryrefslogtreecommitdiff
path: root/include/mbgl/storage
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2016-02-05 17:10:13 -0800
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-02-10 15:40:20 -0800
commitc3c4c7b9a695ad1dbebe57242ba071103fe9a567 (patch)
treee205ecdc6a2f6318c6ba6308b5aa8baacc42f481 /include/mbgl/storage
parente9302c797f68c7e48b908b87b126045c8c5e5209 (diff)
downloadqtlocation-mapboxgl-c3c4c7b9a695ad1dbebe57242ba071103fe9a567.tar.gz
[core] Interface and implementation for offline
Diffstat (limited to 'include/mbgl/storage')
-rw-r--r--include/mbgl/storage/default_file_source.hpp77
-rw-r--r--include/mbgl/storage/offline.hpp181
2 files changed, 258 insertions, 0 deletions
diff --git a/include/mbgl/storage/default_file_source.hpp b/include/mbgl/storage/default_file_source.hpp
index d8fc4b98a3..e7ffe125b1 100644
--- a/include/mbgl/storage/default_file_source.hpp
+++ b/include/mbgl/storage/default_file_source.hpp
@@ -2,6 +2,9 @@
#define MBGL_STORAGE_DEFAULT_FILE_SOURCE
#include <mbgl/storage/file_source.hpp>
+#include <mbgl/storage/offline.hpp>
+
+#include <vector>
namespace mbgl {
@@ -22,6 +25,80 @@ public:
std::unique_ptr<FileRequest> request(const Resource&, Callback) override;
+ /*
+ * Retrieve all regions in the offline database.
+ *
+ * The query will be executed asynchronously and the results passed to the given
+ * callback, which will be executed on the database thread; it is the responsibility
+ * of the SDK bindings to re-execute a user-provided callback on the main thread.
+ */
+ void listOfflineRegions(std::function<void (std::exception_ptr,
+ optional<std::vector<OfflineRegion>>)>);
+
+ /*
+ * Create an offline region in the database.
+ *
+ * When the initial database queries have completed, the provided callback will be
+ * executed on the database thread; it is the responsibility of the SDK bindings
+ * to re-execute a user-provided callback on the main thread.
+ *
+ * Note that the resulting region will be in an inactive download state; to begin
+ * downloading resources, call `setOfflineRegionDownloadState(OfflineRegionDownloadState::Active)`,
+ * optionally registering an `OfflineRegionObserver` beforehand.
+ */
+ void createOfflineRegion(const OfflineRegionDefinition& definition,
+ const OfflineRegionMetadata& metadata,
+ std::function<void (std::exception_ptr,
+ optional<OfflineRegion>)>);
+
+ /*
+ * Register an observer to be notified when the state of the region changes.
+ */
+ void setOfflineRegionObserver(OfflineRegion&, std::unique_ptr<OfflineRegionObserver>);
+
+ /*
+ * Pause or resume downloading of regional resources.
+ */
+ void setOfflineRegionDownloadState(OfflineRegion&, OfflineRegionDownloadState);
+
+ /*
+ * Retrieve the current status of the region. The query will be executed
+ * asynchronously and the results passed to the given callback, which will be
+ * executed on the database thread; it is the responsibility of the SDK bindings
+ * to re-execute a user-provided callback on the main thread.
+ */
+ void getOfflineRegionStatus(OfflineRegion&, std::function<void (std::exception_ptr,
+ optional<OfflineRegionStatus>)>) const;
+
+ /*
+ * Initiate the removal of offline region from the database.
+ *
+ * All resources required by the region, but not also required by other regions, will
+ * become eligible for removal for space-optimization. Because the offline database is
+ * also used for ambient usage-based caching, and offline resources may still be useful
+ * for ambient usage, they are not immediately removed. To immediately remove resources
+ * not used by any extant region, call removeUnusedOfflineResources().
+ *
+ * Note that this method takes ownership of the input, reflecting the fact that once
+ * region deletion is initiated, it is not legal to perform further actions with the
+ * region.
+ *
+ * When the operation is complete or encounters an error, the given callback will be
+ * executed on the database thread; it is the responsibility of the SDK bindings
+ * to re-execute a user-provided callback on the main thread.
+ */
+ void deleteOfflineRegion(OfflineRegion&&, std::function<void (std::exception_ptr)>);
+
+ /*
+ * Remove all resources in the database that are not required by any region, thus
+ * optimizing the disk space used by the offline database.
+ *
+ * When the operation is complete or encounters an error, the given callback will be
+ * executed on the database thread; it is the responsibility of the SDK bindings
+ * to re-execute a user-provided callback on the main thread.
+ */
+ void removeUnusedOfflineResources(std::function<void (std::exception_ptr)>);
+
// For testing only.
void put(const Resource&, const Response&);
void goOffline();
diff --git a/include/mbgl/storage/offline.hpp b/include/mbgl/storage/offline.hpp
new file mode 100644
index 0000000000..dd63cf968f
--- /dev/null
+++ b/include/mbgl/storage/offline.hpp
@@ -0,0 +1,181 @@
+#pragma once
+
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/style/types.hpp>
+#include <mbgl/storage/response.hpp>
+
+#include <string>
+#include <vector>
+#include <functional>
+
+namespace mbgl {
+
+class TileID;
+class SourceInfo;
+
+/*
+ * An offline region defined by a style URL, geographic bounding box, zoom range, and
+ * device pixel ratio.
+ *
+ * Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom.
+ *
+ * maxZoom may be ∞, in which case for each tile source, the region will include
+ * tiles from minZoom up to the maximum zoom level provided by that source.
+ *
+ * pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0.
+ */
+class OfflineTilePyramidRegionDefinition {
+public:
+ OfflineTilePyramidRegionDefinition(const std::string&, const LatLngBounds&, double, double, float);
+
+ /* Private */
+ std::vector<TileID> tileCover(SourceType, uint16_t tileSize, const SourceInfo&) const;
+
+ const std::string styleURL;
+ const LatLngBounds bounds;
+ const double minZoom;
+ const double maxZoom;
+ const float pixelRatio;
+};
+
+/*
+ * For the present, a tile pyramid is the only type of offline region. In the future,
+ * other definition types will be available and this will be a variant type.
+ */
+using OfflineRegionDefinition = OfflineTilePyramidRegionDefinition;
+
+/*
+ * The encoded format is private.
+ */
+std::string encodeOfflineRegionDefinition(const OfflineRegionDefinition&);
+OfflineRegionDefinition decodeOfflineRegionDefinition(const std::string&);
+
+/*
+ * Arbitrary binary region metadata. The contents are opaque to the mbgl implementation;
+ * it just stores and retrieves a BLOB. SDK bindings should leave the interpretation of
+ * this data up to the application; they _should not_ enforce a higher-level data format.
+ * In the future we want offline database to be portable across target platforms, and a
+ * platform-specific metadata format would prevent that.
+ */
+using OfflineRegionMetadata = std::vector<uint8_t>;
+
+/*
+ * A region is either inactive (not downloading, but previously-downloaded
+ * resources are available for use), or active (resources are being downloaded
+ * or will be downloaded, if necessary, when network access is available).
+ *
+ * This state is independent of whether or not the complete set of resources
+ * is currently available for offline use. To check if that is the case, use
+ * `OfflineRegionStatus::complete()`.
+ */
+enum class OfflineRegionDownloadState {
+ Inactive,
+ Active
+};
+
+/*
+ * A region's status includes its active/inactive state as well as counts
+ * of the number of resources that have completed downloading, their total
+ * size in bytes, and the total number of resources that are required.
+ *
+ * Note that the total required size in bytes is not currently available. A
+ * future API release may provide an estimate of this number.
+ */
+class OfflineRegionStatus {
+public:
+ OfflineRegionDownloadState downloadState = OfflineRegionDownloadState::Inactive;
+
+ /**
+ * The number of resources that have been fully downloaded and are ready for
+ * offline access.
+ */
+ uint64_t completedResourceCount = 0;
+
+ /**
+ * The cumulative size, in bytes, of all resources that have been fully downloaded.
+ */
+ uint64_t completedResourceSize = 0;
+
+ /**
+ * The number of resources that are known to be required for this region. See the
+ * documentation for `requiredResourceCountIsIndeterminate` for an important caveat
+ * about this number.
+ */
+ uint64_t requiredResourceCount = 0;
+
+ /**
+ * This property is true during early phases of an offline download, when the total
+ * required resource count is unknown and requiredResourceCount is merely a lower
+ * bound.
+ *
+ * Specifically, it is true before until the style and tile sources have been
+ * downloaded, and false thereafter.
+ */
+ bool requiredResourceCountIsIndeterminate = true;
+
+ bool complete() const {
+ return completedResourceCount == requiredResourceCount;
+ }
+};
+
+/*
+ * A region can have a single observer, which gets notified whenever a change
+ * to the region's status occurs.
+ */
+class OfflineRegionObserver {
+public:
+ virtual ~OfflineRegionObserver() = default;
+
+ /*
+ * Implement this method to be notified of a change in the status of an
+ * offline region. Status changes include any change in state of the members
+ * of OfflineRegionStatus.
+ *
+ * Note that this method will be executed on the database thread; it is the
+ * responsibility of the SDK bindings to wrap this object in an interface that
+ * re-executes the user-provided implementation on the main thread.
+ */
+ virtual void statusChanged(OfflineRegionStatus) {}
+
+ /*
+ * Implement this method to be notified of errors encountered while downloading
+ * regional resources. Such errors may be recoverable; for example the implementation
+ * will attempt to re-request failed resources based on an exponential backoff
+ * algorithm, or when it detects that network access has been restored.
+ *
+ * Note that this method will be executed on the database thread; it is the
+ * responsibility of the SDK bindings to wrap this object in an interface that
+ * re-executes the user-provided implementation on the main thread.
+ */
+ virtual void responseError(Response::Error) {}
+};
+
+class OfflineRegion {
+public:
+ // Move-only; not publicly constructible.
+ OfflineRegion(OfflineRegion&&);
+ OfflineRegion& operator=(OfflineRegion&&);
+ ~OfflineRegion();
+
+ OfflineRegion() = delete;
+ OfflineRegion(const OfflineRegion&) = delete;
+ OfflineRegion& operator=(const OfflineRegion&) = delete;
+
+ int64_t getID() const;
+ const OfflineRegionDefinition& getDefinition() const;
+ const OfflineRegionMetadata& getMetadata() const;
+
+private:
+ friend class OfflineDatabase;
+
+ OfflineRegion(int64_t id,
+ const OfflineRegionDefinition&,
+ const OfflineRegionMetadata&);
+
+ const int64_t id;
+ const OfflineRegionDefinition definition;
+ const OfflineRegionMetadata metadata;
+};
+
+} // namespace mbgl