I've looked at This SO question and This article to try and implement Server-Sent Events in Laravel 5. Though, between the two, I can't figure how push updates to the client based on an event. In this case, the event is a ClientException being thrown. A ClientException in my application is caused by a user made error. When one is thrown, I want to push an update to the client that populates a universal error panel.
Here's what I have in my blade:
<script>
var source = new EventSource("{{ route('globalmessages') }}");
source.addEventListener("message", function(e)
{
$("#errors").html(e);
}, false);
</script>
<div id="errors">
</div>
The EventSource successfully hits the the controller action:
public function pushErrors()
{
$response = new StreamedResponse(function()
{
$errors = ???; // How do I populate this
if (!empty($error))
{
echo $error;
ob_flush();
flush();
}
else
{
\Log::info("No errors to push");
}
});
$response->headers->set('Content-Type', 'text/event-stream');
return $response;
}
And the error handling happens in Handler.php@render:
if ($e instanceof ClientException)
{
$message = $e->getMessage(); // Need to send this to client
return \Response::json([]);
}
else
{
return parent::render($request, $e);
}
So, what I need to do is somehow give the errors to the controller route. I tried using a singleton, but I couldn't get that to work. I tried giving the controller a field to hold it, but that was always empty.
On top of that, this current implementation seems to be running every 5 seconds. I'd like to be able to call a function when the ClientException is thrown to push the update.
Thanks for any help.
EDIT:
Some more info:
Here's the controller action that renders my page:
class HomeController
{
public function getHome()
{
return view('home');
}
}
My controller using an infinite loop:
class MainController extends RouteController
{
public function pushErrors()
{
$response = new StreamedResponse();
$response->headers->set('Content-Type', 'text/event-stream');
$response->headers->set('Cach-Control', 'no-cache');
$response->setCallback(
function()
{
while (true)
{
$error = MessageQueue::dequeue();
if (!empty($error))
{
echo 'data: ' . $error. "\n\n";
ob_flush();
flush();
}
sleep(1);
}
});
return $response;
}
}
If I take out the while loop, this code works, in that the message is pushed, the connection dropped, then re-established and pushed again. With the while loop, the page just hangs.
My routes:
+--------+----------+----------------+----------------+--------------------------------------------------+------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+----------------+----------------+--------------------------------------------------+------------+
| | GET|HEAD | globalmessages | globalmessages | App\Http\Controllers\MainController@pushErrors | |
| | GET|HEAD | / | / | App\Http\Controllers\HomeController@getHome | |
| | POST | login | login | App\Http\Controllers\HomeController@postLogin | |
+--------+----------+----------------+----------------+--------------------------------------------------+------------+
HomeController@postLogin is the route that I call to that generates the ClientException.