Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@
"console": "integratedTerminal",
"showLog": false, // Hides some Go Debugger(Delve) log stuff that is not useful for debugging atm
"args": ["--NoSteamCMD"]
},
{
"name": "Debug Go Server noSteamCMD noSvelte overrideAdvertisedIp",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/server.go",
"console": "integratedTerminal",
"showLog": false, // Hides some Go Debugger(Delve) log stuff that is not useful for debugging atm
"args": ["--NoSteamCMD", "--OverrideAdvertisedIp=127.0.0.1"]
}
]
}
12 changes: 4 additions & 8 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,17 @@ func main() {
logger.ConfigureConsole()
loader.ParseFlags()
loader.HandleSanityCheckFlag()
loader.SanityCheck(&wg)
wg.Wait()
loader.SanityCheck()
logger.Main.Info("Initializing resources...")
loader.InitVirtFS(v1uiFS)
logger.Install.Info("Starting setup...")
loader.ReloadConfig() // Load the config file before starting the setup process
loader.HandleFlags()
setup.Install(&wg)
wg.Wait()
setup.Install()
logger.Main.Debug("Initializing Backend...")
loader.InitBackend(&wg)
wg.Wait()
loader.InitBackend()
logger.Main.Debug("Initializing after start tasks...")
loader.AfterStartComplete(&wg)
wg.Wait()
loader.AfterStartComplete()
logger.Main.Debug("Starting webserver...")
web.StartWebServer(&wg)
logger.Main.Debug("Initializing SSUICLI...")
Expand Down
110 changes: 110 additions & 0 deletions src/advertiser/advertiser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package advertiser

import (
"bytes"
"encoding/json"
"net/http"
"runtime"
"strconv"
"time"

"github.com/JacksonTheMaster/StationeersServerUI/v5/src/config"
"github.com/JacksonTheMaster/StationeersServerUI/v5/src/logger"
"github.com/JacksonTheMaster/StationeersServerUI/v5/src/managers/detectionmgr"
"github.com/JacksonTheMaster/StationeersServerUI/v5/src/managers/gamemgr"
)

const StationeersAdvertisementEndpoint = "http://40.82.200.175:8081/Ping"

type ServerAdMessage struct {
SessionId int
Name string
Password bool
Version string
Address string
Port string
Players int
MaxPlayers int
Type int
}

type ServerAdResponse struct {
SessionId int
Status string
}

func StartAdvertiser() {
if config.GetServerVisible() {
logger.Advertiser.Warn("Server advertisement is enabled. Disable it in the config and restart SSUI to use manual advertisement. Skipping for now...")
return
}
go func() {
sessionId := -1
for {
// Only advertise if we are running
if gamemgr.InternalIsServerRunning() {
// Get max players
maxplayers, err := strconv.Atoi(config.GetServerMaxPlayers())
if err != nil {
logger.Advertiser.Errorf("ServerAdvertiser failed to convert max players number to int: %s", config.GetServerMaxPlayers())
return
Comment thread
akirilov marked this conversation as resolved.
}
// Get connected players
detector := detectionmgr.GetDetector()
players := len(detectionmgr.GetPlayers(detector))
// Get platform
platform := 0
switch runtime.GOOS {
case "windows":
platform = 1
case "linux":
platform = 2
}
adMessage := ServerAdMessage{
SessionId: sessionId,
Name: config.GetServerName(),
Password: config.GetServerPassword() != "",
Version: config.GetExtractedGameVersion(),
Address: config.GetOverrideAdvertisedIp(),
Port: config.GetGamePort(),
Players: players,
MaxPlayers: maxplayers,
Type: platform,
}
body, err := json.Marshal(adMessage)
if err != nil {
logger.Advertiser.Errorf("ServerAdvertiser failed to Serialize to JSON from native Go struct type: %v", err)
return
Comment thread
akirilov marked this conversation as resolved.
}
// Send advertisement
resp, err := http.Post(StationeersAdvertisementEndpoint, "application/json", bytes.NewBuffer(body))
// Check for errors
if err != nil {
logger.Advertiser.Errorf("ServerAdvertiser failed to send request: %v", err)
return
Comment thread
akirilov marked this conversation as resolved.
}
defer resp.Body.Close()
// Check the status
if resp.StatusCode != 200 {
logger.Advertiser.Warnf("ServerAdvertiser received non-200 status: %d", resp.StatusCode)
}
// Read the response and update our sessionId if needed
adResponse := ServerAdResponse{}
err = json.NewDecoder(resp.Body).Decode(&adResponse)
if err != nil {
logger.Advertiser.Errorf("Failed to decode response body: %v", err)
return
Comment thread
akirilov marked this conversation as resolved.
}
if adResponse.Status != "Success" {
logger.Advertiser.Warnf("ServerAdvertiser received unexpected status: %s", adResponse.Status)
}
sessionId = adResponse.SessionId
} else {
// Reset sessionid for the next run
sessionId = -1
}
// Sleep for 30 seconds to follow the standard advertisement timer
time.Sleep(30 * time.Second)
}
}()
}
12 changes: 8 additions & 4 deletions src/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ type JsonConfig struct {
StartLocation string `json:"StartLocation"`

// Logging and debug settings
Debug *bool `json:"Debug"`
CreateSSUILogFile *bool `json:"CreateSSUILogFile"`
LogLevel int `json:"LogLevel"`
SubsystemFilters []string `json:"subsystemFilters"`
Debug *bool `json:"Debug"`
CreateSSUILogFile *bool `json:"CreateSSUILogFile"`
LogLevel int `json:"LogLevel"`
SubsystemFilters []string `json:"subsystemFilters"`
OverrideAdvertisedIp string `json:"OverrideAdvertisedIp"`

// Authentication Settings
Users map[string]string `json:"users"` // Map of username to hashed password
Expand Down Expand Up @@ -296,6 +297,8 @@ func applyConfig(cfg *JsonConfig) {
// use Safebackups folder either way.
ConfiguredSafeBackupDir = filepath.Join("./saves/", SaveName, "Safebackups")

OverrideAdvertisedIp = getString(cfg.OverrideAdvertisedIp, "OVERRIDE_ADVERTISED_IP", "")

safeSaveConfig()
}

Expand Down Expand Up @@ -365,6 +368,7 @@ func safeSaveConfig() error {
AutoStartServerOnStartup: &AutoStartServerOnStartup,
SSUIIdentifier: SSUIIdentifier,
SSUIWebPort: SSUIWebPort,
OverrideAdvertisedIp: OverrideAdvertisedIp,
}

file, err := os.Create(ConfigPath)
Expand Down
6 changes: 6 additions & 0 deletions src/config/getters.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,3 +513,9 @@ func GetIsDockerContainer() bool {
defer ConfigMu.RUnlock()
return IsDockerContainer
}

func GetOverrideAdvertisedIp() string {
ConfigMu.RLock()
defer ConfigMu.RUnlock()
return OverrideAdvertisedIp
}
8 changes: 8 additions & 0 deletions src/config/setters.go
Original file line number Diff line number Diff line change
Expand Up @@ -694,3 +694,11 @@ func SetAllowAutoGameServerUpdates(value bool) error {
AllowAutoGameServerUpdates = value
return safeSaveConfig()
}

func SetOverrideAdvertisedIp(value string) error {
ConfigMu.Lock()
defer ConfigMu.Unlock()

OverrideAdvertisedIp = value
return safeSaveConfig()
}
1 change: 1 addition & 0 deletions src/config/vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ var (
LanguageSetting string
AutoStartServerOnStartup bool
SSUIIdentifier string
OverrideAdvertisedIp string
)

// Runtime only variables
Expand Down
6 changes: 1 addition & 5 deletions src/core/loader/afterstart.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package loader

import (
"sync"

"github.com/JacksonTheMaster/StationeersServerUI/v5/src/config"
"github.com/JacksonTheMaster/StationeersServerUI/v5/src/discordrpc"
"github.com/JacksonTheMaster/StationeersServerUI/v5/src/logger"
"github.com/JacksonTheMaster/StationeersServerUI/v5/src/managers/gamemgr"
"github.com/JacksonTheMaster/StationeersServerUI/v5/src/setup"
)

func AfterStartComplete(wg *sync.WaitGroup) {
wg.Add(1)
defer wg.Done()
func AfterStartComplete() {
config.SetSaveConfig() // Save config after startup through setters
err := setup.CleanUpOldUIModFolderFiles()
if err != nil {
Expand Down
8 changes: 8 additions & 0 deletions src/core/loader/cmdargs.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var recoveryPasswordFlag string
var devModeFlag bool
var skipSteamCMDFlag bool
var sanityCheckFlag bool
var overrideAdvertisedIpFlag string

// ParseFlags parses command-line arguments ONCE at startup (called from func main)
func ParseFlags() {
Expand All @@ -39,6 +40,7 @@ func ParseFlags() {
flag.BoolVar(&createSSUILogFileFlag, "lf", false, "(Alias) Create log files for SSUI")
flag.BoolVar(&skipSteamCMDFlag, "NoSteamCMD", false, "Skips SteamCMD installation")
flag.BoolVar(&sanityCheckFlag, "NoSanityCheck", false, "Skips the sanity check. Not recommended.")
flag.StringVar(&overrideAdvertisedIpFlag, "OverrideAdvertisedIp", "", "Override the advertised server IP (to allow server advertisement if you are behind a reverse proxy)")

// Parse command-line flags
flag.Parse()
Expand Down Expand Up @@ -100,6 +102,12 @@ func HandleFlags() {
logger.Main.Info(fmt.Sprintf("Overriding IsDebugMode from command line: Before=%t, Now=true", oldDebug))
}

if overrideAdvertisedIpFlag != "" {
Comment thread
akirilov marked this conversation as resolved.
oldOverrideAdvertisedIp := config.GetOverrideAdvertisedIp()
config.SetOverrideAdvertisedIp(overrideAdvertisedIpFlag)
logger.Main.Info(fmt.Sprintf("Overriding Advertised Server IP from command line: Before=%s, Now=%s", oldOverrideAdvertisedIp, overrideAdvertisedIpFlag))
}

if createSSUILogFileFlag {
oldCreateSSUILogFile := config.GetCreateSSUILogFile()
config.SetCreateSSUILogFile(true)
Expand Down
14 changes: 7 additions & 7 deletions src/core/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ package loader
import (
"embed"
"os"
"sync"
"time"

"github.com/JacksonTheMaster/StationeersServerUI/v5/src/advertiser"
"github.com/JacksonTheMaster/StationeersServerUI/v5/src/config"
"github.com/JacksonTheMaster/StationeersServerUI/v5/src/discordbot"
"github.com/JacksonTheMaster/StationeersServerUI/v5/src/localization"
Expand All @@ -19,16 +19,18 @@ import (
)

// only call this once at startup
func InitBackend(wg *sync.WaitGroup) {
wg.Add(1)
defer wg.Done()
func InitBackend() {
ReloadConfig()
ReloadSSCM()
ReloadBackupManager()
ReloadLocalizer()
ReloadAppInfoPoller()
ReloadDiscordBot()
InitDetector()
if config.GetOverrideAdvertisedIp() != "" {
logger.Advertiser.Info("Starting server advertiser...")
advertiser.StartAdvertiser()
}
}

// use this to reload backend at runtime
Expand Down Expand Up @@ -100,9 +102,7 @@ func InitVirtFS(v1uiFS embed.FS) {
config.SetV1UIFS(v1uiFS)
}

func SanityCheck(wg *sync.WaitGroup) {
wg.Add(1)
defer wg.Done()
func SanityCheck() {
err := runSanityCheck()
if err != nil {
logger.Main.Error("Sanity check failed, exiting in 10 secconds: " + err.Error())
Expand Down
3 changes: 3 additions & 0 deletions src/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var (
SSE = &Logger{suffix: SYS_SSE}
Security = &Logger{suffix: SYS_SECURITY}
Localization = &Logger{suffix: SYS_LOCALIZATION}
Advertiser = &Logger{suffix: SYS_ADVERTISER}
)

// Severity Levels
Expand All @@ -48,6 +49,7 @@ const (
SYS_SSE = "SSE"
SYS_SECURITY = "SECURITY"
SYS_LOCALIZATION = "LOCALIZATION"
SYS_ADVERTISER = "ADVERTISER"
)

const (
Expand All @@ -73,6 +75,7 @@ var subsystemColors = map[string]string{
SYS_SSE: colorCyan, // Matches WEB, streaming vibe
SYS_SECURITY: colorRed, // Screams "pay attention"
SYS_LOCALIZATION: colorCyan, // Matches WEB, localization-related
SYS_ADVERTISER: colorYellow, // Matches Config, advanced feature
}

// Global channels and mutex for all loggers
Expand Down
5 changes: 1 addition & 4 deletions src/setup/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ import (
var downloadBranch string // Holds the branch to download from

// Install performs the entire installation process and ensures the server waits for it to complete
func Install(wg *sync.WaitGroup) {
wg.Add(1)
defer wg.Done() // Signal that installation is complete

func Install() {
// Step 0: Check for updates
if err := update.UpdateExecutable(); err != nil {
logger.Install.Error("❌Update check went sideways: " + err.Error())
Expand Down