FastMovieAI 二开基线 v1.0 (完整源码)
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
|
||||
local _M = {
|
||||
root_path = nil
|
||||
}
|
||||
|
||||
|
||||
local function get_script_dir()
|
||||
local lfs_ok, lfs = pcall(require, "lfs")
|
||||
|
||||
local source
|
||||
if debug and debug.getinfo then
|
||||
-- OpenResty 或标准 Lua 都适用
|
||||
source = debug.getinfo(2, "S").source:sub(2)
|
||||
elseif arg and arg[0] then
|
||||
source = arg[0]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
-- 如果是相对路径,转换为绝对路径
|
||||
if not source:match("^/") then
|
||||
if lfs_ok then
|
||||
source = lfs.currentdir() .. "/" .. source
|
||||
else
|
||||
-- 没有 lfs,使用 io.popen("pwd") 获取当前目录
|
||||
local handle = io.popen("pwd")
|
||||
local cwd = handle:read("*l")
|
||||
handle:close()
|
||||
source = cwd .. "/" .. source
|
||||
end
|
||||
end
|
||||
|
||||
-- 提取目录
|
||||
local dir = source:match("(.*/)")
|
||||
-- 降末尾的/lua/module/去掉
|
||||
return dir:sub(1,-13)
|
||||
end
|
||||
|
||||
_M.root_path = get_script_dir()
|
||||
print(_M.root_path)
|
||||
return _M
|
||||
@@ -0,0 +1,122 @@
|
||||
--[[
|
||||
load_env.lua
|
||||
功能:
|
||||
自动读取 .env 文件(优先当前目录,其次模块上一级目录),解析为键值表。
|
||||
提供安全的 env.get(key, default, type) 方法:
|
||||
- 不存在 .env 文件或 key 时返回 default
|
||||
- 支持类型转换(string / number / boolean)
|
||||
使用示例:
|
||||
local env = require("load_env")
|
||||
local port = env.get("SERVER_PORT", 8080, "number")
|
||||
local debug = env.get("DEBUG", false, "boolean")
|
||||
]]
|
||||
local config = require "config"
|
||||
local M = {}
|
||||
local env_cache = nil
|
||||
|
||||
------------------------------------------------------------
|
||||
-- 工具函数
|
||||
------------------------------------------------------------
|
||||
|
||||
-- 读取文件内容
|
||||
local function read_file(path)
|
||||
local file = io.open(path, "r")
|
||||
if not file then return nil end
|
||||
local content = file:read("*a")
|
||||
file:close()
|
||||
-- 去掉 UTF-8 BOM
|
||||
if content:sub(1,3) == "\239\187\191" then
|
||||
content = content:sub(4)
|
||||
end
|
||||
return content
|
||||
end
|
||||
|
||||
-- 解析 .env 文件为表
|
||||
local function parse_env(content)
|
||||
local env = {}
|
||||
if not content then return env end
|
||||
for line in content:gmatch("[^\r\n]+") do
|
||||
if not line:match("^%s*#") and line:match("%S") then
|
||||
local key, value = line:match("^%s*([%w_]+)%s*=%s*(.-)%s*$")
|
||||
if key then
|
||||
value = value:gsub("^['\"](.-)['\"]$", "%1")
|
||||
env[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
return env
|
||||
end
|
||||
|
||||
-- 自动搜索 .env 文件路径
|
||||
local function find_env()
|
||||
local dirs = {
|
||||
config.root_path .. "/lua/", -- Lua目录
|
||||
config.root_path .. "/" -- 项目跟目录
|
||||
}
|
||||
for _, dir in ipairs(dirs) do
|
||||
local path = dir .. ".env"
|
||||
local f = io.open(path, "r")
|
||||
if f then f:close() return path end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
-- 主逻辑
|
||||
------------------------------------------------------------
|
||||
|
||||
local function load_env()
|
||||
if env_cache then return env_cache end
|
||||
local env_path = find_env()
|
||||
if not env_path then
|
||||
print("未找到 .env 文件,返回空表")
|
||||
env_cache = {}
|
||||
return env_cache
|
||||
end
|
||||
print("加载 .env 文件路径: " .. env_path)
|
||||
local content = read_file(env_path)
|
||||
env_cache = parse_env(content)
|
||||
return env_cache
|
||||
end
|
||||
|
||||
-- 类型转换
|
||||
local function convert_type(value, expect_type)
|
||||
if expect_type == "number" then
|
||||
return tonumber(value)
|
||||
elseif expect_type == "boolean" then
|
||||
local v = tostring(value):lower()
|
||||
return (v == "true" or v == "1" or v == "yes" or v == "on")
|
||||
else
|
||||
return tostring(value)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------
|
||||
-- 导出接口
|
||||
------------------------------------------------------------
|
||||
|
||||
--- 获取单个键值
|
||||
-- @param key string 键名
|
||||
-- @param default any 默认值
|
||||
-- @param expect_type string 期望类型: "string" | "number" | "boolean"
|
||||
function M.get(key, default, expect_type)
|
||||
expect_type = expect_type or "string"
|
||||
local env = load_env()
|
||||
local val = env[key]
|
||||
if val == nil or val == "" then
|
||||
return default
|
||||
end
|
||||
local converted = convert_type(val, expect_type)
|
||||
if converted == nil then
|
||||
return default
|
||||
end
|
||||
return converted
|
||||
end
|
||||
|
||||
-- 获取完整表
|
||||
function M.all()
|
||||
return load_env()
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,121 @@
|
||||
local function get_script_dir()
|
||||
local lfs_ok, lfs = pcall(require, "lfs")
|
||||
|
||||
local source
|
||||
if debug and debug.getinfo then
|
||||
-- OpenResty 或标准 Lua 都适用
|
||||
source = debug.getinfo(2, "S").source:sub(2)
|
||||
elseif arg and arg[0] then
|
||||
source = arg[0]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
-- 如果是相对路径,转换为绝对路径
|
||||
if not source:match("^/") then
|
||||
if lfs_ok then
|
||||
source = lfs.currentdir() .. "/" .. source
|
||||
else
|
||||
-- 没有 lfs,使用 io.popen("pwd") 获取当前目录
|
||||
local handle = io.popen("pwd")
|
||||
local cwd = handle:read("*l")
|
||||
handle:close()
|
||||
source = cwd .. "/" .. source
|
||||
end
|
||||
end
|
||||
|
||||
-- 提取目录
|
||||
local dir = source:match("(.*/)")
|
||||
return dir
|
||||
end
|
||||
|
||||
package.path = package.path .. ";"..get_script_dir().."module/?.lua;"
|
||||
-- 如过不是以/app/开头的请求,不进行QPS控制
|
||||
local request_uri = ngx.var.request_uri
|
||||
if not string.match(request_uri, "^/app/") then
|
||||
return
|
||||
end
|
||||
|
||||
-- 获取请求方法
|
||||
local method = ngx.req.get_method()
|
||||
method=tostring(method)
|
||||
|
||||
-- 获取请求路径
|
||||
local path = string.match(request_uri, "([^?]*)")
|
||||
path=tostring(path)
|
||||
|
||||
local env = require("load_env")
|
||||
-- 连接Redis
|
||||
local redis = require "resty.redis"
|
||||
local red = redis:new()
|
||||
red:set_timeout(1000) -- 1 秒超时
|
||||
|
||||
local ok, err = red:connect(env.get("REDIS_HOST","127.0.0.1"), env.get("REDIS_PORT",6379,"number"))
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR,"Connection to Redis failed: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
local database = env.get("REDIS_DATABASE",2,"number")
|
||||
-- 选择数据库
|
||||
local ok,err = red:select(database)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR,"Failed to select Redis database ",database,": ", err)
|
||||
return
|
||||
end
|
||||
|
||||
-- 获取请求限制
|
||||
local limit_key="QPS:"..method..":"..path
|
||||
local limit, err = red:get(limit_key)
|
||||
limit = tonumber(limit)
|
||||
|
||||
-- 如果没有设置限制,则不进行QPS控制
|
||||
if not limit then
|
||||
return
|
||||
end
|
||||
|
||||
-- 获取请求头中的Authorization
|
||||
local authorization=ngx.var.http_authorization
|
||||
if not authorization then
|
||||
ngx.log(ngx.ERR,"The request header does not include Authorization: ",authorization)
|
||||
return ngx.exit(401)
|
||||
end
|
||||
|
||||
-- 拼接用户key
|
||||
authorization=tostring(authorization)
|
||||
local user_key = limit_key..":"..authorization
|
||||
|
||||
-- 获取用户请求次数
|
||||
local requests, err = red:get(user_key)
|
||||
requests = tonumber(requests)
|
||||
|
||||
if not requests then
|
||||
requests = 0
|
||||
end
|
||||
|
||||
-- 如果请求次数超过限制,则返回503
|
||||
if requests > limit then
|
||||
ngx.log(ngx.ERR,limit,"qps/s, Authorization: ",authorization)
|
||||
return ngx.exit(429)
|
||||
end
|
||||
|
||||
|
||||
-- 原子增加请求次数
|
||||
local ok, err = red:incr(user_key)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR,"Redis increment operation failed: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
local ok, err = red:expire(user_key, 1)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR,"Failed to set expiration for Redis key: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
-- 释放连接(连接池实现)
|
||||
local ok, err = red:set_keepalive(10000, 100)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR,"Failed to set keepalive: ", err)
|
||||
return
|
||||
end
|
||||
@@ -0,0 +1,38 @@
|
||||
local function get_script_dir()
|
||||
local lfs_ok, lfs = pcall(require, "lfs")
|
||||
|
||||
local source
|
||||
if debug and debug.getinfo then
|
||||
-- OpenResty 或标准 Lua 都适用
|
||||
source = debug.getinfo(2, "S").source:sub(2)
|
||||
elseif arg and arg[0] then
|
||||
source = arg[0]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
-- 如果是相对路径,转换为绝对路径
|
||||
if not source:match("^/") then
|
||||
if lfs_ok then
|
||||
source = lfs.currentdir() .. "/" .. source
|
||||
else
|
||||
-- 没有 lfs,使用 io.popen("pwd") 获取当前目录
|
||||
local handle = io.popen("pwd")
|
||||
local cwd = handle:read("*l")
|
||||
handle:close()
|
||||
source = cwd .. "/" .. source
|
||||
end
|
||||
end
|
||||
|
||||
-- 提取目录
|
||||
local dir = source:match("(.*/)")
|
||||
return dir
|
||||
end
|
||||
|
||||
package.path = package.path .. ";"..get_script_dir().."module/?.lua;"
|
||||
local env = require("load_env")
|
||||
print("ENV文件加载成功,服务名称:"..env.get("SERVER_NAME"))
|
||||
|
||||
|
||||
-- 测试
|
||||
print(get_script_dir())
|
||||
Reference in New Issue
Block a user