Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions internal/events/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ var triggerSupported = map[string]bool{
"revoke": true,
"shield-mode-begin": true,
"shield-mode-end": true,
"shoutout-create": true,
"shoutout-received": true,
"stream-change": true,
"streamdown": true,
"streamup": true,
Expand Down
169 changes: 169 additions & 0 deletions internal/events/types/shoutout/shoutout.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package shoutout

import (
"encoding/json"
"strings"
"time"

"github.com/twitchdev/twitch-cli/internal/events"
"github.com/twitchdev/twitch-cli/internal/models"
"github.com/twitchdev/twitch-cli/internal/util"
)

var transportsSupported = map[string]bool{
models.TransportEventSub: true,
}
var triggers = []string{"shoutout-create", "shoutout-received"}

var triggerMapping = map[string]map[string]string{
models.TransportEventSub: {
"shoutout-create": "channel.shoutout.create",
"shoutout-received": "channel.shoutout.receive",
},
}

type Event struct{}

func (e Event) GenerateEvent(params events.MockEventParameters) (events.MockEventResponse, error) {
var event []byte
var err error

switch params.Transport {
case models.TransportEventSub:
viewerCount := util.RandomInt(2000)
startedAt := util.GetTimestamp()

moderatorUserID := "3502151007"

if params.Trigger == "shoutout-create" {
body := models.ShoutoutCreateEventSubResponse{
Subscription: models.EventsubSubscription{
ID: params.ID,
Status: params.SubscriptionStatus,
Type: triggerMapping[params.Transport][params.Trigger],
Version: e.SubscriptionVersion(),
Condition: models.EventsubCondition{
BroadcasterUserID: params.FromUserID,
ModeratorUserID: moderatorUserID,
},
Transport: models.EventsubTransport{
Method: "webhook",
Callback: "null",
},
Cost: 0,
CreatedAt: params.Timestamp,
},
Event: models.ShoutoutCreateEventSubEvent{
BroadcasterUserID: params.FromUserID,
BroadcasterUserName: params.FromUserName,
BroadcasterUserLogin: params.FromUserName,
ToBroadcasterUserID: params.ToUserID,
ToBroadcasterUserName: params.ToUserName,
ToBroadcasterUserLogin: params.ToUserName,
ModeratorUserID: moderatorUserID,
ModeratorUserName: "TrustedUser123",
ModeratorUserLogin: "trusteduser123",
ViewerCount: int(viewerCount),
StartedAt: startedAt.Format(time.RFC3339Nano),
CooldownEndsAt: startedAt.Add(2 * time.Minute).Format(time.RFC3339Nano),
TargetCooldownEndsAt: startedAt.Add(1 * time.Hour).Format(time.RFC3339Nano),
},
}

event, err = json.Marshal(body)
if err != nil {
return events.MockEventResponse{}, err
}
} else if params.Trigger == "shoutout-received" {
body := models.ShoutoutReceivedEventSubResponse{
Subscription: models.EventsubSubscription{
ID: params.ID,
Status: params.SubscriptionStatus,
Type: triggerMapping[params.Transport][params.Trigger],
Version: e.SubscriptionVersion(),
Condition: models.EventsubCondition{
BroadcasterUserID: params.ToUserID,
ModeratorUserID: moderatorUserID,
},
Transport: models.EventsubTransport{
Method: "webhook",
Callback: "null",
},
Cost: 0,
CreatedAt: params.Timestamp,
},
Event: models.ShoutoutReceivedEventSubEvent{
BroadcasterUserID: params.ToUserID,
BroadcasterUserName: params.ToUserName,
BroadcasterUserLogin: params.ToUserName,
FromBroadcasterUserID: params.FromUserID,
FromBroadcasterUserName: params.FromUserName,
FromBroadcasterUserLogin: params.FromUserName,
ViewerCount: int(viewerCount),
StartedAt: startedAt.Format(time.RFC3339Nano),
},
}

event, err = json.Marshal(body)
if err != nil {
return events.MockEventResponse{}, err
}
}

// Delete event info if Subscription.Status is not set to "enabled"
if !strings.EqualFold(params.SubscriptionStatus, "enabled") {
var i interface{}
if err := json.Unmarshal([]byte(event), &i); err != nil {
return events.MockEventResponse{}, err
}
if m, ok := i.(map[string]interface{}); ok {
delete(m, "event") // Matches JSON key defined in body variable above
}

event, err = json.Marshal(i)
if err != nil {
return events.MockEventResponse{}, err
}
}
default:
return events.MockEventResponse{}, nil
}

return events.MockEventResponse{
ID: params.ID,
JSON: event,
ToUser: params.ToUserID,
FromUser: params.FromUserID,
}, nil
}

func (e Event) ValidTransport(transport string) bool {
return transportsSupported[transport]
}

func (e Event) ValidTrigger(trigger string) bool {
for _, t := range triggers {
if t == trigger {
return true
}
}
return false
}
func (e Event) GetTopic(transport string, trigger string) string {
return triggerMapping[transport][trigger]
}
func (e Event) GetEventSubAlias(t string) string {
// check for aliases
for trigger, topic := range triggerMapping[models.TransportEventSub] {
if topic == t {
return trigger
}
}
return ""
}

func (e Event) SubscriptionVersion() string {
return "beta"
}
107 changes: 107 additions & 0 deletions internal/events/types/shoutout/shoutout_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package shoutout

import (
"encoding/json"
"testing"

"github.com/twitchdev/twitch-cli/internal/events"
"github.com/twitchdev/twitch-cli/internal/models"
"github.com/twitchdev/twitch-cli/test_setup"
)

var fromUser = "1234"
var toUser = "4567"

func TestEventSub(t *testing.T) {
a := test_setup.SetupTestEnv(t)

beginParams := *&events.MockEventParameters{
FromUserID: fromUser,
ToUserID: toUser,
Transport: models.TransportEventSub,
Trigger: "shoutout-create",
SubscriptionStatus: "enabled",
Cost: 0,
}
endParams := *&events.MockEventParameters{
FromUserID: fromUser,
ToUserID: toUser,
Transport: models.TransportEventSub,
Trigger: "shoutout-received",
SubscriptionStatus: "enabled",
Cost: 0,
}

r1, err := Event{}.GenerateEvent(beginParams)
a.Nil(err)

r2, err := Event{}.GenerateEvent(endParams)
a.Nil(err)

var body1 models.ShoutoutCreateEventSubResponse
err = json.Unmarshal(r1.JSON, &body1)
a.Nil(err)

var body2 models.ShoutoutReceivedEventSubResponse
err = json.Unmarshal(r2.JSON, &body2)
a.Nil(err)
}

func TestFakeTransport(t *testing.T) {
a := test_setup.SetupTestEnv(t)

beginParams := *&events.MockEventParameters{
FromUserID: fromUser,
ToUserID: toUser,
Transport: "fake_transport",
Trigger: "shoutout-create",
SubscriptionStatus: "enabled",
}
endParams := *&events.MockEventParameters{
FromUserID: fromUser,
ToUserID: toUser,
Transport: "fake_transport",
Trigger: "shoutout-received",
SubscriptionStatus: "enabled",
}

r1, err1 := Event{}.GenerateEvent(beginParams)
r2, err2 := Event{}.GenerateEvent(endParams)
a.Nil(err1)
a.Nil(err2)
a.Empty(r1)
a.Empty(r2)
}
func TestValidTrigger(t *testing.T) {
a := test_setup.SetupTestEnv(t)

r := Event{}.ValidTrigger("shoutout-create")
a.Equal(true, r)

r = Event{}.ValidTrigger("shoutout-received")
a.Equal(true, r)

r = Event{}.ValidTrigger("notshoutout")
a.Equal(false, r)
}

func TestValidTransport(t *testing.T) {
a := test_setup.SetupTestEnv(t)

r := Event{}.ValidTransport(models.TransportEventSub)
a.Equal(true, r)

r = Event{}.ValidTransport("noteventsub")
a.Equal(false, r)
}
func TestGetTopic(t *testing.T) {
a := test_setup.SetupTestEnv(t)

r := Event{}.GetTopic(models.TransportEventSub, "shoutout-create")
a.NotNil(r)

r = Event{}.GetTopic(models.TransportEventSub, "shoutout-receieve")
a.NotNil(r)
}
2 changes: 2 additions & 0 deletions internal/events/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/twitchdev/twitch-cli/internal/events/types/prediction"
"github.com/twitchdev/twitch-cli/internal/events/types/raid"
"github.com/twitchdev/twitch-cli/internal/events/types/shield_mode"
"github.com/twitchdev/twitch-cli/internal/events/types/shoutout"
"github.com/twitchdev/twitch-cli/internal/events/types/stream_change"
"github.com/twitchdev/twitch-cli/internal/events/types/streamdown"
"github.com/twitchdev/twitch-cli/internal/events/types/streamup"
Expand Down Expand Up @@ -51,6 +52,7 @@ func All() []events.MockEvent {
prediction.Event{},
raid.Event{},
shield_mode.Event{},
shoutout.Event{},
stream_change.Event{},
streamup.Event{},
streamdown.Event{},
Expand Down
44 changes: 44 additions & 0 deletions internal/models/shoutout.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package models

// channel.shoutout.create

type ShoutoutCreateEventSubResponse struct {
Subscription EventsubSubscription `json:"subscription"`
Event ShoutoutCreateEventSubEvent `json:"event"`
}

type ShoutoutCreateEventSubEvent struct {
BroadcasterUserID string `json:"broadcaster_user_id"`
BroadcasterUserName string `json:"broadcaster_user_name"`
BroadcasterUserLogin string `json:"broadcaster_user_login"`
ToBroadcasterUserID string `json:"to_broadcaster_user_id"`
ToBroadcasterUserName string `json:"to_broadcaster_user_name"`
ToBroadcasterUserLogin string `json:"to_broadcaster_user_login"`
ModeratorUserID string `json:"moderator_user_id"`
ModeratorUserName string `json:"moderator_user_name"`
ModeratorUserLogin string `json:"moderator_user_login"`
ViewerCount int `json:"viewer_count"`
StartedAt string `json:"started_at"`
CooldownEndsAt string `json:"cooldown_ends_at"`
TargetCooldownEndsAt string `json:"target_cooldown_ends_at"`
}

// channel.shoutout.receive

type ShoutoutReceivedEventSubResponse struct {
Subscription EventsubSubscription `json:"subscription"`
Event ShoutoutReceivedEventSubEvent `json:"event"`
}

type ShoutoutReceivedEventSubEvent struct {
BroadcasterUserID string `json:"broadcaster_user_id"`
BroadcasterUserName string `json:"broadcaster_user_name"`
BroadcasterUserLogin string `json:"broadcaster_user_login"`
FromBroadcasterUserID string `json:"from_broadcaster_user_id"`
FromBroadcasterUserName string `json:"from_broadcaster_user_name"`
FromBroadcasterUserLogin string `json:"from_broadcaster_user_login"`
ViewerCount int `json:"viewer_count"`
StartedAt string `json:"started_at"`
}