B4J Question Rate Limit Worker

hatzisn

Expert
Licensed User
Longtime User
Good evening everybody,

this is the code of a worker that is supposed to create requests limits per a given period for a web app. See the code, and what I do is to set a same type variable in Main to the class instance. When though I try to check the rate limit for the IP, as seen in the picture bellow, the code breaks and the reason is that all of the variables in the class are null although they are initialized in worker initialize. What am I doing wrong and I cannot see it right now?

B4X:
Sub Class_Globals
    Private mRequests As Map
    Private tm As Timer
    Private iMaxRequests As Int = 60
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
    mRequests.Initialize
    tm.Initialize("tm", 60000)
    tm.Enabled = True
    Main.wrkLimmiter = Me
    StartMessageLoop
End Sub

Public Sub tm_Tick
    Log(mRequests)
    mRequests.Clear
End Sub

Public Sub GetWorker As wrkRateLimitter
    Return Me
End Sub

Public Sub IsRequestAboveRateLimit(sIP As String) As Boolean
    Dim su As StringUtils
    sIP = su.EncodeUrl(sIP, "UTF8")
    If mRequests.ContainsKey(sIP) Then
        mRequests.Put(sIP, mRequests.Get(sIP).As(Int) + 1)
    Else
        mRequests.Put(sIP, 1)
    End If
    Log(mRequests.Get(sIP))
    Return mRequests.Get(sIP).As(Int) > iMaxRequests
End Sub

Public Sub setMaxRequests(iMax As Int)
    iMaxRequests = iMax
End Sub

Public Sub setTimeIntervalInSeconds(iSecs As Int)
    tm.Interval = iSecs * 1000
    tm.Enabled = False
    tm.Enabled = True
End Sub


1782915625924.png
 
Last edited:

hatzisn

Expert
Licensed User
Longtime User
Some times I can be completely blind... Here is what was missing:

B4X:
' This was missing from Main.AppStart
srvr.AddBackgroundWorker("wrkRateLimitter")
 
Upvote 0

hatzisn

Expert
Licensed User
Longtime User
This is the final corrected code which is thread-safe for the rate worker.

B4X:
#Event: ContinueAfterCheckingRatetLimit(bRequestExceedsLimit As Boolean)

Sub Class_Globals
    Private mRequests As Map
    Private tm As Timer
    Private iMaxRequests As Int = 60
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
    mRequests.Initialize
    tm.Initialize("tm", 60000)
    tm.Enabled = True
    Main.wrkLimmiter = Me
    StartMessageLoop
End Sub

Public Sub tm_Tick
   ClearRequests
End Sub

Sub ClearRequests
    If Main.bLogShow Then Log(mRequests)
    mRequests.Clear
End Sub

Public Sub GetWorker As wrkRateLimitter
    Return Me
End Sub

Public Sub IsRequestAboveRateLimit(parObj As Object, sSend() As String)
    Dim su As StringUtils
 
    Dim sIP As String
    sIP = sSend(0)
    sIP = su.EncodeUrl(sIP, "UTF8")
    Dim sEv As String
    sEv = sSend(1)
 
    If mRequests.ContainsKey(sIP) Then
        mRequests.Put(sIP, mRequests.Get(sIP).As(Int) + 1)
    Else
        mRequests.Put(sIP, 1)
    End If
    Log(mRequests.Get(sIP))
 
    If SubExists(parObj, sEv & "_ContinueAfterCheckingRatetLimit") Then
        CallSubDelayed2(parObj, sEv & "_ContinueAfterCheckingRatetLimit", mRequests.Get(sIP).As(Int) > iMaxRequests)
    End If
 
End Sub

Public Sub setMaxRequests(iMax As Int)
    iMaxRequests = iMax
End Sub

Public Sub setTimeIntervalInSeconds(iSecs As Int)
    tm.Interval = iSecs * 1000
    tm.Enabled = False
    tm.Enabled = True
End Sub


It is called like this:

B4X:
CallSubDelayed3(Main.wrkLimmiter, "IsRequestAboveRateLimit", Me, Array As String(sIP, "wrkLimit"))
    StartMessageLoop

And callback is:

B4X:
Private Sub wrkLimit_ContinueAfterCheckingRatetLimit(bRequestExceedsLimit As Boolean)
    StopMessageLoop
    If bRequestExceedsLimit Then
        respmem.Status = 430
        Dim result As Map = CreateMap("success":False, "error":"e001", "message":"You have exceeded your quota for this time period.")
        WriteJson(respmem, result)
        Return
    End If
    '
    ' Do something
    '
    '
End Sub
 
Last edited:
Upvote 0
Top