summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2014-08-22 18:50:09 +0200
committerKonstantin Käfer <mail@kkaefer.com>2014-09-24 16:12:02 +0200
commit34fe7dc627f08d57ac259c383e248ddf2f6fb0d3 (patch)
treedddbde6891826329f92922409fbed6964d5e4e7e /src/util
parentee3e0827a20492ba0f91c5c5f60cf24b2e49cb32 (diff)
downloadqtlocation-mapboxgl-34fe7dc627f08d57ac259c383e248ddf2f6fb0d3.tar.gz
add basic request caching with sqlite
Diffstat (limited to 'src/util')
-rw-r--r--src/util/filesource.cpp143
1 files changed, 141 insertions, 2 deletions
diff --git a/src/util/filesource.cpp b/src/util/filesource.cpp
index 503d4dfb1d..3f52a09119 100644
--- a/src/util/filesource.cpp
+++ b/src/util/filesource.cpp
@@ -1,13 +1,46 @@
#include <mbgl/util/filesource.hpp>
#include <mbgl/platform/platform.hpp>
+#include <mbgl/platform/log.hpp>
+
+#include <sqlite3.h>
#include <fstream>
#include <sstream>
namespace mbgl {
-FileSource::FileSource() {}
+FileSource::FileSource() {
+ const int err = sqlite3_open_v2("cache.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr);
+ if (err != SQLITE_OK) {
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ db = nullptr;
+ }
+
+ createSchema();
+}
+
+FileSource::~FileSource() {
+ closeDatabase();
+}
+
+void FileSource::createSchema() {
+ if (db) {
+ // Create schema
+ const int err = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS `http_cache` (`url` TEXT PRIMARY KEY, `expires` INTEGER, `data` BLOB)", nullptr, nullptr, nullptr);
+ if (err != SQLITE_OK) {
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ closeDatabase();
+ }
+ }
+}
+void FileSource::closeDatabase() {
+ if (db) {
+ const int err = sqlite3_close_v2(db);
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ db = nullptr;
+ }
+}
void FileSource::setBase(const std::string &value) {
base = value;
@@ -17,6 +50,104 @@ const std::string &FileSource::getBase() const {
return base;
}
+bool FileSource::loadFile(const std::string &url, std::function<void(platform::Response *)> callback) {
+ if (!db) {
+ return false;
+ }
+
+ sqlite3_stmt *stmt = nullptr;
+ int err;
+
+ err = sqlite3_prepare_v2(db, "SELECT `data` FROM `http_cache` WHERE `url` = ?", -1, &stmt, nullptr);
+ if (err != SQLITE_OK) {
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ return false;
+ }
+
+ err = sqlite3_bind_text(stmt, 1, url.data(), url.size(), nullptr);
+ if (err != SQLITE_OK) {
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ err = sqlite3_finalize(stmt);
+ if (err != SQLITE_OK) {
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ }
+ return false;
+ }
+
+ bool status = false;
+
+ err = sqlite3_step(stmt);
+ if (err == SQLITE_ROW) {
+ // There is data.
+ platform::Response res(callback);
+ res.code = 200;
+ const char *data = reinterpret_cast<const char *>(sqlite3_column_blob(stmt, 0));
+ const size_t size = sqlite3_column_bytes(stmt, 0);
+ res.body = { data, size };
+ callback(&res);
+ status = true;
+ } else if (err == SQLITE_DONE) {
+ // There is no data.
+ // This is a noop.
+ } else {
+ // Another error occured.
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ }
+
+ err = sqlite3_finalize(stmt);
+ if (err != SQLITE_OK) {
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ }
+ return status;
+}
+
+void FileSource::saveFile(const std::string &url, platform::Response *const res) {
+ if (!db) {
+ return;
+ }
+
+ sqlite3_stmt *stmt = nullptr;
+ int err;
+
+ err = sqlite3_prepare_v2(db, "REPLACE INTO `http_cache` (`url`, `data`) VALUES(?, ?)", -1, &stmt, nullptr);
+ if (err != SQLITE_OK) {
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ return;
+ }
+
+ err = sqlite3_bind_text(stmt, 1, url.data(), url.size(), nullptr);
+ if (err != SQLITE_OK) {
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ err = sqlite3_finalize(stmt);
+ if (err != SQLITE_OK) {
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ }
+ return;
+ }
+
+ err = sqlite3_bind_blob(stmt, 2, res->body.data(), res->body.size(), nullptr);
+ if (err != SQLITE_OK) {
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ err = sqlite3_finalize(stmt);
+ if (err != SQLITE_OK) {
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ }
+ return;
+ }
+
+ err = sqlite3_step(stmt);
+ if (err != SQLITE_DONE) {
+ // Another error occured.
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ }
+
+ err = sqlite3_finalize(stmt);
+ if (err != SQLITE_OK) {
+ Log::Warning(Event::Database, "%s: %s", sqlite3_errstr(err), sqlite3_errmsg(db));
+ }
+}
+
+
void FileSource::load(ResourceType /*type*/, const std::string &url, std::function<void(platform::Response *)> callback, const std::shared_ptr<uv::loop> loop) {
// convert relative URLs to absolute URLs
@@ -51,7 +182,15 @@ void FileSource::load(ResourceType /*type*/, const std::string &url, std::functi
callback(&response);
} else {
// load from the internet
- platform::request_http(absoluteURL, callback, loop);
+ if (!loadFile(absoluteURL, callback)) {
+ const std::shared_ptr<FileSource> source = shared_from_this();
+ platform::request_http(absoluteURL, [=](platform::Response *res) {
+ if (res->code == 200) {
+ source->saveFile(absoluteURL, res);
+ }
+ callback(res);
+ }, loop);
+ }
}
}