Socket.io not working with React Native on Android - socket.io

I'm learning React Native recently, and having trouble with using Socket.IO. I'm using latest React native and cli(just updated), and this is my code:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
window.navigator.userAgent = 'react-native';
const io = require('socket.io-client/socket.io');
const socket = io('localhost:3000', { jsonp: false });
socket.connect();
class wschat extends Component { ... }
You can see, the code is quite simple, and no error. This is my server code:
"use strict";
const express = require('express');
const app = express();
const http = require('http').Server(app);
const io = require('socket.io')(http);
http.listen(3000, () => {
console.log('WSChat Server for React-Native listening on port 3000');
});
io.on('connection', (socket) => {
console.log('connected: ' + socket.id);
});
Seems fine, and it is actually worked with ios, but not worked on android. I was enabled remote debugger, and checked the properties, and Socket.IO it self it was loaded well, but no connection was established. You can see the server code, when 'connection' event occured, logged on console.
I used AVD(nexus5) and my device(LG G4 optimus), but both won't worked. What am I missing? Any advice will be very appreciate it!

The VM react-native runs in isn't nodejs. This means you can't rely on packages such as socket.io-client that in turn rely on nodejs native modules (http, fs, crypto, etc)
I.e. socket.io-client relies on engine-i.o and there you will find stuff like:
var http = require('http');
What's devious is that as long as you're in dev-mode, iOS is backed by nodejs, so it may look like all is working, but if you compile the app, it won't.
Check out react-native-socketio, sadly (as of 2016-09-12) the project isn't well maintained, but it can be made to work.

If you want to use socket io for your react native project I would suggest you use feathers js socket io.
https://docs.feathersjs.com/api/socketio.html
This framework also supports Primus, Express, and REST so you got lots of options to choose from. Hope this will help.

Related

How do you shut down a stale Apollo-Client websocket connection?

I have a page that is loading connected apollo-client pages as widgets inside of a main page. My GraphQL server is self-hosted. They are served up through iFrame (self-hosted), connecting back to my own server. Communications are done through a 3rd party's iFrame communications SDK.
For some reason the widgets are not cleared out from the window when they are stale (I have no control over this). However I do have access to know when they are "stale". When they turn stale I want to disconnect / shutdown the websocket connection. The trouble is the still-connected clients are eating up my back-end's CPU. I am watching the websocket connection through chrome dev-tools. I notice every 5 seconds it sends a keep-alive request to the websocket sever. Every so often I see a stop request, and I want to figure out how to replicate that.
Im my react apollo-connected component I tried calling these two commands, but after they are called with no errors, the keep-alive flags are still being sent to the websocket server.
this.props.client.stop()
this.props.client.clearStore();
How do I tell the apollo-client to shut itself down?
For Apollo V3, the WebSocketLink has an internal SubscriptionClient instance, but the problem is that WebSocketLink doesn't expose methods that give you access to the SubscriptionClient instance, so there's no accessing SubscriptionClient.close(). Fortunately, WebSocketLink accepts a client as an argument:
const subscriptionClient = new SubscriptionClient(`wss://example.com/subscriptions`, {
// example options:
reconnect: true,
lazy: true,
connectionParams: () => ({ accessToken: 'secret' }),
});
const wsLink = new WebSocketLink(subscriptionClient);
Now you just need to move subscriptionClient into a context in order to gain access to the client in various places:
export const SubscriptionClientContext = createContext<
SubscriptionClient | undefined
>(undefined);
export const useSubscriptionClient = (): SubscriptionClient => {
const subscriptionClient = useContext(SubscriptionClientContext);
if (subscriptionClient === undefined) {
throw Error(
'SubscriptionClient not initiated, can only be called inside SubscriptionClientContext.Provider',
);
}
return subscriptionClient;
};
<SubscriptionClientContext.Provider value={subscriptionClient}>
<App />
</SubscriptionClientContext.Provider>
This will let you access methods on the client for logout behavior in various parts of the app:
const subscriptionClient = useSubscriptionClient();
subscriptionClient.close();
There are also two arguments for .close, that have various behaviors. E.g. close and reconnect, close and do not reconnect.

Is there analog of express's app.set( 'something', something ) in koa?

I need socket.io instance in several places in my app. To achieve this in express i can do this:
app.set('io', io);
In koa right now i have this:
app.use( async ( ctx, next ) => {
ctx.io = io;
await next();
});
This works, but this middleware executes every time my server recieves request. Is there a better way to do this?
I don't know how you are fully implementing but there are a couple things that you can do is you can either pass an addition argument and upgrade the connection to a websocket that will bypass the rest of the middlewares. Or, what I do personally is just have any websocket connection go to a different end point. This will help with any future scalability issues. for example, if you need to create clusters of your server then you will have more control as well will help you testing your backend easier. That's what I would do atleast. My socket.io back end looks like this:
server.ts
oh yea I'm using typescript in the back end
require('dotenv').config({ path: __dirname + '/.env' });
import Koa from 'koa';
const koa = new Koa();
import cors from '#koa/cors';
const PORT = process.env.CHAT_PORT || 3000;
const ENV = process.env.NODE_ENV || 'development';
const server = require('http').createServer(app, { origins: 'http://server.ip' });
const io = (module.exports.io = require('socket.io')(server));
import SocketManager from './lib/SocketManager';
app.use(
cors({
origin: '*',
optionsSuccessStatus: 200,
}),
);
// server setup
server.listen(PORT, (err: ErrorEvent): void => {
if (err) console.error('❌ Unable to connect the server: ', err);
console.log(`💻 Chat server listening on port ${PORT} - ${ENV} environment`);
});
io.on('connection', SocketManager);
then just create a socket manager that imports the io instance and you can then go ahead and handle all the connections.
I hope this is the answer you were looking for/gave you some better insight.

Connect to a sails.js instance via websockets

Is it possible to connect any external application to my sails.js application via WebSockets?
I can use the underlying socket.io embedded in sails.js to talk between the client and server, that's not a problem.
But, I would like to connect another, separate, application to the sails.js server via websockets, and have those two communicate with each other that way, and I am wondering if this is possible?
If so, how can we do this?
Thanks.
Based on SailsJS documentation, we have access to the io object of socket.io, via sails.io.
From that, I just adjusted boostrap.js:
module.exports.bootstrap = function (cb) {
sails.io.on('connection', function (socket) {
socket.on('helloFromClient', function (data) {
console.log('helloFromClient', data);
socket.emit('helloFromServer', {server: 'says hello'});
});
});
cb();
};
Then, in my other nodejs application, which could also be another SailsJS application and I will test that later on, I simply connected and sent a message:
var io = require('socket.io-client');
var socket = io.connect('http://localhost:3000');
socket.emit('helloFromClient', {client: 'says hello'});
socket.on('helloFromServer', function (data) {
console.log('helloFromServer', data);
});
And here are the outputs.
In SailsJS I see:
helloFromClient { client: 'says hello' }
In my client nodejs app I see:
helloFromServer { server: 'says hello' }
So, it seems to be working just fine.

socket.io-client keeping on connecting when using in react-native

I want to use the websocket in my RN project. And I did it using the ws at server side and the RN built-in websocket implementation.
But it seems not so convinient since I use socket.io before.
So I tried to use socket.io:
In RN:
import './userAgent'
import io from "socket.io-client/socket.io"
In component:
componentDidMount() {
this.socket = io('https://localhost:4080',{jsonp: false});
this.socket.on('hello', (msg) =>{
this.setState({response:msg})
});
}
In the server:
io.on('connection', function(socket){
socket.emit('hello','hello world')
console.log('a user connected');
socket.on('disconnect',function(){
console.log('user disconnected')
})
})
And in userAgent.js
window.navigator.userAgent = 'react-native';
That is just the result I googled and they said it will work. But for me, the chrome debugger stopped at:
function load() {
var r;
try {
r = exports.storage.debug;
} catch(e) {}
return r;
}
And it says the storage is not defined.
Then I looked into the socket.io.js and find that the exports.storage is window.localStorage. So I disabled the remote js debug, and the code began running.
But the server continues to log : a user connected . as if my RN app is keeping on connecting to the server. And it seems the socket.on() did not work at client side.
react-native version:0.27.2
socket.io-client version:1.4.8
Anyone knows where is going wrong?
Well,finally I found the solution after looking through the socket.io source.
It seems that the socket.io does not use 'websocket' as transport defaultly. It will use the 'polling' in my case, so just explicityly set it :
componentDidMount() {
var socket = io('http://localhost:4080', { jsonp: false, transports: ['websocket'] })
socket.on('hello', (msg) => {
//do something
});
}
Now it works.
But what still confuses me is that in brower client I do not set the transports and it just work well but in react-native it doesn't. Not figured out why.

React Native with socket.io doesn't work

i create simple socket.io server and react native project and tested, but socket.io on React Native doesn't work at all.
i printed "socket.io-client" on console and it's loaded well, and i made simple HTML file with using socket.io, it works, but only React Native doesn't work.
i'm using React native 0.26.2, and socket.io 1.4.6.
this is my server code:
"strict mode";
const express = require('express');
const app = express();
const http = require('http').Server(app);
const io = require('socket.io')(http);
io.on('connection', (socket) => {
console.log('user connected');
});
http.listen(3000, () => {
console.log('server started on 3000');
});
// web testing
app.get('/', (req, res, next) => {
res.sendFile(__dirname + '/index.html');
});
and this is rn code:
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, TextInput, TouchableHighlight, View } from 'react-native';
import "./userAgent"; //window.navigator.userAgent = "react-native";
const io = require('socket.io-client/socket.io');
class SocketChat extends Component {
constructor(props) {
super(props);
this.socket = io('localhost:3000', { jsonp: false });
this.state = {
text: null
};
}
...
}
as i heard, using React native with socket.io causes ajax long polling instead of websocket, so i added 'user-agent' trick. whether it is working or not, even connection isn't established, but if i try with browser, it works well. it will be very appreciate me that tell me what should i do.
I solved this by replacing another websocket module. Socket.IO doesn't work on Android and as someone said to me, Socket.io uses node native modules internally so it should be not working after build production app.

Resources