I am going crazy for last two days, i cannot make connection on NodeJS client with durable exchange and durable queue.
So PHP code creates and send message:
<?php
$connection = new AMQPConnection(array(
'host' => 'localhost',
'vhost' => 'bvh',
'port' => 5672,
'login' => 'bizneus',
'password' => 'lozinkus'
));
//$connection = new AMQPConnection();
$connection->connect();
if (!$connection->isConnected()) {
die('Not connected :(' . PHP_EOL);
}
// Open Channel
$channel = new AMQPChannel($connection);
// Declare exchange
$exchange = new AMQPExchange($channel);
$exchange->setName('biznea_e_1');
$exchange->setType('fanout');
$exchange->setFlags(AMQP_DURABLE);
$exchange->declare();
// Create Queue
$queue = new AMQPQueue($channel);
$queue->setName('notify');
$queue->setFlags(AMQP_DURABLE);
$queue->declare();
$message = $exchange->publish(json_encode($s), 'kljuc');
if (!$message) {
echo 'Message not sent', PHP_EOL;
} else {
echo 'Message sent!', PHP_EOL;
}
if ($connection->isConnected()) {
$connection->disconnect();
}
On screen it says that messege is sent.
Next thing is NodeJS client, which should get messages, but it can't:
var amqp = require('amqp');
var conParam = {
host: 'localhost',
port: 5672,
login: 'bizneus',
password: 'lozinkus',
vhost: 'bvh'
}
var connection = amqp.createConnection(conParam);
connection.on('ready', function(){
var exchange = connection.exchange('biznea_e_1');
var queue = connection.queue('notify');
queue.bind('biznea_e_1', 'kljuc');
queue.subscribe( {ack:true}, function(message){
var dj = JSON.parse(message.data.toString());
console.log(JSON.stringify(dj));
queue.shift();
});
});
but I get this error
events.js:66
throw arguments[1]; // Unhandled 'error' event
^
Error: PRECONDITION_FAILED - cannot redeclare exchange 'biznea_e_1' in vhost 'bvh' with different type, durable, internal or autodelete value
at Exchange._onMethod (/home/zijad/node_modules/amqp/amqp.js:1824:15)
at Exchange.Channel._onChannelMethod (/home/zijad/node_modules/amqp/amqp.js:1365:14)
at Connection._onMethod (/home/zijad/node_modules/amqp/amqp.js:922:28)
at AMQPParser.self.addListener.parser.onMethod (/home/zijad/node_modules/amqp/amqp.js:797:12)
at AMQPParser._parseMethodFrame (/home/zijad/node_modules/amqp/amqp.js:442:10)
at frameEnd (/home/zijad/node_modules/amqp/amqp.js:187:16)
at frame (/home/zijad/node_modules/amqp/amqp.js:172:14)
at AMQPParser.header [as parse] (/home/zijad/node_modules/amqp/amqp.js:159:14)
at AMQPParser.execute (/home/zijad/node_modules/amqp/amqp.js:231:21)
at Connection.<anonymous> (/home/zijad/node_modules/amqp/amqp.js:837:12)
I tried to remove var exchange = connection.exchange('biznea_e_1'); that line but than it cannot declare queue.
I just want to send messages from PHP to NodeJS deamon and that is all!
Help :)
Try this: In the node.js code, declare the exchanges and queues with EXACTLY the same parameters as you did in your PHP code. e.g. durable. This may solve your problem.
Cheers!
Looks like you are trying to create the exchange 'biznea_e_1' again in the node.js code. It is already created by the php code. Try only to subscribe.
Related
my goal is to somehow trigger a secure ratchet websocket, where my clients have logged in via javascript, to send an update message to them.
My secure ratchet websocket is already working fine, as well as the wss connection via javascript, the clients can connect and disconnect from the websocket.
Websocket (PHP):
use Ratchet\Http\HttpServer;
use socket\secure\IoSecureServer;
use Ratchet\WebSocket\WsServer;
use socket\http\WebHttpServer;
$http_server = IoSecureServer::factory(
new HttpServer(
new WsServer(
new WebHttpServer()
)
),
8091,
"0.0.0.0",
array(
"local_cert" => "path/to/my/cert",
"local_pk" => "path/to/my/key",
"allow_self_signed" => true,
"verify_peer" => false
)
);
$http_server->run();
Client (JS):
let web_socket = new WebSocket("wss://domainname.de:8091");
web_socket.onopen = function () {
//do some stuff
console.log("Connected to websocket");
}
web_socket.onclose = function () {
//do some stuff
console.warn("Connection closed");
}
web_socket.onerror = function () {
//do some stuff
web_socket.close();
}
web_socket.onmessage = function (ev) {
//do some stuff
}
Idea:
Now I was wondering how I could trigger this ratchet websocket:
My idea:
Through a connector I send a message to the socket, it recognizes that it was sent from the same device and accepts the content, evaluates it and sends a message with new information to all clients.
Problem:
I do not manage to reach the socket with a connector. The best attempt so far was the following:
$contextOptions = array(
'ssl' => array(
"verify_peer"=>false,
"verify_peer_name"=>false
)
);
$context = stream_context_create($contextOptions);
$fp =stream_socket_client("ssl://domainname.de:8091",$errstr,$errno,30,STREAM_CLIENT_CONNECT,$context);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
fwrite($fp, "GET / HTTP/1.1\r\nHost: domainname.de\r\nAccept: */*\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n");
fclose($fp);
}
So i get the following output:
[2022-07-02 12:29:20] (68) connected to the server
[2022-07-02 12:29:20] 68 disconnected from the server
It should be noted that the ratchet server cannot determine an IP address.
I would like to know how I can get the IP address to be recognized and still be able to send a message?
Or is there another way to tell a ratchet websocket: now you have to send out a message?
Thanks a lot for your support!
I'm trying to send some data from php application to the user's browser using websockets. Therefore I've decided to use Swoole in combination with RabbitMQ.
It's the first time I'm working with websockets and after reading some posts about Socket.IO, Ratchet, etc. I've decided to halt on Swoole because it's written in C and handy to use with php.
This is how I understood the idea of enabling data transfer using websockets:
1) Start RabbitMQ worker and Swoole server in CLI
2) php application sends data to RabbitMQ
3) RabbitMQ sends message with data to worker
4) Worker receives message with data + establishes socket connection with Swoole socket server.
5) Swoole server broadcasts data to all connections
The question is how to bind Swoole socket server with RabbitMQ? Or how to make RabbitMQ to establish connection with Swoole and send data to it?
Here is the code:
Swoole server (swoole_sever.php)
$server = new \swoole_websocket_server("0.0.0.0", 2345, SWOOLE_BASE);
$server->on('open', function(\Swoole\Websocket\Server $server, $req)
{
echo "connection open: {$req->fd}\n";
});
$server->on('message', function($server, \Swoole\Websocket\Frame $frame)
{
echo "received message: {$frame->data}\n";
$server->push($frame->fd, json_encode(["hello", "world"]));
});
$server->on('close', function($server, $fd)
{
echo "connection close: {$fd}\n";
});
$server->start();
Worker which receives message from RabbitMQ, then makes connection to Swoole and broadcasts the message via socket connection (worker.php)
$connection = new AMQPStreamConnection('0.0.0.0', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('task_queue', false, true, false, false);
echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";
$callback = function($msg){
echo " [x] Received ", $msg->body, "\n";
sleep(substr_count($msg->body, '.'));
echo " [x] Done", "\n";
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
// Here I'm trying to make connection to Swoole server and sernd data
$cli = new \swoole_http_client('0.0.0.0', 2345);
$cli->on('message', function ($_cli, $frame) {
var_dump($frame);
});
$cli->upgrade('/', function($cli)
{
$cli->push('This is the message to send to Swoole server');
$cli->close();
});
};
$channel->basic_qos(null, 1, null);
$channel->basic_consume('task_queue', '', false, false, false, false, $callback);
while(count($channel->callbacks)) {
$channel->wait();
}
$channel->close();
$connection->close();
New task where the message will be send to RabbitMQ (new_task.php):
$connection = new AMQPStreamConnection('0.0.0.0', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('task_queue', false, true, false, false);
$data = implode(' ', array_slice($argv, 1));
if(empty($data)) $data = "Hello World!";
$msg = new AMQPMessage($data,
array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT)
);
$channel->basic_publish($msg, '', 'task_queue');
echo " [x] Sent ", $data, "\n";
$channel->close();
$connection->close();
After starting both swoole server and worker I'm triggering new_task.php from command line:
php new_task.php
In command line prompt where a RabbitMQ Worker is running (worker.php) I can see that a message is delivered to the worker ("[x] Received Hello World!" message is appearing).
However in command line prompt where Swoole server is running happens nothing.
So the questions are:
1) Is the idea of this approach right?
2) What am I doing wrong?
In the callback(in worker.php) that fires when a message is received you're using swoole_http_client which is async only. This seems to results in the code never being fully executed as the callback function returns before the async code is triggered.
A synchronous method of doing the same thing will solve the problem. Here is a simple example:
$client = new WebSocketClient('0.0.0.0', 2345);
$client->connect();
$client->send('This is the message to send to Swoole server');
$recv = $client->recv();
print_r($recv);
$client->close();
Check out the WebSocketClient class and example usage at github.
You can also wrap it in a coroutine, like this:
go(function () {
$client = new WebSocketClient('0.0.0.0', 2345);
$client->connect();
$client->send('This is the message to send to Swoole server');
$recv = $client->recv();
print_r($recv);
$client->close();
});
I can connect to the server but cannot read the acknowledgements messages sent by the gcm server. I want to know how to retrieve the XML sent by gcm server.
Here is my code :
<?php
require 'jaxl/jaxl.php';
$sender = 'sender id';
$client = new \JAXL(array(
'jid'=>$sender,
'pass'=>'pass',
'auth_type'=>'PLAIN',
'host' => 'gcm.googleapis.com',
'port' => '5235',
'force_tls' => true,
'strict' => FALSE,
'ssl' => TRUE,
'log_level' => JAXL_DEBUG,
'log_path'=> 'ex.txt'
));
$client->add_cb('on_message_stanza', function($msg) {
echo 'now what!!';
});
$client->add_cb('on_auth_success', function() {
echo 'it should';
global $client;
global $sender;
$namespace = 'google:mobile:data';
$arr=array("hello"=>"world");
$json_data=json_encode($arr,JSON_UNESCAPED_SLASHES);
$arr = array('to'=>'server','message_id'=>'123','data'=>$arr);
$json = json_encode($arr);
$xml = new JAXLXml('gcm',$namespace,array(),$json);
$msg = new JAXLXml('message','',array('id'=>'123'),'');
$msg->cnode($xml);
$client->send($msg);
});
$client->add_cb('on_error_message',function()
{
global $client;
echo 'error<br/>';
_info('got on_error_message cb jid'.$client->full_jid->to_string());
});
In the callback 'on_auth_success', i am sending a message to gcm server directed to my server id, it is sending a negative acknowledgement 'nack' which i can see in the log, but I don't know how to receive that in php code.
The XML received by gcm as per log is :
<message>
<data:gcm xmlns:data="google:mobile:data">{"message_id":"123","from":"someid",
"error_description":"","error":"BAD_REGISTRATION",
"message_type":"nack"}</data:gcm></message>
Oh, I got it, since the response message didn't had any type, I have to add the callback 'on__message', with 2 underscore, because middle value is the value of type attribute of the message which the response don't have.
For an ACK, you can use message type 'normal', so the cb would look like below (I am just logging response):
$client->add_cb('on_normal_message', function($stanza) {
global $client;
// echo back incoming message stanza
//$stanza->to = $stanza->from;
//$stanza->from = $client->full_jid->to_string();
//$client->send($stanza);
_info('Received response******'.$stanza->to_string());
});
Also: in the example, you need to add
$client->start();
For us newbies.
Then it works fine with GCM.
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
}
I wish to send a message to XMPP based chat servers using php.
I am using JAXL, which seems the best (of limited) options for pure PHP server based chat.
However, I have yet to establish any connect, let alone send a message.
I am having a hard time working out if the problem is my code, my server (which is shared server, but has Cpanel, and a very helpfull host), or my settings.
The code I am using to try to connect to GTalk is;
$client = new JAXL(array(
'jid' => 'name#gmail.com',
'pass' => 'password',
'host'=> 'talk.google.com',
'port'=> 5222,
'domain'=> 'gmail.com', //unsure if this is the right setting.
'force_tls' => true,
'auth_type' => #$argv[3] ? $argv[3] : 'PLAIN',
));
//
// required XEP's
//
$client->require_xep(array(
'0199' // XMPP Ping
));
//
// add necessary event callbacks here
//
$client->add_cb('on_auth_success', function() {
global $client;
_info("got on_auth_success cb, jid ".$client->full_jid->to_string());
// fetch roster list
$client->get_roster();
// fetch vcard
$client->get_vcard();
// set status
$client->set_status("available!", "dnd", 10);
});
$client->add_cb('on_connect_error', function() {
echo 'Connect Error';
});
$client->add_cb('on_auth_failure', function() {
echo 'Auth Error';
});
$client->add_cb('on_auth_success', function() {
global $client;
echo 'connected';
$client->send_chat_msg('test2#domain.com', 'webtest');
$client->shutdown();
});
//
// finally start configured xmpp stream
//
$client->start(array(
'--with-debug-shell' => true,
'--with-unix-sock' => true
));
echo "done\n";
Triggering the php (from a browser) then results in the server getting stuck. (no "done" message, just constant loading till a timeout from the browser)
The server logs show;
strict mode enabled, adding exception handlers. Set 'strict'=>TRUE inside JAXL config to disable this[0m
error handler called with 8, Undefined index: priv_dir,
And then lots of;
unable to connect tcp://talk.google.com:5222 with error no: 110, error str: Connection timed out
So I would appreciate help with any of the following;
Any specific problems with my code
Any issues with the gtalk connection settings at the start
Alternative recommendations to investigate this issue.
Or any general advice from people that have successfully used JAXL.
Thanks,
Thomas Wrobel
Ok problem might be TCP port is closed for your hosting , try to open it with your hosting first, also try to run your code locally to see if it's work fine .
Some people reported the issue was fixed by override method connect from file XMLStream.php by this one
/**
* Connect to XMPP Host
*
* #param integer $timeout
* #param boolean $persistent
* #param boolean $sendinit
*/
public function connect($timeout = 30, $persistent = false, $sendinit = true) {
$this->sent_disconnect = false;
$starttime = time();
do {
$this->disconnected = false;
$this->sent_disconnect = false;
if($persistent) {
$conflag = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT;
} else {
$conflag = STREAM_CLIENT_CONNECT;
}
$conntype = 'tcp';
if($this->use_ssl) $conntype = 'ssl';
$this->log->log("Connecting to $conntype://{$this->host}:{$this->port}");
try {
$this->socket = #stream_socket_client("$conntype://{$this->host}:{$this->port}", $errno, $errstr, $timeout, $conflag);
} catch (Exception $e) {
throw new XMPPHP_Exception($e->getMessage());
}
if(!$this->socket) {
$this->log->log("Could not connect.", XMPPHP_Log::LEVEL_ERROR);
$this->disconnected = true;
# Take it easy for a few seconds
sleep(min($timeout, 5));
}
} while (!$this->socket/* && (time() - $starttime) < $timeout*/);
if ($this->socket) {
stream_set_blocking($this->socket, 0);
if($sendinit) $this->send($this->stream_start);
} else {
throw new XMPPHP_Exception("Could not connect before timeout.");
}
}