JavaPhoenixChannels icon indicating copy to clipboard operation
JavaPhoenixChannels copied to clipboard

Socket closes after every Channel.push command

Open gupta11 opened this issue 8 years ago • 12 comments

The Server I connect to generates random URLs and once connected I need to join a channel and then maintain the connection. The server uses Phoenix protocol as well which is why I am using this library.

However whenever I do my initiate channel join command and get a return on my callback function, the library closes the socket. I am not able to find a way to keep the socket open long enough to make my any other calls.

Is there a way to prevent the socket from closing after I make the first push/join on the channel?

gupta11 avatar Nov 28 '16 18:11 gupta11

Hi, is it possible to show a code example? Also, are there any relevant logs? It's definitely possible it is a bug.

bryanjos avatar Nov 29 '16 14:11 bryanjos

public class WebSocketConnection  {

    private WebSocketConnection(){

    }

    public static WebSocketConnection connection;

    public static synchronized WebSocketConnection getInstance(){
        if (connection == null)
        {
            connection =  new WebSocketConnection();
        }
        return connection;
    }


    private static Socket socket;
    private Channel channel;

    public void connectWebSocket(String uri) {
    try {
        if(socket ==null || !socket.isConnected()) {
            socket = new Socket(uri, 20000);
            socket.reconectOnFailure(false);
            socket.connect();

        }

    }
    catch(Exception e)
    {

    }
    }

    public void join() throws IOException {
        new AsyncTask() {

            @Override
            protected Object doInBackground(Object[] objects) {
                ObjectNode node = new ObjectNode(JsonNodeFactory.instance);
                channel = socket.chan("user", node);
                try {
                    channel.join()
                            .receive("ignore", new IMessageCallback() {
                                        @Override
                                        public void onMessage(Envelope envelope) {
                                            System.out.println("IGNORE");
                                        }
                                    }

                            )
                            .receive("ok", new IMessageCallback() {
                                        @Override
                                        public void onMessage(Envelope envelope) {
                                            System.out.println("JOINED with " + envelope.toString());
                                            ObjectNode node = new ObjectNode(JsonNodeFactory.instance)
                                               //removed data from the values
                                                    .put("name", "")
                                                    .put("card", "")
                                                    .put("month","")
                                                    .put("year","")
                                                    .put("cvc","")
                                                    .put("address_line1", "")
                                                    .put("address_line2","")
                                                    .put("city","")
                                                    .put("state","")
                                                    .put("postal_code","")
                                                    .put("country","")
                                                    .put("phone_number","");

                                            sendMessage("user","add_card",node);
                                        }
                                    }

                            );
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }

        }.execute();

        socket.onClose(new ISocketCloseCallback() {
            @Override
            public void onClose() {
                System.out.println("Socket just closed");
            }
        });
    }

     public void sendMessage(final String topic, final String event, final JsonNode payload){

         new AsyncTask(){

             @Override
             protected Object doInBackground(Object[] objects) {

                 Envelope envelope = new Envelope(topic, event, payload, UUID.randomUUID().toString());
                // ObjectNode node = new ObjectNode(JsonNodeFactory.instance);

                 channel.on("new:msg", new IMessageCallback() {
                     @Override
                     public void onMessage(Envelope envelope) {
                         System.out.println("NEW MESSAGE: " + envelope.toString());
                     }
                 });
                 try{
                     socket.push(envelope);
//                     channel.push(event,payload)
//                             .receive("ok", new IMessageCallback() {
//                                 @Override
//                                 public void onMessage(final Envelope envelope) {
//                                     System.out.println("NEW MESSAGE: " + envelope.toString());
//                                     //addToList(message);
//                                 }
//                             })
//                             .timeout(new ITimeoutCallback() {
//                                 @Override
//                                 public void onTimeout() {
//                                     System.out.println("MESSAGE TIMED OUT");
//                                 }
//                             });
                     //channel.push(event,payload);
                 } catch (IOException e) {
                     e.printStackTrace();
                     // showToast("Failed to send");
                 };

                 return null;
             }
         }.execute();

     }

}

gupta11 avatar Nov 30 '16 13:11 gupta11

Thanks, I'm looking into it today to see if I can reproduce it and find a cause

bryanjos avatar Dec 02 '16 15:12 bryanjos

@gupta11 I wasn't able to reproduce the issue I don't think. I updated the code example a little bit and maybe that had something to do with it here is my version of WebSocketConnection.java (I used the phoenix chat example for testing so topics and event names changed in my example:

package com.basstype.androidphoenixchanneltester;

import android.os.AsyncTask;
import android.util.Log;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;

import org.phoenixframework.channels.Channel;
import org.phoenixframework.channels.Envelope;
import org.phoenixframework.channels.IMessageCallback;
import org.phoenixframework.channels.ISocketCloseCallback;
import org.phoenixframework.channels.ITimeoutCallback;
import org.phoenixframework.channels.Socket;

import java.io.IOException;
import java.util.UUID;

public class WebSocketConnection {

    private WebSocketConnection() {

    }

    public static WebSocketConnection connection;

    public static synchronized WebSocketConnection getInstance() {
        if (connection == null) {
            connection = new WebSocketConnection();
        }
        return connection;
    }


    private static Socket socket;
    private Channel channel;

    public void connectWebSocket(String uri) {
        try {
            if (socket == null || !socket.isConnected()) {
                socket = new Socket(uri, 20000);
                socket.reconectOnFailure(false);
                socket.connect();
                ObjectNode node = new ObjectNode(JsonNodeFactory.instance);
                channel = socket.chan("rooms:lobby", node);
            }

        } catch (Exception e) {

        }
    }

    public void join() throws IOException {
        new AsyncTask() {

            @Override
            protected Object doInBackground(Object[] objects) {
                try {
                    channel.join()
                            .receive("ignore", new IMessageCallback() {
                                        @Override
                                        public void onMessage(Envelope envelope) {
                                            Log.d(WebSocketConnection.class.getName(), "IGNORE");
                                            System.out.println("IGNORE");
                                        }
                                    }

                            )
                            .receive("ok", new IMessageCallback() {
                                        @Override
                                        public void onMessage(Envelope envelope) {
                                            Log.d(WebSocketConnection.class.getName(), "JOINED with " + envelope.toString());
                                            System.out.println("JOINED with " + envelope.toString());
                                            ObjectNode node = new ObjectNode(JsonNodeFactory.instance)
                                                    //removed data from the values
                                                    .put("name", "")
                                                    .put("card", "")
                                                    .put("month", "")
                                                    .put("year", "")
                                                    .put("cvc", "")
                                                    .put("address_line1", "")
                                                    .put("address_line2", "")
                                                    .put("city", "")
                                                    .put("state", "")
                                                    .put("postal_code", "")
                                                    .put("country", "")
                                                    .put("phone_number", "");

                                            sendMessage("new:msg", "new:msg", node);
                                        }
                                    }

                            );
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }

        }.execute();

        socket.onClose(new ISocketCloseCallback() {
            @Override
            public void onClose() {
                Log.d(WebSocketConnection.class.getName(), "Socket just closed");
                System.out.println("Socket just closed");
            }
        });
    }

    public void sendMessage(final String topic, final String event, final JsonNode payload) {

        new AsyncTask() {

            @Override
            protected Object doInBackground(Object[] objects) {

                Envelope envelope = new Envelope(topic, event, payload, UUID.randomUUID().toString());
                ObjectNode node = new ObjectNode(JsonNodeFactory.instance);

                channel.on("new:msg", new IMessageCallback() {
                    @Override
                    public void onMessage(Envelope envelope) {
                        Log.d(WebSocketConnection.class.getName(), "NEW MESSAGE: " + envelope.toString());
                        System.out.println("NEW MESSAGE: " + envelope.toString());
                    }
                });
                try {
                    socket.push(envelope);
                     //channel.push(event,payload)
                     //        .receive("ok", new IMessageCallback() {
                     //            @Override
                     //            public void onMessage(final Envelope envelope) {
                     //                Log.d(WebSocketConnection.class.getName(), "NEW MESSAGE: " + envelope.toString());
                     //                System.out.println("NEW MESSAGE: " + envelope.toString());
                                     //addToList(message);
                     //            }
                     //        })
                     //        .timeout(new ITimeoutCallback() {
                     //            @Override
                     //            public void onTimeout() {
                     //                Log.d(WebSocketConnection.class.getName(), "MESSAGE TIMED OUT");
                     //                System.out.println("MESSAGE TIMED OUT");
                     //            }
                     //        });
                    //channel.push(event,payload);
                } catch (IOException e) {
                    e.printStackTrace();
                    // showToast("Failed to send");
                }
                ;

                return null;
            }
        }.execute();

    }

}

bryanjos avatar Dec 02 '16 19:12 bryanjos

Thank you so much for taking a look @bryanjos . I will check it next week and again check my code and revert back to you. I hope this works. :)

gupta11 avatar Dec 02 '16 19:12 gupta11

I'm having this same problem, as soon as I push a message.

The thing that is strange to me is that there doesn't seem to be adequate error reporting around the connection closing. If we can't find the bug for this, could we at least make sure there are mechanisms for appropriate error reporting to the Android logs?

relwell avatar Dec 22 '16 23:12 relwell

I was not able to verify if this is working. I had a release that I was working towards and had to use another socket library with my own implementation of the phoenix protocol. @relwell can you post your code as well so that @bryanjos can check it out. I will try this in the new year once my release is done and see if the code works for me but for now it doesn't and closes the socket after the first message.

gupta11 avatar Dec 23 '16 14:12 gupta11

I managed to do some more debugging and I think I see the problem.

There's an error on the Elixir side, so I'm guessing the server is closing the channel. It seems like we should get something in the logs for this, shouldn't we?

relwell avatar Dec 23 '16 17:12 relwell

Never mind. I'm able to confirm that even when pushing a well-formed message, using channel.push results in the channel trying to rejoin.

relwell avatar Dec 23 '16 17:12 relwell

I have this problem too. And problem occurs in API 26, and in API 22 it's correct.

Reza-Soltani avatar Jan 02 '17 12:01 Reza-Soltani

Is there a way anyone could show small example projects both on the Elixir and Android side with the issue present? I haven't been able to reproduce it on my own

bryanjos avatar Jan 02 '17 14:01 bryanjos

I was also experiencing this but realized that I was updating the UI after I received a response from the push on a background thread (the thread the socket was using). Running the block of code in the response callback on the main thread will no longer cause the socket to be disconnected.

Daltron avatar Apr 18 '17 17:04 Daltron