Files
acc-server-manager/local/service/config.go
2025-02-05 19:48:55 +01:00

253 lines
5.7 KiB
Go

package service
import (
"acc-server-manager/local/model"
"acc-server-manager/local/repository"
"acc-server-manager/local/utl/common"
"bytes"
"encoding/json"
"errors"
"io"
"os"
"path/filepath"
"time"
"github.com/gofiber/fiber/v2"
"github.com/qjebbs/go-jsons"
"golang.org/x/text/encoding/unicode"
"golang.org/x/text/transform"
)
type ConfigService struct {
repository *repository.ConfigRepository
serverRepository *repository.ServerRepository
}
func NewConfigService(repository *repository.ConfigRepository, serverRepository *repository.ServerRepository) *ConfigService {
return &ConfigService{
repository: repository,
serverRepository: serverRepository,
}
}
// UpdateConfig
// Updates physical config file and caches it in database.
//
// Args:
// context.Context: Application context
// Returns:
// string: Application version
func (as ConfigService) UpdateConfig(ctx *fiber.Ctx, body *map[string]interface{}) (*model.Config, error) {
serverID := ctx.Locals("serverId").(int)
configFile := ctx.Params("file")
override := ctx.QueryBool("override")
server := as.serverRepository.GetFirst(ctx.UserContext(), serverID)
if server == nil {
return nil, fiber.NewError(404, "Server not found")
}
// Read existing config
configPath := filepath.Join(server.ConfigPath, "\\server\\cfg", configFile)
oldData, err := os.ReadFile(configPath)
if err != nil {
return nil, err
}
oldDataUTF8, err := DecodeUTF16LEBOM(oldData)
if err != nil {
return nil, err
}
// Write new config
newData, err := json.Marshal(&body)
if err != nil {
return nil, err
}
if !override {
newData, err = jsons.Merge(oldDataUTF8, newData)
if err != nil {
return nil, err
}
}
newData, err = common.IndentJson(newData)
if err != nil {
return nil, err
}
newDataUTF16, err := EncodeUTF16LEBOM(newData)
if err != nil {
return nil, err
}
if err := os.WriteFile(configPath, newDataUTF16, 0644); err != nil {
return nil, err
}
// Log change
return as.repository.UpdateConfig(ctx.UserContext(), &model.Config{
ServerID: uint(serverID),
ConfigFile: configFile,
OldConfig: string(oldDataUTF8),
NewConfig: string(newData),
ChangedAt: time.Now(),
}), nil
}
// GetConfig
// Gets physical config file and caches it in database.
//
// Args:
// context.Context: Application context
// Returns:
// string: Application version
func (as ConfigService) GetConfig(ctx *fiber.Ctx) (map[string]interface{}, error) {
serverID, _ := ctx.ParamsInt("id")
configFile := ctx.Params("file")
server := as.serverRepository.GetFirst(ctx.UserContext(), serverID)
if server == nil {
return nil, fiber.NewError(404, "Server not found")
}
config, err := readFile(server.ConfigPath, configFile)
if err != nil {
return nil, err
}
decoded, err := DecodeToMap(config)
if err != nil {
return nil, err
}
return decoded, nil
}
// GetConfigs
// Gets physical config file and caches it in database.
//
// Args:
// context.Context: Application context
// Returns:
// string: Application version
func (as ConfigService) GetConfigs(ctx *fiber.Ctx) (*model.Configurations, error) {
serverID, _ := ctx.ParamsInt("id")
server := as.serverRepository.GetFirst(ctx.UserContext(), serverID)
if server == nil {
return nil, fiber.NewError(404, "Server not found")
}
configuration, err := readFile(server.ConfigPath, "configuration.json")
if err != nil {
return nil, err
}
decodedconfiguration, err := DecodeToMap(configuration)
if err != nil {
return nil, err
}
entrylist, err := readFile(server.ConfigPath, "entrylist.json")
if err != nil {
return nil, err
}
decodedentrylist, err := DecodeToMap(entrylist)
if err != nil {
return nil, err
}
event, err := readFile(server.ConfigPath, "event.json")
if err != nil {
return nil, err
}
decodedevent, err := DecodeToMap(event)
if err != nil {
return nil, err
}
eventRules, err := readFile(server.ConfigPath, "eventRules.json")
if err != nil {
return nil, err
}
decodedeventRules, err := DecodeToMap(eventRules)
if err != nil {
return nil, err
}
settings, err := readFile(server.ConfigPath, "settings.json")
if err != nil {
return nil, err
}
decodedsettings, err := DecodeToMap(settings)
if err != nil {
return nil, err
}
return &model.Configurations{
Configuration: decodedconfiguration,
Event: decodedevent,
EventRules: decodedeventRules,
Settings: decodedsettings,
Entrylist: decodedentrylist,
}, nil
}
func readFile(path string, configFile string) ([]byte, error) {
configPath := filepath.Join(path, "\\server\\cfg", configFile)
oldData, err := os.ReadFile(configPath)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return nil, err
} else if errors.Is(err, os.ErrNotExist) {
return nil, nil
}
return oldData, nil
}
func EncodeUTF16LEBOM(input []byte) ([]byte, error) {
encoder := unicode.UTF16(unicode.LittleEndian, unicode.UseBOM)
return transformBytes(encoder.NewEncoder(), input)
}
func DecodeUTF16LEBOM(input []byte) ([]byte, error) {
decoder := unicode.UTF16(unicode.LittleEndian, unicode.UseBOM)
return transformBytes(decoder.NewDecoder(), input)
}
func DecodeToMap(input []byte) (map[string]interface{}, error) {
if input == nil {
return nil, nil
}
configUTF8 := new(map[string]interface{})
decoded, err := DecodeUTF16LEBOM(input)
if err != nil {
return nil, err
}
err = json.Unmarshal(decoded, configUTF8)
if err != nil {
return nil, err
}
return *configUTF8, nil
}
func transformBytes(t transform.Transformer, input []byte) ([]byte, error) {
var buf bytes.Buffer
w := transform.NewWriter(&buf, t)
if _, err := io.Copy(w, bytes.NewReader(input)); err != nil {
return nil, err
}
if err := w.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}