Add many types of handling

fix listen loop
improve example
This commit is contained in:
Karmanyaah Malhotra 2021-03-04 01:21:23 -05:00
parent da7bc977a3
commit d6a8b0818f
2 changed files with 263 additions and 73 deletions

View File

@ -3,13 +3,17 @@ package main
import (
"context"
"fmt"
"os"
"github.com/densestvoid/groupme"
)
// This is not a real token. Please find yours by logging
// into the GroupMe development website: https://dev.groupme.com/
var authorizationToken = "ABCD"
//var authorizationToken = "ABCD"
var authorizationToken = "aa608b00a46401385ead62dd938575cf"
// A short program that gets the gets the first 5 groups
// the user is part of, and then the first 10 messages of
@ -23,7 +27,7 @@ func main() {
context.Background(),
&groupme.GroupsQuery{
Page: 0,
PerPage: 5,
PerPage: 1,
Omit: "memberships",
},
)
@ -33,49 +37,79 @@ func main() {
return
}
// fmt.Println(groups)
// Get first 10 messages of the first group
if len(groups) == 0 {
fmt.Println("No groups")
os.Exit(1)
}
// messages, err := client.IndexMessages(context.Background(), groups[0].ID, &groupme.IndexMessagesQuery{
// Limit: 10,
// })
// if err != nil {
// fmt.Println(err)
// }
// fmt.Println(messages)
p := client.NewPushSubscription(context.Background())
go p.Listen(context.Background())
p := groupme.NewPushSubscription(context.Background())
go p.StartListening(context.TODO())
client = groupme.NewClient(authorizationToken)
a, _ := client.MyUser(context.Background())
User, _ := client.MyUser(context.Background())
p.SubscribeToUser(context.Background(), User.ID, authorizationToken)
p.SubscribeToUser(context.Background(), a.ID, authorizationToken)
authorizationToken = "BCDF"
client = groupme.NewClient(authorizationToken)
a, _ = client.MyUser(context.Background())
p.SubscribeToUser(context.Background(), a.ID, authorizationToken)
for {
select {
case msg := <-p.MessageChannel:
println(msg.Text)
break
case like := <-p.LikeChannel:
println("Liked")
println(like.Message.ID.String())
println(like.Message.Text)
break
}
for _, j := range groups {
p.SubscribeToGroup(context.TODO(), j.ID, authorizationToken)
}
p.AddFullHandler(Handler{User: User})
<-make(chan (struct{}))
}
type Handler struct {
User *groupme.User
}
func (h Handler) HandleError(e error) {
fmt.Println(e)
}
func (h Handler) HandleTextMessage(msg groupme.Message) {
fmt.Println(msg.Text, msg.Name)
}
func (h Handler) HandleJoin(group groupme.ID) {
fmt.Println("User joined group with id", group.String())
}
func (h Handler) HandleLike(id groupme.ID, by []string) {
fmt.Println(id.String(), "liked by", by)
}
func (h Handler) HandlerMembership(i groupme.ID) {
fmt.Println("Membership event on", i.String())
}
func (h Handler) HandleGroupTopic(group groupme.ID, newTopic string) {
fmt.Println(group.String(), "has new topic of", newTopic)
}
func (h Handler) HandleGroupName(group groupme.ID, newName string) {
fmt.Println(group.String(), "has new name of", newName)
}
func (h Handler) HandleGroupAvatar(group groupme.ID, newAvatar string) {
fmt.Println(group.String(), "has new avatar url of", newAvatar)
}
func (h Handler) HandleLikeIcon(group groupme.ID, PackID, PackIndex int, Type string) {
//Not sure how to use without groupme icon packs
if len(Type) == 0 {
fmt.Println("Default like icon set")
return
}
fmt.Println(group.String(), "has new like icon of", PackID, PackIndex, Type)
}
func (h Handler) HandleNewNickname(group groupme.ID, user groupme.ID, newName string) {
fmt.Printf("In group %s, user %s has new nickname %s\n", group.String(), user.String(), newName)
}
func (h Handler) HandleNewAvatarInGroup(group groupme.ID, user groupme.ID, avatarURL string) {
if avatarURL == "" {
//get default avatar
avatarURL = h.User.ImageURL
}
fmt.Printf("In group %s, user %s has new avatar with url %s\n", group.String(), user.String(), avatarURL)
}

View File

@ -4,7 +4,10 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"log"
"strconv"
"strings"
"sync"
"time"
@ -15,6 +18,7 @@ const (
pushServer = "https://push.groupme.com/faye"
userChannel = "/user/"
groupChannel = "/group/"
dmChannel = "/direct_message/"
handshakeChannel = "/meta/handshake"
connectChannel = "/meta/connect"
subscribeChannel = "/meta/subscribe"
@ -32,7 +36,7 @@ func (l fayeLogger) Errorf(f string, a ...interface{}) {
log.Printf("[ERROR] : "+f, a...)
}
func (l fayeLogger) Debugf(f string, a ...interface{}) {
// log.Printf("[DEBUG] : "+f, a...)
log.Printf("[DEBUG] : "+f, a...)
}
func (l fayeLogger) Warnf(f string, a ...interface{}) {
log.Printf("[WARN] : "+f, a...)
@ -42,18 +46,14 @@ func init() {
wray.RegisterTransports([]wray.Transport{&wray.HTTPTransport{}})
}
//LikeEvent returns events as they happen from GroupMe
type LikeEvent struct {
Message Message
type HandlerAll interface {
Handler
HandlerText
HandlerLike
HandlerMembership
HandleGroupMembership
HandleGroupMetadata
}
type EventType = int
const (
EventMessage EventType = iota
EventLike
)
type Handler interface {
HandleError(error)
}
@ -61,17 +61,30 @@ type HandlerText interface {
HandleTextMessage(Message)
}
type HandlerLike interface {
HandleLike(Message)
HandleLike(messageID ID, favBy []string)
}
type HandlerMembership interface {
HandleJoin(ID)
}
type HandleGroupMetadata interface {
HandleGroupTopic(group ID, newTopic string)
HandleGroupName(group ID, newName string)
HandleGroupAvatar(group ID, newAvatar string)
HandleLikeIcon(group ID, PackID, PackIndex int, Type string)
}
type HandleGroupMembership interface {
HandleNewNickname(group ID, user ID, newName string)
HandleNewAvatarInGroup(group ID, user ID, avatarURL string)
}
//PushSubscription manages real time subscription
type PushSubscription struct {
channel chan wray.Message
fayeClient *wray.FayeClient
handlers []Handler
channel chan wray.Message
fayeClient *wray.FayeClient
handlers []Handler
LastConnected int64
}
//NewPushSubscription creates and returns a push subscription object
@ -88,6 +101,18 @@ func (r *PushSubscription) AddHandler(h Handler) {
r.handlers = append(r.handlers, h)
}
//AddFullHandler is the same as AddHandler except to ensure interface implements everything
func (r *PushSubscription) AddFullHandler(h HandlerAll) {
r.handlers = append(r.handlers, h)
}
type systemMessage struct {
Event struct {
Kind string `json:"type"`
Data interface{}
}
}
//Listen connects to GroupMe. Runs in Goroutine.
func (r *PushSubscription) StartListening(context context.Context) {
r.fayeClient = wray.NewFayeClient(pushServer)
@ -100,19 +125,34 @@ func (r *PushSubscription) StartListening(context context.Context) {
go r.fayeClient.Listen()
go func() {
for {
msg := <-r.channel
for msg := range r.channel {
r.LastConnected = time.Now().Unix()
data := msg.Data()
content, _ := data["subject"]
contentType := data["type"].(string)
channel := msg.Channel()
if strings.HasPrefix(channel, groupChannel) || strings.HasPrefix(channel, dmChannel) {
r.chatEvent(contentType, content)
}
switch contentType {
case "line.create", "direct_message.create":
case "line.create":
b, _ := json.Marshal(content)
out := Message{}
json.Unmarshal(b, &out)
//fmt.Printf("%+v\n", out) //TODO logging
_ = json.Unmarshal(b, &out)
if out.UserID.String() == "system" {
event := systemMessage{}
err := json.Unmarshal(b, &event)
if err != nil {
fmt.Println(err)
}
r.systemEvent(out.GroupID, event)
break
}
for _, h := range r.handlers {
if h, ok := h.(HandlerText); ok {
h.HandleTextMessage(out)
@ -121,19 +161,7 @@ func (r *PushSubscription) StartListening(context context.Context) {
break
case "like.create":
b, _ := json.Marshal(content.(map[string]interface{})["line"])
out := Message{}
//log.Println(string(b))
err := json.Unmarshal(b, &out)
if err != nil {
log.Println(err)
}
for _, h := range r.handlers {
if h, ok := h.(HandlerLike); ok {
h.HandleLike(out)
}
}
//should be an associated chatEvent
break
case "membership.create":
c, _ := content.(map[string]interface{})
@ -154,8 +182,7 @@ func (r *PushSubscription) StartListening(context context.Context) {
}
log.Println(contentType)
b, _ := json.Marshal(content)
log.Println(string(b))
log.Fatalln(data)
log.Fatalln(string(b))
}
@ -163,6 +190,129 @@ func (r *PushSubscription) StartListening(context context.Context) {
}()
}
func (r *PushSubscription) chatEvent(contentType string, content interface{}) {
switch contentType {
case "favorite":
b, ok := content.(map[string]interface{})["line"].(Message)
if !ok {
log.Println(content)
}
for _, h := range r.handlers {
if h, ok := h.(HandlerLike); ok {
h.HandleLike(b.UserID, b.FavoritedBy)
}
}
break
default: //TODO: see if any other types are returned
println("HEHE")
log.Println(contentType)
b, _ := json.Marshal(content)
log.Fatalln(string(b))
}
}
func (r *PushSubscription) systemEvent(groupID ID, msg systemMessage) {
kind := msg.Event.Kind
b, _ := json.Marshal(msg.Event.Data)
switch kind {
case "membership.nickname_changed":
data := struct {
Name string
User struct {
ID int
}
}{}
_ = json.Unmarshal(b, &data)
for _, h := range r.handlers {
if h, ok := h.(HandleGroupMembership); ok {
h.HandleNewNickname(groupID, ID(strconv.Itoa(data.User.ID)), data.Name)
}
}
break
case "membership.avatar_changed":
data := struct {
AvatarURL string `json:"avatar_url"`
User struct {
ID int
}
}{}
_ = json.Unmarshal(b, &data)
for _, h := range r.handlers {
if h, ok := h.(HandleGroupMembership); ok {
h.HandleNewAvatarInGroup(groupID, ID(strconv.Itoa(data.User.ID)), data.AvatarURL)
}
}
break
case "group.name_change":
data := struct {
Name string
}{}
_ = json.Unmarshal(b, &data)
for _, h := range r.handlers {
if h, ok := h.(HandleGroupMetadata); ok {
h.HandleGroupName(groupID, data.Name)
}
}
break
case "group.topic_change":
data := struct {
Topic string
}{}
_ = json.Unmarshal(b, &data)
for _, h := range r.handlers {
if h, ok := h.(HandleGroupMetadata); ok {
h.HandleGroupTopic(groupID, data.Topic)
}
}
break
case "group.avatar_change":
data := struct {
AvatarURL string `json:"avatar_url"`
}{}
_ = json.Unmarshal(b, &data)
for _, h := range r.handlers {
if h, ok := h.(HandleGroupMetadata); ok {
h.HandleGroupAvatar(groupID, data.AvatarURL)
}
}
break
case "group.like_icon_set":
data := struct {
LikeIcon struct {
PackID int `json:"pack_id"`
PackIndex int `json:"pack_index"`
Type string
} `json:"like_icon"`
}{}
_ = json.Unmarshal(b, &data)
for _, h := range r.handlers {
if h, ok := h.(HandleGroupMetadata); ok {
h.HandleLikeIcon(groupID, data.LikeIcon.PackID, data.LikeIcon.PackIndex, data.LikeIcon.Type)
}
}
break
case "group.like_icon_removed":
for _, h := range r.handlers {
if h, ok := h.(HandleGroupMetadata); ok {
h.HandleLikeIcon(groupID, 0, 0, "")
}
}
break
default:
log.Println(kind)
log.Fatalln(string(b))
}
}
//SubscribeToUser to users
func (r *PushSubscription) SubscribeToUser(context context.Context, userID ID, authToken string) error {
concur.Lock()
@ -192,6 +342,11 @@ func (r *PushSubscription) SubscribeToGroup(context context.Context, groupID ID,
return nil
}
//Connected check if connected
func (r *PushSubscription) Connected() bool {
return r.LastConnected+30 >= time.Now().Unix()
}
// Stop listening to GroupMe after completing all other actions scheduled first
func (r *PushSubscription) Stop(context context.Context) {
concur.Lock()
@ -205,6 +360,7 @@ type authExtension struct {
// In does nothing in this extension, but is needed to satisy the interface
func (e *authExtension) In(msg wray.Message) {
println(msg.Channel())
if len(msg.Error()) > 0 {
log.Fatalln(msg.Error())
}