Skip to content
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

Preparation to merge initial revision of sisbasekt #3

Draft
wants to merge 44 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
40e39ce
[core] Add basic feature set
alikindsys Jun 21, 2022
d823034
Add starting API details
alikindsys Jul 17, 2022
099d79e
Add information for systems
alikindsys Jul 17, 2022
e0ab065
Add `sisbase-commands` subproject
alikindsys Jul 18, 2022
9919363
Add more design details for `sisbase-commands`
alikindsys Jul 20, 2022
82c0a76
Clarify which overload
alikindsys Jul 23, 2022
d204545
Add goals section
alikindsys Jul 23, 2022
86b93d2
Remove reduntant abstraction section
alikindsys Jul 23, 2022
34a510b
Add explanation on "fat bot"
alikindsys Jul 23, 2022
91039ec
Add `sisbase-types` shared dependency
alikindsys Jul 23, 2022
0059861
Remove unecessary "Uses" section on project outline
alikindsys Jul 23, 2022
86bab14
Add "Uses" section
alikindsys Jul 23, 2022
2506190
Remove features related to commands
alikindsys Jul 23, 2022
ba3c173
Add note on prefix handling
alikindsys Jul 23, 2022
a3201e4
Add note on Discord Connection
alikindsys Jul 23, 2022
38e234e
Add "Lifetime Description" section
alikindsys Jul 23, 2022
48fbec5
Move "Commands" section to commands.md
alikindsys Jul 23, 2022
f257c3f
Move "System" section to core.md
alikindsys Jul 23, 2022
6a3d630
Repurpose `sisbase-api`
alikindsys Jul 23, 2022
e61fa83
Remove reference to Kord
alikindsys Jul 23, 2022
942a9e7
Update `sisbase-commands` description
alikindsys Jul 23, 2022
f600d0f
Merge branch 'sisbasekt-reordering' into sisbasekt
alikindsys Jul 23, 2022
b32551e
Add "Project Structure" section
alikindsys Jul 23, 2022
aabf536
Add "Usage" section
alikindsys Jul 23, 2022
92b2067
Add missing packages to package structure
alikindsys Jul 23, 2022
fc33f85
Add "Other Types" section
alikindsys Jul 23, 2022
2cedbb6
Add "Annotations" section
alikindsys Jul 23, 2022
7966fd2
Add note on "Backend Agnostic"
alikindsys Jul 23, 2022
8e74767
Add mod_json.md
alikindsys Jul 24, 2022
4a332f2
Add "Configuration / Metadata" section
alikindsys Jul 24, 2022
cd5a2e9
Add Dependencies section
alikindsys Aug 1, 2022
51699cb
Add Dependencies section
alikindsys Aug 1, 2022
79033de
Add `api` to Uses section
alikindsys Aug 1, 2022
ee1f9d6
Rename Uses section to Dependencies
alikindsys Aug 1, 2022
5eeaa0d
Move "Developing extensions" section to `core.md`
alikindsys Aug 1, 2022
320644f
[Idea] Add "`RequireApiVersion` deriving automatically"
alikindsys Aug 1, 2022
15cf55f
Make `Developing Extensions` a section
alikindsys Aug 1, 2022
b2fd1ac
Add `systems.md`
alikindsys Aug 1, 2022
1243725
Move `Systems` section to `system.md`
alikindsys Aug 1, 2022
154b271
Add "Dependency Management" section
alikindsys Aug 1, 2022
d1c2467
Move "Dependency Management" section to `core.md`
alikindsys Aug 1, 2022
feb4b41
Add `koin` dependency
alikindsys Aug 1, 2022
3cc3b7a
Add "Metadata" section
alikindsys Aug 1, 2022
8b6c0b3
Add "Discord API Version Compatibility" header
alikindsys Aug 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions sisbasekt.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@
`Type: Metaproject`
Kotlin discord bot framework using the lessons learned by developing sisbase.net

## Uses
[`Kord`](https://github.com/kordlib/kord) - **Discord Library Wrapper**
[`pf4j`](https://github.com/pf4j/pf4j) - **Plugin Framework**

## Subprojects
[`sisbase-core`](sisbasekt/core.md) - Fabric-like extension manager.
[`sisbase-api`](sisbasekt/api.md) - Api for writing sisbase extensions.
[`sisbase-api`](sisbasekt/api.md) - A collection of interfaces representing the Discord API Spec.
[`sisbase-commands`](sisbasekt/commands.md) - Command Library.
[`sisbase-types`](sisbasekt/types.md) - Shared discord types.

## Rationale
Learning [`kotlin-coroutines`](https://github.com/Kotlin/kotlinx.coroutines).
Expand All @@ -17,3 +15,37 @@ Simplifying discord bot creation by centralizing all the boilerplate in a single

Future proofing code by having an easy-to-update path for extensions since all low-level bookkeeping is delegated to the manager.

## Goals

- Extensibility

The library should be as extensible as possible as to allow advanced extension authors to have all tools necessary to implement their already existing code into an extension.

- Easy upgrade path

If discord changes their API, upgrading a sisbasekt bot would be as easy as updating the `sisbase-core.jar` loader.
If an extension author updates their extension, upgrading it would be as easy as replacing the `extensions/extension.jar` file.
If someone decides to port their "fat bot"<sup>1</sup> into a sisbase extension the path should be as clear as possible.

<sup>1</sup>- Bots which embed the discord library with them.

- Modularity

Extension writers should only import what they need.
E.g. If they already have their own solutions for command handling there would be no need to use `sisbase-commands`.

- Backend Agnostic

In order to explain why this is a goal, a bit of history is required.
Between 2019 and 2021 I had to swap between discord libraries constanly in order to keep my bots up-to-date with the latest API revision (at least 4 times [Discord4J -> discord.py -> DSharpPlus -> Discord.Net]), it was a complete pain and involved rewriting all of my bots' code (since in most cases the code is tied to the library).
Some libraries had a very slow update cycle and had a "bleeding edge" fork where "experiments" (like keeping the Discord API version up-to-date, for some wierd reason) were done and you were forced to add a separate source and keep track of that, leading to "Update Framework Version" commits being way too frequent.
Some libraries were propperly maintained but their design goals were incompatible with my use case and lacked the flexibility necessary to create personalized solutions to even prefix handling (which if you ever made anything more complex then a single-guild bot is a necessity).
Some other libraries just were left in the dust with no one to take care of them.
While some libraries never left the beta phase.

**Developing bots shouldn't require you to pray that your flavour of library is updated.**
If the library you're using dies, just *swap to a different one*, **no code changes required**.
Make the choice of the backing a mere ~runtime detail~. Your code shall run the same on Discord4j and Kord.

*Note:
Thanks to @wffirilat for bringing this to my attention, wouldn't have thougth about this on my own!*
35 changes: 35 additions & 0 deletions sisbasekt/api.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
# sisbase-api
`Type: Subproject`
Subproject of: [`SisbaseKT`](../sisbasekt.md)

A collection of interfaces representing the Discord API Spec.
Implemented by `Backends`.

## Dependencies
[types](types.md)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Features section

## Project Structure
`org.sisbase.sisbase-api`
Base package

`org.sisbase.sisbase-api.rest`
High level wrapper for Discord's Rest API

alikindsys marked this conversation as resolved.
Show resolved Hide resolved
`org.sisbase.sisbase-api.gateway`
High level wrapper for Discord's Gateway

## Usage

### Implementing a Backend
Backends are the actual libraries that connect to discord.
An example of a valid backend would be Discord4J.

To implement a gateway backend, extend `GatewayBackend`
To implement a rest backend, extend `RestBackend`
To implement a backend that supports both, extend `AbstractBackend`

```kt
package org.siscode.sisbasekt-backends.discord4j
class Discord4JBackend() : AbstractBackend {
public restBackend = Discord4JRest();
public gatewaybackend = Discord4JGateway()
}
```
Comment on lines +31 to +37
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code snippet is non-descriptive and only duplicates the text above it.


132 changes: 132 additions & 0 deletions sisbasekt/commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# sisbase-commands
`Type: Subproject`
Subproject of: [`SisbaseKT`](../sisbasekt.md)

Command library.

Implemented as an extension. Users can use `sisbase-commands` optionally for command handling, but can also use their own command handling solutions if they so desire.

## Dependencies
[core](core.md)

## Commands
Simple interactions with the user caused by a direct call to them.

Has the following attributes:

| Field | Type | Description |
|---------------|----------|---------------------------------------------------------------------------------|
| `name` | String | Name of the command |
| `description` | String? | A short description of the command |
| `user` | User | The user that called the command |
| `channel` | Channel | The channel on which the command was called |
| `guild` | Guild? | The guild on which the command was called |

### Text-based
The third-party command system, based on detecting commands from messages sent on a given discord channel.
Has an extensive permission system since the code is fully controlled by the library.
Requires a system that checks every message for a valid command.

Extends the base attributes with:

| Field | Type | Description |
|----------|----------------|-------------------------------------------------------------------------------------------------------------|
| `checks` | [Precondition] | An array with all checks done to the text command by the permission engine, or an empty array if none exist |
| `group` | Group? | The group the command is a part of |
| `alias` | [String] | An array containing all aliases to the command, or an empty array if none exist |

### Slash
Discord's native command system, supercedes text-based commands but has a limit of how many commands can be registered and require modifying the application.
Does not require a system since discord dispatches the command to the bot via the gateway.

**Currently, support for slash commands isn't planned, this could change in the future**


## Structure of the `sisbase-commands` extension

### Persistent Data
The extension must hold a `Registry` for commands during the bot lifetime.

The `Registry` must safeguard against command conflicts, as **only one command** (including overloads) can be registered for a given `Identifier`.

`Identifier`s are a way to uniquely identify a given command and they include the following fields:

| Field | Type | Description | Observations |
|----------------------|--------|----------------------------------------------------|----------------------------------------------------------|
| `source` | String | The id of the extension that registers the command | Automatically set based on the extension's metadata file |
| `fullyQualifiedName` | String | The full command path for a given command | Automatically set once the command is registered |

An example of a `Identifier` is given below:

Command is called as `/help`
```yml
source: "your-bot"
command: "help"
identifier: "your-bot::help"
```

Command is called as `/group subcommand`
```yml
source: "your-bot"
command: "group/subcommand"
identifier: "your-bot::group/subcommand"
```

Identifiers don't care about command overloads, this is handled internally by the library.
Mismatches for commands with equal names registered by the same extension will cause the extension to be rejected. (DUPLICATE COMMAND)
Mismatches for commands with equal names registered by different extensions are to be resolved manually on the `overrides.yml` file. (COMMAND MISMATCH)

Example of a mismatch:

`ext-a` registers a `help` command. -> `ext-a::help`
`ext-b` also registers a `help` command. -> `ext-b::help`

Console Output:
```
[Sisbase-Commands] Command Mismatch Detected:

The following commands will become unavailable until their mismatches are resolved.

for `help`:

`ext-a@version` registered `help`
`ext-b@version` registered `help`

Please resolve all command mismatches on `overrides.yaml.`

[Sisbase-Commands] Disabled `ext-a::help` due to: COMMAND MISMATCH
[Sisbase-Commands] Disabled `ext-b::help` due to: COMMAND MISMATCH
```

Example of a duplicate command:

`ext-a` registers a `help` command. -> `ext-a::help`
`ext-a` later registers a `help` command. -> `ext-a::help`

Console Output:
```
[Sisbase-Commands] Duplicate Command Detected:

The following extensions will become unavailable until their duplicate commands are removed.

for `ext-a`:

Duplicate `help` command registered.

Please contact the extension authors to remove the duplicate commands.

[Sisbase-Commands] Disabled `ext-a` due to: DUPLICATE COMMAND

```

On the case of a critical failure that leads to the extension being shutdown (or on the case of it being disabled)
all commands and hooks **must be unregistered** immediately.

### Required hooks

For command parsing:

| Hook | Usage |
|--------------------------|---------------------------------------------------------------------------------------------------------------|
| `onMessageReceived` | Used for parsing the message contents, building the CommandContext, and forwarding the data to the call site. |
| `onGuildMessageReceived` | Same as `onMessageReceived` |
129 changes: 129 additions & 0 deletions sisbasekt/core.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,132 @@
`Type: Subproject`
Subproject of : [`SisbaseKT`](../sisbasekt.md)

Discord extension manager

## Dependencies
[PF4J](https://github.com/pf4j/pf4j) - Plugin Framework
[api](api.md)

## Features

- Systems `META!`
User-provided lifelong processes. Uses range from repeating jobs bound to a timer or connectors between the bot and an external data source.
Systems can be manually unregistered during runtime via the `core.Manager::unregister` API.
Systems can depend on other systems using the `@DependsOn` annotation.
Systems can add "soft dependencies" using the `@Extends` annotation.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Define how.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Annotations section

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check feasibility of @Extends annotation


- System Handling `Important!`
Handles the lifetime of systems.
The system lifetime is as follows:
- `PreInit`
- `Init` - **Required**
- `PostInit`
- `Disable` - **Required**

- Discord Connection `Important!`
*Note: Actual discord connection will be delegated to a `Backend`*
- Secret Storage
- Configuration API
- Prefix Handling `Important!`
*Note: Prefix handling must be open to the user as easily allow configuring an external prefix handler.*


## Systems
alikindsys marked this conversation as resolved.
Show resolved Hide resolved
Long-term, usually lifelong background procedures.

Has the following attributes:

| Field | Type | Description |
|----------------------|---------------------|-------------------------------------------------------------------------------------------------------------------|
| `name` | String | Name of the system |
| `description` | String? | A short description of the system |
| `expansions` | [Expansion] | An array of system expansions, or an empty array if none exist |
| `OnInit` | suspend fun | A function that runs on the start of the system's lifetime |
| `OnDisable` | suspend fun | A function that runs on the end of the system's lifetime |
| `CheckPreconditions` | suspend fun -> Bool | A function that runs before `OnInit`, if it returns `true` the system is loaded, otherwise the system is skipped. |


### Repeating
Background procedures that repeat at a set interval given by the user.

Implemented by a `Expansion` that has the following attributes:
| Field | Type | Description |
|-------------|-------------|-----------------------------------------------------------------|
| `timeout` | Duration | The period of time that will be used for repeating the function |
| `OnElapsed` | suspend fun | The function that will be repeated once `timeout` elapses |

### Discord-linked
Background procedures that reads/writes data to Discord.

Implemented by a `Expansion` that has the following attributes:
| Field | Type | Description |
|-----------------|----------------------|----------------------------------------------------------------------|
| `applyToClient` | suspend fun (Client) | A function that will be applied to the discord client after `OnInit` |

### Single-instance
Simple background procedures that are set once the bot loads and are used in other parts of the bot.


## Sisbase-Core Lifetime Description

### Initialization

1. Loads configuration
2. Start the Backend
3. Wait for the Backend to connect to Discord
4. Loads Extensions

### Lost Connection to Backend

5. Stops all Extensions
6. Try restarting the backend 3 times
7. Shuts down the backend
8. Shuts down

### Connection to Backend is Resumed

5. Loads Extensions

## Configuration / Metadata

alikindsys marked this conversation as resolved.
Show resolved Hide resolved
See the [sisbasekt.mod.json Documentation](./mod_json.md) for information about the Metadata File Format.

-! IDEA: Due to an change in [`types`](types.md), deriving the `@RequireApiVersion` automatically could be done.
-: [Not Required] [FUTURE]

## Developing extensions

alikindsys marked this conversation as resolved.
Show resolved Hide resolved
In order to make sure your extension is propperly supported, extension writers can annotate their systems with `@RequireApiVersion`.

On the case of a backend not supporting said version that system will be disabled and a warning will be printed to the console.

```
[Sisbase-Loader] Dependency Error:
Extension `id@version` requires
Discord API Version >= X
Backend `id@version` provides
Discord API Version == Z

The following features will be disabled:
- Feature Name [Description]
- Feature Name [Description]

Please update or change the backend to get these features back.
```

Extension writers can also add `require-api-version` to the `mod.json` metadata file.

On the case of a backend not supporting said version the extension won't be loaded and an error will be printed to the console.

```
[Sisbase-Loader] Critical Dependency Failure:
Extension `id@version` requires
Discord API Version >= X
Backend `id@version` provides
Discord API Version == Z

Extension `id@version` is now disabled.

Please update or change the backend to get `id` back.
```

alikindsys marked this conversation as resolved.
Show resolved Hide resolved
Loading