react-native WebSocket & nodejs WebSocket - node.js

NodeJS:
const WebSocket = require('ws');
const ws = new WebSocket('wss://siteurl');
ws.on('open', function open() {
ws.send('');
});
ws.on('message', function incoming(message) {
console.log(message);
});
react-native
let connection = new WebSocket('wss://siteurl');
connection.onopen = () => {
connection.send('');
};
connection.onmessage = ((event) => {
console.log(event);
});
connection.onerror = (event) => {
console.log(event);
}
NodeJS works fine, but react-native return 'Unable to resolve host'.
Android Stuio Emulator, started with npm run android.
Any ideas why it could happens?
UPD:
const socket = new WebSocket('wss://siteurl');
socket.onopen = () => {
console.log('Socket connected!');
socket.send('');
}
socket.onmessage = (message) => {
console.log(`Message:\n`, message.data);
}
```
Browser works fine too

You can use socket.io-client
socket.io-client Document
Example
// ES6 import or TypeScript
import { io } from "socket.io-client";
// CommonJS
const io = require("socket.io-client");
// the following forms are similar
const socket = io("https://server-domain.com");
const socket = io("wss://server-domain.com");
const socket = io("server-domain.com"); // only in the browser when the page is served over https
socket.on('message', (event) => {
console.log(event);
});

Related

Create a crypto payment forwarder

I am trying to make my own cryptocurrency payment forwarder, (like https://apirone.com/), but I am facing an issue, this is my code:
const CryptoAccount = require('send-crypto');
const WebSocket = require('ws');
const qrcode = require('qrcode-terminal');
const clipboardy = require('clipboardy');
const init = async function() {
const socket = new WebSocket('wss://ws.blockchain.info/inv');
const wallets = [];
socket.on('open', stream => {
console.log('WebSocket opened');
setInterval(() => socket.send(JSON.stringify({"op": "ping"})), 10000);
});
socket.on('error', err => {
console.error(err.message);
});
socket.on('message', stream => {
try {
const response = JSON.parse(stream.toString('utf-8'));
if (JSON.stringify(response).includes('pong')) {
console.log('pong');
return;
}
console.log('SOCKET RESPONSE', response);
let outAddr = response.x.out[0].addr;
wallets.find(w => w.addr == outAddr).callback(response);
} catch (error) {
console.error(error);
}
})
const generateWallet = function() {
const privateKey = CryptoAccount.newPrivateKey();
const account = new CryptoAccount(privateKey);
return account;
}
const genWalletAndWatch = async function(currency, callback) {
if (currency !== 'BTC') throw new Error('Only BTC is supported currently.');
const wallet = generateWallet();
wallets.push({addr: (await wallet.address('BTC')), callback});
socket.send(JSON.stringify({"op":"addr_sub", "addr": (await wallet.address(currency))}));
return (await wallet.address(currency));
}
socket.onopen = async function(e) {
const wallet = await genWalletAndWatch('BTC', (response) => {
console.log('ANSWER', JSON.stringify(response));
});
console.log(wallet);
qrcode.generate('bitcoin:'+wallet, {small: true});
clipboardy.writeSync(wallet);
}
};
init();
This is a test code so there is no any express server or forward for the moment, I am only trying to create a btc address then to detect when a payment is done, but my problem is: The payment is never detected by the WebSocket, i can create a wallet without problem, I can ping the blockchain.info WebSocket api successfully, but the "addr_sub" never works, I've tried to send BTC etc, nothing is working.

HTTPS over WebSockets tunnel

I'm trying to build a system in which the backend can send request to the client that will behave as a proxy. I'm constrained in using WebSockets due to the current state of the remote server. I've build a basic version of my idea that works with HTTP request sent from a browser, but as soon as I activate HTTPS it apparently fails on the handshake. I'm adding a request ID to organise and imitate the request/response model. I want to achieve an E2E encryption with this proxy chain.
This is my code for the proxy that catches the requests and sends them over the WebSocket:
const net = require('net');
const WebSocket = require('ws');
const crypto = require("crypto");
const wss = new WebSocket('ws://localhost:8001');
const server = net.createServer();
server.on('connection', (socket) => {
// settings per connection opened
let requests = [];
// Receives data
socket.on('data', data => {
const requestID = crypto.randomBytes(16).toString("hex");
const additionalInfo = JSON.stringify({
"Request": requestID,
});
const header = Buffer.from(`${additionalInfo.length} ${additionalInfo}\n\n`);
wss.send(Buffer.concat([header, data]));
requests.push(requestID);
});
socket.on('error', error => {
console.log(error);
});
socket.on('end', () => {
requests = [];
});
// server response to the request
wss.on('message', (data) => {
// extract basic data
const jsonDataSize = data.toString().split(' ')[0];
const jsonDataOffset = jsonDataSize.length + 1;
const jsonDataText = data.slice(jsonDataOffset, Number(jsonDataSize) + jsonDataOffset).toString();
const jsonData = JSON.parse(jsonDataText);
const message = data.slice(Number(jsonDataSize) + jsonDataOffset + 2);
// check if received response matches the request
if (requests.includes(jsonData.Request)) {
// console.log(data.toString());
socket.write(message);
}
});
wss.on('error', error => {
console.log(error);
});
});
server.on('close', () => {
console.log("Server closed");
})
server.listen({host: "localhost", port: 8000}, () => {
console.log("Server listening on localhost:8000");
});
This is my code for the WebSocket receiver:
const net = require('net');
const WebSocket = require('ws');
const wss = new WebSocket.Server({port: 8001}, () => {
console.log('WebSocket server listening on localhost:8001');
});
wss.on('connection', socket => {
let server;
// trigger for a new message from the same connection
socket.on('message', data => {
// console.log("---------->");
// console.log(data.toString());
const jsonDataSize = data.toString().split(' ')[0];
const jsonDataOffset = jsonDataSize.length + 1;
const jsonDataText = data.slice(jsonDataOffset, Number(jsonDataSize) + jsonDataOffset).toString();
// check if it is a new tls connection request
let isTLSConnection = data.toString().indexOf("CONNECT") !== -1;
// set the new connection's settings
if (isTLSConnection && data.toString().includes('Host: ')) {
const serverPort = 443;
const serverAddress = data
.toString()
.split("CONNECT")[1]
.split(" ")[1]
.split(":")[0];
server = net.createConnection({host: serverAddress, port: serverPort});
// Send back 200 OK to the browser
const header = Buffer.from(`${jsonDataSize} ${jsonDataText}\n\n`);
socket.send(Buffer.concat([header, Buffer.from("HTTP/1.1 200 OK\r\n\r\n")]));
return;
} else if (data.toString().includes('Host: ')) {
const serverPort = 80;
const serverAddress = data.toString().split('Host: ')[1].split("\r\n")[0];
server = net.createConnection({host: serverAddress, port: serverPort});
}
// extract payload
const message = data.slice(Number(jsonDataSize) + jsonDataOffset + 2);
// send payload to server
server.write(message);
server.on('data', (data) => {
// console.log("<----------");
// console.log(data.toString());
const header = Buffer.from(`${jsonDataSize} ${jsonDataText}\n\n`);
socket.send(Buffer.concat([header, data]));
});
server.on('error', error => {
console.log(error);
});
});
socket.on('error', (error) => {
console.log(error);
});
});
I took inspiration from Build your own proxy server from scratch
I tried implementing a request/response model on top of WebSockets since I believe the error relies there, but it didn't work
You should use wss://localhost:8001 when using https

Using Socket.io not working in React Native Mobile App

I have tried to connect socket with React Native mobile App.
Node server socket.io is working i have use with react web, But when i use React Native Mobile App there was not working
Client (React Native
import io from 'socket.io-client';
const ENDPOINT = "http://192.168.1.3:7000";
const socket = io(ENDPOINT, {transports: ['websocket']});
const getMessage = () => {
socket.on('getMessage', (data) => {
console.log('socket data', data);
})
};
const sendMessage = () => {
var userid = log.userid
var message = "msg from app"
socket.emit('send msg', { userid, message });
}
Server (Node Js)
const app = express();
const server = app.listen(7000);
const io = require('socket.io')(server, {
cors : {
origin:'*'
}
});
io.on("connection",(socket)=>{
socket.on('sendMessage',({userid, message})=>{
io.emit('getMessage',{userid, message});
})
})
dev! I solved this just not using socket.io. I got that Socket.io is not a good choice in mobile apps. Use WebSocket API instead.
REACT COMPONENT
import React from 'react';
import { View, Text } from 'react-native';
class WebSocketConnection extends React.Component {
constructor(props) {
super(props);
this.webSocket = this.webSocket.bind(this);
}
webSocket() {
const ws = new WebSocket('ws:172.16.20.201:8080');
ws.onopen = (e) => {
console.log('connected on wsServer');
}
ws.addEventListener('open', function (event) {
ws.send('Hello from React Native!');
});
ws.addEventListener('message', function (event) {
this.message = event.data;
console.log('Message from server ', event.data);
});
ws.onerror = (e) => {
console.log(e);
}
}
render() {
return (
<View>
<Text>
Socket.io YES
</Text>
</View>
)
}
componentDidMount() {
this.webSocket();
}
}
export default WebSocketConnection;
SERVER
/**
* Create WebSocket server.
*/
const WebSocket = require('ws');
const serverWs = new WebSocket.Server({
port: 8080
});
let sockets = [];
serverWs.on('connection', function(socket) {
sockets.push(socket);
console.log(`connectet client`);
// When you receive a message, send that message to every socket.
socket.on('message', function(msg) {
console.log(msg);
sockets.forEach(s => s.send(msg));
});
// When a socket closes, or disconnects, remove it from the array.
socket.on('close', function() {
sockets = sockets.filter(s => s !== socket);
});
});
While using Express, I bind this server inside /bin/www and work fine to me.
I was able to work when i changed the react-native to use the ws protocol. My code was as below
useEffect(()=>{
const socket = io("ws://localhost:3000");
socket.on("connect", () => {
console.log(socket.connected); // true
});
},[])

share mqtt client object between files

I connect to MQTT this way:
//mqtt.js
const mqtt = require('mqtt');
var options = {
//needed options
};
var client = mqtt.connect('mqtt://someURL', options);
client.on('connect', () => {
console.log('Connected to MQTT server');
});
I want to export the client object this way:
//mqtt.js
module.exports = client;
So that I can import it in other files and make use of it this way:
//anotherFile.js
const client = require('./mqtt');
client.publish(...)
However, we all know that this will not work! How can I achieve this ?
Update
I tried promise and get a very strange behavior. When I use the promise in the same file (mqtt.js) like the code below, everything is OK:
//mqtt.js
const mqtt = require('mqtt');
var mqttPromise = new Promise(function (resolve, reject) {
var options = {
//needed options
};
var client = mqtt.connect('mqtt://someURL', options);
client.on('connect', () => {
client.subscribe('#', (err) => {
if (!err) {
console.log('Connected to MQTT server');
resolve(client);
} else {
console.log('Error: ' + err);
reject(err);
}
});
});
});
mqttPromise.then(function (client) {
//do sth with client
}, function (err) {
console.log('Error: ' + err);
});
But when I export the promise and use it in another file, like this:
//mqtt.js
//same code to create the promise
module.exports = mqttPromise;
//anotherFile.js
const mqttPromise = require('./mqtt');
mqttPromise.then(function (client) {
//do sth with client
}, function (err) {
console.log('Error: ' + err);
});
I get this error:
TypeError: mqttPromise.then is not a function
You can probably achieve your goal creating 2 files, one for handling mqtt methods and another to manage the connection object.
Here's the file for the mqtt handler:
//mqttHandler.js
const mqtt = require('mqtt');
class MqttHandler {
constructor() {
this.mqttClient = null;
this.host = 'YOUR_HOST';
this.username = 'YOUR_USER';
this.password = 'YOUR_PASSWORD';
}
connect() {
this.mqttClient = mqtt.connect(this.host, {port: 1883});
// Mqtt error calback
this.mqttClient.on('error', (err) => {
console.log(err);
this.mqttClient.end();
});
// Connection callback
this.mqttClient.on('connect', () => {
console.log(`mqtt client connected`);
});
this.mqttClient.on('close', () => {
console.log(`mqtt client disconnected`);
});
}
// // Sends a mqtt message to topic: mytopic
sendMessage(message, topic) {
this.mqttClient.publish(topic, JSON.stringify(message));
}
}
module.exports = MqttHandler;
Now lets use the exported module to create a mqtt client connection on another file:
//mqttClient.js
var mqttHandler = require('./mqttHandler');
var mqttClient = new mqttHandler();
mqttClient.connect();
module.exports = mqttClient;
With this exported module you can now call your client connection object and use the methods created in the mqttHandler.js file in another file :
//main.js
var mqttClient = require('./mqttClient');
mqttClient.sendMessage('<your_topic>','<message>');
Although there may be a better method to perform your task, this one worked pretty well for me...
Hope it helps!
cusMqtt.js
const mqtt = require("mqtt");
function prgMqtt() {
const options = {
port: 1883,
host: "mqtt://xxxxxxx.com",
clientId: "mqttjs_" + Math.random().toString(16).substr(2, 8),
username: "xxxxxx",
password: "xxxxxx",
keepalive: 60,
reconnectPeriod: 1000,
protocolId: "MQIsdp",
protocolVersion: 3,
clean: true,
encoding: "utf8",
};
prgMqtt.client = mqtt.connect("mqtt://xxxxxxxx.com", options);
prgMqtt.client.on("connect", () => {
prgMqtt.client.subscribe("Room/Fan");
console.log("connected MQTT");
});
prgMqtt.client.on("message", (topic, message) => {
console.log("message is " + message);
console.log("topic is " + topic);
// client.end();
});
}
exports.prgMqtt = prgMqtt;
index.js/main program call
const { prgMqtt } = require("./startup/cusMqtt");
prgMqtt();
another .js
const { prgMqtt } = require("../startup/cusMqtt");
router.get("/:id", async (req, res) => {
prgMqtt.client.publish("Room/Reply", "Replied Message");
});

NodeJS + WS access currently running WS server instance

I have implemented a simple REST API using NodeJS, ExpressJS and routing-controllers. I have also implemented a basic WebSocket server running alongside the REST API and using WS.
const app = express();
app.use(bodyParser.json({limit: "50mb"}));
app.use(bodyParser.urlencoded({limit: "50mb", extended: true}));
useExpressServer(app, {
controllers: [
UserController
]
});
const server = app.listen(21443, (err: Error) => {
console.log("listening on port 21443");
});
const wss = new WebSocket.Server({server});
wss.on("connection", (ws: WebSocket) => {
ws.on("message", (message: string) => {
console.log("received: %s", message);
ws.send(`Hello, you sent -> ${message}`);
});
ws.send("Hi there, I am a WebSocket server");
});
My question is how to I get access to the currently running WS instance so that I am able to send or broadcast from my controller methods. I have a number of POST methods that run long processes and so return a HTTP 200 to the client, I then would like to either send or broadcast to all connected WS clients.
What is the correct way to access the WebSocket.Server instance from within my controller classes?
You can create the websocket earlier and pass the instance around:
const notifier = new NotifierService();
notifier.connect(http.createServer(app));
app.get("/somethingHappened", () => {
notifier.broadcast("new notification!!");
});
app.use(routes(notifier))
Full code:
app.js
Pass the websocket to the other routes:
const express = require("express");
const http = require("http");
const NotifierService = require("../server/NotifierService.js");
const routes = require("./routes");
const app = express();
const server = http.createServer(app);
const notifier = new NotifierService();
notifier.connect(server);
app.get("/somethingHappened", () => {
notifier.broadcast("new notification!!");
});
// to demonstrate how the notifier instance can be
// passed around to different routes
app.use(routes(notifier));
server
.listen(4000)
.on("listening", () =>
console.log("info", `HTTP server listening on port 4000`)
);
NotifierService.js class that handles the websocket
const url = require("url");
const { Server } = require("ws");
class NotifierService {
constructor() {
this.connections = new Map();
}
connect(server) {
this.server = new Server({ noServer: true });
this.interval = setInterval(this.checkAll.bind(this), 10000);
this.server.on("close", this.close.bind(this));
this.server.on("connection", this.add.bind(this));
server.on("upgrade", (request, socket, head) => {
console.log("ws upgrade");
const id = url.parse(request.url, true).query.storeId;
if (id) {
this.server.handleUpgrade(request, socket, head, (ws) =>
this.server.emit("connection", id, ws)
);
} else {
socket.destroy();
}
});
}
add(id, socket) {
console.log("ws add");
socket.isAlive = true;
socket.on("pong", () => (socket.isAlive = true));
socket.on("close", this.remove.bind(this, id));
this.connections.set(id, socket);
}
send(id, message) {
console.log("ws sending message");
const connection = this.connections.get(id);
connection.send(JSON.stringify(message));
}
broadcast(message) {
console.log("ws broadcast");
this.connections.forEach((connection) =>
connection.send(JSON.stringify(message))
);
}
isAlive(id) {
return !!this.connections.get(id);
}
checkAll() {
this.connections.forEach((connection) => {
if (!connection.isAlive) {
return connection.terminate();
}
connection.isAlive = false;
connection.ping("");
});
}
remove(id) {
this.connections.delete(id);
}
close() {
clearInterval(this.interval);
}
}
module.exports = NotifierService;
routes.js
const express = require("express");
const router = express.Router();
module.exports = (webSocketNotifier) => {
router.post("/newPurchase/:id", (req, res, next) => {
webSocketNotifier.send(req.params.id, "purchase made");
res.status(200).send();
});
return router;
};
List of connected clients are stored inside wss object. You can receive and loop through them like this:
wss.clients.forEach((client) => {
if (client.userId === current_user_id && client.readyState === WebSocket.OPEN) {
// this is the socket of your current user
}
})
Now you need to somehow identify your client. You can do it by assigning some id to this client on connection:
wss.on('connection', async (ws, req) => {
// req.url is the url that user connected with
// use a query parameter on connection, or an authorization token by which you can identify the user
// so your connection url will look like
// http://example.com/socket?token=your_token
ws.userId = your_user_identifier
....
})
To broadcast use:
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
If your controller and socket will be in different files (and I am sure they will), you will have to export the wss object in your socket file and import it in controller.

Resources