Basic functionality
This commit is contained in:
42
models/cod4cache.go
Normal file
42
models/cod4cache.go
Normal file
@ -0,0 +1,42 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/patrickmn/go-cache"
|
||||
)
|
||||
|
||||
type CachedProvider struct {
|
||||
provider StatusProvider
|
||||
cache *cache.Cache
|
||||
}
|
||||
|
||||
func NewCachedProvider(provider StatusProvider) (*CachedProvider, error) {
|
||||
c := cache.New(10*time.Second, 20*time.Second)
|
||||
|
||||
return &CachedProvider{
|
||||
provider: provider,
|
||||
cache: c,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *CachedProvider) GetServerStatus(host, port string, timeout time.Duration) (*CoD4ServerStatus, error) {
|
||||
status, found := c.cache.Get(ID(host, port))
|
||||
if found {
|
||||
return status.(*CoD4ServerStatus), nil
|
||||
} else {
|
||||
status, err := c.provider.GetServerStatus(host, port, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.cache.Set(ID(host, port), status, cache.DefaultExpiration)
|
||||
|
||||
return status, nil
|
||||
}
|
||||
}
|
||||
|
||||
func ID(host, port string) string {
|
||||
return fmt.Sprintf("%s:%s", host, port)
|
||||
}
|
||||
@ -12,38 +12,44 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var timeLayout = "Mon Jan 2 15:04:05 2006"
|
||||
var (
|
||||
timeLayout = "Mon Jan 2 15:04:05 2006"
|
||||
)
|
||||
|
||||
type StatusProvider interface {
|
||||
GetServerStatus(string, string, time.Duration) (*CoD4ServerStatus, error)
|
||||
}
|
||||
|
||||
type CoD4Server struct {
|
||||
server string
|
||||
port string
|
||||
protocol string
|
||||
timeout time.Duration
|
||||
server string
|
||||
port string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
type CoD4ServerStatus struct {
|
||||
raw string
|
||||
serverData map[string]string
|
||||
Name string
|
||||
MapStartTime time.Time
|
||||
MapName string
|
||||
MaxPlayers int
|
||||
Score []Score
|
||||
meta map[string]interface{}
|
||||
}
|
||||
|
||||
func NewCOD4ServerStatus(server, port string, timeout time.Duration) (*CoD4Server, error) {
|
||||
type CoD4UdpClient struct{}
|
||||
|
||||
func (CoD4UdpClient) GetServerStatus(server, port string, timeout time.Duration) (*CoD4ServerStatus, error) {
|
||||
if server == "" || port == "" {
|
||||
return nil, errors.New("server or port is empty")
|
||||
}
|
||||
|
||||
return &CoD4Server{
|
||||
server: server,
|
||||
port: port,
|
||||
protocol: "udp",
|
||||
timeout: timeout,
|
||||
}, nil
|
||||
}
|
||||
c := &CoD4Server{
|
||||
server: server,
|
||||
port: port,
|
||||
timeout: timeout,
|
||||
}
|
||||
|
||||
func (c *CoD4Server) GetServerStatus() (*CoD4ServerStatus, error) {
|
||||
data, err := c.receiveData()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -54,7 +60,7 @@ func (c *CoD4Server) GetServerStatus() (*CoD4ServerStatus, error) {
|
||||
|
||||
func (c *CoD4Server) receiveData() (string, error) {
|
||||
address := fmt.Sprintf("%s:%s", c.server, c.port)
|
||||
conn, err := net.DialTimeout(c.protocol, address, c.timeout)
|
||||
conn, err := net.DialTimeout("udp", address, c.timeout)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not connect to server: %s", err)
|
||||
}
|
||||
@ -105,11 +111,16 @@ func parseServerData(data string) (*CoD4ServerStatus, error) {
|
||||
c.serverData[tempData[i]] = tempData[i+1]
|
||||
}
|
||||
|
||||
startTime, err := time.ParseInLocation(timeLayout, c.serverData["g_mapStartTime"], time.Local)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.serverData["sv_hostname"] = colorCode(c.serverData["sv_hostname"])
|
||||
c.Name = c.serverData["sv_hostname"]
|
||||
c.serverData["_Maps"] = strings.Join(strings.Split(c.serverData["_Maps"], "-"), ",")
|
||||
c.MapName = c.serverData["mapname"]
|
||||
|
||||
startTime, err := time.ParseInLocation(timeLayout, c.serverData["g_mapStartTime"], time.Local)
|
||||
c.MaxPlayers, err = strconv.Atoi(c.serverData["sv_maxclients"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -159,9 +170,19 @@ func colorCode(str string) string {
|
||||
"9": "#6E3C3C",
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`\^(\d)(.*?)\^`)
|
||||
return re.ReplaceAllStringFunc(str, func(m string) string {
|
||||
matches := re.FindStringSubmatch(m)
|
||||
return fmt.Sprintf(`<span style="color:%s;">%s</span>^`, colorMap[matches[1]], matches[2])
|
||||
re := regexp.MustCompile(`\^(\d)`)
|
||||
str = re.ReplaceAllStringFunc(str, func(m string) string {
|
||||
code := string(m[1])
|
||||
if color, ok := colorMap[code]; ok {
|
||||
return fmt.Sprintf(`<span style="color:%s;">`, color)
|
||||
}
|
||||
return m
|
||||
})
|
||||
|
||||
// Close open span tags
|
||||
str += "^"
|
||||
reClose := regexp.MustCompile(`\^(.*?)\^`)
|
||||
str = reClose.ReplaceAllString(str, "$1</span>")
|
||||
|
||||
return str[:len(str)-1]
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
|
||||
type Persistence interface {
|
||||
CreateCapture(context.Context, *Capture) error
|
||||
UpdateCapture(context.Context, *Capture) error
|
||||
GetCaptures(context.Context) ([]Capture, error)
|
||||
GetCapturesByID(context.Context, int64) (*Capture, error)
|
||||
DeleteCapture(context.Context, int64) error
|
||||
@ -68,6 +69,12 @@ func (s *SQLitePersistence) GetCapturesByID(ctx context.Context, id int64) (*Cap
|
||||
return &capture, err
|
||||
}
|
||||
|
||||
func (s *SQLitePersistence) UpdateCapture(ctx context.Context, capture *Capture) error {
|
||||
_, err := s.db.NewUpdate().Model(capture).WherePK().Exec(ctx)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *SQLitePersistence) DeleteCapture(ctx context.Context, id int64) error {
|
||||
capture := Capture{
|
||||
ID: id,
|
||||
|
||||
Reference in New Issue
Block a user