I have a webchat application which is running on Node.js and Socket.io. After user logins on main homepage port 80, he gets redirected to port 3000 (chat application) along with POST data containing his ID, username etc... On chat application page it validates details and registers user as new client.
However, now I am building android chat application and I get immediately disconnected from chat because basically android client fails validation since there is no POST data attached.
How can I add POST data along with connection request?
Here is a code that does it all in android:
try {
IO.Options opts = new IO.Options();
opts.forceNew = true;
final Socket socket = IO.socket("http://host:3000", opts);
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener(){
#Override
public void call(Object... args){
socket.emit("mobile_ping", sf.getTextValue(MainActivity.this, R.id.editText));
}
});
socket.connect();
} catch (Exception e) {
Log.d("ERR", String.valueOf(e));
}
Related
I am trying to connect signalR from the android client. I have already setup signalR hub and its working properly with javascript client on the browser. javascript client able to sent bearer-token and on the server side, I am able to get user identity.
But android java client is not able to send bearer token on. I am using https://github.com/SignalR/java-client library (As I am not using SIgnalR-core so not using latest SIgnalR core library)
connection = new HubConnection(serverUrl);
connection.getHeaders().put("Authorization","Bearer XYZ");
proxy = connection.createHubProxy(hubName);
When I run this code, I got an error
java.lang.InterruptedException: Operation was canceled
But when I don't send AUthorization header with the request then on server-side SIgnalR OnConnected() method called successfully.
The issue seems to be with sending Authorization header with the request.
For reference, the following is code to show how token authentication is implemented on the server-side
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new QueryStringOAuthBearerProvider()
});
var hubConfiguration = new HubConfiguration
{
Resolver = GlobalHost.DependencyResolver,
};
map.RunSignalR(hubConfiguration);
});
ConfigureAuth(app);
I have tried calling it by removing authorization from the server. Then it called successfully. But not works when called with Authorization header.
When I tried connection without Authorization then on server-side OnCOnnected method called but Context. Identity is null.
android Java code for connecting to SignalR client
Platform.loadPlatformComponent(new AndroidPlatformComponent());
// Create Connection
connection = new HubConnection(serverUrl);
connection.getHeaders().put("Authorization","Bearer XYZ");
// Create Proxy
proxy = connection.createHubProxy(hubName);
// Establish Connection
ClientTransport clientTransport = new
ServerSentEventsTransport(connection.getLogger());
SignalRFuture<Void> signalRFuture = connection.start(clientTransport);
try {
signalRFuture.get();
} catch (InterruptedException e) {
return false;
} catch (ExecutionException e) {
return false;
}
return true;
If you are using Websocket, try this
https://github.com/doctorcareanywhere/java-client
build signalr-client-sdk and import the jar to your project
eg.
implementation files('libs/signalr-client-sdk.jar')
What I have:
I have Android application with socket.io implementation. Servers run on node.js. Servers IPs are hardcoded in the app. Clients communicate with servers successfully - they send and receive messages.
IO.socket version I am using in my client: ('io.socket:socket.io-client:1.0.0')
What I need to get: My problem is I have to change server IP which the client is connected to, after client receives determined message.
Simplified client socket behaviour is more less like this:
socket.on("msg", new Emitter.Listener() {
#Override
public void call(Object... args) {
try {
switch (msg){
case "1":
keepOnListeningFirstServer();
break;
case "2":
connectToAnotherServer();
break;
...
What I managed to achieve is that after specific server command (msg = 2) client connects to the second server, but client remains connected to the first server (client is still listening to commands from the first server). Actually what happens I think is that client creates second socket, but not properly closing the first socket.
In this situation, client still receives messages form first server but it sends responses to the new second server. Quite weird, but that was the furthest I managed to get with this here.
What I have tried to disconnect client and start new listener was calling on client:
socket.disconnect();
socket.close();
socket.off();
and then creating new socket and connecting it:
socket = IOSocket.getInstance(socketIP).getSocket();
socket.connect();
So my questions in general are:
Why isn't my client starting listening to new server messages even though this client is sending responses to this new server?
Maybe there is a way to switch/update socket listener without closing it?
What is a proper way of closing/disconnecting/destroying this first socket?
Maybe somebody can give me a hint of better method to change io.socket server IP that client is listening to? (Please note that this application is Android native)
Any help or advice will be very appreciated, so thanks in advance!
You should close the socket and shutdown the channel before the disconnection really completes.
This should be your case:
//create the initial socket
Socket socket = IO.socket("your_url");
//define a constant for your channel
public static final String ON_MESSAGE_RECEIVED = "msg";
//define the event listener
private Emitter.Listener onMessageReceived = new Emitter.Listener() {
#Override
public void call(Object... args) {
//your logic for the event here
}
});
//attach your channels to the socket
socket.on(ON_MESSAGE_RECEIVED, onMessageReceived);
socket.connect();
//when you want to disconnect the socket remember to shutdown all your channels
socket.disconnect();
socket.off(ON_MESSAGE_RECEIVED, onMessageReceived);
//Then create a new socket with a new url and register again for the same event
IO.Options opts = new IO.Options();
opts.forceNew = true;
opts.reconnection = false;
socket = IO.socket("new_url", opts);
socket.on(ON_MESSAGE_RECEIVED, onMessageReceived);
socket.connect();
I making a android chat app. Im use the api level 23, the Xmpp Smack lib version 4.1.8, and on server I use ejabberd, version 16.06.
I use this code to build a XMPP connection.
(TIMEOUT = 5000)
private void buildConnection() {
XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder()
.setServiceName(mServiceName)
.setHost(mServiceName)
.setConnectTimeout(TIMEOUT)
.setResource("Smack")
.setUsernameAndPassword(mUsername, mPassword)
.setSendPresence(true)
.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
mConnection = new XMPPTCPConnection(builder.build());
mConnection.setPacketReplyTimeout(TIMEOUT);
chatManager = ChatManager.getInstanceFor(mConnection);
chatManager.addChatListener(this);
PingManager pingManager = PingManager.getInstanceFor(mConnection);
pingManager.setPingInterval(5);
pingManager.registerPingFailedListener(this);
ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(mConnection);
reconnectionManager.enableAutomaticReconnection();
mConnection.addConnectionListener(this);
if (mConnection != null) {
DeliveryReceiptManager.getInstanceFor(mConnection).addReceiptReceivedListener(new ReceiptReceivedListener() {
#Override
public void onReceiptReceived(String fromJid, String toJid, String receiptId, Stanza receipt) {
updateMessageStatusReceived(receipt);
Log.i(TAG, "Confirmation stanza Got: " + receipt);
}
});
}
}
(the updateMessageStatusReceived(receipt) method is only to refresh the view).
after that, I connect and authenticate.
Everthing is normal, but when the connection is down, I need to resend the failed messages when the connection is restored. I didn't find any solution or event in Smack to detected if a message fails. Sometimes the delay of confirmation server stanza is high, and my app assumes that message fails but don't, and the other side receive many times the same message.
I build a Message object and send using this code:
try {
Chat chat = chatManager.createChat(chatMessage.getJid());
chat.sendMessage(message);
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
When the connection is lost and I send message, no one exception is throw.
my question is: How I know the message realy fail, to try again?
Thanks, and sorry about the english.
I have offline messages option enabled in the openfire server.But I'm unable to get offline messages
User A is online ,User B is online ,in this case I'm able to get messages.
Now User B Turned off his WiFi(Note : User A waited till the user B Session completely killed in the server )
now User A send a message to User B
in this case I'm able to see the message in the openfire offline table.
Now User B Comes online again server is sending the message to user B as the server come to know that User B is online
(Message disappeared from offline messages table ).
But User B is not going to receive that message.
connection.login(userName, userPwd, UiUtility.getMyPhoneNO());
PacketFilter filter = new PacketTypeFilter(org.jivesoftware.smack.packet.Message.class);
packetListener =new PacketListener() {
public void processPacket(Packet packet) {
Message message = (Message) packet;
if (message.getBody() != null) {
String fromName = StringUtils.parseBareAddress(message
.getFrom());
Log.i("XMPPClient", "Got text [" + message.getBody()
+ "] from [" + fromName + "]");
}
}
};
connection.addPacketListener(packetListener, filter);
Again after successful login im able to chat normally.But I wonder why those offline messages are missing ? .My PacketListener unable to catch those offline messages .Please Help me
Asmack is depreceated. Use Smack. An Open Source XMPP Client Library written in Java for JVMs and Android. Add the following lines to your gradle file:
compile 'org.igniterealtime.smack:smack-android:4.1.3'
compile 'org.igniterealtime.smack:smack-tcp:4.1.3'
compile 'org.igniterealtime.smack:smack-extensions:4.1.3'
The problem is easy to be solved.
Before making connection with the XMPP server just register providers using ProviderManager class provided by ASmack library.
If this can't solve ur problem visit ur local server and search for offline messages, and select the option ALWAYS STORE setting the storage limit to be 1000 kb. It is 100 kb by default.
Hope this works.
After lot struggle, I have resolved the issue. In your openfire admin page, go to "client settings" and reduce the idle time from 360sec (by default) to 1 sec(may be). Only then when you disconnected from Internet, it can detect that you are offline and preserve rest of the messages as OFFLINE.
#Override
public void onNetworkConnectionChanged(boolean isConnected) {
if(isConnected){
new Thread() {
public void run() {
try {
XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder();
builder.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
builder.setUsernameAndPassword("phone", "admin");
builder.setSendPresence(true);
builder.setServiceName(<Service name>);
builder.setHost(<Host name>);
builder.setResource("Test");
builder.setDebuggerEnabled(true);
Presence presence = new Presence(Presence.Type.available);
presence.setStatus("Available");
connection = new XMPPTCPConnection(builder.build());
connection.connect();
connection.login();
Presence presence123 = new Presence(Presence.Type.available);
presence123.setStatus("Available");
try {
connection.sendStanza(presence123);
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
StanzaFilter filter = new AndFilter(new StanzaTypeFilter(Message.class));
PacketListener myListener = new PacketListener()
{
public void processPacket(Stanza stanza)
{
retrieveMessage(stanza,userType);
}
};
connection.addPacketListener(myListener, filter);
try {
connection.sendStanza(presence);
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
} catch (SmackException | XMPPException | IOException e) {
e.printStackTrace();
}
//return connection.isConnected();
}
}.start();
The above is working fine and able to retrieve the offline messages. The method "retrieveMessage(stanza,userType);" is used to process the incoming message and update the Adapter. Make sure to send the Presence as "Available" when you reconnect. Please let me know if there are still any issues.
i'm trying to write simple application with nodejs and express.io after reading some express.io document and successful connection to http://chat.socket.io i'm find simple sample for create server side with nodejs and express.io, after run this below code in command line and opening http://localhost:3000 in browser i dont get any error, i can not find any good document about coding in http://chat.socket.io server, now i want to try send request from android client to server with samples, but i get connection error:
Error:
CONNECTION ERROR
server.js:
// Setup basic express server
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('../..')(server);
var port = process.env.PORT || 3000;
server.listen(port, function () {
console.log('Server listening at port %d', port);
});
// Routing
app.use(express.static(__dirname + '/public'));
// Chatroom
// usernames which are currently connected to the chat
var usernames = {};
var numUsers = 0;
io.on('connection', function (socket) {
var addedUser = false;
// when the client emits 'new message', this listens and executes
socket.on('new message', function (data) {
// we tell the client to execute 'new message'
socket.broadcast.emit('new message', {
username: socket.username,
message: data
});
});
// when the client emits 'add user', this listens and executes
socket.on('add user', function (username) {
// we store the username in the socket session for this client
socket.username = username;
// add the client's username to the global list
usernames[username] = username;
++numUsers;
addedUser = true;
socket.emit('login', {
numUsers: numUsers
});
// echo globally (all clients) that a person has connected
socket.broadcast.emit('user joined', {
username: socket.username,
numUsers: numUsers
});
});
// when the client emits 'typing', we broadcast it to others
socket.on('typing', function () {
socket.broadcast.emit('typing', {
username: socket.username
});
});
// when the client emits 'stop typing', we broadcast it to others
socket.on('stop typing', function () {
socket.broadcast.emit('stop typing', {
username: socket.username
});
});
// when the user disconnects.. perform this
socket.on('disconnect', function () {
// remove the username from global usernames list
if (addedUser) {
delete usernames[socket.username];
--numUsers;
// echo globally that this client has left
socket.broadcast.emit('user left', {
username: socket.username,
numUsers: numUsers
});
}
});
});
my android code:
private Socket mSocket;
{
try {
/* connection successful to http://chat.socket.io */
mSocket = IO.socket("http://localhost:3000");
} catch (URISyntaxException e) {
Log.e("Error URI", String.valueOf(e));
throw new RuntimeException(e);
}
}
public void onCreate(Bundle savedInstanceState) {
...
mSocket.on(Socket.EVENT_CONNECT_ERROR, onConnectError);
mSocket.on(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
mSocket.on("new message", onNewMessage);
mSocket.on("user joined", onUserJoined);
mSocket.on("user left", onUserLeft);
mSocket.on("typing", onTyping);
mSocket.on("stop typing", onStopTyping);
mSocket.connect();
...
Button signInButton = (Button) findViewById(R.id.sign_in_button);
signInButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
attemptLogin();
}
});
mSocket.on("login", onLogin);
}
private void attemptLogin() {
mUsernameView.setError(null);
String username = mUsernameView.getText().toString().trim();
if (TextUtils.isEmpty(username)) {
mUsernameView.setError(getString(R.string.error_field_required));
mUsernameView.requestFocus();
return;
}
mUsername = username;
mSocket.emit("add user", username);
}
Android Error:
E/AndroidRuntime﹕ FATAL EXCEPTION: EventThread
java.lang.IllegalArgumentException: delay < 0: -432345566375051264
at java.util.Timer.schedule(Timer.java:457)
at com.github.nkzawa.socketio.client.Manager.reconnect(Manager.java:497)
at com.github.nkzawa.socketio.client.Manager.access$2000(Manager.java:20)
at com.github.nkzawa.socketio.client.Manager$8$1$1.call(Manager.java:519)
at com.github.nkzawa.socketio.client.Manager$1$3.call(Manager.java:282)
at com.github.nkzawa.emitter.Emitter.emit(Emitter.java:117)
at com.github.nkzawa.engineio.client.Socket.onError(Socket.java:754)
at com.github.nkzawa.engineio.client.Socket.access$800(Socket.java:29)
at com.github.nkzawa.engineio.client.Socket$4.call(Socket.java:293)
at com.github.nkzawa.emitter.Emitter.emit(Emitter.java:117)
at com.github.nkzawa.engineio.client.Transport.onError(Transport.java:63)
at com.github.nkzawa.engineio.client.transports.PollingXHR.access$100(PollingXHR.java:19)
at com.github.nkzawa.engineio.client.transports.PollingXHR$6$1.run(PollingXHR.java:126)
at com.github.nkzawa.thread.EventThread$2.run(EventThread.java:75)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:838)
I would blame this:
mSocket = IO.socket("http://localhost:3000");
I assume you are not running your node.js server on your android, but probably on your PC. If so, when testing on your android, you are trying to connect back on port 3000 to your android itself - as localhost links to device itself.
If you are using the same local network on your server and android, you should check your PC's IP and put it instead of localhost. If your server has public IP, you may want to use it instead.
edit
1
In other words, according to your comment: your PC IP is 192.168.1.5. As this is an internal IP, your android have to be connected to same sub-network your PC is, just because youre able to occur your connectin error. Basing to that, i assume you need to type http://192.168.1.5/ in adress bar in your android, to visit page your PC is serving. Assuming that, one remains nonchanged - the script "my android code" is running on your android. So instead of localhost there is required a proper host: 192.168.1.5. Cant tell if your android is blocking 3000 port, but localhost is improper from androids' point of view, as long as you are not running your nodejs server on that device.
Also that change may not take affect ad-hoc, during browser cache on mobile devices.
2
Looking into your code, I assume you will also occur some problems with users using same username. Yeah, sounds strange, but users may want to open few tabs in browser, connected to same socket server. Once that, your usernames and numUsers variables will corrupt.
As long as app is single-intance dedicated (eg. player#game), I would use
usernames[username] = socket
to store sockets aside, being able to post cross-player related events avoiding iteration over all opened sockets.
Also for chat-purposes, you may want to allow users being connected on few browser tabs at once. Usually I'm storing all sockets just this way:
if (!users[user]) {
users[user] = {
sockets: [socket]
};
console.log(sprintf('[%s] [CONNECTED] User %s', Date(), user));
} else {
users[user].sockets.push(socket);
}
your may be different, prolly based on chat-channels etc. Pushing sockets aside listeners allowed me to run separate UDP server in same node script file. It was in purpose of being able to monit/block/alert single user through all opened tabs, event if their are spread over two different browsers.