fix env, add additional type support, use coroutines for endpoint exec

This commit is contained in:
Sky Johnson 2025-06-04 09:25:49 -05:00
parent ff01a1f0b1
commit 2c0067dfcf
3 changed files with 90 additions and 42 deletions

View File

@ -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

View File

@ -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

View File

@ -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)