fix env, add additional type support, use coroutines for endpoint exec
This commit is contained in:
parent
ff01a1f0b1
commit
2c0067dfcf
@ -1,5 +1,4 @@
|
||||
-- Environment variable module for Moonshark
|
||||
-- Provides access to persistent environment variables stored in .env file
|
||||
-- env.lua
|
||||
|
||||
-- Get an environment variable with a default value
|
||||
function env_get(key, default_value)
|
||||
@ -8,8 +7,8 @@ function env_get(key, default_value)
|
||||
end
|
||||
|
||||
-- Check context for environment variables
|
||||
if __ctx and __ctx._env and __ctx._env[key] ~= nil then
|
||||
return __ctx._env[key]
|
||||
if __ctx and __ctx.env and __ctx.env[key] ~= nil then
|
||||
return __ctx.env[key]
|
||||
end
|
||||
|
||||
return default_value
|
||||
@ -23,8 +22,8 @@ function env_set(key, value)
|
||||
|
||||
-- Update context immediately for future reads
|
||||
if __ctx then
|
||||
__ctx._env = __ctx._env or {}
|
||||
__ctx._env[key] = value
|
||||
__ctx.env = __ctx.env or {}
|
||||
__ctx.env[key] = value
|
||||
end
|
||||
|
||||
-- Persist to Go backend
|
||||
@ -34,9 +33,9 @@ end
|
||||
-- Get all environment variables as a table
|
||||
function env_get_all()
|
||||
-- Return context table directly if available
|
||||
if __ctx and __ctx._env then
|
||||
if __ctx and __ctx.env then
|
||||
local copy = {}
|
||||
for k, v in pairs(__ctx._env) do
|
||||
for k, v in pairs(__ctx.env) do
|
||||
copy[k] = v
|
||||
end
|
||||
return copy
|
||||
@ -53,8 +52,8 @@ function env_exists(key)
|
||||
end
|
||||
|
||||
-- Check context first
|
||||
if __ctx and __ctx._env then
|
||||
return __ctx._env[key] ~= nil
|
||||
if __ctx and __ctx.env then
|
||||
return __ctx.env[key] ~= nil
|
||||
end
|
||||
|
||||
return false
|
||||
@ -67,24 +66,24 @@ function env_set_many(vars)
|
||||
end
|
||||
|
||||
if __ctx then
|
||||
__ctx._env = __ctx._env or {}
|
||||
__ctx.env = __ctx.env or {}
|
||||
end
|
||||
|
||||
local success = true
|
||||
for key, value in pairs(vars) do
|
||||
if type(key) == "string" and type(value) == "string" then
|
||||
if type(key) == "string" then
|
||||
-- Update context
|
||||
if __ctx and __ctx._env then
|
||||
__ctx._env[key] = value
|
||||
if __ctx and __ctx.env then
|
||||
__ctx.env[key] = value
|
||||
end
|
||||
-- Persist to Go
|
||||
if not __env_set(key, value) then
|
||||
success = false
|
||||
end
|
||||
else
|
||||
error("env_set_many: all keys and values must be strings")
|
||||
error("env_set_many: all keys must be strings")
|
||||
end
|
||||
end
|
||||
|
||||
return success
|
||||
end
|
||||
end
|
||||
|
@ -1,31 +1,38 @@
|
||||
-- Simplified sandbox.lua - Global function approach
|
||||
-- sandbox.lua
|
||||
|
||||
function __execute(script_func, ctx, response)
|
||||
-- Store context and response globally for function access
|
||||
__ctx = ctx
|
||||
__response = response
|
||||
_G.ctx = ctx
|
||||
|
||||
-- Execute script in global environment
|
||||
local ok, result = pcall(script_func)
|
||||
|
||||
|
||||
-- Create a coroutine for script execution to handle early exits
|
||||
local co = coroutine.create(function()
|
||||
return script_func()
|
||||
end)
|
||||
|
||||
local ok, result = coroutine.resume(co)
|
||||
|
||||
-- Clean up
|
||||
__ctx = nil
|
||||
__response = nil
|
||||
|
||||
|
||||
if not ok then
|
||||
if result == "__EXIT__" then
|
||||
return {nil, response}
|
||||
end
|
||||
-- Real error during script execution
|
||||
error(result, 0)
|
||||
end
|
||||
|
||||
|
||||
-- Check if exit was requested
|
||||
if result == "__EXIT__" then
|
||||
return {nil, response}
|
||||
end
|
||||
|
||||
return {result, response}
|
||||
end
|
||||
|
||||
-- Exit sentinel
|
||||
-- Exit sentinel using coroutine yield instead of error
|
||||
function exit()
|
||||
error("__EXIT__")
|
||||
coroutine.yield("__EXIT__")
|
||||
end
|
||||
|
||||
-- ======================================================================
|
||||
@ -55,7 +62,7 @@ function http_redirect(url, status)
|
||||
__response.status = status or 302
|
||||
__response.headers = __response.headers or {}
|
||||
__response.headers["Location"] = url
|
||||
error("__EXIT__")
|
||||
coroutine.yield("__EXIT__")
|
||||
end
|
||||
|
||||
-- ======================================================================
|
||||
@ -158,15 +165,15 @@ function csrf_validate()
|
||||
local token = __ctx.session and __ctx.session.data and __ctx.session.data["_csrf_token"]
|
||||
if not token then
|
||||
__response.status = 403
|
||||
error("__EXIT__")
|
||||
coroutine.yield("__EXIT__")
|
||||
end
|
||||
|
||||
local request_token = (__ctx._request_form and __ctx._request_form._csrf_token) or
|
||||
|
||||
local request_token = (__ctx._request_form and __ctx._request_form._csrf_token) or
|
||||
(__ctx._request_headers and (__ctx._request_headers["x-csrf-token"] or __ctx._request_headers["csrf-token"]))
|
||||
|
||||
|
||||
if not request_token or request_token ~= token then
|
||||
__response.status = 403
|
||||
error("__EXIT__")
|
||||
coroutine.yield("__EXIT__")
|
||||
end
|
||||
return true
|
||||
end
|
||||
@ -420,4 +427,4 @@ function password_verify(plain_password, hash_string)
|
||||
end
|
||||
|
||||
return __password_verify(plain_password, hash_string)
|
||||
end
|
||||
end
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@ -65,6 +66,29 @@ func GetGlobalEnvManager() *EnvManager {
|
||||
return globalEnvManager
|
||||
}
|
||||
|
||||
// parseValue attempts to parse a string value into the appropriate type
|
||||
func parseValue(value string) any {
|
||||
// Try boolean first
|
||||
if value == "true" {
|
||||
return true
|
||||
}
|
||||
if value == "false" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Try number
|
||||
if num, err := strconv.ParseFloat(value, 64); err == nil {
|
||||
// Check if it's actually an integer
|
||||
if num == float64(int64(num)) {
|
||||
return int64(num)
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
// Default to string
|
||||
return value
|
||||
}
|
||||
|
||||
// load reads the .env file and populates the vars map
|
||||
func (e *EnvManager) load() error {
|
||||
file, err := os.Open(e.envPath)
|
||||
@ -110,7 +134,7 @@ func (e *EnvManager) load() error {
|
||||
}
|
||||
}
|
||||
|
||||
e.vars[key] = value
|
||||
e.vars[key] = parseValue(value)
|
||||
}
|
||||
|
||||
return scanner.Err()
|
||||
@ -139,8 +163,7 @@ func (e *EnvManager) Save() error {
|
||||
sort.Strings(keys)
|
||||
|
||||
// Write header comment
|
||||
fmt.Fprintln(file, "# Environment variables for Moonshark")
|
||||
fmt.Fprintln(file, "# Generated automatically - you can edit this file")
|
||||
fmt.Fprintln(file, "# env variables - generated automatically - you can edit this file")
|
||||
fmt.Fprintln(file)
|
||||
|
||||
// Write each variable
|
||||
@ -152,6 +175,12 @@ func (e *EnvManager) Save() error {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
strValue = v
|
||||
case bool:
|
||||
strValue = strconv.FormatBool(v)
|
||||
case int64:
|
||||
strValue = strconv.FormatInt(v, 10)
|
||||
case float64:
|
||||
strValue = strconv.FormatFloat(v, 'g', -1, 64)
|
||||
case nil:
|
||||
continue // Skip nil values
|
||||
default:
|
||||
@ -255,10 +284,23 @@ func envSet(state *luajit.State) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
value, err := state.SafeToString(2)
|
||||
if err != nil {
|
||||
state.PushBoolean(false)
|
||||
return 1
|
||||
// Handle different value types from Lua
|
||||
var value any
|
||||
switch state.GetType(2) {
|
||||
case luajit.TypeBoolean:
|
||||
value = state.ToBoolean(2)
|
||||
case luajit.TypeNumber:
|
||||
value = state.ToNumber(2)
|
||||
case luajit.TypeString:
|
||||
value = state.ToString(2)
|
||||
default:
|
||||
// Try to convert to string as fallback
|
||||
if str, err := state.SafeToString(2); err == nil {
|
||||
value = str
|
||||
} else {
|
||||
state.PushBoolean(false)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
globalEnvManager.Set(key, value)
|
||||
|
Loading…
x
Reference in New Issue
Block a user