I am trying to develop a publish/subscribe application where a Java program is a publisher and nodejs program is a subscriber. The Java client connects to MQTT server and sends some random data. The NodeJS client should subscribe to the topic the java client has registered. I am getting the data from java client on to the NodeJS console, but I have to print that data asynchronously on a web page.
Here's the code I've written.
MqttPublishSample.java
public class MqttPublishSample {
public static void main(String[] args) {
String topic = "MQTT-Examples";
String content = "HelloWorld";
int qos = 2;
int i =0;
String broker = "tcp://localhost:1883";
String clientId = "JavaSample";
MemoryPersistence persistence = new MemoryPersistence();
try {
MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
System.out.println("Connecting to broker: " + broker);
sampleClient.connect(connOpts);
System.out.println("Connected");
while(i < 100)
{
int num = (int) (Math.random() * 2);
String text = content + num;
System.out.println("Publishing message: "+content+ " "+ num);
MqttMessage message = new MqttMessage(text.getBytes());
message.setQos(qos);
sampleClient.publish(topic, message);
System.out.println("Message published");
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// System.out.println("Publishing message: " + content);
/*sampleClient.disconnect();
System.out.println("Disconnected");
System.exit(0);*/
} catch (MqttException me) {
System.out.println("reason " + me.getReasonCode());
System.out.println("msg " + me.getMessage());
System.out.println("loc " + me.getLocalizedMessage());
System.out.println("cause " + me.getCause());
System.out.println("excep " + me);
me.printStackTrace();
}
}
}
app.js
var express = require('express');
var app = express();
app.get('/', function (req, res) {
client.on('connect', function() {
console.log("Connection Successful");
client.subscribe('MQTT-Examples');
});
var content;
client.on('message', function (topic, message) {
content = message;
console.log(message.toString());
});
res.render('index', { title: content });
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
I tried printing the message on the web page but I am unable to see any message.
I need to asynchronously print the data on the web page. Any help with how to proceed. Thanks!
try moving the line res.render('index', { title: content }); inside the callback for client.on e.g:
var express = require('express');
var app = express();
/*
* MQTT Client
*/
var content = ""; //buffer
client.on('connect', function() {
console.log("Connection Successful");
client.subscribe('MQTT-Examples');
});
client.on('message', function(topic, message) {
content += message.toString() + "<br>";
console.log(message.toString());
});
/*
* Express
*/
app.get('/', function(req, res) {
res.render('index', {
title: content
});
});
app.listen(3000, function() {
console.log('Example app listening on port 3000!');
});
Update
I did update to code, in the new code you will be able to see all messages received every time you reload the web page.
In the previous implementation was a kind of long polling, the resource will wait for a message from the broker.
Hope it helps.
Related
I'm running the below node-rdkafka code in Eclipse as Node.js application. This is the sample code from https://blizzard.github.io/node-rdkafka/current/tutorial-producer_.html
I want to run this in a test server and call from iOS Mobile application.
I knew about running node.js app in AWS.
Question I: Is there any other options to run in a free test server environment like Tomcat?
Question II: Even If I am able to run this node.js app in a server, how do i call from a mobile application? Do I need to call producer.on('ready', function(arg) (or) What function i need to call from Mobile app?
var Kafka = require('node-rdkafka');
//console.log(Kafka.features);
//console.log(Kafka.librdkafkaVersion);
var producer = new Kafka.Producer({
'metadata.broker.list': 'localhost:9092',
'dr_cb': true
});
var topicName = 'MyTest';
//logging debug messages, if debug is enabled
producer.on('event.log', function(log) {
console.log(log);
});
//logging all errors
producer.on('event.error', function(err) {
console.error('Error from producer');
console.error(err);
});
//counter to stop this sample after maxMessages are sent
var counter = 0;
var maxMessages = 10;
producer.on('delivery-report', function(err, report) {
console.log('delivery-report: ' + JSON.stringify(report));
counter++;
});
//Wait for the ready event before producing
producer.on('ready', function(arg) {
console.log('producer ready.' + JSON.stringify(arg));
for (var i = 0; i < maxMessages; i++) {
var value = new Buffer('MyProducerTest - value-' +i);
var key = "key-"+i;
// if partition is set to -1, librdkafka will use the default partitioner
var partition = -1;
producer.produce(topicName, partition, value, key);
}
//need to keep polling for a while to ensure the delivery reports are received
var pollLoop = setInterval(function() {
producer.poll();
if (counter === maxMessages) {
clearInterval(pollLoop);
producer.disconnect();
}
}, 1000);
});
/*
producer.on('disconnected', function(arg) {
console.log('producer disconnected. ' + JSON.stringify(arg));
});*/
//starting the producer
producer.connect();
First of all, you need an HTTP server. ExpressJS can be used. Then, just tack on the Express code basically at the end, but move the producer loop into the request route.
So, start with what you had
var Kafka = require('node-rdkafka');
//console.log(Kafka.features);
//console.log(Kafka.librdkafkaVersion);
var producer = new Kafka.Producer({
'metadata.broker.list': 'localhost:9092',
'dr_cb': true
});
var topicName = 'MyTest';
//logging debug messages, if debug is enabled
producer.on('event.log', function(log) {
console.log(log);
});
//logging all errors
producer.on('event.error', function(err) {
console.error('Error from producer');
console.error(err);
});
producer.on('delivery-report', function(err, report) {
console.log('delivery-report: ' + JSON.stringify(report));
counter++;
});
//Wait for the ready event before producing
producer.on('ready', function(arg) {
console.log('producer ready.' + JSON.stringify(arg));
});
producer.on('disconnected', function(arg) {
console.log('producer disconnected. ' + JSON.stringify(arg));
});
//starting the producer
producer.connect();
Then, you can add this in the same file.
var express = require('express')
var app = express()
app.get('/', (req, res) => res.send('Ready to send messages!'))
app.post('/:maxMessages', function (req, res) {
if (req.params.maxMessages) {
var maxMessages = parseInt(req.params.maxMessages);
for (var i = 0; i < maxMessages; i++) {
var value = new Buffer('MyProducerTest - value-' +i);
var key = "key-"+i;
// if partition is set to -1, librdkafka will use the default partitioner
var partition = -1;
producer.produce(topicName, partition, value, key);
} // end for
} // end if
}); // end app.post()
app.listen(3000, () => console.log('Example app listening on port 3000!'))
I don't think the poll loop is necessary since you don't care about the counter anymore.
Now, connect your mobile app to http://<your server IP>:3000/ and send test messages with a POST request to http://<your server IP>:3000/10, for example, and adjust to change the number of messages to send
I might be late on this but this is how I did using promises and found it better than have a time out etc.
const postMessageToPublisher = (req, res) => {
return new Promise((resolve, reject) => {
producer.connect();
producer.setPollInterval(globalConfigs.producerPollingTime);
const actualBody = requestBody.data;
const requestBody = req.body;
const topicName = req.body.topicName;
const key = requestBody.key || uuid();
const partition = requestBody.partition || undefined;
const data = Buffer.from(JSON.stringify(udpatedBody));
/**
* Actual messages are sent here when the producer is ready
*/
producer.on(kafkaEvents.READY, () => {
try {
producer.produce(
topic,
partition,
message,
key // setting key user provided or UUID
);
} catch (error) {
reject(error);
}
});
// Register listener for debug information; only invoked if debug option set in driver_options
producer.on(kafkaEvents.LOG, log => {
logger.info('Producer event log notification for debugging:', log);
});
// Register error listener
producer.on(kafkaEvents.ERROR, err => {
logger.error('Error from producer:' + JSON.stringify(err));
reject(err);
});
// Register delivery report listener
producer.on(kafkaEvents.PUBLISH_ACKNOWLEDGMENT, (err, ackMessage) => {
if (err) {
logger.error(
'Delivery report: Failed sending message ' + ackMessage.value
);
logger.error('and the error is :', err);
reject({ value: ackMessage.value, error: err });
} else {
resolve({
teamName: globalConfigs.TeamNameService,
topicName: ackMessage.topic,
key: ackMessage.key.toString()
});
}
});
});
};
Please note that kafkaEvents contains my constants for the events we listen to and it is just a reference such as kafkaEvents.LOG is same as event.log
and also the calling function is expecting this to a promise and accordingly we user .then(data => 'send your response to user from here') and .catch(error => 'send error response to user
this is how I achieved it using promises
I have opened the server.js and the address:http://localhost:8081 on my browser. But then a text "Upgrade Required" appeared at the top left conern of the website.
What is the problem of that? What else do I need to upgrade?
Here is the server.js:
var serialport = require('serialport');
var WebSocketServer = require('ws').Server;
var SERVER_PORT = 8081;
var wss = new WebSocketServer({
port: SERVER_PORT
});
var connections = new Array;
SerialPort = serialport.SerialPort,
portName = process.argv[2],
serialOptions = {
baudRate: 9600,
parser: serialport.parsers.readline('\n')
};
if (typeof portName === "undefined") {
console.log("You need to specify the serial port when you launch this script, like so:\n");
console.log(" node wsServer.js <portname>");
console.log("\n Fill in the name of your serial port in place of <portname> \n");
process.exit(1);
}
var myPort = new SerialPort(portName, serialOptions);
myPort.on('open', showPortOpen);
myPort.on('data', sendSerialData);
myPort.on('close', showPortClose);
myPort.on('error', showError);
function showPortOpen() {
console.log('port open. Data rate: ' + myPort.options.baudRate);
}
function sendSerialData(data) {
if (connections.length > 0) {
broadcast(data);
}
}
function showPortClose() {
console.log('port closed.');
}
function showError(error) {
console.log('Serial port error: ' + error);
}
function sendToSerial(data) {
console.log("sending to serial: " + data);
myPort.write(data);
}
wss.on('connection', handleConnection);
function handleConnection(client) {
console.log("New Connection");
connections.push(client);
client.on('message', sendToSerial);
client.on('close', function () {
console.log("connection closed");
var position = connections.indexOf(client);
connections.splice(position, 1);
});
}
function broadcast(data) {
for (c in connections) {
connections[c].send(data);
}
}
OK, websockets...
The "upgrade required" status marks the start of a websocket handshake. Normally your client sends this first to the WS server. The server answers in a pretty similar manner (details here : https://www.rfc-editor.org/rfc/rfc6455 ), and then proceed to pipe the actual data.
Here, you're opening a connection from your client as regular http, sending a simple GET. What you see on the screen is the server dumbly proceeding with an already corrupted handshake.
That's not how you open a WS client side connection. You don't usually open WS pages from the browser. It ought to be opened from a JavaScript call, such as new WebSocket(uri). So what you want is a regular http server on another port, that serves a page containing the necessary Javascript to open the actual WS connection and do something useful with its data. You'll find a clean example here : http://www.websocket.org/echo.html
I am developing chat based on websockets and webrtc. I would like to send messages to all connected users except sender but I cannot find suitable solution. To be more specific, I would like to send notifications to other connected users that new user has joined to the chat.
I am trying to give a unique ID to every connected user, but the first assigned ID is re-writed by every new user and I cannot diferentiate users.
Server:
// list of users
var CLIENTS=[];
var id;
// web server is using 8081 port
var webSocketServer = new WebSocketServer.Server({ port: 8081 });
// check if connection is established
webSocketServer.on('connection', function(ws) {
id = Math.random();
CLIENTS[id] = ws;
CLIENTS.push(ws);
ws.on('message', function(message) {
console.log('received: %s', message);
var received = JSON.parse(message);
if(received.type == "login"){
ws.send(message); // send message to itself
/* *********************************************************** */
/* *** Here I trying to check if message comes from sender *** */
sendNotes(JSON.stringify({
user: received.name,
type: "notes"
}), ws, id);
/* *********************************************************** */
}else if(received.type == "message"){
sendAll(message); // broadcast messages to everyone including sender
}
});
ws.on('close', function() {
console.log('user ' + CLIENTS[ws] + ' left chat');
delete CLIENTS[ws];
});
});
function sendNotes(message, ws, id) {
console.log('sendNotes : ', id);
if (CLIENTS[id] !== ws) {
console.log('IF : ', message);
for (var i = 0; i < CLIENTS.length; i++) {
CLIENTS[i].send(message);
}
}else{
console.log('ELSE : ', message);
}
}
function sendAll(message) {
for (var i=0; i < CLIENTS.length; i++) {
CLIENTS[i].send(message); // broadcast messages to everyone including sender
}
}
Client:
loginButton.addEventListener("click", function(){
name = usernameInput.value;
if(name.length > 0){
socket.send(JSON.stringify({
type: "login",
name: name
}));
}
});
function sendData() {
var data = dataChannelSend.value;
var userName = document.getElementById('greetingUser').innerHTML;
socket.send(JSON.stringify({
username : userName, // fetch user name from browser, after login
type : "message",
message : data
}));
}
socket.onmessage = function(message) {
var envelope = JSON.parse(message.data);
switch(envelope.type) {
case "login":
onLogin(envelope);
break;
case "message":
showMessage(envelope);
break;
}
};
I would highly appreciate If you could give me any hint. Thanks
Here is a very simple way of sending to everyone connected except the sender.
Create a broadcast function on your webSocketServer instance that will
take two params.
...
var webSocketServer = new WebSocketServer.Server({ port: 8081 });
...
/*
* method: broadcast
* #data: the data you wanna send
* #sender: which client/ws/socket is sending
*/
webSocketServer.broadcast = function(data, sender) {
webSocketServer.clients.forEach(function(client) {
if (client !== sender) {
client.send(data)
}
})
}
...
// On your message callback.
ws.on('message', function(message) {
...
// Note that we're passing the (ws) here
webSocketServer.broadcast(message, ws);
})
That's it, the broadcast method will send to each connected client
except the one who is sending.
Ok, so we are now storing the CLIENTS in a way that allows us to uniquely identify each client that is connecting, and store arbitrary information about them for later retrieval.
The code below will send the "notes" message to all clients, and THEN add the newly connecting client to the "all clients" list.
SERVER.JS:
var http = require('http'),
Static = require('node-static'),
WebSocketServer = new require('ws'),
// list of users
/*
We are now storing client data like this:
CLIENTS = {
uniqueRandomClientID: {
socket: {}, // The socket that this client is connected on
clientDetails: { // Any details you might wish to store about this client
username: "",
etc: "etc"
}
}
};
So now to get at the socket for a client, it'll be: CLIENTS[uniqueRandomClientID].socket.
Or to show a client's username, it'll be: CLIENTS[uniqueRandomClientID].clientDetails.username.
You might want to write a 'getClientByUsername' function that iterates the CLIENTS array and returns the client with that username.
*/
CLIENTS = {},
// web server is using 8081 port
webSocketServer = new WebSocketServer.Server({ port: 8081 });
// check if connection is established
webSocketServer.on('connection', function(ws) {
console.log('connection is established');
// Now using a randomly generated ID to reference a client. Probably should be better than Math.random :D
var wsID = Math.floor(Math.random() * 1000);
ws.on('message', function(message) {
console.log('received: %s', message);
var received = JSON.parse(message);
if(received.type == "login"){
// If a client with this login name doesnt exist already, its a new client
if(!CLIENTS[wsID]) {
doBroadcast(
{
"newuser": received.name,
type: "notes"
}
);
// Now add this new client to the list
CLIENTS[wsID] = {
socket: ws,
clientDetails: {
username: received.name
}
};
}
} else if(received.type == "message") {
doBroadcast(message); // broadcast messages to everyone including sender
}
});
ws.on('close', function(_event) {
if(CLIENTS[wsID]) {
console.log('user ' + CLIENTS[wsID].clientDetails.username + ' left chat');
delete CLIENTS[wsID];
}
});
/*
* Added this to 'catch' errors rather than just red dump to console. I've never actually done anything with this myself (I *like* red text in my console), but I know this handler should be here :P
*/
ws.on('error', function(_error) {
console.log("error!");
console.log(_error);
});
/*
* Send an object to a client
*
* #param WebSocketClient _to - The client you want to send to (generally an index in the CLIENTS array, i.e CLIENTS["bobsusername123"]
* #param Object _message - A stringifyable JSON object. Complex ones can screw things up, but your basic key/value pairs are usually fine to send.
*/
function doSend(_to, _message) {
_to.send(JSON.stringify(_message));
};
// Added broadcast function to replace sendAll
// Notice how it JSON stringifies the data before sending
/*
* Broadcast a message to all clients
*
* #param Object _message - A stringifyable JSON object. Complex ones can screw things up, but your basic key/value pairs are usually fine to send.
*/
function doBroadcast(_message) {
for(var client in CLIENTS) {
if(!CLIENTS.hasOwnProperty(client)) continue;
doSend(CLIENTS[client].socket, _message);
}
};
});
var fileServer = new Static.Server('.');
http.createServer(function (req, res) {
fileServer.server(req, res);
}).listen(8080, function(){
console.log("Server is listening 8080 port.");
});
console.log("Server is running on 8080 and 8081 ports");
MY CLIENT.JS (for your reference):
var loginButton = document.getElementById("loginbutton"),
usernameInput = document.getElementById("usernameInput");
var SocketClient = function(_uri, _callbacks) {
this.uri = _uri;
this.callbacks = _callbacks;
};
SocketClient.prototype = {
send: function(_message) {
this.socket.send(_message);
},
connect: function() {
try {
this.socket = new WebSocket("ws://" + this.uri);
} catch(e) { return false; }
for(var callback in this.callbacks) {
if(!this.callbacks.hasOwnProperty(callback)) continue;
this.socket["on" + callback] = this.callbacks[callback];
}
return true;
}
};
var socketClient = new SocketClient(
"127.0.0.1:8081",
{
open: function() {
console.log("connected.");
},
message: function(_message) {
console.log("received data:");
console.log(_message);
},
close: function() {
console.log("closed.");
},
error: function(_error) {
console.log("error: ");
console.log(_error);
}
}
);
socketClient.connect();
loginButton.addEventListener("click", function(){
name = usernameInput.value;
if(name.length > 0){
socketClient.send(JSON.stringify({
type: "login",
name: name
}));
}
});
AND THE CLIENT.HTML TO GO WITH IT:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<input type="text" id="usernameInput"/>
<button type="button" id="loginbutton">Login</button>
<script src="client.js"></script>
</body>
</html>
Ive tested this with NWJS v0.12.3 running the server and Firefox on the client.
This should work
const WebSocket = require('ws');
// Websocket variables
const wss = new WebSocket.Server({
port: 3000
});
console.log('Websocket active on port 3000...');
// New WebSocket Connection
wss.on('connection', function connection(ws) {
console.log('new connection')
// On Message Received
ws.on('message', function incoming(message) {
console.log(message)
// Send To Everyone Except Sender
wss.clients.forEach(function(client) {
if (client !== ws) client.send(message);
});
});
});
In Laravel 5 not implemented ShouldBroadCast method, any idea how I can implement it manualy?
Here is my try.
This is handler for ProjectNotificationEvent:
<?php namespace App\Handlers\Events;
use App\Events\ProjectNotificationEvent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;
use App\Notification;
use Illuminate\Support\Facades\Redis;
class NotifyUserAboutGroup {
CONST CHANNEL = 'update.group';
public function handle(ProjectNotificationEvent $event)
{
foreach ($event as $events){
$redis = Redis::connection();
$redis->publish(self::CHANNEL, $events->name);
}
}
}
This is node.js:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();
redis.subscribe('update.group', function(err, count) {
});
redis.on('message', function(channel, message) {
console.log('Message Recieved: ' + message);
message = JSON.parse(message);
io.emit(channel + ':' + message.event, message.data);
});
http.listen(3000, function(){
console.log('Listening on Port 3000');
});
And on client side in my view I have this:
var socket = io.connect('127.0.0.1:3000');
socket.on("update.group:App\\Events\\ProjectNotificationEvent", function(message){
// increase the power everytime we load test route
console.log(message);
});
Problem is on client side console.log don't return anything.
Any solution for this?
var socket = io.connect('127.0.0.1:3000');
socket.on('message', function (data) {
console.log(data);
});
Please try this
I am using Node Restify Module to create a REST service that accepts POST. Within the service I am trying to create a Sandboxed process using Node Sandbox module because we will be running dynamically inserted Javascript and if something goes wrong, I dont want it to affect the main Node instance.
When I try to create the Sandbox, something goes wrong and causes the REST service to come back empty.
Here is my code
var restify = require('restify');
var Sandbox = require("sandbox");
var logic;
function createSandbox(body) {
var s = new Sandbox();
s.run("1 + 1", function(output) {
logic = body.names + " has " + output.result;
});
}
function respond(req, res, next) {
createSandbox(req.body);
res.send(logic);
}
var server = restify.createServer();
server.use(restify.bodyParser({
mapParams: false
}));
server.post('/hello/:name', respond);
server.head('/hello/:name', respond);
server.listen(8080, function() {
console.log('%s listening at %s', server.name, server.url);
});
In my http request I have {"names":"rob"} in the body
I am expecting the following response
rob has 2
------------UPDATE-------------------
This works
var restify = require('restify');
var Sandbox = require("sandbox");
var logic;
function respond(req, res, next) {
var s = new Sandbox();
s.run("1 + 1", function(output) {
logic = req.body.names + " has " + output.result;
res.send(logic);
});
}
var server = restify.createServer();
server.use(restify.bodyParser({
mapParams: false
}));
server.post('/run/:id', respond);
server.head('/run/:id', respond);
server.listen(8080, function() {
console.log('%s listening at %s', server.name, server.url);
});
Sandbox.run() is asyncronous. It just sets the sandbox up to run at a later time and returns immediately before the code it sandboxes is actually run, so you're reading logic before it's set.
A quick demo;
var Sandbox = require("sandbox");
function createSandbox() {
var s = new Sandbox();
s.run("1 + 1", function(output) {
console.log("inside");
});
}
createSandbox();
console.log("outside");
> outside
> inside