diff --git a/internal/provider/data_source_all_usergroups.go b/internal/provider/data_source_all_usergroups.go index 4504347..2ce3d85 100644 --- a/internal/provider/data_source_all_usergroups.go +++ b/internal/provider/data_source_all_usergroups.go @@ -7,6 +7,8 @@ import ( "context" "fmt" + "github.com/essent/terraform-provider-slack/internal/slackExt" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" @@ -21,7 +23,7 @@ func NewAllUserGroupsDataSource() datasource.DataSource { } type AllUserGroupsDataSource struct { - client *slack.Client + client slackExt.Client } type AllUserGroupsDataSourceModel struct { diff --git a/internal/provider/data_source_all_users.go b/internal/provider/data_source_all_users.go index c28c0cb..46e3a05 100644 --- a/internal/provider/data_source_all_users.go +++ b/internal/provider/data_source_all_users.go @@ -7,11 +7,12 @@ import ( "context" "fmt" + "github.com/essent/terraform-provider-slack/internal/slackExt" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" - "github.com/slack-go/slack" ) var _ datasource.DataSource = &AllUsersDataSource{} @@ -21,7 +22,7 @@ func NewAllUsersDataSource() datasource.DataSource { } type AllUsersDataSource struct { - client *slack.Client + client slackExt.Client } type AllUsersDataSourceModel struct { diff --git a/internal/provider/data_source_user.go b/internal/provider/data_source_user.go index 163fceb..c4a7745 100644 --- a/internal/provider/data_source_user.go +++ b/internal/provider/data_source_user.go @@ -7,6 +7,8 @@ import ( "context" "fmt" + "github.com/essent/terraform-provider-slack/internal/slackExt" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" @@ -24,7 +26,7 @@ func NewUserDataSource() datasource.DataSource { } type UserDataSource struct { - client *slack.Client + client slackExt.Client } type UserDataSourceModel struct { diff --git a/internal/provider/provider.go b/internal/provider/provider.go index a7bce2d..17b8304 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -8,6 +8,8 @@ import ( "fmt" "os" + "github.com/essent/terraform-provider-slack/internal/slackExt" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/function" "github.com/hashicorp/terraform-plugin-framework/provider" @@ -30,7 +32,7 @@ type SlackProviderModel struct { } type SlackProviderData struct { - Client *slack.Client + Client slackExt.Client } func (p *SlackProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { @@ -83,8 +85,8 @@ func (p *SlackProvider) Configure(ctx context.Context, req provider.ConfigureReq return } - resp.DataSourceData = &SlackProviderData{Client: client} - resp.ResourceData = &SlackProviderData{Client: client} + resp.DataSourceData = &SlackProviderData{Client: slackExt.New(client)} + resp.ResourceData = &SlackProviderData{Client: slackExt.New(client)} } func (p *SlackProvider) Resources(ctx context.Context) []func() resource.Resource { diff --git a/internal/slackExt/client.go b/internal/slackExt/client.go new file mode 100644 index 0000000..1a36623 --- /dev/null +++ b/internal/slackExt/client.go @@ -0,0 +1,18 @@ +package slackExt + +import ( + "context" + + "github.com/slack-go/slack" +) + +type Client interface { + GetUserInfo(user string) (*slack.User, error) + GetUserByEmail(email string) (*slack.User, error) + GetUsersContext(ctx context.Context) ([]slack.User, error) + GetUserGroups(options ...slack.GetUserGroupsOption) ([]slack.UserGroup, error) +} + +func New(base *slack.Client) Client { + return &clientRateLimit{&clientImpl{base}} +} diff --git a/internal/slackExt/client_impl.go b/internal/slackExt/client_impl.go new file mode 100644 index 0000000..291b435 --- /dev/null +++ b/internal/slackExt/client_impl.go @@ -0,0 +1,27 @@ +package slackExt + +import ( + "context" + + "github.com/slack-go/slack" +) + +type clientImpl struct { + base *slack.Client +} + +func (c *clientImpl) GetUserInfo(user string) (*slack.User, error) { + return c.base.GetUserInfo(user) +} + +func (c *clientImpl) GetUserByEmail(email string) (*slack.User, error) { + return c.base.GetUserByEmail(email) +} + +func (c *clientImpl) GetUsersContext(ctx context.Context) ([]slack.User, error) { + return c.base.GetUsersContext(ctx) +} + +func (c *clientImpl) GetUserGroups(options ...slack.GetUserGroupsOption) ([]slack.UserGroup, error) { + return c.base.GetUserGroups(options...) +} diff --git a/internal/slackExt/client_rate_limit.go b/internal/slackExt/client_rate_limit.go new file mode 100644 index 0000000..7f88321 --- /dev/null +++ b/internal/slackExt/client_rate_limit.go @@ -0,0 +1,49 @@ +package slackExt + +import ( + "context" + "time" + + "github.com/slack-go/slack" +) + +type clientRateLimit struct { + base Client +} + +func rateLimit[R any](f func() (R, error)) (R, error) { + for { + result, err := f() + + if err == nil { + return result, nil + } + + if rateLimitedError, ok := err.(*slack.RateLimitedError); ok { + <-time.After(rateLimitedError.RetryAfter) + err = nil + } + } +} + +func (c *clientRateLimit) GetUserInfo(user string) (result *slack.User, err error) { + return rateLimit(func() (*slack.User, error) { + return c.base.GetUserInfo(user) + }) +} + +func (c *clientRateLimit) GetUserByEmail(email string) (*slack.User, error) { + return c.base.GetUserByEmail(email) +} + +func (c *clientRateLimit) GetUsersContext(ctx context.Context) ([]slack.User, error) { + return rateLimit(func() ([]slack.User, error) { + return c.base.GetUsersContext(ctx) + }) +} + +func (c *clientRateLimit) GetUserGroups(options ...slack.GetUserGroupsOption) ([]slack.UserGroup, error) { + return rateLimit(func() ([]slack.UserGroup, error) { + return c.base.GetUserGroups(options...) + }) +}