Compare commits

..

26 Commits

Author SHA1 Message Date
f9c1b24194 Bump fayec 2023-09-26 13:03:49 -05:00
a58e4100e1 Upgrading fayec 2023-09-25 15:29:44 -05:00
7b9e2a8d29 Fixing bug where nil handler was called 2023-09-24 15:36:17 -04:00
d81730e3e7 Handlers are now fired for individual users 2023-09-22 16:10:44 -05:00
08bfe83ba4 Updating API to re-use client for multiple users 2023-09-20 16:47:47 -05:00
c0f3da8060 Using updated fayec client 2023-09-19 16:28:22 -05:00
5727a20506 Updating package name 2023-09-18 21:37:41 -05:00
3e9851b2c0 Usinc fayec client instead of wray 2023-09-18 21:35:00 -05:00
Sumner Evans
8f23e04eea
namespace under beeper
Signed-off-by: Sumner Evans <sumner@beeper.com>
2022-10-21 15:59:45 -05:00
Karmanyaah Malhotra
c2dbe7021e fix 2021-05-08 16:01:24 -04:00
Karmanyaah Malhotra
6eba33b3be relations api 2021-05-08 15:54:12 -04:00
Karmanyaah Malhotra
7961d30a51 Dependencies 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
12931fb275 ChatID name different over push 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
65299d9606 Update example to use new real-time api 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
aa216ed4af Reformat real_time 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
28b2d85660 logging 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
8dd5993481 Fix panic 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
042fb9a951 fix golangcilint issues 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
b6715c2375 added more conditions 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
c5d6c8a29c replace not required in production version 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
d6a8b0818f Add many types of handling
fix listen loop
improve example
2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
da7bc977a3 Add membership 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
eeb2f88b97 Use interfaces and callbacks 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
784cfe93c1 real time push basics 2021-05-08 15:53:38 -04:00
Karmanyaah Malhotra
6d42a230d1 Fix bugs with direct message api 2021-05-08 15:44:18 -04:00
Karmanyaah Malhotra
7166300503 Add more attachment values 2021-05-08 15:44:18 -04:00
20 changed files with 827 additions and 113 deletions

View File

@ -23,7 +23,7 @@ const (
/*//////// API Requests ////////*/
// IndexBlock - A list of contacts you have blocked. These people cannot DM you
func (c *Client) IndexBlock(ctx context.Context, userID string) ([]*Block, error) {
func (c *Client) IndexBlock(ctx context.Context, userID string, authToken string) ([]*Block, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+indexBlocksEndpoint, nil)
if err != nil {
return nil, err
@ -37,7 +37,7 @@ func (c *Client) IndexBlock(ctx context.Context, userID string) ([]*Block, error
var resp struct {
Blocks []*Block `json:"blocks"`
}
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -46,7 +46,7 @@ func (c *Client) IndexBlock(ctx context.Context, userID string) ([]*Block, error
}
// BlockBetween - Asks if a block exists between you and another user id
func (c *Client) BlockBetween(ctx context.Context, userID, otherUserID string) (bool, error) {
func (c *Client) BlockBetween(ctx context.Context, userID, otherUserID string, authToken string) (bool, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+blockBetweenEndpoint, nil)
if err != nil {
return false, err
@ -61,7 +61,7 @@ func (c *Client) BlockBetween(ctx context.Context, userID, otherUserID string) (
var resp struct {
Between bool `json:"between"`
}
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return false, err
}
@ -70,7 +70,7 @@ func (c *Client) BlockBetween(ctx context.Context, userID, otherUserID string) (
}
// CreateBlock - Creates a block between you and the contact
func (c *Client) CreateBlock(ctx context.Context, userID, otherUserID string) (*Block, error) {
func (c *Client) CreateBlock(ctx context.Context, userID, otherUserID string, authToken string) (*Block, error) {
httpReq, err := http.NewRequest("POST", c.endpointBase+createBlockEndpoint, nil)
if err != nil {
return nil, err
@ -85,7 +85,7 @@ func (c *Client) CreateBlock(ctx context.Context, userID, otherUserID string) (*
var resp struct {
Block *Block `json:"block"`
}
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -94,7 +94,7 @@ func (c *Client) CreateBlock(ctx context.Context, userID, otherUserID string) (*
}
// Unblock - Removes block between you and other user
func (c *Client) Unblock(ctx context.Context, userID, otherUserID string) error {
func (c *Client) Unblock(ctx context.Context, userID, otherUserID string, authToken string) error {
httpReq, err := http.NewRequest("DELETE", c.endpointBase+unblockEndpoint, nil)
if err != nil {
return err
@ -106,7 +106,7 @@ func (c *Client) Unblock(ctx context.Context, userID, otherUserID string) error
query.Set("otherUser", otherUserID)
URL.RawQuery = query.Encode()
err = c.doWithAuthToken(ctx, httpReq, nil)
err = c.doWithAuthToken(ctx, httpReq, nil, authToken)
if err != nil {
return err
}

View File

@ -27,7 +27,7 @@ const (
// CreateBot - Create a bot. See the Bots Tutorial (https://dev.groupme.com/tutorials/bots)
// for a full walkthrough.
func (c *Client) CreateBot(ctx context.Context, bot *Bot) (*Bot, error) {
func (c *Client) CreateBot(ctx context.Context, bot *Bot, authToken string) (*Bot, error) {
URL := c.endpointBase + createBotEndpoint
var data = struct {
@ -47,7 +47,7 @@ func (c *Client) CreateBot(ctx context.Context, bot *Bot) (*Bot, error) {
}
var resp Bot
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -84,14 +84,14 @@ func (c *Client) PostBotMessage(ctx context.Context, botID ID, text string, pict
}
// IndexBots - list bots that you have created
func (c *Client) IndexBots(ctx context.Context) ([]*Bot, error) {
func (c *Client) IndexBots(ctx context.Context, authToken string) ([]*Bot, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+indexBotsEndpoint, nil)
if err != nil {
return nil, err
}
var resp []*Bot
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -100,7 +100,7 @@ func (c *Client) IndexBots(ctx context.Context) ([]*Bot, error) {
}
// DestroyBot - Remove a bot that you have created
func (c *Client) DestroyBot(ctx context.Context, botID ID) error {
func (c *Client) DestroyBot(ctx context.Context, botID ID, authToken string) error {
URL := fmt.Sprintf(c.endpointBase + destroyBotEndpoint)
var data = struct {
@ -119,5 +119,5 @@ func (c *Client) DestroyBot(ctx context.Context, botID ID) error {
return err
}
return c.doWithAuthToken(ctx, httpReq, nil)
return c.doWithAuthToken(ctx, httpReq, nil, authToken)
}

View File

@ -27,7 +27,7 @@ type IndexChatsQuery struct {
// IndexChats - Returns a paginated list of direct message chats, or
// conversations, sorted by updated_at descending.
func (c *Client) IndexChats(ctx context.Context, req *IndexChatsQuery) ([]*Chat, error) {
func (c *Client) IndexChats(ctx context.Context, req *IndexChatsQuery, authToken string) ([]*Chat, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+indexChatsEndpoint, nil)
if err != nil {
return nil, err
@ -46,7 +46,27 @@ func (c *Client) IndexChats(ctx context.Context, req *IndexChatsQuery) ([]*Chat,
URL.RawQuery = query.Encode()
var resp []*Chat
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
return resp, nil
}
func (c *Client) IndexRelations(ctx context.Context, authToken string) ([]*User, error) {
httpReq, err := http.NewRequest("GET", "https://api.groupme.com/v4"+"/relationships", nil)
if err != nil {
return nil, err
}
URL := httpReq.URL
query := URL.Query()
query.Set("include_blocked", "true")
URL.RawQuery = query.Encode()
var resp []*User
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}

View File

@ -18,16 +18,14 @@ const GroupMeAPIBase = "https://api.groupme.com/v3"
type Client struct {
httpClient *http.Client
endpointBase string
authorizationToken string
}
// NewClient creates a new GroupMe API Client
func NewClient(authToken string) *Client {
func NewClient() *Client {
return &Client{
// TODO: enable transport information passing in
httpClient: &http.Client{},
endpointBase: GroupMeAPIBase,
authorizationToken: authToken,
}
}
@ -112,10 +110,10 @@ func (c Client) do(ctx context.Context, req *http.Request, i interface{}) error
return nil
}
func (c Client) doWithAuthToken(ctx context.Context, req *http.Request, i interface{}) error {
func (c Client) doWithAuthToken(ctx context.Context, req *http.Request, i interface{}, authToken string) error {
URL := req.URL
query := URL.Query()
query.Set("token", c.authorizationToken)
query.Set("token", authToken)
URL.RawQuery = query.Encode()
return c.do(ctx, req, i)

View File

@ -63,10 +63,11 @@ Note that for historical reasons, likes are returned as an array
of user ids in the favorited_by key.
Parameters:
otherUserID - required, ID(string); the other participant in the conversation.
See IndexDirectMessagesQuery
*/
func (c *Client) IndexDirectMessages(ctx context.Context, otherUserID string, req *IndexDirectMessagesQuery) (IndexDirectMessagesResponse, error) {
func (c *Client) IndexDirectMessages(ctx context.Context, otherUserID string, req *IndexDirectMessagesQuery, authToken string) (IndexDirectMessagesResponse, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+indexDirectMessagesEndpoint, nil)
if err != nil {
return IndexDirectMessagesResponse{}, err
@ -82,9 +83,10 @@ func (c *Client) IndexDirectMessages(ctx context.Context, otherUserID string, re
query.Add("since_id", req.SinceID.String())
}
}
httpReq.URL.RawQuery = query.Encode()
var resp IndexDirectMessagesResponse
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return IndexDirectMessagesResponse{}, err
}
@ -106,7 +108,7 @@ specify a replacement charmap to substitute emoji characters
The character map is an array of arrays containing rune data
([[{pack_id,offset}],...]).
*/
func (c *Client) CreateDirectMessage(ctx context.Context, m *Message) (*Message, error) {
func (c *Client) CreateDirectMessage(ctx context.Context, m *Message, authToken string) (*Message, error) {
URL := fmt.Sprintf(c.endpointBase + createDirectMessageEndpoint)
m.SourceGUID = uuid.New().String()
@ -127,9 +129,9 @@ func (c *Client) CreateDirectMessage(ctx context.Context, m *Message) (*Message,
}
var resp struct {
*Message `json:"message"`
*Message `json:"direct_message"`
}
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}

View File

@ -3,8 +3,6 @@ package main
import (
"context"
"fmt"
"github.com/densestvoid/groupme"
)
// This is not a real token. Please find yours by logging

View File

@ -3,8 +3,6 @@ package main
import (
"context"
"fmt"
"github.com/densestvoid/groupme"
)
// This is not a real Bot ID. Please find yours by logging

View File

@ -0,0 +1,177 @@
package main
import (
"context"
"fmt"
"log"
"gitea.watsonlabs.net/watsonb8/groupme-lib"
)
// This is not a real token. Please find yours by logging
// into the GroupMe development website: https://dev.groupme.com/
var authorizationToken = "ASD"
var authorizationToken2 = "ASDF"
// A short program that subscribes to 2 groups and 2 direct chats
// and prints out all recognized events in those
func main() {
//create push subscription and start listening
p := groupme.NewPushSubscription(context.Background())
err := p.Connect(context.TODO())
if err != nil {
return
}
// Create a new client with your auth token
client := groupme.NewClient()
User, _ := client.MyUser(context.Background(), authorizationToken)
User2, _ := client.MyUser(context.Background(), authorizationToken2)
//handles (in this case prints) all messages
p.AddFullHandler(Handler{User: User}, authorizationToken)
p.AddHandler(Handler{User: User2}, authorizationToken2)
//Subscribe to get messages and events for the specific user
p.SubscribeToUser(context.Background(), User.ID, authorizationToken)
p.SubscribeToUser(context.Background(), User2.ID, authorizationToken2)
if err != nil {
log.Fatal(err)
}
// Get the groups your user is part of
groups, err := client.IndexGroups(
context.Background(),
&groupme.GroupsQuery{
Page: 0,
PerPage: 2,
Omit: "memberships",
}, authorizationToken)
groups2, err := client.IndexGroups(
context.Background(),
&groupme.GroupsQuery{
Page: 0,
PerPage: 2,
Omit: "memberships",
}, authorizationToken2)
if err != nil {
fmt.Println(err)
return
}
//Subscribe to those groups
for _, j := range groups {
err = p.SubscribeToGroup(context.TODO(), j.ID, authorizationToken)
if err != nil {
log.Fatal(err)
}
}
for _, j := range groups2 {
err = p.SubscribeToGroup(context.TODO(), j.ID, authorizationToken2)
if err != nil {
log.Fatal(err)
}
}
//get chats your user is part of
chats, err := client.IndexChats(context.Background(),
&groupme.IndexChatsQuery{
Page: 0,
PerPage: 2,
}, authorizationToken)
chats2, err := client.IndexChats(context.Background(),
&groupme.IndexChatsQuery{
Page: 0,
PerPage: 2,
}, authorizationToken2)
//subscribe to all those chats
for _, j := range chats {
go func() {
err := p.SubscribeToDM(context.TODO(), j.LastMessage.ConversationID, authorizationToken)
if err != nil {
log.Fatal(err)
}
}()
}
for _, j := range chats2 {
go func() {
err := p.SubscribeToDM(context.TODO(), j.LastMessage.ConversationID, authorizationToken2)
if err != nil {
log.Fatal(err)
}
}()
}
//blocking
<-make(chan (struct{}))
}
// Following example handlers print out all data
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, msg.Attachments)
}
func (h Handler) HandleJoin(group groupme.ID) {
fmt.Println("User joined group with id", group.String())
}
func (h Handler) HandleLike(msg groupme.Message) {
fmt.Println(msg.ID, "liked by", msg.FavoritedBy)
}
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)
}
func (h Handler) HandleMembers(group groupme.ID, members []groupme.Member, added bool) {
action := "removed"
if added {
action = "added"
}
fmt.Printf("In group %s, users %v %s\n", group.String(), members, action)
}

12
go.mod
View File

@ -1,9 +1,17 @@
module github.com/densestvoid/groupme
module gitea.watsonlabs.net/watsonb8/groupme-lib
go 1.15
go 1.21.0
require (
gitea.watsonlabs.net/watsonb8/fayec v0.0.5-0.20230926180210-b375ab3c8c11
github.com/google/uuid v1.2.0
github.com/gorilla/mux v1.8.0
github.com/stretchr/testify v1.7.0
)
require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)

36
go.sum
View File

@ -1,15 +1,49 @@
gitea.watsonlabs.net/watsonb8/fayec v0.0.0-20230919020138-8f0db7048755 h1:FEhNSjSNvZ+nVg5Z3ds6X8ys3qjM+mmyLTSqKhCUHuQ=
gitea.watsonlabs.net/watsonb8/fayec v0.0.0-20230919020138-8f0db7048755/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.0-20230919151904-5ca9ade6f946 h1:loc70tiaFs1U4sqn+lKMSBlo5OfvVfClYnWjfGLXaSg=
gitea.watsonlabs.net/watsonb8/fayec v0.0.0-20230919151904-5ca9ade6f946/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.1 h1:MNFmTaTyyKKgrw04dGO9C5ojtm1jIvy8oHYqbj0ECeY=
gitea.watsonlabs.net/watsonb8/fayec v0.0.1/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.2 h1:tqbgr1vRZ6Wq4W81xBg+FTOywSv3EJpK263SAVXXTco=
gitea.watsonlabs.net/watsonb8/fayec v0.0.2/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.3 h1:YpaZBIee8Ix6uGm1UoEtBix1dEU1TURChAsJGJ3pVRo=
gitea.watsonlabs.net/watsonb8/fayec v0.0.3/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.4 h1:SLvwip1DQy13QngVsEgoLtN7T6bS+X6348p6PQhUF2A=
gitea.watsonlabs.net/watsonb8/fayec v0.0.4/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.5-0.20230926180210-b375ab3c8c11 h1:xJ9eSFyIrDA43UVpbxOD1QkA2jhg+vS+eezFKCDV3Dw=
gitea.watsonlabs.net/watsonb8/fayec v0.0.5-0.20230926180210-b375ab3c8c11/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
gitea.watsonlabs.net/watsonb8/fayec v0.0.5 h1:9+UHzUuEcLuZ5Gx5S/NTBxYshUhsiQ5M3vzUF8RAKxw=
gitea.watsonlabs.net/watsonb8/fayec v0.0.5/go.mod h1:gv8CWMq6dFJQhH30u8bO3u4k2irKlclZktLNYDebQ/0=
github.com/autogrowsystems/wray v0.0.0-20160519030252-f36984f6648c/go.mod h1:druJ8QMeBCUmwJ7ZSFowx77dWxEWF3SYlQlsqZaLZQg=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/karmanyaahm/wray v0.0.0-20210303233435-756d58657c14 h1:NrATjZKvkY+ojL8FXTWa3fQ+wihFrAxLNE6T+wOkIcY=
github.com/karmanyaahm/wray v0.0.0-20210303233435-756d58657c14/go.mod h1:ysD86MIEevmAkdfdg5s6Qt3I07RN6fvMAyna7jCGG2o=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=

View File

@ -86,7 +86,7 @@ app for users who are participating in huge groups.
Parameters: See GroupsQuery
*/
func (c *Client) IndexGroups(ctx context.Context, req *GroupsQuery) ([]*Group, error) {
func (c *Client) IndexGroups(ctx context.Context, req *GroupsQuery, authToken string) ([]*Group, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+indexGroupsEndpoint, nil)
if err != nil {
return nil, err
@ -108,7 +108,7 @@ func (c *Client) IndexGroups(ctx context.Context, req *GroupsQuery) ([]*Group, e
URL.RawQuery = query.Encode()
var resp []*Group
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -123,14 +123,14 @@ FormerGroups -
List they groups you have left but can rejoin.
*/
func (c *Client) FormerGroups(ctx context.Context) ([]*Group, error) {
func (c *Client) FormerGroups(ctx context.Context, authToken string) ([]*Group, error) {
httpReq, err := http.NewRequest("GET", c.endpointBase+formerGroupsEndpoint, nil)
if err != nil {
return nil, err
}
var resp []*Group
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -146,9 +146,10 @@ ShowGroup -
Loads a specific group.
Parameters:
groupID - required, ID(string)
*/
func (c *Client) ShowGroup(ctx context.Context, groupID ID) (*Group, error) {
func (c *Client) ShowGroup(ctx context.Context, groupID ID, authToken string) (*Group, error) {
URL := fmt.Sprintf(c.endpointBase+showGroupEndpoint, groupID)
httpReq, err := http.NewRequest("GET", URL, nil)
@ -157,7 +158,7 @@ func (c *Client) ShowGroup(ctx context.Context, groupID ID) (*Group, error) {
}
var resp Group
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -170,11 +171,11 @@ func (c *Client) ShowGroup(ctx context.Context, groupID ID) (*Group, error) {
/*
CreateGroup -
Create a new group
# Create a new group
Parameters: See GroupSettings
*/
func (c *Client) CreateGroup(ctx context.Context, gs GroupSettings) (*Group, error) {
func (c *Client) CreateGroup(ctx context.Context, gs GroupSettings, authToken string) (*Group, error) {
URL := fmt.Sprintf(c.endpointBase + createGroupEndpoint)
jsonBytes, err := json.Marshal(&gs)
@ -188,7 +189,7 @@ func (c *Client) CreateGroup(ctx context.Context, gs GroupSettings) (*Group, err
}
var resp Group
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -201,13 +202,14 @@ func (c *Client) CreateGroup(ctx context.Context, gs GroupSettings) (*Group, err
/*
UpdateGroup -
Update a group after creation
# Update a group after creation
Parameters:
groupID - required, ID(string)
See GroupSettings
*/
func (c *Client) UpdateGroup(ctx context.Context, groupID ID, gs GroupSettings) (*Group, error) {
func (c *Client) UpdateGroup(ctx context.Context, groupID ID, gs GroupSettings, authToken string) (*Group, error) {
URL := fmt.Sprintf(c.endpointBase+updateGroupEndpoint, groupID)
jsonBytes, err := json.Marshal(&gs)
@ -221,7 +223,7 @@ func (c *Client) UpdateGroup(ctx context.Context, groupID ID, gs GroupSettings)
}
var resp Group
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -234,14 +236,15 @@ func (c *Client) UpdateGroup(ctx context.Context, groupID ID, gs GroupSettings)
/*
DestroyGroup -
Disband a group
# Disband a group
This action is only available to the group creator
# This action is only available to the group creator
Parameters:
groupID - required, ID(string)
*/
func (c *Client) DestroyGroup(ctx context.Context, groupID ID) error {
func (c *Client) DestroyGroup(ctx context.Context, groupID ID, authToken string) error {
url := fmt.Sprintf(c.endpointBase+destroyGroupEndpoint, groupID)
httpReq, err := http.NewRequest("POST", url, nil)
@ -249,7 +252,7 @@ func (c *Client) DestroyGroup(ctx context.Context, groupID ID) error {
return err
}
return c.doWithAuthToken(ctx, httpReq, nil)
return c.doWithAuthToken(ctx, httpReq, nil, authToken)
}
/*/// Join ///*/
@ -257,13 +260,14 @@ func (c *Client) DestroyGroup(ctx context.Context, groupID ID) error {
/*
JoinGroup -
Join a shared group
# Join a shared group
Parameters:
groupID - required, ID(string)
shareToken - required, string
*/
func (c *Client) JoinGroup(ctx context.Context, groupID ID, shareToken string) (*Group, error) {
func (c *Client) JoinGroup(ctx context.Context, groupID ID, shareToken string, authToken string) (*Group, error) {
URL := fmt.Sprintf(c.endpointBase+joinGroupEndpoint, groupID, shareToken)
httpReq, err := http.NewRequest("POST", URL, nil)
@ -272,7 +276,7 @@ func (c *Client) JoinGroup(ctx context.Context, groupID ID, shareToken string) (
}
var resp Group
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -288,9 +292,10 @@ RejoinGroup -
Rejoin a group. Only works if you previously removed yourself.
Parameters:
groupID - required, ID(string)
*/
func (c *Client) RejoinGroup(ctx context.Context, groupID ID) (*Group, error) {
func (c *Client) RejoinGroup(ctx context.Context, groupID ID, authToken string) (*Group, error) {
URL := fmt.Sprintf(c.endpointBase + rejoinGroupEndpoint)
var data = struct {
@ -310,7 +315,7 @@ func (c *Client) RejoinGroup(ctx context.Context, groupID ID) (*Group, error) {
}
var resp Group
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -330,7 +335,7 @@ the result of change owner action for the request
Parameters: See ChangeOwnerRequest
*/
func (c *Client) ChangeGroupOwner(ctx context.Context, reqs ChangeOwnerRequest) (ChangeOwnerResult, error) {
func (c *Client) ChangeGroupOwner(ctx context.Context, reqs ChangeOwnerRequest, authToken string) (ChangeOwnerResult, error) {
URL := fmt.Sprintf(c.endpointBase + changeGroupOwnerEndpoint)
var data = struct {
@ -353,7 +358,7 @@ func (c *Client) ChangeGroupOwner(ctx context.Context, reqs ChangeOwnerRequest)
Results []ChangeOwnerResult `json:"results"`
}
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return ChangeOwnerResult{}, err
}

View File

@ -111,6 +111,8 @@ type Message struct {
System bool `json:"system,omitempty"`
Name string `json:"name,omitempty"`
RecipientID ID `json:"recipient_id,omitempty"`
//ChatID - over push ConversationID seems to be called ChatID
ChatID ID `json:"chat_id,omitempty"`
ConversationID ID `json:"conversation_id,omitempty"`
AvatarURL string `json:"avatar_url,omitempty"`
// Maximum length of 1000 characters
@ -150,11 +152,14 @@ type Attachment struct {
Loci [][]int `json:"loci,omitempty"`
UserIDs []ID `json:"user_ids,omitempty"`
URL string `json:"url,omitempty"`
FileID string `json:"file_id,omitempty"`
VideoPreviewURL string `json:"preview_url,omitempty"`
Name string `json:"name,omitempty"`
Latitude string `json:"lat,omitempty"`
Longitude string `json:"lng,omitempty"`
Placeholder string `json:"placeholder,omitempty"`
Charmap [][]int `json:"charmap,omitempty"`
ReplyID ID `json:"reply_id,omitempty"`
}
func (a *Attachment) String() string {

View File

@ -35,7 +35,7 @@ const (
// IndexLeaderboard - A list of the liked messages in the group for a given period of
// time. Messages are ranked in order of number of likes.
func (c *Client) IndexLeaderboard(ctx context.Context, groupID ID, p period) ([]*Message, error) {
func (c *Client) IndexLeaderboard(ctx context.Context, groupID ID, p period, authToken string) ([]*Message, error) {
url := fmt.Sprintf(c.endpointBase+indexLeaderboardEndpoint, groupID)
httpReq, err := http.NewRequest("GET", url, nil)
if err != nil {
@ -50,7 +50,7 @@ func (c *Client) IndexLeaderboard(ctx context.Context, groupID ID, p period) ([]
var resp struct {
Messages []*Message `json:"messages"`
}
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -68,9 +68,10 @@ reverse chrono-order. Note that the payload includes a liked_at
timestamp in ISO-8601 format.
Parameters:
groupID - required, ID(string)
*/
func (c *Client) MyLikesLeaderboard(ctx context.Context, groupID ID) ([]*Message, error) {
func (c *Client) MyLikesLeaderboard(ctx context.Context, groupID ID, authToken string) ([]*Message, error) {
url := fmt.Sprintf(c.endpointBase+myLikesLeaderboardEndpoint, groupID)
httpReq, err := http.NewRequest("GET", url, nil)
if err != nil {
@ -80,7 +81,7 @@ func (c *Client) MyLikesLeaderboard(ctx context.Context, groupID ID) ([]*Message
var resp struct {
Messages []*Message `json:"messages"`
}
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -98,9 +99,10 @@ reverse chrono-order. Note that the payload includes a liked_at
timestamp in ISO-8601 format.
Parameters:
groupID - required, ID(string)
*/
func (c *Client) MyHitsLeaderboard(ctx context.Context, groupID ID) ([]*Message, error) {
func (c *Client) MyHitsLeaderboard(ctx context.Context, groupID ID, authToken string) ([]*Message, error) {
url := fmt.Sprintf(c.endpointBase+myHitsLeaderboardEndpoint, groupID)
httpReq, err := http.NewRequest("GET", url, nil)
if err != nil {
@ -110,7 +112,7 @@ func (c *Client) MyHitsLeaderboard(ctx context.Context, groupID ID) ([]*Message,
var resp struct {
Messages []*Message `json:"messages"`
}
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}

View File

@ -23,7 +23,7 @@ const (
// Create
// CreateLike - Like a message.
func (c *Client) CreateLike(ctx context.Context, conversationID, messageID ID) error {
func (c *Client) CreateLike(ctx context.Context, conversationID, messageID ID, authToken string) error {
url := fmt.Sprintf(c.endpointBase+createLikeEndpoint, conversationID, messageID)
httpReq, err := http.NewRequest("POST", url, nil)
@ -31,11 +31,11 @@ func (c *Client) CreateLike(ctx context.Context, conversationID, messageID ID) e
return err
}
return c.doWithAuthToken(ctx, httpReq, nil)
return c.doWithAuthToken(ctx, httpReq, nil, authToken)
}
// DestroyLike - Unlike a message.
func (c *Client) DestroyLike(ctx context.Context, conversationID, messageID ID) error {
func (c *Client) DestroyLike(ctx context.Context, conversationID, messageID ID, authToken string) error {
url := fmt.Sprintf(c.endpointBase+destroyLikeEndpoint, conversationID, messageID)
httpReq, err := http.NewRequest("POST", url, nil)
@ -43,5 +43,5 @@ func (c *Client) DestroyLike(ctx context.Context, conversationID, messageID ID)
return err
}
return c.doWithAuthToken(ctx, httpReq, nil)
return c.doWithAuthToken(ctx, httpReq, nil, authToken)
}

View File

@ -40,6 +40,7 @@ GUIDs can be added to the members parameters. These GUIDs will
be reflected in the membership JSON objects.
Parameters:
groupID - required, ID(string)
See Member.
Nickname - required
@ -48,7 +49,7 @@ Parameters:
PhoneNumber - PhoneNumber(string)
Email - string
*/
func (c *Client) AddMembers(ctx context.Context, groupID ID, members ...*Member) (string, error) {
func (c *Client) AddMembers(ctx context.Context, groupID ID, authToken string, members ...*Member) (string, error) {
URL := fmt.Sprintf(c.endpointBase+addMembersEndpoint, groupID)
var data = struct {
@ -71,7 +72,7 @@ func (c *Client) AddMembers(ctx context.Context, groupID ID, members ...*Member)
ResultsID string `json:"results_id"`
}
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return "", err
}
@ -94,10 +95,11 @@ Keep in mind that results are temporary -- they will only be
available for 1 hour after the add request.
Parameters:
groupID - required, ID(string)
resultID - required, string
*/
func (c *Client) AddMembersResults(ctx context.Context, groupID ID, resultID string) ([]*Member, error) {
func (c *Client) AddMembersResults(ctx context.Context, groupID ID, resultID string, authToken string) ([]*Member, error) {
URL := fmt.Sprintf(c.endpointBase+addMembersResultsEndpoint, groupID, resultID)
httpReq, err := http.NewRequest("GET", URL, nil)
@ -109,7 +111,7 @@ func (c *Client) AddMembersResults(ctx context.Context, groupID ID, resultID str
Members []*Member `json:"members"`
}
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -127,10 +129,11 @@ Remove a member (or yourself) from a group.
Note: The creator of the group cannot be removed or exit.
Parameters:
groupID - required, ID(string)
membershipID - required, ID(string). Not the same as userID
*/
func (c *Client) RemoveMember(ctx context.Context, groupID, membershipID ID) error {
func (c *Client) RemoveMember(ctx context.Context, groupID, membershipID ID, authToken string) error {
URL := fmt.Sprintf(c.endpointBase+removeMemberEndpoint, groupID, membershipID)
httpReq, err := http.NewRequest("POST", URL, nil)
@ -138,7 +141,7 @@ func (c *Client) RemoveMember(ctx context.Context, groupID, membershipID ID) err
return err
}
return c.doWithAuthToken(ctx, httpReq, nil)
return c.doWithAuthToken(ctx, httpReq, nil, authToken)
}
/*/// Update ///*/
@ -149,7 +152,7 @@ UpdateMember -
Update your nickname in a group. The nickname must be
between 1 and 50 characters.
*/
func (c *Client) UpdateMember(ctx context.Context, groupID ID, nickname string) (*Member, error) {
func (c *Client) UpdateMember(ctx context.Context, groupID ID, nickname string, authToken string) (*Member, error) {
URL := fmt.Sprintf(c.endpointBase+updateMemberEndpoint, groupID)
type Nickname struct {
@ -173,7 +176,7 @@ func (c *Client) UpdateMember(ctx context.Context, groupID ID, nickname string)
var resp Member
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}

View File

@ -75,7 +75,7 @@ we return code 304.
Note that for historical reasons, likes are returned as an
array of user ids in the favorited_by key.
*/
func (c *Client) IndexMessages(ctx context.Context, groupID ID, req *IndexMessagesQuery) (IndexMessagesResponse, error) {
func (c *Client) IndexMessages(ctx context.Context, groupID ID, req *IndexMessagesQuery, authToken string) (IndexMessagesResponse, error) {
url := fmt.Sprintf(c.endpointBase+indexMessagesEndpoint, groupID)
httpReq, err := http.NewRequest("GET", url, nil)
if err != nil {
@ -101,7 +101,7 @@ func (c *Client) IndexMessages(ctx context.Context, groupID ID, req *IndexMessag
URL.RawQuery = query.Encode()
var resp IndexMessagesResponse
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return IndexMessagesResponse{}, err
}
@ -125,7 +125,7 @@ The character map is an array of arrays containing rune data
The placeholder should be a high-point/invisible UTF-8 character.
*/
func (c *Client) CreateMessage(ctx context.Context, groupID ID, m *Message) (*Message, error) {
func (c *Client) CreateMessage(ctx context.Context, groupID ID, m *Message, authToken string) (*Message, error) {
URL := fmt.Sprintf(c.endpointBase+createMessagesEndpoint, groupID)
m.SourceGUID = uuid.New().String()
@ -148,7 +148,7 @@ func (c *Client) CreateMessage(ctx context.Context, groupID ID, m *Message) (*Me
var resp struct {
*Message `json:"message"`
}
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}

196
real_time.go Normal file
View File

@ -0,0 +1,196 @@
package groupme
import (
"context"
"errors"
"gitea.watsonlabs.net/watsonb8/fayec"
"gitea.watsonlabs.net/watsonb8/fayec/message"
"gitea.watsonlabs.net/watsonb8/fayec/subscription"
"log"
"strings"
"sync"
"time"
)
const (
PushServer = "wss://push.groupme.com/faye"
userChannel = "/user/"
groupChannel = "/group/"
dmChannel = "/direct_message/"
)
var (
ErrHandlerNotFound = errors.New("Handler not found")
ErrListenerNotStarted = errors.New("GroupMe listener not started")
)
var concur = sync.Mutex{}
type HandlerAll interface {
Handler
//of self
HandlerText
HandlerLike
HandlerMembership
//of group
HandleGroupTopic
HandleGroupAvatar
HandleGroupName
HandleGroupLikeIcon
//of group members
HandleMemberNewNickname
HandleMemberNewAvatar
HandleMembers
}
type Handler interface {
HandleError(error)
}
type HandlerText interface {
HandleTextMessage(Message)
}
type HandlerLike interface {
HandleLike(Message)
}
type HandlerMembership interface {
HandleJoin(ID)
}
// Group Handlers
type HandleGroupTopic interface {
HandleGroupTopic(group ID, newTopic string)
}
type HandleGroupName interface {
HandleGroupName(group ID, newName string)
}
type HandleGroupAvatar interface {
HandleGroupAvatar(group ID, newAvatar string)
}
type HandleGroupLikeIcon interface {
HandleLikeIcon(group ID, PackID, PackIndex int, Type string)
}
// Group member handlers
type HandleMemberNewNickname interface {
HandleNewNickname(group ID, user ID, newName string)
}
type HandleMemberNewAvatar interface {
HandleNewAvatarInGroup(group ID, user ID, avatarURL string)
}
type HandleMembers interface {
//HandleNewMembers returns only partial member with id and nickname; added is false if removing
HandleMembers(group ID, members []Member, added bool)
}
// PushSubscription manages real time subscription
type PushSubscription struct {
channel chan message.Data
client *fayec.Client
handlers map[string][]Handler // key == token
LastConnected int64
}
// NewPushSubscription creates and returns a push subscription object
func NewPushSubscription(context context.Context) PushSubscription {
r := PushSubscription{
channel: make(chan message.Data),
handlers: make(map[string][]Handler),
}
return r
}
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)
}
// AddFullHandler is the same as AddHandler except it ensures the interface implements everything
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)
}
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)
// Listen connects to GroupMe. Runs in Goroutine.
func (r *PushSubscription) Connect(context context.Context) error {
c, err := fayec.NewClient(PushServer)
if err != nil {
return err
}
r.client = c
return nil
}
// SubscribeToUser to users
func (r *PushSubscription) SubscribeToUser(context context.Context, id ID, authToken string) error {
return r.subscribeWithPrefix(userChannel, context, id, authToken)
}
// SubscribeToGroup to groups for typing notification
func (r *PushSubscription) SubscribeToGroup(context context.Context, id ID, authToken string) error {
return r.subscribeWithPrefix(groupChannel, context, id, authToken)
}
// SubscribeToDM to users
func (r *PushSubscription) SubscribeToDM(context context.Context, id ID, authToken string) error {
id = ID(strings.Replace(id.String(), "+", "_", 1))
return r.subscribeWithPrefix(dmChannel, context, id, authToken)
}
func (r *PushSubscription) subscribeWithPrefix(prefix string, context context.Context, groupID ID, authToken string) error {
concur.Lock()
defer concur.Unlock()
if r.client == nil {
return ErrListenerNotStarted
}
var sub *subscription.Subscription
sub, err := r.client.Subscribe(prefix+groupID.String(), authToken)
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)
} else {
handler(r, channel, authToken, content)
}
})
return nil
}
// Connected check if connected
func (r *PushSubscription) Connected() bool {
return r.LastConnected+30 >= time.Now().Unix()
}

266
real_time_handler.go Normal file
View File

@ -0,0 +1,266 @@
package groupme
import (
"encoding/json"
"fmt"
"log"
"strconv"
)
func init() {
RealTimeHandlers = make(map[string]func(r *PushSubscription, channel string, authToken string, data ...interface{}))
//Base Handlers on user channel
RealTimeHandlers["direct_message.create"] = func(r *PushSubscription, channel string, authToken string, data ...interface{}) {
b, _ := json.Marshal(data[0])
out := Message{}
_ = json.Unmarshal(b, &out)
//maybe something with API versioning
out.ConversationID = out.ChatID
if out.UserID.String() == "system" {
event := struct {
Event struct {
Kind string `json:"type"`
Data interface{}
}
}{}
err := json.Unmarshal(b, &event)
if err != nil {
fmt.Println(err)
}
rawData, _ := json.Marshal(event.Event.Data)
handler, ok := RealTimeSystemHandlers[event.Event.Kind]
if !ok {
log.Println("Unable to handle system message of type", event.Event.Kind)
return
}
id := out.GroupID
if len(id) == 0 {
id = out.ConversationID
}
handler(r, channel, id, authToken, rawData)
return
}
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandlerText); ok {
h.HandleTextMessage(out)
}
}
}
RealTimeHandlers["line.create"] = RealTimeHandlers["direct_message.create"]
RealTimeHandlers["like.create"] = func(r *PushSubscription, channel string, authToken string, data ...interface{}) { //should be an associated chatEvent
}
RealTimeHandlers["membership.create"] = func(r *PushSubscription, channel string, authToken string, data ...interface{}) {
c, _ := data[0].(map[string]interface{})
id, _ := c["id"].(string)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandlerMembership); ok {
h.HandleJoin(ID(id))
}
}
}
//following are for each chat
RealTimeHandlers["favorite"] = func(r *PushSubscription, channel string, authToken string, data ...interface{}) {
c, ok := data[0].(map[string]interface{})
if !ok {
fmt.Println(data, "err")
return
}
e, ok := c["line"]
if !ok {
fmt.Println(data, "err")
return
}
d, _ := json.Marshal(e)
msg := Message{}
_ = json.Unmarshal(d, &msg)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandlerLike); ok {
h.HandleLike(msg)
}
}
}
//following are for messages from system (administrative/settings changes)
RealTimeSystemHandlers = make(map[string]func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte))
RealTimeSystemHandlers["membership.nickname_changed"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
thing := struct {
Name string
User struct {
ID int
}
}{}
_ = json.Unmarshal(rawData, &thing)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleMemberNewNickname); ok {
h.HandleNewNickname(id, ID(strconv.Itoa(thing.User.ID)), thing.Name)
}
}
}
RealTimeSystemHandlers["membership.avatar_changed"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
content := struct {
AvatarURL string `json:"avatar_url"`
User struct {
ID int
}
}{}
_ = json.Unmarshal(rawData, &content)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleMemberNewAvatar); ok {
h.HandleNewAvatarInGroup(id, ID(strconv.Itoa(content.User.ID)), content.AvatarURL)
}
}
}
RealTimeSystemHandlers["membership.announce.added"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
Added []Member `json:"added_users"`
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleMembers); ok {
h.HandleMembers(id, data.Added, true)
}
}
}
RealTimeSystemHandlers["membership.notifications.removed"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
Added Member `json:"removed_user"`
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleMembers); ok {
h.HandleMembers(id, []Member{data.Added}, false)
}
}
}
RealTimeSystemHandlers["membership.name_change"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
Name string
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleGroupName); ok {
h.HandleGroupName(id, data.Name)
}
}
}
RealTimeSystemHandlers["group.name_change"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
Name string
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleGroupName); ok {
h.HandleGroupName(id, data.Name)
}
}
}
RealTimeSystemHandlers["group.topic_change"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
Topic string
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleGroupTopic); ok {
h.HandleGroupTopic(id, data.Topic)
}
}
}
RealTimeSystemHandlers["group.avatar_change"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
AvatarURL string `json:"avatar_url"`
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleGroupAvatar); ok {
h.HandleGroupAvatar(id, data.AvatarURL)
}
}
}
RealTimeSystemHandlers["group.like_icon_set"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
data := struct {
LikeIcon struct {
PackID int `json:"pack_id"`
PackIndex int `json:"pack_index"`
Type string
} `json:"like_icon"`
}{}
_ = json.Unmarshal(rawData, &data)
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleGroupLikeIcon); ok {
h.HandleLikeIcon(id, data.LikeIcon.PackID, data.LikeIcon.PackIndex, data.LikeIcon.Type)
}
}
}
RealTimeSystemHandlers["group.like_icon_removed"] = func(r *PushSubscription, channel string, id ID, authToken string, rawData []byte) {
handlers := r.handlers[authToken]
for _, h := range handlers {
if h, ok := h.(HandleGroupLikeIcon); ok {
h.HandleLikeIcon(id, 0, 0, "")
}
}
}
}

View File

@ -31,13 +31,14 @@ Enables SMS mode for N hours, where N is at most 48. After N
hours have elapsed, user will receive push notfications.
Parameters:
duration - required, integer
registration_id - string; The push notification ID/token
that should be suppressed during SMS mode. If this is
omitted, both SMS and push notifications will be
delivered to the device.
*/
func (c *Client) CreateSMSMode(ctx context.Context, duration int, registrationID *ID) error {
func (c *Client) CreateSMSMode(ctx context.Context, duration int, registrationID *ID, authToken string) error {
URL := fmt.Sprintf(c.endpointBase + createSMSModeEndpoint)
var data = struct {
@ -58,7 +59,7 @@ func (c *Client) CreateSMSMode(ctx context.Context, duration int, registrationID
return err
}
err = c.doWithAuthToken(ctx, httpReq, nil)
err = c.doWithAuthToken(ctx, httpReq, nil, authToken)
if err != nil {
return err
}
@ -73,7 +74,7 @@ DeleteSMSMode -
Disables SMS mode
*/
func (c *Client) DeleteSMSMode(ctx context.Context) error {
func (c *Client) DeleteSMSMode(ctx context.Context, authToken string) error {
url := fmt.Sprintf(c.endpointBase + deleteSMSModeEndpoint)
httpReq, err := http.NewRequest("POST", url, nil)
@ -81,5 +82,5 @@ func (c *Client) DeleteSMSMode(ctx context.Context) error {
return err
}
return c.doWithAuthToken(ctx, httpReq, nil)
return c.doWithAuthToken(ctx, httpReq, nil, authToken)
}

View File

@ -31,9 +31,10 @@ MyUser -
Loads a specific group.
Parameters:
groupID - required, ID(string)
*/
func (c *Client) MyUser(ctx context.Context) (*User, error) {
func (c *Client) MyUser(ctx context.Context, authToken string) (*User, error) {
URL := fmt.Sprintf(c.endpointBase + myUserEndpoint)
httpReq, err := http.NewRequest("GET", URL, nil)
@ -42,7 +43,7 @@ func (c *Client) MyUser(ctx context.Context) (*User, error) {
}
var resp User
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}
@ -65,11 +66,11 @@ type UserSettings struct {
/*
UpdateMyUser -
Update attributes about your own account
# Update attributes about your own account
Parameters: See UserSettings
*/
func (c *Client) UpdateMyUser(ctx context.Context, us UserSettings) (*User, error) {
func (c *Client) UpdateMyUser(ctx context.Context, us UserSettings, authToken string) (*User, error) {
URL := fmt.Sprintf(c.endpointBase + updateMyUserEndpoint)
jsonBytes, err := json.Marshal(&us)
@ -83,7 +84,7 @@ func (c *Client) UpdateMyUser(ctx context.Context, us UserSettings) (*User, erro
}
var resp User
err = c.doWithAuthToken(ctx, httpReq, &resp)
err = c.doWithAuthToken(ctx, httpReq, &resp, authToken)
if err != nil {
return nil, err
}