Skip to content
This repository has been archived by the owner on Jul 11, 2024. It is now read-only.

Commit

Permalink
support http Do injection + websocket http client
Browse files Browse the repository at this point in the history
  • Loading branch information
andersfylling committed Mar 14, 2021
1 parent 701ab68 commit d07895e
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 29 deletions.
56 changes: 38 additions & 18 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"github.com/andersfylling/disgord/internal/httd"
)

var DefaultHttpClient = &http.Client{}

// New create a Client. But panics on configuration/setup errors.
func New(conf Config) *Client {
client, err := NewClient(context.Background(), conf)
Expand Down Expand Up @@ -58,7 +60,7 @@ func createClient(ctx context.Context, conf *Config) (c *Client, err error) {
}
if conf.HTTPClient == nil {
// WARNING: do not set http.Client.Timeout (!)
conf.HTTPClient = &http.Client{}
conf.HTTPClient = DefaultHttpClient
} else if conf.HTTPClient.Timeout > 0 {
// https://github.com/nhooyr/websocket/issues/67
return nil, errors.New("do not set timeout in the http.Client, use context.Context instead")
Expand All @@ -70,6 +72,16 @@ func createClient(ctx context.Context, conf *Config) (c *Client, err error) {
},
}
}
if conf.HttpClient == nil {
if conf.HTTPClient != nil {
conf.HttpClient = conf.HTTPClient
} else {
return nil, errors.New("missing configured HTTP client")
}
}
if conf.WebsocketHttpClient == nil {
conf.WebsocketHttpClient = DefaultHttpClient
}

if conf.Intents > 0 {
conf.DMIntents |= conf.Intents
Expand Down Expand Up @@ -111,7 +123,7 @@ func createClient(ctx context.Context, conf *Config) (c *Client, err error) {
UserAgentSourceURL: constant.GitHubURL,
UserAgentVersion: constant.Version,
UserAgentExtra: conf.ProjectName,
HTTPClient: conf.HTTPClient,
HttpClient: conf.HTTPClient,
CancelRequestWhenRateLimited: conf.CancelRequestWhenRateLimited,
RESTBucketManager: conf.RESTBucketManager,
})
Expand Down Expand Up @@ -148,17 +160,16 @@ func createClient(ctx context.Context, conf *Config) (c *Client, err error) {

// create a disgord Client/instance/session
c = &Client{
shutdownChan: conf.shutdownChan,
config: conf,
httpClient: conf.HTTPClient,
proxy: conf.Proxy,
botToken: conf.BotToken,
dispatcher: dispatch,
req: httdClient,
cache: cache,
log: conf.Logger,
pool: newPools(),
eventChan: evtChan,
shutdownChan: conf.shutdownChan,
config: conf,
WebsocketHttpClient: conf.WebsocketHttpClient,
botToken: conf.BotToken,
dispatcher: dispatch,
req: httdClient,
cache: cache,
log: conf.Logger,
pool: newPools(),
eventChan: evtChan,
}
c.handlers.c = c // parent reference
c.dispatcher.addSessionInstance(c)
Expand All @@ -182,6 +193,10 @@ func createClient(ctx context.Context, conf *Config) (c *Client, err error) {

type ShardConfig = gateway.ShardConfig

type HttpClientDoer interface {
Do(req *http.Request) (*http.Response, error)
}

// Config Configuration for the Disgord Client
type Config struct {
// ################################################
Expand All @@ -192,9 +207,16 @@ type Config struct {
// ## what they are doing.
// ##
// ################################################
BotToken string
BotToken string

HttpClient HttpClientDoer
WebsocketHttpClient *http.Client

// Deprecated: use WebsocketHttpClient and HttpClient
HTTPClient *http.Client
Proxy proxy.Dialer

// Deprecated: use WebsocketHttpClient and HttpClient
Proxy proxy.Dialer

// Deprecated: use DMIntents (values here are copied to DMIntents for now)
// For direct communication with you bot you must specify intents
Expand Down Expand Up @@ -291,9 +313,7 @@ type Client struct {
// req holds the rate limiting logic and error parsing unique for Discord
req *httd.Client

// http Client used for connections
httpClient *http.Client
proxy proxy.Dialer
WebsocketHttpClient *http.Client

shardManager gateway.ShardManager
eventChan chan *gateway.Event
Expand Down
26 changes: 22 additions & 4 deletions docs/examples/proxy/bot.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package main

import (
"context"
"net"
"net/http"
"os"

"golang.org/x/net/proxy"
Expand All @@ -11,17 +14,32 @@ import (
// In the event that the Discord connections need to be routed
// through a proxy, you can do so by using this approach. In
// this example we will be using SOCKS5, but any custom
// implementation can be used as long as they satisfy the
// proxy.Dialer interface.
// implementation can be used. You just configure your own http client.
//
// For REST methods the only Do method is required. So any configuration, libraries, whatever that
// implements the Do method is good enough.
//
// For websocket connection you must specify the WebsocketHttpClient config option. Currently there is a issue
// when specifying http.Client timeouts for websocket, which is why you have the option to specify both.
// When a WebsocketHttpClient is not specified, a default config is utilised.
func main() {
p, err := proxy.SOCKS5("tcp", "localhost:8080", nil, proxy.Direct)
if err != nil {
panic(err)
}

httpClient := &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (conn net.Conn, e error) {
return p.Dial(network, addr)
},
},
}

client := disgord.New(disgord.Config{
BotToken: os.Getenv("DISCORD_TOKEN"),
Proxy: p, // Anything satisfying the proxy.Dialer interface will work
BotToken: os.Getenv("DISCORD_TOKEN"),
HttpClient: httpClient, // REST requests with proxy support
WebsocketHttpClient: httpClient, // Websocket setup with proxy support
})
defer client.Gateway().StayConnectedUntilInterrupted()
}
1 change: 1 addition & 0 deletions gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func (g gatewayQueryBuilder) Connect() (err error) {
}

shardMngrConf := gateway.ShardManagerConfig{
HTTPClient: g.client.WebsocketHttpClient,
ShardConfig: g.client.config.ShardConfig,
Logger: g.client.config.Logger,
ShutdownChan: g.client.config.shutdownChan,
Expand Down
16 changes: 9 additions & 7 deletions internal/httd/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,15 @@ func (e *ErrREST) Error() string {
return fmt.Sprintf("%s\n%s\n%s => %+v", e.Msg, e.Suggestion, e.HashedEndpoint, e.Bucket)
}

type HttpClientDoer interface {
Do(req *http.Request) (*http.Response, error)
}

// Client for handling Discord REST requests
type Client struct {
url string // base url with API version
reqHeader http.Header
httpClient *http.Client
httpClient HttpClientDoer
cancelRequestWhenRateLimited bool
buckets RESTBucketManager
}
Expand Down Expand Up @@ -131,10 +135,8 @@ func NewClient(conf *Config) (*Client, error) {
return nil, errors.New("no Discord Bot Token was provided")
}

// if no http client was provided, create a new one
if conf.HTTPClient == nil {
// no need for a timeout, everything uses context.Context now
conf.HTTPClient = &http.Client{}
if conf.HttpClient == nil {
return nil, errors.New("missing http client")
}

if conf.RESTBucketManager == nil {
Expand All @@ -160,7 +162,7 @@ func NewClient(conf *Config) (*Client, error) {
return &Client{
url: BaseURL + "/v" + strconv.Itoa(conf.APIVersion),
reqHeader: header,
httpClient: conf.HTTPClient,
httpClient: conf.HttpClient,
buckets: conf.RESTBucketManager,
}, nil
}
Expand All @@ -171,7 +173,7 @@ type Config struct {
APIVersion int
BotToken string

HTTPClient *http.Client
HttpClient HttpClientDoer

CancelRequestWhenRateLimited bool

Expand Down

0 comments on commit d07895e

Please sign in to comment.