Files
sky_phone-sky-systems/sky_phone/source/server/custom_app_compat.lua
T
Leon.Schmidt 42ac955052 ADD - expand phone application platform
Add the Companies app, resilient call handling, custom app registry, vendor compatibility, storage policies, frontend bridge, tests, documentation, config, locale, and SQL migrations.
2026-08-11 00:22:39 +02:00

139 lines
3.9 KiB
Lua

local RESOURCE_NAME = GetCurrentResourceName()
local SNAPSHOT_COOLDOWN_MS = 2000
local SNAPSHOT_REJECTION_LOG_COOLDOWN_MS = 10000
local registered_apps = {}
local snapshot_requests = {}
local snapshot_rejection_logs = {}
local function get_calling_resource(export_name)
local owner_resource = GetInvokingResource()
if owner_resource then
return owner_resource
end
print(("[%s] %s rejected: the export must be called by another resource."):format(
RESOURCE_NAME,
export_name
))
return nil, "invalid_owner"
end
local function add_high_application(app_name, data, locales)
local owner_resource, owner_error = get_calling_resource("addApplication")
if not owner_resource then
return false, owner_error
end
local definition, definition_error = SkyPhoneCompatibility.BuildHighDefinition(
owner_resource,
app_name,
data,
locales
)
if not definition then
print(("[%s] High Phone registration rejected for %s: %s."):format(
RESOURCE_NAME,
owner_resource,
definition_error
))
return false, definition_error
end
local existing = registered_apps[app_name]
if existing and existing.owner_resource ~= owner_resource then
return false, "duplicate_app_id"
end
local revision = existing and existing.revision + 1 or 1
registered_apps[app_name] = {
definition = definition,
owner_resource = owner_resource,
revision = revision,
}
TriggerClientEvent(
"sky_phone:compat:high:client:syncApplication",
-1,
owner_resource,
definition,
revision
)
return true
end
local function build_snapshot()
local ids = {}
for app_id in pairs(registered_apps) do
ids[#ids + 1] = app_id
end
table.sort(ids)
local snapshot = {}
for index = 1, #ids do
snapshot[index] = registered_apps[ids[index]]
end
return snapshot
end
RegisterNetEvent("sky_phone:compat:high:server:requestSnapshot", function()
local player_source = source
if player_source <= 0 then
print(("[%s] Rejected High Phone snapshot request without a player source."):format(
RESOURCE_NAME
))
return
end
local now = GetGameTimer()
local last_request = snapshot_requests[player_source]
local elapsed = last_request and now - last_request or SNAPSHOT_COOLDOWN_MS
if elapsed >= 0 and elapsed < SNAPSHOT_COOLDOWN_MS then
local last_log = snapshot_rejection_logs[player_source]
local log_elapsed = last_log and now - last_log or SNAPSHOT_REJECTION_LOG_COOLDOWN_MS
if log_elapsed < 0 or log_elapsed >= SNAPSHOT_REJECTION_LOG_COOLDOWN_MS then
snapshot_rejection_logs[player_source] = now
print(("[%s] Rate-limited High Phone snapshot request from player %s."):format(
RESOURCE_NAME,
player_source
))
end
return
end
snapshot_requests[player_source] = now
TriggerClientEvent(
"sky_phone:compat:high:client:replaceSnapshot",
player_source,
build_snapshot()
)
end)
AddEventHandler("playerDropped", function()
snapshot_requests[source] = nil
snapshot_rejection_logs[source] = nil
end)
AddEventHandler("onResourceStop", function(resource_name)
if resource_name == RESOURCE_NAME then
return
end
local removed_ids = {}
for app_id, record in pairs(registered_apps) do
if record.owner_resource == resource_name then
removed_ids[#removed_ids + 1] = app_id
end
end
for index = 1, #removed_ids do
local app_id = removed_ids[index]
registered_apps[app_id] = nil
TriggerClientEvent(
"sky_phone:compat:high:client:removeApplication",
-1,
resource_name,
app_id
)
end
end)
exports("addApplication", add_high_application)