github.com/diamondburned/arikawa/v2@v2.1.0/voice/voicegateway/commands.go (about)

     1  package voicegateway
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/diamondburned/arikawa/v2/discord"
     8  	"github.com/pkg/errors"
     9  )
    10  
    11  var (
    12  	// ErrMissingForIdentify is an error when we are missing information to identify.
    13  	ErrMissingForIdentify = errors.New("missing GuildID, UserID, SessionID, or Token for identify")
    14  
    15  	// ErrMissingForResume is an error when we are missing information to resume.
    16  	ErrMissingForResume = errors.New("missing GuildID, SessionID, or Token for resuming")
    17  )
    18  
    19  // OPCode 0
    20  // https://discord.com/developers/docs/topics/voice-connections#establishing-a-voice-websocket-connection-example-voice-identify-payload
    21  type IdentifyData struct {
    22  	GuildID   discord.GuildID `json:"server_id"` // yes, this should be "server_id"
    23  	UserID    discord.UserID  `json:"user_id"`
    24  	SessionID string          `json:"session_id"`
    25  	Token     string          `json:"token"`
    26  }
    27  
    28  // Identify sends an Identify operation (opcode 0) to the Gateway Gateway.
    29  func (c *Gateway) Identify() error {
    30  	ctx, cancel := context.WithTimeout(context.Background(), c.Timeout)
    31  	defer cancel()
    32  
    33  	return c.IdentifyCtx(ctx)
    34  }
    35  
    36  // IdentifyCtx sends an Identify operation (opcode 0) to the Gateway Gateway.
    37  func (c *Gateway) IdentifyCtx(ctx context.Context) error {
    38  	guildID := c.state.GuildID
    39  	userID := c.state.UserID
    40  	sessionID := c.state.SessionID
    41  	token := c.state.Token
    42  
    43  	if guildID == 0 || userID == 0 || sessionID == "" || token == "" {
    44  		return ErrMissingForIdentify
    45  	}
    46  
    47  	return c.SendCtx(ctx, IdentifyOP, IdentifyData{
    48  		GuildID:   guildID,
    49  		UserID:    userID,
    50  		SessionID: sessionID,
    51  		Token:     token,
    52  	})
    53  }
    54  
    55  // OPCode 1
    56  // https://discord.com/developers/docs/topics/voice-connections#establishing-a-voice-udp-connection-example-select-protocol-payload
    57  type SelectProtocol struct {
    58  	Protocol string             `json:"protocol"`
    59  	Data     SelectProtocolData `json:"data"`
    60  }
    61  
    62  type SelectProtocolData struct {
    63  	Address string `json:"address"`
    64  	Port    uint16 `json:"port"`
    65  	Mode    string `json:"mode"`
    66  }
    67  
    68  // SelectProtocol sends a Select Protocol operation (opcode 1) to the Gateway Gateway.
    69  func (c *Gateway) SelectProtocol(data SelectProtocol) error {
    70  	ctx, cancel := context.WithTimeout(context.Background(), c.Timeout)
    71  	defer cancel()
    72  
    73  	return c.SelectProtocolCtx(ctx, data)
    74  }
    75  
    76  // SelectProtocolCtx sends a Select Protocol operation (opcode 1) to the Gateway Gateway.
    77  func (c *Gateway) SelectProtocolCtx(ctx context.Context, data SelectProtocol) error {
    78  	return c.SendCtx(ctx, SelectProtocolOP, data)
    79  }
    80  
    81  // OPCode 3
    82  // https://discord.com/developers/docs/topics/voice-connections#heartbeating-example-heartbeat-payload
    83  // type Heartbeat uint64
    84  
    85  // Heartbeat sends a Heartbeat operation (opcode 3) to the Gateway Gateway.
    86  func (c *Gateway) Heartbeat() error {
    87  	ctx, cancel := context.WithTimeout(context.Background(), c.Timeout)
    88  	defer cancel()
    89  
    90  	return c.HeartbeatCtx(ctx)
    91  }
    92  
    93  // HeartbeatCtx sends a Heartbeat operation (opcode 3) to the Gateway Gateway.
    94  func (c *Gateway) HeartbeatCtx(ctx context.Context) error {
    95  	return c.SendCtx(ctx, HeartbeatOP, time.Now().UnixNano())
    96  }
    97  
    98  // https://discord.com/developers/docs/topics/voice-connections#speaking
    99  type SpeakingFlag uint64
   100  
   101  const (
   102  	NotSpeaking SpeakingFlag = 0
   103  	Microphone  SpeakingFlag = 1 << iota
   104  	Soundshare
   105  	Priority
   106  )
   107  
   108  // OPCode 5
   109  // https://discord.com/developers/docs/topics/voice-connections#speaking-example-speaking-payload
   110  type SpeakingData struct {
   111  	Speaking SpeakingFlag   `json:"speaking"`
   112  	Delay    int            `json:"delay"`
   113  	SSRC     uint32         `json:"ssrc"`
   114  	UserID   discord.UserID `json:"user_id,omitempty"`
   115  }
   116  
   117  // Speaking sends a Speaking operation (opcode 5) to the Gateway Gateway.
   118  func (c *Gateway) Speaking(flag SpeakingFlag) error {
   119  	ctx, cancel := context.WithTimeout(context.Background(), c.Timeout)
   120  	defer cancel()
   121  
   122  	return c.SpeakingCtx(ctx, flag)
   123  }
   124  
   125  // SpeakingCtx sends a Speaking operation (opcode 5) to the Gateway Gateway.
   126  func (c *Gateway) SpeakingCtx(ctx context.Context, flag SpeakingFlag) error {
   127  	// How do we allow a user to stop speaking?
   128  	// Also: https://discordapp.com/developers/docs/topics/voice-connections#voice-data-interpolation
   129  
   130  	return c.SendCtx(ctx, SpeakingOP, SpeakingData{
   131  		Speaking: flag,
   132  		Delay:    0,
   133  		SSRC:     c.ready.SSRC,
   134  	})
   135  }
   136  
   137  // OPCode 7
   138  // https://discord.com/developers/docs/topics/voice-connections#resuming-voice-connection-example-resume-connection-payload
   139  type ResumeData struct {
   140  	GuildID   discord.GuildID `json:"server_id"` // yes, this should be "server_id"
   141  	SessionID string          `json:"session_id"`
   142  	Token     string          `json:"token"`
   143  }
   144  
   145  // Resume sends a Resume operation (opcode 7) to the Gateway Gateway.
   146  func (c *Gateway) Resume() error {
   147  	ctx, cancel := context.WithTimeout(context.Background(), c.Timeout)
   148  	defer cancel()
   149  	return c.ResumeCtx(ctx)
   150  }
   151  
   152  // ResumeCtx sends a Resume operation (opcode 7) to the Gateway Gateway.
   153  func (c *Gateway) ResumeCtx(ctx context.Context) error {
   154  	guildID := c.state.GuildID
   155  	sessionID := c.state.SessionID
   156  	token := c.state.Token
   157  
   158  	if !guildID.IsValid() || sessionID == "" || token == "" {
   159  		return ErrMissingForResume
   160  	}
   161  
   162  	return c.SendCtx(ctx, ResumeOP, ResumeData{
   163  		GuildID:   guildID,
   164  		SessionID: sessionID,
   165  		Token:     token,
   166  	})
   167  }