diff --git a/codersdk/agentsdk/agentsdk.go b/codersdk/agentsdk/agentsdk.go index 3b865f04ad8a6..a6c8e5b1ea620 100644 --- a/codersdk/agentsdk/agentsdk.go +++ b/codersdk/agentsdk/agentsdk.go @@ -45,10 +45,16 @@ var ExternalLogSourceID = uuid.MustParse("3b579bf4-1ed8-4b99-87a8-e9a1e3410410") // @typescript-ignore SessionTokenSetup type SessionTokenSetup func(client *codersdk.Client) RefreshableSessionTokenProvider -func New(serverURL *url.URL, setup SessionTokenSetup) *Client { - c := codersdk.New(serverURL) - provider := setup(c) - c.SessionTokenProvider = provider +// New creates a new *Client which can be used by an agent to connect to Coderd. Use a SessionTokenSetup function +// to define the session token provider for the Client. This overrides the SessionTokenProvider on the underlying +// `*codersdk.Client`, so any `codersdk.ClientOptions` passed as `opts` should not set this property. +func New(serverURL *url.URL, setup SessionTokenSetup, opts ...codersdk.ClientOption) *Client { + var provider RefreshableSessionTokenProvider + opts = append(opts, func(c *codersdk.Client) { + provider = setup(c) + c.SessionTokenProvider = provider + }) + c := codersdk.New(serverURL, opts...) return &Client{ SDK: c, RefreshableSessionTokenProvider: provider, diff --git a/codersdk/client.go b/codersdk/client.go index b6f10465e3a07..6c1003d0c9a0d 100644 --- a/codersdk/client.go +++ b/codersdk/client.go @@ -105,13 +105,19 @@ var loggableMimeTypes = map[string]struct{}{ "text/html": {}, } +type ClientOption func(*Client) + // New creates a Coder client for the provided URL. -func New(serverURL *url.URL) *Client { - return &Client{ +func New(serverURL *url.URL, opts ...ClientOption) *Client { + client := &Client{ URL: serverURL, HTTPClient: &http.Client{}, SessionTokenProvider: FixedSessionTokenProvider{}, } + for _, opt := range opts { + opt(client) + } + return client } // Client is an HTTP caller for methods to the Coder API. @@ -129,15 +135,18 @@ type Client struct { // PlainLogger may be set to log HTTP traffic in a human-readable form. // It uses the LogBodies option. + // Deprecated: Use WithPlainLogger to set this. PlainLogger io.Writer // Trace can be enabled to propagate tracing spans to the Coder API. // This is useful for tracking a request end-to-end. + // Deprecated: Use WithTrace to set this. Trace bool // DisableDirectConnections forces any connections to workspaces to go // through DERP, regardless of the BlockEndpoints setting on each // connection. + // Deprecated: Use WithDisableDirectConnections to set this. DisableDirectConnections bool } @@ -149,6 +158,7 @@ func (c *Client) Logger() slog.Logger { } // SetLogger sets the logger for the client. +// Deprecated: Use WithLogger to set this. func (c *Client) SetLogger(logger slog.Logger) { c.mu.Lock() defer c.mu.Unlock() @@ -163,6 +173,7 @@ func (c *Client) LogBodies() bool { } // SetLogBodies sets whether to log request and response bodies. +// Deprecated: Use WithLogBodies to set this. func (c *Client) SetLogBodies(logBodies bool) { c.mu.Lock() defer c.mu.Unlock() @@ -177,16 +188,11 @@ func (c *Client) SessionToken() string { } // SetSessionToken sets a fixed token for the client. -// Deprecated: Create a new client instead of changing the token after creation. +// Deprecated: Create a new client using WithSessionToken instead of changing the token after creation. func (c *Client) SetSessionToken(token string) { - c.SetSessionTokenProvider(FixedSessionTokenProvider{SessionToken: token}) -} - -// SetSessionTokenProvider sets the session token provider for the client. -func (c *Client) SetSessionTokenProvider(provider SessionTokenProvider) { c.mu.Lock() defer c.mu.Unlock() - c.SessionTokenProvider = provider + c.SessionTokenProvider = FixedSessionTokenProvider{SessionToken: token} } func prefixLines(prefix, s []byte) []byte { @@ -641,3 +647,47 @@ func (h *HeaderTransport) CloseIdleConnections() { tr.CloseIdleConnections() } } + +// ClientOptions + +func WithSessionToken(token string) ClientOption { + return func(c *Client) { + c.SessionTokenProvider = FixedSessionTokenProvider{SessionToken: token} + } +} + +func WithHTTPClient(httpClient *http.Client) ClientOption { + return func(c *Client) { + c.HTTPClient = httpClient + } +} + +func WithLogger(logger slog.Logger) ClientOption { + return func(c *Client) { + c.logger = logger + } +} + +func WithLogBodies() ClientOption { + return func(c *Client) { + c.logBodies = true + } +} + +func WithPlainLogger(plainLogger io.Writer) ClientOption { + return func(c *Client) { + c.PlainLogger = plainLogger + } +} + +func WithTrace() ClientOption { + return func(c *Client) { + c.Trace = true + } +} + +func WithDisableDirectConnections() ClientOption { + return func(c *Client) { + c.DisableDirectConnections = true + } +}