React Native WS
Real-time chat with Websockets
Zak Burki
23-03-2017
The Product




Real Time Chat for Networking at Conferences. Join conference channels. View people. Then 1-to-1 chat to them.
http://near.pro
The Brief
- Component UI Polish and Smoothness
- Real-Time Messaging (1-to-1 initially)
- Robust enough to support say approx 1,000 simultaneous chats.
- As Cheap as Possible. (Ruddy Clients)
Real-Time Options
XMPP Bosh
Websockets
MQTT
CoAP
Protocols
React Native

Node.js WS
Options
sockets.io
sails.js (node.js framework)
nodejs-websocket
websocket
express-ws
ws
General Design Thought
User
A
User
B
ChatRoom.
Conversation
ID
If User A sends a message in the chat room, and User B isn't connected - then send a Push notification instead.
Websocket Connection
Websocket Connection
Open a new websocket connection based on entry into conversation (chat-room) only.
Websocket Endpoint
ws endpoints instead of http
For example - ws://api.product.com/:conversationId?accessToken=MA_73XP87WG^oH[*bW12TpRXU;t$JD
var wsServer = require('./ws_routes/chat')(app,server,cookieParser,client);
config.ws + config.host + '/' + this.state.chatroomId + '?accessToken=' + this.state.token
RN Code:
Node Code:
Text
RN Websocket Client Code
this.ws.onmessage = (e) => {
// a message was received
console.log('Received: ' + e.data);
if (e.data != 'ping') {
this.setState({
messages: this.state.messages.concat([JSON.parse(e.data)])
});
this.updateListChats();
}
};
updateListChats: function() {
...
// get current chatlist
var chatList = this.props.tabBar.mountedComponents["chats"].state.chats;
var found = false;
// map through the collections
chatList.map(function(conversation) {
// if the current iterated conversation is the one you're in, update its last message with the newly sent/received one
if (conversation._id === $this.state.chatroomId) {
found = true;
conversation.lastMessage = $this.state.messages[$this.state.messages.length - 1];
}
return conversation;
});
...
}
Websocket Server Code
ws.on('message', function incoming(message) {
try {
var data = JSON.parse(message);
data['senderId'] = userData.userId;
console.log('Received Message: ', data); // JUST LOG THE MESSAGE ON THE SERVER
if (!data.senderId) {
console.log('Websocket Sending Error : no data.senderId');
return ws.send(JSON.stringify({
err: 'Sender is required'
}), function ack(wsError) {
if (wsError) console.log('Websocket Sending Error : no data.senderId', wsError);
});
}
var messageData = {
sender: data.senderId, // SHOULD BE FROM THE SESSION
message: data.message
} ...
Push Notifications
if (!isOnChatroom) {
// PUSH NOTIF HERE ON RECEIVER ONLY
userModel.getDeviceToken(receiverId, function(err, res) {
if (err) console.log('Cannot Find User');
if (!res) console.log('Cannot Find User');
//console.log('Receiver Token: ', results);
if (res.token) {
apnService.pushMessage(res.token, userData.name,
chatroomId, results, userData, function() {
console.log('Notification Sent');
});
}
});
}
Check to see if other person (recipient of broadcast) is in the room and has a ws connection...if not..send them a push notification.
Security Issues
Websocket Protocol is not as mature as HTTP and the security measures are not as robust.
- WSS (SSL)
- Avoid Tunnelling
- Validate Client/Server Input
- Authentication/Authorization
- Origin Header
Check out Heroku's Websocket Security Blog for the implementation details.
Next?
Extending it for Group Chat.
exports.leaveGroup = function(req,res,next){
var userId = JSON.parse(req.session.userSession).userId;
var input = req.body;
if(!input.groupId){
return res.status(400).send('Group id is required');
}
Group.update({_id:input.groupId},{$pull:{"members" : {"id": userId}}},function(err,g){
if(err) return res.status(400).send(err);
res.sendStatus(200);
});
}
More work required on the chat broadcasting logic within a group, but keep simple!
The End
Twitter: @zakburki
React Native Websockets
By Zak Burki
React Native Websockets
Code Share Mar 2017. Kennedy Town, Hong Kong.
- 3,516