Change ponger and api top use network promises, refactor and cleanup
This commit is contained in:
parent
8ad711091f
commit
21cefc125c
@ -1,8 +1,10 @@
|
||||
local minTimeout = CreateConVar( "sv_mintimeout", 900, FCVAR_REPLICATED + FCVAR_ARCHIVE + FCVAR_PROTECTED ):GetInt()
|
||||
|
||||
local timeout = GetConVar( "cl_timeout" )
|
||||
if not timeout or timeout:GetInt() < minTimeout then
|
||||
RunConsoleCommand( "cl_timeout", minTimeout )
|
||||
end
|
||||
|
||||
include( "cfc_disconnect_interface/client/cl_detached_timer.lua" )
|
||||
include( "cfc_disconnect_interface/client/cl_ponger.lua" )
|
||||
include( "cfc_disconnect_interface/client/cl_interface.lua" )
|
||||
|
@ -1,12 +1,14 @@
|
||||
crashApi = {}
|
||||
require( "cfc_promises" )
|
||||
|
||||
-- local references
|
||||
local http, concommand = http, concommand
|
||||
CFCCrashAPI = {}
|
||||
|
||||
local cfc_endpoint = "https://nanny.cfcservers.org/cfc3-ping"
|
||||
local global_endpoint = "https://www.google.com"
|
||||
local endpointDirectory = "cfc/cfc_disconnect_interface/endpoint.txt"
|
||||
|
||||
local api = crashApi
|
||||
local endpointCFC = file.Read( endpointDirectory ) or "https://nanny.cfcservers.org/cfc3-ping"
|
||||
local endpointGlobal = "https://www.google.com"
|
||||
|
||||
local api = CFCCrashAPI
|
||||
api.state = api.INACTIVE
|
||||
|
||||
api.INACTIVE = 0
|
||||
api.PINGING_API = 1
|
||||
@ -14,116 +16,36 @@ api.NO_INTERNET = 2
|
||||
api.SERVER_DOWN = 3
|
||||
api.SERVER_UP = 4
|
||||
|
||||
local DEV_MODE = false
|
||||
function api._checkCFCEndpoint()
|
||||
local success, body = await( NP.http.fetch( endpointCFC ) )
|
||||
|
||||
api.inDebug = false
|
||||
api.debugMode = api.INACTIVE
|
||||
if not success then return false end
|
||||
|
||||
if DEV_MODE then
|
||||
-- Testing
|
||||
local function testServerCrash()
|
||||
api.inDebug = true
|
||||
api.debugMode = api.SERVER_DOWN
|
||||
end
|
||||
concommand.Add( "cfc_di_testcrash", testServerCrash )
|
||||
|
||||
local function testNoInternet()
|
||||
api.inDebug = true
|
||||
api.debugMode = api.NO_INTERNET
|
||||
end
|
||||
concommand.Add( "cfc_di_testnointernet", testNoInternet )
|
||||
|
||||
local function serverRestarted()
|
||||
api.inDebug = true
|
||||
api.debugMode = api.SERVER_UP
|
||||
end
|
||||
concommand.Add( "cfc_di_testrestart", serverRestarted )
|
||||
|
||||
local function serverRecovered()
|
||||
api.inDebug = false
|
||||
end
|
||||
concommand.Add( "cfc_di_testrecover", serverRecovered )
|
||||
local data = util.JSONToTable( body )
|
||||
return tobool( data and data["server-is-up"] )
|
||||
end
|
||||
api.checkCFCEndpoint = async( api._checkCFCEndpoint )
|
||||
|
||||
|
||||
local responses = { cfc = nil, global = nil } -- Does nothing but helps with clarity
|
||||
|
||||
local state = api.INACTIVE
|
||||
|
||||
local pingCancelled = false
|
||||
|
||||
local function getState()
|
||||
return state
|
||||
function api._checkGlobalEndpoint()
|
||||
local success = await( NP.http.fetch( endpointGlobal ) )
|
||||
return success
|
||||
end
|
||||
api.checkGlobalEndpoint = async( api._checkGlobalEndpoint )
|
||||
|
||||
-- Check both websites responded, set state accordingly
|
||||
local function handleResponses()
|
||||
if pingCancelled then -- Ignore responses if ping was cancelled
|
||||
return
|
||||
end
|
||||
if responses.cfc == nil or responses.global == nil then -- Not all responses arrived yet
|
||||
return
|
||||
end
|
||||
function api._ping()
|
||||
api.state = api.PINGING_API
|
||||
|
||||
-- If in debug mode, set state to debug state
|
||||
if api.inDebug then state = api.debugMode return end
|
||||
local _, data = await( promises.all( api.checkCFCEndpoint(), api.checkGlobalEndpoint() ) )
|
||||
local cfcStatus, globalStatus = data[1][1], data[2][1]
|
||||
|
||||
if responses.cfc then
|
||||
-- Server is up
|
||||
state = api.SERVER_UP
|
||||
elseif not responses.cfc and responses.global then
|
||||
-- Server is down
|
||||
state = api.SERVER_DOWN
|
||||
if cfcStatus and globalStatus then
|
||||
api.state = api.SERVER_UP
|
||||
elseif globalStatus then
|
||||
api.state = api.SERVER_DOWN
|
||||
else
|
||||
-- Internet is down
|
||||
state = api.NO_INTERNET
|
||||
api.state = api.NO_INTERNET
|
||||
end
|
||||
|
||||
return api.state
|
||||
end
|
||||
|
||||
-- Fetch cfc and global end points
|
||||
local function triggerPing()
|
||||
pingCancelled = false
|
||||
state = api.PINGING_API
|
||||
responses = { cfc = nil, global = nil }
|
||||
|
||||
http.Fetch( cfc_endpoint,
|
||||
function( body, size, headers, code )
|
||||
local data = util.JSONToTable( body )
|
||||
-- If response is malformed, or empty, set cfc false
|
||||
if not data or data.status == nil then -- Can't use dot notation cuz api field has dashes >:(
|
||||
responses.cfc = false
|
||||
handleResponses()
|
||||
else
|
||||
responses.cfc = data.status == "server-is-up"
|
||||
handleResponses()
|
||||
end
|
||||
end,
|
||||
function( err )
|
||||
-- If cfc doesn't respond, set cfc false, might want to do something special here, as this means cfcservers had a heart attack
|
||||
responses.cfc = false
|
||||
handleResponses()
|
||||
end
|
||||
)
|
||||
|
||||
http.Fetch( global_endpoint,
|
||||
function( body, size, headers, code )
|
||||
responses.global = true
|
||||
handleResponses()
|
||||
end,
|
||||
function( err )
|
||||
responses.global = false
|
||||
handleResponses()
|
||||
end
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
local function cancelPing()
|
||||
state = api.INACTIVE
|
||||
pingCancelled = true
|
||||
end
|
||||
|
||||
|
||||
api.getState = getState
|
||||
api.triggerPing = triggerPing
|
||||
api.cancelPing = cancelPing
|
||||
api.ping = async( api._ping )
|
||||
|
@ -1,7 +1,5 @@
|
||||
include( "cfc_disconnect_interface/client/cl_api.lua" )
|
||||
|
||||
local vgui, hook = vgui, hook
|
||||
|
||||
surface.CreateFont( "CFC_Normal",
|
||||
{
|
||||
font = "arial",
|
||||
@ -47,9 +45,9 @@ local timeDown = 0
|
||||
local apiState
|
||||
local previouslyShown = false
|
||||
local disconnectMessages = {}
|
||||
disconnectMessages[crashApi.SERVER_DOWN] = "Are you sure? Hang in there, the server will restart soon..."
|
||||
disconnectMessages[crashApi.SERVER_UP] = "Are you sure? The server is already back up and ready!"
|
||||
disconnectMessages[crashApi.NO_INTERNET] = "Are you sure? If your internet comes back, you can easily rejoin from this page."
|
||||
disconnectMessages[CFCCrashAPI.SERVER_DOWN] = "Are you sure? Hang in there, the server will restart soon..."
|
||||
disconnectMessages[CFCCrashAPI.SERVER_UP] = "Are you sure? The server is already back up and ready!"
|
||||
disconnectMessages[CFCCrashAPI.NO_INTERNET] = "Are you sure? If your internet comes back, you can easily rejoin from this page."
|
||||
|
||||
-- Helper function
|
||||
local function getFrom( i, ... )
|
||||
@ -275,7 +273,7 @@ local function addButtonsBar( frame )
|
||||
end
|
||||
|
||||
if not self.disconMode then return end
|
||||
if apiState ~= crashApi.SERVER_UP then return end
|
||||
if apiState ~= CFCCrashAPI.SERVER_UP then return end
|
||||
if self.backUp then return end
|
||||
|
||||
showMessage( getDisconnectMessage() )
|
||||
@ -365,7 +363,7 @@ local function populateBodyServerDown( body )
|
||||
-- When the server comes back up, "It has been down for" => "It was down for"
|
||||
-- Then resize and move
|
||||
function curTimePreLabel:Think()
|
||||
if apiState == crashApi.SERVER_UP and not self.backUp then
|
||||
if apiState == CFCCrashAPI.SERVER_UP and not self.backUp then
|
||||
self:setTextAndAlign( "It was down for" )
|
||||
self.backUp = true
|
||||
end
|
||||
@ -376,7 +374,7 @@ local function populateBodyServerDown( body )
|
||||
-- If timeDown > averageTimeDown, make it red and show the messageLabel
|
||||
local curTimeLabel = makeLabel( body, secondsAsTime( math.floor( timeDown ) ), 70, Color( 251, 191, 83 ), 0.5, "CFC_Mono" )
|
||||
function curTimeLabel:Think()
|
||||
if apiState ~= crashApi.SERVER_UP then
|
||||
if apiState ~= CFCCrashAPI.SERVER_UP then
|
||||
self:setTextAndAlign( secondsAsTime( math.floor( timeDown ) ) )
|
||||
if timeDown > TIME_TO_RESTART then
|
||||
self:SetTextColor( Color( 255, 0, 0 ) )
|
||||
@ -403,8 +401,8 @@ local function populateBody( body )
|
||||
interfaceDerma.messageLabel:SetAlpha( 0 )
|
||||
interfaceDerma.messageLabel:Hide()
|
||||
|
||||
-- Fill top text based on crashApi state
|
||||
if apiState == crashApi.NO_INTERNET then
|
||||
-- Fill top text based on CFCCrashAPI state
|
||||
if apiState == CFCCrashAPI.NO_INTERNET then
|
||||
title = populateBodyInternetDown( body )
|
||||
else -- Server down or up via api, and down via net
|
||||
title = populateBodyServerDown( body )
|
||||
@ -468,9 +466,9 @@ local function createInterface()
|
||||
-- If server fully recovers without crashing, close menu
|
||||
-- If server reboots, enabled the reconnect button
|
||||
function frame:Think()
|
||||
if apiState == crashApi.INACTIVE then
|
||||
if apiState == CFCCrashAPI.INACTIVE then
|
||||
frame:Close() -- Server recovered without ever closing
|
||||
elseif apiState == crashApi.SERVER_UP then
|
||||
elseif apiState == CFCCrashAPI.SERVER_UP then
|
||||
if btnsPanel.reconBtn:GetDisabled() == true and not btnsPanel.reconBtn.dontEnable then
|
||||
btnsPanel.reconBtn:SetDisabled( false ) -- Server back up
|
||||
end
|
||||
@ -484,14 +482,14 @@ end
|
||||
|
||||
hook.Add( "cfc_di_crashTick", "cfc_di_interfaceUpdate", function( isCrashing, _timeDown, _apiState )
|
||||
timeDown = _timeDown or 0
|
||||
if _apiState ~= crashApi.PINGING_API then
|
||||
if _apiState ~= CFCCrashAPI.PINGING_API then
|
||||
apiState = _apiState
|
||||
end
|
||||
|
||||
|
||||
if isCrashing then
|
||||
-- Open interface if server is crashing, API has responded, interface isn't already open, and interface has not yet been opened
|
||||
if _apiState == crashApi.PINGING_API or _apiState == crashApi.SERVER_UP then return end
|
||||
if _apiState == CFCCrashAPI.PINGING_API or _apiState == CFCCrashAPI.SERVER_UP then return end
|
||||
if interfaceDerma or previouslyShown then return end
|
||||
createInterface()
|
||||
previouslyShown = true
|
||||
|
@ -1,20 +1,19 @@
|
||||
include( "cfc_disconnect_interface/client/cl_api.lua" )
|
||||
|
||||
local net, hook = net, hook
|
||||
|
||||
local GRACE_TIME = 3.5 -- How many seconds of lag should we have before showing the panel?
|
||||
local PING_MISS = 2 -- How many pings can we miss on join?
|
||||
|
||||
local API_TIMEOUT = 5 -- How often to call the api
|
||||
|
||||
local lastPong
|
||||
local lastApiCall
|
||||
|
||||
local pongerStatus = false
|
||||
local pingLoopRunning = false
|
||||
|
||||
net.Receive( "cfc_di_ping", function()
|
||||
if PING_MISS > 0 then -- Allow some pings before actually starting crash systems. ( Avoid bugs on join stutter. )
|
||||
PING_MISS = PING_MISS - 1
|
||||
else
|
||||
if crashApi.inDebug then return end
|
||||
lastPong = SysTime()
|
||||
end
|
||||
end )
|
||||
@ -27,17 +26,18 @@ end
|
||||
net.Receive( "cfc_di_shutdown", shutdown )
|
||||
hook.Add( "ShutDown", "cfc_di_shutdown", shutdown )
|
||||
|
||||
local function crashTick( timedown )
|
||||
local apiState = crashApi.getState();
|
||||
if ( apiState == crashApi.INACTIVE ) or -- No ping sent
|
||||
( SysTime() - lastApiCall > API_TIMEOUT ) then -- API_TIMEOUT has passed
|
||||
crashApi.triggerPing()
|
||||
lastApiCall = SysTime()
|
||||
local function _pingLoop()
|
||||
if pingLoopRunning then return end
|
||||
pingLoopRunning = true
|
||||
|
||||
apiState = crashApi.getState();
|
||||
while pongerStatus do
|
||||
await( CFCCrashAPI.ping() )
|
||||
await( NP.timeout( API_TIMEOUT ) )
|
||||
end
|
||||
hook.Run( "cfc_di_crashTick", true, timedown, apiState );
|
||||
|
||||
pingLoopRunning = false
|
||||
end
|
||||
pingLoop = async( _pingLoop )
|
||||
|
||||
local function checkCrashTick()
|
||||
if not lastPong then return end
|
||||
@ -45,24 +45,25 @@ local function checkCrashTick()
|
||||
|
||||
local timeout = SysTime() - lastPong
|
||||
|
||||
if timeout > GRACE_TIME then
|
||||
crashTick( timeout )
|
||||
else
|
||||
-- Server recovered while crashApi was running, cancel the request
|
||||
if crashApi.getState() ~= crashApi.INACTIVE then
|
||||
crashApi.cancelPing();
|
||||
end
|
||||
hook.Run( "cfc_di_crashTick", false );
|
||||
local inGrace = timeout > GRACE_TIME
|
||||
|
||||
if pongerStatus ~= inGrace then
|
||||
pongerStatus = inGrace
|
||||
|
||||
pingLoop()
|
||||
end
|
||||
|
||||
hook.Run( "cfc_di_crashTick", pongerStatus, timedown, CFCCrashAPI.state )
|
||||
end
|
||||
|
||||
-- Ping the server when the client is ready.
|
||||
dTimer.Create( "cfc_di_startup", 0.01, 0, function()
|
||||
local ply = LocalPlayer()
|
||||
if ply:IsValid() then
|
||||
if LocalPlayer():IsValid() then
|
||||
dTimer.Remove( "cfc_di_startup" )
|
||||
|
||||
net.Start( "cfc_di_loaded" )
|
||||
net.SendToServer()
|
||||
dTimer.Remove( "cfc_di_startup" )
|
||||
|
||||
print( "cfc_disconnect_interface loaded." )
|
||||
hook.Add( "Tick", "cfc_di_tick", checkCrashTick )
|
||||
end
|
||||
|
@ -1,7 +1,6 @@
|
||||
local PING_TIME = 1
|
||||
|
||||
local players = {}
|
||||
local table = table
|
||||
|
||||
local function ping( ply )
|
||||
net.Start( "cfc_di_ping" )
|
||||
@ -20,9 +19,7 @@ hook.Add( "PlayerDisconnected", "crashsys", function( ply )
|
||||
table.RemoveByValue( players, ply )
|
||||
end )
|
||||
|
||||
timer.Create( "cfc_di_pingTimer", PING_TIME, 0, function()
|
||||
ping()
|
||||
end )
|
||||
timer.Create( "cfc_di_pingTimer", PING_TIME, 0, ping )
|
||||
|
||||
hook.Add( "ShutDown", "cfc_di", function()
|
||||
net.Start( "cfc_di_shutdown" )
|
||||
|
Loading…
Reference in New Issue
Block a user