I want to subscribe to a specific channel of action cable.
Any library or client of actioncable for android?
I am using one library https://github.com/hosopy/actioncable-client-java but not able to connect with action cable.
1.connect with the rails action cable path
private void start() {
try {
Request request = new Request.Builder().url("ws://"+Constants.HOST_ADDRESS +"/cable").addHeader("auth-token", AUTH_TOKEN).build();
EchoWebSocketListener listener = new EchoWebSocketListener();
WebSocket ws = client.newWebSocket(request, listener);
client.dispatcher().executorService().shutdown();
client = new OkHttpClient();
} catch (Exception e) {
e.printStackTrace();
}
}
2.Subscribe to the channel
private final class EchoWebSocketListener extends WebSocketListener {
#Override
public void onOpen(WebSocket webSocket, Response response) {
webSocket.send("{\"command\":\"subscribe\", \"identifier\":\"{\\\"channel\\\":\\\"CommunicationsChannel\\\"}\"}");
#Override
public void onMessage(WebSocket webSocket, String text) {
try {
JSONObject jsonBot = new JSONObject(text);
}
}
}
The WebSocket listener can receive all the message send from rails application via ‘CommunicationsChannel’, you will be able to recive it in ‘onMessage’ function
check this resource for other actionable android implementation :
https://www.xploralab.com/?s=action+cable
Related
I have developed and Android application with is connecting to JAVA Web Socket and basically it is working very well.
The issue is, that sometimes the client is disconnected but connection at the server side is appearing to be connected.
I try to investigate, when and why it happened but unfortunately i could not find the a specific scenario that cause to this problem.
I have thought to implement Ping/Pong messaging between server and all clients and in case that there is no answer from the clients is to closed the connection at the server side.
i can easily implement such my private mechanism but I have read around and I understand that Java and Android has an build in Ping/Pong messaging mechanism but i was not able to find any example of that.
Can anyway, provide a simple example how to implement Ping/Pong messaging functionality using the build in tools?
I have succeed to implement Ping/Pong functionality between EE JAVA WebSocket and android application. The server is sending Ping message to client every 5 min. if server does not got Pong message back within 5 second, the server is closing client connection.
here is my solution if someone will need it:
WebSocket side:
public class User {
public ScheduledExecutorService pingExecutorService;
public Timer disconnectTimer;
private Session userSession;
private String userName;
public User(Session userSession) {
this.userSession = userSession;
}
public Session getUserSession() {
return userSession;
}
public void setUserSession(Session userSession) {
this.userSession = userSession;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
#OnOpen
public void onOpen(Session session) {
User newUserConnection = new User(session);
connections.getConnections().put(session.getId(), newUserConnection);
schedulePingMessages(newUserConnection);
}
#OnClose
public void onClose(Session session) {
handleOnClose(session);
}
#OnMessage
public void onMessage(String message, Session session) {
messageHandler.handleMessage(message, session);
}
#OnMessage
public void onPong(PongMessage pongMessage, Session session) {
String sourceSessionId = session.getId();
User user = connections.getConnections().get(sourceSessionId);
user.disconnectTimer.cancel();
user.disconnectTimer.purge();
}
#OnError
public void onError(Throwable t) {
System.out.println(new Date() + "onError::" + t.getMessage());
t.printStackTrace();
}
private void schedulePingMessages(User newUserConnection) {
newUserConnection.pingExecutorService = Executors.newScheduledThreadPool(1);
newUserConnection.pingExecutorService.scheduleAtFixedRate(() -> {
scheduleDiconnection(newUserConnection);
try {
String data = "Ping";
ByteBuffer payload = ByteBuffer.wrap(data.getBytes());
newUserConnection.getUserSession().getBasicRemote().sendPing(payload);
} catch (IOException e) {
e.printStackTrace();
}
}, 300, 300, TimeUnit.SECONDS);
}
private void scheduleDiconnection(User user) {
user.disconnectTimer = new Timer();
user.disconnectTimer.schedule(new TimerTask() {
#Override
public void run() {
try {
user.getUserSession().close(new CloseReason(CloseCodes.UNEXPECTED_CONDITION," Client does not response"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, 5000);
}
The android side just need to add the following override method:
#Override
public void onWebsocketPing(WebSocket conn, Framedata f) {
Log.i("ZCF","got Ping !");
super.onWebsocketPing(conn, f);
}
I have socket server that need user-id in order to connect. Therefore, I need to set extraHeader to connection constructor. I tried the following code but there's no luck. Please help me get through, thanks.
Add extra header 'x-user-id': userId to connection constructor
private Socket mSocket;
{
try {
IO.Options opts = new IO.Options();
mSocket = IO.socket(socket_url, opts);
mSocket.io().on(Manager.EVENT_TRANSPORT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Transport transport = (Transport)args[0];
transport.on(Transport.EVENT_REQUEST_HEADERS, new Emitter.Listener() {
#Override
public void call(Object... args) {
#SuppressWarnings("unchecked")
Map<String, List<String>> headers = (Map<String, List<String>>)args[0];
// modify request headers
headers.put("x-user-id", Arrays.asList("5B59F68B7B7811E88C3E52964BF487E4"));
}
}).on(Transport.EVENT_RESPONSE_HEADERS, new Emitter.Listener() {
#Override
public void call(Object... args) {
}
});
}
});
} catch (URISyntaxException e) {}
}
This is my swift code that is works.
private init(){
self.socketManager = SocketManager(socketURL: URL(string:"\(MAIN_URL)/message")!, config: [.log(true),.extraHeaders(["x-user-id":AppManager.instance.userId])])
self.socket = socketManager?.defaultSocket
}
You can use also stomp client provided by Spring framework.
To compile and run the following method you should add 'spring-messaging' and 'spring-websocket' maven dependencies to your project.
public ListenableFuture<StompSession> connect() {
List<Transport> transports = new ArrayList<>(2);
transports.add(new WebSocketTransport(new StandardWebSocketClient()));
transports.add(new RestTemplateXhrTransport());
SockJsClient sockJsClient = new SockJsClient(transports);
sockJsClient.setMessageCodec(new Jackson2SockJsMessageCodec());
WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
headers.add("x-user-id", "5B59F68B7B7811E88C3E52964BF487E4");
return stompClient.connect(socket_url, headers, new StompSessionHandlerAdapter() {});
}
The problem is fixed on server side. Here is my configuration.
Add this >>>
var server = app.listen(3000, {// options can go here
transports: ['xhr-polling']
});
io.use((socket, next) => {
let clientId = socket.handshake.headers['x-user-id'];
});
I built a server using node.js and socket.io for a chat application and I want to connect to the server from my android client application that uses native java.net.Socket. Can I do it?
Here I found a solution that works fine. This code section is for server side socket.
var net = require('net');
var sockets = [];
var svr = net.createServer(function(sock) {
console.log('Connected: ' + sock.remoteAddress + ':' + sock.remotePort);
sockets.push(sock);
sock.write('Welcome to the server!\n');
sock.on('data', function(data) {
for (var i=0; i<sockets.length ; i++) {
if (sockets[i] != sock) {
if (sockets[i]) {
sockets[i].write(data);
}
}
}
});
sock.on('end', function() {
console.log('Disconnected: ' + sock.remoteAddress + ':' + sock.remotePort);
var idx = sockets.indexOf(sock);
if (idx != -1) {
delete sockets[idx];
}
});
});
var svraddr = '192.168.0.8';
var svrport = 1234;
svr.listen(svrport, svraddr);
console.log('Server Created at ' + svraddr + ':' + svrport + '\n');
Android client side code is given below: connect to the given ip and port for server through android client side.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
public class Client {
private Socket socket;
private OutputStream socketOutput;
private BufferedReader socketInput;
private String ip;
private int port;
private ClientCallback listener=null;
public Client(String ip, int port){
this.ip=ip;
this.port=port;
}
public void connect(){
new Thread(new Runnable() {
#Override
public void run() {
socket = new Socket();
InetSocketAddress socketAddress = new InetSocketAddress(ip, port);
try {
socket.connect(socketAddress);
socketOutput = socket.getOutputStream();
socketInput = new BufferedReader(new InputStreamReader(socket.getInputStream()));
new ReceiveThread().start();
if(listener!=null)
listener.onConnect(socket);
} catch (IOException e) {
if(listener!=null)
listener.onConnectError(socket, e.getMessage());
}
}
}).start();
}
public void disconnect(){
try {
socket.close();
} catch (IOException e) {
if(listener!=null)
listener.onDisconnect(socket, e.getMessage());
}
}
public void send(String message){
try {
socketOutput.write(message.getBytes());
} catch (IOException e) {
if(listener!=null)
listener.onDisconnect(socket, e.getMessage());
}
}
private class ReceiveThread extends Thread implements Runnable{
public void run(){
String message;
try {
while((message = socketInput.readLine()) != null) { // each line must end with a \n to be received
if(listener!=null)
listener.onMessage(message);
}
} catch (IOException e) {
if(listener!=null)
listener.onDisconnect(socket, e.getMessage());
}
}
}
public void setClientCallback(ClientCallback listener){
this.listener=listener;
}
public void removeClientCallback(){
this.listener=null;
}
public interface ClientCallback {
void onMessage(String message);
void onConnect(Socket socket);
void onDisconnect(Socket socket, String message);
void onConnectError(Socket socket, String message);
}
}
MainActivity is:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Client socket = new Client("192.168.0.8", 1234);
socket.setClientCallback(new Client.ClientCallback () {
#Override
public void onMessage(String message) {
}
#Override
public void onConnect(Socket socket) {
socket.send("Hello World!\n");
socket.disconnect();
}
#Override
public void onDisconnect(Socket socket, String message) {
}
#Override
public void onConnectError(Socket socket, String message) {
}
});
socket.connect();
}
}
The answer to your question is No. A java.net.socket cannot be connected with a nodejs socket.io because the protocol specifications are different for both.
Note: Socket.IO is not a WebSocket implementation. Although Socket.IO indeed uses WebSocket as a transport when possible, it adds some metadata to each packet: the packet type, the namespace and the ack id when a message acknowledgement is needed. That is why a WebSocket client will not be able to successfully connect to a Socket.IO server, and a Socket.IO client will not be able to connect to a WebSocket server (like ws://echo.websocket.org) either. Please see the protocol specification here.
Quoted From nodejs socket.io github page.So when web socket cannot be connected to socket.io so the java.net.socket can also be not connected.
If you want to have communication with the java client you can use the Socket.io library designed for java.
In Nodejs, You can use from this example
And in Sockect.io blog
In Java, as a server, you can use PrintWriter to write your data on Socket in a very simple situation. like below open socket on port 9090 and send current date to the client:
/**
* Runs the server.
*/
public static void main(String[] args) throws IOException {
ServerSocket listener = new ServerSocket(9090);
try {
while (true) {
Socket socket = listener.accept();
try {
PrintWriter out =
new PrintWriter(socket.getOutputStream(), true);
out.println(new Date().toString());
} finally {
socket.close();
}
}
}
finally {
listener.close();
}
}
Code from here
I am trying to implement a MockWebServer from Square and i am behind a proxy. The problem is that every time i am executing my instrumentation test will fail because i am getting a 407 for every request i am doing to my MockWebServer.
debug.level.titleD/OkHttp: <-- 407 Proxy Authentication Required http://localhost:12345/user/login (767ms)
As u see i am pointing to my localhost and i dont know why i am getting this!
Here is my MockWebServer implementation!
public class MockedTestServer {
private final int PORT = 12345;
private final MockWebServer server;
private int lastResponseCode;
private String lastRequestPath;
/**
* Creates and starts a new server, with a non-default dispatcher
*
* #throws Exception
*/
public MockedTestServer() throws Exception {
server = new MockWebServer();
server.start(PORT);
setDispatcher();
}
private void setDispatcher() {
final Dispatcher dispatcher = new Dispatcher() {
#Override
public MockResponse dispatch(final RecordedRequest request) throws InterruptedException {
try {
final String requestPath = request.getPath();
final MockResponse response = new MockResponse().setResponseCode(200);
String filename;
// response for alerts
if (requestPath.equals(Constantes.ACTION_LOGIN)) {
filename = ConstantesJSON.LOGIN_OK;
} else {
// no response
lastResponseCode = 404;
return new MockResponse().setResponseCode(404);
}
lastResponseCode = 200;
response.setBody(RestServiceTestHelper.getStringFromFile(filename));
lastRequestPath = requestPath;
return response;
} catch (final Exception e) {
throw new InterruptedException(e.getMessage());
}
}
};
server.setDispatcher(dispatcher);
}
public String getLastRequestPath() {
return lastRequestPath;
}
public String getUrl() {
return server.url("/").toString();
}
public int getLastResponseCode() {
return lastResponseCode;
}
public void setDefaultDispatcher() {
server.setDispatcher(new QueueDispatcher());
}
public void enqueueResponse(final MockResponse response) {
server.enqueue(response);
}
public void shutdownServer() throws IOException {
server.shutdown();
}
My end point when i am executing instrumentation test is "/".
This problem only occurs when i am behind a proxy network, if in my mobile device i switch to another network that is not behind proxy the mock server works well. Any idea what i am doing wrong?
Edit:
When i am behind proxy the dispatcher never gets called
Ok i just figuered out in the end.... Result that my okhttp3 client was pointing to the real proxy server and not to the mock web server in localhost. I solved this by adding a proxy to my okhttp3 client only when in testing Flavour and then add it to Retrofit2 builder. The code looks like this.
if (BuildConfig.TEST_PROXY){
try {
InetSocketAddress sock = new InetSocketAddress(InetAddress.getByName("localhost"),12345);
builderOkhttpClient.proxy(new Proxy(Proxy.Type.HTTP, sock));
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
It's important to note that the port when building the InetSocketAddress is the same as the mock web server port.
I'm trying learn how to use the websocket and make a simple servlet for being connected with Android but I don't get it.
The index.jsp :
var ws = new WebSocket("ws://" + document.location.host + "/myws/ServletWS");
ws.onopen = function() { };
ws.onclose = function() { };
ws.onerror = function() { log("ERROR"); };
ws.onmessage = function(data) { var message = data.data; };
function sendMessage(msg) { ws.send(msg); }
How or where I receive the data from client?
Now on the servlet:
#Override protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) {
return new ConnectionWS();
}
class ConnectionWS extends MessageInbound {
private WsOutbound outbound;
#Override protected void onOpen(WsOutbound outbound) {
this.outbound = outbound;
}
#Override protected void onTextMessage(CharBuffer msg) throws IOException {
String message = msg.toString();
ServletWS.processData(message);
}
public void sendMessage(String message) {
CharBuffer cb = CharBuffer.wrap(message);
try {
outbound.writeTextMessage(cb);
} catch (IOException e) {}
}
}
public void processData(String message){
here I have to call the sendMessage with the answer to the client
}
I have saw a lot of examples on web but all of then about chat.
Thanks a lot for any help.
I understand that, you have a basic knowledge about tomcat configuration as well as java Servlet programming. As WekSocket is newly introduced in Tomcat, you may need to use latest tomcat version to implement WebSocket over it. I have used Apache Tomcat 7.0.42 for it.
So here we go. First, create a Servlet which will just create a new WebSocket for the request. You may need to modify it, if you want to go by session rather than request. Here is sample code.
import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WebSocketServlet;
public class WsChatServlet extends WebSocketServlet {
private static final long serialVersionUID = 1456546233L;
#Override
protected StreamInbound createWebSocketInbound(String protocol,
HttpServletRequest request) {
return new IncomingMessageHandler();
}
}
Now, create a Message Handler class which will handle each WebSocket stream independently. and that's it !
public class IncomingMessageHandler extends MessageInbound {
private WsOutbound myoutbound;
public IncomingMessageHandler() {
}
#Override
public void onOpen(WsOutbound outbound) {
logger.info("Open Client.");
this.myoutbound = outbound;
}
#Override
public void onClose(int status) {
logger.info("Close Client.");
}
/**
* Called when received plain Text Message
*/
#Override
public void onTextMessage(CharBuffer cb) throws IOException {
}
/**
* We can use this method to pass image binary data, eventually !
*/
#Override
public void onBinaryMessage(ByteBuffer bb) throws IOException {
}
public synchronized void sendTextMessage(String message) {
try {
CharBuffer buffer = CharBuffer.wrap(message);
this.getMyoutbound().writeTextMessage(buffer);
this.getMyoutbound().flush();
} catch (IOException e) {
}
}
/**
* Set websocket connection timeout in milliseconds,
* -1 means never
*/
#Override
public int getReadTimeout() {
return -1;
}
public WsOutbound getMyoutbound() {
return myoutbound;
}
public void setMyoutbound(WsOutbound myoutbound) {
this.myoutbound = myoutbound;
}
}
If not misunderstood and you want to use web sockets on Android then recommended API for you is jWebSocket.
Get it here, hopefully it already provides you APIs for a lot of the work that you need to do or even more.
http://jwebsocket.org/