Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[core] [WIP] Interface and implementation for offline
Browse files Browse the repository at this point in the history
  • Loading branch information
jfirebaugh committed Feb 5, 2016
1 parent 4445778 commit 36c4452
Show file tree
Hide file tree
Showing 23 changed files with 1,328 additions and 2 deletions.
5 changes: 5 additions & 0 deletions gyp/platform-android.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@
'../platform/default/timer.cpp',
'../platform/default/default_file_source.cpp',
'../platform/default/online_file_source.cpp',
'../platform/default/mbgl/storage/offline.hpp',
'../platform/default/mbgl/storage/offline.cpp',
'../platform/default/mbgl/storage/offline_database.hpp',
'../platform/default/mbgl/storage/offline_database.cpp',
'../platform/default/mbgl/storage/offline_download.hpp',
'../platform/default/mbgl/storage/offline_download.cpp',
'../platform/default/sqlite3.hpp',
'../platform/default/sqlite3.cpp',
],
Expand All @@ -35,6 +39,7 @@
'<@(nunicode_cflags)',
'<@(boost_cflags)',
'<@(sqlite_cflags)',
'<@(rapidjson_cflags)',
],
'ldflags': [
'<@(libpng_ldflags)',
Expand Down
5 changes: 5 additions & 0 deletions gyp/platform-ios.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@
'../platform/default/timer.cpp',
'../platform/default/default_file_source.cpp',
'../platform/default/online_file_source.cpp',
'../platform/default/mbgl/storage/offline.hpp',
'../platform/default/mbgl/storage/offline.cpp',
'../platform/default/mbgl/storage/offline_database.hpp',
'../platform/default/mbgl/storage/offline_database.cpp',
'../platform/default/mbgl/storage/offline_download.hpp',
'../platform/default/mbgl/storage/offline_download.cpp',
'../platform/default/sqlite3.hpp',
'../platform/default/sqlite3.cpp',
'../platform/darwin/log_nslog.mm',
Expand Down Expand Up @@ -72,6 +76,7 @@
'<@(boost_cflags)',
'<@(sqlite_cflags)',
'<@(zlib_cflags)',
'<@(rapidjson_cflags)',
],
'ldflags': [
'<@(sqlite_ldflags)',
Expand Down
5 changes: 5 additions & 0 deletions gyp/platform-linux.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
'../platform/default/timer.cpp',
'../platform/default/default_file_source.cpp',
'../platform/default/online_file_source.cpp',
'../platform/default/mbgl/storage/offline.hpp',
'../platform/default/mbgl/storage/offline.cpp',
'../platform/default/mbgl/storage/offline_database.hpp',
'../platform/default/mbgl/storage/offline_database.cpp',
'../platform/default/mbgl/storage/offline_download.hpp',
'../platform/default/mbgl/storage/offline_download.cpp',
'../platform/default/sqlite3.hpp',
'../platform/default/sqlite3.cpp',
],
Expand All @@ -38,6 +42,7 @@
'<@(boost_cflags)',
'<@(sqlite_cflags)',
'<@(webp_cflags)',
'<@(rapidjson_cflags)',
],
'ldflags': [
'<@(libpng_ldflags)',
Expand Down
5 changes: 5 additions & 0 deletions gyp/platform-osx.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
'../platform/default/timer.cpp',
'../platform/default/default_file_source.cpp',
'../platform/default/online_file_source.cpp',
'../platform/default/mbgl/storage/offline.hpp',
'../platform/default/mbgl/storage/offline.cpp',
'../platform/default/mbgl/storage/offline_database.hpp',
'../platform/default/mbgl/storage/offline_database.cpp',
'../platform/default/mbgl/storage/offline_download.hpp',
'../platform/default/mbgl/storage/offline_download.cpp',
'../platform/default/sqlite3.hpp',
'../platform/default/sqlite3.cpp',
'../platform/darwin/log_nslog.mm',
Expand Down Expand Up @@ -63,6 +67,7 @@
'<@(boost_cflags)',
'<@(sqlite_cflags)',
'<@(zlib_cflags)',
'<@(rapidjson_cflags)',
],
'ldflags': [
'<@(zlib_ldflags)',
Expand Down
65 changes: 65 additions & 0 deletions include/mbgl/storage/default_file_source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -22,6 +25,68 @@ class DefaultFileSource : public FileSource {

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 be deleted.
*
* If an observer is registered for the region, it will receive status notifications
* as the deletion progresses.
*
* 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)>);

// For testing only.
void put(const Resource&, const Response&);
void goOffline();
Expand Down
173 changes: 173 additions & 0 deletions include/mbgl/storage/offline.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
#pragma once

#include <mbgl/util/geo.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/style/types.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. Note
* that during early phases of the download, this number is merely a _lower bound_
* and does not necessarily reflect the complete number of required resources.
* This is due to the fact that certain resources must themselves be downloaded
* before the total number can be calculated. For example, the style must be
* downloaded before any other resources can be determined.
*/
uint64_t requiredResourceCount = 0;

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 error(std::exception_ptr) {};
};

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
Loading

0 comments on commit 36c4452

Please sign in to comment.