/**
|
* Cesium - https://github.com/CesiumGS/cesium
|
*
|
* Copyright 2011-2020 Cesium Contributors
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*
|
* Columbus View (Pat. Pend.)
|
*
|
* Portions licensed separately.
|
* See https://github.com/CesiumGS/cesium/blob/master/LICENSE.md for full licensing details.
|
*/
|
define(['./when-8d13db60', './createTaskProcessorWorker'], function (when, createTaskProcessorWorker) { 'use strict';
|
|
/**
|
* @exports defined
|
*
|
* @param {*} value The object.
|
* @returns {Boolean} Returns true if the object is defined, returns false otherwise.
|
*
|
* @example
|
* if (Cesium.defined(positions)) {
|
* doSomething();
|
* } else {
|
* doSomethingElse();
|
* }
|
*/
|
function defined(value) {
|
return value !== undefined && value !== null;
|
}
|
|
/**
|
* Constructs an exception object that is thrown due to a developer error, e.g., invalid argument,
|
* argument out of range, etc. This exception should only be thrown during development;
|
* it usually indicates a bug in the calling code. This exception should never be
|
* caught; instead the calling code should strive not to generate it.
|
* <br /><br />
|
* On the other hand, a {@link RuntimeError} indicates an exception that may
|
* be thrown at runtime, e.g., out of memory, that the calling code should be prepared
|
* to catch.
|
*
|
* @alias DeveloperError
|
* @constructor
|
* @extends Error
|
*
|
* @param {String} [message] The error message for this exception.
|
*
|
* @see RuntimeError
|
*/
|
function DeveloperError(message) {
|
/**
|
* 'DeveloperError' indicating that this exception was thrown due to a developer error.
|
* @type {String}
|
* @readonly
|
*/
|
this.name = 'DeveloperError';
|
|
/**
|
* The explanation for why this exception was thrown.
|
* @type {String}
|
* @readonly
|
*/
|
this.message = message;
|
|
//Browsers such as IE don't have a stack property until you actually throw the error.
|
var stack;
|
try {
|
throw new Error();
|
} catch (e) {
|
stack = e.stack;
|
}
|
|
/**
|
* The stack trace of this exception, if available.
|
* @type {String}
|
* @readonly
|
*/
|
this.stack = stack;
|
}
|
|
if (defined(Object.create)) {
|
DeveloperError.prototype = Object.create(Error.prototype);
|
DeveloperError.prototype.constructor = DeveloperError;
|
}
|
|
DeveloperError.prototype.toString = function() {
|
var str = this.name + ': ' + this.message;
|
|
if (defined(this.stack)) {
|
str += '\n' + this.stack.toString();
|
}
|
|
return str;
|
};
|
|
/**
|
* @private
|
*/
|
DeveloperError.throwInstantiationError = function() {
|
throw new DeveloperError('This function defines an interface and should not be called directly.');
|
};
|
|
var DataStatus = {
|
NONE : 0,
|
STORING : 1,
|
STORED : 2,
|
FAILED : 3
|
};
|
|
function IndexedDBScheduler(options) {
|
if(!defined(options.name)){
|
throw new DeveloperError('options.name is required.');
|
}
|
var defer = when.when.defer();
|
this.dbname = options.name;
|
var request = indexedDB.open(this.dbname);
|
|
var that = this;
|
request.onsuccess = function (event) {
|
that.db = event.target.result;
|
that.version = that.db.version;
|
|
if (!defined(that.cachestatus)) {
|
that.cachestatus = {
|
|
};
|
}
|
defer.resolve(that);
|
};
|
|
request.onupgradeneeded = function (event) {
|
that.db = event.target.result;
|
that.version = that.db.version;
|
defer.resolve(that);
|
};
|
|
request.onerror = function (event) {
|
that.db = null;
|
defer.reject('create database fail, error code : ' + event.target.errorcode);
|
};
|
|
this.layer = options.layer || null;
|
this.storageType = options.storageType || "arrayBuffer";
|
this.creatingTable = false;
|
this.cachestatus = {};
|
return defer.promise;
|
}
|
|
IndexedDBScheduler.prototype.checkObjectStoreExit = function(storeName) {
|
if (!defined(this.db)) {
|
return false;
|
}
|
|
return this.db.objectStoreNames.contains(storeName);
|
};
|
|
IndexedDBScheduler.prototype.createObjectStore = function(storeName) {
|
var defer = when.when.defer();
|
|
//防止多个请求同时创建同一张表
|
if (!this.creatingTable) {
|
if (this.db.objectStoreNames.contains(storeName)) {
|
defer.reject(false);
|
return defer.promise;
|
}
|
this.creatingTable = true;
|
|
var that = this;
|
|
//只能在onupgradeneeded方法中创建新表,所以需要用更高版本打开数据库触发更新
|
var version = parseInt(that.db.version);
|
that.db.close();
|
var secondRequest = indexedDB.open(that.dbname, version + 1);
|
secondRequest.onupgradeneeded = function(e) {
|
var database = e.target.result;
|
that.db = database;
|
var objectStore = database.createObjectStore(storeName, { keyPath : 'id'});
|
if (defined(objectStore)) {
|
objectStore.createIndex('value', 'value', { unique : false});
|
that.creatingTable = false;
|
//初始化表的缓存状态
|
if (!defined(that.cachestatus)) {
|
that.cachestatus = {};
|
}
|
|
that.cachestatus[storeName] = {
|
|
};
|
|
//这边创建成功表后直接使用会出现各种奇怪的问题,索性关闭数据库后再打开
|
that.db.close();
|
var thirdRequest = indexedDB.open(that.dbname);
|
|
thirdRequest.onsuccess = function(e) {
|
var database = e.target.result;
|
that.db = database;
|
defer.resolve(true);
|
};
|
} else {
|
that.creatingTable = false;
|
defer.reject(false);
|
}
|
};
|
|
secondRequest.onsuccess = function(e) {
|
e.target.result.close();
|
defer.resolve(true);
|
};
|
|
secondRequest.onerror = function(e) {
|
that.creatingTable = false;
|
defer.reject(false);
|
};
|
} else {
|
defer.reject(false);
|
}
|
|
return defer.promise;
|
};
|
|
IndexedDBScheduler.prototype.putElementInDB = function (table, key, data, objectArray) {
|
var defer = when.when.defer();
|
|
if (!defined(this.db)) {
|
defer.reject(false);
|
return defer.promise;
|
}
|
|
var objectStore;
|
var that = this;
|
|
//先检查缓存,如果已经写了就不去写了
|
if (defined(that.cachestatus[table]) && !defined(objectArray)) {
|
if (defined(that.cachestatus[table][key])) {
|
if (that.cachestatus[table][key] === DataStatus.STORING || that.cachestatus[table][key] === DataStatus.STORED) {
|
defer.resolve(false);
|
return defer.promise;
|
}
|
}
|
}
|
|
//没有表,去创建指定名称的表
|
if (!this.db.objectStoreNames.contains(table)) {
|
this.createObjectStore(table).then(function(success) {
|
var transaction = that.db.transaction([table], "readwrite");
|
objectStore = transaction.objectStore(table);
|
|
if (defined(objectArray)) {
|
for (var i = 0, len = objectArray.length; i < len; i++) {
|
objectStore.add({ id : objectArray[i].key, value : objectArray[i].value});
|
}
|
|
defer.resolve(true);
|
} else {
|
var request = objectStore.add({ id : key, value : data});
|
request.onsuccess = function (event) {
|
defer.resolve(true);
|
};
|
|
request.onerror = function (event) {
|
defer.reject(false);
|
};
|
}
|
}, function(error) {
|
defer.reject(false);
|
});
|
} else {
|
if (!defined(that.cachestatus[table])) {
|
that.cachestatus[table] = {
|
|
};
|
}
|
|
//打开表并添加对应数据
|
var transaction;
|
try {
|
transaction = this.db.transaction([table], "readwrite");
|
} catch (e) {
|
defer.reject(null);
|
return defer.promise;
|
}
|
|
objectStore = transaction.objectStore(table);
|
|
if (defined(objectArray)) {
|
if (objectArray instanceof Array) {
|
for (var i = 0, len = objectArray.length; i < len; i++) {
|
if (that.cachestatus[table][objectArray[i].key] !== DataStatus.STORED) {
|
objectStore.add({ id : objectArray[i].key, value : objectArray[i].value});
|
that.cachestatus[table][objectArray[i].key] = DataStatus.STORED;
|
}
|
}
|
defer.resolve(true);
|
} else {
|
for (var key in objectArray) {
|
if (isNaN(key * 1)) {
|
continue;
|
}
|
objectStore.add({ id : key, value : objectArray[key]});
|
}
|
defer.resolve(true);
|
}
|
|
} else if (key.length > 0 && data.length > 0) {
|
for (var i = 0, len = key.length; i < len; i++) {
|
if (that.cachestatus[table][key[i]] !== DataStatus.STORED) {
|
objectStore.add({ id : key[i], value : data[i]});
|
that.cachestatus[table][key[i]] = DataStatus.STORED;
|
}
|
}
|
|
transaction.oncomplete = function(e) {
|
defer.resolve(true);
|
};
|
|
transaction.onerror = function(e) {
|
defer.reject(false);
|
};
|
} else {
|
var request = objectStore.add({ id : key, value : data});
|
that.cachestatus[table][key] = DataStatus.STORING;
|
request.onsuccess = function (event) {
|
that.cachestatus[table][key] = DataStatus.STORED;
|
defer.resolve(true);
|
};
|
|
request.onerror = function (event) {
|
that.cachestatus[table][key] = DataStatus.FAILED;
|
defer.reject(false);
|
};
|
}
|
}
|
|
return defer.promise;
|
};
|
|
IndexedDBScheduler.prototype.getRangeFromDB = function(table, idRange) {
|
var defer = when.when.defer();
|
|
if (!defined(this.db)) {
|
return null;
|
}
|
|
if (!this.db.objectStoreNames.contains(table)) {
|
return null;
|
}
|
|
var transaction;
|
try {
|
transaction = this.db.transaction([table]);
|
} catch (e) {
|
defer.reject(null);
|
return defer.promise;
|
}
|
|
var objectStore;
|
try {
|
objectStore = transaction.objectStore(table);
|
} catch (e) {
|
defer.reject(null);
|
}
|
|
var request = objectStore.openCursor(IDBKeyRange.bound(idRange[0], idRange[1]));
|
|
var rs = [];
|
request.onsuccess = function(event) {
|
var cursor = event.target.result;
|
if (!defined(cursor)) {
|
defer.resolve(rs);
|
} else {
|
rs.push(cursor.value);
|
cursor.continue();
|
}
|
};
|
|
request.onerror = function(event) {
|
defer.reject(null);
|
};
|
|
return defer.promise;
|
};
|
|
IndexedDBScheduler.prototype.getElementFromDB = function (table, key) {
|
var defer = when.when.defer();
|
|
if (!defined(this.db)) {
|
return null;
|
}
|
|
if (!this.db.objectStoreNames.contains(table)) {
|
return null;
|
}
|
|
var transaction;
|
try {
|
transaction = this.db.transaction([table]);
|
} catch (e) {
|
defer.reject(null);
|
return defer.promise;
|
}
|
|
var objectStore;
|
try {
|
objectStore = transaction.objectStore(table);
|
} catch (e) {
|
defer.reject(null);
|
}
|
|
var request = objectStore.get(key);
|
|
request.onsuccess = function(event) {
|
if (!defined(event.target.result)) {
|
defer.reject(null);
|
return;
|
}
|
|
defer.resolve(event.target.result.value);
|
};
|
|
request.onerror = function(event) {
|
defer.reject(null);
|
};
|
|
return defer.promise;
|
};
|
|
IndexedDBScheduler.prototype.getAllElementFromDB = function (table) {
|
var defer = when.when.defer();
|
|
if (!defined(this.db)) {
|
return null;
|
}
|
|
if (!this.db.objectStoreNames.contains(table)) {
|
return null;
|
}
|
|
var transaction;
|
if (this.transaction != null) {
|
transaction = this.transaction;
|
} else {
|
try {
|
transaction = this.db.transaction([table]);
|
} catch (e) {
|
defer.reject(null);
|
return defer.promise;
|
}
|
}
|
|
|
var objectStore;
|
try {
|
objectStore = transaction.objectStore(table);
|
} catch (e) {
|
defer.reject(null);
|
}
|
|
var request = objectStore.getAll();
|
|
request.onsuccess = function(event) {
|
if (!defined(event.target.result)) {
|
defer.reject(null);
|
return;
|
}
|
|
defer.resolve(event.target.result);
|
};
|
|
request.onerror = function(event) {
|
defer.reject(null);
|
};
|
|
return defer.promise;
|
};
|
|
IndexedDBScheduler.prototype.updateElementInDB = function (table, key, value, append) {
|
var defer = when.when.defer();
|
|
if (!defined(this.db)) {
|
defer.resolve(false);
|
return defer.promise;
|
}
|
|
if (!this.db.objectStoreNames.contains(table)) {
|
defer.resolve(false);
|
return defer.promise;
|
}
|
|
var transaction = this.db.transaction([table], "readwrite");
|
var objectStore;
|
try {
|
objectStore = transaction.objectStore(table);
|
} catch (e) {
|
defer.resolve(false);
|
}
|
|
var request = objectStore.get(key);
|
|
request.onsuccess = function(event) {
|
var data = event.target.result;
|
if (!defined(data)) {
|
data = {
|
id : key
|
};
|
}
|
|
if (append === true) {
|
data.value = Object.assign(data.value, value);
|
} else {
|
data.value = value;
|
}
|
|
|
var requestUpdate = objectStore.put(data);
|
requestUpdate.onsuccess = function(event) {
|
defer.resolve(true);
|
};
|
|
requestUpdate.onerror = function(event) {
|
defer.resolve(false);
|
};
|
};
|
|
request.onerror = function(event) {
|
defer.resolve(false);
|
};
|
|
return defer.promise;
|
};
|
|
IndexedDBScheduler.prototype.removeElementFromDB = function (table, key) {
|
var defer = when.when.defer();
|
|
if (!defined(this.db)) {
|
defer.resolve(false);
|
return defer.promise;
|
}
|
|
if (!this.db.objectStoreNames.contains(table)) {
|
defer.resolve(false);
|
return defer.promise;
|
}
|
|
var transaction = this.db.transaction([table], "readwrite");
|
var objectStore;
|
try {
|
objectStore = transaction.objectStore(table);
|
} catch (e) {
|
defer.resolve(false);
|
}
|
|
var request = objectStore.delete(key);
|
|
request.onerror = function(event) {
|
defer.resolve(false);
|
};
|
|
request.onsuccess = function(event) {
|
defer.resolve(true);
|
};
|
|
return defer.promise;
|
};
|
|
IndexedDBScheduler.prototype.clear = function(table) {
|
var defer = when.when.defer();
|
|
if (!defined(this.db)) {
|
defer.resolve(false);
|
return defer.promise;
|
}
|
|
if (!this.db.objectStoreNames.contains(table)) {
|
defer.resolve(false);
|
return defer.promise;
|
}
|
|
var transaction = this.db.transaction([table], "readwrite");
|
var objectStore;
|
try {
|
objectStore = transaction.objectStore(table);
|
} catch (e) {
|
defer.resolve(false);
|
}
|
|
var request = objectStore.clear();
|
|
request.onerror = function(event) {
|
defer.resolve(false);
|
};
|
|
request.onsuccess = function(event) {
|
defer.resolve(true);
|
};
|
|
return defer.promise;
|
};
|
|
var cache = {};
|
|
function indexedDBWorker(parameters, transferableObjects) {
|
var blob = parameters.blob;
|
var key = parameters.key;
|
var tablename = parameters.tablename;
|
var dbname = parameters.dbname;
|
var cacheSize = parameters.cacheSize || 100;
|
|
var cahceKey = dbname + tablename;
|
if (typeof cache[cahceKey] === "undefined") {
|
cache[cahceKey] = {
|
cache: [],
|
creatingDB: false,
|
scheduler: null,
|
creatingTable: false
|
};
|
} else {
|
cache[cahceKey].cache.push({
|
key: key,
|
value: blob
|
});
|
}
|
|
|
if (cache[cahceKey].cache.length > cacheSize) {
|
putElementInDB(dbname, tablename, cache[cahceKey]);
|
}
|
}
|
|
function putElementInDB(dbname, tablename, cache) {
|
if (cache.scheduler === null) {
|
if (!cache.creatingDB) {
|
cache.creatingDB = true;
|
new IndexedDBScheduler({ name: dbname }).then(function (result) {
|
cache.creatingDB = false;
|
cache.scheduler = result;
|
if (!result.checkObjectStoreExit(tablename)) {
|
if (!cache.creatingTable) {
|
cache.creatingTable = true;
|
result.createObjectStore(tablename).then(function () {
|
cache.creatingTable = false;
|
result.putElementInDB(tablename, null, null, cache.cache);
|
cache.cache = [];
|
});
|
}
|
} else {
|
result.putElementInDB(tablename, null, null, cache.cache);
|
cache.cache = [];
|
}
|
});
|
}
|
|
} else {
|
if (!cache.scheduler.checkObjectStoreExit(tablename)) {
|
if (!cache.creatingTable) {
|
cache.creatingTable = true;
|
cache.scheduler.createObjectStore(tablename).then(function () {
|
cache.creatingTable = false;
|
cache.scheduler.putElementInDB(tablename, null, null, cache.cache);
|
cache.cache = [];
|
});
|
}
|
} else {
|
cache.scheduler.putElementInDB(tablename, null, null, cache.cache);
|
cache.cache = [];
|
}
|
}
|
|
}
|
|
var indexedDBWorker$1 = createTaskProcessorWorker(indexedDBWorker);
|
|
return indexedDBWorker$1;
|
|
});
|