Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory Only Storage Option #102

Merged
merged 14 commits into from
Oct 3, 2024
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## xx.xx.xx
* Default max segmentation value count changed from 30 to 100
- Default max segmentation value count changed from 30 to 100
- Mitigated an issue where attempting to read a missing or empty file could result in the creation of an unintended empty file.

## 22.06.0
- Fixed a bug where remote config requests were rejected
Expand Down
31 changes: 23 additions & 8 deletions lib/countly-storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,20 @@ const fileStorage = {
},
storeRemove: function(key) {
delete __data[key];
var dir = path.resolve(__dirname, `${getStoragePath()}__${key}.json`);
fs.unlink(dir, (err) => {
if (err) {
cc.log(cc.logLevelEnums.ERROR, `storeRemove, Failed to remove file with key: [${key}]. Error: [${err}].`);
var filePath = path.resolve(__dirname, `${getStoragePath()}__${key}.json`);
fs.access(filePath, fs.constants.F_OK, (accessErr) => {
if (accessErr) {
cc.log(cc.logLevelEnums.WARNING, `storeRemove, No file found with key: [${key}]. Nothing to remove.`);
return;
}
fs.rmSync(filePath, { recursive: true, force: true }, (err) => {
AliRKat marked this conversation as resolved.
Show resolved Hide resolved
if (err) {
cc.log(cc.logLevelEnums.ERROR, `storeRemove, Failed to remove file with key: [${key}]. Error: [${err.message}].`);
}
else {
cc.log(cc.logLevelEnums.INFO, `storeRemove, Successfully removed file with key: [${key}].`);
}
});
});
},
};
Expand Down Expand Up @@ -181,15 +190,21 @@ var resetStorage = function() {
*/
var readFile = function(key) {
var dir = path.resolve(__dirname, `${getStoragePath()}__${key}.json`);

// try reading data file
var data;
try {
data = fs.readFileSync(dir);
data = fs.readFileSync(dir, 'utf8'); // read file as string
}
catch (ex) {
// there was no file, probably new init
data = null;
cc.log(cc.logLevelEnums.WARN, `readFile, File not found for key: [${key}]. Returning null.`);
return null; // early exit if file doesn't exist
}

// early exit if file is empty or whitespace
if (!data.trim()) {
cc.log(cc.logLevelEnums.WARN, `readFile, File is empty or contains only whitespace for key: [${key}]. Returning null.`);
return null;
}

try {
Expand All @@ -202,7 +217,7 @@ var readFile = function(key) {
// backup corrupted file data
fs.writeFile(path.resolve(__dirname, `${getStoragePath()}__${key}.${cc.getTimestamp()}${Math.random()}.json`), data, () => { });
// start with new clean object
data = null;
return null; // return null in case of corrupted data
}
return data;
};
Expand Down
34 changes: 25 additions & 9 deletions test/helpers/helper_functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ var path = require("path");
var assert = require("assert");
var fs = require("fs");
var Countly = require("../../lib/countly");
var CountlyStorage = require("../../lib/countly-storage");

// paths for convenience
var dir = path.resolve(__dirname, "../../");
var idDir = (`${dir}/data/__cly_id.json`);
var idTypeDir = (`${dir}/data/__cly_id_type.json`);
var eventDir = (`${dir}/data/__cly_event.json`);
var reqDir = (`${dir}/data/__cly_queue.json`);
var bulkEventDir = (`${dir}/bulk_data/__cly_bulk_event.json`);
Expand Down Expand Up @@ -39,24 +41,37 @@ function readRequestQueue(givenPath = null, isBulk = false) {
}
return a;
}
// queue files clearing logic
function doesFileStoragePathsExist(callback) {
fs.access(idDir, fs.constants.F_OK, (err1) => {
fs.access(idTypeDir, fs.constants.F_OK, (err2) => {
fs.access(eventDir, fs.constants.F_OK, (err3) => {
// If all err variables are null, all files exist
const allFilesExist = !err1 && !err2 && !err3;
callback(allFilesExist);
});
});
});
}
function clearStorage(keepID = false, isBulk = false, customDir = '') {
// Resets Countly
Countly.halt(true);
// Determine the directory based on isBulk or customDir
const eventDirectory = customDir || (isBulk ? bulkEventDir : eventDir);
const reqDirectory = customDir || (isBulk ? bulkQueueDir : reqDir);
// Remove event directory if it exists
if (fs.existsSync(eventDirectory)) {
fs.rmSync(eventDirectory, { recursive: true, force: true });
// Helper function to remove directory and files
function removeDir(directory) {
if (fs.existsSync(directory)) {
fs.rmSync(directory, { recursive: true, force: true });
}
}
// Remove event directory if it exists
removeDir(eventDirectory);
// Remove request directory if it exists
if (fs.existsSync(reqDirectory)) {
fs.rmSync(reqDirectory, { recursive: true, force: true });
}
removeDir(reqDirectory);
// Optionally keep the ID directory
if (!keepID && fs.existsSync(idDir)) {
fs.rmSync(idDir, { recursive: true, force: true });
if (!keepID) {
removeDir(idDir);
removeDir(idTypeDir);
}
}
/**
Expand Down Expand Up @@ -215,4 +230,5 @@ module.exports = {
sessionRequestValidator,
userDetailRequestValidator,
viewEventValidator,
doesFileStoragePathsExist,
};
19 changes: 17 additions & 2 deletions test/tests_storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,9 @@ describe("Storage Tests", () => {
clear_stored_device_id: true,
storage_type: StorageTypes.MEMORY,
});
hp.doesFileStoragePathsExist((exists) => {
assert.equal(false, exists);
});
assert.equal(storage.getStoragePath(), undefined);
assert.equal(storage.storeGet("cly_id", null), "Test-Device-Id");
assert.equal(storage.storeGet("cly_id_type", null), cc.deviceIdTypeEnums.DEVELOPER_SUPPLIED);
Expand All @@ -325,6 +328,9 @@ describe("Storage Tests", () => {
clear_stored_device_id: true,
storage_type: StorageTypes.MEMORY,
});
hp.doesFileStoragePathsExist((exists) => {
assert.equal(false, exists);
});
Countly.add_event(eventObj);
setTimeout(() => {
const storedData = storage.storeGet("cly_queue", null);
Expand All @@ -344,6 +350,9 @@ describe("Storage Tests", () => {
clear_stored_device_id: true,
storage_type: StorageTypes.MEMORY,
});
hp.doesFileStoragePathsExist((exists) => {
assert.equal(false, exists);
});
Countly.user_details(userDetailObj);
const storedData = storage.storeGet("cly_queue", null);
const userDetailsReq = storedData[0];
Expand All @@ -359,6 +368,9 @@ describe("Storage Tests", () => {
clear_stored_device_id: true,
storage_type: StorageTypes.MEMORY,
});
hp.doesFileStoragePathsExist((exists) => {
assert.equal(false, exists);
});
assert.equal(storage.getStoragePath(), undefined);
assert.equal(storage.storeGet("cly_id", null), Countly.get_device_id());
assert.equal(storage.storeGet("cly_id_type", null), Countly.get_device_id_type());
Expand All @@ -379,6 +391,9 @@ describe("Storage Tests", () => {
});
assert.equal(storage.getStoragePath(), undefined);
assert.equal(storage.getStorageType(), StorageTypes.MEMORY);
hp.doesFileStoragePathsExist((exists) => {
assert.equal(false, exists);
});

storage.initStorage();
assert.equal(storage.getStoragePath(), "../data/");
Expand All @@ -387,7 +402,7 @@ describe("Storage Tests", () => {
});

it("23- storeRemove Memory Only /no-init", (done) => {
storage.resetStorage();
hp.clearStorage();
storage.initStorage(null, StorageTypes.MEMORY);
assert.equal(storage.getStoragePath(), undefined);
assert.equal(storage.getStorageType(), StorageTypes.MEMORY);
Expand All @@ -400,7 +415,7 @@ describe("Storage Tests", () => {
});

it("24- storeRemove File Storage /no-init", (done) => {
storage.resetStorage();
hp.clearStorage();
storage.initStorage();
assert.equal(storage.getStoragePath(), "../data/");
assert.equal(storage.getStorageType(), StorageTypes.FILE);
Expand Down
Loading