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