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

add websockets #12

Merged
merged 45 commits into from
Jul 14, 2022
Merged

add websockets #12

merged 45 commits into from
Jul 14, 2022

Conversation

t-rog
Copy link
Contributor

@t-rog t-rog commented Jun 1, 2022

Co-Authored-By: SwitchUpCB <81384235+switchupcb@users.noreply.github.com>
@t-rog t-rog marked this pull request as draft June 1, 2022 02:48
wrapper/sessions.go Outdated Show resolved Hide resolved
wrapper/sessions.go Outdated Show resolved Hide resolved
wrapper/sessions.go Outdated Show resolved Hide resolved
wrapper/sessions.go Outdated Show resolved Hide resolved
wrapper/sessions.go Outdated Show resolved Hide resolved
wrapper/sessions.go Outdated Show resolved Hide resolved
@t-rog t-rog marked this pull request as ready for review June 2, 2022 03:14
@t-rog t-rog marked this pull request as draft June 2, 2022 03:16
@switchupcb
Copy link
Owner

Event Handling

Event Handling will use two functions in order to avoid type asserting.

Function One

The first function will be a generic function to handle all events. Upon receiving events, this function will be called with a goroutine to prevent it's code from blocking the main thread.

image

The steps are as follows:

  1. A JSON FILE is received and passed to onEvent(bot *Client, data []byte) where data represents the JSON file.
  2. The op is checked using a generic/custom/gjson marshal.
  3. A global map is checked for the op. The purpose of this map is to provide event handlers for events that must be handled (and usually in the same way). For example, heartbeat events which require continuous pinging to discord, or resume events.
  4. A custom map is checked for the op. The purpose of this map is to provide events handlers for events that are handled by the bot. For example, events that are defined by the user using function two.

Map may be replaced by an alternate data structure or switch.

Function Two

Function two represents the disgo UI for event handling. This can be defined in a similar manner to the Send() function such as event.Add(bot, func() { ... } to add an event handler to the bot, or similar to the current method in the proof of concept README.

// Define an event handler.
handler := disgo.EventHandler{
    Event: disgo.EventInteractionCreate,
    Call: func (i disgo.ResourceInteraction) {
        log.Printf("main called by %s", i.User.Username)
    },
}

// Add the event handler to the bot.
bot.Add(handler)

Regardless of the choice, we must allow the user to determine the event they are using before runtime, such that we can also add it to the bot at compile time in the correct list of handlers.

Function Three

The "third function" represents the goroutines that run the event handler functions from the onEvent thread.

@switchupcb
Copy link
Owner

Event names were added using the following code:

import re

# format formats the given string from CapitalWord to CAPITAL_WORD.
def formatString(s):
    words = re.findall('[A-Z][^A-Z]*', s)
    formatted = ''
    for word in words:
        formatted += word.upper() + "_"
    
    return formatted[:len(formatted) - 1]

# flag is appended to the start of the line.
flag = "FlagGatewayEventName"

# create the new file.
newfile = ""
lines = file.split("\n")
for line in lines:
    newfile += flag + line + " = " + '"' + formatString(line) + '"' + "\n"

print(newfile)

@switchupcb
Copy link
Owner

This outline works in essentially the same way as above, however we can NOT use the opcode itself to determine the event.

Instead, onEvent is used to determine the Opcode, and if Op == 0, then we can use t (EventName) with the handle function to handle the actual event. This entails adding generated code which — for each event — unmarshals d into the respective object, and then runs the bot's handler functions on a goroutine.

The original idea to use a map was thwarted because a map[string]func(interface{}) is not usable (since a func(interface{}) is NOT equivalent to a func(*<Event>)). In contrast, a func(<whatever>) is equivalent to a interface{}, but this warrants unnecessary complexity and type assertions at some point. We can avoid type assertion by simply using slices to store event handler functions such as []func(*Hello). However, this may have memory implications I have not looked into (when we are NOT using pointers to a slice).

In any case, there will always be a concrete amount of handlers: Storing them via map would involve complexity and type assertion while saving initial memory compared to storing them via slices: Even using pointers, 62 event slices * 8 bytes = 496 bytes or .496 KB, before handlers have been added. Given that is bot is usually only created once (or with an uninitialized Handlers field which only takes 8 bytes), this is NOT a costly implementation.

The side effect however is that we must add an easy way for the user to ensure that there is a handlers object when it needs to be used. This can be done at initialization or in any other simple manner.

@switchupcb
Copy link
Owner

switchupcb commented Jun 5, 2022

I have added the autogenerated Handlers struct, Handle function, and handle function. This may require some edits depending on the handling of certain events. Otherwise, the UI for the end user is even simpler:

// Add an event handler to the bot.
bot.Handle(disgo.FlagGatewayEventNameInteractionCreate, func(i disgo.InteractionCreate) {
	log.Printf("main called by %s", i.User.Username)
})

We will want to ensure the following prior to merging this request (after everything else for this PR is completed):

  • Use correct imports during generation (easy fix likely handled outside of PR).
  • Showcase how to remove a handler (using direct access index in examples).
  • Session code event handling is consistent.
  • Ensure user can instantiate a handler at Config.

Here is an example of how one may add a global handler. Keep in mind that this is not yet applicable for the first Hello handle prior to opening the session (because the session needs to be listening for events first).

// check if an event handler for hello events has been added to the bot.
if len(bot.Handlers.Hello) == 0 {
    // add the handler to the bot.
    bot.Handle(FlagGatewayEventNameHello, func(*Hello) {
        // add event handler code here.
    })
}
// otherwise, handler isn't added to the bot.

This code would be called when the session begins listening for events and a Hello is received.

@switchupcb
Copy link
Owner

The Handle function can implement automatic intent calculation by specifying which intents are required in the setup.go file for copygen events.

switchupcb added 2 commits June 7, 2022 02:25
handles missing opcode 11
@switchupcb switchupcb mentioned this pull request Jun 7, 2022
@switchupcb
Copy link
Owner

image

fixes ticker semantics, highlights issues with hearbeart algorithm, needs context/conn fix
@switchupcb
Copy link
Owner

image

New Heartbeat Algorithm

switchupcb and others added 7 commits June 10, 2022 13:34
switchupcb and others added 3 commits June 25, 2022 18:22
with automatic intent calculation
added zlib compression and fixed listen function

Co-Authored-By: SwitchUpCB <81384235+switchupcb@users.noreply.github.com>
Copy link
Owner

@switchupcb switchupcb left a comment

Choose a reason for hiding this comment

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

note to self: add nlreturn (?)

wrapper/sessions.go Outdated Show resolved Hide resolved
wrapper/sessions.go Outdated Show resolved Hide resolved
wrapper/sessions.go Outdated Show resolved Hide resolved
wrapper/sessions.go Outdated Show resolved Hide resolved
wrapper/sessions.go Outdated Show resolved Hide resolved
wrapper/sessions.go Outdated Show resolved Hide resolved
wrapper/sessions_test.go Show resolved Hide resolved
wrapper/sessions_test.go Outdated Show resolved Hide resolved
wrapper/sessions_test.go Outdated Show resolved Hide resolved
wrapper/sessions_test.go Show resolved Hide resolved
switchupcb and others added 2 commits July 10, 2022 23:36
event variable initialization; add automod
t-rog and others added 11 commits July 11, 2022 20:21
adds internal socket package, read, write, and disconnect helper functions, improves heartbeat functionality test
connect optimization; needs data race fix
@switchupcb switchupcb marked this pull request as ready for review July 14, 2022 19:45
switchupcb added 3 commits July 14, 2022 15:34
@switchupcb
Copy link
Owner

switchupcb commented Jul 14, 2022

Secrets (and environment secrets) can not be used by forked repositories unless certain conditions are granted.

https://stackoverflow.com/questions/58737785/github-actions-empty-env-secrets

@switchupcb switchupcb merged commit 480d5b5 into switchupcb:main Jul 14, 2022
switchupcb added a commit that referenced this pull request Jul 15, 2022
* add connect to gateway

* add Reconn and Terminate

* add event handler outline

* fix semantics for implementation

* add heartbeat func

* add event handler generation

* add listen func

* fix connect and disconnect func

* fix heartbeat func

handles missing opcode 11

* implement mutex

fixes ticker semantics, highlights issues with hearbeart algorithm, needs context/conn fix

* change heartbeat algorithm

* fix heartbeat edge case

* review changes

fix heartbeat, error logic

* add mutex to event generation

* add listen optimization note

* add automatic intent calculation

* fix opcode marshal

needs readability rewrite

* add Remove func

for event handlers; needs documentation

* format

* refactor session errors

* fix client initialization

IntentSet

* fix Client pointer init

* fix Connect with test

Co-Authored-By: SwitchUpCB <81384235+switchupcb@users.noreply.github.com>

* fix token variable

NEVER COMMIT TOKEN

Co-Authored-By: SwitchUpCB <81384235+switchupcb@users.noreply.github.com>

* add event handler test

with automatic intent calculation

* fix websocket errors

added zlib compression and fixed listen function

Co-Authored-By: SwitchUpCB <81384235+switchupcb@users.noreply.github.com>

* fix handle function

event variable initialization; add automod

* edit requested changes

* fix test data race

* refactor websocket functionality

adds internal socket package, read, write, and disconnect helper functions, improves heartbeat functionality test

* swap dasgo

* changefix heartbeat algorithm

* add reconnect test

connect optimization; needs data race fix

* refactor connect disconnect reconnect

fixes data races

* update errors

* update contributing

* update ci

* fix ci

* remove godotenv

move env to steps

* debug ci

* fix ci on forks

Co-authored-by: SwitchUpCB <81384235+switchupcb@users.noreply.github.com>
Co-Authored-By: t-rog <74488354+t-rog@users.noreply.github.com>
@switchupcb
Copy link
Owner

Updated Documentation

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants