pztrn
51b23fa68f
Fixed servers lists refresh. Despite on what list we're updating (all servers or only favorites) server item should be updated in both.
212 lines
6.2 KiB
Go
212 lines
6.2 KiB
Go
// URTator - Urban Terror server browser and game launcher, written in
|
|
// Go.
|
|
//
|
|
// Copyright (c) 2016, Stanslav N. a.k.a pztrn (or p0z1tr0n)
|
|
// All rights reserved.
|
|
//
|
|
// Licensed under Terms and Conditions of GNU General Public License
|
|
// version 3 or any higher.
|
|
// ToDo: put full text of license here.
|
|
package requester
|
|
|
|
import (
|
|
// stdlib
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
//"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
// local
|
|
"github.com/pztrn/urtrator/datamodels"
|
|
)
|
|
|
|
type Pooler struct {
|
|
// Maximum number of simultaneous requests running.
|
|
maxrequests int
|
|
// Packet prefix.
|
|
pp string
|
|
}
|
|
|
|
func (p *Pooler) Initialize() {
|
|
fmt.Println("Initializing requester goroutine pooler...")
|
|
// ToDo: figure out how to make this work nice.
|
|
p.maxrequests = 500
|
|
p.pp = "\377\377\377\377"
|
|
fmt.Println("Pooler initialized")
|
|
}
|
|
|
|
// Servers pinging pooler. Should be started as goroutine to prevent
|
|
// UI blocking.
|
|
func (p *Pooler) PingServers(servers_type string) {
|
|
fmt.Println("About to ping " + servers_type + " servers...")
|
|
|
|
cur_requests := 0
|
|
var wait sync.WaitGroup
|
|
|
|
for _, server_to_ping := range Cache.Servers {
|
|
if servers_type == "favorites" && server_to_ping.Server.Favorite != "1" {
|
|
continue
|
|
}
|
|
for {
|
|
if cur_requests == p.maxrequests {
|
|
time.Sleep(time.Second * 1)
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
wait.Add(1)
|
|
cur_requests += 1
|
|
go func(srv *datamodels.Server) {
|
|
defer wait.Done()
|
|
p.pingServersExecutor(srv)
|
|
cur_requests -= 1
|
|
}(server_to_ping.Server)
|
|
}
|
|
wait.Wait()
|
|
}
|
|
|
|
func (p *Pooler) pingServersExecutor(server *datamodels.Server) error {
|
|
srv := server.Ip + ":" + server.Port
|
|
fmt.Println("Pinging " + srv)
|
|
// Dial to server.
|
|
start_p := time.Now()
|
|
conn_ping, err2 := net.Dial("udp", srv)
|
|
if err2 != nil {
|
|
fmt.Println("Error dialing to server " + srv + "!")
|
|
return errors.New("Error dialing to server " + srv + "!")
|
|
}
|
|
// Set deadline, so we won't wait forever.
|
|
ddl_ping := time.Now()
|
|
// This should be enough. Maybe, you should'n run URTrator on modem
|
|
// connections? :)
|
|
ddl_ping = ddl_ping.Add(time.Second * 10)
|
|
conn_ping.SetDeadline(ddl_ping)
|
|
|
|
msg_ping := []byte(p.pp + "getinfo")
|
|
conn_ping.Write(msg_ping)
|
|
|
|
// UDP Buffer.
|
|
var received_buf_ping []byte = make([]byte, 128)
|
|
// Received buffer.
|
|
var raw_received_ping []byte
|
|
_, err := conn_ping.Read(received_buf_ping)
|
|
if err != nil {
|
|
fmt.Println("PING ERROR")
|
|
}
|
|
raw_received_ping = append(raw_received_ping, received_buf_ping...)
|
|
conn_ping.Close()
|
|
|
|
delta := strconv.Itoa(int(time.Since(start_p).Nanoseconds()) / 1000000)
|
|
server.Ping = delta
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *Pooler) UpdateServers(servers_type string) {
|
|
var wait sync.WaitGroup
|
|
|
|
for _, server := range Cache.Servers {
|
|
if servers_type == "favorites" && server.Server.Favorite != "1" {
|
|
continue
|
|
}
|
|
wait.Add(1)
|
|
go func(server *datamodels.Server) {
|
|
defer wait.Done()
|
|
p.updateSpecificServer(server)
|
|
}(server.Server)
|
|
}
|
|
wait.Wait()
|
|
p.PingServers(servers_type)
|
|
Eventer.LaunchEvent("flushServers")
|
|
|
|
Eventer.LaunchEvent("loadAllServers")
|
|
Eventer.LaunchEvent("loadFavoriteServers")
|
|
Eventer.LaunchEvent("serversUpdateCompleted")
|
|
}
|
|
|
|
// Updates information about specific server.
|
|
func (p *Pooler) updateSpecificServer(server *datamodels.Server) error {
|
|
server_addr := server.Ip + ":" + server.Port
|
|
fmt.Println("Updating server: " + server_addr)
|
|
|
|
// Dial to server.
|
|
conn, err1 := net.Dial("udp", server_addr)
|
|
if err1 != nil {
|
|
fmt.Println("Error dialing to server " + server_addr + "!")
|
|
return errors.New("Error dialing to server " + server_addr + "!")
|
|
}
|
|
|
|
// Set deadline, so we won't wait forever.
|
|
ddl := time.Now()
|
|
// This should be enough. Maybe, you should'n run URTrator on modem
|
|
// connections? :)
|
|
ddl = ddl.Add(time.Second * 2)
|
|
conn.SetDeadline(ddl)
|
|
|
|
msg := []byte(p.pp + "getstatus")
|
|
conn.Write(msg)
|
|
|
|
// UDP Buffer.
|
|
var received_buf []byte = make([]byte, 4096)
|
|
// Received buffer.
|
|
var raw_received []byte
|
|
for {
|
|
_, err := conn.Read(received_buf)
|
|
if err != nil {
|
|
break
|
|
}
|
|
raw_received = append(raw_received, received_buf...)
|
|
}
|
|
conn.Close()
|
|
|
|
// First line is "infoResponse" string, which we should skip by
|
|
// splitting response by "\n".
|
|
received_lines := strings.Split(string(raw_received), "\n")
|
|
// We have server's data!
|
|
if len(received_lines) > 1 {
|
|
srv_config := strings.Split(received_lines[1], "\\")
|
|
// Parse server configuration into passed server's datamodel.
|
|
for i := 0; i < len(srv_config); i = i + 1 {
|
|
if srv_config[i] == "g_modversion" {
|
|
server.Version = srv_config[i + 1]
|
|
}
|
|
if srv_config[i] == "g_gametype" {
|
|
server.Gamemode = srv_config[i + 1]
|
|
}
|
|
if srv_config[i] == "sv_maxclients" {
|
|
server.Maxplayers = srv_config[i + 1]
|
|
}
|
|
if srv_config[i] == "clients" {
|
|
server.Players = srv_config[i + 1]
|
|
}
|
|
if srv_config[i] == "mapname" {
|
|
server.Map = srv_config[i + 1]
|
|
}
|
|
if srv_config[i] == "sv_hostname" {
|
|
server.Name = srv_config[i + 1]
|
|
}
|
|
server.ExtendedConfig = received_lines[1]
|
|
}
|
|
if len(received_lines) >= 2 {
|
|
// Here we go, players information.
|
|
players := received_lines[2:]
|
|
fmt.Println(players, len(players), len(players[0]))
|
|
// Calculate players!
|
|
if len(players) == 1 && len(players[0]) > 255 {
|
|
server.Players = "0"
|
|
} else {
|
|
server.Players = strconv.Itoa(len(players))
|
|
}
|
|
server.PlayersInfo = strings.Join(received_lines[2:], "\\")
|
|
}
|
|
}
|
|
|
|
// ToDo: Calculate ping. 0 for now.
|
|
server.Ping = "0"
|
|
return nil
|
|
}
|