GithubHelp home page GithubHelp logo

strawbrryflurry / watson Goto Github PK

View Code? Open in Web Editor NEW
33.0 4.0 1.0 5.6 MB

๐Ÿš€ Fast, scalable framework for building Discord applications

License: MIT License

TypeScript 99.58% JavaScript 0.42%
bot discord framework discordjs discord-bots watson typescript nodejs

watson's Introduction

A scalable Node.js framework for building Discord applications

NPM Version Package License NPM Downloads

Description

Watson is a framework for building scalable Discord application in Node.js. It uses TypeScript to provide an easy to use API to scale along with the growth and complexity of your app.

As an interface to the Discord API we use DiscordJS however we also plan to support other libraries in the future.

Usage

Please read the docs at watsonjs.io.

Credits and references

Hat fanart by: @maka_hayashi

The architecture of this project is inspired by NestJS

Misc

Git Commit Format

[๐Ÿš€] [Type] [Message]

Types:

  • ๐Ÿš€ [FEATURE] A new addition to the package
  • โœ [UPDATE] Update existing feature
  • ๐Ÿ”จ [FIX] Fixing a bug
  • ๐Ÿ“ [DOCS] Adding comments, documentation..
  • ๐Ÿ—‘ [REMOVED] Removing files / Changes

License

Watson is MIT licensed.

watson's People

Contributors

koflin avatar strawbrryflurry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

the-real-thisas

watson's Issues

Provide different Message Matchers

Different apps might need different message matching behavior to make sure we don't waste time with this initial filtering step.

We assume there are four different kinds of commonly expected behavior for which we provide an implementation.

SimpleStaticMessageMatcher

A SimpleStaticMessageMatcher assumes that all prefixes defined in the Application are already resolved (therefore static) and will not change while the app is running. Knowing this we can just iterate over the limited set of prefixes on every message event to check for one of the prefixes.

TransientDynamicMessageMatcher

The TransientDynamicMessageMatcher is able to resolve dynamic prefixes which might be asynchronous or depend on some other outside data. It will resolve all possible prefixes that are defined in the application using the incoming message. On resolution, the message content will be checked for possible matches.

CachedDynamicMessageMatcher

The CachedDynamicMessageMatcher works almost exactly like the TransientDynamicMessageMatcher with the key difference that the resolved prefix is saved in a cache for later reference.

When a message passes, a resync of the cache will be scheduled asynchronously using the prefix and the message. (This process will not be awaited and can happen in the background). This way the cache will stay up to date while still having good lookup times for prefixes. Because we're dealing with dynamic prefixes which, depending on the size of the app, could be too many to just iterate over, we'll use a Trie will be used to figure out the prefix used in a given message.

GuildScopedMessageMatcher

A GuildScopedMessageMatcher works very similarly to the CachedDynamicMessageMatcher. Here we assume that every guild only has one prefix assigned to it. That way we can cache prefixes in a guildId - prefix map to look up prefixes. Similar to the other implementation we'll also sync the prefix cache for a prefix on every message.

To force a resync (After a guild prefix update maybe) we provide a public method on the matcher to force an update for a given guild.

Note that you'll also be able to provide your own implementation to best fit your needs.

Extract DI to @watsonjs/di

Should we extract everything DI-related into its own package such that it can be used without the framework?

JSX message builder

Allow for jsx to be returned from a command/interaction or for it to be sent using a provided method by the framework.

@Command("ping")
handlePing() {
  return <embed>
                <title> Pong! </title>
             <embed>
}

Add more providers to the module DI scope

Watson uses a lot of internal class instances like:

  • CommandParser
  • CommandTokenizer
  • CommandContainer
  • Injector
  • ApplicationConfig
  • ApplicationProxy
    And many more which could be useful for dynamic modules or command matching / adding custom commands.

For that reason, we should make them publicly available via DI as well as make them interchangeable with custom versions of a user's implementation.

Update error handling

During the rewrite of the parsing/command implementation, the error handling did not get updated. It should be able to provide feedback about parsing errors as well as errors thrown within a command/event context.

Discord rate-limiting

Discord's APIs are rate-limited. As a result, we'll have to figure out how we can make sure that every request can still be processed as expected by the user, even if we have to delay it for some time to work around the rate limits. - Discord rate-limits

Countermeasures

Add a global rate limit handler to reschedule calls that couldn't be completed due to rate limiting.

Provide a global rate limiter for scheduling calls that will likely get rate limited:

A rate limiter implementation could look something like this and would of curse also be customizable by the user.

/**
* Custom handlers of a rate limiter need to 
* implement the minimal features of this interface
*/
interface IRateLimitHandler {
  /**
  * Call the `cb` and check if it was rate limited.
  * If so retry the method call after `x` delay.
  *
  * The framework will also use this method
  * by default if a command or event route
  * call is being rate limited.
  * 
  * @returns A `Promise` that resolves once the
  * `cb` was successfully called.
  */
  retryOnLimit(cb: () => void): Promise<void>;
  /** 
  * When having to make a lot of API calls to 
  * delete channel messages or update a bunch 
  * of users you can use this method as a way
  * to schedule them. You provide an array of 
  * inputs which are then being used to execute 
  * the callback function. Items are processed 
  * every `x` interval or if we know for sure
  * we are not getting rate limited.
  * 
  * @returns A `Promise` that resolves once all
  * arguments were successfully processed.
  */
  scheduleBulk<T>(args: T[], (arg: T) => void): Promise<void>;
}

The Rate Limit handler should be available via DI and overwrote by using a custom provider.

Support for command callbacks

Support command callbacks which would looks something like this:

@Receiver()
class SomeReceiver {
  @CallbackFor("boop", {
    step: "boop-accepted",
    verifyFn?: (messageResponse: Message / MessageAST) => boolean
  })
  onBoop(response: string, commandArgs?: [unknown]) {
    if(response === "y") {
      const [{user}] = commandArgs;
      return `Boop ${username}!`;
    }
  }

  @Command("boop")
  boop(boopee: UserMention) {
    const { user } = boopee;
    return `Are you sure you want to boop ${user.username}? <y / n>`;
  }
}

Re-implement the @Command decorator

Change the command registration to work with the parameters provided in the command method instead of the parameters provided in its configuration.

@Receiver()
class SomeReceiver {
  /**
   * `!boop @Michael`
   * > Boop Michael :3
   */
  @Command("boop")
  boop(mention: UserMention) {
    const { user } = mention;
    return `Boop ${user.username} :3`;
  }
}

Web Dashboard API

Integrated web API & boilerplate to manage the bot instance and configure it.

Improve DI token management

All custom providers should use an InjectionToken instead of a class/string reference.

Internal providers should be more distinguishable within a modules Provider/Injectable map.

Scripting API for Watson

Allow users to write custom scripts for Watson using CodeBlocks:

?run
\```.ws
const message = "Heya!! :3";
await say(message);
const response = await prompt("What's up?");
\```

Service / Provider scoping for DI - DI Rework

Right now all providers are initialized during the bootstrapping process. We would like to also support providers that are instantiated at runtime depending on the use case.

Singleton (Default) - Instantiated during bootstrapping, shared among all modules that import the same exporting module.

Transient - Instantiated for each command/event call.

Scoped - Instantiated for every scope if present, otherwise the module is used as a scope.

NestJs integration

Provide full builtin support for using a nest app with watson. Also add a new injector type NestInjector that the nest injector can use as a mock module to resolve Watson deps.

Decouple the framework from DiscordJs

Use standardized classes (provided by the framework) for Discord objects like messages and the client DiscordAdapter instead of the ones provided by DiscordJs. This is to decouple the framework from DiscordJs and support other clients in the future.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.