Remove deprecated classes and static singleton-based architecture
This commit is contained in:
1 parent
54a27883d1
commit
b8786c8dc9
133 files changed
+4984
-1038
No files matched your search
+102
@@ -0,0 +1,102 @@
|
||||
# Event Handling & Routing
|
||||
|
||||
**Package:** `me.bobert.netneutrality.platform.event`
|
||||
**Primary class:** `EventsHandler`
|
||||
|
||||
`EventsHandler` is the single JDA `EventListener` registered on the `JDA` instance
|
||||
(`jda.addEventListener(new EventsHandler())` in `App.startup()`). It is the funnel through
|
||||
which **every** gateway event passes. Its job is to translate a raw JDA event into a
|
||||
[Context](contexts.md) and route that context to the correct subsystem.
|
||||
|
||||
## Listener registry
|
||||
|
||||
Listeners are held in a static, thread-safe map keyed by the JDA event class:
|
||||
|
||||
```java
|
||||
private static final Map<Class<? extends Event>, Function<? extends Event, Context>> listeners
|
||||
= new ConcurrentHashMap<>();
|
||||
```
|
||||
|
||||
Each entry is a **factory function**: given an event of that type, it returns a `Context` (or `null`).
|
||||
The map is populated once in a `static {}` block.
|
||||
|
||||
### `addListener` vs `addGenericListener`
|
||||
|
||||
- `addListener(Class<T>, Function<? super T, Context>)` — registers a factory that produces a
|
||||
`Context` to be routed onward (command or task flow).
|
||||
- `addGenericListener(Class<T>, Consumer<T>)` — registers a factory that runs a side-effecting
|
||||
consumer and returns `null`, so nothing is routed onward. This is the **lambda flow** for simple
|
||||
events.
|
||||
|
||||
## Registered events
|
||||
|
||||
| JDA event | Produces | Flow |
|
||||
|---|---|---|
|
||||
| `MessageReceivedEvent` (prefix match) | `MessageCommandContext` | Command |
|
||||
| `MessageReceivedEvent` (no prefix) | `MessageTaskContext` | Task |
|
||||
| `SlashCommandInteractionEvent` | `SlashCommandContext` | Command |
|
||||
| `UserContextInteractionEvent` | `UserMenuContext` | Command |
|
||||
| `MessageContextInteractionEvent` | `MessageMenuContext` | Command |
|
||||
| `ButtonInteractionEvent` | `ButtonTaskContext` | Task |
|
||||
| `ModalInteractionEvent` | `ModalTaskContext` | Task |
|
||||
| `MessageReactionAddEvent` | `EmojiTaskContext` | Task |
|
||||
| `GuildJoinEvent` | — (consumer) | Lambda |
|
||||
| `GuildLeaveEvent` | — (consumer) | Lambda |
|
||||
|
||||
### Message routing detail
|
||||
|
||||
For `MessageReceivedEvent` the factory:
|
||||
|
||||
1. Ignores messages authored by bots and webhook messages (returns `null`).
|
||||
2. Reads the configured prefix (`NETNEUTRALITY_BOT_PREFIX`, default `$`).
|
||||
3. If the trimmed message starts with the prefix → **`MessageCommandContext`** (command flow).
|
||||
4. Otherwise → **`MessageTaskContext`** (task flow). This lets ordinary messages participate in the
|
||||
task system, e.g. as a reply that advances a [step task](tasks.md#33-step-tasks).
|
||||
|
||||
### Guild lifecycle (lambda flow)
|
||||
|
||||
- `GuildJoinEvent` — resolves `GuildService.get(guild)`; if debug logging is enabled for that guild,
|
||||
sends a notice to the debug channel.
|
||||
- `GuildLeaveEvent` — `GuildService.get(guild).deleteGuild()` removes the guild's stored data.
|
||||
|
||||
## Dispatch algorithm
|
||||
|
||||
```java
|
||||
@Override
|
||||
public void onEvent(@Nonnull GenericEvent event) {
|
||||
handleEvent((Event) event);
|
||||
}
|
||||
|
||||
private void handleEvent(Event event) {
|
||||
Class<?> eventClass = event.getClass();
|
||||
while (eventClass != null) {
|
||||
if (listeners.containsKey(eventClass)) {
|
||||
Context context = listeners.get(eventClass).apply(event);
|
||||
if (context instanceof CommandContext c) handleCommand(c);
|
||||
if (context instanceof TaskContext t) handleTask(t);
|
||||
break;
|
||||
}
|
||||
eventClass = eventClass.getSuperclass(); // walk up the class hierarchy
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Key points:
|
||||
|
||||
- **Superclass walk** — if the exact event class is not registered, the handler walks up the
|
||||
superclass chain until it finds a match. This means a listener registered for a base event type
|
||||
also catches subclasses.
|
||||
- **Routing by context type** — the resulting object is routed purely by its runtime type:
|
||||
a `CommandContext` goes to `CommandProcessor.dispatch()`, a `TaskContext` goes to
|
||||
`TaskManager.getInstance().handle(context)`.
|
||||
- **`null` contexts** (bot messages, consumer-only events) are simply not routed anywhere.
|
||||
|
||||
## Extending the event system
|
||||
|
||||
To handle a new event type:
|
||||
|
||||
1. Add an `addListener(SomeEvent.class, SomeContext::new)` (or `addGenericListener(...)` for a
|
||||
consumer-only side effect) to the `static {}` block.
|
||||
2. If it should run the command or task flow, make the produced context extend
|
||||
[`CommandContext`](contexts.md#commandcontext) or [`TaskContext`](contexts.md#taskcontext)
|
||||
respectively.
|
||||
Reference in new issue
Block a user