mirror of
https://github.com/livekit/livekit.git
synced 2026-03-30 19:55:41 +00:00
* cli: Allow setting the current node region with flag or env variable Also add region to "starting LiveKit server" log. * routing: Add region to node registration Register the node's region on the selected router so it can be used for region aware node selection. Also add the region to the list-nodes output. * regionaware: Set minDist to zero for the current node If you don't set the minDist when leaving the loop early for a node that matches the current region, the minDist value with still be at max. This causes the the wrong node to be selected if the current node is the first one the loop passes through. Add a test that validates this change. The new test fails if this new change is not in place.
194 lines
4.4 KiB
Go
194 lines
4.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/livekit/protocol/auth"
|
|
"github.com/livekit/protocol/utils"
|
|
"github.com/olekukonko/tablewriter"
|
|
"github.com/urfave/cli/v2"
|
|
"gopkg.in/yaml.v3"
|
|
|
|
"github.com/livekit/livekit-server/pkg/routing"
|
|
"github.com/livekit/livekit-server/pkg/service"
|
|
)
|
|
|
|
func generateKeys(c *cli.Context) error {
|
|
apiKey := utils.NewGuid(utils.APIKeyPrefix)
|
|
secret := utils.RandomSecret()
|
|
fmt.Println("API Key: ", apiKey)
|
|
fmt.Println("API Secret: ", secret)
|
|
return nil
|
|
}
|
|
|
|
func printPorts(c *cli.Context) error {
|
|
conf, err := getConfig(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
udpPorts := make([]string, 0)
|
|
tcpPorts := make([]string, 0)
|
|
|
|
tcpPorts = append(tcpPorts, fmt.Sprintf("%d - HTTP service", conf.Port))
|
|
if conf.RTC.TCPPort != 0 {
|
|
tcpPorts = append(tcpPorts, fmt.Sprintf("%d - ICE/TCP", conf.RTC.TCPPort))
|
|
}
|
|
if conf.RTC.UDPPort != 0 {
|
|
udpPorts = append(udpPorts, fmt.Sprintf("%d - ICE/UDP", conf.RTC.UDPPort))
|
|
} else {
|
|
udpPorts = append(udpPorts, fmt.Sprintf("%d-%d - ICE/UDP range", conf.RTC.ICEPortRangeStart, conf.RTC.ICEPortRangeEnd))
|
|
}
|
|
|
|
if conf.TURN.Enabled {
|
|
if conf.TURN.TLSPort > 0 {
|
|
tcpPorts = append(tcpPorts, fmt.Sprintf("%d - TURN/TLS", conf.TURN.TLSPort))
|
|
}
|
|
if conf.TURN.UDPPort > 0 {
|
|
udpPorts = append(udpPorts, fmt.Sprintf("%d - TURN/UDP", conf.TURN.UDPPort))
|
|
}
|
|
}
|
|
|
|
fmt.Println("TCP Ports")
|
|
for _, p := range tcpPorts {
|
|
fmt.Println(p)
|
|
}
|
|
|
|
fmt.Println("UDP Ports")
|
|
for _, p := range udpPorts {
|
|
fmt.Println(p)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func createToken(c *cli.Context) error {
|
|
room := c.String("room")
|
|
identity := c.String("identity")
|
|
|
|
conf, err := getConfig(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// use the first API key from config
|
|
if len(conf.Keys) == 0 {
|
|
// try to load from file
|
|
if _, err := os.Stat(conf.KeyFile); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.Open(conf.KeyFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
_ = f.Close()
|
|
}()
|
|
decoder := yaml.NewDecoder(f)
|
|
if err = decoder.Decode(conf.Keys); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(conf.Keys) == 0 {
|
|
return fmt.Errorf("keys are not configured")
|
|
}
|
|
}
|
|
|
|
var apiKey string
|
|
var apiSecret string
|
|
for k, v := range conf.Keys {
|
|
apiKey = k
|
|
apiSecret = v
|
|
break
|
|
}
|
|
|
|
grant := &auth.VideoGrant{
|
|
RoomJoin: true,
|
|
Room: room,
|
|
}
|
|
if c.Bool("recorder") {
|
|
grant.Hidden = true
|
|
grant.SetCanPublish(false)
|
|
grant.SetCanPublishData(false)
|
|
}
|
|
|
|
at := auth.NewAccessToken(apiKey, apiSecret).
|
|
AddGrant(grant).
|
|
SetIdentity(identity).
|
|
SetValidFor(30 * 24 * time.Hour)
|
|
|
|
token, err := at.ToJWT()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Println("Token:", token)
|
|
|
|
return nil
|
|
}
|
|
|
|
func listNodes(c *cli.Context) error {
|
|
conf, err := getConfig(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
currentNode, err := routing.NewLocalNode(conf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
router, err := service.InitializeRouter(conf, currentNode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
nodes, err := router.ListNodes()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
table := tablewriter.NewWriter(os.Stdout)
|
|
table.SetHeader([]string{
|
|
"ID", "IP Address", "Region",
|
|
"CPUs", "Load",
|
|
"Clients", "Rooms", "Tracks In/Out",
|
|
"Bytes In/Out", "Packets In/Out", "Nack", "Bps In/Out", "Pps In/Out", "Nack/Sec",
|
|
"Started At", "Updated At",
|
|
})
|
|
for _, node := range nodes {
|
|
// System stats
|
|
cpus := strconv.Itoa(int(node.Stats.NumCpus))
|
|
loadAvg := fmt.Sprintf("%.2f, %.2f, %.2f", node.Stats.LoadAvgLast1Min, node.Stats.LoadAvgLast5Min, node.Stats.LoadAvgLast15Min)
|
|
|
|
// Room stats
|
|
clients := strconv.Itoa(int(node.Stats.NumClients))
|
|
rooms := strconv.Itoa(int(node.Stats.NumRooms))
|
|
tracks := fmt.Sprintf("%d / %d", node.Stats.NumTracksIn, node.Stats.NumTracksOut)
|
|
|
|
// Packet stats
|
|
bytes := fmt.Sprintf("%d / %d", node.Stats.BytesIn, node.Stats.BytesOut)
|
|
packets := fmt.Sprintf("%d / %d", node.Stats.PacketsIn, node.Stats.PacketsOut)
|
|
nack := strconv.Itoa(int(node.Stats.NackTotal))
|
|
bps := fmt.Sprintf("%.2f / %.2f", node.Stats.BytesInPerSec, node.Stats.BytesOutPerSec)
|
|
packetsPerSec := fmt.Sprintf("%.2f / %.2f", node.Stats.PacketsInPerSec, node.Stats.PacketsOutPerSec)
|
|
nackPerSec := fmt.Sprintf("%f", node.Stats.NackPerSec)
|
|
|
|
startedAt := time.Unix(node.Stats.StartedAt, 0).String()
|
|
updatedAt := time.Unix(node.Stats.UpdatedAt, 0).String()
|
|
|
|
table.Append([]string{
|
|
node.Id, node.Ip, node.Region,
|
|
cpus, loadAvg,
|
|
clients, rooms, tracks,
|
|
bytes, packets, nack, bps, packetsPerSec, nackPerSec,
|
|
startedAt, updatedAt,
|
|
})
|
|
}
|
|
table.Render()
|
|
|
|
return nil
|
|
}
|