Skip to content

Commit

Permalink
[udf] Unlock JavaScript for user-defined functions
Browse files Browse the repository at this point in the history
  • Loading branch information
amotl committed May 9, 2023
1 parent bad20a1 commit 51e0b0e
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ in progress
As per RFC 7568, SSLv3 has been deprecated in 2015 already.
- Tests: Add more test cases to increase mqttwarn core coverage to ~100%
- Improve example "Forward OwnTracks low-battery warnings to ntfy"
- [udf] Unlock JavaScript for user-defined functions


2023-04-28 0.34.0
Expand Down
27 changes: 27 additions & 0 deletions examples/owntracks-battery/mqttwarn-owntracks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
*
* Forward OwnTracks low-battery warnings to ntfy.
* https://mqttwarn.readthedocs.io/en/latest/examples/owntracks-battery/readme.html
*
*/

function owntracks_batteryfilter(topic, message) {
let ignore = true;
let data;
try {
data = JSON.parse(message);
} catch {
data = null;
}
if (data && "batt" in data && data["batt"] !== null) {
ignore = Number.parseFloat(data["batt"]) > 20
}

return ignore;
}

module.exports = {
"owntracks_batteryfilter": owntracks_batteryfilter,
};

console.log("Loaded JavaScript module.");
20 changes: 20 additions & 0 deletions examples/owntracks-battery/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,32 @@ a different URL, and make sure to restart mqttwarn afterwards.
targets = {'testdrive': 'http://localhost:5555/testdrive'}
```

### Using JavaScript
You can alternatively use JavaScript to implement user-defined functions, based on the
[JSPyBridge] package.

To try that, use the alternative `mqttwarn-owntracks.js` implementation by adjusting
the `functions` setting within the `[defaults]` section of your configuration.
```ini
[defaults]
functions = mqttwarn-owntracks.js
```

The JavaScript function `owntracks_batteryfilter()` implements the same rule as the
previous one, which was written in Python.

:::{literalinclude} mqttwarn-owntracks.js
:language: javascript
:::


### Backlog
:::{todo}
- [o] Define battery threshold level within the configuration file.
:::


[JSPyBridge]: https://pypi.org/project/javascript/
[Mosquitto]: https://mosquitto.org
[ntfy.sh]: https://ntfy.sh/
[OwnTracks]: https://owntracks.org
30 changes: 30 additions & 0 deletions mqttwarn/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,17 @@ def load_functions(filepath: t.Optional[str] = None) -> t.Optional[types.ModuleT

mod_name, file_ext = os.path.splitext(os.path.split(filepath)[-1])

logger.info(f"Loading functions module {mod_name} from {filepath}")

if file_ext.lower() == ".py":
py_mod = imp.load_source(mod_name, filepath)

elif file_ext.lower() == ".pyc":
py_mod = imp.load_compiled(mod_name, filepath)

elif file_ext.lower() in [".js", ".javascript"]:
py_mod = load_source_js(mod_name, filepath)

else:
raise ValueError("'{}' does not have the .py or .pyc extension".format(filepath))

Expand Down Expand Up @@ -251,3 +256,28 @@ def load_file(path: t.Union[str, Path], retry_tries=None, retry_interval=0.075,
except: # pragma: nocover
pass
return reader


def module_factory(name, variables):
"""
Create a synthetic Python module object.
Derived from:
https://www.oreilly.com/library/view/python-cookbook/0596001673/ch15s03.html
"""
module = imp.new_module(name)
module.__dict__.update(variables)
module.__file__ = "<synthesized>"
return module


def load_source_js(mod_name, filepath):
"""
Load a JavaScript module, and import its exported symbols into a synthetic Python module.
"""
import javascript

js_code = load_file(filepath, retry_tries=0).read().decode("utf-8")
module = {}
javascript.eval_js(js_code)
return module_factory(mod_name, module["exports"])
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"funcy<3",
"future>=0.18.0,<1",
"importlib-metadata; python_version<'3.8'",
"javascript==1!1.0.1",
"jinja2<4",
"paho-mqtt<2",
"requests<3",
Expand Down

0 comments on commit 51e0b0e

Please sign in to comment.