1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
# Objective
The NotifyTools provide a bidirectional messaging system between Experiments scripts and the WebExtension's background page (even with [e10s](https://developer.thunderbird.net/add-ons/updating/tb91/changes#thunderbird-is-now-multi-process-e-10-s) being enabled in Thunderbird Beta 86).

They allow to work on add-on uprades in smaller steps, as single calls (like `window.openDialog()`)
in the middle of legacy code can be replaced by WebExtension calls, by stepping out of the Experiment
and back in when the task has been finished.
More details can be found in [this update tutorial](https://github.com/thundernest/addon-developer-support/wiki/Tutorial:-Convert-add-on-parts-individually-by-using-a-messaging-system).
# Example
This repository includes the [NotifyToolsExample Add-On](https://github.com/thundernest/addon-developer-support/raw/master/auxiliary-apis/NotifyTools/notifyToolsExample.zip), showcasing how the NotifyTools can be used.
# Usage
Add the [NotifyTools API](https://github.com/thundernest/addon-developer-support/tree/master/auxiliary-apis/NotifyTools) to your add-on. Your `manifest.json` needs an entry like this:
```
"experiment_apis": {
"NotifyTools": {
"schema": "api/NotifyTools/schema.json",
"parent": {
"scopes": ["addon_parent"],
"paths": [["NotifyTools"]],
"script": "api/NotifyTools/implementation.js",
"events": ["startup"]
}
}
},
```
Additionally to the [NotifyTools API](https://github.com/thundernest/addon-developer-support/tree/master/auxiliary-apis/NotifyTools) the [notifyTools.js](https://github.com/thundernest/addon-developer-support/tree/master/scripts/notifyTools) script is needed as the counterpart in Experiment scripts.
**Note:** You need to adjust the `notifyTools.js` script and add your add-on ID at the top.
## Receiving notifications from Experiment scripts
Add a listener for the `onNotifyBackground` event in your WebExtension's background page:
```
messenger.NotifyTools.onNotifyBackground.addListener(async (info) => {
switch (info.command) {
case "doSomething":
//do something
let rv = await doSomething();
return rv;
break;
}
});
```
The `onNotifyBackground` event will receive and respond to notifications send from your Experiment scripts:
```
notifyTools.notifyBackground({command: "doSomething"}).then((data) => {
console.log(data);
});
```
Include the [notifyTools.js](https://github.com/thundernest/addon-developer-support/tree/master/scripts/notifyTools) script in your Experiment script to be able to use `notifyTools.notifyBackground()`. If you are injecting the script into a global Thunderbird window object, make sure to wrap it in your custom namespace, to prevent clashes with other add-ons.
**Note**: If multiple `onNotifyBackground` listeners are registered in the WebExtension's background page and more than one is returning data, the value
from the first one is returned to the Experiment. This may lead to inconsistent behavior, so make sure that for each
request only one listener is returning data.
## Sending notifications to Experiments scripts
Use the `notifyExperiment()` method to send a notification from the WebExtension's background page to Experiment scripts:
```
messenger.NotifyTools.notifyExperiment({command: "doSomething"}).then((data) => {
console.log(data)
});
```
The receiving Experiment script needs to include the [notifyTools.js](https://github.com/thundernest/addon-developer-support/tree/master/scripts/notifyTools) script and must setup a listener using the following methods:
### addListener(callback);
Adds a callback function, which is called when a notification from the WebExtension's background page has been received. The `addListener()` function returns an `id` which can be used to remove the listener again.
Example:
```
function doSomething(data) {
console.log(data);
return true;
}
let id = notifyTools.addListener(doSomething);
```
**Note**: NotifyTools currently is not 100% compatible with the behavior of
runtime.sendMessage. While runtime messaging is ignoring non-Promise return
values, NotifyTools only ignores `null`.
Why does this matter? Consider the following three listeners:
```
async function dominant_listener(data) {
if (data.type == "A") {
return { msg: "I should answer only type A" };
}
}
function silent_listener(data) {
if (data.type == "B") {
return { msg: "I should answer only type B" };
}
}
function selective_listener(data) {
if (data.type == "C") {
return Promise.resolve({ msg: "I should answer only type C" });
}
}
```
When all 3 listeners are registered for the runtime.onMessage event,
the dominant listener will always respond, even for `data.type != "A"` requests,
because it is always returning a Promise (it is an async function). The return
value of the silent listener is ignored, and the selective listener returns a
value just for `data.type == "C"`. But since the dominant listener also returns
`null` for these requests, the actual return value depends on which listener is faster
and/or was registered first.
All notifyTools listener however ignore only `null` return values (so `null` can
actually never be returned). The above dominant listener will only respond to
`type == "A"` requests, the silent listener will only respond to `type == "B"`
requests and the selective listener will respond only to `type == "C"` requests.
### removeListener(id)
Removes the listener with the given `id`.
Example:
```
notifyTools.removeListener(id);
```
### removeAllListeners()
You must remove all added listeners when your add-on is disabled/reloaded. Instead of calling `removeListener()` for each added listener, you may call `removeAllListeners()`.
### setAddOnId(add-on-id)
The `notifyTools.js` script needs to know the ID of your add-on to be able to listen for messages. You may either define the ID directly in the first line of the script, or set it using `setAddOnId()`.
|