diff --git a/client.go b/client.go index 4097cdd..6fdc7e4 100644 --- a/client.go +++ b/client.go @@ -1,6 +1,7 @@ package tempest import ( + "context" "crypto/ed25519" "encoding/hex" "errors" @@ -170,6 +171,48 @@ func (client *Client) ListenAndServeTLS(route string, address string, certFile, return http.ListenAndServeTLS(address, certFile, keyFile, nil) } +// Tries to gracefully shutdown client. It'll clear all queued actions and shutdown underlying http server. +func (client *Client) Close(ctx context.Context) error { + if client.State() == INIT_STATE { + return errors.New("client is still in initiallization phase, there's nothing to shutdown") + } + + if client.State() != RUNNING_STATE { + return errors.New("client is already either closed or during closing process") + } + + client.state.Store(uint32(CLOSING_STATE)) + client.preCommandHandler = func(cmd *Command, itx *CommandInteraction) bool { + return false + } + + for key, componentChannel := range client.queuedComponents { + if _, open := <-componentChannel; open { + close(componentChannel) + } + delete(client.queuedComponents, key) + } + + for key, modalChannel := range client.queuedModals { + if _, open := <-modalChannel; open { + close(modalChannel) + } + delete(client.queuedModals, key) + } + + err := client.httpServer.Shutdown(ctx) + if err != nil { + err2 := client.httpServer.Close() + if err2 != nil { + return errors.Join(err, err2) + } + return err + } + + client.state.Store(uint32(CLOSED_STATE)) + return nil +} + func NewDefaultClient(options ClientOptions) *Client { discordPublicKey, err := hex.DecodeString(options.PublicKey) if err != nil {