-
-
Notifications
You must be signed in to change notification settings - Fork 31
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
[cache] Reimplementation to use the new core caches #191
Merged
florian-h05
merged 10 commits into
openhab:main
from
florian-h05:cache-core-reimplementation
Dec 11, 2022
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
3cc96bd
[cache] Change implementation to the core caches
florian-h05 306b6e9
[cache] Fix legacy cache access
florian-h05 3837ad8
[cache] Improve logging
florian-h05 1057480
[test] Test JSCache instead of exported methods
florian-h05 c02c23f
README: Explain private & shared caches
florian-h05 bfee379
[cache] Update type definitions
florian-h05 382e093
Update CHANGELOG
florian-h05 d1b3140
README: Mention automatic cancellation of timers in cache
florian-h05 3477c84
[cache] Fix swapped JSDoc comments
florian-h05 4afb37f
[cache] Add timer cancellation note to JSDoc
florian-h05 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,120 @@ | ||
/** | ||
* Shared cache namespace. | ||
* This namespace provides a default cache that can be used to set and retrieve objects that will be persisted between reloads of scripts. | ||
* | ||
* Cache namespace. | ||
* This namespace provides caches that can be used to set and retrieve objects that will be persisted between reloads of scripts. | ||
* @namespace cache | ||
*/ | ||
|
||
const cache = require('@runtime').sharedcache; | ||
const log = require('./log')('cache'); | ||
const { privateCache, sharedCache } = require('@runtime/cache'); // The new cache from core | ||
const addonSharedCache = require('@runtime').sharedcache; // The old cache from the adddon | ||
|
||
/** | ||
* Returns the value to which the specified key is mapped | ||
* | ||
* @example <caption>Get a previously set value with a default value (times = 0)</caption> | ||
* let counter = cache.get("counter", () => ({ "times": 0 })); | ||
* console.log("Count",counter.times++); | ||
* | ||
* @example <caption>Get a previously set object</caption> | ||
* let counter = cache.get("counter"); | ||
* if(counter == null){ | ||
* counter = {times: 0}; | ||
* cache.put("counter", counter); | ||
* } | ||
* console.log("Count",counter.times++); | ||
* | ||
* @memberof cache | ||
* @param {string} key the key whose associated value is to be returned | ||
* @param {function} [defaultSupplier] if the specified key is not already associated with a value, this function will return a default value | ||
* @returns {(*|null)} the current object for the supplied key, a default value if defaultSupplier is provided, or null | ||
*/ | ||
const get = function (key, defaultSupplier) { | ||
if (typeof defaultSupplier === 'function') { | ||
return cache.get(key, defaultSupplier); | ||
} else { | ||
return cache.get(key); | ||
} | ||
}; | ||
const coreCacheAvail = Java.isJavaObject(privateCache) && Java.isJavaObject(sharedCache); | ||
|
||
/** | ||
* Associates the specified value with the specified key | ||
* | ||
* @memberof cache | ||
* @param {string} key key with which the specified value is to be associated | ||
* @param {*} value value to be associated with the specified key | ||
* @returns {(*|null)} the previous value associated with null, or null if there was no mapping for key | ||
*/ | ||
const put = function (key, value) { | ||
return cache.put(key, value); | ||
const logDeprecationWarning = (funcName) => { | ||
console.warn(`"cache.${funcName}" has been deprecated and will be removed in a future release. Use "cache.private.${funcName}" or "cache.shared.${funcName}" instead. Visit the JavaScript Scripting Automation addon docs for more information about the cache.`); | ||
}; | ||
|
||
/** | ||
* Removes the mapping for a key from this map if it is present | ||
* | ||
* @memberof cache | ||
* @param {string} key key whose mapping is to be removed from the map | ||
* @returns {(*|null)} the previous value associated with key or null if there was no mapping for key | ||
* The {@link JSCache} can be used by to share information between subsequent runs of the same script or between scripts (depending on implementation). | ||
*/ | ||
const remove = function (key) { | ||
return cache.remove(key); | ||
}; | ||
class JSCache { | ||
/** | ||
* @param {*} valueCacheImpl an implementation of the Java {@link https://github.com/openhab/openhab-core/blob/main/bundles/org.openhab.core.automation.module.script.rulesupport/src/main/java/org/openhab/core/automation/module/script/rulesupport/shared/ValueCache.java ValueCache} interface | ||
* @param {boolean} [deprecated] | ||
* @hideconstructor | ||
*/ | ||
constructor (valueCacheImpl, deprecated = false) { | ||
this._valueCache = valueCacheImpl; | ||
this._deprecated = deprecated; | ||
} | ||
|
||
/** | ||
* Checks the mapping for a key from this map. | ||
* | ||
* @memberof cache | ||
* @param {string} key key whose mapping is to be checked in the map | ||
* @returns {boolean} whether the key has a mapping | ||
*/ | ||
const exists = function (key) { | ||
return get(key) !== null; | ||
}; | ||
/** | ||
* Returns the value to which the specified key is mapped. | ||
* | ||
* @param {string} key the key whose associated value is to be returned | ||
* @param {function} [defaultSupplier] if the specified key is not already associated with a value, this function will return a default value | ||
* @returns {*|null} the current object for the supplied key, a default value if defaultSupplier is provided, or null | ||
*/ | ||
get (key, defaultSupplier) { | ||
if (this._deprecated === true) logDeprecationWarning('get'); | ||
if (typeof defaultSupplier === 'function') { | ||
return this._valueCache.get(key, defaultSupplier); | ||
} else { | ||
return this._valueCache.get(key); | ||
} | ||
} | ||
|
||
/** | ||
* Associates the specified value with the specified key. | ||
* | ||
* @param {string} key key with which the specified value is to be associated | ||
* @param {*} value value to be associated with the specified key | ||
* @returns {*|null} the previous value associated with the key, or null if there was no mapping for key | ||
*/ | ||
put (key, value) { | ||
if (this._deprecated === true) logDeprecationWarning('put'); | ||
return this._valueCache.put(key, value); | ||
} | ||
|
||
/** | ||
* Removes the mapping for a key from this map if it is present. | ||
* | ||
* @param {string} key key whose mapping is to be removed from the cache | ||
* @returns {*|null} the previous value associated with the key or null if there was no mapping for key | ||
*/ | ||
remove (key) { | ||
if (this._deprecated === true) logDeprecationWarning('remove'); | ||
return this._valueCache.remove(key); | ||
} | ||
|
||
/** | ||
* Checks the mapping for a key from this map. | ||
* | ||
* @param {string} key key whose mapping is to be checked in the map | ||
* @returns {boolean} whether the key has a mapping | ||
*/ | ||
exists (key) { | ||
if (this._deprecated === true) logDeprecationWarning('exists'); | ||
return this._valueCache.get(key) !== null; | ||
} | ||
} | ||
|
||
let addonSharedJSCache; | ||
if (coreCacheAvail === true) { | ||
log.debug('Caches from core are available, enable legacy cache methods to keep the old API.'); | ||
addonSharedJSCache = new JSCache(sharedCache, true); | ||
} else { | ||
log.debug('Caches from core are unavailable, using the addon-provided cache.'); | ||
addonSharedJSCache = new JSCache(addonSharedCache); | ||
} | ||
|
||
module.exports = { | ||
get, | ||
put, | ||
remove, | ||
exists | ||
/** @deprecated */ | ||
get: (key, defaultSupplier) => { return addonSharedJSCache.get(key, defaultSupplier); }, | ||
/** @deprecated */ | ||
put: (key, value) => { return addonSharedJSCache.put(key, value); }, | ||
/** @deprecated */ | ||
remove: (key) => { return addonSharedJSCache.remove(key); }, | ||
/** @deprecated */ | ||
exists: (key) => { return addonSharedJSCache.exists(key); }, | ||
/** | ||
* Shared cache that is shared across all rules and scripts, it can therefore be accessed from any automation language. | ||
* The access to every key is tracked and the key is removed when all scripts that ever accessed that key are unloaded. | ||
* If the key that has been auto-removed stored a timer, that timer is cancelled. | ||
* | ||
* @memberof cache | ||
* @type JSCache | ||
*/ | ||
shared: (coreCacheAvail === true) ? new JSCache(sharedCache) : undefined, | ||
/** | ||
* Private cache for each script. | ||
* The private cache can only be accessed by the same script and is cleared when the script is unloaded. | ||
* You can use it to e.g. store timers or counters between subsequent runs of that script. | ||
* When the script is unloaded and the cache is cleared, all timers in the cache are cancelled. | ||
* | ||
* @memberof cache | ||
* @type JSCache | ||
*/ | ||
private: (coreCacheAvail === true) ? new JSCache(privateCache) : undefined, | ||
JSCache | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way we can get the ruleUID or filename to log out as part of this warning? At first some users may get hundreds or these warnings and knowing which rules they are coming from can help in prioritization in dealing with them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By using
console.warn
instead oflog.warn
we are logging to the logger name of the script/rule, so for file-based script toorg.openhab.automation.script.file.filename.js
and for UI toorg.openhab.automation.script.ui.ruleUid
.