Yii2 send event from php to clients using yii2-nod-socket - javascript

I am using yii2-node-socket to send event to clients in a concrete room. I followed all steps to install the extension in my project, the server was started successfully and the client was connected to socket but when I tried to send event from php code the client did not receive any data.
Javascript code:
var socket = new YiiNodeSocket();
socket.onConnect(function () {
socket.room('testRoom').join(function (success, numberOfRoomSubscribers) {
// success - boolean, numberOfRoomSubscribers - number of room members
// if error occurred then success = false, and numberOfRoomSubscribers - contains error message
if (success) {
console.log(numberOfRoomSubscribers + ' clients in room: testRoom');
// do something
// bind events
this.on('join', function (newMembersCount) {
// fire on client join
});
this.on('data', function (data) {
// fire when server send frame into this room with 'data' event
console.log('in data : ', data);
});
} else {
// numberOfRoomSubscribers - error message
alert(numberOfRoomSubscribers);
}
});
});
PHP code:
// create frame
$frame = Yii::$app->nodeSocket->getFrameFactory()->createEventFrame();
// set event name
$frame->setEventName('data');
// set room name
$frame->setRoom('testRoom');
// set data
$frame['key'] = 'hello';
// send
$frame->send();

Related

SignalR javascript client not picking up event from hub

I have a method on the hub however I am not getting any messages from this. I get the connection ID's from my user to connectionid mapping dictionary and loop through these connectionid's and then invoke a method on the client side called deviceDiscovered I can also confirm that the browser does connect to the hub
Here is my hub method
public async Task DetectDevice(dynamic message)
{
//We will be searching via the userid
var connectionId = Context.ConnectionId;
//now we get the connectionID from the table.
var connectionObj = ConnectionTable[connectionId];
//we now check whether this is a pathfinder or browser client
if (connectionObj.clientType == "pathfinder")
{
/*The pathfinder initiated the request and so this means the message should be forwarded to the browser client
that requested this resource*/
//Grab the data out of the dictionary.
PathfinderDetection deviceDiscoveredNotification = JsonConvert.DeserializeObject<PathfinderDetection>(message);
var userId = deviceDiscoveredNotification.userId;
var sysInfo = deviceDiscoveredNotification.sysInfo;
var found = deviceDiscoveredNotification.data;
if (found == "FOUND")
{
var deviceId = deviceDiscoveredNotification.deviceID;
var connections = ConnectionTable.Where(val => val.Value.id == connectionObj.id).Select(key => key.Key).ToList();
foreach (string connection in connections)
{
Clients.Client(connection).deviceDiscovered(deviceId);
}
}
else
{
//call a method on client side.
Clients.Group(userId.ToString()).noDevice("NOTFOUND");
}
I can see that the deviceID variable is populated and that the connection exists, however not getting anything back from the hub when looking at the client
here is my client side code:
<script>
$(document).ready(function(){
var connection = $.hubConnection("http://localhost:59016");
var contosoChatHubProxy = connection.createHubProxy('metrics');
contosoChatHubProxy.on('taskAdded', function(data){
console.log(data);
});
contosoChatHubProxy.on('deviceDiscovered', function(data) {
console.log(data);
});
contosoChatHubProxy.on('taskUpdate', function(data){
console.log(data);
});
contosoChatHubProxy.on('noDevice', function(found) {
console.log(found);
});
});
</script>

Delay is socket.io event?

I created an ajax call to the IMBd database
// API Key
key = "4dba72b2-7558-4c0f-bd18-9ffcb0999c4e";
// Url
mainUrl = "http://api.myapifilms.com/imdb/top?token="+ key +"&format=json&data=0&start=1&end=250";
// API Call
var request = require('request');
request(mainUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Storing data in an object
var obj = JSON.parse(body), //JSON Parser
movieArray = obj.data.movies, //Creating Array
item = movieArray[randomMovieRank]; //Setting random movie variable
itermArray = [item.ranking,item.title,item.year];
console.log(itermArray);
io.sockets.emit("serverAnswer", {ranking: itermArray[0], title: itermArray[1], year: itermArray});
}
});
return false;
Followed up by:
socket.on("serverAnswer", function(data){
console.log(data.title);
});
The socket.on is called on the client side. The problem I am having is that it is pulling through the data very slowly if at all. The API is working as it is console logging correctly in terminal. But client side it sometimes pulls through ad sometimes doesnt. Is there something I am doing wrong?
EDIT:
Added pastebin: http://pastebin.com/TYHsqBmK
When you invoke the emit method, your client is not guaranteed connected,you can trigger the ajax event after the client connected or emit specified messages,such as
the server:
io.on('connection',function(socket){
if(movies !== null)
{
socket.emit("serverAnswer", {movies:movies});
}
else{
//1.ajax request IMDB resource
//2.set movies variables
//3.emit message
}
});
the client:
socket.on("serverAnswer", function(data){
console.log(data);
});

Unhandled ''error'' event in Node.JS

I'm trying to active an RFID reader through node.js and then send the tag back.
It works great. It reads the tag, responds with an ID, then send the ID to the pinging node client.
However, every time the node.JS program picks up a set of data from an RFID tag, after it sends, it closes down with the following error:
events.js:72
throw er; // Unhandled 'error' event
^
Error: EBADF, read
This causes the node process to quit all the time. What could be the problem here?
My code is the following;
// Socket.io server details
var io = require('socket.io').listen(3000);
// Serialport plugin declared and made a serialport variable
var serialport = require("serialport");
var SerialPort = serialport.SerialPort;
// Variable containing technical USB port details
var serialPort = new SerialPort("/dev/ttyUSB0",
{baudrate: 2400, parser: serialport.parsers.readline("\n")},
false); // this is the openImmediately flag [default is true]
io.sockets.on('connection', function (socket) {
console.log('user connected');
socket.on('ping', function (data) {
serialPort.open(function () {
// Open notification
console.log('open');
//Start listening
serialPort.on('data', function(data) {
// If content is empty, filter out
if (data.trim() !== '') {
line = data;
//Execute function again, get tag, handle tag and end process
serialPort.close(function () {
console.log('De uiteindelijke tag is ' + data);
console.log('Ping received with data: ' + data);
socket.emit('pong', data);
console.log('closing');
});
console.log('hallo');
}
});
});
});
});
Add a listener to handle the error in the serial port, like the code below:
serialPort.on('error', function(error) {
console.log('The error: '+error);
//...
});

Node.js calling a function from script to update UI

Here is my webserver:
var net = require('net');
var server = net.createServer(function(socket) {
socket.write('hello\n');
socket.write('world\n');
//RECEIVE PACKET ON SOCKET
socket.on('data', function(data) {
//socket.write(data);
//console.log(data);
testSocketData(data)
});
});
server.listen(8000);
And the method testSocketData(data) is located in file update_ui.js and does the following:
function testSocketData(test) {
$('#p1').text(test)
}
Where #p1 refers to the id of a paragraph element in my main.html. I know that my socket is working, however I get:
ReferenceError: testSocketData is not defined.
How can I simply pass off the data received from my node.js server to the rest of my web application?
You must move that method(with socket.on('data') as well) from the server to the client side. When you receive a message via socket, the p1 element will update its text too.
On the server you will still need to have a socket.on('data') to receive the messages from the client.
Edit:
Here is some code, a little bit changed from my comment below.
On server:
function computeSomeResults(data) {
// your logic here
}
socket.on('servermsg', function(data) {
var result = computeSomeResults(data);
socket.emit('clientmsg', result);
});
On client:
function testSocketData(test) {
$('#p1').text(test);
}
socket.on('clientmsg', function(data) {
testSocketData(data);
// emit something maybe?
}
Eventually, you may want to send something to the server:
$('#p1').on('click', function(){
socket.emit('servermsg', $(this).text());
});

Creating a map of ids to sockets and vice versa in Node.js

I'm trying to manage a bunch of socket connections. My app is basically an http server that receives posts and passes these along to a socket. When clients open a socket connection, they send a connect message with an id:
{"m":"connect","id":"1"}
The app then saves this id and socket in the id2socket and socket2id maps. On disconnect, the socket/id pair is deleted from the maps.
A post will also contain an id, which indicates the post data should be sent to the socket with that id.
That's great, and this works fine for a single open socket. However, when I have more than one socket open, and then I close a socket, that disconnect wipes everything from the map. I think my understanding of sockets in node is incomplete- is there only a single socket object that is used in the callback? Is there a better way to manage my open socket connections and ids?
start server:
>>node server.js
TCP server listening on 127.0.0.1:5280
HTTP server listening on 127.0.0.1:9002
telnet in:
>>telnet localhost 5280
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
{"m":"connect","id":"123"}
{"m":"connect","id":"123","success":"true"}
server after connection:
>>Connection from 127.0.0.1:57572
received data: {"m":"connect","id":"123"}
id: 1
m: connect
associating uid 1 with socket [object Object]
do a post:
python post.py {"foo":"bar"}
So this works fine for several open sockets (as long as 1 device is id 123, server has this hardwired for now). However, as soon as you close one connection all the socket connections are removed from the map.
Here's my code:
python script to do post:
import sys
import json
import httplib, urllib, urllib2
values = json.loads('{"foo":"bar"}')
headers = {"Content-type": "application/json"}
conn = httplib.HTTPConnection('127.0.0.1', 9002)
headers = {"Content-type": "application/json"}
conn.request("POST", "", json.dumps(values), headers)
response = conn.getresponse()
print "response.status: "+response.status
print "response.reason: "+response.reason
print "response.read: "+response.read()
conn.close()
node server (http and tcp), hardwired to send data to device '123' on post:
var net = require('net'); // tcp-server
var http = require("http"); // http-server
var qs = require('querystring'); // http-post
// Map of sockets to devices
var id2socket = new Object;
var socket2id = new Object;
// Setup a tcp server
var server_plug = net.createServer(function(socket) {
// Event handlers
socket.addListener("connect", function(conn) {
console.log("Connection from " + socket.remoteAddress + ":" + socket.remotePort );
});
socket.addListener("data", function(data) {
console.log("received data: " + data);
try {
request = JSON.parse(data);
response = request;
if(request.m !== undefined && request['id'] !== undefined){ // hack on 'id', id is js obj property
console.log("id: "+request['id']);
console.log("m: "+request.m);
if(request.m == 'connect'){
console.log("associating uid " + request['id'] + " with socket " + socket);
id2socket[request['id']] = socket;
socket2id[socket] = request['id'];
response.success = 'true';
} else {
response.success = 'true';
}
}
socket.write(JSON.stringify(response));
} catch (SyntaxError) {
console.log('Invalid JSON:' + data);
socket.write('{"success":"false","response":"invalid JSON"}');
}
});
socket.on('end', function() {
id = socket2id[socket]
console.log("socket disconnect by id " + id);
// wipe out the stored info
console.log("removing from map socket:"+socket+" id:"+id);
delete id2socket[id];
delete socket2id[socket];
});
socket.on('timeout', function() {
console.log('socket timeout');
});
});
// Setup http server
var server_http = http.createServer(
// Function to handle http:post requests, need two parts to it
// http://jnjnjn.com/113/node-js-for-noobs-grabbing-post-content/
function onRequest(request, response) {
request.setEncoding("utf8");
request.addListener("data", function(chunk) {
request.content += chunk;
});
request.addListener("end", function() {
console.log("post received!");
//console.log("Request received: "+request.content);
if (request.method == 'POST') {
//var json = qs.parse(request.content);
//console.log("Post: "+json);
// HACK TO TEST STUFF:
// send a message to one of the open sockets
try {
var socket = id2socket['123']; //hardwired
socket.write('{"m":"post"}');
} catch (Error) {
console.log("Cannot find socket with id "+'123');
}
}
});
}
);
// Fire up the servers
var HOST = '127.0.0.1';
var PORT = 5280;
var PORT2 = 9002;
server_plug.listen(PORT, HOST);
console.log("TCP server listening on "+HOST+":"+PORT);
server_http.listen(PORT2);
console.log("HTTP server listening on "+HOST+":"+PORT2);
Objects only take strings as keys for their properties. As your log shows, a socket object is converted into the string "[object Object]". As a result, socket #2 overwrites the id from socket #1 in the object, because all sockets are converted into the same string key. So, there is only one property in the object at all times, because all sockets come down to the same key. When you try to remove the id for socket #2, the single property is deleted and the object is empty.
You seem to want a custom property for each separate socket when used as a key. You can use WeakMaps for this. WeakMaps do allow objects as keys (as opposed to string-only keys), but as they're relatively new they may contain bugs at the moment.
(Note that the id2socket map can just be a plain object, because numbers are converted into strings just fine, and each number has its own, distinct string representation*.)
Using WeakMaps is as follows:
var socket2id = new WeakMap; // as if you were doing: var socket2id = {};
socket2id.set(socket, id); // as if you were doing: socket2id[socket] = id;
socket2id.get(socket); // as if you were doing: socket2id[socket];
socket2id.delete(socket); // as if you were doing: delete socket2id[socket];
Make sure to run with node --harmony (>= 0.7) or node --harmony_weakmaps (<= 0.6).
* 0 and -0 are exceptions, but you shouldn't be using -0 anyway because 0 === -0, so it's difficult to differ between them.

Categories

Resources