mirror of
https://github.com/finos/SymphonyElectron.git
synced 2025-02-25 18:55:29 -06:00
Swift Search to Master (#405)
* SEARCH-627 & SEARCH-628 - Add implementation for memory indexing - Batch indexing and Real-time indexing * ELECTRON-426 (#345) - Changes innerHTML to innerText - Removes 'replaceStrongTag' and 'replaceHTMLTags' function and changing to innerHTML to innerText * SEARCH-764 - Rework "deleteIndexFolders" in the Electron Preload Script - Fixes the Security Vulnerability * SEARCH-764 - Updates spectron test preload api version * SEARCH-766 - Rework "readFile" in Electron Preload Script - Removing this method as this is only for the demo app * SEARCH-766 - Removes merge method * SEARCH-767 - Rework "path" in Electron Preload Script - Removes the constructor to use hardcoded path * SEARCH-767 - Updates unit test * SEARCH-775 - Adds search api version to match with the client app * SEARCH-775 - Spectron test fix * SEARCH-770 (#391) - constructor is required which was removed as part of SEARCH-767
This commit is contained in:
parent
65c304766f
commit
4aaa9ac539
@ -92,12 +92,14 @@
|
||||
<th>Container Identifier</th>
|
||||
<th>Container Version</th>
|
||||
<th>Build Number</th>
|
||||
<th>Search Api Version</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="api-version"></td>
|
||||
<td id="container-identifier"></td>
|
||||
<td id="container-ver"></td>
|
||||
<td id="build-number"></td>
|
||||
<td id="search-api-ver"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
@ -250,11 +252,13 @@
|
||||
let containerIdentifier = document.getElementById('container-identifier');
|
||||
let version = document.getElementById('container-ver');
|
||||
let buildNumber = document.getElementById('build-number');
|
||||
let searchApiVer = document.getElementById('search-api-ver');
|
||||
|
||||
apiVersionInfo.innerText = verInfo.apiVer;
|
||||
containerIdentifier.innerText = verInfo.containerIdentifier;
|
||||
version.innerText = verInfo.containerVer;
|
||||
buildNumber.innerText = verInfo.buildNumber;
|
||||
searchApiVer.innerText = verInfo.searchApiVer;
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -79,13 +79,7 @@
|
||||
</div>
|
||||
<br>
|
||||
<div>
|
||||
<label for="batchNumber">Batch Number: </label><input placeholder="Ex: batch1, batch2" id="batchNumber">
|
||||
<button id='index'>Index Messages</button>
|
||||
<button id='merge'>Merge</button>
|
||||
</div>
|
||||
<br>
|
||||
<div>
|
||||
<label for="batchNumber">Get Latest Message Timestamp</label>
|
||||
<label for="getLatestMessageTimestamp">Get Latest Message Timestamp</label>
|
||||
<button id='getLatestMessageTimestamp'>Click</button>
|
||||
</div>
|
||||
<br>
|
||||
@ -125,8 +119,6 @@
|
||||
var search = new ssf.Search("12345678910112", "jjjehdnctsjyieoalskcjdhsnahsadndfnusdfsdfsd=");
|
||||
var searchUtils = new ssf.SearchUtils();
|
||||
var buttonEl = document.getElementById('search');
|
||||
var merge = document.getElementById('merge');
|
||||
var buttonIndex = document.getElementById('index');
|
||||
var queryEl = document.getElementById('query');
|
||||
var offsetEl = document.getElementById('offset');
|
||||
var limitEl = document.getElementById('limit');
|
||||
@ -139,7 +131,6 @@
|
||||
var table = document.getElementById('table');
|
||||
var sendMessage = document.getElementById('sendMessage');
|
||||
var realTimeIndexing = document.getElementById('realTimeIndexing');
|
||||
var batchNumber = document.getElementById('batchNumber');
|
||||
var timestamp = document.getElementById('getLatestMessageTimestamp');
|
||||
var has = document.getElementById('has');
|
||||
var checkFreeSpace = document.getElementById('checkFreeSpace');
|
||||
@ -148,18 +139,6 @@
|
||||
var rotationId = document.getElementById('rotationId');
|
||||
var updateUserConfig = document.getElementById('updateUserConfig');
|
||||
|
||||
|
||||
buttonIndex.addEventListener('click', function () {
|
||||
let batchIndex = batchNumber.value;
|
||||
search.readJson(batchIndex).then(function (res) {
|
||||
search.indexBatch(JSON.stringify(res)).then(function () {
|
||||
resultsEl.innerHTML = "Index created";
|
||||
});
|
||||
}).catch(function (err) {
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
|
||||
buttonEl.addEventListener('click', function () {
|
||||
if (!search.isLibInit()) {
|
||||
search.init();
|
||||
@ -238,20 +217,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
merge.addEventListener('click', function () {
|
||||
search.mergeIndexBatches().then(function () {
|
||||
search.encryptIndex('jjjehdnctsjyieoalskcjdhsnahsadndfnusdfsdfsd=').then(function () {
|
||||
searchUtils.updateUserConfig(12345678910112, {rotationId:0, version: 1}).then(function (res) {
|
||||
resultsEl.innerHTML = JSON.stringify(res);
|
||||
}).catch(function (err) {
|
||||
resultsEl.innerHTML = JSON.stringify(err);
|
||||
});
|
||||
});
|
||||
}).catch(function (err) {
|
||||
resultsEl.innerHTML = 'Error: ' + err;
|
||||
});
|
||||
});
|
||||
|
||||
timestamp.addEventListener('click', function () {
|
||||
search.getLatestMessageTimestamp().then(function (res) {
|
||||
resultsEl.innerHTML = res;
|
||||
@ -289,4 +254,4 @@
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@ -110,7 +110,8 @@ function createAPI() {
|
||||
containerIdentifier: appName,
|
||||
containerVer: appVer,
|
||||
buildNumber: buildNumber,
|
||||
apiVer: '1.0.0'
|
||||
apiVer: '2.0.0',
|
||||
searchApiVer: '2.0.0'
|
||||
};
|
||||
resolve(verInfo);
|
||||
});
|
||||
@ -448,4 +449,4 @@ function createAPI() {
|
||||
window.addEventListener('beforeunload', sanitize, false);
|
||||
|
||||
updateOnlineStatus();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const { randomString } = require('../search/utils/randomString.js');
|
||||
const ref = require('ref');
|
||||
const childProcess = require('child_process');
|
||||
const path = require('path');
|
||||
const isDevEnv = require('../utils/misc.js').isDevEnv;
|
||||
@ -17,6 +17,7 @@ const Crypto = require('../cryptoLib');
|
||||
|
||||
const INDEX_VALIDATOR = searchConfig.LIBRARY_CONSTANTS.INDEX_VALIDATOR;
|
||||
|
||||
/*eslint class-methods-use-this: ["error", { "exceptMethods": ["deleteRealTimeFolder"] }] */
|
||||
/**
|
||||
* This search class communicates with the SymphonySearchEngine C library via node-ffi.
|
||||
* There should be only 1 instance of this class in the Electron
|
||||
@ -67,16 +68,18 @@ class Search {
|
||||
* and creates a folder in the userData
|
||||
*/
|
||||
init() {
|
||||
libSymphonySearch.symSEDestroy();
|
||||
libSymphonySearch.symSEInit();
|
||||
libSymphonySearch.symSEClearMainRAMIndex();
|
||||
libSymphonySearch.symSEClearRealtimeRAMIndex();
|
||||
libSymphonySearch.symSEEnsureFolderExists(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH);
|
||||
Search.deleteIndexFolders(searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX);
|
||||
Search.deleteIndexFolders(searchConfig.FOLDERS_CONSTANTS.TEMP_BATCH_INDEX_FOLDER);
|
||||
Search.indexValidator(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`);
|
||||
Search.indexValidator(searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX);
|
||||
let indexDateStartFrom = new Date().getTime() - searchConfig.SEARCH_PERIOD_SUBTRACTOR;
|
||||
libSymphonySearch.symSEMainFSIndexToRAMIndex(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`);
|
||||
// Deleting all the messages except 3 Months from now
|
||||
libSymphonySearch.symSEDeleteMessages(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`, null,
|
||||
libSymphonySearch.symSEDeleteMessagesFromRAMIndex(null,
|
||||
searchConfig.MINIMUM_DATE, indexDateStartFrom.toString());
|
||||
Search.deleteIndexFolders();
|
||||
this.isInitialized = true;
|
||||
}
|
||||
|
||||
@ -113,17 +116,10 @@ class Search {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH)) {
|
||||
log.send(logLevels.ERROR, 'User index folder not found');
|
||||
reject(new Error('User index folder not found'));
|
||||
return;
|
||||
}
|
||||
|
||||
const indexId = randomString();
|
||||
libSymphonySearch.symSECreatePartialIndexAsync(searchConfig.FOLDERS_CONSTANTS.TEMP_BATCH_INDEX_FOLDER, indexId, messages, (err, res) => {
|
||||
libSymphonySearch.symSEIndexMainRAMAsync(messages, function (err, res) {
|
||||
if (err) {
|
||||
log.send(logLevels.ERROR, 'Batch Indexing: error ->' + err);
|
||||
reject(new Error(err));
|
||||
log.send(logLevels.ERROR, `IndexBatch: Error indexing messages to memory : ${err}`);
|
||||
reject(new Error('IndexBatch: Error indexing messages to memory '));
|
||||
return;
|
||||
}
|
||||
resolve(res);
|
||||
@ -135,22 +131,24 @@ class Search {
|
||||
* Merging the temporary
|
||||
* created from indexBatch()
|
||||
*/
|
||||
mergeIndexBatches() {
|
||||
memoryIndexToFSIndex() {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
Search.deleteIndexFolders();
|
||||
libSymphonySearch.symSEEnsureFolderExists(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH);
|
||||
|
||||
if (!fs.existsSync(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH)) {
|
||||
log.send(logLevels.ERROR, 'User index folder not found');
|
||||
reject(new Error('User index folder not found'));
|
||||
return;
|
||||
}
|
||||
|
||||
libSymphonySearch.symSEMergePartialIndexAsync(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`, searchConfig.FOLDERS_CONSTANTS.TEMP_BATCH_INDEX_FOLDER, (err, res) => {
|
||||
libSymphonySearch.symSEMainRAMIndexToFSIndexAsync(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`, (err, res) => {
|
||||
if (err) {
|
||||
log.send(logLevels.ERROR, 'Error merging the index ->' + err);
|
||||
reject(new Error(err));
|
||||
return;
|
||||
}
|
||||
Search.deleteIndexFolders(searchConfig.FOLDERS_CONSTANTS.TEMP_BATCH_INDEX_FOLDER);
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
@ -197,13 +195,8 @@ class Search {
|
||||
throw new Error('Library not initialized');
|
||||
}
|
||||
|
||||
if (!fs.existsSync(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH)) {
|
||||
log.send(logLevels.ERROR, 'User index folder not found');
|
||||
throw new Error('User index folder not found');
|
||||
}
|
||||
|
||||
this.isRealTimeIndexing = true;
|
||||
return libSymphonySearch.symSEIndexRealTimeAsync(searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX, message, (err, result) => {
|
||||
return libSymphonySearch.symSEIndexRealtimeRAMAsync(message, (err, result) => {
|
||||
this.isRealTimeIndexing = false;
|
||||
if (err) {
|
||||
log.send(logLevels.ERROR, 'RealTime Indexing: error -> ' + err);
|
||||
@ -213,16 +206,6 @@ class Search {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reading a json file
|
||||
* for the demo search app only
|
||||
* @param {String} batch
|
||||
* @returns {Promise}
|
||||
*/
|
||||
readJson(batch) {
|
||||
return readFile.call(this, batch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypting the index after the merging the index
|
||||
* to the main user index
|
||||
@ -259,12 +242,6 @@ class Search {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`) || !fs.existsSync(searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX)) {
|
||||
log.send(logLevels.ERROR, 'Index folder does not exist.');
|
||||
reject(new Error('Index folder does not exist.'));
|
||||
return;
|
||||
}
|
||||
|
||||
let q = Search.constructQuery(query, senderIds, threadIds, fileType);
|
||||
|
||||
if (q === undefined) {
|
||||
@ -301,9 +278,9 @@ class Search {
|
||||
_sortOrder = searchConfig.SORT_BY_SCORE;
|
||||
}
|
||||
|
||||
const returnedResult = libSymphonySearch.symSESearch(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`, searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX, q, startDateTime.toString(), endDateTime.toString(), _offset, _limit, _sortOrder);
|
||||
const returnedResult = libSymphonySearch.symSERAMIndexSearch(q, startDateTime.toString(), endDateTime.toString(), _offset, _limit, _sortOrder);
|
||||
try {
|
||||
let ret = returnedResult.readCString();
|
||||
let ret = ref.readCString(returnedResult);
|
||||
resolve(JSON.parse(ret));
|
||||
} finally {
|
||||
libSymphonySearch.symSEFreeResult(returnedResult);
|
||||
@ -324,20 +301,14 @@ class Search {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`)) {
|
||||
log.send(logLevels.ERROR, 'Index folder does not exist.');
|
||||
reject(new Error('Index folder does not exist.'));
|
||||
return;
|
||||
}
|
||||
|
||||
libSymphonySearch.symSEGetLastMessageTimestampAsync(`${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME_PATH}_${this.userId}`, (err, res) => {
|
||||
libSymphonySearch.symSEMainRAMIndexGetLastMessageTimestampAsync((err, res) => {
|
||||
if (err) {
|
||||
log.send(logLevels.ERROR, 'Error getting the index timestamp ->' + err);
|
||||
reject(new Error(err));
|
||||
}
|
||||
const returnedResult = res;
|
||||
try {
|
||||
let ret = returnedResult.readCString();
|
||||
let ret = ref.readCString(returnedResult);
|
||||
resolve(ret);
|
||||
} finally {
|
||||
libSymphonySearch.symSEFreeResult(returnedResult);
|
||||
@ -346,10 +317,8 @@ class Search {
|
||||
});
|
||||
}
|
||||
|
||||
/*eslint class-methods-use-this: ["error", { "exceptMethods": ["deleteRealTimeFolder"] }] */
|
||||
deleteRealTimeFolder() {
|
||||
Search.deleteIndexFolders(searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX);
|
||||
Search.indexValidator(searchConfig.FOLDERS_CONSTANTS.TEMP_REAL_TIME_INDEX);
|
||||
libSymphonySearch.symSEClearRealtimeRAMIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -541,20 +510,22 @@ class Search {
|
||||
|
||||
/**
|
||||
* Removing all the folders and files inside the data folder
|
||||
* @param location
|
||||
*/
|
||||
static deleteIndexFolders(location) {
|
||||
if (fs.existsSync(location)) {
|
||||
fs.readdirSync(location).forEach((file) => {
|
||||
let curPath = location + "/" + file;
|
||||
if (fs.lstatSync(curPath).isDirectory()) {
|
||||
Search.deleteIndexFolders(curPath);
|
||||
} else {
|
||||
fs.unlinkSync(curPath);
|
||||
}
|
||||
});
|
||||
fs.rmdirSync(location);
|
||||
static deleteIndexFolders() {
|
||||
function removeFiles(filePath) {
|
||||
if (fs.existsSync(filePath)) {
|
||||
fs.readdirSync(filePath).forEach((file) => {
|
||||
let curPath = filePath + "/" + file;
|
||||
if (fs.lstatSync(curPath).isDirectory()) {
|
||||
removeFiles(curPath);
|
||||
} else {
|
||||
fs.unlinkSync(curPath);
|
||||
}
|
||||
});
|
||||
fs.rmdirSync(filePath);
|
||||
}
|
||||
}
|
||||
removeFiles(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH);
|
||||
}
|
||||
|
||||
}
|
||||
@ -562,39 +533,16 @@ class Search {
|
||||
/**
|
||||
* Deleting the data index folder
|
||||
* when the app is closed/signed-out/navigates
|
||||
* isEncryption if that is true
|
||||
* will not clear the memory index
|
||||
*/
|
||||
function deleteIndexFolder() {
|
||||
Search.deleteIndexFolders(searchConfig.FOLDERS_CONSTANTS.INDEX_PATH);
|
||||
function deleteIndexFolder(isEncryption) {
|
||||
if (!isEncryption) {
|
||||
libSymphonySearch.symSEDestroy();
|
||||
}
|
||||
Search.deleteIndexFolders();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the file from the msgjson
|
||||
* this is only for the demo page
|
||||
* @param batch
|
||||
* @returns {Promise<Array>}
|
||||
*/
|
||||
function readFile(batch) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let dirPath = path.join(searchConfig.FOLDERS_CONSTANTS.EXEC_PATH, isMac ? '..' : '', 'msgsjson', batch);
|
||||
let messageFolderPath = isDevEnv ? path.join('./msgsjson', batch) : dirPath;
|
||||
let files = fs.readdirSync(messageFolderPath);
|
||||
this.messageData = [];
|
||||
files.forEach((file) => {
|
||||
let tempPath = path.join(messageFolderPath, file);
|
||||
let data = fs.readFileSync(tempPath, "utf8");
|
||||
if (data) {
|
||||
try {
|
||||
this.messageData.push(JSON.parse(data));
|
||||
} catch (err) {
|
||||
reject(new Error(err))
|
||||
}
|
||||
} else {
|
||||
reject(new Error('Error reading batch'))
|
||||
}
|
||||
});
|
||||
resolve(this.messageData);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creating launch agent for handling the deletion of
|
||||
|
@ -53,7 +53,6 @@ const libraryPaths = {
|
||||
const folderPaths = {
|
||||
INDEX_PATH: indexFolderPath,
|
||||
TEMP_BATCH_INDEX_FOLDER: indexFolderPath + '/temp_batch_indexes',
|
||||
TEMP_REAL_TIME_INDEX: indexFolderPath + '/temp_realtime_index',
|
||||
PREFIX_NAME: 'search_index',
|
||||
PREFIX_NAME_PATH: indexFolderPath + '/search_index',
|
||||
EXEC_PATH: execPath,
|
||||
|
@ -13,6 +13,22 @@ const symLucyIndexerPtr = ref.refType(symLucyIndexer);
|
||||
* using the node-ffi
|
||||
*/
|
||||
let libSymphonySearch = ffi.Library(searchConfig.LIBRARY_CONSTANTS.SEARCH_LIBRARY_PATH, {
|
||||
|
||||
//New Memory Indexing API
|
||||
'symSE_index_main_RAM': ['int', [ 'string' ] ],
|
||||
'symSE_index_realtime_RAM': ['int', [ 'string' ] ],
|
||||
'symSE_main_RAM_index_to_FS_index': ['int', [ 'string' ] ],
|
||||
'symSE_realtime_RAM_index_to_FS_index': ['int', [ 'string' ] ],
|
||||
'symSE_main_RAM_index_get_last_message_timestamp': ['char *', [] ],
|
||||
'symSE_RAM_index_search': ['char *', [ 'string', 'string', 'string', 'int', 'int', 'int' ] ],
|
||||
'symSE_main_FS_index_to_RAM_index': ['int', [ 'string' ] ],
|
||||
'symSE_realtime_FS_index_to_RAM_index': ['int', [ 'string' ] ],
|
||||
'symSE_clear_realtime_RAM_index': ['int', [] ],
|
||||
'symSE_clear_main_RAM_index': ['int', [] ],
|
||||
'symSE_delete_messages_from_RAM_index': ['int', [ 'string', 'string', 'string' ] ],
|
||||
'symSE_destroy': ['int', [] ],
|
||||
|
||||
|
||||
//init
|
||||
'symSE_init': ['void', []],
|
||||
'symSE_remove_folder': ['int', ['string']],
|
||||
@ -40,6 +56,32 @@ let libSymphonySearch = ffi.Library(searchConfig.LIBRARY_CONSTANTS.SEARCH_LIBRAR
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
// New Memory Indexing API
|
||||
symSEIndexMainRAM: libSymphonySearch.symSE_index_main_RAM,
|
||||
symSEIndexRealtimeRAM: libSymphonySearch.symSE_index_realtime_RAM,
|
||||
symSEMainRAMIndexToFSIndex: libSymphonySearch.symSE_main_RAM_index_to_FS_index,
|
||||
symSERealtimeRAMIndexToFSIndex: libSymphonySearch.symSE_realtime_RAM_index_to_FS_index,
|
||||
symSEMainRAMIndexGetLastMessageTimestamp: libSymphonySearch.symSE_main_RAM_index_get_last_message_timestamp,
|
||||
symSERAMIndexSearch: libSymphonySearch.symSE_RAM_index_search,
|
||||
symSEMainFSIndexToRAMIndex: libSymphonySearch.symSE_main_FS_index_to_RAM_index,
|
||||
symSERealtimeFSIndexToRAMIndex: libSymphonySearch.symSE_realtime_FS_index_to_RAM_index,
|
||||
symSEClearRealtimeRAMIndex: libSymphonySearch.symSE_clear_realtime_RAM_index,
|
||||
symSEClearMainRAMIndex: libSymphonySearch.symSE_clear_main_RAM_index,
|
||||
symSEDeleteMessagesFromRAMIndex: libSymphonySearch.symSE_delete_messages_from_RAM_index,
|
||||
symSEDestroy: libSymphonySearch.symSE_destroy,
|
||||
symSEIndexMainRAMAsync: libSymphonySearch.symSE_index_main_RAM.async,
|
||||
symSEIndexRealtimeRAMAsync: libSymphonySearch.symSE_index_realtime_RAM.async,
|
||||
symSEMainRAMIndexToFSIndexAsync: libSymphonySearch.symSE_main_RAM_index_to_FS_index.async,
|
||||
symSERealtimeRAMIndexToFSIndexAsync: libSymphonySearch.symSE_realtime_RAM_index_to_FS_index.async,
|
||||
symSEMainRAMIndexGetLastMessageTimestampAsync: libSymphonySearch.symSE_main_RAM_index_get_last_message_timestamp.async,
|
||||
symSERAMIndexSearchAsync: libSymphonySearch.symSE_RAM_index_search.async,
|
||||
symSEMainFSIndexToRAMIndexAsync: libSymphonySearch.symSE_main_FS_index_to_RAM_index.async,
|
||||
symSERealtimeFSIndexToRAMIndexAsync: libSymphonySearch.symSE_realtime_FS_index_to_RAM_index.async,
|
||||
symSEClearRealtimeRAMIndexAsync: libSymphonySearch.symSE_clear_realtime_RAM_index.async,
|
||||
symSEClearMainRAMIndexAsync: libSymphonySearch.symSE_clear_main_RAM_index.async,
|
||||
symSEDeleteMessagesFromRAMIndexAsync: libSymphonySearch.symSE_delete_messages_from_RAM_index.async,
|
||||
symSEDestroyAsync: libSymphonySearch.symSE_destroy.async,
|
||||
|
||||
symSEInit: libSymphonySearch.symSE_init,
|
||||
symSERemoveFolder: libSymphonySearch.symSE_remove_folder,
|
||||
symSEEnsureIndexExists: libSymphonySearch.symSE_ensure_index_exists,
|
||||
@ -69,5 +111,5 @@ module.exports = {
|
||||
symSEDeleteMessagesAsync: libSymphonySearch.symSE_delete_messages.async,
|
||||
symSECommitIndexAsync: libSymphonySearch.symSE_commit_index.async,
|
||||
symSEFreeResultAsync: libSymphonySearch.symSE_free_results.async,
|
||||
symSEGetLastMessageTimestampAsync: libSymphonySearch.symSE_get_last_message_timestamp.async
|
||||
symSEGetLastMessageTimestampAsync: libSymphonySearch.symSE_get_last_message_timestamp.async,
|
||||
};
|
@ -7,12 +7,12 @@ const { isMac } = require('../utils/misc.js');
|
||||
* Utils to validate users config data and
|
||||
* available disk space to enable electron search
|
||||
*/
|
||||
/*eslint class-methods-use-this: ["error", { "exceptMethods": ["checkFreeSpace"] }] */
|
||||
class SearchUtils {
|
||||
|
||||
constructor() {
|
||||
this.path = searchConfig.FOLDERS_CONSTANTS.USER_DATA_PATH;
|
||||
this.indexVersion = searchConfig.INDEX_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns true if the available disk space
|
||||
* is more than the constant MINIMUM_DISK_SPACE
|
||||
@ -20,14 +20,15 @@ class SearchUtils {
|
||||
*/
|
||||
checkFreeSpace() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let userDataPath = searchConfig.FOLDERS_CONSTANTS.USER_DATA_PATH;
|
||||
if (!isMac) {
|
||||
try {
|
||||
this.path = this.path.substring(0, 1);
|
||||
userDataPath = userDataPath.substring(0, 1);
|
||||
} catch (e) {
|
||||
reject(new Error('Invalid Path : ' + e));
|
||||
}
|
||||
}
|
||||
checkDiskSpace(this.path, resolve, reject);
|
||||
checkDiskSpace(userDataPath, resolve, reject);
|
||||
});
|
||||
}
|
||||
|
||||
@ -120,7 +121,7 @@ function createUserConfigFile(userId, data) {
|
||||
let createStream = fs.createWriteStream(searchConfig.FOLDERS_CONSTANTS.USER_CONFIG_FILE);
|
||||
if (userData) {
|
||||
if (!userData.indexVersion) {
|
||||
userData.indexVersion = searchConfig.INDEX_VERSION;
|
||||
userData.indexVersion = this.indexVersion;
|
||||
}
|
||||
try {
|
||||
userData = JSON.stringify(userData);
|
||||
@ -146,7 +147,7 @@ function updateConfig(userId, data, resolve, reject) {
|
||||
let userData = data;
|
||||
|
||||
if (userData && !userData.indexVersion) {
|
||||
userData.indexVersion = searchConfig.INDEX_VERSION;
|
||||
userData.indexVersion = this.indexVersion;
|
||||
}
|
||||
|
||||
let configPath = searchConfig.FOLDERS_CONSTANTS.USER_CONFIG_FILE;
|
||||
|
@ -7,6 +7,7 @@ let userConfigDir = null;
|
||||
|
||||
let searchConfig;
|
||||
let SearchApi;
|
||||
let libSymphonySearch;
|
||||
|
||||
jest.mock('electron', function() {
|
||||
return {
|
||||
@ -37,9 +38,6 @@ describe('Tests for Search', function() {
|
||||
let userId;
|
||||
let key;
|
||||
let dataFolderPath;
|
||||
let realTimeIndexPath;
|
||||
let tempBatchPath;
|
||||
let launchAgent;
|
||||
let currentDate = new Date().getTime();
|
||||
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;
|
||||
@ -48,28 +46,32 @@ describe('Tests for Search', function() {
|
||||
userId = 12345678910112;
|
||||
key = 'jjjehdnctsjyieoalskcjdhsnahsadndfnusdfsdfsd=';
|
||||
|
||||
executionPath = path.join(__dirname, 'library');
|
||||
if (isWindowsOS) {
|
||||
executionPath = path.join(__dirname, '..', 'library');
|
||||
}
|
||||
userConfigDir = path.join(__dirname, '..');
|
||||
executionPath = path.join(__dirname, 'library');
|
||||
if (isWindowsOS) {
|
||||
executionPath = path.join(__dirname, '..', 'library');
|
||||
}
|
||||
userConfigDir = path.join(__dirname, '..');
|
||||
libSymphonySearch = require('../js/search/searchLibrary.js');
|
||||
searchConfig = require('../js/search/searchConfig.js');
|
||||
let root = path.join(userConfigDir, `${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME}_${userId}.enc`);
|
||||
if (fs.existsSync(root)) {
|
||||
fs.unlinkSync(root);
|
||||
}
|
||||
const { Search } = require('../js/search/search.js');
|
||||
SearchApi = new Search(userId, key);
|
||||
|
||||
searchConfig = require('../js/search/searchConfig.js');
|
||||
const { Search } = require('../js/search/search.js');
|
||||
SearchApi = new Search(userId, key);
|
||||
launchAgent = require('../js/search/utils/search-launchd.js');
|
||||
realTimeIndexPath = path.join(userConfigDir, 'data', 'temp_realtime_index');
|
||||
tempBatchPath = path.join(userConfigDir, 'data', 'temp_batch_indexes');
|
||||
dataFolderPath = path.join(userConfigDir, 'data');
|
||||
if (fs.existsSync(dataFolderPath)) {
|
||||
deleteIndexFolders(dataFolderPath);
|
||||
}
|
||||
done();
|
||||
libSymphonySearch.symSEDestroy();
|
||||
dataFolderPath = path.join(userConfigDir, 'data');
|
||||
if (fs.existsSync(dataFolderPath)) {
|
||||
deleteIndexFolders(dataFolderPath)
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
afterAll(function (done) {
|
||||
setTimeout(function () {
|
||||
|
||||
libSymphonySearch.symSEDestroy();
|
||||
deleteIndexFolders(dataFolderPath);
|
||||
let root = path.join(userConfigDir, `${searchConfig.FOLDERS_CONSTANTS.PREFIX_NAME}_${userId}.enc`);
|
||||
if (fs.existsSync(root)) {
|
||||
@ -83,12 +85,15 @@ describe('Tests for Search', function() {
|
||||
}, 3000);
|
||||
});
|
||||
|
||||
function deleteIndexFolders(location) {
|
||||
function deleteIndexFolders(location, isEncryption) {
|
||||
if (!isEncryption) {
|
||||
libSymphonySearch.symSEDestroy();
|
||||
}
|
||||
if (fs.existsSync(location)) {
|
||||
fs.readdirSync(location).forEach(function(file) {
|
||||
let curPath = path.join(location, file);
|
||||
if (fs.lstatSync(curPath).isDirectory()) {
|
||||
deleteIndexFolders(curPath);
|
||||
deleteIndexFolders(curPath, true);
|
||||
} else {
|
||||
fs.unlinkSync(curPath);
|
||||
}
|
||||
@ -123,13 +128,9 @@ describe('Tests for Search', function() {
|
||||
});
|
||||
|
||||
it('should exist index folder', function() {
|
||||
expect(fs.existsSync(path.join(userConfigDir, 'data', 'search_index_12345678910112'))).toBe(true);
|
||||
expect(fs.existsSync(realTimeIndexPath)).toBe(true);
|
||||
expect(fs.existsSync(path.join(userConfigDir, 'data', 'search_index_12345678910112'))).toBe(false);
|
||||
});
|
||||
|
||||
it('should not exist index folder', function() {
|
||||
expect(fs.existsSync(tempBatchPath)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Batch indexing process tests', function () {
|
||||
@ -165,7 +166,6 @@ describe('Tests for Search', function() {
|
||||
}];
|
||||
const indexBatch = jest.spyOn(SearchApi, 'indexBatch');
|
||||
SearchApi.indexBatch(JSON.stringify(messages)).then(function () {
|
||||
expect(fs.existsSync(tempBatchPath)).toBe(true);
|
||||
expect(indexBatch).toHaveBeenCalledWith(JSON.stringify(messages));
|
||||
done();
|
||||
});
|
||||
@ -232,28 +232,22 @@ describe('Tests for Search', function() {
|
||||
it('should match messages length after batch indexing', function (done) {
|
||||
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
|
||||
SearchApi.searchQuery('it works', [], [], '', undefined, undefined, 25, 0, 0).then(function (res) {
|
||||
expect(res.messages.length).toEqual(0);
|
||||
expect(res.messages.length).toEqual(3);
|
||||
expect(searchQuery).toHaveBeenCalled();
|
||||
done()
|
||||
});
|
||||
});
|
||||
|
||||
it('should merge batch index to user index', function (done) {
|
||||
const mergeIndexBatches = jest.spyOn(SearchApi, 'mergeIndexBatches');
|
||||
SearchApi.mergeIndexBatches().then(function () {
|
||||
expect(fs.existsSync(tempBatchPath)).toBe(false);
|
||||
expect(mergeIndexBatches).toHaveBeenCalled();
|
||||
const memoryIndexToFSIndex = jest.spyOn(SearchApi, 'memoryIndexToFSIndex');
|
||||
SearchApi.memoryIndexToFSIndex().then(function () {
|
||||
expect(memoryIndexToFSIndex).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should match messages length after batch indexing', function (done) {
|
||||
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
|
||||
SearchApi.searchQuery('it works', [], [], '', undefined, undefined, 25, 0, 0).then(function (res) {
|
||||
expect(res.messages.length).toEqual(3);
|
||||
expect(searchQuery).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
it('should exist data folder after ram index to fs index', function () {
|
||||
expect(fs.existsSync(dataFolderPath)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -280,7 +274,6 @@ describe('Tests for Search', function() {
|
||||
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
|
||||
SearchApi.searchQuery('realtime working', ["71811853189212"], ["Au8O2xKHyX1LtE6zW019GX///rZYegAtdA=="], '', undefined, undefined, 25, 0, 0).then(function (res) {
|
||||
expect(res.messages.length).toEqual(3);
|
||||
expect(fs.existsSync(realTimeIndexPath)).toBe(true);
|
||||
expect(searchQuery).toHaveBeenCalled();
|
||||
done();
|
||||
})
|
||||
@ -309,8 +302,6 @@ describe('Tests for Search', function() {
|
||||
|
||||
SearchApi.searchQuery('isRealTimeIndexing', [], [], '', undefined, undefined, 25, 0, 0).then(function (res) {
|
||||
expect(res.messages.length).toEqual(0);
|
||||
expect(fs.existsSync(realTimeIndexPath)).toBe(true);
|
||||
|
||||
done();
|
||||
});
|
||||
}, 6000)
|
||||
@ -378,7 +369,6 @@ describe('Tests for Search', function() {
|
||||
it('should delete realtime index', function () {
|
||||
const deleteRealTimeFolder = jest.spyOn(SearchApi, 'deleteRealTimeFolder');
|
||||
SearchApi.deleteRealTimeFolder();
|
||||
expect(fs.existsSync(realTimeIndexPath)).toBe(true);
|
||||
expect(deleteRealTimeFolder).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@ -425,13 +415,14 @@ describe('Tests for Search', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should not get the latest timestamp', function (done) {
|
||||
it('should be equal to 0000000000000', function (done) {
|
||||
const getLatestMessageTimestamp = jest.spyOn(SearchApi, 'getLatestMessageTimestamp');
|
||||
deleteIndexFolders(dataFolderPath);
|
||||
SearchApi.getLatestMessageTimestamp().catch(function (err) {
|
||||
expect(err).toEqual(new Error('Index folder does not exist.'));
|
||||
libSymphonySearch.symSEClearMainRAMIndex();
|
||||
libSymphonySearch.symSEClearRealtimeRAMIndex();
|
||||
SearchApi.getLatestMessageTimestamp().then(function (res) {
|
||||
expect(getLatestMessageTimestamp).toHaveBeenCalled();
|
||||
expect(getLatestMessageTimestamp).toHaveBeenCalledTimes(3);
|
||||
expect(res).toEqual('0000000000000');
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -479,26 +470,25 @@ describe('Tests for Search', function() {
|
||||
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
|
||||
SearchApi.searchQuery('works', [], [], '', '', '', 2, 0, 0).then(function (res) {
|
||||
expect(res.messages.length).toBe(2);
|
||||
expect(searchQuery).toHaveBeenCalledTimes(7);
|
||||
expect(searchQuery).toHaveBeenCalledTimes(6);
|
||||
expect(searchQuery).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should search fails index folder not fund', function (done) {
|
||||
deleteIndexFolders(dataFolderPath);
|
||||
setTimeout(function () {
|
||||
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
|
||||
SearchApi.searchQuery('it works', [], [], '', '', '', 25, 0, 0).catch(function (err) {
|
||||
expect(err).toEqual(new Error('Index folder does not exist.'));
|
||||
expect(searchQuery).toHaveBeenCalledTimes(8);
|
||||
expect(searchQuery).toHaveBeenCalled();
|
||||
SearchApi = undefined;
|
||||
const { Search } = require('../js/search/search.js');
|
||||
SearchApi = new Search(userId, key);
|
||||
done();
|
||||
})
|
||||
}, 3000);
|
||||
it('should search fails result cleared', function (done) {
|
||||
libSymphonySearch.symSEClearMainRAMIndex();
|
||||
libSymphonySearch.symSEClearRealtimeRAMIndex();
|
||||
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
|
||||
SearchApi.searchQuery('it works', [], [], '', '', '', 25, 0, 0).then(function (res) {
|
||||
expect(res.messages.length).toBe(0);
|
||||
expect(searchQuery).toHaveBeenCalledTimes(7);
|
||||
expect(searchQuery).toHaveBeenCalled();
|
||||
SearchApi = undefined;
|
||||
const { Search } = require('../js/search/search.js');
|
||||
SearchApi = new Search(userId, key);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should search fails query is undefined', function (done) {
|
||||
@ -531,5 +521,52 @@ describe('Tests for Search', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should index for testing quote', function (done) {
|
||||
let messages = [{
|
||||
messageId: "Jc+4K8RtPxHJfyuDQU9atX///qN3KHYXdA==",
|
||||
threadId: "Au8O2xKHyX1LtE6zW019GX///rZYegAtdA==",
|
||||
ingestionDate: currentDate.toString(),
|
||||
senderId: "71811853189212",
|
||||
chatType: "CHATROOM",
|
||||
isPublic: "false",
|
||||
sendingApp: "lc",
|
||||
text: "quote search"
|
||||
}, {
|
||||
messageId: "Jc+4K8RtPxHJfyuDQU9atX///qN3KHYXdA==",
|
||||
threadId: "Au8O2xKHyX1LtE6zW019GX///rZYegAtdA==",
|
||||
ingestionDate: currentDate.toString(),
|
||||
senderId: "71811853189212",
|
||||
chatType: "CHATROOM",
|
||||
isPublic: "false",
|
||||
sendingApp: "lc",
|
||||
text: "search"
|
||||
}];
|
||||
const indexBatch = jest.spyOn(SearchApi, 'indexBatch');
|
||||
SearchApi.indexBatch(JSON.stringify(messages)).then(function () {
|
||||
expect(indexBatch).toHaveBeenCalledWith(JSON.stringify(messages));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should search without quote', function (done) {
|
||||
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
|
||||
SearchApi.searchQuery('search', [], [], undefined, '', '', 25, 0, 0).then(function (res) {
|
||||
expect(res.messages.length).toEqual(2);
|
||||
expect(searchQuery).toHaveBeenCalled();
|
||||
expect(searchQuery).toHaveBeenCalledTimes(4);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should quote search', function (done) {
|
||||
const searchQuery = jest.spyOn(SearchApi, 'searchQuery');
|
||||
SearchApi.searchQuery('\"quote search\"', [], [], undefined, '', '', 25, 0, 0).then(function (res) {
|
||||
expect(res.messages.length).toEqual(1);
|
||||
expect(searchQuery).toHaveBeenCalled();
|
||||
expect(searchQuery).toHaveBeenCalledTimes(5);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -65,14 +65,14 @@ describe('Tests for Search Utils', function() {
|
||||
it('should return error', function (done) {
|
||||
const checkFreeSpace = jest.spyOn(SearchUtilsAPI, 'checkFreeSpace');
|
||||
if (isMac) {
|
||||
SearchUtilsAPI.path = undefined;
|
||||
searchConfig.FOLDERS_CONSTANTS.USER_DATA_PATH = undefined;
|
||||
SearchUtilsAPI.checkFreeSpace().catch(function (err) {
|
||||
expect(err).toEqual(new Error("Please provide path"));
|
||||
expect(checkFreeSpace).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
SearchUtilsAPI.path = undefined;
|
||||
searchConfig.FOLDERS_CONSTANTS.USER_DATA_PATH = undefined;
|
||||
SearchUtilsAPI.checkFreeSpace().catch(function (err) {
|
||||
expect(err).toBeTruthy();
|
||||
expect(checkFreeSpace).toHaveBeenCalled();
|
||||
@ -85,7 +85,7 @@ describe('Tests for Search Utils', function() {
|
||||
const checkFreeSpace = jest.spyOn(SearchUtilsAPI, 'checkFreeSpace');
|
||||
SearchUtilsAPI.path = './tp';
|
||||
if (isWindowsOS) {
|
||||
SearchUtilsAPI.path = 'A://test';
|
||||
searchConfig.FOLDERS_CONSTANTS.USER_DATA_PATH = 'A://test';
|
||||
searchConfig.LIBRARY_CONSTANTS.FREE_DISK_SPACE = path.join(__dirname, '..',
|
||||
"node_modules/electron-utils/FreeDiskSpace/bin/Release/FreeDiskSpace.exe");
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ const { buildNumber } = require('../../package');
|
||||
const electronVersion = require('../../package').devDependencies.electron;
|
||||
const bluebird = require('bluebird');
|
||||
|
||||
const SEARCH_API_VERSION = '2.0.0';
|
||||
|
||||
let app = new Application({});
|
||||
|
||||
describe('Tests for getVersionInfo API', () => {
|
||||
@ -56,14 +58,16 @@ describe('Tests for getVersionInfo API', () => {
|
||||
'#api-version',
|
||||
'#container-identifier',
|
||||
'#container-ver',
|
||||
'#build-number'
|
||||
'#build-number',
|
||||
'#search-api-ver'
|
||||
]).mapSeries((string) => {
|
||||
return app.client.getText(string)
|
||||
}).then((values) => {
|
||||
expect(values[ 0 ]).toBe('1.0.0');
|
||||
expect(values[ 0 ]).toBe('2.0.0');
|
||||
expect(values[ 1 ]).toBe('Electron');
|
||||
expect(values[ 2 ]).toBe(electronVersion);
|
||||
expect(values[ 3 ]).toBe(buildNumber);
|
||||
expect(values[ 4 ]).toBe(SEARCH_API_VERSION);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user