2021-01-29 04:47:48 +00:00
|
|
|
package groupme
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
2023-09-19 02:34:54 +00:00
|
|
|
"gitea.watsonlabs.net/watsonb8/fayec"
|
|
|
|
"gitea.watsonlabs.net/watsonb8/fayec/message"
|
|
|
|
"gitea.watsonlabs.net/watsonb8/fayec/subscription"
|
2021-01-29 04:47:48 +00:00
|
|
|
"log"
|
2021-03-04 06:21:23 +00:00
|
|
|
"strings"
|
2021-01-29 04:47:48 +00:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2023-09-19 02:34:54 +00:00
|
|
|
PushServer = "wss://push.groupme.com/faye"
|
|
|
|
userChannel = "/user/"
|
|
|
|
groupChannel = "/group/"
|
|
|
|
dmChannel = "/direct_message/"
|
2021-01-29 04:47:48 +00:00
|
|
|
)
|
|
|
|
|
2021-05-08 19:35:08 +00:00
|
|
|
var (
|
|
|
|
ErrHandlerNotFound = errors.New("Handler not found")
|
|
|
|
ErrListenerNotStarted = errors.New("GroupMe listener not started")
|
|
|
|
)
|
|
|
|
|
2021-01-29 04:47:48 +00:00
|
|
|
var concur = sync.Mutex{}
|
|
|
|
|
2021-03-04 06:21:23 +00:00
|
|
|
type HandlerAll interface {
|
|
|
|
Handler
|
2021-05-08 19:35:08 +00:00
|
|
|
|
|
|
|
//of self
|
2021-03-04 06:21:23 +00:00
|
|
|
HandlerText
|
|
|
|
HandlerLike
|
|
|
|
HandlerMembership
|
2021-05-08 19:35:08 +00:00
|
|
|
|
|
|
|
//of group
|
|
|
|
HandleGroupTopic
|
|
|
|
HandleGroupAvatar
|
|
|
|
HandleGroupName
|
|
|
|
HandleGroupLikeIcon
|
|
|
|
|
|
|
|
//of group members
|
|
|
|
HandleMemberNewNickname
|
|
|
|
HandleMemberNewAvatar
|
|
|
|
HandleMembers
|
2021-01-29 04:47:48 +00:00
|
|
|
}
|
2021-02-22 03:53:43 +00:00
|
|
|
type Handler interface {
|
|
|
|
HandleError(error)
|
|
|
|
}
|
|
|
|
type HandlerText interface {
|
|
|
|
HandleTextMessage(Message)
|
|
|
|
}
|
|
|
|
type HandlerLike interface {
|
2021-05-08 19:35:08 +00:00
|
|
|
HandleLike(Message)
|
2021-02-22 03:53:43 +00:00
|
|
|
}
|
2021-03-01 15:06:01 +00:00
|
|
|
type HandlerMembership interface {
|
|
|
|
HandleJoin(ID)
|
|
|
|
}
|
2021-02-22 03:53:43 +00:00
|
|
|
|
2023-09-19 02:34:54 +00:00
|
|
|
// Group Handlers
|
2021-05-08 19:35:08 +00:00
|
|
|
type HandleGroupTopic interface {
|
2021-03-04 06:21:23 +00:00
|
|
|
HandleGroupTopic(group ID, newTopic string)
|
2021-05-08 19:35:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type HandleGroupName interface {
|
2021-03-04 06:21:23 +00:00
|
|
|
HandleGroupName(group ID, newName string)
|
2021-05-08 19:35:08 +00:00
|
|
|
}
|
|
|
|
type HandleGroupAvatar interface {
|
2021-03-04 06:21:23 +00:00
|
|
|
HandleGroupAvatar(group ID, newAvatar string)
|
2021-05-08 19:35:08 +00:00
|
|
|
}
|
|
|
|
type HandleGroupLikeIcon interface {
|
2021-03-04 06:21:23 +00:00
|
|
|
HandleLikeIcon(group ID, PackID, PackIndex int, Type string)
|
|
|
|
}
|
|
|
|
|
2023-09-19 02:34:54 +00:00
|
|
|
// Group member handlers
|
2021-05-08 19:35:08 +00:00
|
|
|
type HandleMemberNewNickname interface {
|
2021-03-04 06:21:23 +00:00
|
|
|
HandleNewNickname(group ID, user ID, newName string)
|
2021-05-08 19:35:08 +00:00
|
|
|
}
|
2021-03-05 05:43:05 +00:00
|
|
|
|
2021-05-08 19:35:08 +00:00
|
|
|
type HandleMemberNewAvatar interface {
|
|
|
|
HandleNewAvatarInGroup(group ID, user ID, avatarURL string)
|
|
|
|
}
|
|
|
|
type HandleMembers interface {
|
2021-03-05 05:43:05 +00:00
|
|
|
//HandleNewMembers returns only partial member with id and nickname; added is false if removing
|
|
|
|
HandleMembers(group ID, members []Member, added bool)
|
2021-03-04 06:21:23 +00:00
|
|
|
}
|
|
|
|
|
2023-09-19 02:34:54 +00:00
|
|
|
// PushSubscription manages real time subscription
|
2021-01-29 04:47:48 +00:00
|
|
|
type PushSubscription struct {
|
2023-09-19 02:34:54 +00:00
|
|
|
channel chan message.Data
|
|
|
|
client *fayec.Client
|
2023-09-21 15:53:49 +00:00
|
|
|
handlers map[string][]Handler // key == token
|
2021-03-04 06:21:23 +00:00
|
|
|
LastConnected int64
|
2021-01-29 04:47:48 +00:00
|
|
|
}
|
|
|
|
|
2023-09-19 02:34:54 +00:00
|
|
|
// NewPushSubscription creates and returns a push subscription object
|
2021-01-29 04:47:48 +00:00
|
|
|
func NewPushSubscription(context context.Context) PushSubscription {
|
|
|
|
|
|
|
|
r := PushSubscription{
|
2023-09-21 15:53:49 +00:00
|
|
|
channel: make(chan message.Data),
|
|
|
|
handlers: make(map[string][]Handler),
|
2021-01-29 04:47:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2023-09-21 15:53:49 +00:00
|
|
|
func (r *PushSubscription) AddHandler(h Handler, authToken string) {
|
|
|
|
if r.handlers[authToken] == nil {
|
|
|
|
r.handlers[authToken] = []Handler{h}
|
|
|
|
} else {
|
|
|
|
r.handlers[authToken] = append(r.handlers[authToken], h)
|
|
|
|
}
|
|
|
|
//r.handlers = append(r.handlers, h)
|
2021-02-22 03:53:43 +00:00
|
|
|
}
|
|
|
|
|
2023-09-19 02:34:54 +00:00
|
|
|
// AddFullHandler is the same as AddHandler except it ensures the interface implements everything
|
2023-09-21 15:53:49 +00:00
|
|
|
func (r *PushSubscription) AddFullHandler(h HandlerAll, authToken string) {
|
|
|
|
if r.handlers[authToken] == nil {
|
|
|
|
r.handlers[authToken] = []Handler{h}
|
|
|
|
} else {
|
|
|
|
r.handlers[authToken] = append(r.handlers[authToken], h)
|
|
|
|
}
|
|
|
|
|
|
|
|
//r.handlers = append(r.handlers, h)
|
2021-03-04 06:21:23 +00:00
|
|
|
}
|
|
|
|
|
2023-09-21 15:53:49 +00:00
|
|
|
var RealTimeHandlers map[string]func(r *PushSubscription, channel string, authToken string, data ...interface{})
|
|
|
|
var RealTimeSystemHandlers map[string]func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte)
|
2021-03-04 06:21:23 +00:00
|
|
|
|
2023-09-19 02:34:54 +00:00
|
|
|
// Listen connects to GroupMe. Runs in Goroutine.
|
2023-09-20 02:08:46 +00:00
|
|
|
func (r *PushSubscription) Connect(context context.Context) error {
|
|
|
|
c, err := fayec.NewClient(PushServer)
|
2023-09-19 02:34:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
r.client = c
|
|
|
|
|
|
|
|
return nil
|
2021-01-29 04:47:48 +00:00
|
|
|
}
|
|
|
|
|
2023-09-19 02:34:54 +00:00
|
|
|
// SubscribeToUser to users
|
2023-09-20 02:08:46 +00:00
|
|
|
func (r *PushSubscription) SubscribeToUser(context context.Context, id ID, authToken string) error {
|
|
|
|
return r.subscribeWithPrefix(userChannel, context, id, authToken)
|
2021-03-04 06:21:23 +00:00
|
|
|
}
|
|
|
|
|
2023-09-19 02:34:54 +00:00
|
|
|
// SubscribeToGroup to groups for typing notification
|
2023-09-20 02:08:46 +00:00
|
|
|
func (r *PushSubscription) SubscribeToGroup(context context.Context, id ID, authToken string) error {
|
|
|
|
return r.subscribeWithPrefix(groupChannel, context, id, authToken)
|
2021-03-04 06:21:23 +00:00
|
|
|
}
|
|
|
|
|
2023-09-19 02:34:54 +00:00
|
|
|
// SubscribeToDM to users
|
2023-09-20 02:08:46 +00:00
|
|
|
func (r *PushSubscription) SubscribeToDM(context context.Context, id ID, authToken string) error {
|
2021-05-08 19:35:08 +00:00
|
|
|
id = ID(strings.Replace(id.String(), "+", "_", 1))
|
2023-09-20 02:08:46 +00:00
|
|
|
return r.subscribeWithPrefix(dmChannel, context, id, authToken)
|
2021-01-29 04:47:48 +00:00
|
|
|
}
|
|
|
|
|
2023-09-20 02:08:46 +00:00
|
|
|
func (r *PushSubscription) subscribeWithPrefix(prefix string, context context.Context, groupID ID, authToken string) error {
|
2021-01-29 04:47:48 +00:00
|
|
|
concur.Lock()
|
|
|
|
defer concur.Unlock()
|
2023-09-19 02:34:54 +00:00
|
|
|
if r.client == nil {
|
2021-05-08 19:35:08 +00:00
|
|
|
return ErrListenerNotStarted
|
2021-01-29 04:47:48 +00:00
|
|
|
}
|
|
|
|
|
2023-09-19 02:34:54 +00:00
|
|
|
var sub *subscription.Subscription
|
2023-09-20 02:08:46 +00:00
|
|
|
sub, err := r.client.Subscribe(prefix+groupID.String(), authToken)
|
2023-09-19 02:34:54 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = sub.OnMessage(func(channel string, data message.Data) {
|
|
|
|
r.LastConnected = time.Now().Unix()
|
|
|
|
dataMap := data.(map[string]interface{})
|
|
|
|
content := dataMap["subject"]
|
|
|
|
contentType := dataMap["type"].(string)
|
|
|
|
|
|
|
|
handler, ok := RealTimeHandlers[contentType]
|
|
|
|
if !ok {
|
|
|
|
if contentType == "ping" ||
|
|
|
|
len(contentType) == 0 ||
|
|
|
|
content == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
log.Println("Unable to handle GroupMe message type", contentType)
|
|
|
|
}
|
|
|
|
|
2023-09-21 15:53:49 +00:00
|
|
|
handler(r, channel, authToken, content)
|
2023-09-19 02:34:54 +00:00
|
|
|
})
|
2021-01-29 04:47:48 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-09-19 02:34:54 +00:00
|
|
|
// Connected check if connected
|
2021-03-04 06:21:23 +00:00
|
|
|
func (r *PushSubscription) Connected() bool {
|
|
|
|
return r.LastConnected+30 >= time.Now().Unix()
|
|
|
|
}
|