If you need create more live application this extension helps you with it.
Based on nodejs socket.io library.
Features:
- yii2 supported from 2.0.1 release see on github
- emit events to all connected clients
- create rooms and emit events into some room
- set up data in nodejs memory from php and get in from javascript
- invoke any function or method of object in javascript (in window scope) from php
- browser support
Requirements ¶
OS: linux/unix/windows
git installed
Installation ¶
Install nodejs, if not installed see nodejs official site
Install extension
- Using git clone
$> git clone https://github.com/oncesk/yii-node-socket.git
Now go to the folder where you install extension application.ext.yii-node-socket and execute
$> git submodule init
$> git submodule update
Yii configuration
- Configure console command in (main/console.php). You can use config below:
'commandMap' => array(
'node-socket' => 'application.extensions.yii-node-socket.lib.php.NodeSocketCommand'
)
- Register Yii component, need to add into main.php and console.php:
'nodeSocket' => array(
'class' => 'application.extensions.yii-node-socket.lib.php.NodeSocket',
'host' => 'localhost', // default is 127.0.0.1, can be ip or domain name, without http
'port' => 3001 // default is 3001, should be integer
)
Install nodejs components in application.ext.yii-node-socket.lib.js.server:
$> npm install
Congratulation, installation completed!
Notice: if the name of the component will not be nodeSocket, your need to use special key in console command --componentName=component_name
Console command actions ¶
$> ./yiic node-socket # show help
$> ./yiic node-socket start # start server
$> ./yiic node-socket stop # stop server
$> ./yiic node-socket restart # restart server
$> ./yiic node-socket getPid # show pid of nodejs process
Javascript ¶
before work in javascript you need start server (./yiic node-socket start) and register clients scripts in PHP (see below, into PHP section)
// create object and connect to web socket server
var socket = new YiiNodeSocket();
// enable debug mode
socket.debug(true);
// add event listener
socket.on('updateBoard', function (data) {
// do any action
});
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: ' + roomId);
// 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
});
} else {
// numberOfRoomSubscribers - error message
alert(numberOfRoomSubscribers);
}
});
PHP ¶
Registering client scripts
Yii::app()->nodeSocket->registerClientScripts();
Frames ¶
Frame - data package for nodejs server wrapped into Class. Per one request to nodejs server you can send only 1 frame. For send several frames at a time use Multiple frame.
Frames:
- Event - send event to javascript
- Invoke - invoke javascript function or method of object in window scope
- PublicData - set up shared data into nodejs memory, any client can get it
- Multiple - needed for sending more several frames per a time
Event frame ¶
// create event frame
$frame = Yii::app()->nodeSocket->createEventFrame();
// set event name
$frame->setEventName('updateBoard');
// set data using ArrayAccess interface
$frame['boardId'] = 25;
$frame['boardData'] = $html;
// or you can use setData(array $data) method
// setData overwrite data setted before
$frame->send();
Set up shared data
¶
Notice: You can set expiration using setLifeTime(integer $lifetime) method of class PublicData
// create frame
$frame = Yii::app()->nodeSocket->createPublicDataFrame();
// set key in storage
$frame->setKey('error.strings');
// set data
$frame->setData($errorStrings);
// you can set data via ArrayAccess interface
// $frame['empty_name'] = 'Please enter name';
// set data lifetime
$frame->setLifeTime(3600*2); // after two hours data will be deleted from storage
// send
$frame->send();
Send event into room ¶
// create frame
$frame = Yii::app()->nodeSocket->createEventFrame();
// set event name
$frame->setEventName('updateBoard');
// set room name
$frame->setRoom('testRoom');
// set data
$frame['key'] = $value;
// send
$frame->send();
Invoke javascript function ¶
$invokeFrame = Yii::app()->nodeSocket->createInvokeFrame();
$invokeFrame->invokeFunction('alert', array('Hello world'));
$invokeFrame->send(); // alert will be showed on all clients
DOM manipulations with jquery ¶
Task: you need update price on client side after price update in each product
...
$product = Product::model()->findByPk($productId);
if ($product) {
$product->price = $newPrice;
if ($product->save()) {
$jFrame = Yii::app()->nodeSocket->createJQueryFrame();
$jFrame
->createQuery('#product' . $product->id)
->find('span.price')
->text($product->price);
$jFrame->send();
// and all connected clients will can see updated price
}
}
...
Send more than one frame per a time ¶
Example 1:
$multipleFrame = Yii::app()->nodeSocket->createMultipleFrame();
$eventFrame = Yii::app()->nodeSocket->createEventFrame();
$eventFrame->setEventName('updateBoard');
$eventFrame['boardId'] = 25;
$eventFrame['boardData'] = $html;
$dataEvent = Yii::app()->nodeSocket->createPublicDataFrame();
$dataEvent->setKey('error.strings');
$dataEvent['key'] = $value;
$multipleFrame->addFrame($eventFrame);
$multipleFrame->addFrame($dataEvent);
$multipleFrame->send();
Example 2:
$multipleFrame = Yii::app()->nodeSocket->createMultipleFrame();
$eventFrame = $multipleFrame->createEventFrame();
$eventFrame->setEventName('updateBoard');
$eventFrame['boardId'] = 25;
$eventFrame['boardData'] = $html;
$dataEvent = $multipleFrame->createPublicDataFrame();
$dataEvent->setKey('error.strings');
$dataEvent['key'] = $value;
$multipleFrame->send();
See github for more documentation above!
TODO ¶
- implement https (this is done but not commited, only for yii1 yet)
Superb Work!
I am so glad to start using this in my project. It was such a great idea to integrate Node.js and Socket.io with Yii. Kudos to YOU! Would you provide a demo, downloadable examples, or instructional videos to help with using this? Also this would be great to integrate with Yiinitializr advanced structure!
github
see github page, for more examples need more time but i do not have it) maybe later
https://github.com/oncesk/yii-node-socket/tree/0.1
Thank you
Okay Thanks!
I definitely understand these busy days. Well I appreciate your hard work, and I do thank you for what you have done!
On every $frame->(send)
On every $frame->(send) when I create an event for the client side to recognize, I am getting the below in my log file socket-transport.server.log
info: socket.io started
Listening localhost:3001
Set origin: localhost:*
debug: client authorized
info: handshake authorized uEY2xdiEL0O9GHY8HZH-
debug: setting request GET /socket.io/1/websocket/uEY2xdiEL0O9GHY8HZH-
debug: set heartbeat interval for client uEY2xdiEL0O9GHY8HZH-
debug: client authorized for
debug: websocket writing 1::
debug: client authorized for /server
debug: websocket writing 1::/server
info: transport end (undefined)
debug: set close timeout for client uEY2xdiEL0O9GHY8HZH-
debug: cleared close timeout for client uEY2xdiEL0O9GHY8HZH-
debug: cleared heartbeat interval for client uEY2xdiEL0O9GHY8HZH-
debug: discarding transport
debug: served static content /socket.io.js
I am using the exact code examples on branch 0.1
Is there something simple I am missing? Or can you lead me in the direction to rectify this? I've been trying to figure this out for a few days, and I am just not receiving anything on the client side.
Thanks so much for any help or comments.
seems like only one client connected
Hi, in your logs, your emit frame and only after that your page is loaded and client javascript can catch events, try open more then one page in your browser
All frames take effect to connected sockets
I thin, this helps you
Thank you.
A group within a room
I have a room set up and I have four clients that have joined the room. I understand that only one client can send a message event to all the others plus itself, but the others can not send message events for the room to see. My question: Is there a way for everyone in the room to send message events and everyone in the room see the messages (sort of like a group chat within that room only)?
hm, all clients in the room can send and catch events from any client in the room
if your clients connected in some room, clients can:
if this functionality did not works try create issue on github
And several days ago i update extension, see more on github, maybe it helps
Today i try test it again and give you more explanations
Thank you
Yes it works within same view file!
My prior inquiry was for a common room loaded within two different views. So I retested this for a common room loaded for the same view. It does work for the same view! So my question, is should it work for same room-different views also?
yes, it should works for different views
Yes, it should works for different views but for same rooms, in any view you can join into some room and send event into this room, in any view it should works!
How many clients are on
Hi once! On the server side, is there a way to find out if there is more than one client in any one room?
there is no way
Hello, i guess server side it's PHP?
in current version no ability to get number of connected clients, or clients in concrete room, but
On this week i try implement this.
Client.php missing
I went to https://github.com/oncesk/yii-node-socket/tree/0.1, dowloaded and extracted the archive ( git clone git@github.com:oncesk/yii-node-socket.git terminated with "Permission denied") but it seems like the required "yii-node-socket/lib/php/../vendor/elephant.io/lib/ElephantIO/Client.php" is missing ...
Hi, try with https
Hello
try this
Fix git clone
I am fix this
you can try again
~~~
>$ git clone https://github.com/oncesk/yii-node-socket.git
>$ cd yii-node-socket/
>$ git submodule init
>$ git submodule update
~~~
Undefined offset: 1
I'm trying to run the example provided and I get the following error when visiting sendEvent:
Undefined offset: 1 (/Users/mckracken83/Sites/GigaFIT-AWS/protected/extensions/yii-node-socket/lib/vendor/elephant.io/lib/ElephantIO/Client.php:325) Stack trace: #0 /Users/mckracken83/Sites/GigaFIT-AWS/protected/extensions/yii-node-socket/lib/php/frames/AFrame.php(76): YiiNodeSocket\Frames\Event->emit() #1 /Users/mckracken83/Sites/GigaFIT-AWS/protected/modules/gigafit/controllers/NodesockettestController.php(32): YiiNodeSocket\Frames\Event->send()
Can you provide ore information
Hello, can you provide more information.
Commands are not working (Server not starting :()
$> ./yiic node-socket # show help
$> ./yiic node-socket start # start server
$> ./yiic node-socket stop # stop server
$> ./yiic node-socket restart # restart server
$> ./yiic node-socket getPid # show pid of nodejs process
// GETTING THIS ERROR
Yii command runner (based on Yii v1.1.8)
Usage: ./yiic <command-name> [parameters...]
The following commands are available:
To see individual command help, use the following:
./yiic help <command-name>
Not working command, why?
Hello, did you add this code in config/console.php?
'commandMap' => array( 'node-socket' => 'application.extensions.yii-node-socket.lib.php.NodeSocketCommand' )
See commandMap
Error line
$sess = explode(':', $res); $this->session['sid'] = $sess[0]; Line 325-> $this->session['heartbeat_timeout'] = $sess[1]; $this->session['connection_timeout'] = $sess[2]; $this->session['supported_transports'] = array_flip(explode(',', $sess[3]));
Error cont.
I'm not sure about socket.io version - is there a minimum version that's required?
Yes i added
Yes i added this already
'commandMap' => array(
'node-socket' => 'application.extensions.yii-node-socket.lib.php.NodeSocketCommand'
)
but its not working :(
Still no dice?
I've got this set up to connect to a Nodejitsu socket.io server, and still getting this error. Is there something wrong with my elephant.io version?
Error cont.
looking in Firebug, it appears that my client is never connected:
1401342848310: Creating new event emitter with scope global client.js (line 37) GET http://mydomain.nodejitsu.com/socket.io/1/?t=1401342848316 200 OK 134ms socket.io.js (line 1659) 1401342848326: Attach event listener for event: invoke client.js (line 37) 1401342848328: Compiled event name: system:invoke client.js (line 37) 1401342848330: Attach event listener for event: jquery client.js (line 37) 1401342848332: Compiled event name: system:jquery client.js (line 37) 1401342848335: Attach event listener for event: updateBoard client.js (line 37) 1401342848337: Compiled event name: global:updateBoard client.js (line 37) 1401342848551: Creating new event emitter with scope room:myroom client.js (line 37) 1401342848553: Attach event listener for event: system:update.members_count client.js (line 37) 1401342848555: Compiled event name: room:myroom:system:update.members_count client.js (line 37) connecting... nodesockettest (line 163) GET http://mydomain.nodejitsu.com/socket.io/1/?t=1401343190413 200 OK 194ms socket.io.js (line 1659) connecting...
then nothing. I put some code in to be written to the console when the client connects and its never being written - so no connection. thoughts?
nodejitsu
Hi, so, can you show server logs?
And you can see socket.io version into node_modules/socket.io/package.json
command notworking
Hi, can you create other command for tests with command map?
Tell me,please, yii version and can you show your console.php config?
Check class path, maybe its invalid
Server log
My server logs show the following:
out Thu, 29 May 2014 14:45:40 GMT debug: websocket writing 7::/client:undefined out Thu, 29 May 2014 14:45:40 GMT debug: set heartbeat interval for client iBo7qBfaDhf-1jX5cYr5 out Thu, 29 May 2014 14:45:40 GMT debug: setting request GET /socket.io/1/websocket/iBo7qBfaDhf-1jX5cYr5 out Thu, 29 May 2014 14:45:40 GMT debug: client unauthorized for /client out Thu, 29 May 2014 14:45:40 GMT debug: websocket writing 1:: out Thu, 29 May 2014 14:45:40 GMT warn: handshake error NO COOKIE TRANSMITTED for /client out Thu, 29 May 2014 14:45:40 GMT debug: client authorized for out Thu, 29 May 2014 14:45:40 GMT debug: setting request GET /socket.io/1/websocket/5Gkyx96_LJ8ZzEbacYr4 out Thu, 29 May 2014 14:45:40 GMT debug: set heartbeat interval for client 5Gkyx96_LJ8ZzEbacYr4 out Thu, 29 May 2014 14:46:05 GMT debug: emitting heartbeat for client Z1UzPzyUnt05av7RcYr2 out Thu, 29 May 2014 14:46:05 GMT debug: websocket writing 2:: out Thu, 29 May 2014 14:46:05 GMT debug: set heartbeat timeout for client Z1UzPzyUnt05av7RcYr2 out Thu, 29 May 2014 14:46:05 GMT debug: cleared heartbeat timeout for client Z1UzPzyUnt05av7RcYr2 out Thu, 29 May 2014 14:46:05 GMT debug: got heartbeat packet out Thu, 29 May 2014 14:46:05 GMT debug: set heartbeat interval for client Z1UzPzyUnt05av7RcYr2 out Thu, 29 May 2014 14:46:05 GMT debug: emitting heartbeat for client 5CwW3_QpZIp3NW8RcYr3 out Thu, 29 May 2014 14:46:05 GMT debug: cleared heartbeat timeout for client 5CwW3_QpZIp3NW8RcYr3 out Thu, 29 May 2014 14:46:05 GMT debug: set heartbeat interval for client 5CwW3_QpZIp3NW8RcYr3 out Thu, 29 May 2014 14:46:05 GMT debug: set heartbeat timeout for client 5CwW3_QpZIp3NW8RcYr3 out Thu, 29 May 2014 14:46:05 GMT debug: emitting heartbeat for client 5Gkyx96_LJ8ZzEbacYr4 out Thu, 29 May 2014 14:46:05 GMT debug: set heartbeat timeout for client 5Gkyx96_LJ8ZzEbacYr4 out Thu, 29 May 2014 14:46:05 GMT debug: cleared heartbeat timeout for client 5Gkyx96_LJ8ZzEbacYr4 out Thu, 29 May 2014 14:46:05 GMT debug: set heartbeat interval for client 5Gkyx96_LJ8ZzEbacYr4 out Thu, 29 May 2014 14:46:05 GMT debug: set heartbeat timeout for client iBo7qBfaDhf-1jX5cYr5 out Thu, 29 May 2014 14:46:05 GMT debug: set heartbeat interval for client iBo7qBfaDhf-1jX5cYr5 out Thu, 29 May 2014 14:46:05 GMT debug: cleared heartbeat timeout for client iBo7qBfaDhf-1jX5cYr5 out Thu, 29 May 2014 14:46:05 GMT debug: emitting heartbeat for client iBo7qBfaDhf-1jX5cYr5 out Thu, 29 May 2014 14:46:30 GMT debug: emitting heartbeat for client Z1UzPzyUnt05av7RcYr2
handshake error
NO COOKIE TRANSMITTED
seems like you use cross domain request and cookie not transmitted
We need to define problem on your local server
CORS
How can I make this work with CORS?
Right now I have this:
// accept all connections from local server if (serverConfiguration.checkClientOrigin) { console.log('Set origin: ' + serverConfiguration.origin); log.info('Set origin: ' + serverConfiguration.origin); io.set("origins", serverConfiguration.origin); } // Enables CORS var enableCORS = function(req, res, next) { res.header('Access-Control-Allow-Origin', serverConfiguration.origin); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With'); // intercept OPTIONS method if ('OPTIONS' == req.method) { res.send(200); } else { next(); } }; // enable CORS! app.use(enableCORS);
Getting closer...
Instead of messing with CORS I just set up an A record so that my client and server are on the same domain. Which helped (no more "NO COOKIE TRANSMITTED" error) but now I'm seeing this in my server log:
out Thu, 29 May 2014 19:25:13 GMT warn: handshake error Have no session id for /client
DB sessions?
I'm using DB sessions and I think that's the problem - in firebug it looks like the session var name is "sessionid." Not sure where to adjust it though? I changed it in the server.config.js, and in NodeSocket.php and it doesn't seem to be helping?
session problems
Hi, you can set up your own session variable name, NodeSocket have variable
public $sessionVarName = 'PHPSESSID';
you can change it into your config, but need chane console and main configs
Session ID
I changed the value of the property like you advised, but it looks like for some reason the session ID isn't being passed as a parameter in the cookie. If I look at the cookie in Firebug, and I look at it in the server log, it looks like this:
fbm_111062145712496=base_domain=.mydomain.com; path=/
Correct me if I'm wrong but shouldn't there be another parameter like sessionid=foo?
Send a notification to a user outside of the room
Hi! I would like to send a user a notification/message even though he may be outside of the room. I am using createUserEventFrame(), but the user only gets the notification if he is inside of the room. If I am inside the room, is there a way to send a user an event frame no matter if he is inside of the room or outside of the room?
userEventFrame
Hi, i can not test it right now, but by the code you can send and catch it inside the room or outside
if outside code should be like that
var socket = new YiiNodeSocket(); socket.onConnect(function () { socket.on('user-event', function () { }); });
or inside
var socket = new YiiNodeSocket(); socket.onConnect(function () { socket.room('testRoom').join(function (success, numberOfRoomSubscribers) { if (success) { console.log(numberOfRoomSubscribers + ' clients in room: ' + roomId); // do something // bind events this.on('user-event', function (newMembersCount) { // fire on client join }); } else { // numberOfRoomSubscribers - error message alert(numberOfRoomSubscribers); } }); });
maybe this helps you
Re: userEventFrame
Thanks once! You are awesome :-)
It works! I had to put the on.socket frame script also on the outside the room page.
Node-socket doesn't seem to start
First of all thanks so much for this extension. I'm really excited to get it working. I'm having some issues getting the socket io server running. I followed all the stops above and it appears to have gotten installed. When I type ./yiic node-socket start is gives me these messages:
Compile server
Compile client
Starting server
Server successfully started
Update pid in file /Users/roger_obando/Clients/Baker/Development/yii/htdocs/protected/runtime/socket-transport.pid
But when I think go to stop the server it tells me that the server is already stopped. I verify this because when I attempt to access the server at http://localhost:3001/socket.io/socket.io.js I'm getting a "net::ERR_CONNECTION_REFUSED" error in my JS console.
Any ideas what might be happening?
hi
Hi, can you show me server logs from runtime folder, do notremember log file name ;)
Node-socket doesn't seem to start
I figured out the issue, once.
The issue appears to have been with this step: Install nodejs components in application.ext.yii-node-socket.lib.js.server:
It appears that when doing this step by simply using npm install on my Mac the node modules were not installed correctly. Once I went into the modules directory and manually installed all of the node modules then it started working fine. Thanks for your help!
;)
Good news) happy for you
Elephant.io handshake timeout
Now that I've got this working it really is fantastic, once! Thanks again. I'm seeing an issue in my production server that I wasn't seeing in my local environment that I was wondering if you had any experience with. Sometimes when Elephant.io is trying to emit an event and it goes to make the handshake with socket.io the connection times out. I was wondering if you'd come across this in the past. Thanks!
Issue on Yii 1.x
When i run command on Yii 1.14 its give me
PHP Fatal error: Class 'yii\console\Controller' not found in /var/www/taskewprod/protected/extensions/yii-node-socket/lib/php/NodeSocketCommand.php on line 13
wrong yii-node-socket version
Hi, you clone version of library for Yii2, you can checkout to 2.0.0
if you use clone via installation you can
$> cd protected/extensions/yii-node-socket/
$> git checkout 2.0.0
and check
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.