Git Product home page Git Product logo

msgroom-orm's People

Contributors

dependabot[bot] avatar nandertga avatar semantic-release-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

msgroom-orm's Issues

Aliases proposal

// let's say we want to define pong, an alias for ping
client.commands.pong = {
  alias: true,
  original: client.commands.ping,
  originalName: "ping",
}
// let's say we want to define pong, an alias for otherCommand.ping
client.commands.pong = {
  alias: true,
  original: client.commands.otherCommand.ping,
  originalName: "otherCommand.ping",
}

Like this we can hide aliases from the help command.

Don't have bots respond to themselves

With a say command, there's always the issue of someone doing !say !say !say !say !say !say !say !say !say and rate limiting the bot. This would be solved if the bot automatically didn't respond to itself.

A problem: It would need to somehow know if it is itself, or just its creator with the same ID.

Plans for nightly builds

When trying to help someone on msgroom called \u202e yesterday (actually he uses that unicode character as his name, but everyone refers to him by that name because it's an invisible character), I found out it's a pain to get a nightly build from the repository.

The problem

I configured the project in package.json to only include the dist/ folder (the readme, license and package.json are included too by npm).
This causes npm to only fetch those things from the repository when telling it to do so.
Because of this npm won't download the src/ folder, nor the dist/ folder (it doesn't exist on the repo) and you have to manually clone the repository, rename the cloned folder from msgroom-orm to msgroom and run npm install and npm run build.
This is very annoying and I don't want to remove the above setting, because I want to save space.

Solution

I'm working on a new github actions workflow to automatically test and run npm pack on every commit, and to also publish the result at a new package called msgroom-nightly.

The version naming scheme will go as follows:

  • Get the current version and only get the coerced contents of it (2.0.0-0 -> 2.0.0)
  • Append -(full git sha here) (the dash makes it a prerelease)

This will result in something like this: 2.0.0-ffac537e6cbbf934b08745a378932722df287a53
This won't really work with semantic versioning (even though it's parseable by it), but I don't think it's that much of a problem since it's just a nightly build and use is at your own risk, and you'd have to check manually every time when updating anyway, because every commit could have a breaking change in it.

Suffix for help command

I have noticed several people adding suffixes to their bots' help commands.
Syntax: new option in constructor and new property named helpSuffix.

Utility field: `User.escapedName`

msgroom (the chat room, not this library) can have some problematic usernames that make putting usernames in chat messages tricky. As far as I can tell, there are two main problems:

  • \u202e
  • Special characters - e.g. **nolanwhy**

A username() utility function that you could just wrap usernames that would be output in would help with this. It would:

  • Censor the usernames - is the wordlist s#heesh uses public?
  • Add \u202d at the end of the username to negate any text reversal going on

Command metadata

We need some way to be able to tell users more about a command.
My current idea is to put an object where you'd put a function (command handler) now.
This object can contain aliases for a command, the handler and a description.
The way to detect this is simple: from the moment a property called handler is defined, it's considered a command.
I think we should also provide a class the user can instantiate for better code readability.

block other bots too

So turns out people have been experimenting with TestBot's repeat command, and used it to trigger other bots.
This is not good, as people could for example abuse one bot to trigger another, while the bot that was triggered wouldn't know.
Solution? New option in the constructor: blockBots.
This new option will block anyone who has a prefix or "bot" in their name.
I'll also notify a user when they change their name or join with such a name that they will be ignored due to their name.

fix: correctly deal with blocked users

Recently, Yabluzo and other bots on recent versions have started crashing now and then.
I have been aware of this issue for some time now and have been able to log some of the events that caused one of these undefined errors.
These logs indicate that a message event is sometimes handled before the user-join event assigns a new user to client.users.
However, this is impossible because these event handlers are all synchronous and socket.io guarantees that all events are received (and thus have their event handlers run) in the same order they were sent.

My conclusion is that client.users[user] must be undefined for some other reason.
I think this may be related to a recent change that introduced blocking bots using Sheesh's bot API.
I have also noticed that the crashes seem to happen for bots or people who have the same ID as a bot.
I will investigate further.

Centralize normalizing commands

Ever since I decided to allow to leave out the description and aliases properties, I have been having to deal with them in the already messy help command.
I'm working on putting this in a separate transform.

Running a subcommand without the actual subcommand crashes

If you have subcommands like !a b, !a c, !a d, just trying to call !a crashes msgroom-nightly. Here's the error from toB:

<toBPath>\node_modules\msgroom-nightly\dist\index.js:281
                    if (key.toLowerCase() == command.toLowerCase()) {
                                                     ^

TypeError: Cannot read properties of undefined (reading 'toLowerCase')
    at Client.getCommand (<toBPath>\node_modules\msgroom-nightly\dist\index.js:281:54)
    at Client.processCommands (<toBPath>\node_modules\msgroom-nightly\dist\index.js:317:42)
    at Socket.<anonymous> (<toBPath>\node_modules\msgroom-nightly\dist\index.js:136:27)
    at Emitter.emit (<toBPath>\node_modules\@socket.io\component-emitter\index.js:143:20)
    at Socket.emitEvent (<toBPath>\node_modules\socket.io-client\build\cjs\socket.js:519:20)
    at Socket.onevent (<toBPath>\node_modules\socket.io-client\build\cjs\socket.js:506:18)
    at Socket.onpacket (<toBPath>\node_modules\socket.io-client\build\cjs\socket.js:474:22)
    at Emitter.emit (<toBPath>\node_modules\@socket.io\component-emitter\index.js:143:20)
    at <toBPath>\node_modules\socket.io-client\build\cjs\manager.js:237:18
    at process.processTicksAndRejections (node:internal/process/task_queues:81:21)

Node.js v18.16.0

API docs not generating

The API docs stopped generating ever since the migration to docusaurus v3.
I should really fix this.

Tell user when message is too long

The maximum length of a message is 2048 characters.
Since the server doesn't bother telling us when a message is too long, we should.
I have no idea yet if it should throw an error or something.
Maybe tell them using werror? Maybe split the message?
I need some input for this.

Change client.users to hashmap

Currently it's an array you have to search through and that's annoying when we know the session ID is guaranteed to be unique.
A hashmap is easier and more efficient here.
The fact that I was lazy and used an array in the first place caused the mess of #4.

feat!: move options to `options` field and add command-specific options

Currently, every option is a field on the Client class.
The new approach will have all the options in a separate field.
For example: client.helpCommandLimit
New approach: client.options.helpCommandLimit
I'm changing it like this for more clarity.

I also want to add a feature where you can override certain options for a specific command.
I'll add a new field to Command and one to CommandContext to change and view the options respectively.

And while we're at it, why not let an option be a function that takes the context and any more arguments that provide more information (or maybe put them on the context too?)

client.getCommand() is turning into spaghetti code

I'm currently attempting to make commands case-insensitive (#36), but if this is going to work, there will be a for loop inside a while loop.
This is not really good for performance.
If we make aliases work too (#35), that will need to use walkCommandMapEntry(), which is a recursive function.
I need to rewrite this entire function.

Documentation for v2

Msgroom v2 is coming along nicely, but there's one big problem: documentation.
The plan is to write some proper documentation on the repository wiki.
Until I fix the other 2 issues and write some proper documentaton, v2 cannot release.

Add source maps

Affected tsconfig.json compilerOptions:

  • sourceMap
  • declarationMap

Adding API keys

You should add bot API keys. Example: import Client from "msgroom";

const client = new Client("TestBot", "APIKey", [ "!" ]);
await client.connect();

Hidden commands

This will allow you to hide commands from the help command.
The plan is to add an extra field to Command called hidden.
This will be a simple boolean (false by default).

Metadata for command arguments

Command gets a new property: arguments
Example:

client.commands.dice = {
    arguments: [
        {   // turns into <sides>
            name: "sides",
            required: true,
        }, {
            // turns into [...stuff]
            name: "stuff",
            required: false,
            rest: true,
        }
    ]
}

I also have this idea to do some validation perhaps. (Sending a user things like missing command error...).

Command should be easier to access

The current toB code does this:

import Client from "msgroom-nightly";
import Command from "msgroom-nightly/dist/utils/Command.js";

This isn't ideal. Perhaps this could be changed to work like this:

import { Client, Command } from "msgroom-nightly";

Classes instead of objects for commands

Say you wanted to implement a counter command. It'd look like this:

let counter = 0;
client.commands.counter = {
  description: "A counter.",
  handler: () => `The counter is ${++counter}!`,
}

This works, but it uses a global variable, so it pollutes the global scope.

A much nicer way to do this would be:

client.commands.counter = class {
  private counter = 0;

  public description = "A counter.";
  public handler() {
    return `The counter is ${++this.counter}`;
  }
};

I think this would improve the UX of this library by a lot. I'm currently facing this problem with my toB's command:

const hangmanSymbols = [
  // ...
];
let hangman: string | null = null;
let hangmanIncorrectGuesses = 0;
let hangmanGuessed: string[] = [];
const hangmanGuessesAmount = 9;
const hangmanReset = () => {
  // ...
};
const hangmanView = () => {
  // ...
};
const hangmanSolved = () => {
  // ...
};
client.commands.hangman = {
  // ...
};

Admin-only commands

I've seen quite some bots implementing some admin system of their own, often having people with the same ID being an admin by default, who then can give other people admin access.
Then they have to deal with loading and saving that stuff.

Since this kind of functionality is common, and people don't get promoted or demoted a lot, and there usually only are a few admins, a simple JSON file will do just fine.

I'll do it like this:

  • The developer tells the library where to find the JSON file with a list of admins. (through an extra option in the constructor)
  • We load the JSON file and cache the list of admins.
  • We watch the file for changes and update the cache accordingly.
  • Error while reading file? We just keep watching it and send an error in the console.
  • If someone gets promoted or demoted, we update the JSON file. If we're overwriting a JSON file we cannot parse, create a backup.
  • What if there already is a .bak file? We put a timestamp in the filename to prevent this.
  • The developer isn't happy with our solution? We provide an option for them to write their own solution. They will have 3 tasks: load, save and watch whatever thing they are using.

arguments using quotes

Executing this: !thing "first argument" "second one"
Will turn into thing.handler(context, "first argument", "second one") being called.
The same way it works in cmd, powershell, bash...

allow promises in command handlers

It's annoying to have to use .then and all that stuff.
The way this would work is by making client.processCommands async and not awaiting the Promise it returns on handling commands.

rework arguments passed to events

I want to transform some properties of objects you receive from the server like session_id to have a different name instead (sessionID in this case).
This is something for v2.

Don't embed prefixes in regex

Problem

Say you want to use $ as a prefix.
You set the prefix to $, but stuff breaks.
Turns out you need to escape it, so you change it to "\\$" (confusing, I know).
It works, until you want to tell people your prefix, but you only have the escaped one.
Then you need to remove the backslash and yada yada, basically one giant mess.

How did this even happen?

At the time of writing the command parser, I thought it would be a good idea to use regex to check for matching prefixes in a message, to avoid a (simpler) for loop.
As a result of this, people could use regex themselves to check for prefixes. Awesome, right?
It seemed to work fine, until someone wanted to use $ as a prefix.
The dollar sign has a special meaning in regex, so when you embed that into a regex expression, you get broken behavior.

Solution

Loop over the prefixes instead.
If the current prefix is a string, check if the message starts with it and remove it from the message.
If it's a regexp, test if the regex matches and remove the matching parts

fix: implement a proper way to get the sessionID

This is a follow-up issue to #34.
In 3 months time the msgroom server has seemingly changed a bit. For example, I recall seeing a werror in the console sent by the server saying You are doing this too much - please wait a while ago.
I also recall seeing another bot written in python which seemingly got the session ID from an event.
I need to investigate this further because the hack to get the sessionID is pretty janky and barely works.
Turns out I didn't account for people getting the session ID when blockSelf is off.

Thanks to Kelbaz for reporting the issue.

feat: protect users against ReDoS

ReDoS vulnerabilities are a serious problem and people using regex prefixes could fall victim to this.
I want to protect people against this by checking for ReDoS vulnerabilities in the background using recheck.

It does add an extra dependency though.
Do or don't?

Metadata for commandMaps

Right now a commandMap cannot have a description of its own.
Solution?

client.commands.thing = {
  undefined: { handler: ... },
  subcommand: { handler: ... },
}

Will turn into

client.commands.thing = {
  description: ...,
  aliases: [...],
  handler: () => "some thing",
  subcommands: {
    undefined: { handler: ... },
    subcommand: { handler: ... },
  }
}

I don't know for sure if this is a proper solution though.
Any feedback is greatly appreciated!

Allow any capitalization for commands

If a command ask gets registered, then %ask something and %ASK something and %aSK something should also lead to that command. There have been some cases of people using %ASK A CAPITALIZED QUESTION, so I think it makes sense.

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.