diff --git a/request.go b/request.go index 6945fd7b..9a679e24 100644 --- a/request.go +++ b/request.go @@ -139,13 +139,15 @@ func (cli *Client) sendIQAsync(query infoQuery) (<-chan *waBinary.Node, error) { return ch, err } +const defaultRequestTimeout = 75 * time.Second + func (cli *Client) sendIQ(query infoQuery) (*waBinary.Node, error) { resChan, data, err := cli.sendIQAsyncAndGetData(&query) if err != nil { return nil, err } if query.Timeout == 0 { - query.Timeout = 75 * time.Second + query.Timeout = defaultRequestTimeout } if query.Context == nil { query.Context = context.Background() diff --git a/send.go b/send.go index 3bbb777d..26f786d7 100644 --- a/send.go +++ b/send.go @@ -104,6 +104,10 @@ type SendRequestExtra struct { ID types.MessageID // Should the message be sent as a peer message (protocol messages to your own devices, e.g. app state key requests) Peer bool + // A timeout for the send request. Unlike timeouts using the context parameter, this only applies + // to the actual response waiting and not preparing/encrypting the message. + // Defaults to 75 seconds. The timeout can be disabled by using a negative value. + Timeout time.Duration } // SendMessage sends the given message. @@ -148,6 +152,9 @@ func (cli *Client) SendMessage(ctx context.Context, to types.JID, message *waPro return } + if req.Timeout == 0 { + req.Timeout = defaultRequestTimeout + } if len(req.ID) == 0 { req.ID = cli.GenerateMessageID() } @@ -202,9 +209,20 @@ func (cli *Client) SendMessage(ctx context.Context, to types.JID, message *waPro return } var respNode *waBinary.Node + var timeoutChan <-chan time.Time + if req.Timeout > 0 { + timeoutChan = time.After(req.Timeout) + } else { + timeoutChan = make(<-chan time.Time) + } select { case respNode = <-respChan: + case <-timeoutChan: + cli.cancelResponse(req.ID, respChan) + err = ErrMessageTimedOut + return case <-ctx.Done(): + cli.cancelResponse(req.ID, respChan) err = ctx.Err() return }