2018-08-24 01:24:20 +00:00
|
|
|
package gavalink
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"log"
|
2019-10-13 04:42:08 +00:00
|
|
|
"net/http"
|
2018-08-24 01:24:20 +00:00
|
|
|
"os"
|
|
|
|
"sort"
|
2019-10-13 04:42:08 +00:00
|
|
|
"time"
|
2018-08-24 01:24:20 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Log sets the log.Logger gavalink will write to
|
|
|
|
var Log *log.Logger
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
Log = log.New(os.Stdout, "(gavalink) ", 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lavalink manages a connection to Lavalink Nodes
|
|
|
|
type Lavalink struct {
|
|
|
|
shards string
|
|
|
|
userID string
|
|
|
|
|
2019-10-13 03:57:59 +00:00
|
|
|
nodes []*Node
|
2018-08-24 01:24:20 +00:00
|
|
|
players map[string]*Player
|
2019-10-13 03:57:59 +00:00
|
|
|
|
|
|
|
BestNodeFunc func([]*Node) (*Node, error)
|
2018-08-24 01:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
errNoNodes = errors.New("No nodes present")
|
|
|
|
errNodeNotFound = errors.New("Couldn't find that node")
|
|
|
|
errPlayerNotFound = errors.New("Couldn't find a player for that guild")
|
|
|
|
errVolumeOutOfRange = errors.New("Volume is out of range, must be within [0, 1000]")
|
|
|
|
errInvalidVersion = errors.New("This library requires Lavalink >= 3")
|
|
|
|
errUnknownPayload = errors.New("Lavalink sent an unknown payload")
|
|
|
|
errNilHandler = errors.New("You must provide an event handler. Use gavalink.DummyEventHandler if you wish to ignore events")
|
|
|
|
)
|
|
|
|
|
|
|
|
// NewLavalink creates a new Lavalink manager
|
|
|
|
func NewLavalink(shards string, userID string) *Lavalink {
|
|
|
|
return &Lavalink{
|
2019-10-13 03:57:59 +00:00
|
|
|
shards: shards,
|
|
|
|
userID: userID,
|
2018-08-24 01:24:20 +00:00
|
|
|
players: make(map[string]*Player),
|
2019-10-13 03:57:59 +00:00
|
|
|
|
|
|
|
BestNodeFunc: BestNodeByLoad,
|
2018-08-24 01:24:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddNodes adds a node to the Lavalink manager
|
|
|
|
func (lavalink *Lavalink) AddNodes(nodeConfigs ...NodeConfig) error {
|
2019-10-13 03:57:59 +00:00
|
|
|
nodes := make([]*Node, len(nodeConfigs))
|
2019-01-13 23:37:38 +00:00
|
|
|
|
2019-10-13 04:42:08 +00:00
|
|
|
client := &http.Client{
|
|
|
|
Timeout: 60 * time.Second,
|
|
|
|
}
|
|
|
|
|
2018-08-24 01:24:20 +00:00
|
|
|
for i, c := range nodeConfigs {
|
2019-10-13 03:57:59 +00:00
|
|
|
n := &Node{
|
2018-08-24 01:24:20 +00:00
|
|
|
config: c,
|
|
|
|
manager: lavalink,
|
2019-10-13 04:42:08 +00:00
|
|
|
client: client,
|
2018-08-24 01:24:20 +00:00
|
|
|
}
|
2019-10-13 01:13:23 +00:00
|
|
|
|
2018-08-24 01:24:20 +00:00
|
|
|
err := n.open()
|
2019-10-13 01:13:23 +00:00
|
|
|
|
2018-08-24 01:24:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-10-13 01:13:23 +00:00
|
|
|
|
2018-08-24 01:24:20 +00:00
|
|
|
nodes[i] = n
|
|
|
|
}
|
2019-01-13 23:37:38 +00:00
|
|
|
|
2018-08-24 01:24:20 +00:00
|
|
|
lavalink.nodes = append(lavalink.nodes, nodes...)
|
2019-01-13 23:37:38 +00:00
|
|
|
|
2018-08-24 01:24:20 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveNode removes a node from the manager
|
|
|
|
func (lavalink *Lavalink) removeNode(node *Node) error {
|
|
|
|
idx := -1
|
|
|
|
for i, n := range lavalink.nodes {
|
2019-10-13 03:57:59 +00:00
|
|
|
if n == node {
|
2018-08-24 01:24:20 +00:00
|
|
|
idx = i
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if idx == -1 {
|
|
|
|
return errNodeNotFound
|
|
|
|
}
|
|
|
|
|
|
|
|
node.stop()
|
|
|
|
|
2019-10-13 03:57:59 +00:00
|
|
|
for _, player := range lavalink.players {
|
|
|
|
if player.node == node {
|
|
|
|
n, err := lavalink.BestNode()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
player.ChangeNode(n)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-24 01:24:20 +00:00
|
|
|
// temp var for easier reading
|
|
|
|
n := lavalink.nodes
|
|
|
|
z := len(n) - 1
|
|
|
|
|
|
|
|
n[idx] = n[z] // swap idx with last
|
|
|
|
n = n[:z]
|
|
|
|
|
|
|
|
lavalink.nodes = n
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// BestNode returns the Node with the lowest latency
|
|
|
|
func (lavalink *Lavalink) BestNode() (*Node, error) {
|
|
|
|
if len(lavalink.nodes) < 1 {
|
|
|
|
return nil, errNoNodes
|
|
|
|
}
|
|
|
|
|
2019-10-13 03:57:59 +00:00
|
|
|
return lavalink.BestNodeFunc(lavalink.nodes)
|
2018-08-24 01:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetPlayer gets a player for a guild
|
|
|
|
func (lavalink *Lavalink) GetPlayer(guild string) (*Player, error) {
|
|
|
|
p, ok := lavalink.players[guild]
|
2019-01-13 23:37:38 +00:00
|
|
|
|
2018-08-24 01:24:20 +00:00
|
|
|
if !ok {
|
|
|
|
return nil, errPlayerNotFound
|
|
|
|
}
|
2019-01-13 23:37:38 +00:00
|
|
|
|
2018-08-24 01:24:20 +00:00
|
|
|
return p, nil
|
|
|
|
}
|
2019-10-13 03:57:59 +00:00
|
|
|
|
|
|
|
func BestNodeByLoad(n []*Node) (*Node, error) {
|
|
|
|
sort.SliceStable(n, func(i, j int) bool {
|
|
|
|
return n[i].load < n[j].load
|
|
|
|
})
|
|
|
|
|
|
|
|
return n[0], nil
|
|
|
|
}
|