WebSocket reconnect attempts stopping app.Exit() ?

156 views
Skip to first unread message

Simon Davison

unread,
May 22, 2021, 9:37:47 PM5/22/21
to DroidScript
Hi,  

I'm having a good deal of success using websockets to connect two devices of my local wifi. However, there are some extra details that are causing a few head scratches.

For now I'm not to worried about the messages they will eventually exchange as that just seems to be straightforward enough. I'm just concentrating on the connections. 

My setup.

Phone A app has a simple DS webserver setup with two functions for whenever a websocket is opened or closed. (I read up on the WebServer rocket example on the DroidStore).  The app on Phone A never initiates any websockets of its own, it just waits for incoming ones.

Phone B has a simple button which when pressed opens a new websocket on Phone A. The ip and port numbers for Phone A are hard wired for now.  This obviously assumes the webserver is already up and running on Phone A, otherwise Phone B throws an error.

Problem:-

If after creating one or more websockets using Phone B I go ahead and close or exit the webserver app on Phone A prematurely, this will obviously throw an error on Phone B and it will automatically try and reconnect all the websockets that have been made to the server.  I can catch this error and offer the choice (dialog box) to the user to exit the app with app.Exit() or even app.Exit(kill)  Unfortunately app.Exit() function doesn't seem to work because I think the automatic attempts to reconnect the websockets is perhaps preventing this? I imagined app.Exit() would close the app no matter what.  

Would there also be a way to prevent the automatic reconnection attempts from DS if the user wishes it?

I'll give the Phone A webserver code in this post and the Phone B client code in the following post.

Thanks for any help you can give,

Simon

Phone A code:---

function OnStart()
{
    app.EnableBackKey(false);
    ip = app.GetIPAddress();
if( ip == "0.0.0.0" ) { 
    app.ShowPopup( "Please Enable Wi-Fi" ); 
    app.Exit();
    }
app.PreventWifiSleep();

    lay = app.CreateLayout( "linear", "VCenter,FillXY" );

    txt = app.CreateText( "Connected clients:." + "\n\n" , 0.8, 0.3, "AutoScale,log" );
    //Create a text label and add it to layout.
var s = "No clients connected"
txt = app.CreateText( s, 0.8, 0.3, "AutoScale,MultiLine" );
txt.SetTextSize( 22 );
lay.AddChild( txt );

    
    txt.SetTextSize( 22 );
    lay.AddChild( txt );

    app.AddLayout( lay );

    serv = app.CreateWebServer( 8080 ); // I don't use 8080 in the final app 
    serv.SetFolder( app.GetAppPath() );
    serv.SetOnReceive( serv_OnReceive );
    serv.Start();

    setInterval( ShowConnections, 3000 )

 }

function ShowConnections()
{
var clients = serv.GetWebSockClients();
if( clients.length > 0 )
{
    //Make a list of clients.
    var list = "";
    for( var i=0; i<clients.length; i++ )
        list += clients[i].id + ": " + clients[i].remoteAddress + "\n";
        
    //Show client list.
    txt.SetText( list );
}
}
 


Simon Davison

unread,
May 22, 2021, 9:38:44 PM5/22/21
to DroidScript
function OnStart()
{
    ip = app.GetIPAddress();
    var exit = false;

    lay = app.CreateLayout( "linear", "VCenter,FillXY" );

    butCon = app.CreateButton("Connect", 0.5, 0.1)
    butCon.SetOnTouch(butCon_OnTouch)
    lay.AddChild(butCon)
    
    txt = app.CreateText("This device ip: " + ip)
    lay.AddChild(txt)
    
    app.AddLayout(lay)
    app.SetOnError( OnError )

}

function butCon_OnTouch()
{
        var ws = app.CreateWebSocket("sock1","111.222.333.444",8080)// This is Phone A ip and port of webserver
        ws.SetOnOpen( OnSockOpen )
        ws.SetOnClose( OnSockClose )
}

function OnSockOpen()
{
    app.ShowPopup( "Connected" );
}

function OnSockClose()
{
    app.ShowPopup( "Disconnected" );
}

function OnError() 
    ynd = app.CreateYesNoDialog("Connection was lost")
    
    //This next SetButtonText instruction works on screen but gives an error in Debug.
    //The texts are switched on the dialog box too.
    //Maps "Exit" to dialog 'Yes' button
    ynd.SetButtonText("Exit", "Continue")
        
    ynd.SetOnTouch(Ynd_OnTouch)
    ynd.Show()
}

function Ynd_OnTouch(choice)
{
    if (choice == "Yes") 
    {
        app.Exit(kill); //Doesn't work here.

Steve Garman

unread,
May 23, 2021, 3:57:08 AM5/23/21
to DroidScript
app.Exit(kill) is invalid because you don't have a global variable kill
So it's throwing another error and your error handler is being called again

Just use app.Exit()

app.Exit(true) is another possibility but you don't need it

Simon Davison

unread,
May 23, 2021, 4:38:06 AM5/23/21
to DroidScript
Hi Steve,

Thank you for replying.  I reverted back to app.Exit() and now all is well.   

It's bizarre. I could have sworn I tried app.Exit() before app.Exit(kill) but had no success. However, it seems fine now. 

Thinking that the 7 second connection retry was stopping the app.exit() working, I tried replacing the internal CreateWebSocket() function with its source pasted into my code from the post Dave gave a while ago and commented out the reconnection attempts. That seemed to work fine, but I may as well use the internal one again if my code is behaving itself again. 

Did you happen to see the other error in debug to do with the text choices being changed for the YesNoDialog? The ynd.SetButtonText() does actually work as expected and the program runs fine, but there is some kind of fail going on in the debug console.

Cheers again

Steve Garman

unread,
May 23, 2021, 6:21:48 AM5/23/21
to DroidScript
The order of SetButtonText is a historical anomaly
The YesNoDialog has always had the "Yes" button on the right
When the  SetButtonText method was added, it became apparent that for a control with "yesno" in its name,
yesno.SetButtonText("negative","afermative")
was going to make users think that "Yes" would be returned by the negative button
The yes,no sequence was chosen as the lesser of two evils

The debug warning of failure is just plain confusing though. I am seeing it on all my YesNoDialogs but they are working fine

/*
Debug log
Ynd.SetButtonText( Exit, Stay )
WARNING: Ynd.SetButtonText() failed! (Attempt to invoke virtual method 'void android.widget.Button.setText(java.lang.CharSequence)' on a null object reference)
*/

I only have beta versions installed to test on right now. What version of DroidScript are you using?

Simon Davison

unread,
May 23, 2021, 7:19:25 AM5/23/21
to DroidScript
I'm using v2.09 on both an android TV box and Phone.  The webserver runs on the phone and the client runs on the TV box for now, but it will go on a phone eventually.

That's exactly the same error as I have with my yesno dialogs too.  It doesn't stop them from working though. I can kinda live with it apart from it throwing up an error which my handler is only assuming is the severed websocket's fault.  I might see if I can persuade my handler to ignore the ynd failure if possible.

Steve Garman

unread,
May 23, 2021, 9:59:30 AM5/23/21
to DroidScript
/*
When you are developing an app I have a number of recommendations about error handlers like app.SetOnError()
1) add handlers as late in the development cycle as possible. Once you have a handler your assumptions about what is causing errors will usually be wrong
2) if you must turn on your handlers during development, make sure they give you as much information as possible. See the code below
3) if you get inexplcable behaviour from your app, suspect your error handler is faulty before checking anything else
4) if your handler is catching errors, try hard to find a way to avoid the errors before they happen rather than relying on the handler 
5) if you change your error handler before release to hide information from the user, double and triple test the handler again. This applies even if the changes appear to be minimal

Having said all that, in complex apps, throwing a specific error and catching it can be a useful, sometimes elegant, way to return to a fixed point in your app and clean up

There are also times when there is a good reason to wrap short pieces of code in a try/catch/finally block when checking for a specific failure you know may occur but cannot easily check in advance

The poor practice tends to be catching errors you did not throw deliberately because it's easier than getting the code right. 

And please never allow an error to occur in your app without reading the error message to confirm you know why it happened
*/

// simple SetOnError example
function OnStart()
{
   app.SetOnError(OnError)
   lay = app.CreateLayout("Linear", "VCenter,fillXY")
   btn = app.AddButton(lay, "Test")
   btn.SetOnTouch(btn_OnTouch)

   app.AddLayout(lay)
}

function btn_OnTouch()
{
   var test = Math.floor(Math.random() * 6)
   if(test == 5) doStuff()
   app.ShowPopup(test+"\nkeep trying")
}

function OnError(errmsg, line, file)
{
   var msg =
      'Message: "' + errmsg + '"\n' +
      'Line: ' + line + '\n' +
      'File: "' + app.Uri2Path(file) + '"';

   yn = app.CreateYesNoDialog(msg)
   yn.SetOnTouch(yn_OnTouch)
   yn.SetButtonText("Exit", "Remain")
   yn.Show()
}

function yn_OnTouch(ans)
{
   if(ans == 'Yes') app.Exit()
Reply all
Reply to author
Forward
0 new messages