Reactphp can't get total data on stream - php

im using reactphp library , and im working with a device that sends packages in different sizes. My problem is when i get the data
$stream->on('data', function ($data, React\Stream\ReadableStreamInterface $stream) {
$this->respuesta .= $data;
$stream->close();
});
I only get a part of the first package. Is there a way to keep waiting until the device sends all the data?
Here, on the wireshark capture the last package is the one that i cant get with react.
$loop = React\EventLoop\Factory::create();
$dnsResolverFactory = new React\Dns\Resolver\Factory();
$dns = $dnsResolverFactory->createCached('8.8.8.8', $loop);
$connector = new React\SocketClient\Connector($loop, $dns);
$connector->create($this->host, $this->port)->then(function (React\Stream\Stream $stream) use ($hex) {
$stream->write($hex);
$stream->on('data', function ($data, React\Stream\ReadableStreamInterface $stream) {
$this->respuesta .= $data;
$stream->close();
});
});
$loop->run();

It appears you are closing the connection right after receiving the data... You should keep this connection open until after you receive all of the data. The data event is dispatched after receiving some data, not all data.
Typically this is implementation specific, if your dealing with RPC style api, the client sending the request may not care about acknowledgment from the service and cut the connection after sending the data; in this case you should accumulate your buffer on the data event, and then process it on the end event.
If you want to keep the connection open, and send discrete chunks of information, typically you either lead the data package with the size of the package, allowing you to know how much of the buffer to fill before processing, or you can send a delimiter (typically a null byte) that marks the end of the package.

Related

AWSs sendEmailAsync not working in PHP application

I have a PHP application where I can send mails via AmazonSES by using the offical SDK.
By default sending emails works when using the sendMail method: (simplified):
$result = aws_client()->sendEmail([/* ... */]);
For the Async method I would like to use this:
$promise = aws_client()->sendEmailAsync([/* ... */]);
$promise->then(
function ( $value ) {
error_log( 'ok, fulfilled' );
},
function ( $reason ) {
error_log('on no, rejected' );
}
);
// $result = $promise->wait();
$promise->resolve();
I instantly get ok, fulfilled in my console but no email has been sent, not even after a couple of minutes.
When I use the mentioned line $result = $promise->wait(); everything works as expected but the process takes much longer (of course because of the synchronism and this is why I like to go with the async method).
So is it just not possible to run an async process in PHP or do I miss something?
AWS SDK *Async functions in PHP don't spawn a separate process for sending the email. Instead, they return a promise. This is useful if you need to do several slow processes at the same time, such as sending several emails. But the promise needs to be resolved (you need to wait for the response).
What I think is happening, AWS SDK connects to SES endpoint, starts sending your email and before it finishes, your script terminates. This also terminates the sending.

How do I generate a custom response when a script times out due to blocking io?

Goal
I am developing a JSON endpoint that basically reads data from a server-side COM port into a file (on the server end) when a user sends a GET request to it. The response from the server has to be a properly formed JSON response containing the name of the file where the contents were dumped to. If the COM port takes too long to respond, the file is closed and still considered valid with whatever contents it did read from the COM port. A valid response is still provided.
Problem
When the COM port is no longer being fed data, it blocks until the script times out. This results in an error and IIS provides a generic error page on a json endpoint. This is not valid json, but it also does not contain the name of the file where the com data was dumped to.
Details
I have to use the PHP Direct IO extension to interface with a serial com port.
This is blocking IO, and on windows, asynchronous IO is not supported (as far as I have seen.)
register_shutdown_function does not guarantee it is executed while a connection is still open to the client, so I cannot use this to print a valid response.
For your JSON endpoint, you could create a wrapper script that calls your IO script. Set a timeout for your attempt to get a response from it, and then return JSON with either whatever it got from the script, or some custom message if the script timed out.
$timeout = 5; // some reasonable time less than the wrapper script timeout
$data = ['filename' => 'something']; // create the file name
$q = http_build_query($data); // pass it to the IO script
$context = stream_context_create(['http'=> ['timeout' => $timeout]]);
$response = file_get_contents("http://yourserver/io_script.php?$q", false, $context);
echo json_encode($data + ['data' => $response ?: 'no data']);

PHP AJAX, return multiple values in realtime in a for loop

What I have:
foreach ($contacts as $contact) {
$this->StocklistMailer($contact, $weekOrDay, $data, $content, $itemGroup);
}
return new Response('completed', 204);
What I would like is :
foreach ($contacts as $contact) {
$this->StocklistMailer($contact, $weekOrDay, $data, $content, $itemGroup);
return new Response($contact->getEmail, 204);
}
return new Response('completed', 204);
And it returns to a AJAX call on the page, the reason I want to accomplish this is because I want realtime feedback to whom it has send an email to.
You can't send multiple responses from your application, the whole idea is that you only generate one response.
However, you can put all the information you require in one response.
$emails = [];
foreach ($contacts as $contact) {
$this->StocklistMailer($contact, $weekOrDay, $data, $content, $itemGroup);
$emails[] = $contact->getEmail;
}
return new Response(json_encode($emails), 200);
Note that I changed 204 (No content) to 200 (OK).
You would have to break it into multiple calls;
First call will return the array of contacts which you will store in your JavaScript array. (assuming you are using Client Side JS/Ajax to call this php file).
Then loop through the array and make as many calls to php as many contacts are in your array while passing each contact at a time to php.
You can show fancy progress bar as you are looping through the array :)
You can do that, but not from Symfony. Look into ReactPHP, Ratchet and related technologies.
https://blog.wyrihaximus.net/2015/03/reactphp-sockets/
http://socketo.me/docs/hello-world
You can create a websockets server that would listen on localhost for messages from your Symfony application and will be redirecting them using websockets to the browser.
The cliend would open a websocket connection to your websockets server, and send the request to your application. While the application is processing, it is sending the progress to the websocket server using a socket on the local machine. The client should be getting the progress realtime from the websocket and should be displaying it.
This way, you get a realtime interactive interface, with a long-running process.
Even better would be creating a rabbitmq worker, that would be sending the emails and reporting the progress to the websockets server. You would create the task for the worker from your Symfony application, and therefore you wouldn't be limited by the execution time limit for php requests. Another win with the rabbitmq worker is that you can have only one (or as many as you like), and therefore the tasks will queue and you won't be burning server resources by 50 processes generating and sending emails at once.

Running php code chunk in background

I have a php script which is responsible for reading some request parameters from my iPhone app. Once I do some manipulations to it I save them in db and will need to send some push notification message using apple APNS. So currently its done like this in the code.
<?php
$param1 = $_POST['param1'];
$param2 = $_POST['param2'];
//saving part here
//push notifications
$pushService = new PushService();
$pushService -> init();
$pushService -> push($param1, $param2);
//json response
echo json_encode(array($success, $dbsavedid);
?>
Problem occurs with the push part. Now it takes lot of time for this push notification code chunk to execute because the table has grown with lot of data. Hence the iPhone app waits too long for this to execute (to get the success response to iPhone).
Hence is there any way to make this push part asynchronous and send a response to iPhone side using the echo other than using a separate script for push notifications? Also note that I need to get some data from saved records as well to iPhone side. So I will need the output to reach the iPhone side.
You can force PHP to send a response by using the flush() function for example. (there might be other possibilities to accomplish too)
So what you have to do is write with echo to the output buffer when your db operations finished (these should be really fast if you have 100-1000 records) and right after call the flush() function. Your client should get a response right away.
Also see this link about flush() itself, because there might be other parameters of your enviroment which prevents your response in reaching the client side as soon as expected.
http://php.net/manual/en/function.flush.php
<?php
$param1 = $_POST['param1'];
$param2 = $_POST['param2'];
//saving part here
//json response
echo json_encode(array($success, $dbsavedid);
//response should be sent right away, no need for wait on the pushservice operations
flush();
//push notifications
$pushService = new PushService();
$pushService -> init();
$pushService -> push($param1, $param2);
?>
The actual reasons for this is, my server provider has blocked port 2195 and port 2196 which is used by apple APNS. I believe once you allow it this will be fixed and should work like earlier.

How increases the speed Ajax-php-xml chat application?

I made chat application using Ajax-php-xml technology. It work fine if the number of users below 50.
otherwise speed of application dramatically decreases. I want to manage 200s users at a time.
my XML format is
<?xml version="1.0" encoding="utf-8"?>
<messageData>
<message>
<sender>user__5338</sender>
<receiver>user__5339</receiver>
<content>hello</content>
<date_time>2012-08-17 09:24:57</date_time>
<status>unread</status>
</message>
<message>
<sender>user__5338</sender>
<receiver>user__5339</receiver>
<content>hello</content>
<date_time>2012-08-17 09:26:21</date_time>
<status>unread</status>
</message>
</messageData>
In my php, I fetch data from xml file using this method
$xml = simplexml_load_file($this->xml_file);
foreach($xml->message as $chat_data){
if($chat_data->status =='unread' && $chat_data->receiver ==$username){
$chat_data->status = 'read';
$xml->asXML($this->xml_file);
$sender =(string)$chat_data->sender;
$chat['message'] = (string)$chat_data->content;
$chat['date'] = (string)$chat_data->date_time;
}
}
How can inrease the speed of chat application? Can i increase the speed by using node js?
Why don't you use json as ajax transfer data type? I believe it might be faster, because php doesn't need to parse xml. And use jQuery as javascript library for your ajax requests, it is one of the best. It supports json. And use this tutorial as an example.
And one more thing, set the interval between ajax requests to 1-3 seconds. Maybe even more.
using sockets could increase your communication speed for sure , it may sound complicated but for your purpose it's the answer.
sockets are :
The WebSocket specification defines an API establishing "socket"
connections between a web browser and a server. In plain words: There
is an persistent connection between the client and the server and both
parties can start sending data at any time.
simple example :
var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);
// When the connection is open, send some data to the server
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
searching will give your more examples

Categories