nikoksr/notify

View on GitHub
service/plivo/plivo.go

Summary

Maintainability
A
35 mins
Test Coverage
package plivo

import (
    "context"
    "errors"
    "fmt"
    "net/http"
    "strings"

    plivo "github.com/plivo/plivo-go/v7"
)

// ClientOptions allow you to configure a Plivo SDK client.
type ClientOptions struct {
    AuthID    string // If empty, env variable PLIVO_AUTH_ID will be used
    AuthToken string // If empty, env variable PLIVO_AUTH_TOKEN will be used

    // Optional
    HTTPClient *http.Client // Bring Your Own Client
}

// MessageOptions allow you to configure options for sending a message.
type MessageOptions struct {
    Source string // a Plivo source phone number or a Plivo Powerpack UUID

    // Optional
    CallbackURL    string // URL to which status update callbacks for the message should be sent
    CallbackMethod string // The HTTP method to be used when calling CallbackURL - GET or POST(default)
}

// plivoMsgClient abstracts Plivo SDK for writing unit tests.
type plivoMsgClient interface {
    Create(plivo.MessageCreateParams) (*plivo.MessageCreateResponseBody, error)
}

// Service is a Plivo client.
type Service struct {
    client       plivoMsgClient
    mopts        MessageOptions
    destinations []string
}

// New creates a new instance of plivo service.
func New(cOpts *ClientOptions, mOpts *MessageOptions) (*Service, error) {
    if cOpts == nil {
        return nil, errors.New("client-options cannot be nil")
    }

    if mOpts == nil {
        return nil, errors.New("message-options cannot be nil")
    }

    if mOpts.Source == "" {
        return nil, errors.New("source cannot be empty")
    }

    client, err := plivo.NewClient(
        cOpts.AuthID,
        cOpts.AuthToken,
        &plivo.ClientOptions{
            HttpClient: cOpts.HTTPClient,
        },
    )
    if err != nil {
        return nil, err
    }

    return &Service{
        client: client.Messages,
        mopts:  *mOpts,
    }, nil
}

// AddReceivers adds the given destination phone numbers to the notifier.
func (s *Service) AddReceivers(phoneNumbers ...string) {
    s.destinations = append(s.destinations, phoneNumbers...)
}

// Send sends a SMS via Plivo to all previously added receivers.
func (s *Service) Send(ctx context.Context, subject, message string) error {
    text := subject + "\n" + message

    var dst string
    switch len(s.destinations) {
    case 0:
        return errors.New("no receivers added")
    case 1:
        dst = s.destinations[0]
    default:
        // multiple destinations, use bulk message syntax
        // see: https://www.plivo.com/docs/sms/api/message#bulk-messaging
        dst = strings.Join(s.destinations, "<")
    }

    select {
    case <-ctx.Done():
        return ctx.Err()
    default:
        _, err := s.client.Create(plivo.MessageCreateParams{
            Dst:    dst,
            Text:   text,
            Src:    s.mopts.Source,
            URL:    s.mopts.CallbackURL,
            Method: s.mopts.CallbackMethod,
        })
        if err != nil {
            return fmt.Errorf("send SMS to %q: %w", dst, err)
        }
    }

    return nil
}