Files
go-playit/core/mod.go

157 lines
3.7 KiB
Go

package core
import (
"fmt"
"net"
"net/netip"
"slices"
"time"
"sirherobrine23.com.br/go-bds/go-playit/api"
"sirherobrine23.com.br/go-bds/go-playit/proto"
"sirherobrine23.com.br/go-bds/go-playit/xcode"
)
func authenticateAgent(api *api.ApiClient, pong proto.Pong) (*api.SignedAgentKey, error) {
return api.ProtoRegisterRegister(pong.ClientAddr, pong.TunnelAddr)
}
func getControlAddresses(api *api.ApiClient) (addrs []netip.AddrPort, err error) {
data, err := api.AgentRoutings(nil)
if err != nil {
return
}
slices.SortFunc(data.TargetsV6, func(a, b netip.Addr) int { return a.Compare(b) })
slices.SortFunc(data.TargetsV4, func(a, b netip.Addr) int { return a.Compare(b) })
for _, addr := range append(data.TargetsV6, data.TargetsV4...) {
addrs = append(addrs, netip.AddrPortFrom(addr, 5525))
}
return
}
func connectToFirst(agent *PlayitAgent) (err error) {
if agent.PacketIo, err = net.ListenUDP("udp", nil); err != nil {
return
}
defer agent.PacketIo.SetReadDeadline(time.Time{})
buffer := make([]byte, 2048)
addrs, err := getControlAddresses(agent.Config.Api)
if err != nil {
return
}
for _, addr := range addrs {
attempts := 3
if addr.Addr().Is6() {
attempts = 1
}
for range attempts {
msg, err := xcode.Marshal(proto.ControlRpcMessage[proto.ControlRequest]{
Request: 1,
Content: proto.ControlRequest{
Ping: &proto.Ping{
Now: time.Now(),
},
},
})
if err != nil {
return err
}
if _, err = agent.PacketIo.WriteToUDPAddrPort(msg, addr); err != nil {
break
}
waits := 5
if addr.Addr().Is6() {
waits = 3
}
for range waits {
agent.PacketIo.SetReadDeadline(time.Now().Add(time.Millisecond * 500))
n, peer, err := agent.PacketIo.ReadFromUDPAddrPort(buffer)
if err != nil {
if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
continue
}
break
} else if peer != addr {
continue
}
feed := new(proto.ControlFeed)
if err = xcode.Unmarshal(buffer[:n], feed); err != nil {
continue
} else if feed.Response == nil {
continue
} else if feed.Response.Request != 1 {
continue
} else if feed.Response.Content.Pong == nil {
continue
}
agent.PongLatest = *feed.Response.Content.Pong
agent.ControlAddr = addr
agent.LastControlTargets = addrs
return nil
}
}
}
return fmt.Errorf("could not connect to any address")
}
// Get pong to test connection into main controller
func GetPong() (*proto.Pong, error) {
conn, err := net.Dial("udp", "control.playit.gg:5525")
if err != nil {
return nil, fmt.Errorf("cannot connect to control.playit.gg: %w", err)
}
currentTime := time.Now()
msg, err := xcode.Marshal(proto.ControlRpcMessage[proto.ControlRequest]{
Request: 1,
Content: proto.ControlRequest{
Ping: &proto.Ping{
Now: currentTime,
},
},
})
if err != nil {
return nil, fmt.Errorf("cannot encode Rpc Ping: %w", err)
} else if _, err = conn.Write(msg); err != nil {
return nil, fmt.Errorf("cannot write rpc ping to controller: %w", err)
}
msg = slices.Concat(msg, make([]byte, 2048-len(msg)))
for range 30 {
conn.SetReadDeadline(time.Now().Add(time.Second)) // Set 1 second to wait controller process request
n, err := conn.Read(msg)
if err != nil {
if e, ok := err.(net.Error); ok && e.Timeout() {
continue
}
return nil, err
}
var feed proto.ControlFeed
if err = xcode.Unmarshal(msg[:n], &feed); err != nil {
return nil, fmt.Errorf("cannot decode rpc feed response: %w", err)
} else if feed.Response == nil {
continue
} else if feed.Response.Request != 1 {
continue
} else if feed.Response.Content.Pong == nil {
continue
}
return feed.Response.Content.Pong, nil
}
return nil, fmt.Errorf("timeout get ping")
}