update tracking
This commit is contained in:
@@ -26,7 +26,7 @@ func NewApiService(repository *repository.ApiRepository,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (as ApiService) SetServerService(serverService *ServerService) {
|
func (as *ApiService) SetServerService(serverService *ServerService) {
|
||||||
as.serverService = serverService
|
as.serverService = serverService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func NewConfigService(repository *repository.ConfigRepository, serverRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (as ConfigService) SetServerService(serverService *ServerService) {
|
func (as *ConfigService) SetServerService(serverService *ServerService) {
|
||||||
as.serverService = serverService
|
as.serverService = serverService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
@@ -42,57 +38,13 @@ func NewServerService(repository *repository.ServerRepository, apiService *ApiSe
|
|||||||
return service
|
return service
|
||||||
}
|
}
|
||||||
|
|
||||||
var leaderboardUpdateRegex = regexp.MustCompile(`Updated leaderboard for (\d+) clients`)
|
|
||||||
var sessionChangeRegex = regexp.MustCompile(`Session changed: (\w+) -> (\w+)`)
|
|
||||||
|
|
||||||
func handleLogLine(instance *model.AccServerInstance) func(string) {
|
|
||||||
return func (line string) {
|
|
||||||
state := (*instance).State
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
if strings.Contains(line, "client(s) online") {
|
|
||||||
parts := strings.Fields(line)
|
|
||||||
if len(parts) >= 2 {
|
|
||||||
countStr := parts[1]
|
|
||||||
if count, err := strconv.Atoi(countStr); err == nil {
|
|
||||||
state.Lock()
|
|
||||||
state.PlayerCount = count
|
|
||||||
state.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(line, "Session changed") {
|
|
||||||
match := sessionChangeRegex.FindStringSubmatch(line)
|
|
||||||
if len(match) == 3 {
|
|
||||||
newSession := match[2]
|
|
||||||
|
|
||||||
state.Lock()
|
|
||||||
state.Session = newSession
|
|
||||||
state.SessionStart = now
|
|
||||||
state.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(line, "Updated leaderboard for") {
|
|
||||||
match := leaderboardUpdateRegex.FindStringSubmatch(line)
|
|
||||||
if len(match) == 2 {
|
|
||||||
if count, err := strconv.Atoi(match[1]); err == nil {
|
|
||||||
state.Lock()
|
|
||||||
state.PlayerCount = count
|
|
||||||
state.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ServerService) StartAccServerRuntime(server *model.Server) {
|
func (s *ServerService) StartAccServerRuntime(server *model.Server) {
|
||||||
s.instances.Delete(server.ID)
|
s.instances.Delete(server.ID)
|
||||||
instance := &model.AccServerInstance{
|
instance := tracking.NewAccServerInstance(server, func(states ...tracking.StateChange) {
|
||||||
Model: server,
|
for _, state := range states {
|
||||||
State: &model.ServerState{PlayerCount: 0},
|
log.Println(tracking.StateChanges[state])
|
||||||
}
|
}
|
||||||
|
})
|
||||||
config, _ := DecodeFileName(ConfigurationJson)(server.ConfigPath)
|
config, _ := DecodeFileName(ConfigurationJson)(server.ConfigPath)
|
||||||
cfg := config.(model.Configuration)
|
cfg := config.(model.Configuration)
|
||||||
event, _ := DecodeFileName(EventJson)(server.ConfigPath)
|
event, _ := DecodeFileName(EventJson)(server.ConfigPath)
|
||||||
@@ -101,7 +53,7 @@ func (s *ServerService) StartAccServerRuntime(server *model.Server) {
|
|||||||
instance.State.MaxConnections = cfg.MaxConnections.ToInt()
|
instance.State.MaxConnections = cfg.MaxConnections.ToInt()
|
||||||
instance.State.Track = evt.Track
|
instance.State.Track = evt.Track
|
||||||
|
|
||||||
go tracking.TailLogFile(filepath.Join(server.ConfigPath, "\\server\\log\\server.log"), handleLogLine(instance))
|
go tracking.TailLogFile(filepath.Join(server.ConfigPath, "\\server\\log\\server.log"), instance.HandleLogLine)
|
||||||
s.instances.Store(server.ID, instance)
|
s.instances.Store(server.ID, instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +77,7 @@ func (as ServerService) GetAll(ctx *fiber.Ctx) *[]model.Server {
|
|||||||
if !ok {
|
if !ok {
|
||||||
log.Print("Unable to retrieve instance for server of ID: ", server.ID)
|
log.Print("Unable to retrieve instance for server of ID: ", server.ID)
|
||||||
} else {
|
} else {
|
||||||
serverInstance := instance.(*model.AccServerInstance)
|
serverInstance := instance.(*tracking.AccServerInstance)
|
||||||
if (serverInstance.State != nil) {
|
if (serverInstance.State != nil) {
|
||||||
(*servers)[i].State = *serverInstance.State
|
(*servers)[i].State = *serverInstance.State
|
||||||
}
|
}
|
||||||
@@ -153,7 +105,7 @@ func (as ServerService) GetById(ctx *fiber.Ctx, serverID int) *model.Server {
|
|||||||
if !ok {
|
if !ok {
|
||||||
log.Print("Unable to retrieve instance for server of ID: ", server.ID)
|
log.Print("Unable to retrieve instance for server of ID: ", server.ID)
|
||||||
} else {
|
} else {
|
||||||
serverInstance := instance.(*model.AccServerInstance)
|
serverInstance := instance.(*tracking.AccServerInstance)
|
||||||
if (serverInstance.State != nil) {
|
if (serverInstance.State != nil) {
|
||||||
server.State = *serverInstance.State
|
server.State = *serverInstance.State
|
||||||
}
|
}
|
||||||
|
|||||||
26
local/utl/regexHandler/regexHandler.go
Normal file
26
local/utl/regexHandler/regexHandler.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package regexHandler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"acc-server-manager/local/model"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AccServerInstance struct {
|
||||||
|
Model *model.Server
|
||||||
|
State *model.ServerState
|
||||||
|
}
|
||||||
|
|
||||||
|
type RegexHandler struct {
|
||||||
|
regex *regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rh *RegexHandler) Contains(line string, callback func(...string)) {
|
||||||
|
match := rh.regex.FindStringSubmatch(line)
|
||||||
|
callback(match...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(str string) *RegexHandler {
|
||||||
|
return &RegexHandler{
|
||||||
|
regex: regexp.MustCompile(str),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,80 @@
|
|||||||
package tracking
|
package tracking
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"acc-server-manager/local/model"
|
||||||
|
"acc-server-manager/local/utl/regexHandler"
|
||||||
"bufio"
|
"bufio"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type StateChange int
|
||||||
|
const (
|
||||||
|
PlayerCount StateChange = iota
|
||||||
|
Session
|
||||||
|
)
|
||||||
|
|
||||||
|
var StateChanges = map[StateChange]string {
|
||||||
|
PlayerCount: "player-count",
|
||||||
|
Session: "session",
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccServerInstance struct {
|
||||||
|
Model *model.Server
|
||||||
|
State *model.ServerState
|
||||||
|
OnStateChange func(...StateChange)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAccServerInstance(server *model.Server, onStateChange func(...StateChange)) *AccServerInstance {
|
||||||
|
return &AccServerInstance{
|
||||||
|
Model: server,
|
||||||
|
State: &model.ServerState{PlayerCount: 0},
|
||||||
|
OnStateChange: onStateChange,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type StateRegexHandler struct {
|
||||||
|
*regexHandler.RegexHandler
|
||||||
|
test string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRegexHandler(str string, test string) *StateRegexHandler {
|
||||||
|
return &StateRegexHandler{
|
||||||
|
RegexHandler: regexHandler.New(str),
|
||||||
|
test: test,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rh *StateRegexHandler) Test(line string) bool{
|
||||||
|
return strings.Contains(line, rh.test)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rh *StateRegexHandler) Count(line string) int{
|
||||||
|
var count int = 0
|
||||||
|
rh.Contains(line, func (strs ...string) {
|
||||||
|
if len(strs) == 2 {
|
||||||
|
if ct, err := strconv.Atoi(strs[1]); err == nil {
|
||||||
|
count = ct
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rh *StateRegexHandler) Change(line string) (string, string){
|
||||||
|
var old string = ""
|
||||||
|
var new string = ""
|
||||||
|
rh.Contains(line, func (strs ...string) {
|
||||||
|
if len(strs) == 3 {
|
||||||
|
old = strs[1]
|
||||||
|
new = strs[2]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return old, new
|
||||||
|
}
|
||||||
|
|
||||||
func TailLogFile(path string, callback func(string)) {
|
func TailLogFile(path string, callback func(string)) {
|
||||||
file, _ := os.Open(path)
|
file, _ := os.Open(path)
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
@@ -22,3 +91,84 @@ func TailLogFile(path string, callback func(string)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LogStateType int
|
||||||
|
const (
|
||||||
|
SessionChange LogStateType = iota
|
||||||
|
LeaderboardUpdate
|
||||||
|
UDPCount
|
||||||
|
ClientsOnline
|
||||||
|
)
|
||||||
|
|
||||||
|
var logStateContain = map[LogStateType]string {
|
||||||
|
SessionChange: "Session changed",
|
||||||
|
LeaderboardUpdate: "Updated leaderboard for",
|
||||||
|
UDPCount: "Udp message count",
|
||||||
|
ClientsOnline: "client(s) online",
|
||||||
|
}
|
||||||
|
|
||||||
|
var sessionChangeRegex = NewRegexHandler(`Session changed: (\w+) -> (\w+)`, logStateContain[SessionChange])
|
||||||
|
var leaderboardUpdateRegex = NewRegexHandler(`Updated leaderboard for (\d+) clients`, logStateContain[LeaderboardUpdate])
|
||||||
|
var udpCountRegex = NewRegexHandler(`Udp message count ((\d+) client`, logStateContain[UDPCount])
|
||||||
|
var clientsOnlineRegex = NewRegexHandler(`(\d+) client(s) online`, logStateContain[ClientsOnline])
|
||||||
|
|
||||||
|
var logStateRegex = map[LogStateType]*StateRegexHandler {
|
||||||
|
SessionChange: sessionChangeRegex,
|
||||||
|
LeaderboardUpdate: leaderboardUpdateRegex,
|
||||||
|
UDPCount: udpCountRegex,
|
||||||
|
ClientsOnline: clientsOnlineRegex,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *AccServerInstance) HandleLogLine(line string) {
|
||||||
|
for logState, regexHandler := range logStateRegex {
|
||||||
|
if (regexHandler.Test(line)) {
|
||||||
|
switch logState {
|
||||||
|
case LeaderboardUpdate:
|
||||||
|
case UDPCount:
|
||||||
|
case ClientsOnline:
|
||||||
|
count := regexHandler.Count(line)
|
||||||
|
instance.UpdatePlayerCount(count)
|
||||||
|
case SessionChange:
|
||||||
|
_, new := regexHandler.Change(line)
|
||||||
|
instance.UpdateSessionChange(new)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *AccServerInstance) UpdateState(callback func(state *model.ServerState)) {
|
||||||
|
state := instance.State
|
||||||
|
state.Lock()
|
||||||
|
defer state.Unlock()
|
||||||
|
callback(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *AccServerInstance) UpdatePlayerCount(count int) {
|
||||||
|
changes := []StateChange{}
|
||||||
|
instance.UpdateState(func (state *model.ServerState) {
|
||||||
|
if (count > 0 && state.PlayerCount == 0) {
|
||||||
|
state.SessionStart = time.Now()
|
||||||
|
changes = append(changes, Session)
|
||||||
|
} else if (count == 0) {
|
||||||
|
state.SessionStart = time.Time{}
|
||||||
|
changes = append(changes, Session)
|
||||||
|
}
|
||||||
|
state.PlayerCount = count
|
||||||
|
changes = append(changes, PlayerCount)
|
||||||
|
})
|
||||||
|
instance.OnStateChange(changes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *AccServerInstance) UpdateSessionChange(session string) {
|
||||||
|
changes := []StateChange{}
|
||||||
|
instance.UpdateState(func (state *model.ServerState) {
|
||||||
|
if (state.PlayerCount > 0) {
|
||||||
|
state.SessionStart = time.Now()
|
||||||
|
} else {
|
||||||
|
state.SessionStart = time.Time{}
|
||||||
|
}
|
||||||
|
state.Session = session
|
||||||
|
changes = append(changes, Session)
|
||||||
|
})
|
||||||
|
instance.OnStateChange(changes...)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user