Skip to content

Commit 9ad36fe

Browse files
authored
Merge pull request #112 from jackmcguire1/goals-event-sub
Twitch Creator Goals - Event Sub - SUPPORT
2 parents be0c569 + 4d68249 commit 9ad36fe

File tree

6 files changed

+280
-0
lines changed

6 files changed

+280
-0
lines changed

docs/event.md

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ Used to either create or send mock events for use with local webhooks testing.
2626
| `cheer` | Only usable with the `eventsub` transport |
2727
| `drop` | Drops Entitlement event. |
2828
| `gift` | A gifted subscription event. Triggers a basic tier 1 sub. |
29+
| `goal-begin` | Channel creator goal start event. |
30+
| `goal-end` | Channel creator goal end event. |
31+
| `goal-progress` | Channel creator goal progress event. |
2932
| `grant` | Authorization grant event. |
3033
| `hype-train-begin` | Channel hype train start event. |
3134
| `hype-train-end` | Channel hype train end event. |
@@ -131,6 +134,9 @@ Allows you to test if your webserver responds to subscription requests properly.
131134
| `cheer` | Only usable with the `eventsub` transport |
132135
| `drop` | Drops Entitlement event. |
133136
| `gift` | A gifted subscription event. Triggers a basic tier 1 sub. |
137+
| `goal-begin` | Channel creator goal start event. |
138+
| `goal-end` | Channel creator goal end event. |
139+
| `goal-progress` | Channel creator goal progress event. |
134140
| `grant` | Authorization grant event. |
135141
| `hype-train-begin` | Channel hype train start event. |
136142
| `hype-train-end` | Channel hype train end event. |

internal/events/models.go

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ var triggerSupported = map[string]bool{
2121
"hype-train-begin": true,
2222
"hype-train-progress": true,
2323
"hype-train-end": true,
24+
"goal-begin": true,
25+
"goal-progress": true,
26+
"goal-end": true,
2427
}
2528

2629
var transportSupported = map[string]bool{
+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package goal
4+
5+
import (
6+
"encoding/json"
7+
"time"
8+
9+
"github.com/twitchdev/twitch-cli/internal/events"
10+
"github.com/twitchdev/twitch-cli/internal/models"
11+
"github.com/twitchdev/twitch-cli/internal/util"
12+
)
13+
14+
var transportsSupported = map[string]bool{
15+
models.TransportEventSub: true,
16+
}
17+
18+
var triggerSupported = []string{"goal-begin", "goal-progress", "goal-end"}
19+
20+
var triggerMapping = map[string]map[string]string{
21+
models.TransportEventSub: {
22+
"goal-progress": "channel.goal.progress",
23+
"goal-begin": "channel.goal.begin",
24+
"goal-end": "channel.goal.end",
25+
},
26+
}
27+
28+
type Event struct{}
29+
30+
func (e Event) GenerateEvent(params events.MockEventParameters) (events.MockEventResponse, error) {
31+
var event []byte
32+
var err error
33+
var isAchieved *bool
34+
var goalEndDate *string
35+
var goalType string
36+
var currentAmount int64
37+
var targetAmount int64
38+
39+
goalStartedAt := util.GetTimestamp()
40+
currentAmount = util.RandomInt(10 * 10)
41+
targetAmount = util.RandomInt(10 * 100)
42+
43+
if params.Trigger == "goal-end" {
44+
endDate := goalStartedAt.Add(time.Hour * 24).Format(time.RFC3339)
45+
goalEndDate = &endDate
46+
47+
achieved := util.RandomInt(1) == 1
48+
if achieved {
49+
currentAmount = 100
50+
targetAmount = 100
51+
}
52+
53+
isAchieved = &achieved
54+
}
55+
56+
goalType = params.ItemName
57+
if goalType == "" {
58+
goalType = "follower"
59+
}
60+
61+
switch params.Transport {
62+
case models.TransportEventSub:
63+
64+
body := *&models.EventsubResponse{
65+
Subscription: models.EventsubSubscription{
66+
ID: params.ID,
67+
Status: "enabled",
68+
Type: triggerMapping[params.Transport][params.Trigger],
69+
Version: "1",
70+
Condition: models.EventsubCondition{
71+
BroadcasterUserID: params.ToUserID,
72+
},
73+
Transport: models.EventsubTransport{
74+
Method: "webhook",
75+
Callback: "null",
76+
},
77+
Cost: 0,
78+
CreatedAt: util.GetTimestamp().Format(time.RFC3339Nano),
79+
},
80+
Event: models.GoalEventSubEvent{
81+
ID: params.ID,
82+
BroadcasterUserID: params.ToUserID,
83+
BroadcasterUserLogin: params.ToUserName,
84+
BroadcasterUserName: params.ToUserName,
85+
Type: goalType,
86+
Description: params.Description,
87+
CurrentAmount: currentAmount,
88+
TargetAmount: targetAmount,
89+
StartedAt: goalStartedAt.Format(time.RFC3339Nano),
90+
EndedAt: goalEndDate,
91+
IsAchieved: isAchieved,
92+
},
93+
}
94+
95+
event, err = json.Marshal(body)
96+
if err != nil {
97+
return events.MockEventResponse{}, err
98+
}
99+
100+
default:
101+
return events.MockEventResponse{}, nil
102+
}
103+
104+
return events.MockEventResponse{
105+
ID: params.ID,
106+
JSON: event,
107+
FromUser: params.FromUserID,
108+
ToUser: params.ToUserID,
109+
}, nil
110+
}
111+
112+
func (e Event) ValidTransport(t string) bool {
113+
return transportsSupported[t]
114+
}
115+
116+
func (e Event) ValidTrigger(trigger string) bool {
117+
for _, t := range triggerSupported {
118+
if t == trigger {
119+
return true
120+
}
121+
}
122+
return false
123+
}
124+
125+
func (e Event) GetTopic(transport string, trigger string) string {
126+
return triggerMapping[transport][trigger]
127+
}
128+
129+
func (e Event) GetEventSubAlias(t string) string {
130+
// check for aliases
131+
for trigger, topic := range triggerMapping[models.TransportEventSub] {
132+
if topic == t {
133+
return trigger
134+
}
135+
}
136+
return ""
137+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package goal
4+
5+
import (
6+
"encoding/json"
7+
"testing"
8+
9+
"github.com/twitchdev/twitch-cli/internal/events"
10+
"github.com/twitchdev/twitch-cli/internal/models"
11+
"github.com/twitchdev/twitch-cli/test_setup"
12+
)
13+
14+
var user = "1234"
15+
16+
func TestEventSub(t *testing.T) {
17+
a := test_setup.SetupTestEnv(t)
18+
19+
params := *&events.MockEventParameters{
20+
ToUserID: user,
21+
Description: "Twitch Subscriber Goal",
22+
Transport: models.TransportEventSub,
23+
Trigger: "goal-begin",
24+
Status: "subscriber",
25+
}
26+
27+
r, err := Event{}.GenerateEvent(params)
28+
a.Nil(err)
29+
30+
var body models.GoalEventSubResponse
31+
err = json.Unmarshal(r.JSON, &body)
32+
a.Nil(err)
33+
34+
a.Equal("channel.goal.begin", body.Subscription.Type, "Expected event type %v, got %v", "channel.goal.begin", body.Subscription.Type)
35+
a.Equal(user, body.Event.BroadcasterUserID, "Expected from user %v, got %v", r.ToUser, body.Event.BroadcasterUserID)
36+
a.Equal("Twitch Subscriber Goal", body.Event.Description, "Expected from goal type %v, got %v", "Twitch Subscriber Goal", body.Event.Type)
37+
38+
params = *&events.MockEventParameters{
39+
ToUserID: user,
40+
Description: "Twitch Follower Goal",
41+
Transport: models.TransportEventSub,
42+
Trigger: "goal-progress",
43+
}
44+
45+
r, err = Event{}.GenerateEvent(params)
46+
a.Nil(err)
47+
48+
err = json.Unmarshal(r.JSON, &body)
49+
a.Nil(err)
50+
51+
a.Equal("channel.goal.progress", body.Subscription.Type, "Expected event type %v, got %v", "channel.goal.progress", body.Subscription.Type)
52+
a.Equal(user, body.Event.BroadcasterUserID, "Expected from user %v, got %v", r.ToUser, body.Event.BroadcasterUserID)
53+
54+
params = *&events.MockEventParameters{
55+
ToUserID: user,
56+
Description: "Twitch Follower Goal",
57+
Transport: models.TransportEventSub,
58+
Trigger: "goal-end",
59+
}
60+
61+
r, err = Event{}.GenerateEvent(params)
62+
a.Nil(err)
63+
64+
err = json.Unmarshal(r.JSON, &body)
65+
a.Nil(err)
66+
67+
a.Equal("channel.goal.end", body.Subscription.Type, "Expected event type %v, got %v", "channel.goal.end", body.Subscription.Type)
68+
a.Equal(user, body.Event.BroadcasterUserID, "Expected from user %v, got %v", r.ToUser, body.Event.BroadcasterUserID)
69+
a.NotNil(body.Event.EndedAt, "Expected endedDate to be nil got %v", body.Event.EndedAt)
70+
a.NotNil(body.Event.IsAchieved, "Expected endedDate to be nil got %v", body.Event.IsAchieved)
71+
}
72+
73+
func TestFakeTransport(t *testing.T) {
74+
a := test_setup.SetupTestEnv(t)
75+
76+
params := *&events.MockEventParameters{
77+
FromUserID: user,
78+
Transport: "fake_transport",
79+
Trigger: "unsubscribe",
80+
}
81+
82+
r, err := Event{}.GenerateEvent(params)
83+
a.Nil(err)
84+
a.Empty(r)
85+
}
86+
87+
func TestValidTrigger(t *testing.T) {
88+
a := test_setup.SetupTestEnv(t)
89+
90+
r := Event{}.ValidTrigger("goal-begin")
91+
a.Equal(true, r)
92+
93+
r = Event{}.ValidTrigger("goal-started")
94+
a.Equal(false, r)
95+
}
96+
97+
func TestValidTransport(t *testing.T) {
98+
a := test_setup.SetupTestEnv(t)
99+
100+
r := Event{}.ValidTransport(models.TransportEventSub)
101+
a.Equal(true, r)
102+
103+
r = Event{}.ValidTransport("noteventsub")
104+
a.Equal(false, r)
105+
}
106+
107+
func TestGetTopic(t *testing.T) {
108+
a := test_setup.SetupTestEnv(t)
109+
110+
r := Event{}.GetTopic(models.TransportEventSub, "goal-progress")
111+
a.NotNil(r)
112+
}

internal/events/types/types.go

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/twitchdev/twitch-cli/internal/events/types/extension_transaction"
1616
"github.com/twitchdev/twitch-cli/internal/events/types/follow"
1717
"github.com/twitchdev/twitch-cli/internal/events/types/gift"
18+
"github.com/twitchdev/twitch-cli/internal/events/types/goal"
1819
"github.com/twitchdev/twitch-cli/internal/events/types/hype_train"
1920
"github.com/twitchdev/twitch-cli/internal/events/types/moderator_change"
2021
"github.com/twitchdev/twitch-cli/internal/events/types/poll"
@@ -49,6 +50,7 @@ func All() []events.MockEvent {
4950
streamdown.Event{},
5051
subscribe.Event{},
5152
subscription_message.Event{},
53+
goal.Event{},
5254
}
5355
}
5456

internal/models/goal.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package models
2+
3+
type GoalEventSubEvent struct {
4+
ID string `json:"id"`
5+
BroadcasterUserID string `json:"broadcaster_user_id"`
6+
BroadcasterUserName string `json:"broadcaster_user_name"`
7+
BroadcasterUserLogin string `json:"broadcaster_user_login"`
8+
Type string `json:"type"`
9+
Description string `json:"description"`
10+
IsAchieved *bool `json:"is_achieved,omitempty"`
11+
CurrentAmount int64 `json:"current_amount"`
12+
TargetAmount int64 `json:"target_amount"`
13+
StartedAt string `json:"started_at"`
14+
EndedAt *string `json:"ended_at,omitempty"`
15+
}
16+
17+
type GoalEventSubResponse struct {
18+
Subscription EventsubSubscription `json:"subscription"`
19+
Event GoalEventSubEvent `json:"event"`
20+
}

0 commit comments

Comments
 (0)