-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add notifier for external plugins (#666)
Co-authored-by: pajlada <[email protected]>
- Loading branch information
Showing
23 changed files
with
685 additions
and
14 deletions.
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 |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# External Plugin Messaging | ||
|
||
Other Plugin Hub plugins can publish a `PluginMessage` via `EventBus#post` that instructs Dink to submit a webhook request. | ||
|
||
Users can opt-out of this capability by disabling `External Plugin Requests > Enable External Plugin Notifications`. | ||
|
||
Plugins can request that a screenshot is included with the notification, but users can also opt-out by | ||
setting `External Plugin Requests > Send Image` to `Never` (default: send image only when requested by the external plugin). | ||
|
||
Plugins can include urls for the webhook, otherwise Dink will utilize `External Webhook Override` | ||
(or `Primary Webhook URLs` if an external url override is not specified). | ||
|
||
Below we describe the payload structure for how plugins can customize the webhook body and include a full code example to streamline implementation. | ||
|
||
## Payload | ||
|
||
The `namespace` for the `PluginMessage` should be `dink` and the `name` should be `notify`. | ||
|
||
The `Map<String, Object>` that is supplied to `PluginMessage` will be converted into [`ExternalNotificationRequest`](../src/main/java/dinkplugin/domain/ExternalNotificationRequest.java). | ||
|
||
| Field | Required | Type | Description | | ||
| ---------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `text` | Y | String | The body text of the notification. This field supports templating (see `replacements` below) and by default `%USERNAME%` is an available replacement. | | ||
| `sourcePlugin` | Y | String | The human-facing name of the plugin submitting the webhook notification request. | | ||
| `urls` | N | List | A list of `okhttp3.HttpUrl`s that the notification should be sent to. | | ||
| `title` | N | String | The title for the Discord embed. | | ||
| `thumbnail` | N | String | A URL to an image for the thumbnail icon of the Discord embed. | | ||
| `imageRequested` | N | boolean | Whether dink should include a screenshot with the notification. | | ||
| `fields` | N | List | A list of [embed fields](https://discord.com/developers/docs/resources/message#embed-object-embed-field-structure). The contained objects should have `name` and `value` properties. | | ||
| `replacements` | N | Map | A map of strings to be replaced to objects containing `value` (and optionally `richValue`) that indicate what the template string should be replaced with for plain text and rich text. | | ||
| `metadata` | N | Map | A map of strings to any gson-serializable object to be included in the notification body for non-Discord consumers. | | ||
|
||
## Example | ||
|
||
The example below assumes you already have injected RuneLite's eventbus into your plugin like so: `private @Inject EventBus eventBus;` | ||
|
||
```java | ||
Map<String, Object> data = new HashMap<>(); | ||
data.put("sourcePlugin", "My Plugin Name"); | ||
data.put("text", "This is the primary content within the webhook. %USERNAME% will automatically be replaced with the player name and you can define your own template replacements like %XYZ%"); | ||
data.put("replacements", Map.of("%XYZ%", Replacement.ofText("sample replacement"))); | ||
data.put("title", "An optional embed title for your notification"); | ||
data.put("imageRequested", true); | ||
data.put("fields", List.of(new Field("sample key", "sample value"))); | ||
data.put("metadata", Map.of("custom key", "custom value")); | ||
data.put("urls", Arrays.asList(HttpUrl.parse("https://discord.com/api/webhooks/a/b"), HttpUrl.parse("https://discord.com/api/webhooks/c/d"))); | ||
|
||
PluginMessage dinkRequest = new PluginMessage("dink", "notify", data); | ||
eventBus.post(dinkRequest); | ||
``` | ||
|
||
### Useful Classes | ||
|
||
```java | ||
@Value | ||
@AllArgsConstructor | ||
public class Field { | ||
String name; | ||
String value; | ||
Boolean inline; | ||
|
||
public Field(String name, String value) { | ||
this(name, value, null); | ||
} | ||
} | ||
``` | ||
|
||
```java | ||
@Value | ||
public class Replacement { | ||
String value; | ||
String richValue; | ||
|
||
public static Replacement ofText(String value) { | ||
return new Replacement(value, null); | ||
} | ||
|
||
public static Replacement ofLink(String text, String link) { | ||
return new Replacement(text, String.format("[%s](%s)", text, link)); | ||
} | ||
|
||
public static Replacement ofWiki(String text, String searchPhrase) { | ||
return ofLink(text, "https://oldschool.runescape.wiki/w/Special:Search?search=" + UrlEscapers.urlPathSegmentEscaper().escape(searchPhrase)); | ||
} | ||
} | ||
``` |
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
39 changes: 39 additions & 0 deletions
39
src/main/java/dinkplugin/domain/ExternalNotificationRequest.java
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 |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package dinkplugin.domain; | ||
|
||
import dinkplugin.message.Field; | ||
import dinkplugin.message.templating.impl.SimpleReplacement; | ||
import lombok.Data; | ||
import okhttp3.HttpUrl; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.function.Supplier; | ||
import java.util.stream.Collectors; | ||
|
||
@Data | ||
public class ExternalNotificationRequest { | ||
|
||
private String sourcePlugin; | ||
private String text; | ||
private boolean imageRequested; | ||
private @Nullable String title; | ||
private @Nullable String thumbnail; | ||
private @Nullable List<Field> fields; | ||
private @Nullable Map<String, SimpleReplacement> replacements; | ||
private @Nullable Map<String, Object> metadata; | ||
private @Nullable List<HttpUrl> urls; | ||
|
||
public String getUrls(Supplier<String> defaultValue) { | ||
return urls != null | ||
? urls.stream().filter(Objects::nonNull).map(HttpUrl::toString).collect(Collectors.joining("\n")) | ||
: defaultValue.get(); | ||
} | ||
|
||
public List<Field> getFields() { | ||
return this.fields != null ? this.fields : Collections.emptyList(); | ||
} | ||
|
||
} |
17 changes: 17 additions & 0 deletions
17
src/main/java/dinkplugin/domain/ExternalScreenshotPolicy.java
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 |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package dinkplugin.domain; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@RequiredArgsConstructor | ||
public enum ExternalScreenshotPolicy { | ||
ALWAYS("Always"), | ||
REQUESTED("When requested"), | ||
NEVER("Never"); | ||
|
||
private final String displayName; | ||
|
||
@Override | ||
public String toString() { | ||
return this.displayName; | ||
} | ||
} |
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
Oops, something went wrong.