Skip to content

Commit

Permalink
Merge pull request #163 from electron-userland/get-sync
Browse files Browse the repository at this point in the history
Add a .getSync() function
  • Loading branch information
jviotti committed Apr 13, 2021
2 parents 3f23e43 + 3e36d27 commit 26ffd0e
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 5 deletions.
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ electron-json-storage
[![Build Status](https://travis-ci.org/electron-userland/electron-json-storage.svg?branch=master)](https://travis-ci.org/electron-userland/electron-json-storage)
[![Build status](https://ci.appveyor.com/api/projects/status/ulwk1nnh7l8209xg/branch/master?svg=true)](https://ci.appveyor.com/project/electron-userland/electron-json-storage/branch/master)

[Electron](http://electron.atom.io) lacks an easy way to persist and read user settings for your application. `electron-json-storage` implements an API somehow similar to [localStorage](https://developer.mozilla.org/en/docs/Web/API/Window/localStorage) to write and read JSON objects to/from the operating system application data directory, as defined by `app.getPath('userData')`.
[Electron](http://electron.atom.io) lacks an easy way to persist and read user settings for your application. `electron-json-storage` implements an API somewhat similar to [localStorage](https://developer.mozilla.org/en/docs/Web/API/Window/localStorage) to write and read JSON objects to/from the operating system application data directory, as defined by `app.getPath('userData')`.

Related modules:

Expand All @@ -35,7 +35,7 @@ When loaded in renderer processes, this module will try to make use of

Electron 10 now [defaults `enableRemoteModule` to
false](https://www.electronjs.org/docs/breaking-changes#default-changed-enableremotemodule-defaults-to-false),
which means that `electron-json-storage` will not be able to calculate a data path by default.
which means that `electron-json-storage` will be able to calculate a data path by default.

The solution is to manually call `storage.setDataPath()` before reading or
writing any values or setting `enableRemoteModule` to `true`.
Expand All @@ -49,6 +49,7 @@ Documentation
* [.setDataPath(directory)](#module_storage.setDataPath)
* [.getDataPath()](#module_storage.getDataPath) ⇒ <code>String</code>
* [.get(key, [options], callback)](#module_storage.get)
* [.getSync(key, [options])](#module_storage.getSync)
* [.getMany(keys, [options], callback)](#module_storage.getMany)
* [.getAll([options], callback)](#module_storage.getAll)
* [.set(key, json, [options], callback)](#module_storage.set)
Expand Down Expand Up @@ -142,6 +143,28 @@ storage.get('foobar', function(error, data) {
console.log(data);
});
```
<a name="module_storage.getSync"></a>

### storage.getSync(key, [options])
See `.get()`.

**Kind**: static method of [<code>storage</code>](#module_storage)
**Summary**: Read user data (sync)
**Access**: public

| Param | Type | Description |
| --- | --- | --- |
| key | <code>String</code> | key |
| [options] | <code>Object</code> | options |
| [options.dataPath] | <code>String</code> | data path |

**Example**
```js
const storage = require('electron-json-storage');

var data = storage.getSync('foobar');
console.log(data);
```
<a name="module_storage.getMany"></a>

### storage.getMany(keys, [options], callback)
Expand Down
2 changes: 1 addition & 1 deletion doc/README.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ electron-json-storage
[![Build Status](https://travis-ci.org/electron-userland/electron-json-storage.svg?branch=master)](https://travis-ci.org/electron-userland/electron-json-storage)
[![Build status](https://ci.appveyor.com/api/projects/status/ulwk1nnh7l8209xg/branch/master?svg=true)](https://ci.appveyor.com/project/electron-userland/electron-json-storage/branch/master)

[Electron](http://electron.atom.io) lacks an easy way to persist and read user settings for your application. `electron-json-storage` implements an API somehow similar to [localStorage](https://developer.mozilla.org/en/docs/Web/API/Window/localStorage) to write and read JSON objects to/from the operating system application data directory, as defined by `app.getPath('userData')`.
[Electron](http://electron.atom.io) lacks an easy way to persist and read user settings for your application. `electron-json-storage` implements an API somewhat similar to [localStorage](https://developer.mozilla.org/en/docs/Web/API/Window/localStorage) to write and read JSON objects to/from the operating system application data directory, as defined by `app.getPath('userData')`.

Related modules:

Expand Down
55 changes: 53 additions & 2 deletions lib/lock.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ exports.lock = function(file, callback, times) {
lockFile.lock(file, lockOptions, function(error) {
if (error && error.code === 'EPERM' && times < 10) {
setTimeout(function() {
exports.unlock(file, callback, times + 1);
exports.lock(file, callback, times + 1);
}, 1000);
return;
}
Expand All @@ -68,7 +68,34 @@ exports.lock = function(file, callback, times) {
};

/**
* @summary Unlock a lock file
* @summary Create a lock file (sync)
* @function
* @public
*
* @param {String} file - lock file
*
* @example
* lock.lockSync('foo.lock');
*/
exports.lockSync = function(file, times) {
times = times || 0;

try {
lockFile.lockSync(file, {
stale: lockOptions.stale,
retries: lockOptions.retries
});
} catch (error) {
if (error && error.code === 'EPERM' && times < 10) {
return exports.lockSync(file, times + 1);
}

throw error;
}
};

/**
* @summary Unlock a locked file
* @function
* @public
*
Expand Down Expand Up @@ -96,3 +123,27 @@ exports.unlock = function(file, callback, times) {
return callback(error);
});
};

/**
* @summary Unlock a locked file (sync)
* @function
* @public
*
* @param {String} file - lock file
*
* @example
* lock.unlockSync('foo.lock');
*/
exports.unlockSync = function(file, times) {
times = times || 0;

try {
lockFile.unlockSync(file);
} catch (error) {
if (error && error.code === 'EPERM' && times < 10) {
return exports.unlockSync(file, times + 1);
}

throw error;
}
};
63 changes: 63 additions & 0 deletions lib/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@ const readFile = function(fileName, callback, times) {
});
};

const readFileSync = function(fileName, times) {
times = times || 0;
try {
return fs.readFileSync(fileName);
} catch (error) {
if (error.code === 'ENOENT') {
return JSON.stringify({});
}

if (error.code === 'EPERM' && times < 10) {
return readFileSync(fileName, times + 1);
}

throw error;
}
};

/**
* @summary Get the default data path
* @function
Expand Down Expand Up @@ -193,6 +210,52 @@ exports.get = function(key, options, callback) {
});
};

/**
* @summary Read user data (sync)
* @function
* @public
*
* @description
* See `.get()`.
*
* @param {String} key - key
* @param {Object} [options] - options
* @param {String} [options.dataPath] - data path
*
* @example
* const storage = require('electron-json-storage');
*
* var data = storage.getSync('foobar');
* console.log(data);
*/
exports.getSync = function(key, options) {
options = options || {};
var fileName = utils.getFileName(key, {
dataPath: options.dataPath
});

mkdirp.sync(path.dirname(fileName));

try {
lock.lockSync(utils.getLockFileName(fileName));
} catch (error) {
if (error && error.code === 'EEXIST') {
return exports.getSync(key, options);
}

throw error;
}

var object = readFileSync(fileName);
lock.unlockSync(utils.getLockFileName(fileName));

try {
return JSON.parse(object);
} catch (error) {
throw new Error('Invalid data: ' + object);
}
};

/**
* @summary Read many user data keys
* @function
Expand Down
96 changes: 96 additions & 0 deletions tests/storage.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@ describe('Electron JSON Storage', function() {
});
});

it('should yield an error if no key (sync)', function(done) {
chai.expect(() => {
storage.getSync(null);
}).to.throw('Missing key');
done();
});

it('should yield an error if key is not a string', function(done) {
storage.get(123, function(error, data) {
chai.expect(error).to.be.an.instanceof(Error);
Expand All @@ -169,6 +176,13 @@ describe('Electron JSON Storage', function() {
});
});

it('should yield an error if key is not a string (sync)', function(done) {
chai.expect(() => {
storage.getSync(123);
}).to.throw('Invalid key');
done();
});

it('should yield an error if key is a blank string', function(done) {
storage.get(' ', function(error, data) {
chai.expect(error).to.be.an.instanceof(Error);
Expand All @@ -178,6 +192,13 @@ describe('Electron JSON Storage', function() {
});
});

it('should yield an error if key is a blank string (sync)', function(done) {
chai.expect(() => {
storage.getSync(' ');
}).to.throw('Invalid key');
done();
});

describe('given the user data path does not exist', function() {

beforeEach(function(done) {
Expand All @@ -196,6 +217,12 @@ describe('Electron JSON Storage', function() {
});
});

it('should return an empty object for any key (sync)', function(done) {
var data = storage.getSync('foobarbaz');
chai.expect(data).to.deep.equal({});
done();
});

});

describe('given the same key stored in multiple data paths', function(done) {
Expand Down Expand Up @@ -233,6 +260,15 @@ describe('Electron JSON Storage', function() {
});
});

it('should initially return the key in the default location (sync)', function(done) {
var data = storage.getSync('foo');
chai.expect(data).to.deep.equal({
location: 'default'
});

done();
});

it('should return the new value given the right data path', function(done) {
storage.setDataPath(this.newDataPath);
storage.get('foo', function(error, data) {
Expand All @@ -245,6 +281,16 @@ describe('Electron JSON Storage', function() {
});
});

it('should return the new value given the right data path (sync)', function(done) {
storage.setDataPath(this.newDataPath);
var data = storage.getSync('foo');
chai.expect(data).to.deep.equal({
location: 'new'
});

done();
});

it('should return nothing given the wrong data path', function(done) {
if (os.platform() === 'win32') {
storage.setDataPath('C:\\tmp\\electron-json-storage');
Expand All @@ -263,6 +309,25 @@ describe('Electron JSON Storage', function() {
done();
});
});

it('should return nothing given the wrong data path (sync)', function(done) {
if (os.platform() === 'win32') {
storage.setDataPath('C:\\tmp\\electron-json-storage');
} else {
storage.setDataPath('/tmp/electron-json-storage');
}

async.waterfall([
storage.clear,
function(callback) {
callback(null, storage.getSync('foo'));
}
], function(error, data) {
chai.expect(error).to.not.exist;
chai.expect(data).to.deep.equal({});
done();
});
});
});

describe('given stored keys with a colon', function() {
Expand Down Expand Up @@ -301,6 +366,12 @@ describe('Electron JSON Storage', function() {
});
});

it('should yield the data (sync)', function(done) {
var data = storage.getSync('foo');
chai.expect(data).to.deep.equal({ data: 'hello world' });
done();
});

it('should yield the data if explicitly passing the extension', function(done) {
storage.get('foo.json', function(error, data) {
chai.expect(error).to.not.exist;
Expand All @@ -309,6 +380,12 @@ describe('Electron JSON Storage', function() {
});
});

it('should yield the data if explicitly passing the extension (sync)', function(done) {
var data = storage.getSync('foo.json');
chai.expect(data).to.deep.equal({ data: 'hello world' });
done();
});

it('should yield an empty object given an incorrect key', function(done) {
storage.get('foobarbaz', function(error, data) {
chai.expect(error).to.not.exist;
Expand All @@ -317,6 +394,12 @@ describe('Electron JSON Storage', function() {
});
});

it('should yield an empty object given an incorrect key (sync)', function(done) {
var data = storage.getSync('foobarbaz');
chai.expect(data).to.deep.equal({});
done();
});

});

describe('given invalid stored JSON', function() {
Expand All @@ -340,6 +423,13 @@ describe('Electron JSON Storage', function() {
});
});

it('should yield an error (sync)', function(done) {
chai.expect(() => {
return storage.getSync('foo');
}).to.throw('Invalid data: Foo{bar}123');
done();
});

});

describe('given a non-existent user data path', function() {
Expand All @@ -365,6 +455,12 @@ describe('Electron JSON Storage', function() {
});
});

it('should return an empty object for any key (sync)', function(done) {
var result = storage.getSync('foo');
chai.expect(result).to.deep.equal({});
done();
});

});

});
Expand Down

0 comments on commit 26ffd0e

Please sign in to comment.