mirror of
https://github.com/nikoksr/notify.git
synced 2025-07-15 01:34:58 +02:00
fmt/linter ran in correct order
This commit is contained in:
2
Makefile
2
Makefile
@ -27,7 +27,7 @@ test:
|
|||||||
|
|
||||||
# gofumports and gci all go files
|
# gofumports and gci all go files
|
||||||
fmt:
|
fmt:
|
||||||
find . -name '*.go' -not -wholename './vendor/*' | while read -r file; do gofumports -w "$$file"; done
|
find . -name '*.go' -not -wholename './vendor/*' | while read -r file; do gofumpt -w "$$file"; done
|
||||||
gci -w -local github.com/nikoksr/notify .
|
gci -w -local github.com/nikoksr/notify .
|
||||||
.PHONY: fmt
|
.PHONY: fmt
|
||||||
|
|
||||||
|
@ -1,58 +1,56 @@
|
|||||||
package wechat
|
package wechat
|
||||||
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pkg/errors"
|
"net/http"
|
||||||
"github.com/silenceper/wechat/v2"
|
"sync"
|
||||||
"github.com/silenceper/wechat/v2/cache"
|
|
||||||
"github.com/silenceper/wechat/v2/officialaccount/config"
|
|
||||||
"github.com/silenceper/wechat/v2/officialaccount/message"
|
|
||||||
"github.com/silenceper/wechat/v2/util"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/silenceper/wechat/v2"
|
||||||
|
"github.com/silenceper/wechat/v2/cache"
|
||||||
|
"github.com/silenceper/wechat/v2/officialaccount/config"
|
||||||
|
"github.com/silenceper/wechat/v2/officialaccount/message"
|
||||||
|
"github.com/silenceper/wechat/v2/util"
|
||||||
|
)
|
||||||
|
|
||||||
// Config is the Service configuration.
|
// Config is the Service configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
AppID string
|
AppID string
|
||||||
AppSecret string
|
AppSecret string
|
||||||
Token string
|
Token string
|
||||||
EncodingAESKey string
|
EncodingAESKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
// wechatMessageManager abstracts go-wechat's message.Manager for writing unit tests
|
// wechatMessageManager abstracts go-wechat's message.Manager for writing unit tests
|
||||||
type wechatMessageManager interface {
|
type wechatMessageManager interface {
|
||||||
Send(msg *message.CustomerMessage) error
|
Send(msg *message.CustomerMessage) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Service encapsulates the WeChat client along with internal state for storing users.
|
// Service encapsulates the WeChat client along with internal state for storing users.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
config Config
|
config Config
|
||||||
messageManager wechatMessageManager
|
messageManager wechatMessageManager
|
||||||
userIDs []string
|
userIDs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new instance of a WeChat notification service.
|
// New returns a new instance of a WeChat notification service.
|
||||||
func New(cfg Config) *Service {
|
func New(cfg Config) *Service {
|
||||||
|
wc := wechat.NewWechat()
|
||||||
|
wcCfg := &config.Config{
|
||||||
|
AppID: cfg.AppID,
|
||||||
|
AppSecret: cfg.AppSecret,
|
||||||
|
Token: cfg.Token,
|
||||||
|
EncodingAESKey: cfg.EncodingAESKey,
|
||||||
|
Cache: cache.NewMemory(),
|
||||||
|
}
|
||||||
|
|
||||||
wc := wechat.NewWechat()
|
oa := wc.GetOfficialAccount(wcCfg)
|
||||||
wcCfg := &config.Config{
|
|
||||||
AppID: cfg.AppID,
|
|
||||||
AppSecret: cfg.AppSecret,
|
|
||||||
Token: cfg.Token,
|
|
||||||
EncodingAESKey: cfg.EncodingAESKey,
|
|
||||||
Cache: cache.NewMemory(),
|
|
||||||
}
|
|
||||||
|
|
||||||
oa := wc.GetOfficialAccount(wcCfg)
|
return &Service{
|
||||||
|
config: cfg,
|
||||||
return &Service{
|
messageManager: oa.GetCustomerMessageManager(),
|
||||||
config: cfg,
|
}
|
||||||
messageManager: oa.GetCustomerMessageManager(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitForOneOffVerification waits for the verification call from the WeChat backend.
|
// WaitForOneOffVerification waits for the verification call from the WeChat backend.
|
||||||
@ -63,84 +61,84 @@ func New(cfg Config) *Service {
|
|||||||
//
|
//
|
||||||
// See https://developers.weixin.qq.com/doc/offiaccount/en/Basic_Information/Access_Overview.html
|
// See https://developers.weixin.qq.com/doc/offiaccount/en/Basic_Information/Access_Overview.html
|
||||||
func (s *Service) WaitForOneOffVerification(
|
func (s *Service) WaitForOneOffVerification(
|
||||||
addr string,
|
addr string,
|
||||||
devMode bool,
|
devMode bool,
|
||||||
callback func(r *http.Request, verified bool)) error {
|
callback func(r *http.Request, verified bool)) error {
|
||||||
|
srv := &http.Server{Addr: addr}
|
||||||
|
verificationDone := &sync.WaitGroup{}
|
||||||
|
verificationDone.Add(1)
|
||||||
|
|
||||||
srv := &http.Server{Addr: addr}
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
verificationDone := &sync.WaitGroup{}
|
query := r.URL.Query()
|
||||||
verificationDone.Add(1)
|
|
||||||
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
echoStr := query.Get("echostr")
|
||||||
query := r.URL.Query()
|
if devMode {
|
||||||
|
if callback != nil {
|
||||||
|
callback(r, true)
|
||||||
|
}
|
||||||
|
_, _ = w.Write([]byte(echoStr))
|
||||||
|
// verification done; dev mode
|
||||||
|
verificationDone.Done()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
echoStr := query.Get("echostr")
|
// perform signature check
|
||||||
if devMode {
|
timestamp := query.Get("timestamp")
|
||||||
if callback != nil {
|
nonce := query.Get("nonce")
|
||||||
callback(r, true)
|
suppliedSignature := query.Get("signature")
|
||||||
}
|
computedSignature := util.Signature(s.config.Token, timestamp, nonce)
|
||||||
w.Write([]byte(echoStr))
|
if suppliedSignature == computedSignature {
|
||||||
// verification done; dev mode
|
if callback != nil {
|
||||||
verificationDone.Done()
|
callback(r, true)
|
||||||
return
|
}
|
||||||
} else {
|
_, _ = w.Write([]byte(echoStr))
|
||||||
// perform signature check
|
// verification done; prod mode
|
||||||
timestamp := query.Get("timestamp")
|
verificationDone.Done()
|
||||||
nonce := query.Get("nonce")
|
return
|
||||||
suppliedSignature := query.Get("signature")
|
}
|
||||||
computedSignature := util.Signature(s.config.Token, timestamp, nonce)
|
|
||||||
if suppliedSignature == computedSignature {
|
|
||||||
if callback != nil {
|
|
||||||
callback(r, true)
|
|
||||||
}
|
|
||||||
w.Write([]byte(echoStr))
|
|
||||||
// verification done; prod mode
|
|
||||||
verificationDone.Done()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// verification not done (keep waiting)
|
|
||||||
if callback != nil {
|
|
||||||
callback(r, false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
var err error
|
// verification not done (keep waiting)
|
||||||
go func() {
|
if callback != nil {
|
||||||
if innerErr := srv.ListenAndServe(); innerErr != http.ErrServerClosed {
|
callback(r, false)
|
||||||
err = errors.Wrapf(innerErr, "failed to wait for verification at '%s'", addr)
|
}
|
||||||
}
|
})
|
||||||
}()
|
|
||||||
|
|
||||||
// wait until verification is done and shutdown the server
|
var err error
|
||||||
verificationDone.Wait()
|
go func() {
|
||||||
|
if innerErr := srv.ListenAndServe(); innerErr != http.ErrServerClosed {
|
||||||
|
err = errors.Wrapf(innerErr, "failed to start verification listener '%s'", addr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
srv.Shutdown(context.TODO())
|
// wait until verification is done and shutdown the server
|
||||||
|
verificationDone.Wait()
|
||||||
|
|
||||||
return err
|
if innerErr := srv.Shutdown(context.TODO()); innerErr != nil {
|
||||||
|
err = errors.Wrap(innerErr, "failed to shutdown verification listerer")
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddReceivers takes user ids and adds them to the internal users list. The Send method will send
|
// AddReceivers takes user ids and adds them to the internal users list. The Send method will send
|
||||||
// a given message to all those users.
|
// a given message to all those users.
|
||||||
func (s *Service) AddReceivers(userIDs ...string) {
|
func (s *Service) AddReceivers(userIDs ...string) {
|
||||||
s.userIDs = append(s.userIDs, userIDs...)
|
s.userIDs = append(s.userIDs, userIDs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send takes a message subject and a message content and sends them to all previously set users.
|
// Send takes a message subject and a message content and sends them to all previously set users.
|
||||||
func (s *Service) Send(ctx context.Context, subject, content string) error {
|
func (s *Service) Send(ctx context.Context, subject, content string) error {
|
||||||
|
for _, userID := range s.userIDs {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
text := fmt.Sprintf("%s\n%s", subject, content)
|
||||||
|
if err := s.messageManager.Send(message.NewCustomerTextMessage(userID, text)); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to send message to WeChat user '%s'", userID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, userID := range s.userIDs {
|
return nil
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
default:
|
|
||||||
text := fmt.Sprintf("%s\n%s", subject, content)
|
|
||||||
if err := s.messageManager.Send(message.NewCustomerTextMessage(userID, text)); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to send message to WeChat user '%s'", userID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package wechat
|
package wechat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/silenceper/wechat/v2/officialaccount/message"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/silenceper/wechat/v2/officialaccount/message"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAddReceivers(t *testing.T) {
|
func TestAddReceivers(t *testing.T) {
|
||||||
@ -24,29 +25,29 @@ func TestSend(t *testing.T) {
|
|||||||
assert := require.New(t)
|
assert := require.New(t)
|
||||||
|
|
||||||
svc := &Service{
|
svc := &Service{
|
||||||
userIDs: []string{},
|
userIDs: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// test wechat message manager returning error
|
// test wechat message manager returning error
|
||||||
mockMsgManager := new(mockWechatMessageManager)
|
mockMsgManager := new(mockWechatMessageManager)
|
||||||
mockMsgManager.On("Send", message.NewCustomerTextMessage("UserID1", "subject\nmessage")).
|
mockMsgManager.On("Send", message.NewCustomerTextMessage("UserID1", "subject\nmessage")).
|
||||||
Return(errors.New("some error"))
|
Return(errors.New("some error"))
|
||||||
svc.messageManager = mockMsgManager
|
svc.messageManager = mockMsgManager
|
||||||
svc.AddReceivers("UserID1")
|
svc.AddReceivers("UserID1")
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := svc.Send(ctx, "subject", "message")
|
err := svc.Send(ctx, "subject", "message")
|
||||||
assert.NotNil(err)
|
assert.NotNil(err)
|
||||||
mockMsgManager.AssertExpectations(t)
|
mockMsgManager.AssertExpectations(t)
|
||||||
|
|
||||||
// test success and multiple receivers
|
// test success and multiple receivers
|
||||||
mockMsgManager = new(mockWechatMessageManager)
|
mockMsgManager = new(mockWechatMessageManager)
|
||||||
mockMsgManager.On("Send", message.NewCustomerTextMessage("UserID1", "subject\nmessage")).
|
mockMsgManager.On("Send", message.NewCustomerTextMessage("UserID1", "subject\nmessage")).
|
||||||
Return(nil)
|
Return(nil)
|
||||||
mockMsgManager.On("Send", message.NewCustomerTextMessage("UserID2", "subject\nmessage")).
|
mockMsgManager.On("Send", message.NewCustomerTextMessage("UserID2", "subject\nmessage")).
|
||||||
Return(nil)
|
Return(nil)
|
||||||
svc.messageManager = mockMsgManager
|
svc.messageManager = mockMsgManager
|
||||||
svc.AddReceivers("UserID1", "UserID2")
|
svc.AddReceivers("UserID1", "UserID2")
|
||||||
err = svc.Send(ctx, "subject", "message")
|
err = svc.Send(ctx, "subject", "message")
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
mockMsgManager.AssertExpectations(t)
|
mockMsgManager.AssertExpectations(t)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user