B4J Question SOLVED - [ABMaterial] WebSocket timeout

Harris

Expert
Licensed User
Longtime User
b4j_ws.min.js:1 connection is closed. Trying to reconnect.

I keep getting the above from my remote server. Using Chrome browser on my Win 8.1 PC.
(This also happens on my dev laptop with local server).

The site is: http://104.168.173.164:51050/punchclock/
(demo / demo) - user and password

Menu - Configure App, any sub item - Company, Users, Employees....
When the table does not populate (Employees), you can click the pagination arrow and the grid will update but not fully (tool bar is missing in Row 1).
Pressing F5 repeatably is like rolling the dice - maybe you will get lucky.

Any Ideas?

I have implemented the re-connect websocket code as per advised:

B4X:
' class_globals...
    Type GuessMyNumberState (Number As Int)
    Private state As GuessMyNumberState

' sub...
Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
    Log("Emp Connected")
    ws = WebSocket1   
   
   Dim session As HttpSession = ws.UpgradeRequest.GetSession
   If session.HasAttribute("state") = False Then
     state.Initialize
     state.Number = Rnd(1, 101)
     session.SetAttribute("state", state) 'sets a reference to the state object.
     Log($"Creating new state. Number = ${state.Number}"$)
   Else
     state = session.GetAttribute("state")
     Log($"Reusing previous state. Number = ${state.Number}"$)
   End If
  
    If ABMShared.NeedsAuthorization Then
        Log(" Needs Autho ")
        If ws.Session.GetAttribute2("IsAuthorized", "") = "" Then
            Log(" Must Autho")
            ABMShared.NavigateToPage(ws, "../")
            Return
        End If
    End If
    ' connect our page with the websocket   
    page.SetWebSocket(ws)
    Log(" page.SetWebSocket...")

    ' Prepare the page IMPORTANT!
    page.Prepare   
   
    UserType = page.ws.Session.GetAttribute2( "UserType", "0")
    UserID = page.ws.Session.GetAttribute2("UserID", "0")
    UserRows = page.ws.Session.GetAttribute2("UserRows", "0")
   
    Dim SQL As SQL = DBM.GetSQL
    Dim users As List = DBM.SQLSelect(SQL, "SELECT UserName, UserRows FROM Users WHERE userId=" & UserID)
    If users.Size > 0 Then
        Dim user As Map = users.Get(0)
        UserName = user.GetDefault("username", "")
        UserRows = user.GetDefault("userrows",  5)
        If UserRows > 0 Then
           iRecs = UserRows
        Else
           iRecs = 5
        End If 
    Log(" users.Size > 0...")           
    End If
       
    DBM.CloseSQL(SQL)
   
    page.NavigationBar.Refresh
    Log(" page.NavigationBar.Refresh... or not...")
End Sub
 

alwaysbusy

Expert
Licensed User
Longtime User
I don't see anything wrong with it. All tables load/look ok to me. What exactly do you mean with 'I have implemented the re-connect websocket code as per advised:'? Beware that you cannot use the reconnect ws trick Erel posted some time ago. ABMaterial has this already build in and needs the b4j_ws you got in the ABMaterial package, not the default one from B4J.
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
I don't see anything wrong with it. All tables load/look ok to me. What exactly do you mean with 'I have implemented the re-connect websocket code as per advised:'? Beware that you cannot use the reconnect ws trick Erel posted some time ago. ABMaterial has this already build in and needs the b4j_ws you got in the ABMaterial package, not the default one from B4J.

This is the re-connect section.
With / or without it, I get a timeout on my end (even on my dev localhost).
I did read in the post for using this, you stated it was implemented in ABM.
I thought it still needed this section for use within ABM.

I am using all files contained in the 1.08 package and no others...

Try pressing F5 on Employee page to see if it will eventually time out for you?
It is hard to believe my connection is so slow, it times out more often than not.

Thanks


B4X:
 Dim session As HttpSession = ws.UpgradeRequest.GetSession
   If session.HasAttribute("state") = False Then
     state.Initialize
     state.Number = Rnd(1, 101)
     session.SetAttribute("state", state) 'sets a reference to the state object.
     Log($"Creating new state. Number = ${state.Number}"$)
   Else
     state = session.GetAttribute("state")
     Log($"Reusing previous state. Number = ${state.Number}"$)
   End If
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
initplugins
b4j_ws.min.js:1 RestoreNavigationBarPosition
b4j_ws.min.js:1 getactivetablerow
b4j_ws.min.js:1 getsortcolumn
b4j_ws.min.js:1 inittable
b4j_ws.min.js:1 SetProperty

Above - console display of Chrome browser when it works fine...


b4j_ws.min.js:1 connection is closed. Trying to reconnect.n.onload @ b4j_ws.min.js:1

b4j_ws.min.js:1 ShowPage
b4j_ws.min.js:1 initplugins

This is all that is shown with connection is closed...
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
DBM.InitializeMySQL("jdbc:mysql://localhost/callum?characterEncoding=utf8", "harris", "******", 100) ' s1 server

In AppStart() I use this to Init MySQL. Should it be changed from localhost to Server IP?
The server is a Ubuntu 12.04 LTS VPS.

Thanks
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
Even with network throttling enabled (latency 500ms, download 50kb/s, upload 20kb/s) I always get all the events in the logging. It takes some time of course in this case, but never a connection lost. Weird...

I must say I never tried such a construction as you use in the WebSocket_Connect. You shouldn't need it. And you also use an ABMSessionCreator like this?

B4X:
'Filter class
Sub Class_Globals
  
End Sub

Public Sub Initialize
  
End Sub

'Return True to allow the request to proceed.
Public Sub Filter(req As ServletRequest, resp As ServletResponse) As Boolean
    Log("Req params: " & req.FullRequestURI)
    req.GetSession 'a new session will be created if a session doesn't exist.
    Return True
End Sub

in ABMApplication in StartServer:

B4X:
   ...
    ' start the server
    srvr.Initialize(srvrName)
    srvr.AddFilter("/js/b4j_ws.min.js", "ABMSessionCreator", False)
    srvr.AddWebSocket("/ws/" & AppName, "ABMApplication")
...

Finally in the page class WebSocket_Connected():

B4X:
Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
    Log("Connected")
    ws = WebSocket1  
    If ABMShared.NeedsAuthorization Then
        If ws.Session.GetAttribute2("IsAuthorized", "") = "" Then
            ABMShared.NavigateToPage(ws, "../")
            Return
        End If
    End If
    ' connect our page with the websocket  
    page.SetWebSocket(ws)  
  
   ...
  
    ' Prepare the page IMPORTANT!
    page.Prepare  
  
End Sub

That should be enough.
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
Speedtest.net results:

Ping: 13ms
Download: 14.58 Mbps
Upload: 0.50 Mbps
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
Even with network throttling enabled (latency 500ms, download 50kb/s, upload 20kb/s) I always get all the events in the logging. It takes some time of course in this case, but never a connection lost. Weird...

I must say I never tried such a construction as you use in the WebSocket_Connect. You shouldn't need it. And you also use an ABMSessionCreator like this?

B4X:
'Filter class
Sub Class_Globals

End Sub

Public Sub Initialize

End Sub

'Return True to allow the request to proceed.
Public Sub Filter(req As ServletRequest, resp As ServletResponse) As Boolean
    Log("Req params: " & req.FullRequestURI)
    req.GetSession 'a new session will be created if a session doesn't exist.
    Return True
End Sub

in ABMApplication in StartServer:

B4X:
   ...
    ' start the server
    srvr.Initialize(srvrName)
    srvr.AddFilter("/js/b4j_ws.min.js", "ABMSessionCreator", False)
    srvr.AddWebSocket("/ws/" & AppName, "ABMApplication")
...

Finally in the page class WebSocket_Connected():

B4X:
Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
    Log("Connected")
    ws = WebSocket1
    If ABMShared.NeedsAuthorization Then
        If ws.Session.GetAttribute2("IsAuthorized", "") = "" Then
            ABMShared.NavigateToPage(ws, "../")
            Return
        End If
    End If
    ' connect our page with the websocket
    page.SetWebSocket(ws)

   ...

    ' Prepare the page IMPORTANT!
    page.Prepare

End Sub

That should be enough.


Yes, I have all of the above..
Stolen directly from your Feedback and other examples.
Tis weird, I need some other friends to test at different locations to see if they experience what I do.

This app is for a friend who hires people in his bee-keeping business.
He needs a punch clock app to keep (accurate) track of their time for payroll.

B4A side is done, just fleshing out the webapp.

Thanks
 
Last edited:
Upvote 0

inakigarm

Well-Known Member
Licensed User
Longtime User
Looks fine here too ...
upload_2016-5-10_22-34-57.png
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
When issues such as these arrive, one must resort to old days measures...
Format drive C and begin again...

Looks like I could use a little powder on the old cranium to reduce the glare!

Thanks
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
Well, I just ended a test session with my bud in Saskatchewan (I am in BC).
He would occasionally get the "connection is closed" issue as he cycled through the menu items (and pressed F5 to see if it would drop connection).

But, to further fan the flames, he would be sitting on Employees, pressing F5, and low and behold he would be presented with the Users page!

I was also testing on my end, refreshing the Users page... We were both logged in as demo... I changed to user - mhw.
Same thing. Whenever I changed to another page and he refreshed, he would be directed to that page I selected.
Now that is freakin weird... This server is in Dallas, TX.

Perhaps later, we can arrange a time where we log in together and change pages to see if this persists.
If it helps, I can send you this entire project for examination (like anyone has time for that).

Thanks
 
Last edited:
Upvote 0

Hilton

Active Member
Licensed User
Longtime User
I keep getting the above from my remote server. Using Chrome browser on my Win 8.1 PC.
(This also happens on my dev laptop with local server).

The site is: http://104.168.173.164:51050/punchclock/
(demo / demo) - user and password

Menu - Configure App, any sub item - Company, Users, Employees....
When the table does not populate (Employees), you can click the pagination arrow and the grid will update but not fully (tool bar is missing in Row 1).
Pressing F5 repeatably is like rolling the dice - maybe you will get lucky.

Any Ideas?

I have implemented the re-connect websocket code as per advised:

B4X:
' class_globals...
    Type GuessMyNumberState (Number As Int)
    Private state As GuessMyNumberState

' sub...
Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
    Log("Emp Connected")
    ws = WebSocket1  
  
   Dim session As HttpSession = ws.UpgradeRequest.GetSession
   If session.HasAttribute("state") = False Then
     state.Initialize
     state.Number = Rnd(1, 101)
     session.SetAttribute("state", state) 'sets a reference to the state object.
     Log($"Creating new state. Number = ${state.Number}"$)
   Else
     state = session.GetAttribute("state")
     Log($"Reusing previous state. Number = ${state.Number}"$)
   End If
 
    If ABMShared.NeedsAuthorization Then
        Log(" Needs Autho ")
        If ws.Session.GetAttribute2("IsAuthorized", "") = "" Then
            Log(" Must Autho")
            ABMShared.NavigateToPage(ws, "../")
            Return
        End If
    End If
    ' connect our page with the websocket  
    page.SetWebSocket(ws)
    Log(" page.SetWebSocket...")

    ' Prepare the page IMPORTANT!
    page.Prepare  
  
    UserType = page.ws.Session.GetAttribute2( "UserType", "0")
    UserID = page.ws.Session.GetAttribute2("UserID", "0")
    UserRows = page.ws.Session.GetAttribute2("UserRows", "0")
  
    Dim SQL As SQL = DBM.GetSQL
    Dim users As List = DBM.SQLSelect(SQL, "SELECT UserName, UserRows FROM Users WHERE userId=" & UserID)
    If users.Size > 0 Then
        Dim user As Map = users.Get(0)
        UserName = user.GetDefault("username", "")
        UserRows = user.GetDefault("userrows",  5)
        If UserRows > 0 Then
           iRecs = UserRows
        Else
           iRecs = 5
        End If
    Log(" users.Size > 0...")          
    End If
      
    DBM.CloseSQL(SQL)
  
    page.NavigationBar.Refresh
    Log(" page.NavigationBar.Refresh... or not...")
End Sub
Hi Harris,

Tried your demo and all seemed to work ok.
Tried for about 10 mins.

Bye,
Hilton.
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
At first glance, I think I see a major flaw in 'private Sub LoadCases(fromPage As Int)':

You are using a shared variable (among all sessions!) to determine the SQL you need to run:

--> Select Case ABMShared.pgActionName

This will definitely be the cause of your problem seeing users instead of employees if you are using the apps with more than one person.

If one of the logged in persons picks 'Users', ALL logged in persons will change to 'Users'.

You need to save this info in the session, not in a module.

This may even be the root to all your problems. You do multiple checks to this var in the method, so it can even change along the way (starting as 'users' and in the middle of the method becoming 'employees').
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
Thanks for looking..

Looks like I out smarted myself trying to shortcut the use of many pages buy incorporating them into one (with a Case).
I am just following what might be permissible until it breaks... Looks like I broke it.

You need to save this info in the session, not in a module.
Ok, How to? Seems like a creep back to JS to manage these things.. Hey, whatever is required.
Point me and I shall follow.

Extra: It is sometimes difficult to comprehend (the little) javascript and html we may know, and convert it to ABM to direct us on the right path (or think in these terms).
Again I state - I cannot imagine what you must go through to convert my scribble to logical (web) code. You and Erel must eat from the same cereal bowl to be able to digest the nutritional input and output your functional results. And, that in no way means, implies or otherwise would express - crap...

Also, seems from where I reside, and judging by your replies (where you reside), you get anywhere from 4 - 6 hours of sleep... On a good night.
Me too... Whatever works...

Thanks
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
Ok, How to? Seems like a creep back to JS to manage these things.. Hey, whatever is required.
Point me and I shall follow.
No JS required, it is the same as with:

page.ws.Session.SetAttribute("UserType", UserType)
UserType = page.ws.Session.GetAttribute2( "UserType", "0")

So just make a new var like "UserActionName"
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
Ok, I have a new session attribute called UserActionName.
It is made from the userID logging in &"_"& datetime.now string.
In my Chrome and IE browsers, I get unique ID's that persist for each session.

I just can't figure out how to use (apply) it...
How can I tell which user is clicking what?

Sorry for the dumb questions but my brain is not thinking clearly.

Thanks
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
Do not use an unique var, just one, e.g. UserAction

Where you used to set: 'ABMShared.pgActionName = Action', now put 'page.ws.Session.SetAttribute("UserAction", Action)'

Where you used to test for 'Select Case ABMShared.pgActionName' or 'If ABMShared.pgActionName = "Employees" Then' etc, now use:
'Select Case page.ws.Session.GetAttribute2( "UserAction", "")' and 'If page.ws.Session.GetAttribute2( "UserAction", "") = "Employees" Then'

Remember, each connected user gets its own page 'Class' (and session) and they share the modules.
 
Upvote 0
Top