mirror of
https://github.com/nasa/openmct.git
synced 2025-06-26 03:00:13 +00:00
Compare commits
6 Commits
stackplots
...
pouchdb-pr
Author | SHA1 | Date | |
---|---|---|---|
2301d43b45 | |||
50016db052 | |||
629ec8950b | |||
bca4eaf9c2 | |||
15ddd43cf0 | |||
0c90b46d6e |
@ -81,7 +81,8 @@
|
|||||||
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
|
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
|
||||||
);
|
);
|
||||||
|
|
||||||
openmct.install(openmct.plugins.LocalStorage());
|
// openmct.install(openmct.plugins.LocalStorage());
|
||||||
|
openmct.install(openmct.plugins.PouchDB());
|
||||||
openmct.install(openmct.plugins.Espresso());
|
openmct.install(openmct.plugins.Espresso());
|
||||||
openmct.install(openmct.plugins.MyItems());
|
openmct.install(openmct.plugins.MyItems());
|
||||||
openmct.install(openmct.plugins.Generator());
|
openmct.install(openmct.plugins.Generator());
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
"node-sass": "^4.14.1",
|
"node-sass": "^4.14.1",
|
||||||
"painterro": "^1.0.35",
|
"painterro": "^1.0.35",
|
||||||
"printj": "^1.2.1",
|
"printj": "^1.2.1",
|
||||||
|
"pouchdb": "^7.2.2",
|
||||||
"raw-loader": "^0.5.1",
|
"raw-loader": "^0.5.1",
|
||||||
"request": "^2.69.0",
|
"request": "^2.69.0",
|
||||||
"split": "^1.0.0",
|
"split": "^1.0.0",
|
||||||
|
222
src/plugins/persistence/pouchdb/PouchObjectProvider.js
Normal file
222
src/plugins/persistence/pouchdb/PouchObjectProvider.js
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is 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.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import CouchDocument from "../couch/CouchDocument";
|
||||||
|
import CouchObjectQueue from "../couch/CouchObjectQueue";
|
||||||
|
import PouchDB from 'pouchdb';
|
||||||
|
|
||||||
|
const REV = "_rev";
|
||||||
|
const ID = "_id";
|
||||||
|
const HEARTBEAT = 50000;
|
||||||
|
|
||||||
|
export default class CouchObjectProvider {
|
||||||
|
// options {
|
||||||
|
// url: couchdb url,
|
||||||
|
// disableObserve: disable auto feed from couchdb to keep objects in sync,
|
||||||
|
// filter: selector to find objects to sync in couchdb
|
||||||
|
// }
|
||||||
|
constructor(openmct, options, namespace) {
|
||||||
|
options = this._normalize(options);
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.url = options.url;
|
||||||
|
this.remoteCouch = options.remoteCouch;
|
||||||
|
this.namespace = namespace;
|
||||||
|
this.objectQueue = {};
|
||||||
|
this.observers = {};
|
||||||
|
|
||||||
|
this.pouchdb = new PouchDB(options.name);
|
||||||
|
this.observeChanges();
|
||||||
|
|
||||||
|
let replicateOptions = {live: true};
|
||||||
|
this.pouchdb.replicate.to(this.remoteCouch, replicateOptions, this.logError);
|
||||||
|
this.pouchdb.replicate.from(this.remoteCouch, replicateOptions, this.logError);
|
||||||
|
}
|
||||||
|
|
||||||
|
//backwards compatibility, options used to be a url. Now it's an object
|
||||||
|
_normalize(options) {
|
||||||
|
if (typeof options === 'string') {
|
||||||
|
return {
|
||||||
|
url: options
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
observeChanges() {
|
||||||
|
this.pouchdb.changes({
|
||||||
|
since: 'now',
|
||||||
|
live: true
|
||||||
|
}).on('change', this.updateObject.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
observe(identifier, callback) {
|
||||||
|
const keyString = this.openmct.objects.makeKeyString(identifier);
|
||||||
|
this.observers[keyString] = this.observers[keyString] || [];
|
||||||
|
this.observers[keyString].push(callback);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
this.observers[keyString] = this.observers[keyString].filter(observer => observer !== callback);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
logError(error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateObject(response) {
|
||||||
|
const object = {};
|
||||||
|
object.identifier = {
|
||||||
|
namespace: this.namespace,
|
||||||
|
key: response.id
|
||||||
|
};
|
||||||
|
let keyString = this.openmct.objects.makeKeyString(object.identifier);
|
||||||
|
let observersForObject = this.observers[keyString];
|
||||||
|
|
||||||
|
if (observersForObject) {
|
||||||
|
observersForObject.forEach(async (observer) => {
|
||||||
|
const updatedObject = await this.get(object.identifier);
|
||||||
|
observer(updatedObject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the response to a create/update/delete request;
|
||||||
|
// track the rev if it's valid, otherwise return false to
|
||||||
|
// indicate that the request failed.
|
||||||
|
// persist any queued objects
|
||||||
|
checkResponse(response, intermediateResponse) {
|
||||||
|
let requestSuccess = false;
|
||||||
|
const id = response ? response.id : undefined;
|
||||||
|
let rev;
|
||||||
|
if (response && response.ok) {
|
||||||
|
rev = response.rev;
|
||||||
|
requestSuccess = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
intermediateResponse.resolve(requestSuccess);
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
if (!this.objectQueue[id]) {
|
||||||
|
this.objectQueue[id] = new CouchObjectQueue(undefined, rev);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.objectQueue[id].updateRevision(rev);
|
||||||
|
this.objectQueue[id].pending = false;
|
||||||
|
if (this.objectQueue[id].hasNext()) {
|
||||||
|
this.updateQueued(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getModel(response) {
|
||||||
|
if (response && response.model) {
|
||||||
|
let key = response[ID];
|
||||||
|
let object = response.model;
|
||||||
|
object.identifier = {
|
||||||
|
namespace: this.namespace,
|
||||||
|
key: key
|
||||||
|
};
|
||||||
|
if (!this.objectQueue[key]) {
|
||||||
|
this.objectQueue[key] = new CouchObjectQueue(undefined, response[REV]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.objectQueue[key].updateRevision(response[REV]);
|
||||||
|
|
||||||
|
return object;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get(identifier, abortSignal) {
|
||||||
|
return this.pouchdb.get(identifier.key).then(this.getModel.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
abortGetChanges() {
|
||||||
|
if (this.controller) {
|
||||||
|
this.controller.abort();
|
||||||
|
this.controller = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getIntermediateResponse() {
|
||||||
|
let intermediateResponse = {};
|
||||||
|
intermediateResponse.promise = new Promise(function (resolve, reject) {
|
||||||
|
intermediateResponse.resolve = resolve;
|
||||||
|
intermediateResponse.reject = reject;
|
||||||
|
});
|
||||||
|
|
||||||
|
return intermediateResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
enqueueObject(key, model, intermediateResponse) {
|
||||||
|
if (this.objectQueue[key]) {
|
||||||
|
this.objectQueue[key].enqueue({
|
||||||
|
model,
|
||||||
|
intermediateResponse
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.objectQueue[key] = new CouchObjectQueue({
|
||||||
|
model,
|
||||||
|
intermediateResponse
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
create(model) {
|
||||||
|
let intermediateResponse = this.getIntermediateResponse();
|
||||||
|
const key = model.identifier.key;
|
||||||
|
this.enqueueObject(key, model, intermediateResponse);
|
||||||
|
this.objectQueue[key].pending = true;
|
||||||
|
const queued = this.objectQueue[key].dequeue();
|
||||||
|
let document = new CouchDocument(key, queued.model);
|
||||||
|
this.pouchdb.put(document).then((response) => {
|
||||||
|
this.checkResponse(response, queued.intermediateResponse);
|
||||||
|
});
|
||||||
|
|
||||||
|
return intermediateResponse.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateQueued(key) {
|
||||||
|
if (!this.objectQueue[key].pending) {
|
||||||
|
this.objectQueue[key].pending = true;
|
||||||
|
const queued = this.objectQueue[key].dequeue();
|
||||||
|
let document = new CouchDocument(key, queued.model, this.objectQueue[key].rev);
|
||||||
|
|
||||||
|
this.pouchdb.put(document).then((response) => {
|
||||||
|
this.checkResponse(response, queued.intermediateResponse);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(model) {
|
||||||
|
let intermediateResponse = this.getIntermediateResponse();
|
||||||
|
const key = model.identifier.key;
|
||||||
|
this.enqueueObject(key, model, intermediateResponse);
|
||||||
|
this.updateQueued(key);
|
||||||
|
|
||||||
|
return intermediateResponse.promise;
|
||||||
|
}
|
||||||
|
}
|
34
src/plugins/persistence/pouchdb/plugin.js
Normal file
34
src/plugins/persistence/pouchdb/plugin.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is 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.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import PouchObjectProvider from './PouchObjectProvider';
|
||||||
|
const NAMESPACE = '';
|
||||||
|
const PERSISTENCE_SPACE = 'mct';
|
||||||
|
|
||||||
|
export default function PouchPlugin(options) {
|
||||||
|
return function install(openmct) {
|
||||||
|
options = options || {name: 'openmct', remoteCouch: 'http://127.0.0.1:5984/openmct'};
|
||||||
|
|
||||||
|
install.pouchProvider = new PouchObjectProvider(openmct, options, NAMESPACE);
|
||||||
|
openmct.objects.addProvider(PERSISTENCE_SPACE, install.pouchProvider);
|
||||||
|
};
|
||||||
|
}
|
@ -65,7 +65,8 @@ define([
|
|||||||
'./interceptors/plugin',
|
'./interceptors/plugin',
|
||||||
'./performanceIndicator/plugin',
|
'./performanceIndicator/plugin',
|
||||||
'./CouchDBSearchFolder/plugin',
|
'./CouchDBSearchFolder/plugin',
|
||||||
'./timeline/plugin'
|
'./timeline/plugin',
|
||||||
|
'./persistence/pouchdb/plugin'
|
||||||
], function (
|
], function (
|
||||||
_,
|
_,
|
||||||
UTCTimeSystem,
|
UTCTimeSystem,
|
||||||
@ -111,7 +112,8 @@ define([
|
|||||||
ObjectInterceptors,
|
ObjectInterceptors,
|
||||||
PerformanceIndicator,
|
PerformanceIndicator,
|
||||||
CouchDBSearchFolder,
|
CouchDBSearchFolder,
|
||||||
Timeline
|
Timeline,
|
||||||
|
PouchDB
|
||||||
) {
|
) {
|
||||||
const bundleMap = {
|
const bundleMap = {
|
||||||
LocalStorage: 'platform/persistence/local',
|
LocalStorage: 'platform/persistence/local',
|
||||||
@ -212,6 +214,7 @@ define([
|
|||||||
plugins.PerformanceIndicator = PerformanceIndicator.default;
|
plugins.PerformanceIndicator = PerformanceIndicator.default;
|
||||||
plugins.CouchDBSearchFolder = CouchDBSearchFolder.default;
|
plugins.CouchDBSearchFolder = CouchDBSearchFolder.default;
|
||||||
plugins.Timeline = Timeline.default;
|
plugins.Timeline = Timeline.default;
|
||||||
|
plugins.PouchDB = PouchDB.default;
|
||||||
|
|
||||||
return plugins;
|
return plugins;
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user