-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #325 from pixel365/feat/events-refactoring
feat: refactoring 'event' subcommands
- Loading branch information
Showing
8 changed files
with
461 additions
and
394 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package events | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
configure_event "github.com/twitchdev/twitch-cli/internal/events/configure" | ||
) | ||
|
||
func ConfigureCommand() (command *cobra.Command) { | ||
command = &cobra.Command{ | ||
Use: "configure", | ||
Short: "Allows users to configure defaults for the twitch event subcommands.", | ||
RunE: configureEventRun, | ||
Example: `twitch event configure`, | ||
} | ||
|
||
command.Flags().StringVarP(&forwardAddress, "forward-address", "F", "", "Forward address for mock event (webhook only).") | ||
command.Flags().StringVarP(&secret, "secret", "s", "", "Webhook secret. If defined, signs all forwarded events with the SHA256 HMAC and must be 10-100 characters in length.") | ||
|
||
return | ||
} | ||
|
||
func configureEventRun(cmd *cobra.Command, args []string) error { | ||
return configure_event.ConfigureEvents(configure_event.EventConfigurationParams{ | ||
ForwardAddress: forwardAddress, | ||
Secret: secret, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package events | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"github.com/spf13/cobra" | ||
configure_event "github.com/twitchdev/twitch-cli/internal/events/configure" | ||
"github.com/twitchdev/twitch-cli/internal/events/trigger" | ||
"github.com/twitchdev/twitch-cli/internal/util" | ||
) | ||
|
||
func RetriggerCommand() (command *cobra.Command) { | ||
command = &cobra.Command{ | ||
Use: "retrigger", | ||
Short: "Refires events based on the event ID. Can be forwarded to the local webserver for event testing.", | ||
RunE: retriggerCmdRun, | ||
Example: `twitch event retrigger subscribe`, | ||
} | ||
|
||
command.Flags().StringVarP(&forwardAddress, "forward-address", "F", "", "Forward address for mock event (webhook only).") | ||
command.Flags().StringVarP(&eventID, "id", "i", "", "ID of the event to be refired.") | ||
command.Flags().StringVarP(&secret, "secret", "s", "", "Webhook secret. If defined, signs all forwarded events with the SHA256 HMAC and must be 10-100 characters in length.") | ||
command.Flags().BoolVarP(&noConfig, "no-config", "D", false, "Disables the use of the configuration, if it exists.") | ||
command.MarkFlagRequired("id") | ||
|
||
return | ||
} | ||
|
||
func retriggerCmdRun(cmd *cobra.Command, args []string) error { | ||
if transport == "websub" { | ||
return fmt.Errorf(websubDeprecationNotice) | ||
} | ||
|
||
defaults := configure_event.GetEventConfiguration(noConfig) | ||
|
||
if secret != "" { | ||
if len(secret) < 10 || len(secret) > 100 { | ||
return fmt.Errorf("Invalid secret provided. Secrets must be between 10-100 characters") | ||
} | ||
} else { | ||
secret = defaults.Secret | ||
} | ||
|
||
if forwardAddress == "" { | ||
if defaults.ForwardAddress == "" { | ||
return fmt.Errorf("if a default configuration is not set, forward-address must be provided") | ||
} | ||
forwardAddress = defaults.ForwardAddress | ||
} | ||
|
||
res, err := trigger.RefireEvent(eventID, trigger.TriggerParameters{ | ||
ForwardAddress: forwardAddress, | ||
Secret: secret, | ||
Timestamp: util.GetTimestamp().Format(time.RFC3339Nano), | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("Error refiring event: %s", err) | ||
} | ||
|
||
fmt.Println(res) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package events | ||
|
||
import "github.com/spf13/cobra" | ||
|
||
func StartWebsocketServerCommand() *cobra.Command { | ||
return &cobra.Command{ | ||
Use: "start-websocket-server", | ||
Deprecated: `use "twitch event websocket start-server" instead.`, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
package events | ||
|
||
import ( | ||
"fmt" | ||
"net/url" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/twitchdev/twitch-cli/internal/events" | ||
configure_event "github.com/twitchdev/twitch-cli/internal/events/configure" | ||
"github.com/twitchdev/twitch-cli/internal/events/trigger" | ||
"github.com/twitchdev/twitch-cli/internal/events/types" | ||
) | ||
|
||
func TriggerCommand() (command *cobra.Command) { | ||
command = &cobra.Command{ | ||
Use: "trigger [event]", | ||
Short: "Creates mock events that can be forwarded to a local webserver for event testing.", | ||
Long: fmt.Sprintf(`Creates mock events that can be forwarded to a local webserver for event testing. | ||
Supported: | ||
%s`, types.AllWebhookTopics()), | ||
Args: cobra.MaximumNArgs(1), | ||
ValidArgs: types.AllWebhookTopics(), | ||
RunE: triggerCmdRun, | ||
Example: `twitch event trigger subscribe`, | ||
Aliases: []string{ | ||
"fire", "emit", | ||
}, | ||
} | ||
|
||
// flags for forwarding functionality/changing payloads | ||
command.Flags().StringVarP(&forwardAddress, "forward-address", "F", "", "Forward address for mock event (webhook only).") | ||
command.Flags().StringVarP(&transport, "transport", "T", "webhook", fmt.Sprintf("Preferred transport method for event. Defaults to /EventSub.\nSupported values: %s", events.ValidTransports())) | ||
command.Flags().StringVarP(&secret, "secret", "s", "", "Webhook secret. If defined, signs all forwarded events with the SHA256 HMAC and must be 10-100 characters in length.") | ||
command.Flags().BoolVarP(&noConfig, "no-config", "D", false, "Disables the use of the configuration, if it exists.") | ||
|
||
// per-topic flags | ||
command.Flags().StringVarP(&toUser, "to-user", "t", "", "User ID of the receiver of the event. For example, the user that receives a follow. In most contexts, this is the broadcaster.") | ||
command.Flags().StringVarP(&fromUser, "from-user", "f", "", "User ID of the user sending the event, for example the user following another user.") | ||
command.Flags().StringVarP(&giftUser, "gift-user", "g", "", "Used only for \"gift\" events. Denotes the User ID of the gifting user.") | ||
command.Flags().BoolVarP(&isAnonymous, "anonymous", "a", false, "Denotes if the event is anonymous. Only applies to Gift and Sub events.") | ||
command.Flags().IntVarP(&count, "count", "c", 1, "Number of times to run an event. This can be used to simulate rapid events, such as multiple sub gift, or large number of cheers.") | ||
command.Flags().StringVarP(&eventStatus, "event-status", "S", "", "Status of the Event object (.event.status in JSON); currently applies to channel points redemptions.") | ||
command.Flags().StringVarP(&subscriptionStatus, "subscription-status", "r", "enabled", "Status of the Subscription object (.subscription.status in JSON). Defaults to \"enabled\".") | ||
command.Flags().StringVarP(&itemID, "item-id", "i", "", "Manually set the ID of the event payload item (for example the reward ID in redemption events). For stream events, this is the game ID.") | ||
command.Flags().StringVarP(&itemName, "item-name", "n", "", "Manually set the name of the event payload item (for example the reward ID in redemption events). For stream events, this is the game title.") | ||
command.Flags().Int64VarP(&cost, "cost", "C", 0, "Amount of drops, subscriptions, bits, or channel points redeemed/used in the event.") | ||
command.Flags().StringVarP(&description, "description", "d", "", "Title the stream should be updated with.") | ||
command.Flags().StringVarP(&gameID, "game-id", "G", "", "Sets the game/category ID for applicable events.") | ||
command.Flags().StringVarP(&tier, "tier", "", "", "Sets the subscription tier. Valid values are 1000, 2000, and 3000.") | ||
command.Flags().StringVarP(&eventID, "subscription-id", "u", "", "Manually set the subscription/event ID of the event itself.") // TODO: This description will need to change with https://github.com/twitchdev/twitch-cli/issues/184 | ||
command.Flags().StringVar(×tamp, "timestamp", "", "Sets the timestamp to be used in payloads and headers. Must be in RFC3339Nano format.") | ||
command.Flags().IntVar(&charityCurrentValue, "charity-current-value", 0, "Only used for \"charity-*\" events. Manually set the current dollar value for charity events.") | ||
command.Flags().IntVar(&charityTargetValue, "charity-target-value", 1500000, "Only used for \"charity-*\" events. Manually set the target dollar value for charity events.") | ||
command.Flags().StringVar(&clientId, "client-id", "", "Manually set the Client ID used in revoke, grant, and bits transaction events.") | ||
command.Flags().StringVarP(&version, "version", "v", "", "Chooses the EventSub version used for a specific event. Not required for most events.") | ||
command.Flags().StringVar(&websocketClient, "session", "", "Defines a specific websocket client/session to forward an event to. Used only with \"websocket\" transport.") | ||
command.Flags().StringVar(&banStart, "ban-start", "", "Sets the timestamp a ban started at.") | ||
command.Flags().StringVar(&banEnd, "ban-end", "", "Sets the timestamp a ban is intended to end at. If not set, the ban event will appear as permanent. This flag can take a timestamp or relative time (600, 600s, 10d4h12m55s)") | ||
|
||
return | ||
} | ||
|
||
func triggerCmdRun(cmd *cobra.Command, args []string) error { | ||
if len(args) == 0 { | ||
cmd.Help() | ||
return fmt.Errorf("") | ||
} | ||
|
||
if transport == "websub" { | ||
return fmt.Errorf(websubDeprecationNotice) | ||
} | ||
|
||
defaults := configure_event.GetEventConfiguration(noConfig) | ||
|
||
if secret != "" { | ||
if len(secret) < 10 || len(secret) > 100 { | ||
return fmt.Errorf("Invalid secret provided. Secrets must be between 10-100 characters") | ||
} | ||
} else { | ||
secret = defaults.Secret | ||
} | ||
|
||
// Validate that the forward address is actually a URL | ||
if len(forwardAddress) > 0 { | ||
_, err := url.ParseRequestURI(forwardAddress) | ||
if err != nil { | ||
return err | ||
} | ||
} else { | ||
forwardAddress = defaults.ForwardAddress | ||
} | ||
|
||
for i := 0; i < count; i++ { | ||
res, err := trigger.Fire(trigger.TriggerParameters{ | ||
Event: args[0], | ||
EventID: eventID, | ||
Transport: transport, | ||
ForwardAddress: forwardAddress, | ||
FromUser: fromUser, | ||
ToUser: toUser, | ||
GiftUser: giftUser, | ||
Secret: secret, | ||
IsAnonymous: isAnonymous, | ||
EventStatus: eventStatus, | ||
ItemID: itemID, | ||
Cost: cost, | ||
Description: description, | ||
ItemName: itemName, | ||
GameID: gameID, | ||
Tier: tier, | ||
SubscriptionStatus: subscriptionStatus, | ||
Timestamp: timestamp, | ||
CharityCurrentValue: charityCurrentValue, | ||
CharityTargetValue: charityTargetValue, | ||
ClientID: clientId, | ||
Version: version, | ||
WebSocketClient: websocketClient, | ||
BanStartTimestamp: banStart, | ||
BanEndTimestamp: banEnd, | ||
}) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Println(res) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package events | ||
|
||
const websubDeprecationNotice = "Halt! It appears you are trying to use WebSub, which has been deprecated. For more information, see: https://discuss.dev.twitch.tv/t/deprecation-of-websub-based-webhooks/32152" | ||
|
||
var ( | ||
isAnonymous bool | ||
forwardAddress string | ||
transport string | ||
noConfig bool | ||
fromUser string | ||
toUser string | ||
giftUser string | ||
eventID string | ||
secret string | ||
eventStatus string | ||
subscriptionStatus string | ||
itemID string | ||
itemName string | ||
cost int64 | ||
count int | ||
description string | ||
gameID string | ||
tier string | ||
timestamp string | ||
charityCurrentValue int | ||
charityTargetValue int | ||
clientId string | ||
version string | ||
websocketClient string | ||
banStart string | ||
banEnd string | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package events | ||
|
||
import ( | ||
"fmt" | ||
"net/url" | ||
"time" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/twitchdev/twitch-cli/internal/events" | ||
configure_event "github.com/twitchdev/twitch-cli/internal/events/configure" | ||
"github.com/twitchdev/twitch-cli/internal/events/types" | ||
"github.com/twitchdev/twitch-cli/internal/events/verify" | ||
"github.com/twitchdev/twitch-cli/internal/util" | ||
) | ||
|
||
func VerifySubscriptionCommand() (command *cobra.Command) { | ||
command = &cobra.Command{ | ||
Use: "verify-subscription [event]", | ||
Short: "Mocks the subscription verification event. Can be forwarded to a local webserver for testing.", | ||
Long: fmt.Sprintf(`Mocks the subscription verification event that can be forwarded to a local webserver for testing. | ||
Supported: | ||
%s`, types.AllWebhookTopics()), | ||
Args: cobra.MaximumNArgs(1), | ||
ValidArgs: types.AllWebhookTopics(), | ||
RunE: verifyCmdRun, | ||
Example: `twitch event verify-subscription subscribe`, | ||
Aliases: []string{ | ||
"verify", | ||
}, | ||
} | ||
|
||
command.Flags().StringVarP(&forwardAddress, "forward-address", "F", "", "Forward address for mock event (webhook only).") | ||
command.Flags().StringVarP(&transport, "transport", "T", "webhook", fmt.Sprintf("Preferred transport method for event. Defaults to EventSub.\nSupported values: %s", events.ValidTransports())) | ||
command.Flags().StringVarP(&secret, "secret", "s", "", "Webhook secret. If defined, signs all forwarded events with the SHA256 HMAC and must be 10-100 characters in length.") | ||
command.Flags().StringVar(×tamp, "timestamp", "", "Sets the timestamp to be used in payloads and headers. Must be in RFC3339Nano format.") | ||
command.Flags().StringVarP(&eventID, "subscription-id", "u", "", "Manually set the subscription/event ID of the event itself.") // TODO: This description will need to change with https://github.com/twitchdev/twitch-cli/issues/184 | ||
command.Flags().StringVarP(&version, "version", "v", "", "Chooses the EventSub version used for a specific event. Not required for most events.") | ||
command.Flags().BoolVarP(&noConfig, "no-config", "D", false, "Disables the use of the configuration, if it exists.") | ||
command.Flags().StringVarP(&toUser, "broadcaster", "b", "", "User ID of the broadcaster for the verification event.") | ||
|
||
return | ||
} | ||
|
||
func verifyCmdRun(cmd *cobra.Command, args []string) error { | ||
if len(args) == 0 { | ||
cmd.Help() | ||
return fmt.Errorf("") | ||
} | ||
|
||
if transport == "websub" { | ||
return fmt.Errorf(websubDeprecationNotice) | ||
} | ||
|
||
defaults := configure_event.GetEventConfiguration(noConfig) | ||
|
||
if secret != "" { | ||
if len(secret) < 10 || len(secret) > 100 { | ||
return fmt.Errorf("Invalid secret provided. Secrets must be between 10-100 characters") | ||
} | ||
} else { | ||
secret = defaults.Secret | ||
} | ||
|
||
// Validate that the forward address is actually a URL | ||
if len(forwardAddress) > 0 { | ||
_, err := url.ParseRequestURI(forwardAddress) | ||
if err != nil { | ||
return err | ||
} | ||
} else { | ||
forwardAddress = defaults.ForwardAddress | ||
} | ||
|
||
if timestamp == "" { | ||
timestamp = util.GetTimestamp().Format(time.RFC3339Nano) | ||
} else { | ||
// Verify custom timestamp | ||
_, err := time.Parse(time.RFC3339Nano, timestamp) | ||
if err != nil { | ||
return fmt.Errorf( | ||
`Discarding verify: Invalid timestamp provided. | ||
Please follow RFC3339Nano, which is used by Twitch as seen here: | ||
https://dev.twitch.tv/docs/eventsub/handling-webhook-events#processing-an-event`) | ||
} | ||
} | ||
|
||
_, err := verify.VerifyWebhookSubscription(verify.VerifyParameters{ | ||
Event: args[0], | ||
Transport: transport, | ||
ForwardAddress: forwardAddress, | ||
Secret: secret, | ||
Timestamp: timestamp, | ||
EventID: eventID, | ||
BroadcasterUserID: toUser, | ||
Version: version, | ||
}) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.