Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Twitch Extension endpoints in Helix #114

Merged
merged 2 commits into from
Aug 31, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,16 @@ If you are looking for the Twitch API docs, see the [Twitch Developer website](h
- [x] Get Videos
- [x] Delete Videos
- [x] Get Webhook Subscriptions
- [ ] Create Extension Secret
- [ ] Get Extension Secret
- [x] Create Extension Secret
- [x] Get Extension Secret
- [ ] Revoke Extension Secrets
- [ ] Get Live Channels with Extension Activated
- [ ] Set Extension Required Configuration
- [ ] Set Extension Configuration Segment
- [x] Set Extension Required Configuration
- [x] Set Extension Configuration Segment
- [ ] Get Extension Channel Configuration
- [ ] Get Extension Configuration Segment
- [ ] Send Extension PubSub Message
- [ ] Send Extension Chat Message
- [x] Get Extension Configuration Segment
- [x] Send Extension PubSub Message
- [x] Send Extension Chat Message

## Quick Usage Example

Expand Down
93 changes: 93 additions & 0 deletions docs/extensions_docs.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,98 @@
# Extensions Documentation

## Extension Helix Requests

### Generate PUBSUB JWT Permissions
> relevant PUBSUB permission must be passed to the 'ExtensionCreateClaims()' func, in order to correctly publish a pubsub message of a particular type
jackmcguire1 marked this conversation as resolved.
Show resolved Hide resolved

Broadcast pubsub type
jackmcguire1 marked this conversation as resolved.
Show resolved Hide resolved
```go
client.FormBroadcastSendPubSubPermissions()
```

Global pubsub type
jackmcguire1 marked this conversation as resolved.
Show resolved Hide resolved
```go
perms := client.FormGlobalSendPubSubPermissions()
```

Whisper User type
jackmcguire1 marked this conversation as resolved.
Show resolved Hide resolved
```go
client.FormWhisperSendPubSubPermissions(userId)
```

### JWT ROLES
> Note:- Currently only the 'external' role is supported by helix endpoints
jackmcguire1 marked this conversation as resolved.
Show resolved Hide resolved


### EBS JWT
this is used to set the correct header for any Extension helix requests
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this is used to set the correct header for any Extension helix requests
This is used to set the correct header for any Extension helix requests.


```go
client, err := helix.NewClient(&helix.Options{
ClientID: "your-client-id",
UserAccessToken: "your-user-access-token",
ExtensionOpts: helix.ExtensionOptions{
OwnerUserID: os.Getenv(""),
Secret: os.Getenv(""),
ConfigurationVersion: os.Getenv(""),
Version: os.Getenv(""),
},
})


// see docs below to see what pub-sub permissions you can pass
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// see docs below to see what pub-sub permissions you can pass
// See docs below to see what pub-sub permissions you can pass.

claims, err := client.ExtensionCreateClaims(broadcasterID, client.FormBroadcastSendPubSubPermissions(), 0)
if err != nil {
// handle err
}

jwt,err := client.ExtensionJWTSign(claims)
if err != nil {
// handle err
}

// set this before doing extension endpoint requests
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// set this before doing extension endpoint requests
// Set this before doing extension endpoint requests.

client.SetExtensionSignedJWTToken(jwt)
```
## Get Extension Configuration Segments

```go

client, err := helix.NewClient(&helix.Options{
ClientID: "your-client-id",
UserAccessToken: "your-user-access-token",
ExtensionOpts: helix.ExtensionOptions{
OwnerUserID: os.Getenv("EXT_OWNER_ID"),
Secret: os.Getenv("EXT_SECRET"),
ConfigurationVersion: os.Getenv("EXT_CFG_VERSION"),
Version: os.Getenv("EXT_VERSION"),
},
})
if err != nil {
// handle error
}

claims, err := client.ExtensionCreateClaims(broadcasterID, ExternalRole, FormBroadcastSendPubSubPermissions(), 0)
if err != nil {
// handle error
}

// set the JWT token to be used as in the Auth bearer header
jackmcguire1 marked this conversation as resolved.
Show resolved Hide resolved
jwt := client.ExtensionJWTSign(claims)
client.SetExtensionSignedJWTToken(jwt)

params := helix.ExtensionGetConfigurationParams{
ExtensionID: "some-extension-id", // Required
Segments: []helix.ExtensionSegmentType{helix.GlobalSegment}, // Optional
}
resp, err := client.GetExtensionConfigurationSegment
if err != nil {
// handle error
}

fmt.Printf("%+v\n", resp)
```

## Get Extension Transactions

```go
Expand Down
120 changes: 120 additions & 0 deletions extension_configuration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package helix

import "fmt"

// SegmentType A segment configuration type
type ExtensionSegmentType string

// Types of segments datastores for the configuration service
const (
ExtensionConfigrationBroadcasterSegment ExtensionSegmentType = "broadcaster"
ExtensionConfigurationDeveloperSegment ExtensionSegmentType = "developer"
ExtensionConfigurationGlobalSegment ExtensionSegmentType = "global"
)

func (s ExtensionSegmentType) String() string {
return string(s)
}

type ExtensionSetConfigurationParams struct {
Segment ExtensionSegmentType `json:"segment"`
ExtensionID string `json:"extension-id"`
BroadcasterID string `json:"broadcaster_id,omitempty"` // populated if segment is of type 'developer' || 'broadcaster'
jackmcguire1 marked this conversation as resolved.
Show resolved Hide resolved
Version string `json:"version"`
Content string `json:"content"`
}

type ExtensionConfigurationSegment struct {
Segment ExtensionSegmentType `json:"segment"`
Version string `json:"version"`
Content string `json:"content"`
}

type ExtensionGetConfigurationParams struct {
ExtensionID string `query:"extension_id"`
BroadcasterID string `query:"broadcaster_id"`
Segments []ExtensionSegmentType `query:"segment"`
}

type ExtensionSetRequiredConfigurationParams struct {
BroadcasterID string `query:"broadcaster_id" json:"-"`
ExtensionID string `json:"extension_id"`
RequiredConfiguration string `json:"required_version"`
ExtensionVersion string `json:"extension_version"`
ConfigurationVersion string `json:"configuration_version"`
}

type ExtensionSetRequiredConfigurationResponse struct {
ResponseCommon
}

type ExtensionGetConfigurationSegmentResponse struct {
ResponseCommon
Data ManyExtensionConfigurationSegments
}

type ManyExtensionConfigurationSegments struct {
Segments []ExtensionConfigurationSegment `json:"data"`
}

type ExtensionSetConfigurationResponse struct {
ResponseCommon
}

// https://dev.twitch.tv/docs/extensions/reference/#set-extension-configuration-segment
func (c *Client) SetExtensionSegmentConfig(params *ExtensionSetConfigurationParams) (*ExtensionSetConfigurationResponse, error) {
if params.BroadcasterID != "" {
switch params.Segment {
case ExtensionConfigurationDeveloperSegment, ExtensionConfigrationBroadcasterSegment:
default:
return nil, fmt.Errorf("error: developer or broadcaster extension configuration segment type must be provided for broadcasters")
}
}

resp, err := c.putAsJSON("/extensions/configurations", &ManyPolls{}, params)
if err != nil {
return nil, err
}

setExtCnfgResp := &ExtensionSetConfigurationResponse{}
resp.HydrateResponseCommon(&setExtCnfgResp.ResponseCommon)

return setExtCnfgResp, nil
}

func (c *Client) GetExtensionConfigurationSegment(params *ExtensionGetConfigurationParams) (*ExtensionGetConfigurationSegmentResponse, error) {

if params.BroadcasterID != "" {
for _, segment := range params.Segments {
switch segment {
case ExtensionConfigurationDeveloperSegment, ExtensionConfigrationBroadcasterSegment:
default:
return nil, fmt.Errorf("error: only developer or broadcaster extension configuration segment type must be provided for broadcasters")
}
}
}

resp, err := c.get("/extensions/configurations", &ManyExtensionConfigurationSegments{}, params)
if err != nil {
return nil, err
}

extCfgSegResp := &ExtensionGetConfigurationSegmentResponse{}
resp.HydrateResponseCommon(&extCfgSegResp.ResponseCommon)
extCfgSegResp.Data.Segments = resp.Data.(*ManyExtensionConfigurationSegments).Segments

return extCfgSegResp, nil
}

func (c *Client) SetExtensionRequiredConfiguration(params *ExtensionSetRequiredConfigurationParams) (*ExtensionSetRequiredConfigurationResponse, error) {

resp, err := c.putAsJSON("/extensions/configurations/required_configuration", &ExtensionSetRequiredConfigurationResponse{}, params)
if err != nil {
return nil, err
}

extReqCfgResp := &ExtensionSetRequiredConfigurationResponse{}
resp.HydrateResponseCommon(&extReqCfgResp.ResponseCommon)

return extReqCfgResp, nil
}
Loading