github.com/diamondburned/arikawa@v1.3.14/voice/voicegateway/commands.go (about)

     1  package voicegateway
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/diamondburned/arikawa/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://discordapp.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://discordapp.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://discordapp.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://discordapp.com/developers/docs/topics/voice-connections#speaking
    99  type SpeakingFlag uint64
   100  
   101  const (
   102  	Microphone SpeakingFlag = 1 << iota
   103  	Soundshare
   104  	Priority
   105  )
   106  
   107  // OPCode 5
   108  // https://discordapp.com/developers/docs/topics/voice-connections#speaking-example-speaking-payload
   109  type SpeakingData struct {
   110  	Speaking SpeakingFlag `json:"speaking"`
   111  	Delay    int          `json:"delay"`
   112  	SSRC     uint32       `json:"ssrc"`
   113  }
   114  
   115  // Speaking sends a Speaking operation (opcode 5) to the Gateway Gateway.
   116  func (c *Gateway) Speaking(flag SpeakingFlag) error {
   117  	ctx, cancel := context.WithTimeout(context.Background(), c.Timeout)
   118  	defer cancel()
   119  
   120  	return c.SpeakingCtx(ctx, flag)
   121  }
   122  
   123  // SpeakingCtx sends a Speaking operation (opcode 5) to the Gateway Gateway.
   124  func (c *Gateway) SpeakingCtx(ctx context.Context, flag SpeakingFlag) error {
   125  	// How do we allow a user to stop speaking?
   126  	// Also: https://discordapp.com/developers/docs/topics/voice-connections#voice-data-interpolation
   127  
   128  	return c.SendCtx(ctx, SpeakingOP, SpeakingData{
   129  		Speaking: flag,
   130  		Delay:    0,
   131  		SSRC:     c.ready.SSRC,
   132  	})
   133  }
   134  
   135  // OPCode 7
   136  // https://discordapp.com/developers/docs/topics/voice-connections#resuming-voice-connection-example-resume-connection-payload
   137  type ResumeData struct {
   138  	GuildID   discord.GuildID `json:"server_id"` // yes, this should be "server_id"
   139  	SessionID string          `json:"session_id"`
   140  	Token     string          `json:"token"`
   141  }
   142  
   143  // Resume sends a Resume operation (opcode 7) to the Gateway Gateway.
   144  func (c *Gateway) Resume() error {
   145  	ctx, cancel := context.WithTimeout(context.Background(), c.Timeout)
   146  	defer cancel()
   147  	return c.ResumeCtx(ctx)
   148  }
   149  
   150  // ResumeCtx sends a Resume operation (opcode 7) to the Gateway Gateway.
   151  func (c *Gateway) ResumeCtx(ctx context.Context) error {
   152  	guildID := c.state.GuildID
   153  	sessionID := c.state.SessionID
   154  	token := c.state.Token
   155  
   156  	if !guildID.IsValid() || sessionID == "" || token == "" {
   157  		return ErrMissingForResume
   158  	}
   159  
   160  	return c.SendCtx(ctx, ResumeOP, ResumeData{
   161  		GuildID:   guildID,
   162  		SessionID: sessionID,
   163  		Token:     token,
   164  	})
   165  }