Files
GoSally/core/sv1/handle_com.go
alex 96fb13e3c7 Refactor and restructure core components
- Removed obsolete files: `hanle_multi.go`, `logger.go`, `handle_com.go`, `handle_list.go`, `server.go`, and `utils.go` from the `general_server` and `sv1` packages.
- Introduced new implementations for the `GeneralServer` and `HandlerV1` in the `core` package, enhancing the overall architecture.
- Updated the `go.mod` and `go.sum` files to include new dependencies.
- Added a new configuration structure in `config.yaml` and `config.go` for better management of application settings.
- Implemented a Lua command handling mechanism in `handle_com.go` and `handle_list.go` for improved command execution.
- Enhanced logging capabilities with a new logger setup in `logger.go`.
- Added a new Lua script `http.lua` for handling HTTP requests.
2025-06-26 16:50:35 +03:00

175 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package sv1
import (
"encoding/json"
"log/slog"
"net/http"
"os"
"path/filepath"
lua "github.com/aarzilli/golua/lua"
"github.com/go-chi/chi/v5"
)
func (h *HandlerV1) _handle() {
uuid16 := h.newUUID()
log := h.log.With(
slog.Group("request",
slog.String("version", h.GetVersion()),
slog.String("url", h.r.URL.String()),
slog.String("method", h.r.Method),
),
slog.Group("connection",
slog.String("connection-uuid", uuid16),
slog.String("remote", h.r.RemoteAddr),
),
)
log.Info("Received request")
cmd := chi.URLParam(h.r, "cmd")
var scriptPath string
if !h.allowedCmd.MatchString(string([]rune(cmd)[0])) {
log.Error("HTTP request error",
slog.String("error", "invalid command"),
slog.String("cmd", cmd),
slog.Int("status", http.StatusBadRequest))
h.writeJSONError(http.StatusBadRequest, "invalid command")
return
}
if !h.listAllowedCmd.MatchString(cmd) {
log.Error("HTTP request error",
slog.String("error", "invalid command"),
slog.String("cmd", cmd),
slog.Int("status", http.StatusBadRequest))
h.writeJSONError(http.StatusBadRequest, "invalid command")
return
}
if scriptPath = h.comMatch(chi.URLParam(h.r, "ver"), cmd); scriptPath == "" {
log.Error("HTTP request error",
slog.String("error", "command not found"),
slog.String("cmd", cmd),
slog.Int("status", http.StatusNotFound))
h.writeJSONError(http.StatusNotFound, "command not found")
return
}
scriptPath = filepath.Join(h.cfg.ComDir, scriptPath)
if _, err := os.Stat(scriptPath); err != nil {
log.Error("HTTP request error",
slog.String("error", "command not found"),
slog.String("cmd", cmd),
slog.Int("status", http.StatusNotFound))
h.writeJSONError(http.StatusNotFound, "command not found")
return
}
L := lua.NewState()
defer L.Close()
L.OpenLibs()
// Создаем таблицу Params
L.NewTable()
paramsTableIndex := L.GetTop() // Индекс таблицы в стеке
// Заполняем таблицу из query параметров
qt := h.r.URL.Query()
for k, v := range qt {
if len(v) > 0 {
L.PushString(v[0]) // Значение
L.SetField(paramsTableIndex, k) // paramsTable[k] = v[0]
}
}
// Помещаем Params в глобальные переменные
L.SetGlobal("Params")
// Создаем пустую таблицу Result
L.NewTable()
L.SetGlobal("Result")
// Загружаем и выполняем скрипт подготовки окружения, если есть
prepareLuaEnv := filepath.Join(h.cfg.ComDir, "_prepare.lua")
if _, err := os.Stat(prepareLuaEnv); err == nil {
if err := L.DoFile(prepareLuaEnv); err != nil {
log.Error("Failed to prepare lua environment",
slog.String("error", err.Error()))
h.writeJSONError(http.StatusInternalServerError, "lua error: "+err.Error())
return
}
} else {
log.Error("No environment preparation script found, skipping preparation",
slog.String("error", err.Error()))
}
// Выполняем основной Lua скрипт
if err := L.DoFile(scriptPath); err != nil {
log.Error("Failed to execute lua script",
slog.Group("lua-status",
slog.String("error", err.Error()),
slog.String("lua-version", lua.LUA_VERSION)))
h.writeJSONError(http.StatusInternalServerError, "lua error: "+err.Error())
return
}
// Получаем глобальную переменную Result (таблица)
L.GetGlobal("Result")
if L.IsTable(-1) {
out := make(map[string]interface{})
L.PushNil() // Первый ключ
for {
if L.Next(-2) == 0 {
break
}
// На стеке: -1 = value, -2 = key
key := L.ToString(-2)
var val interface{}
switch L.Type(-1) {
case lua.LUA_TSTRING:
val = L.ToString(-1)
case lua.LUA_TNUMBER:
val = L.ToNumber(-1)
case lua.LUA_TBOOLEAN:
val = L.ToBoolean(-1)
default:
// fallback
val = L.ToString(-1)
}
out[key] = val
L.Pop(1) // Удаляем value, key остаётся для следующего L.Next
}
L.Pop(1) // Удаляем таблицу Result со стека
h.w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(h.w).Encode(out); err != nil {
log.Error("Failed to encode JSON response",
slog.String("error", err.Error()))
}
switch out["status"] {
case "error":
log.Info("Command executed with error",
slog.String("cmd", cmd),
slog.Any("result", out))
case "ok":
log.Info("Command executed successfully",
slog.String("cmd", cmd), slog.Any("result", out))
default:
log.Info("Command executed and returned an unknown status",
slog.String("cmd", cmd),
slog.Any("result", out))
}
} else {
L.Pop(1) // убираем не таблицу из стека
log.Error("Lua global 'Result' is not a table")
h.writeJSONError(http.StatusInternalServerError, "'Result' is not a table")
return
}
log.Info("Session completed",
slog.Group("lua-status",
slog.String("lua-version", lua.LUA_VERSION)))
}