mirror of
https://github.com/nikoksr/notify.git
synced 2025-01-12 01:22:30 +02:00
146 lines
3.3 KiB
Go
146 lines
3.3 KiB
Go
|
package whatsapp
|
||
|
|
||
|
import (
|
||
|
"encoding/gob"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"time"
|
||
|
|
||
|
qrcodeTerminal "github.com/Baozisoftware/qrcode-terminal-go"
|
||
|
whatsapp "github.com/Rhymen/go-whatsapp"
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
loginWaitTimeSeconds = 3
|
||
|
clientTimeout = 5
|
||
|
)
|
||
|
|
||
|
// whatsappClient abstracts go-whatsapp for writing unit tests
|
||
|
type whatsappClient interface {
|
||
|
Send(msg interface{}) (string, error)
|
||
|
}
|
||
|
|
||
|
// Service encapsulates the WhatsApp client along with internal state for storing contacts.
|
||
|
type Service struct {
|
||
|
client whatsappClient
|
||
|
contacts []string
|
||
|
}
|
||
|
|
||
|
// New returns a new instance of a WhatsApp notification service.
|
||
|
func New() (*Service, error) {
|
||
|
client, err := whatsapp.NewConn(clientTimeout * time.Second)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
err = login(client)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
<-time.After(loginWaitTimeSeconds * time.Second)
|
||
|
|
||
|
s := &Service{
|
||
|
client: client,
|
||
|
contacts: []string{},
|
||
|
}
|
||
|
return s, nil
|
||
|
}
|
||
|
|
||
|
// login helps with the WhatsApp authentication process.
|
||
|
// Refer: https://github.com/Rhymen/go-whatsapp#login for more information.
|
||
|
func login(client *whatsapp.Conn) error {
|
||
|
session, err := readSession()
|
||
|
if err == nil {
|
||
|
session, err = client.RestoreWithSession(session)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("restoring session failed: %v", err)
|
||
|
}
|
||
|
} else {
|
||
|
// No saved session found; need to login again.
|
||
|
qr := make(chan string)
|
||
|
go func() {
|
||
|
terminal := qrcodeTerminal.New()
|
||
|
terminal.Get(<-qr).Print()
|
||
|
}()
|
||
|
|
||
|
session, err = client.Login(qr)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("error during login: %v", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
err = writeSession(&session)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("error saving session: %v", err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// readSession helps load saved WhatsApp session from local file system.
|
||
|
func readSession() (whatsapp.Session, error) {
|
||
|
session := whatsapp.Session{}
|
||
|
file, err := os.Open(os.TempDir() + "/whatsappSession.gob")
|
||
|
if err != nil {
|
||
|
return session, err
|
||
|
}
|
||
|
defer file.Close()
|
||
|
|
||
|
decoder := gob.NewDecoder(file)
|
||
|
err = decoder.Decode(&session)
|
||
|
if err != nil {
|
||
|
return session, err
|
||
|
}
|
||
|
|
||
|
return session, nil
|
||
|
}
|
||
|
|
||
|
// writeSession helps save WhatsApp session to local file system.
|
||
|
func writeSession(session *whatsapp.Session) error {
|
||
|
file, err := os.Create(os.TempDir() + "/whatsappSession.gob")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer file.Close()
|
||
|
|
||
|
encoder := gob.NewEncoder(file)
|
||
|
err = encoder.Encode(*session)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// AddReceivers takes WhatsApp contacts and adds them to the internal contacts list. The Send method will send
|
||
|
// a given message to all those contacts.
|
||
|
func (s *Service) AddReceivers(contacts ...string) {
|
||
|
s.contacts = append(s.contacts, contacts...)
|
||
|
}
|
||
|
|
||
|
// Send takes a message subject and a message body and sends them to all previously set contacts.
|
||
|
func (s *Service) Send(subject, message string) error {
|
||
|
if len(s.contacts) == 0 {
|
||
|
return fmt.Errorf("no contacts added as receivers")
|
||
|
}
|
||
|
|
||
|
msgText := subject + "\n" + message
|
||
|
for _, c := range s.contacts {
|
||
|
contact := c + "@s.whatsapp.net"
|
||
|
msg := whatsapp.TextMessage{
|
||
|
Info: whatsapp.MessageInfo{
|
||
|
RemoteJid: contact,
|
||
|
},
|
||
|
Text: msgText,
|
||
|
}
|
||
|
|
||
|
if _, err := s.client.Send(msg); err != nil {
|
||
|
return errors.Wrapf(err, "failed to send message to WhatsApp contact '%s'", c)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|