UNPKG

c8osdkjscore

Version:
698 lines (633 loc) 34.6 kB
import {C8oBase} from "./c8oBase"; import {C8oCore, FullSyncPolicy} from "./c8oCore"; import {C8oFullSyncChangeListener} from "./c8oFullSyncChangeListener"; import {C8oFullSyncTranslator} from "./c8oFullSyncTranslator"; import {C8oLocalCacheResponse} from "./c8oLocalCacheResponse"; import {C8oResponseJsonListener, C8oResponseListener} from "./c8oResponse"; import {C8oUtilsCore} from "./c8oUtilsCore"; import {C8oCouchBaseLiteException} from "./Exception/c8oCouchBaseLiteException"; import {C8oException} from "./Exception/c8oException"; import {C8oExceptionMessage} from "./Exception/c8oExceptionMessage"; import {C8oRessourceNotFoundException} from "./Exception/c8oRessourceNotFoundException"; import {C8oUnavailableLocalCacheException} from "./Exception/c8oUnavailableLocalCacheException"; import {C8oFullSyncDatabase} from "./fullSyncDatabase"; import {FullSyncDeleteDocumentParameter} from "./fullSyncDeleteDocumentParameter"; import {FullSyncRequestable} from "./fullSyncRequestable"; import {FullSyncDefaultResponse, FullSyncDocumentOperationResponse} from "./fullSyncResponse"; export class C8oFullSync { private static FULL_SYNC_URL_PATH: string = "/fullsync/"; /** * The project requestable value to execute a fullSync request. */ public static FULL_SYNC_PROJECT: string = "fs://"; public static FULL_SYNC__ID: string = "_id"; public static FULL_SYNC__REV: string = "_rev"; public static FULL_SYNC__ATTACHMENTS: string = "_attachments"; public c8o: C8oCore; protected fullSyncDatabaseUrlBase: string; protected localSuffix: string; public constructor(c8o: C8oCore) { this.c8o = c8o; this.fullSyncDatabaseUrlBase = c8o.endpointConvertigo + C8oFullSync.FULL_SYNC_URL_PATH; this.localSuffix = (c8o.fullSyncLocalSuffix !== null) ? c8o.fullSyncLocalSuffix : "_device"; } /** * Handles a fullSync request.<br/> * It determines the type of the request thanks to parameters. * * @param _parameters * @param listener * @return promise<any> * @throws C8oException */ public async handleFullSyncRequest(_parameters: Object, listener: C8oResponseListener): Promise<any> { const parameters = {}; for (const val in _parameters) { if (_parameters[val] instanceof Blob != true) { //if it's not a blob then stringify and parse the value to make some values like true case insensitive ( from string to boolean) parameters[val] = JSON.parse(JSON.stringify(_parameters[val])); } else { parameters[val] = _parameters[val]; } } const projectParameterValue: string = C8oUtilsCore.peekParameterStringValue(parameters, C8oCore.ENGINE_PARAMETER_PROJECT, true); if (projectParameterValue.indexOf(C8oFullSync.FULL_SYNC_PROJECT) !== 0) { throw new C8oException(C8oExceptionMessage.invalidParameterValue(projectParameterValue, "its don't start with" + C8oFullSync.FULL_SYNC_PROJECT)); } let fullSyncRequestableValue: string = C8oUtilsCore.peekParameterStringValue(parameters, C8oCore.ENGINE_PARAMETER_SEQUENCE, true); // get rid of the optional trailing #RouteHint present in the sequence if (fullSyncRequestableValue.indexOf("#") !== -1) { fullSyncRequestableValue = fullSyncRequestableValue.substring(0, fullSyncRequestableValue.indexOf("#")); } const fullSyncRequestable: FullSyncRequestable = FullSyncRequestable.getFullSyncRequestable(fullSyncRequestableValue); if (fullSyncRequestable === null) { throw new C8oException(C8oExceptionMessage.invalidParameterValue(C8oCore.ENGINE_PARAMETER_PROJECT, C8oExceptionMessage.unknownValue("fullSync requestable", fullSyncRequestableValue))); } let databaseName: string = projectParameterValue.substring(C8oFullSync.FULL_SYNC_PROJECT.length); if (databaseName.length < 1) { databaseName = this.c8o.defaultDatabaseName; if (databaseName === null) { throw new C8oException(C8oExceptionMessage.invalidParameterValue(C8oCore.ENGINE_PARAMETER_PROJECT, C8oExceptionMessage.missingValue("fullSync database name"))); } } let response: any; return new Promise((resolve, reject) => { fullSyncRequestable.handleFullSyncRequest(this, databaseName, parameters, listener).then((result) => { response = result; if (response === null || response === undefined) { reject(new C8oException(C8oExceptionMessage.couchNullResult())); } resolve(this.handleFullSyncResponse(response, listener)); }).catch((error) => { if (error instanceof C8oException) { reject(error); } else { reject(new C8oException(C8oExceptionMessage.FullSyncRequestFail(), error)); } }); }); } //noinspection JSUnusedLocalSymbols /** * * @param response * @param listener * @return response * @throws C8oException Failed to parse response. */ public handleFullSyncResponse(response: any, listener: C8oResponseListener): any { return response; } /** * Checks if request parameters correspond to a fullSync request. */ public static isFullSyncRequest(requestParameter: Object): boolean { if (C8oUtilsCore.getParameterStringValue(requestParameter, C8oCore.ENGINE_PARAMETER_PROJECT, false) !== null) { return C8oUtilsCore.getParameterStringValue(requestParameter, C8oCore.ENGINE_PARAMETER_PROJECT, false).indexOf(C8oFullSync.FULL_SYNC_PROJECT) === 0; } else { return false; } } } export class C8oFullSyncCbl extends C8oFullSync { private static ATTACHMENT_PROPERTY_KEY_CONTENT_URL: string = "content_url"; private fullSyncDatabases: Object; private fullSyncChangeListeners: C8oFullSyncChangeListener[][] = []; private cblChangeListeners: any[] = []; constructor(c8o: C8oCore) { super(c8o); this.fullSyncDatabases = {}; } /** * Returns the database with this name in the list.<br/> * If it does not already exist yet then creates it and adds it to the list. * * @param databaseName * @return C8oFullSyncDatabase * @throws C8oException Failed to create a new fullSync database. */ public getOrCreateFullSyncDatabase(databaseName: string): C8oFullSyncDatabase { const localDatabaseName: string = databaseName + this.localSuffix; if (this.fullSyncDatabases[localDatabaseName] == null) { this.fullSyncDatabases[localDatabaseName] = new C8oFullSyncDatabase(this.c8o, databaseName, this.fullSyncDatabaseUrlBase, this.localSuffix); } return this.fullSyncDatabases[localDatabaseName]; } public handleFullSyncResponse(response: any, listener: C8oResponseListener): any { response = super.handleFullSyncResponse(response, listener); if (listener instanceof C8oResponseJsonListener) { if (response instanceof FullSyncDocumentOperationResponse) { return C8oFullSyncTranslator.fullSyncDocumentOperationResponseToJson(response as FullSyncDocumentOperationResponse); } else if (response instanceof FullSyncDefaultResponse) { return C8oFullSyncTranslator.fullSyncDefaultResponseToJson(response as FullSyncDefaultResponse); } else if (response instanceof Object) { return response as JSON; } else { throw new C8oException(C8oExceptionMessage.illegalArgumentIncompatibleListener(listener.toString(), typeof response)); } } } public handleGetAttachmentUrlRequest(fullSyncDatabaseName: string, docid: string, parameters: Object): Promise<any> { let fullSyncDatabase: C8oFullSyncDatabase = null; fullSyncDatabase = this.getOrCreateFullSyncDatabase(fullSyncDatabaseName); const attachmentName = C8oUtilsCore.getParameterStringValue(parameters, "attachment_name", false); return new Promise((resolve) => { fullSyncDatabase.getdatabase.getAttachment(docid, attachmentName).then((buffer) => { resolve(buffer); }); }); } public handleGetDocumentRequest(fullSyncDatabaseName: string, docid: string, parameters: Object): Promise<any> { let fullSyncDatabase: C8oFullSyncDatabase = null; let dictDoc: Object = {}; let param: Object; param = parameters["attachments"] ? {attachments: true} : {}; parameters["binary"] ? param["binary"] = true : {}; fullSyncDatabase = this.getOrCreateFullSyncDatabase(fullSyncDatabaseName); return new Promise((resolve, reject) => { fullSyncDatabase.getdatabase.get(docid, param).then((document) => { if (document != null) { dictDoc = document; const attachments = document[C8oFullSync.FULL_SYNC__ATTACHMENTS]; if (attachments != null) { for (const attachmentName of attachments) { const url = attachments.url; const attachmentDesc: Object = attachments[attachmentName]; attachmentDesc[C8oFullSyncCbl.ATTACHMENT_PROPERTY_KEY_CONTENT_URL] = url.toString(); const dictAny: Object = {}; dictAny[attachmentName] = attachmentDesc; dictDoc[C8oFullSyncCbl.FULL_SYNC__ATTACHMENTS] = dictAny; } } } else { throw new C8oRessourceNotFoundException((C8oExceptionMessage.ressourceNotFound("requested document \"" + docid + "\""))); } if (dictDoc === null) { dictDoc = {}; } resolve(dictDoc); }) .catch((error) => { reject(error); }); }); } public handleDeleteDocumentRequest(DatabaseName: string, docid: string, parameters: Object): Promise<any> { let fullSyncDatabase: C8oFullSyncDatabase = null; fullSyncDatabase = this.getOrCreateFullSyncDatabase(DatabaseName); const revParameterValue: string = C8oUtilsCore.getParameterStringValue(parameters, FullSyncDeleteDocumentParameter.REV.name, false); let documentRevision: string; if (revParameterValue === null) { return new Promise((resolve, reject) => { fullSyncDatabase.getdatabase.get(docid).then((doc) => { if (doc === null) { throw new C8oRessourceNotFoundException("Cannot find document"); } documentRevision = doc._rev; return fullSyncDatabase.getdatabase.remove(doc); }).then((result) => { resolve(new FullSyncDocumentOperationResponse(docid, documentRevision, result.ok)); }).catch((err) => { reject(new C8oException(C8oExceptionMessage.couchRequestDeleteDocument(), err)); }); }); } else { return new Promise((resolve, reject) => { fullSyncDatabase.getdatabase.remove(docid, revParameterValue) .then((result) => { resolve(new FullSyncDocumentOperationResponse(docid, documentRevision, result.ok)); }).catch((err) => { reject(new C8oException(C8oExceptionMessage.couchRequestDeleteDocument(), err)); }); }); } } public handlePostDocumentRequest(databaseName: string, fullSyncPolicy: FullSyncPolicy, parameters: Object): Promise<FullSyncDocumentOperationResponse> { let fullSyncDatabase: C8oFullSyncDatabase; fullSyncDatabase = this.getOrCreateFullSyncDatabase(databaseName); let subkeySeparatorParameterValue: string = C8oUtilsCore.getParameterStringValue(parameters, C8oCore.FS_SUBKEY_SEPARATOR, false); if (subkeySeparatorParameterValue == null) { subkeySeparatorParameterValue = "."; } const newProperties = {}; for (let i = 0; i < Object.keys(parameters).length; i++) { let parameterName: string = Object.keys(parameters)[i]; if (parameterName.indexOf("__") !== 0 && parameterName.indexOf("_use_") !== 0) { let objectParameterValue: any = parameters[Object.keys(parameters)[i]]; const paths: string[] = parameterName.split(subkeySeparatorParameterValue); if (paths.length > 1) { parameterName = paths[0]; let count = paths.length - 1; while (count > 0) { const tmpObject: Object = {}; tmpObject[paths[count]] = objectParameterValue; objectParameterValue = tmpObject; count--; } const existProperty = newProperties[parameterName]; if (existProperty != null) { C8oFullSyncCbl.mergeProperties(objectParameterValue, existProperty); } } newProperties[parameterName] = objectParameterValue; } } const db = fullSyncDatabase.getdatabase; return new Promise((resolve, reject) => { fullSyncPolicy.action(db, newProperties).then((createdDocument) => { const fsDocOpeResp: FullSyncDocumentOperationResponse = new FullSyncDocumentOperationResponse(createdDocument.id, createdDocument.rev, createdDocument.ok); resolve(fsDocOpeResp); }).catch((error) => { reject(error); }); }); } public handlePutAttachmentRequest(databaseName: string, docid: string, attachmentName: string, attachmentType: string, attachmentContent: any): Promise<any> { let document: any = null; const fullSyncDatabase: C8oFullSyncDatabase = this.getOrCreateFullSyncDatabase(databaseName); return new Promise((resolve) => { fullSyncDatabase.getdatabase.get(docid).then((result) => { document = result; if (document !== null) { fullSyncDatabase.getdatabase.putAttachment(docid, attachmentName, result._rev, attachmentContent, attachmentType) .then((result) => { // handle result resolve(new FullSyncDocumentOperationResponse(result._id, result._rev, result.ok)); }).catch((err) => { throw new C8oCouchBaseLiteException("Unable to put the attachment " + attachmentName + " to the document " + docid + ".", err); }); } else { throw new C8oRessourceNotFoundException("Cannot find document"); } }); }); } public handleDeleteAttachmentRequest(databaseName: string, docid: string, attachmentName: string): Promise<any> { let document: any = null; const fullSyncDatabase: C8oFullSyncDatabase = this.getOrCreateFullSyncDatabase(databaseName); return new Promise((resolve, reject) => { fullSyncDatabase.getdatabase.get(docid).then((result) => { document = result; }).then(() => { if (document !== null) { fullSyncDatabase.getdatabase.removeAttachment(docid, attachmentName, document._rev).catch((err) => { throw new C8oCouchBaseLiteException("Unable to delete the attachment " + attachmentName + " to the document " + docid + ".", err); }); } else { throw new C8oRessourceNotFoundException("Document do not exists"); } resolve(new FullSyncDocumentOperationResponse(document._id, document._rev, true)); }) .catch((err)=>{ reject(new C8oException(err.message, err)); }) }); } public handleAllDocumentsRequest(databaseName: string, parameters: Object): Promise<any> { let fullSyncDatabase = null; fullSyncDatabase = this.getOrCreateFullSyncDatabase(databaseName); return new Promise((resolve, reject) => { fullSyncDatabase.getdatabase .allDocs(parameters) .then((res) => { resolve(res); }) .catch((err) => { reject(new C8oException(err.stack)); }); }); } public handleGetViewRequest(databaseName: string, ddocName: string, viewName: string, parameters: Object): Promise<any> { let fullSyncDatabase = null; fullSyncDatabase = this.getOrCreateFullSyncDatabase(databaseName); let attachments; let binary; let include_docs; if (parameters["attachments"] && window["cblite"] !== undefined) { attachments = C8oUtilsCore.getParameterStringValue(parameters, "attachments", false); binary = C8oUtilsCore.getParameterStringValue(parameters, "binary", false); include_docs = C8oUtilsCore.getParameterStringValue(parameters, "include_docs", false); } return new Promise((resolve, reject) => { fullSyncDatabase.getdatabase.query(ddocName + "/" + viewName, parameters) .then((result) => { if (attachments) { const array: Object[] = []; let len = 0; for (const resp of result.rows) { this.handleGetDocumentRequest(databaseName, resp.id, { attachments: true, binary: true, include_docs: true, }).then((getResult) => { array.push(getResult); len++; if (len === result.rows.length) { result.rows = array; resolve(result); } }); } } else { resolve(result); } }).catch((error) => { reject(new C8oException(C8oExceptionMessage.couchRequestGetView(), error)); }); }); } public handleSyncRequest(databaseName: string, parameters: Object, c8oResponseListener: C8oResponseListener): Promise<any> { const fullSyncDatabase: C8oFullSyncDatabase = this.getOrCreateFullSyncDatabase(databaseName); return fullSyncDatabase.startAllReplications(parameters, c8oResponseListener); } public handleReplicatePullRequest(databaseName: string, parameters: Object, c8oResponseListener: C8oResponseListener): Promise<any> { const fullSyncDatabase: C8oFullSyncDatabase = this.getOrCreateFullSyncDatabase(databaseName); return fullSyncDatabase.startPullReplication(parameters, c8oResponseListener); } public handleReplicatePushRequest(databaseName: string, parameters: Object, c8oResponseListener: C8oResponseListener): Promise<any> { const fullSyncDatabase: C8oFullSyncDatabase = this.getOrCreateFullSyncDatabase(databaseName); return fullSyncDatabase.startPushReplication(parameters, c8oResponseListener); } public handleResetDatabaseRequest(databaseName: string): Promise<FullSyncDefaultResponse> { return new Promise((resolve) => { this.handleDestroyDatabaseRequest(databaseName).then(() => { resolve(this.handleCreateDatabaseRequest(databaseName)); }); }); } public handleCreateDatabaseRequest(databaseName: string): FullSyncDefaultResponse { this.getOrCreateFullSyncDatabase(databaseName); return new FullSyncDefaultResponse(true); } public handleBulkRequest(databaseName: string, parameters: Object): Promise<FullSyncDefaultResponse> { const fullSyncDatabase: C8oFullSyncDatabase = this.getOrCreateFullSyncDatabase(databaseName); return new Promise((resolve, reject) => { fullSyncDatabase.getdatabase.load(parameters["data"], { proxy: this.c8o.endpointConvertigo + "/fullsync/" + fullSyncDatabase.getdatabseName }).then(()=> { resolve(new FullSyncDefaultResponse(true)); }).catch((err)=>{ //this.c8o.log.error("Error loading the " + parameters["data"] + " database resource" + JSON.stringify(err, Object.getOwnPropertyNames(err))) reject(new C8oException("Bulk Load failed", err)); }) }) } public handleInfoRequest(databaseName:string): Promise<FullSyncDefaultResponse> { const fullSyncDatabase: C8oFullSyncDatabase = this.getOrCreateFullSyncDatabase(databaseName); return new Promise((resolve, reject) => { fullSyncDatabase.getdatabase.info() .then((response)=> { resolve(response); }).catch((err)=>{ //this.c8o.log.error("Error loading the " + parameters["data"] + " database resource" + JSON.stringify(err, Object.getOwnPropertyNames(err))) reject(new C8oException("Get info failed", err)); }) }) } public handleDestroyDatabaseRequest(databaseName: string): Promise<FullSyncDefaultResponse> { return new Promise((resolve, reject) => { const localDatabaseName = databaseName + this.localSuffix; this.getOrCreateFullSyncDatabase(databaseName).deleteDB().then((response) => { if (this.fullSyncDatabases[localDatabaseName] !== null) { delete this.fullSyncDatabases[localDatabaseName]; } resolve(new FullSyncDefaultResponse(response.ok)); }).catch((err) => { reject(new C8oException(err.message, err)); }); }); } public static mergeProperties(newProperties: Object, oldProperties: Object) { for (let i = 0; i < Object.keys(oldProperties).length; i++) { const oldPropertyKey = Object.keys(oldProperties)[i]; const oldPropertyValue = oldProperties[Object.keys(oldProperties)[i]]; // Checks if the new document contains the same key if (newProperties[oldPropertyKey] !== null && newProperties[oldPropertyKey] !== undefined) { const newDocumentValue = newProperties[oldPropertyKey]; if (Object.prototype.toString.call( newDocumentValue ) === "[object Array]" && Object.prototype.toString.call( oldPropertyValue ) === "[object Array]") { C8oFullSyncCbl.mergeArrayProperties(newDocumentValue, oldPropertyValue); } else if (typeof(newDocumentValue) === "object" && typeof(oldPropertyValue) === "object") { C8oFullSyncCbl.mergeProperties(newDocumentValue, oldPropertyValue); } else { // If the new document has the same key but its value is not the same type than the old one or if their type are "simple" // Does nothing cause the right value is the new one } } else { // If the new document does not contain the key then adds it newProperties[oldPropertyKey] = oldPropertyValue; } } } public static mergeArrayProperties(newArray: any, oldArray: any) { const newArraySize = newArray.length; const oldArraySize = oldArray.length; for (let i = 0; i < oldArraySize; i++) { let newArrayValue: any = null; if (i < newArraySize) { newArrayValue = newArray[i]; } const oldArrayValue = oldArray[i]; if (newArrayValue !== null) { if (newArrayValue instanceof Array && oldArrayValue instanceof Array) { C8oFullSyncCbl.mergeArrayProperties(newArrayValue, oldArrayValue); } else if (typeof(newArrayValue) === "object" && typeof(oldArrayValue) === "object") { C8oFullSyncCbl.mergeProperties(newArrayValue, oldArrayValue); } else { // If the new array value is not the same type than the old one or if their type are "simple" // Does nothing cause the right value is the new one } } else { // If the new array value is null then it means that it size is reach so we can add objects at its end newArray.push(oldArrayValue); } } } //noinspection JSUnusedLocalSymbols public getDocucmentFromDatabase(c8o: C8oCore, databaseName: string, documentId: string): Promise<any> { let c8oFullSyncDatabase: C8oFullSyncDatabase; try { c8oFullSyncDatabase = this.getOrCreateFullSyncDatabase(databaseName); } catch (err) { throw new C8oException(C8oExceptionMessage.fullSyncGetOrCreateDatabase(databaseName)); } return new Promise((resolve) => { c8oFullSyncDatabase.getdatabase().get(documentId).then((result) => { resolve(result); }); }); } public overrideDocument(document: any, properties: Object, databaseName) { properties[C8oFullSync.FULL_SYNC__REV] = document._rev; let c8oFullSyncDatabase: C8oFullSyncDatabase; try { c8oFullSyncDatabase = this.getOrCreateFullSyncDatabase(databaseName); } catch (err) { throw new C8oException(C8oExceptionMessage.fullSyncGetOrCreateDatabase(databaseName)); } c8oFullSyncDatabase.getdatabase().put(properties) .catch((err) => { throw new C8oException(err.message, err); }); } public async getResponseFromLocalCache(c8oCallRequestIdentifier: string): Promise<any> { const fullSyncDatabase = this.getOrCreateFullSyncDatabase(C8oCore.LOCAL_CACHE_DATABASE_NAME); let localCacheDocument = null; return new Promise((resolve, reject) => { fullSyncDatabase.getdatabase.get(c8oCallRequestIdentifier).then((result) => { localCacheDocument = result; const response = JSON.stringify(localCacheDocument[C8oCore.LOCAL_CACHE_DOCUMENT_KEY_RESPONSE]); const responseType = localCacheDocument[C8oCore.LOCAL_CACHE_DOCUMENT_KEY_RESPONSE_TYPE]; const expirationDate = localCacheDocument[C8oCore.LOCAL_CACHE_DOCUMENT_KEY_EXPIRATION_DATE]; let responseString: string = null; let responseTypeString: string = null; let expirationDateNumber: number = -1; if (response != null) { if (typeof response === "string") { responseString = response; } else { throw new C8oException(C8oExceptionMessage.InvalidLocalCacheResponseInformation()); } } if (responseType != null) { if (typeof responseType === "string") { responseTypeString = responseType; } else { throw new C8oException(C8oExceptionMessage.InvalidLocalCacheResponseInformation()); } } if (expirationDate != null) { if (typeof expirationDate === "number") { expirationDateNumber = expirationDate; const currentTime = new Date().getTime(); if (expirationDateNumber < currentTime) { throw new C8oUnavailableLocalCacheException(C8oExceptionMessage.timeToLiveExpired()); } } else { throw new C8oException(C8oExceptionMessage.InvalidLocalCacheResponseInformation()); } } resolve(new C8oLocalCacheResponse(responseString, responseTypeString, expirationDateNumber)); }).catch((err) => { if (err.status === 404) { resolve(new C8oUnavailableLocalCacheException(C8oExceptionMessage.localCacheDocumentJustCreated())); } else { reject(err); } }); }); } public async saveResponseToLocalCache(c8oCallRequestIdentifier: string, localCacheResponse: C8oLocalCacheResponse): Promise<any> { const fullSyncDatabase: C8oFullSyncDatabase = this.getOrCreateFullSyncDatabase(C8oCore.LOCAL_CACHE_DATABASE_NAME); return new Promise((resolve) => { fullSyncDatabase.getdatabase.get(c8oCallRequestIdentifier).then((localCacheDocument) => { const properties = {}; properties[C8oFullSync.FULL_SYNC__ID] = c8oCallRequestIdentifier; properties[C8oCore.LOCAL_CACHE_DOCUMENT_KEY_RESPONSE] = localCacheResponse.getResponse(); properties[C8oCore.LOCAL_CACHE_DOCUMENT_KEY_RESPONSE_TYPE] = localCacheResponse.getResponseType(); if (localCacheResponse.getExpirationDate() > 0) { properties[C8oCore.LOCAL_CACHE_DOCUMENT_KEY_EXPIRATION_DATE] = localCacheResponse.getExpirationDate(); } const currentRevision = localCacheDocument._rev; if (currentRevision !== null) { properties[C8oFullSyncCbl.FULL_SYNC__REV] = currentRevision; } fullSyncDatabase.getdatabase.put(properties).then((result) => { resolve(result); }); }).catch((error) => { if (error.status === 404) { const properties = {}; properties[C8oFullSync.FULL_SYNC__ID] = c8oCallRequestIdentifier; properties[C8oCore.LOCAL_CACHE_DOCUMENT_KEY_RESPONSE] = localCacheResponse.getResponse(); properties[C8oCore.LOCAL_CACHE_DOCUMENT_KEY_RESPONSE_TYPE] = localCacheResponse.getResponseType(); if (localCacheResponse.getExpirationDate() > 0) { properties[C8oCore.LOCAL_CACHE_DOCUMENT_KEY_EXPIRATION_DATE] = localCacheResponse.getExpirationDate(); } fullSyncDatabase.getdatabase.put(properties).then((result) => { resolve(result); }); } else { resolve(error); } }); }); } public addFullSyncChangeListener(db: string, listener: C8oFullSyncChangeListener) { if (db === null || db === "") { db = this.c8o.defaultDatabaseName; } const listeners: C8oFullSyncChangeListener[][] = []; if (this.fullSyncChangeListeners[db] != null) { listeners[0] = this.fullSyncChangeListeners[db]; } else { listeners[0] = []; this.fullSyncChangeListeners[db] = listeners[0]; //noinspection UnnecessaryLocalVariableJS const evtHandler = this.getOrCreateFullSyncDatabase(db).getdatabase .changes({ since: "now", live: true, include_docs: true, }).on("change", function(change) { const changes: Object = {}; const docs: Object[] = []; // docs["isExternal"] = false; const doc: Object = {}; doc["id"] = change.doc._id; doc["rev"] = change.doc._rev; doc["isConflict"] = change.doc._conflicts; if (change.source != null) { doc["sourceUrl"] = change.source; } docs.push(doc); changes["changes"] = docs; for (const handler of listeners[0]) { if (handler !== undefined) { handler.onChange(changes); } } }); this.cblChangeListeners[db] = evtHandler; } listeners[0].push(listener); } public removeFullSyncChangeListener(db: string, listener: C8oFullSyncChangeListener) { if (db === null || db === "") { db = this.c8o.defaultDatabaseName; } if (this.fullSyncChangeListeners[db] != null) { const listeners: C8oFullSyncChangeListener[] = this.fullSyncChangeListeners[db]; for (const list in listeners) { if (listeners[list] === listener) { delete listeners[list]; } } if (listeners.length === 0 || listeners == null) { this.getOrCreateFullSyncDatabase(db).getdatabase.cancel(); this.cblChangeListeners[db].cancel(); delete this.fullSyncChangeListeners[db]; delete this.cblChangeListeners[db]; } } } }