Initial commit
This commit is contained in:
114
backend/internal/api/configs.go
Normal file
114
backend/internal/api/configs.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type createConfigInput struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type updateConfigInput struct {
|
||||
Content string `json:"content" binding:"required"`
|
||||
}
|
||||
|
||||
type duplicateConfigInput struct {
|
||||
NewName string `json:"new_name" binding:"required"`
|
||||
}
|
||||
|
||||
func (h *Handler) ListConfigs(c *gin.Context) {
|
||||
configs, err := h.configs.List()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, configs)
|
||||
}
|
||||
|
||||
func validateConfigName(name string) bool {
|
||||
return name != "" && !strings.ContainsAny(name, "/\\")
|
||||
}
|
||||
|
||||
func (h *Handler) CreateConfig(c *gin.Context) {
|
||||
var input createConfigInput
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if !validateConfigName(input.Name) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid config name"})
|
||||
return
|
||||
}
|
||||
if err := h.configs.Create(input.Name, input.Content); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, gin.H{"name": input.Name})
|
||||
}
|
||||
|
||||
func (h *Handler) GetConfig(c *gin.Context) {
|
||||
name := c.Param("name")
|
||||
if !validateConfigName(name) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid config name"})
|
||||
return
|
||||
}
|
||||
content, err := h.configs.Get(name)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.String(http.StatusOK, content)
|
||||
}
|
||||
|
||||
func (h *Handler) UpdateConfig(c *gin.Context) {
|
||||
var input updateConfigInput
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
name := c.Param("name")
|
||||
if !validateConfigName(name) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid config name"})
|
||||
return
|
||||
}
|
||||
if err := h.configs.Update(name, input.Content); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
||||
}
|
||||
|
||||
func (h *Handler) DeleteConfig(c *gin.Context) {
|
||||
name := c.Param("name")
|
||||
if !validateConfigName(name) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid config name"})
|
||||
return
|
||||
}
|
||||
if err := h.configs.Delete(name); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (h *Handler) DuplicateConfig(c *gin.Context) {
|
||||
var input duplicateConfigInput
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
name := c.Param("name")
|
||||
if !validateConfigName(name) || !validateConfigName(input.NewName) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid config name"})
|
||||
return
|
||||
}
|
||||
if err := h.configs.Duplicate(name, input.NewName); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, gin.H{"name": input.NewName})
|
||||
}
|
||||
196
backend/internal/api/logs.go
Normal file
196
backend/internal/api/logs.go
Normal file
@@ -0,0 +1,196 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool { return true },
|
||||
}
|
||||
|
||||
func (h *Handler) StreamLogs(c *gin.Context) {
|
||||
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
if err != nil {
|
||||
log.Printf("websocket upgrade error: %v", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
clientID := conn.RemoteAddr().String()
|
||||
ch := h.streamer.Subscribe("server", clientID)
|
||||
defer h.streamer.Unsubscribe("server", clientID)
|
||||
|
||||
for line := range ch {
|
||||
if err := conn.WriteMessage(websocket.TextMessage, []byte(line)); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) ListLogs(c *gin.Context) {
|
||||
profilesDir := h.process.ProfilesDir()
|
||||
files := h.collectLogFiles(profilesDir, "")
|
||||
|
||||
logsDir := filepath.Join(profilesDir, "logs")
|
||||
if fi, err := os.Stat(logsDir); err == nil && fi.IsDir() {
|
||||
files = append(files, h.collectLogFiles(logsDir, "logs")...)
|
||||
}
|
||||
|
||||
slices.Sort(files)
|
||||
if files == nil {
|
||||
files = []string{}
|
||||
}
|
||||
c.JSON(http.StatusOK, files)
|
||||
}
|
||||
|
||||
func (h *Handler) collectLogFiles(dir, prefix string) []string {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var files []string
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() {
|
||||
ext := filepath.Ext(e.Name())
|
||||
if ext == ".log" || ext == ".rpt" || e.Name() == "script.log" {
|
||||
if prefix != "" {
|
||||
files = append(files, prefix+"/"+e.Name())
|
||||
} else {
|
||||
files = append(files, e.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return files
|
||||
}
|
||||
|
||||
func (h *Handler) StreamSteamCMDLogs(c *gin.Context) {
|
||||
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
if err != nil {
|
||||
log.Printf("websocket upgrade error: %v", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
clientID := conn.RemoteAddr().String()
|
||||
ch := h.streamer.Subscribe("steamcmd", clientID)
|
||||
defer h.streamer.Unsubscribe("steamcmd", clientID)
|
||||
|
||||
for line := range ch {
|
||||
if err := conn.WriteMessage(websocket.TextMessage, []byte(line)); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) StreamRPTLogs(c *gin.Context) {
|
||||
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
if err != nil {
|
||||
log.Printf("websocket upgrade error: %v", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
profilesDir := h.process.ProfilesDir()
|
||||
var currentPath string
|
||||
var currentOffset int64
|
||||
ticker := time.NewTicker(250 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
for range ticker.C {
|
||||
path := findLatestRPT(profilesDir)
|
||||
|
||||
if path != currentPath {
|
||||
currentPath = path
|
||||
currentOffset = 0
|
||||
if currentPath == "" {
|
||||
continue
|
||||
}
|
||||
conn.WriteMessage(websocket.TextMessage, []byte("--- tailing: "+filepath.Base(currentPath)+" ---"))
|
||||
}
|
||||
if currentPath == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
fi, err := os.Stat(currentPath)
|
||||
if err != nil {
|
||||
currentPath = ""
|
||||
continue
|
||||
}
|
||||
if fi.Size() <= currentOffset {
|
||||
continue
|
||||
}
|
||||
|
||||
f, err := os.Open(currentPath)
|
||||
if err != nil {
|
||||
currentPath = ""
|
||||
continue
|
||||
}
|
||||
f.Seek(currentOffset, io.SeekStart)
|
||||
buf := make([]byte, fi.Size()-currentOffset)
|
||||
n, _ := io.ReadFull(f, buf)
|
||||
f.Close()
|
||||
|
||||
currentOffset += int64(n)
|
||||
for _, line := range strings.Split(string(buf[:n]), "\n") {
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
if err := conn.WriteMessage(websocket.TextMessage, []byte(line)); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findLatestRPT(dir string) string {
|
||||
pattern := filepath.Join(dir, "arma3server_x64_*.rpt")
|
||||
matches, err := filepath.Glob(pattern)
|
||||
if err != nil || len(matches) == 0 {
|
||||
return ""
|
||||
}
|
||||
sort.Slice(matches, func(i, j int) bool {
|
||||
fi, _ := os.Stat(matches[i])
|
||||
fj, _ := os.Stat(matches[j])
|
||||
return fi.ModTime().After(fj.ModTime())
|
||||
})
|
||||
return matches[0]
|
||||
}
|
||||
|
||||
func (h *Handler) GetLog(c *gin.Context) {
|
||||
filename := filepath.Base(c.Param("file"))
|
||||
if filename == "" || strings.ContainsRune(c.Param("file"), os.PathSeparator) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid filename"})
|
||||
return
|
||||
}
|
||||
profilesDir := h.process.ProfilesDir()
|
||||
path := filepath.Join(profilesDir, filename)
|
||||
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
logsPath := filepath.Join(profilesDir, "logs", filename)
|
||||
if _, err2 := os.Stat(logsPath); err2 == nil {
|
||||
path = logsPath
|
||||
} else {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "file not found"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.String(http.StatusOK, string(data))
|
||||
}
|
||||
202
backend/internal/api/modlists.go
Normal file
202
backend/internal/api/modlists.go
Normal file
@@ -0,0 +1,202 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"arma3-web-server/internal/models"
|
||||
"arma3-web-server/internal/services"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type createModlistInput struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
}
|
||||
|
||||
type updateModlistInput struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Mods []models.ModEntry `json:"mods"`
|
||||
}
|
||||
|
||||
type duplicateModlistInput struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
}
|
||||
|
||||
func (h *Handler) ListModlists(c *gin.Context) {
|
||||
items, err := h.modlists.List()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, items)
|
||||
}
|
||||
|
||||
func (h *Handler) CreateModlist(c *gin.Context) {
|
||||
var input createModlistInput
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
ml, err := h.modlists.Create(input.Name)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, ml)
|
||||
}
|
||||
|
||||
func (h *Handler) GetModlist(c *gin.Context) {
|
||||
ml, err := h.modlists.Get(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, ml)
|
||||
}
|
||||
|
||||
func (h *Handler) UpdateModlist(c *gin.Context) {
|
||||
var input updateModlistInput
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
ml, err := h.modlists.Update(c.Param("id"), input.Name, input.Mods)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, ml)
|
||||
}
|
||||
|
||||
func (h *Handler) DeleteModlist(c *gin.Context) {
|
||||
if err := h.modlists.Delete(c.Param("id")); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusNoContent, nil)
|
||||
}
|
||||
|
||||
func (h *Handler) DuplicateModlist(c *gin.Context) {
|
||||
var input duplicateModlistInput
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
ml, err := h.modlists.Duplicate(c.Param("id"), input.Name)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, ml)
|
||||
}
|
||||
|
||||
func (h *Handler) ImportModlist(c *gin.Context) {
|
||||
file, header, err := c.Request.FormFile("file")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "file field required"})
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, mods, err := services.ParseModlistHTML(file)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "parse html: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
listName := services.FileNameToModlistName(header.Filename)
|
||||
|
||||
ml, err := h.modlists.Create(listName)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
ml, err = h.modlists.Update(ml.ID, ml.Name, mods)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, ml)
|
||||
}
|
||||
|
||||
type modStatus struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Downloaded bool `json:"downloaded"`
|
||||
}
|
||||
|
||||
func (h *Handler) CheckModlistMods(c *gin.Context) {
|
||||
ml, err := h.modlists.Get(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
dir := h.process.ServerfileDir()
|
||||
var result []modStatus
|
||||
for _, m := range ml.Mods {
|
||||
result = append(result, modStatus{
|
||||
ID: m.ID,
|
||||
Name: m.Name,
|
||||
Enabled: m.Enabled,
|
||||
Downloaded: services.CheckWorkshopMod(dir, m.ID),
|
||||
})
|
||||
}
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
func (h *Handler) DownloadMissingMods(c *gin.Context) {
|
||||
ml, err := h.modlists.Get(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
dir := h.process.ServerfileDir()
|
||||
var missing []string
|
||||
for _, m := range ml.Mods {
|
||||
if m.ID != "" && !services.CheckWorkshopMod(dir, m.ID) {
|
||||
missing = append(missing, m.ID)
|
||||
}
|
||||
}
|
||||
|
||||
if len(missing) == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"status": "all mods present"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.steamcmd.DownloadMods(missing); err != nil {
|
||||
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"status": "downloading", "count": len(missing)})
|
||||
}
|
||||
|
||||
func (h *Handler) UpdateAllMods(c *gin.Context) {
|
||||
ml, err := h.modlists.Get(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
var ids []string
|
||||
for _, m := range ml.Mods {
|
||||
if m.ID != "" {
|
||||
ids = append(ids, m.ID)
|
||||
}
|
||||
}
|
||||
|
||||
if len(ids) == 0 {
|
||||
c.JSON(http.StatusOK, gin.H{"status": "no mods with workshop ids"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.steamcmd.DownloadMods(ids); err != nil {
|
||||
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"status": "updating", "count": len(ids)})
|
||||
}
|
||||
85
backend/internal/api/router.go
Normal file
85
backend/internal/api/router.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"arma3-web-server/internal/services"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
settings *services.SettingsManager
|
||||
configs *services.ConfigManager
|
||||
modlists *services.ModlistManager
|
||||
process *services.ProcessManager
|
||||
steamcmd *services.SteamCmdManager
|
||||
streamer *services.LogStreamer
|
||||
serverfileDir string
|
||||
modsDir string
|
||||
cfgDir string
|
||||
profilesDir string
|
||||
}
|
||||
|
||||
func New(
|
||||
settings *services.SettingsManager,
|
||||
configs *services.ConfigManager,
|
||||
modlists *services.ModlistManager,
|
||||
process *services.ProcessManager,
|
||||
steamcmd *services.SteamCmdManager,
|
||||
streamer *services.LogStreamer,
|
||||
serverfileDir, modsDir, cfgDir, profilesDir string,
|
||||
) *Handler {
|
||||
return &Handler{
|
||||
settings: settings,
|
||||
configs: configs,
|
||||
modlists: modlists,
|
||||
process: process,
|
||||
steamcmd: steamcmd,
|
||||
streamer: streamer,
|
||||
serverfileDir: serverfileDir,
|
||||
modsDir: modsDir,
|
||||
cfgDir: cfgDir,
|
||||
profilesDir: profilesDir,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) SetupRoutes(r *gin.Engine) {
|
||||
api := r.Group("/api")
|
||||
{
|
||||
api.GET("/server/settings", h.GetSettings)
|
||||
api.PUT("/server/settings", h.UpdateSettings)
|
||||
api.POST("/server/start", h.StartServer)
|
||||
api.POST("/server/stop", h.StopServer)
|
||||
api.POST("/server/restart", h.RestartServer)
|
||||
api.GET("/server/status", h.ServerStatus)
|
||||
api.GET("/server/steamcmd", h.SteamCMDSettings)
|
||||
api.POST("/server/steamcmd/update-game", h.SteamCMDUpdateGame)
|
||||
api.POST("/server/steamcmd/download-mod", h.SteamCMDDownloadMod)
|
||||
api.GET("/server/steamcmd/status", h.SteamCMDStatus)
|
||||
api.GET("/server/paths", h.ServerPaths)
|
||||
|
||||
api.GET("/server/logs", h.ListLogs)
|
||||
api.GET("/server/logs/:file", h.GetLog)
|
||||
|
||||
api.GET("/configs", h.ListConfigs)
|
||||
api.POST("/configs", h.CreateConfig)
|
||||
api.GET("/configs/:name", h.GetConfig)
|
||||
api.PUT("/configs/:name", h.UpdateConfig)
|
||||
api.DELETE("/configs/:name", h.DeleteConfig)
|
||||
api.POST("/configs/:name/duplicate", h.DuplicateConfig)
|
||||
|
||||
api.GET("/modlists", h.ListModlists)
|
||||
api.POST("/modlists", h.CreateModlist)
|
||||
api.GET("/modlists/:id", h.GetModlist)
|
||||
api.PUT("/modlists/:id", h.UpdateModlist)
|
||||
api.DELETE("/modlists/:id", h.DeleteModlist)
|
||||
api.POST("/modlists/:id/duplicate", h.DuplicateModlist)
|
||||
api.POST("/modlists/import", h.ImportModlist)
|
||||
api.GET("/modlists/:id/check", h.CheckModlistMods)
|
||||
api.POST("/modlists/:id/download-missing", h.DownloadMissingMods)
|
||||
api.POST("/modlists/:id/update-all", h.UpdateAllMods)
|
||||
}
|
||||
|
||||
r.GET("/ws/server/logs", h.StreamLogs)
|
||||
r.GET("/ws/steamcmd/logs", h.StreamSteamCMDLogs)
|
||||
r.GET("/ws/server/rpt", h.StreamRPTLogs)
|
||||
}
|
||||
173
backend/internal/api/settings.go
Normal file
173
backend/internal/api/settings.go
Normal file
@@ -0,0 +1,173 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type updateSettingsInput struct {
|
||||
IPPort *string `json:"ip_port"`
|
||||
ServerParameters *string `json:"server_parameters"`
|
||||
SteamBranch *string `json:"steam_branch"`
|
||||
SteamUser *string `json:"steam_user"`
|
||||
Platform *string `json:"platform"`
|
||||
CBASettings *string `json:"cba_settings"`
|
||||
AILevelPresets *string `json:"ai_level_presets"`
|
||||
DifficultyPresets *string `json:"difficulty_presets"`
|
||||
ActiveConfig *string `json:"active_config"`
|
||||
ActiveModlist *string `json:"active_modlist"`
|
||||
}
|
||||
|
||||
func (h *Handler) GetSettings(c *gin.Context) {
|
||||
s, err := h.settings.Load()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, s)
|
||||
}
|
||||
|
||||
func (h *Handler) UpdateSettings(c *gin.Context) {
|
||||
var input updateSettingsInput
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
s, err := h.settings.Load()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if input.IPPort != nil { s.IPPort = *input.IPPort }
|
||||
if input.ServerParameters != nil { s.ServerParameters = *input.ServerParameters }
|
||||
if input.SteamBranch != nil { s.SteamBranch = *input.SteamBranch }
|
||||
if input.SteamUser != nil { s.SteamUser = *input.SteamUser }
|
||||
if input.Platform != nil { s.Platform = *input.Platform }
|
||||
if input.CBASettings != nil { s.CBASettings = *input.CBASettings }
|
||||
if input.AILevelPresets != nil { s.AILevelPresets = *input.AILevelPresets }
|
||||
if input.DifficultyPresets != nil { s.DifficultyPresets = *input.DifficultyPresets }
|
||||
if input.ActiveConfig != nil { s.ActiveConfig = *input.ActiveConfig }
|
||||
if input.ActiveModlist != nil { s.ActiveModlist = *input.ActiveModlist }
|
||||
|
||||
if err := h.process.WriteUserconfigFiles(s); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "write userconfig: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.settings.Save(s); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, s)
|
||||
}
|
||||
|
||||
func (h *Handler) StartServer(c *gin.Context) {
|
||||
if err := h.process.Start(); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"status": "starting"})
|
||||
}
|
||||
|
||||
func (h *Handler) StopServer(c *gin.Context) {
|
||||
if err := h.process.Stop(); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"status": "stopping"})
|
||||
}
|
||||
|
||||
func (h *Handler) RestartServer(c *gin.Context) {
|
||||
if err := h.process.Restart(); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"status": "restarting"})
|
||||
}
|
||||
|
||||
func (h *Handler) ServerStatus(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"running": h.process.IsRunning(),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) SteamCMDSettings(c *gin.Context) {
|
||||
s, err := h.settings.Load()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"branch": s.SteamBranch,
|
||||
"user": s.SteamUser,
|
||||
"platform": s.Platform,
|
||||
})
|
||||
}
|
||||
|
||||
type steamcmdUpdateGameInput struct {
|
||||
Branch string `json:"branch"`
|
||||
User string `json:"user"`
|
||||
}
|
||||
|
||||
func (h *Handler) SteamCMDUpdateGame(c *gin.Context) {
|
||||
var input steamcmdUpdateGameInput
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
user := input.User
|
||||
if user == "" {
|
||||
user = "anonymous"
|
||||
}
|
||||
branch := input.Branch
|
||||
if branch == "" {
|
||||
branch = "stable"
|
||||
}
|
||||
|
||||
if err := h.steamcmd.UpdateGame(branch, user); err != nil {
|
||||
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"status": "started"})
|
||||
}
|
||||
|
||||
type steamcmdDownloadModInput struct {
|
||||
ModID string `json:"mod_id"`
|
||||
}
|
||||
|
||||
func (h *Handler) SteamCMDDownloadMod(c *gin.Context) {
|
||||
var input steamcmdDownloadModInput
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if input.ModID == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "mod_id is required"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.steamcmd.DownloadMod(input.ModID); err != nil {
|
||||
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"status": "started"})
|
||||
}
|
||||
|
||||
func (h *Handler) SteamCMDStatus(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"running": h.steamcmd.IsRunning(),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) ServerPaths(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"serverfile_dir": h.serverfileDir,
|
||||
"mods_dir": h.modsDir,
|
||||
"cfg_dir": h.cfgDir,
|
||||
"profiles_dir": h.profilesDir,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user