MadelineProto: how listen subscribe event? - php

i'm writing telegram bot-administrator and using this package
have this code
$settings = new Settings();
$appInfo = new Settings\AppInfo();
$appInfo->setApiHash(config('telegram.app.app_info.api_hash'))
->setApiId(config('telegram.app.app_info.api_id'));
$settings->setAppInfo($appInfo);
$api = new API(time(), $settings);
$api->botLogin(env('TELEGRAM_BOT_TOKEN'));
$api->startAndLoop(NewSubscriberListener::class);
class NewSubscriberListener extends EventHandler
{
public function onUpdateNewChannelMessage(array $update)
{
print_r(__METHOD__);
yield print_r($update);
}
public function onUpdateChatParticipants(array $update)
{
print_r(__METHOD__);
yield print_r($update);
}
}
when i write message into chat - i listen him, but where new user subscribe - nothing
tell me please where my mistake ? or this not possible?

Related

Send event from php controller

Good morning everyone.
I need to send a notification whenever a user swipes a tab on a particular sensor.
The problem is not the connection to the sensor, which at this moment already takes place and subject to user access.
Currently I have created a server socket inside my yii2 app to be able to send the notification event to the client and update them in real time.
This is my controller server
class ServerController extends Controller
{
public function actionStart()
{
// $server = new CommandsServer();
$server = new ChatServer();
$server->port = 80; //This port must be busy by WebServer and we handle an error
$server->on(WebSocketServer::EVENT_WEBSOCKET_OPEN_ERROR, function ($e) use ($server) {
echo "Error opening port " . $server->port . "\n";
$server->port += 1; //Try next port to open
$server->start();
});
$server->on(WebSocketServer::EVENT_WEBSOCKET_OPEN, function ($e) use ($server) {
echo "Server started at port " . $server->port;
});
$server->start();
}
}
This is my chat server which I created for testing
<?php
namespace frontend\daemons;
use consik\yii2websocket\events\WSClientEvent;
use consik\yii2websocket\WebSocketServer;
use Ratchet\ConnectionInterface;
class ChatServer extends WebSocketServer
{
public function init()
{
parent::init();
$this->on(self::EVENT_CLIENT_CONNECTED, function (WSClientEvent $e) {
$e->client->name = null;
});
}
protected function getCommand(ConnectionInterface $from, $msg)
{
$request = json_decode($msg, true);
return !empty($request['action']) ? $request['action'] : parent::getCommand($from, $msg);
}
public function commandPing(ConnectionInterface $client, $msg)
{
$arr = ["Neo", "Morpheus", "Trinity", "Cypher", "Tank"];
$res = ['type' => 'ping', 'message' => json_encode(array_rand($arr, 1))];
foreach ($this->clients as $chatClient) {
$chatClient->send(json_encode($res));
}
}
}
Now, what I wish I could do is be able to use that commandPing inside another controller, but I haven't found a way I can implement this.
In this sense the round would be:
user swipes card on sensor -> the sensor calls my method to see if the user is actually authorized to enter -> I call commandPing (as an example) to send a notification to the customer (OK / KO )
On the web interface side I will then intercept the message via new Websocket (but this is not a problem)

Why ActiveMQ delivers duplicate messages to my PHP consumer over Stomp?

I am not sure whether this question is related to stomp-php or ActiveMQ Docker (running with defaults).
I have a simple Queue helper class written in PHP that handles both sending the message to the queue (Queue::push), as well as consumes it (Queue::fetch). See code below.
As you can see, fetch() should subscribe to the queue, read one message and unsubscribe. The message should be acknowledged automatically (\Stomp\StatefulStomp::subscribe(), 3rd. argument).
For some reason, about 5-7% of the messages are received by the customer twice or even three times. Why messages are delivered multiple times and how to avoid it?
Publisher (pushing 1000 messages):
$mq = new Queue('tcp://activemq:61613','test');
for ($msgCount = 0; $msgCount < 1000; $msgCount++) {
$mq->push('Message #' . $msgCount);
}
Consumer (receiving ~1070 messages):
$mq = new Queue('tcp://activemq:61613','test');
$received = 0;
while (true) {
$message = $mq->fetch();
if (null === $message) { break; }
$received++;
}
Queue class code:
use Stomp\Client;
use Stomp\Network\Connection;
use Stomp\SimpleStomp;
use Stomp\StatefulStomp;
use Stomp\Transport\Message;
class Queue
{
/**
* #var \Stomp\StatefulStomp
*/
private $stomp;
private $queue;
public function __construct($uri, $queue) {
$connection = new Connection('tcp://activemq:61613');
$this->stomp = new StatefulStomp(new Client($connection));
$connection->setReadTimeout(1);
$this->queue = $queue;
}
public function push($body) {
$message = new Message($body, ['activemq.maximumRedeliveries' => 0]);
$this->stomp->send('/queue/' . $this->queue, $message);
}
public function fetch() {
$subscriptionId = $this->stomp->subscribe('/queue/' . $this->queue, null, 'auto', ['activemq.prefetchSize' => 1]);
$msg = $this->stomp->read();
$this->stomp->unsubscribe($subscriptionId);
return $msg;
}
}

Dynamically-created Twilio Enqueue waitUrl results in 500 server error

I have a function in my Laravel application that generates TwiML for a holding queue. It seems that when I try to dynamically generate the value for the waitUrl attribute, I end up getting a 500 server error during runtime. Routes are properly established and I'm able to view the correct XML at the waitURL in the browser. However, the error persists.
If I create a static XML file with the same exact content, or use a TwiML Bin, it works like a charm.
Here are the relevant functions:
public function wait() {
return $this->generateWaitTwiml();
}
public function onHold($agentId) {
return $this->generateHoldQueueTwiml($agentId, '/phone/wait');
}
private function generateHoldQueueTwiml($agentId, $waitUrl = null) {
$queue = $agentId . '_hold';
if ($waitUrl === null){
$waitUrl = 'path_to_static.xml';
}
$queue = $agentId . '_hold';
$response = new Twiml();
$response->enqueue(
$queue,
['waitUrl' => $waitUrl]
);
return response($response)->header('Content-Type', 'application/xml');
}
private function generateWaitTwiml() {
$response = new Twiml();
$response
->play('http://path_to_my.mp3');
return response($response)->header('Content-Type', 'application/xml');
}
This was resolved by excluding the URIs from the CSRF verification (in VerifyCsrfToken.php):
class VerifyCsrfToken extends Middleware {
protected $except = [
'uri/',
'uri2/*',
];
}

web service soap call - how to get returning parameter

I am creating web service. So I created this soapcall:
public function GetLogon($uzivatel, $heslo){
$soap = new SoapClient('http://www.softhouse.cz/ezopconnector2/ezopconnector.asmx?wsdl');
$params = array('uzivatel'=>$uzivatel, 'password'=>$heslo);
$response = $soap->__soapCall("EzopLogon", array($params));
var_dump($response);
}
call it in presenter like this, but it's not relevant I think:
$this->me->GetLogon("administrator", "a");
my problem is that this function should return me a session (of user).. does anybody know how can I get this session for future use? (for example for logout)
thanks a lot I am a novice, so dont yel at me :D
Update:
code for login:
public function GetLogon($uzivatel, $heslo){
$soapClient = new SoapClient('http://www.softhouse.cz/ezopconnector2/ezopconnector.asmx?wsdl');
$params = array('uzivatel'=>$uzivatel, 'heslo'=>$heslo);
$this->session = $soapClient->__soapCall("EzopLogon", array($params));
var_dump($this->session);
}
session saved as public variable in class:
public $session;
Code of function where session si required:
public function GetCtiSezSdruzAdd2(){
$soapClient = new SoapClient('http://www.softhouse.cz/ezopconnector2/ezopconnector.asmx?wsdl');
$params = array('Session'=>$this->session);
return $soapClient->__soapCall("EzopCtiSeznamSdruzenychAdresaru", array($params));
}
and call in presenter:
$this->me->GetCtiSezSdruzAdd2();

Best Practice for Multiple Subscribe Methods in React / Ratchet / ZMQ

I try to build a little realtime websocket use-case, where users can login and see all other users logged in, get notified when a new user signs in or an existing user logs out.
For this scenario i use the ZMQ PUSH Socket in my UserController when a user logs in or logs out.
UserConstroller
public function login() {
//... here is the auth code, model call etc...
$aUserData = array();// user data comes from the database with username, logintime, etc....
$context = new \ZMQContext();
$oSocket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'USER_LOGIN_PUSHER'); // use persistent_id
if($oSocket instanceof \ZMQSocket) {
$oSocket->connect("tcp://127.0.0.1:5555"); //
$oSocket->send(json_encode($aUserData));
}
}
public function logout() {
//... here is the logout code, model call etc ....
$aUserData = array();// user data comes from the SESSION with username, logintime, etc....
$context = new \ZMQContext();
$oSocket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'USER_LOGOUT_PUSHER'); // use persistent_id
if($oSocket instanceof \ZMQSocket) {
$oSocket->connect("tcp://127.0.0.1:5555"); //
$oSocket->send(json_encode($aUserData));
}
}
Then i've got a Pusher class like in the Ratchet docs: link
In this class there are two methods: onUserLogin and onUserLogout and of course all the other stuff like
onSubscribe, onOpen, onPublish
UserInformationPusher
public function onUserLogin($aUserData) {
//var_dump("onUserLogin");
$sUserData = json_decode($aUserData, true);
$oTopic = $this->subscribedTopics["user_login"];
if($oTopic instanceof Topic) {
$oTopic->broadcast($sUserData);
} else {
return;
}
}
public function onUserLogout($aUserData) {
//var_dump("onUserLogout");
$entryData = json_decode($aUserData, true);
$oTopic = $this->subscribedTopics["user_logout"];
if($oTopic instanceof Topic) {
$oTopic->broadcast($entryData);
} else {
return;
}
}
The last piece is the WampServer/WsServer/HttpServer with a Loop that listens to the incoming connections. There is also my ZMQ PULL socket
RatchetServerConsole
public function start_server() {
$oPusher = new UserInformationPusher();
$oLoop = \React\EventLoop\Factory::create();
$oZMQContext = new \React\ZMQ\Context($oLoop);
$oPullSocket = $oZMQContext->getSocket(\ZMQ::SOCKET_PULL);
$oPullSocket->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means the only client that can connect is itself
$oPullSocket->on('message', array($oPusher, 'onUserLogin'));
$oPullSocket->on('message', array($oPusher, 'onUserLogout'));
$oMemcache = new \Memcache();
$oMemcache->connect('127.0.0.1', 11211);
$oMemcacheHandler = new Handler\MemcacheSessionHandler($oMemcache);
$oSession = new SessionProvider(
new \Ratchet\Wamp\WampServer(
$oPusher
),
$oMemcacheHandler
);
//$this->Output->info("Server start initiation with memcache!...");
$webSock = new \React\Socket\Server($oLoop);
$webSock->listen(8080, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
$oServer = new \Ratchet\Server\IoServer(
new \Ratchet\Http\HttpServer(
new \Ratchet\WebSocket\WsServer(
$oSession
)
),
$webSock
);
$this->Output->info("Server started ");
$oLoop->run();
}
In this example, the call from login() or logout() would always call both methods(onUserLogin and onUserLogout).
I was not able to find some docs, which describe what events i can use in the on($event, callable $listener) method, does anyone have a link/knowledge base?
What is the best approach to check which method from the UserController was fired?
I could add some information to the $sUserData in the Controller and check this in the Pusher
I could bind an other socket to a different port (e.g. 5554 for PULL and PUSH) and use the on() method on this one
I could... is there another best practice to solve this?
No Client code needed cause it works fine
In your RatchetServerConsole,
Remove,
$oPullSocket->on('message', array($oPusher, 'onUserLogin'));
$oPullSocket->on('message', array($oPusher, 'onUserLogout'));
Add,
$oPullSocket->on('message', array($oPusher, 'onUserActionBroadcast'));
.
In your UserInformationPusher,
Remove onUserLogin() and onUserLogout().
Add,
public function onUserActionBroadcast($aUserData)
{
$entryData = json_decode($aUserData, true);
// If the lookup topic object isn't set there is no one to publish to
if (!array_key_exists($entryData['topic'], $this->subscribedTopics)) {
return;
}
$topic = $this->subscribedTopics[$entryData['topic']];
unset($entryData['topic']);
// re-send the data to all the clients subscribed to that category
$topic->broadcast($entryData);
}
.
Your UserConstroller (add the topic in $aUserData),
public function login() {
//... here is the auth code, model call etc...
$aUserData = array();// user data comes from the database with username, logintime, etc....
$aUserData['topic'] = 'USER_LOGIN'; // add the topic name
$context = new \ZMQContext();
$oSocket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'my pusher'); // use persistent_id
if($oSocket instanceof \ZMQSocket) {
$oSocket->connect("tcp://127.0.0.1:5555"); //
$oSocket->send(json_encode($aUserData));
}
}
public function logout() {
//... here is the logout code, model call etc ....
$aUserData = array();// user data comes from the SESSION with username, logintime, etc....
$aUserData['topic'] = 'USER_LOGOUT'; // add the topic name
$context = new \ZMQContext();
$oSocket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'my pusher'); // use persistent_id
if($oSocket instanceof \ZMQSocket) {
$oSocket->connect("tcp://127.0.0.1:5555"); //
$oSocket->send(json_encode($aUserData));
}
}
.
Finally in your view file,
<script>
var conn = new ab.Session('ws://yourdomain.dev:9000', // Add the correct domain and port here
function() {
conn.subscribe('USER_LOGIN', function(topic, data) {
console.log(topic);
console.log(data);
});
conn.subscribe('USER_LOGOUT', function(topic, data) {
console.log(topic);
console.log(data);
});
},
function() {
console.warn('WebSocket connection closed');
},
{'skipSubprotocolCheck': true}
);
</script>
.
NOTE: The basic idea was to use a single broadcast function in the pusher class.
After one month of intensive handling with PHPs best practice in websockets i changed from my approach to the Crossbar.io, voryx/Thruway in the PHP Backend and Autobahn|JS in the Frontend.
All of these componentes support the WAMP V2 Websocket Standard and are able to handle my requirements.
If there are some requests i can post the solution to my problem above, with the usage of the mentioned components.

Categories