157 lines
3.7 KiB
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")
|
|
}
|