i have a web application developed in codeigniter php and an android app for event management what i want to do is that whenever admin on web create an event a notification should be generated and shown into android app so all the user with android app can receive that notification without any interrupt.
so any one have idea how i can achieve this feature??
i am thinking of using web socket but i dont have any idea about it in codeigniter and android so any kind of suggestion will be helpful.
I would use the following components:
ZeroMQ for passing the messages http://zeromq.org
Ratchet for web-socket server http://socketo.me
Autobahn for web-socke client http://autobahn.ws/android/
I have no clue as to what you could use on the android side to subscribe to the web-service server.
The code is fairly simple, here is an example of something i use in my project.
Web-socket server:
composer.json
{
"autoload": {
"psr-0": {
"MyApp": "src"
}
},
"require": {
"cboden/ratchet": "0.3.*",
"react/zmq": "0.2.*|0.3.*"
}
}
push-server.php
<?php
require dirname(__DIR__) . '/vendor/autoload.php';
$loop = React\EventLoop\Factory::create();
$pusher = new MyApp\Pusher;
// Listen for the web server to make a ZeroMQ push after an ajax request
$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
// I assume the codeigniter installation and this server
// will be on the same host, hence 127.0.0.1
$pull->bind('tcp://127.0.0.1:5555');
$pull->on('message', array($pusher, 'onMessage'));
// Set up our WebSocket server for clients wanting real-time updates
$webSock = new React\Socket\Server($loop);
$webSock->listen(8081, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new Ratchet\Server\IoServer(
new Ratchet\Http\HttpServer(
new Ratchet\WebSocket\WsServer(
new Ratchet\Wamp\WampServer(
$pusher
)
)
), $webSock
);
$loop->run();
Then in codeigniter you can use the following to send messages:
$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'pusher');
$zmq_srv = 'your.domain.com:5555';
$socket->connect("tcp://" . $zmq_srv);
$messageContent = array(
'user' => 'username',
'type' => 'success',
'message' => 'Hi this is a test message.',
);
$socket->send(json_encode($messageContent));
I use this above to send messages to particular user, but if you make a new channel to which all your users are connected then all of them would receive a message.
My web based app uses http://autobahn.ws/js/ in the views to subscribe to the web-socket feeds. I see it has android implementation as well, but i've never tried that one: http://autobahn.ws/android/
This is the sample code from one of my views in case it is useful to you:
<script src="http://autobahn.s3.amazonaws.com/js/autobahn.min.js"></script>
<script>
var conn = new ab.Session('ws://your.domain.com:8081',
function () {
// Subscribe to the "username" channel
// For each user this would be their own channel to receive notifications
// for their own events, like successful file generation..
// file upload, etc...
conn.subscribe('username', function (topic, data) {
$.simplyToast(data.message, type = data.type, delay = 8000);
});
// Subscribe to "system" channel.
//In my app all users are subscribed to this one to receive system-wide
// notifications.
conn.subscribe('system', function (topic, data) {
$.simplyToast(data.message, type = data.type, delay = 8000);
});
},
function () {
console.warn('WebSocket connection closed');
},
{'skipSubprotocolCheck': true}
);
</script>
Related
I followed this tutorial socketo/push to push messages from the server to the client in real time. I'm using the CodeIgniter framework. These are my files:
push-server.php
$loop = React\EventLoop\Factory::create();
$pusher = new MyApp\Pusher;
// Listen for the web server to make a ZeroMQ push after an ajax request
$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means
// the only client that can connect
// is itself
$pull->on('message', array($pusher, 'onMessage'));
// Set up our WebSocket server for clients wanting real-time updates
$webSock = new React\Socket\Server('0.0.0.0:8080', $loop);
/*
$webSock->listen(8080, '0.0.0.0'); // Binding to 0.0.0.0 means
// remotes can connect
*/
$webServer = new Ratchet\Server\IoServer(
new Ratchet\Http\HttpServer(
new Ratchet\WebSocket\WsServer(
new Ratchet\Wamp\WampServer(
$pusher
)
)
),
$webSock
);
$loop->run();
I commented the $webSock->listen() line because it was throwing an error and in a git issue someone has commented that this was because an update in the react/zmq library, so that is the only line different to the tutorial.
controller.php
public function post()
{
$entryData = array(
'category' => 'kittensCategory',
'title' => 'Title'
);
$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher');
$socket->connect("tcp://localhost:5555");
$socket->send(json_encode($entryData));
}
This is the function that I'm calling and that should push a message to my pusher class but it does nothing.
I don't know what's the problem, my client is connecting correctly and the pusher is working good in the subscription method, so it has to be something in the push or the pull.
I have been trying to solve this for 2 weeks now but I don't have a clue, any comment would be awesome, thanks.
I'm a beginner in PHP Websockets and I'm trying to create real-time chat with database storage. I was doing pretty good, but now I'm standing at one problem. There's problem, when user1 sends message to user2 and user2 came to the site first (reload first on localhoste), it won't be "real-time".
Let me explain it further.
Here's my server.php. It is practicly the same as ratchet tutorial:
$loop = React\EventLoop\Factory::create();
$pusher = new \Pusher();
$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means the only client that can connect is itself
$pull->on('message', array($pusher, 'onBlogEntry'));
$webSock = new React\Socket\Server($loop);
$webSock->listen(8080, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new Ratchet\Server\IoServer(
new Ratchet\Http\HttpServer(
new Ratchet\WebSocket\WsServer(
new Ratchet\Wamp\WampServer($pusher ))), $webSock);
$loop->run();
In pusher.php are most important these methods (I omitted other non-important stuff):
protected $subscribedTopics = array();
protected $myID = array();
public function onSubscribe(ConnectionInterface $conn, $data) {
$this->subscribedTopics[json_decode($data)->teamID] = $data;
$this->myID[json_decode($data)->userID] = $data;
}
public function onBlogEntry($entry) {
$entryData = json_decode($entry, true);
if ((!array_key_exists($entryData['team_id'], $this->subscribedTopics)) ||
(!array_key_exists($entryData['to_user_id'], $this->myID))
) {
return;
}
$teamID = $this->subscribedTopics[$entryData['team_id']];
$teamID->broadcast($entryData);
}
In my presenter Class I have simple form. When user submits this form, this code follows:
$this->chatPartner = $values['to_user_id']; //this I get from the form
$this->redrawControl('msg'); //here I redraw my layout
$this->messages_model->addMessage($values); //here I send data to database
$context = new \ZMQContext();
$socket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'my pusher');
$socket->connect("tcp://localhost:5555");
$socket->send(json_encode($values));
Then, in view I have this JavaScript code:
var myJSON = '{'
+ '"teamID" : {$teamId},' //this I get from the presenter
+ '"userID" : {$userId}' //this I get from the presenter
+ '}';
var conn = new ab.Session('ws://localhost:8080',
function() {
conn.subscribe(myJSON, function(topic, data) {
if (data.from_user_id == mypartnerIdA) {
//here I edit the DOM
}
});
},
function() {
console.warn('WebSocket connection closed');
},
{'skipSubprotocolCheck': true}
);
So, back to my problem. I simulate 2 users. User1 reloads this page, where is javascript connection first. User2 reloads this page after him. When User1 sends a message to user2, message appers immediatly (real-time). But when user2 sends a message to user1, this message doesn't appear immediatly - it appears only after next reload of the page.
And my question is - How to fix this? How to make user2's message real-time, too? How can I fix this my code?
You probably have a misunderstanding of what the data yous end to subscribe is.
It is meant to use for ID's of chat sessions.
for example:
A has a chat with B (chatId = 1)
B has a chat with C (chatId = 2)
C has a chat with A (chatId = 3)
A, B and C are in one chat (chatId = 4)
var chatId = 2; //this chat is only between users B and C
conn.subscribe( chatId , function(topic, data) {
...
}
The easiest way for me to understand it was by comparing it to a hashtag on twitter.
Each hashtag is in your case a chatId.
And for each subscription to a hashtag/chatId. You will have a WebSocket connection so that you receive all the updates for it.
This will be an easier way to do this in the long run then by having subdivided connections for a userId parameter.
It can also easily be stored in a database so that you know whom to send the messages to and who not.
I'm trying to get a request to my server via a websocket, and return a reply from the server. This is "sort of" working, however I can only do this once, any extra requests just hang somewhere.
Server Bind:
$pull = $context->getSocket(ZMQ::SOCKET_REP);
$pull->bind('tcp://127.0.0.1:5552');
$pull->on('message', array($pusher, 'onPull'));
$pull->recv();
$pull->send('back');
I have a static PHP file on my server, which when I run, want to return the reply from the server:
$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_REQ, 'Sock');
$socket->connect("tcp://localhost:5552");
$socket->send('sending');
$message = $socket->recv();
echo "$message";
Now when I boot the server and run my php file, I get the "back" response back. However when I try to run it again it just hangs. I'm receiving the request each time?
Also, can anyone explain the $pull->on bit to me, I cannot find anywhere what it does.
Full server code:
<?php
require './vendor/autoload.php';
$loop = React\EventLoop\Factory::create();
$pusher = new MyApp\Pusher;
$context = new React\ZMQ\Context($loop);
$push = $context->getSocket(ZMQ::SOCKET_PULL);
$push->bind('tcp://127.0.0.1:5555');
$push->on('message', array($pusher, 'onNewPush'));
$pull = $context->getSocket(ZMQ::SOCKET_REP);
$pull->bind('tcp://127.0.0.1:5552');
$pull->on('message', array($pusher, 'onPull'));
$pull->recv();
$pull->send('back');
$webSock = new React\Socket\Server($loop);
$webSock->listen(8080, '0.0.0.0');
$webServer = new Ratchet\Server\IoServer(
new Ratchet\Http\HttpServer(
new Ratchet\WebSocket\WsServer(
$pusher
)
),
$webSock
);
$loop->run();
I think something like this should do the job:
$pull->on(
'message',
function ($message) use ($pull) {
$pull->send('response');
}
);
In any case, whether you use an anonymous function like above or an object/method pair, you need access to $pull, because that is the communication channel that allows you to send messages. The example at http://socketo.me/docs/push, which seems to be the base of your code, doesn't need that, since it uses a pull socket, which only receives messages.
im working on a PHP project based on Symfony 2.2.11 and I installed the socketo related to the following tutorial http://socketo.me/docs/install to make my chat script working.
ServerCommand.php // Code of the command line that starts the WebSocket server
$oLoop = Factory::create();
// Listen for the web server to make a ZeroMQ push after an ajax request
$oContext = new Context($oLoop);
$oPull = $oContext->getSocket(\ZMQ::SOCKET_PULL);
// LET IT 127.0.0.1
$oPull->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means the only client that can connect is itself
$oPull->on('message', array($oChat, 'onMessage'));
// Set up our WebSocket server for clients wanting real-time updates
$oWebSock = new Server($oLoop);
$oWebSock->listen(7979, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new IoServer(
new HttpServer(
new WsServer(
new WampServer(
$oChat
)
)
),
$oWebSock
);
$oLoop->run();
After a message is being added to database :
MessagesController.php
....
// This is our new stuff
$oContext = new \ZMQContext();
$oSocket = $oContext->getSocket(\ZMQ::SOCKET_PUSH, 'PushMe');
$oSocket->connect("tcp://mydomain:5555");
$aData = array(
'topic' => 'message',
'sUsername' => $oUserCurrent->getUsername(),
'sMessage' => $sMessage
);
$oSocket->send(json_encode($aData));
.....
The chat service :
Chat.php
/**
* A lookup of all the topics clients have subscribed to
*/
public function onSubscribe(ConnectionInterface $conn, $topic)
{
// When a visitor subscribes to a topic link the Topic object in a lookup array
$subject = $topic->getId();
$ip = $conn->remoteAddress;
if (!array_key_exists($subject, $this->subscribedTopics))
{
$this->subscribedTopics[$subject] = $topic;
}
$this->clients[] = $conn->resourceId;
echo sprintf("New Connection: %s" . PHP_EOL, $conn->remoteAddress);
}
/**
* #param string JSON'ified string we'll receive from ZeroMQ
*/
public function onMessage($jData)
{
$aData = json_decode($jData, true);
var_dump($aData);
if (!array_key_exists($aData['topic'], $this->subscribedTopics)) {
return;
}
$topic = $this->subscribedTopics[$aData['topic']];
// This sends out everything to multiple users, not what I want!!
// re-send the data to all the clients subscribed to that category
$topic->broadcast($aData);
}
JS code that receives data :
messages.html.twig :
var conn = new ab.Session(
'ws://mydomain:7979' // The host (our Ratchet WebSocket server) to connect to
, function() { // Once the connection has been established
conn.subscribe('message', function(topic, data)
{
console.log(topic);
console.log(data);
});
}
, function() { // When the connection is closed
console.warn('WebSocket connection closed');
}
, { // Additional parameters, we're ignoring the WAMP sub-protocol for older browsers
'skipSubprotocolCheck': true
}
);
So everytings working perfectly, when I send a new Message, it goes to DB then it lands on the page of the chat.
PROBLEM :
The data lands wherever the JS script is, and the result is that all users can get the same recorded message
ASKING :
How can I make data lands in a specific user page ?
Thank you
You are using Ratchet on backend side, right?
So, here you have very good example of case you need:
http://socketo.me/docs/hello-world
You should keep your client connections inside $clients property (not collection of resources id!). So, you can choose one element from this collection and send a message only to this client.
Example:
public function onSubscribe(ConnectionInterface $conn, $topic)
{
// When a visitor subscribes to a topic link the Topic object in a lookup array
$subject = $topic->getId();
$ip = $conn->remoteAddress;
if (!array_key_exists($subject, $this->subscribedTopics))
{
$this->subscribedTopics[$subject] = $topic;
}
$this->clients[] = $conn; // you add connection to the collection
$conn->send("Hello new user!"); // you send a message only to this one user
}
Following this instruction http://socketo.me/docs/push I had this working.
However, I'd like my service to be compatible with older browsers as well (IE 8 etc), so I need to use a flash fallback (like web_socket.js or similar) to do this:
function initPull() {
var conn = new ab.Session(
// The host (our Ratchet WebSocket server) to
'ws://'+PUSH_SOCKET_SERVER+':'+PUSH_SOCKET_PORT+'/',
// Once the connection has been established
function() {
conn.subscribe(TOPIC_PREFIX+rID, function(topic, data) {
//Trigger action
aTrigger(data);
});
},
// When the connection is closed
function() {
console.warn('WebSocket connection closed');
},
// Additional parameters, we're ignoring the WAMP sub-protocol for older browsers
{
'skipSubprotocolCheck': true
}
);
}
Ratchet supports web-socket-js, which is a natural polyfill. The ZMQ code is on the server side and will still be executed if your client is using native WebSockets or the Flash polyfill.
Keep your code from the Push tutorial as is, add web-socket-js code to your client and then see the code from the FlashPolicy component.
For a bit more involved example, see this example on how to server Flash Policy files without having to run two separate processes.
I believe I have done just what you suggested. The idea is to combine chat server with push messages. This all works except flash polyfill. Here is my server code:
//This is a server to handle both WAMP chat messages and PUSH messages
use Ratchet\Server\IoServer;
use Ratchet\Server\FlashPolicy;
use Ratchet\WebSocket\WsServer;
use Ratchet\Wamp\ServerProtocol;
use React\EventLoop\Factory;
use React\Socket\Server as Reactor;
use React\ZMQ\Context;
use Ratchet\Wamp\WampServer;
use Ratchet\Cookbook\OpenPubSub;
use Ratchet\Website\PortLogger;
use Ratchet\Cookbook\NullComponent;
use Ratchet\Cookbook\MessageLogger;
use Ratchet\Push\Pusher;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// Composer: The greatest thing since sliced bread
require dirname(__DIR__) . '/vendor/autoload.php';
// Setup logging
$stdout = new StreamHandler('php://stdout');
$logout = new Logger('SockOut');
$login = new Logger('Sock-In');
$login->pushHandler($stdout);
$logout->pushHandler($stdout);
// The all mighty event loop
$loop = Factory::create();
// This little thing is to check for connectivity...
// As a case study, when people connect on port 80, we're having them
// also connect on port 9000 and increment a counter if they connect.
// Later, we can publish the results and find out if WebSockets over
// a port other than 80 is viable (theory is blocked by firewalls).
$context = new Context($loop);
$push = $context->getSocket(ZMQ::SOCKET_PUSH);
$push->connect('tcp://127.0.0.1:8080');
// Setup our Ratchet ChatRoom application
$webSock = new Reactor($loop);
$webSock->listen(8080, '0.0.0.0');
$webServer = new IoServer( // Basic I/O with clients, aww yeah
new WsServer( // Boom! WebSockets
new PortLogger($push, 80, // Compare vs the almost over 9000 conns
new MessageLogger( // Log events in case of "oh noes"
new WampServer(
new OpenPubSub
)
, $login
, $logout
)
)
)
, $webSock
);
// Allow Flash sockets (Internet Explorer) to connect to our app
$flashSock = new Reactor($loop);
$flashSock->listen(843, '0.0.0.0');
$policy = new FlashPolicy;
$policy->addAllowedAccess('*', 80);
$policy->addAllowedAccess('*', 8080);
$policy->addAllowedAccess('*', 8081);
$webServer = new IoServer($policy, $flashSock);
$logSock = new Reactor($loop);
$logSock->listen(9000, '0.0.0.0');
$zLogger = new IoServer(
new WsServer(
new MessageLogger(
new PortLogger($push, 9000, new NullComponent)
)
)
, $logSock
);
$pusher = new Pusher;
// Listen for the web server to make a ZeroMQ push after an ajax request
$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means the only client that can connect is itself
$pull->on('message', array($pusher, 'onMsg'));
// Set up our WebSocket server for clients wanting real-time updates
$webSock = new React\Socket\Server($loop);
$webSock->listen(8081, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new Ratchet\Server\IoServer(
new Ratchet\WebSocket\WsServer(
new MessageLogger(
new Ratchet\Wamp\WampServer(
$pusher
)
)
),
$webSock
);
// GO GO GO!
echo "[".Date("Y-m-d H:i:s")."] VPCserver started...\n";
$loop->run();