github.com/diamondburned/arikawa@v1.3.14/webhook/webhook.go (about)

     1  // Package webhook provides means to interact with webhooks directly and not
     2  // through the bot API.
     3  package webhook
     4  
     5  import (
     6  	"mime/multipart"
     7  	"net/url"
     8  	"strconv"
     9  
    10  	"github.com/pkg/errors"
    11  
    12  	"github.com/diamondburned/arikawa/api"
    13  	"github.com/diamondburned/arikawa/discord"
    14  	"github.com/diamondburned/arikawa/utils/httputil"
    15  	"github.com/diamondburned/arikawa/utils/json"
    16  )
    17  
    18  // DefaultHTTPClient is the httputil.Client used in the helper methods.
    19  var DefaultHTTPClient = httputil.NewClient()
    20  
    21  // Client is the client used to interact with a webhook.
    22  type Client struct {
    23  	// Client is the httputil.Client used to call Discord's API.
    24  	*httputil.Client
    25  	// ID is the id of the webhook.
    26  	ID discord.WebhookID
    27  	// Token is the token of the webhook.
    28  	Token string
    29  }
    30  
    31  // NewClient creates a new Client using the passed token and id.
    32  func NewClient(id discord.WebhookID, token string) *Client {
    33  	return NewCustomClient(id, token, httputil.NewClient())
    34  }
    35  
    36  // NewCustomClient creates a new Client creates a new Client using the passed
    37  // token and id and makes API calls using the passed httputil.Client
    38  func NewCustomClient(id discord.WebhookID, token string, c *httputil.Client) *Client {
    39  	return &Client{
    40  		Client: c,
    41  		ID:     id,
    42  		Token:  token,
    43  	}
    44  }
    45  
    46  // Get gets the webhook.
    47  func (c *Client) Get() (*discord.Webhook, error) {
    48  	var w *discord.Webhook
    49  	return w, c.RequestJSON(&w, "GET", api.EndpointWebhooks+c.ID.String()+"/"+c.Token)
    50  }
    51  
    52  // Modify modifies the webhook.
    53  func (c *Client) Modify(data api.ModifyWebhookData) (*discord.Webhook, error) {
    54  	var w *discord.Webhook
    55  	return w, c.RequestJSON(
    56  		&w, "PATCH",
    57  		api.EndpointWebhooks+c.ID.String()+"/"+c.Token,
    58  		httputil.WithJSONBody(data),
    59  	)
    60  }
    61  
    62  // Delete deletes a webhook permanently.
    63  func (c *Client) Delete() error {
    64  	return c.FastRequest("DELETE", api.EndpointWebhooks+c.ID.String()+"/"+c.Token)
    65  }
    66  
    67  // Execute sends a message to the webhook, but doesn't wait for the message to
    68  // get created. This is generally faster, but only applicable if no further
    69  // interaction is required.
    70  func (c *Client) Execute(data api.ExecuteWebhookData) (err error) {
    71  	_, err = c.execute(data, false)
    72  	return
    73  }
    74  
    75  // ExecuteAndWait executes the webhook, and waits for the generated
    76  // discord.Message to be returned.
    77  func (c *Client) ExecuteAndWait(data api.ExecuteWebhookData) (*discord.Message, error) {
    78  	return c.execute(data, true)
    79  }
    80  
    81  func (c *Client) execute(data api.ExecuteWebhookData, wait bool) (*discord.Message, error) {
    82  	if data.Content == "" && len(data.Embeds) == 0 && len(data.Files) == 0 {
    83  		return nil, api.ErrEmptyMessage
    84  	}
    85  
    86  	if data.AllowedMentions != nil {
    87  		if err := data.AllowedMentions.Verify(); err != nil {
    88  			return nil, errors.Wrap(err, "allowedMentions error")
    89  		}
    90  	}
    91  
    92  	for i, embed := range data.Embeds {
    93  		if err := embed.Validate(); err != nil {
    94  			return nil, errors.Wrap(err, "embed error at "+strconv.Itoa(i))
    95  		}
    96  	}
    97  
    98  	var param = url.Values{}
    99  	if wait {
   100  		param.Set("wait", "true")
   101  	}
   102  
   103  	var URL = api.EndpointWebhooks + c.ID.String() + "/" + c.Token + "?" + param.Encode()
   104  	var msg *discord.Message
   105  
   106  	if len(data.Files) == 0 {
   107  		// No files, so no need for streaming.
   108  		return msg, c.RequestJSON(&msg, "POST", URL,
   109  			httputil.WithJSONBody(data))
   110  	}
   111  
   112  	writer := func(mw *multipart.Writer) error {
   113  		return data.WriteMultipart(mw)
   114  	}
   115  
   116  	resp, err := c.MeanwhileMultipart(writer, "POST", URL)
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	var body = resp.GetBody()
   122  	defer body.Close()
   123  
   124  	if !wait {
   125  		// Since we didn't tell Discord to wait, we have nothing to parse.
   126  		return nil, nil
   127  	}
   128  
   129  	return msg, json.DecodeStream(body, &msg)
   130  }
   131  
   132  // Get is a shortcut for NewCustomClient(token, id, DefaultHTTPClient).Get().
   133  func Get(id discord.WebhookID, token string) (*discord.Webhook, error) {
   134  	return NewCustomClient(id, token, DefaultHTTPClient).Get()
   135  }
   136  
   137  // Modify is a shortcut for
   138  // NewCustomClient(token, id, DefaultHTTPClient).Modify(data).
   139  func Modify(
   140  	id discord.WebhookID, token string, data api.ModifyWebhookData) (*discord.Webhook, error) {
   141  
   142  	return NewCustomClient(id, token, DefaultHTTPClient).Modify(data)
   143  }
   144  
   145  // Delete is a shortcut for
   146  // NewCustomClient(token, id, DefaultHTTPClient).Delete().
   147  func Delete(id discord.WebhookID, token string) error {
   148  	return NewCustomClient(id, token, DefaultHTTPClient).Delete()
   149  }
   150  
   151  // Execute is a shortcut for
   152  // NewCustomClient(token, id, DefaultHTTPClient).Execute(data).
   153  func Execute(id discord.WebhookID, token string, data api.ExecuteWebhookData) error {
   154  	return NewCustomClient(id, token, DefaultHTTPClient).Execute(data)
   155  }
   156  
   157  // ExecuteAndWait is a shortcut for
   158  // NewCustomClient(token, id, DefaultHTTPClient).ExecuteAndWait(data).
   159  func ExecuteAndWait(
   160  	id discord.WebhookID, token string, data api.ExecuteWebhookData) (*discord.Message, error) {
   161  
   162  	return NewCustomClient(id, token, DefaultHTTPClient).ExecuteAndWait(data)
   163  }