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

Complete Redesign of YABOB's Architecture #16

Closed
tomli380576 opened this issue Aug 24, 2022 · 8 comments
Closed

Complete Redesign of YABOB's Architecture #16

tomli380576 opened this issue Aug 24, 2022 · 8 comments
Assignees
Labels
new feature New feature request P1 Highest priority issue

Comments

@tomli380576
Copy link
Collaborator

tomli380576 commented Aug 24, 2022

Objective

Avoid bad JS practices and make YABOB more modular.
Allow developers to easily extend YABOB's functionality by providing them with proper interface.

Most up to date diagram
Current Features

Ongoing Design

  • Better start up error messages

Command Performance Issues

  1. /stop is really slow when using google sheets. This is likely a network issue.
    • Potential fix: Give user feedback when their time is recorded and just let google sheets update finish in the background.
@tomli380576 tomli380576 added enhancement New feature or request P2 High priority labels Aug 24, 2022
@tomli380576
Copy link
Collaborator Author

#19 See CLI details here

@tomli380576
Copy link
Collaborator Author

tomli380576 commented Aug 25, 2022

Original Concept (2022-08-25) This is really old now. Will update a new diagram here soon.
Screen Shot 2022-08-25 at 2 30 15 PM
↑ current design.
If we need another extension, extend from the NoExtension class and override the corresponding functions

@tomli380576 tomli380576 self-assigned this Aug 25, 2022
@KaoushikMurugan KaoushikMurugan added new feature New feature request and removed enhancement New feature or request labels Aug 26, 2022
@tomli380576 tomli380576 added P1 Highest priority issue and removed P2 High priority labels Aug 29, 2022
@tomli380576 tomli380576 pinned this issue Aug 30, 2022
@tomli380576
Copy link
Collaborator Author

tomli380576 commented Aug 30, 2022

Current interface design

interface IServerExtension {
    onServerInitSuccess: (server: Readonly<AttendingServerV2>) => Promise<void>;
    onAllQueueInit: (queues: ReadonlyArray<HelpQueueV2>) => Promise<void>;
    onQueueDelete: (queue: Readonly<HelpQueueV2>) => Promise<void>;
    onDequeueFirst: (dequeuedStudent: Readonly<Helpee>) => Promise<void>;
    onHelperStartHelping: (helper: Readonly<Omit<Helper, 'helpEnd'>>) => Promise<void>;
    onHelperStopHelping: (helper: Readonly<Required<Helper>>) => Promise<void>;
    onServerPeriodicUpdate: (server: Readonly<AttendingServerV2>) => Promise<void>;
    loadExternalServerData: (serverId: string) => Promise<ServerBackup | undefined>;
}

// Extensions for individual queues
interface IQueueExtension {
    onQueueCreate: (queue: Readonly<HelpQueueV2>) => Promise<void>;
    onQueueOpen: (queue: Readonly<HelpQueueV2>) => Promise<void>;
    onQueueClose: (queue: Readonly<HelpQueueV2>) => Promise<void>;
    onEnqueue: (student: Readonly<Helpee>) => Promise<void>;
    onDequeue: (student: Readonly<Helpee>) => Promise<void>;
    onStudentRemove: (student: Readonly<Helpee>) => Promise<void>;
    onRemoveAllStudents: (students: ReadonlyArray<Helpee>) => Promise<void>;
    onQueueRenderComplete: (
        queue: Readonly<HelpQueueV2>,
        display: Readonly<QueueDisplayV2>,
        isClenupRender?: boolean
    ) => Promise<void>;
    onQueuePeriodicUpdate: (queue: Readonly<HelpQueueV2>) => Promise<void>;
}

@tomli380576 tomli380576 changed the title Refactor: Isolate base BOB functionalities Complete Redesign of YABOB's architecture Aug 30, 2022
@tomli380576 tomli380576 changed the title Complete Redesign of YABOB's architecture Complete Redesign of YABOB's Architecture Aug 30, 2022
@tomli380576
Copy link
Collaborator Author

The extension design is a simplified version of the Observer Pattern

@tomli380576
Copy link
Collaborator Author

tomli380576 commented Sep 1, 2022

Currently Developed New Features

  1. Modular AttrendingServerV2 and HelpQueueV2

    • On create() server will load server extensions and queue will load queue extensions
    • All creations/initializations are launched synchronously so 1 server or 1 queue won't block any other. It's safe because individual servers and queues never have access to other ones and one instance's setup progress does not influence another. The main client will wait for them to all finish.
    • Both AttrendingServerV2 and HelpQueueV2 support event based (when someone uses a command / queue content change / queue render) emitters and periodic event emitters.
    • Once an event emits, all extensions that override corresponding methods will be launched synchronously and not block main server operation.
    • Queue renderer can be injected with non queue embeds. Every queue extension will get an renderIndex which represent its order in the list of embeds. Extensions only need to provide the complete embed, and QueueDisplayV2 will help maintain the #queue channel integrity by doing checks and ask HelpQueue to trigger a clean render if necessary. Checks are done in $O(1)$ and clean render will not happen unless a message gets deleted or /cleanup was used, so there's minimal overhead when it comes to normal re-renders.
  2. Unified CommandHandler and ButtonHandler

    • Every interaction now follow this flow:
      1. Client receives interaction, checks if the built in handlers can process it, then directly pass to the corresponding handlers.

      2. CommandHandler and ButtonHandler look up functions by interaction name in methodMap hashmap

      3. Immediately reply to the user saying it's processing to provide feedback.

      4. Launch all asynchronous checks. ButtonHandler will always check for valid queue

        i. They follow this syntax: (example: checks for /enqueue)

        const [serverId, queueChannel, member] = await Promise.all([
                  this.isServerInteraction(interaction),
                  this.isValidQueueInteraction(interaction),
                  this.isTriggeredByUserWithValidEmail(interaction, "enqueue"),
         ]);
        

        Checks are decoupled from individual commands so they are easily reusable. If all checks pass, the command will continue with values guaranteed to be clean.

      5. Calls the corresponding server's function if the checks pass. Otherwise reject with CommandParseError.

      6. Wait for the server/queue to finish. If they reject, pass the error back to the user.

        i. Current errors designed to be sent back to the user include ServerError, QueueError, CommandParseError, and CommandNotImplementedError

  3. Currently Implemented Extensions

    • [Server] Firebase Extension: Automatic backup every 30 minutes(arbitrary, change if needed). Automatic reload from firebase on server startup
    • [Queue] Calendar Extension: Reads the given google calendar and looks for upcoming tutoring sessions. Injects upcoming sessions' embed into the queue renderer
      • Added a button to allow manual refresh of the upcoming sessions calendar. I hope google doesn't think we are doing ddos attacks.
    • [Command] Calendar Extension: This is coupled together with the queue one. Posts the following commands:
      • set_calendar: Admin only, switches to a different calendar
      • when_next: Everyone, lists upcoming tutoring sessions in the next 7 days.
      • make_calendar_string: Staff or Admin, make a calendar string that the queue extension can parse.
    • [Server] Attendance Extension: Same as the current attendance tracking method. Reads the google sheet, computes help time every time a tutor uses /stop, then add a new row.
  4. Guild kick and rejoin

    • If YABOB accidentally gets kicked from the server, simply re-invite YABOB and it will DM the server owner to adjust the roles. Once the roles are adjusted (give YABOB the highest role), then it will DM the owner again to say it's ready. It will now perform the normal server initialization sequence using any backup it can find.
  5. About Roles

    • YABOB doesn't rely on role positions anymore to limit user permissions. It will strictly check for the exact name of the role, giving server admins the freedom to adjust specific permissions. This keeps YABOB's behavior simple and easy to debug. If YABOB is not limiting user permissions correctly, then it must related to the role names.
    • To change role permissions for individual commands, change the role names in isTriggeredByUserWithRoles. Role names here have OR relationship meaning that if the user satisfy one or more of the roles, the permission check will pass.
  6. Dev Utilities

    • YABOB is now runnable without any extensions. Enable the -- noExtensions=true flag to disable all extensions.
    • npm run dev and npm run prod are setup if we need to separate dev and production environment. Both will compile then immediately start running the bot so we don't need to npm run build then npm run start. This requires all TS checks to pass.

@tomli380576
Copy link
Collaborator Author

tomli380576 commented Sep 1, 2022

Naming Scheme

Roles

  1. [Bot Admin] Bot administrator, has access to all the commands and the Administrator permission.
    • Admins should manually give Officers this role.
  2. [Staff] Helpers/Tutors, has access to helping related commands like /start /stop /next, etc.
  3. [Student] Has access to enqueueing / leaving queue commands

MemberStates

Only maintained by the queue. Attending server can only see the Readonly versions of them.

  1. Helper This is anyone that is currently helping.
    type Helper = {
        helpStart: Date;
        helpEnd?: Date;
        helpedMembers: GuildMember[];
        readonly member: GuildMember; // backref
    }
    Once the helper uses /stop, helpEnd will have a value and the extensions that are subscribed to this event will get Required<Helper> as the parameter.
  2. Helpee This is anyone that is in queue
    type Helpee = {
        waitStart: Date;
        upNext: boolean;
        readonly member: GuildMember // backref
    }

@KaoushikMurugan
Copy link
Owner

I was thinking about combining replacing Admin with "Bot Admin", i.e. doesn't have to be Admin. This separate role can be given to both Admins and Officers

@tomli380576
Copy link
Collaborator Author

tomli380576 commented Sep 6, 2022

Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature New feature request P1 Highest priority issue
Projects
None yet
Development

No branches or pull requests

2 participants