ic-web/server/framework.lua

138 lines
5 KiB
Lua
Raw Permalink Normal View History

-- ─────────────────────────────────────────────────────────────────────────────
-- ic-web ESX-Bridge, Rechte und Logging
--
-- Alle Framework-Zugriffe zentral. ESX wird bei Bedarf geholt, nicht beim
-- Laden: beim Start ist es je nach Reihenfolge noch nicht bereit, und ein
-- einmal fehlgeschlagener Versuch haette die Bridge dauerhaft lahmgelegt.
-- ─────────────────────────────────────────────────────────────────────────────
ICWeb = ICWeb or {}
ICWeb.FW = {}
local FW = ICWeb.FW
local ESX
local function esx()
if ESX then return ESX end
local ok, obj = pcall(function() return exports['es_extended']:getSharedObject() end)
if ok and obj then ESX = obj end
return ESX
end
local function player(src)
local api = esx()
return api and api.GetPlayerFromId(src) or nil
end
function FW.GetIdentifier(src)
local xPlayer = player(src)
return xPlayer and xPlayer.identifier or nil
end
function FW.GetName(src)
local xPlayer = player(src)
if not xPlayer then return GetPlayerName(src) or 'Unbekannt' end
if xPlayer.getName then return xPlayer.getName() end
return xPlayer.name or 'Unbekannt'
end
-- Job und Dienstgrad. Beides wird fuer die Registrierung gebraucht.
function FW.GetJob(src)
local xPlayer = player(src)
if not xPlayer or not xPlayer.job then return nil, 0 end
return xPlayer.job.name, tonumber(xPlayer.job.grade) or 0
end
-- Jobliste fuer die Adminansicht. Der Job entscheidet nicht mehr ueber Rechte,
-- er steht nur noch als Besitzervermerk an einer Domaene.
function FW.GetJobs()
local api = esx()
if not api or not api.GetJobs then return {} end
local out = {}
for name, job in pairs(api.GetJobs()) do
out[#out + 1] = { name = name, label = job.label or name }
end
table.sort(out, function(a, b) return a.label < b.label end)
return out
end
function FW.Notify(src, message)
local xPlayer = player(src)
if xPlayer and xPlayer.showNotification then
xPlayer.showNotification(message)
return
end
TriggerClientEvent('esx:showNotification', src, message)
end
-- ── Adminrechte ─────────────────────────────────────────────────────────────
function FW.IsAdmin(src)
if not src or src == 0 then return true end -- Serverkonsole
local mode = Config.Admin.mode or 'either'
local okEsx = false
local xPlayer = player(src)
if xPlayer and xPlayer.getGroup then
okEsx = Config.Admin.esxGroups[xPlayer.getGroup()] == true
end
local okAce = IsPlayerAceAllowed(src, Config.Admin.acePermission) == true
if mode == 'esx' then return okEsx end
if mode == 'ace' then return okAce end
if mode == 'both' then return okEsx and okAce end
return okEsx or okAce
end
-- ── Logging ─────────────────────────────────────────────────────────────────
-- Ausschliesslich ueber fmsdk. Fehlt es, wird verworfen statt zu crashen.
ICWeb.Log = {}
function ICWeb.Log.Write(src, action, details, level)
if GetResourceState('fmsdk') ~= 'started' then
if Config.Debug then
print(('[ic-web] fmsdk fehlt, Log verworfen: %s'):format(tostring(action)))
end
return false
end
local meta = details or {}
meta.action = (Config.Logging.actionPrefix or 'ic_web.') .. tostring(action)
meta.resource = GetCurrentResourceName()
meta.playerSource = src or nil
meta.identifier = src and FW.GetIdentifier(src) or nil
local ok = pcall(function()
exports.fmsdk:Log(Config.Logging.dataset or 'ic_web', level or 'info',
('Webhosting: %s'):format(meta.action), meta)
end)
return ok
end
-- ── Drossel ─────────────────────────────────────────────────────────────────
-- Jedes RegisterNetEvent ist frei aufrufbar.
local buckets = {}
function ICWeb.ThrottleOk(src, name, maxPerWindow, windowMs)
local now = GetGameTimer()
local key = ('%s:%s'):format(src, name)
local entry = buckets[key]
if not entry or (now - entry.start) > windowMs then
buckets[key] = { start = now, count = 1 }
return true
end
entry.count = entry.count + 1
return entry.count <= maxPerWindow
end
AddEventHandler('playerDropped', function()
local prefix = tostring(source) .. ':'
for key in pairs(buckets) do
if key:sub(1, #prefix) == prefix then buckets[key] = nil end
end
end)