I am creating an API that uses websockets for real-time communication. I use Laravel 8 with Pusher as the broadcast driver for the backend, Soketi as the web socket server on windows (development environment) and I use postman to test the requests.
The problem is, my connection to the Soketi web socket server Always crashes after about 2 minutes of connectivity with a 4201 Error: Connection was closed due to an unknown error. I would like the connection to last a bit longer or ideally indefinitely, at least I think that's how it should work.
Console Connection message:
Console Disconnection message:
Both Postman and the console show the error, Note the time from connection to disconnection.
I did a work around to force postman to reconnect if an unexpected error caused it to close but that doesn't reconnect to the channels that were subscribed to before disconnection.
In config\broadcasting.php I have:
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'host' => env('PUSHER_HOST'),
'port' => env('PUSHER_PORT'),
'scheme' => env('PUSHER_SCHEME', 'http'),
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => env('PUSHER_SCHEME') === 'https',
],
],
My Soketi config:
{
"debug": true,
"port": 6001,
"appManager.array.apps": [
{
"id": "SLMT",
"key": "1229272",
"secret": "sLq2dAswE&9q",
"webhooks": [
{
"url": "",
"event_types": ["channel_occupied"]
}
]
}
]
}
The key and secret values are only used for development that's why don't hide them. Any help is much appreciated beacuse this situation makes testing websocket events very tedious if the connection keeps breaking.
EDIT
I forgot to mention a crucial piece of information. My project is an API which uses Sanctum to authenticate users. It does not serve any Html. In case someone wants to reproduce.
Alright so I think I figured it out. I believe the socket connection closes due to an activity timeout.
How did I arrive at this conclusion?
I have another app which uses web sockets too but instead of an API it serves Html. Anyway I fired up the Soketi server but with different credentials specific to the Html project and I compared the console output with the API project, where the problem occurs. I noticed that on the Html app, which uses Laravel echo, the client constantly sends a pusher:ping event to the server every 30 seconds, and the server replies with a pusher:pong event.
The interesting part is that the pusher:pong event increments the _iddleStart: value under the Timeout property of the webSocket connection output, which essentially keeps the connection from closing due to inactivity. I think the reason for the 2 minutes delay comes from the _iddleTimeout:120000 property. (Please refer to the images on the question for clarity)
After this discovery I went back to my API application and made a pusher:ping event message on my Postman, which I then kept sending to the server Manually every minute, and the connection held intact!
The ping message that I mention looks like this on Postman:
{
"event":"pusher:ping",
"data":{}
}
So, why was it so hard to figure out in the first place?
I have to admit I had my suspicions but I didn't want to conclude anything without checking. The error shown by the server is not detailed or descriptive, it literally says Connection was closed due to an unknown error and there is no lookup table for the error code afaik.
What does this mean?
Well, this is a Postman problem in my opinion. A client is responsible for keeping the connection with the server open in a WebSockets implementation right? Postman should at least give an option to auto-send some messages for this sort of thing but I will cut them some slack because apparently their WebSocket Request is still in beta development.
I also feel there should be more detailed error info provided by the Soketi server output, but they too I will cut some slack because its a fairly new server app, which is actually great and very stable, if I might add.
Related
I have a PHP Laravel (5.6) system that I need to connect to an FTP server to upload a single file. The FTP server that I am connecting to is restricting access by ip address, uses port 990, and other than that has a seemingly simple configuration. On my local machine (I'm running on Linux Ubuntu if that helps) I am able to connect to the ftp server in FileZilla just fine, FileZilla did seem to automatically choose ftps. I am also able to ping this server.
Now this PHP Laravel (5.6) application is running on NGINX (had this for a while, everything else server-wise seems fine). As of now I am just trying to get this working locally, though there is a production server that it will have to be pushed onto (pretty much identical configuration though).
I started out trying to use the built in PHP function ftp_connect and ftp_ssl_connect - both using the same host and port number (990) as in FileZilla. I have been unable to get past this step - it returns false (so never even gets to my login logic).
$ftp = ftp_connect(env('FTP_HOST'),env('FTP_PORT')); // returns FALSE
$ftp = ftp_ssl_connect(env('FTP_HOST'),env('FTP_PORT')): // returns FALSE
After searching for a while I decided to try Laravel's filesystem to see if that would make it easier, these are my settings in config/filesystems.php:
'ftp' => [
'driver' => 'ftp',
'host' => env('FTP_HOST'),
'username' => env('FTP_USER'),
'password' => env('FTP_PASSWORD'),
'port' => env('FTP_PORT'),
'ssl' => true,
'timeout' => 60,
],
'sftp' => [
'driver' => 'sftp',
'host' => env('FTP_HOST'),
'username' => env('FTP_USER'),
'password' => env('FTP_PASSWORD'),
'port' => env('FTP_PORT'),
'timeout' => 60,
],
I figured I'd try both ftp and sftp here, I then tried the following:
Storage::disk('ftp')->put('test.csv', $file);
and
Storage::disk('sftp')->put('test.csv', $file);
The first just timed out, the second gave me the message: League\Flysystem\Sftp\ConnectionErrorException: Could not login with username: ###, host: ### in...
Any ideas of what this could be or next steps I could take towards troubleshooting would be greatly appreciated, I feel like I just don't know what to try to get a better understanding of what's wrong here. Thanks!
EDIT:
I realized that previously I had always used the quick connect feature in FileZilla for this. I looked into it further and was able to confirm that the encryption has to be implicit FTP over TLS - So I'm wondering if there is a setting for that I'm missing.
The port 990 is for implicit TLS/SSL, as you have eventually figured out.
The implicit TLS/SSL is not supported by the PHP built-in FTP implementation. Neither is implicit TLS/SSL supported by flysystem used by Laravel (which probably internally uses PHP built-in FTP anyway).
The implicit TLS/SSL was a temporary hack back in 90s to allow legacy FTP software to use encrypted connection without modification. It was never something that should have been used in long term, definitely not 30 years later! The implicit FTP never even became part of FTP standard. Only the explicit TLS/SSL was standardized by RFC 4217 in 2005. Since then, noone should be using implicit TLS/SSL ever.
Get your FTP server fixed to use the explicit TLS/SSL.
Take a look at the additional settings (https://flysystem.thephpleague.com/v2/docs/adapter/ftp/) you can add to the filesystem.php for your ftp settings. Match them with what you have on your FileZilla settings and see if it helps.
Laravel underneath uses the flysystem adapters to connect to different storage types and you can reference the settings from the above URL.
Problem description:
I am unable to send SMS from AWS Lambda.
Controller Code
try {
$sms = AwsFacade::createClient('sns');
$result = $sms->publish([
'MessageAttributes' => [
'AWS.SNS.SMS.SenderID' => [
'DataType' => 'String',
'StringValue' => 'CyQuer',
],
'AWS.SNS.SMS.SMSType' => [
'DataType' => 'String',
'StringValue' => 'Transactional',
],
],
'Message' => "Hello John Doe".PHP_EOL."Use following Code to Login:".PHP_EOL."123456",
'PhoneNumber' => $phone,
]);
Log::info($result);
} catch (Exception $e) {
Log::error($e->getMessage());
}
Error message:
via web
{"message": "Internal server error"}Task timed out after 28.00 seconds
via Artisan
Task timed out after 120.00 seconds
Setup
Laravel application running on AWS Lambda using bref/laravel-bridge
IAM user for this application has been created. Locally everything works. Online everything works too except sending SMS.
Tried solutions:
The following packages were tried.
https://github.com/aws/aws-sdk-php
https://github.com/aws/aws-sdk-php-laravel
All the following described approaches worked locally on AWS Lambda but not.
Write AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY directly into config/aws.php
Write AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY directly in the code
$sms = AwsFacade::createClient('sns',[
'credentials' => [
'key' => '********************',
'secret' => '****************************************',
],
'region' => env('AWS_REGION', 'eu-central-1'),
'version' => 'latest',
'ua_append' => [
'L5MOD/' . AwsServiceProvider::VERSION,
],
]);
Giving all IAM users full admin access didn't work either.
Locally, all alternative solutions have also always worked!
Does anyone know the problem and have a solution for it? I've been trying to find a way for more than 24 hours. My last approach would be to rebuild the complete call via CURL and try it out, but I hope someone has/finds a solution.
For anyone facing similar issue, this could be/ most likely is due to lambda being configured in a VPC (most likely to give it access to RDS) and therefore losing internet connection, and by extension of that, access to other AWS services. One of the ways to work around this is to enable internet access to your VPC-bound lambda via setting up a NAT gateway (guide here). Alternatively, you can also use VPC Endpoints if the desired AWS service is supported. More info here.
In my experience, I had issues being unable to use specific credentials for certain clients in the AWS PHP SDK. I've seen that the best solution is to include the IAM permissions needed in the policy statements for the lambda function itself.
In this case for example, you may need to include the relevant statement for SNS like below:
{
"Action": [
"ses:*"
],
"Resource": "*",
"Effect": "Allow"
}
If you're using serverless to deploy, you may define it under provider.iamRoleStatements in the serverless.yml file like below:
provider:
name: aws
iamRoleStatements:
- Effect: Allow
Action:
- sns:*
Resource: '*'
IMPORTANT: Do provide only the minimum permissions that your lambda needs. The above statements are just examples.
After the relevant permissions are applied in this way, you may drop the specific credentials from the constructor of your AWS client.
I'm having problems connecting a Php client app to an Ssl enabled ActiveMq installation. I've looked at many sources and am getting more confused as I go.
My setup so far uses authentication via users/groups.properties and authorizationPlugin. This works fine on regular connections
For ActiveMq Ssl I followed a few articles and created the Jks store and certs and also configured with the following
<sslContext>
<sslContext keyStore="file:${activemq.base}/conf/server.ks"
keyStorePassword="$STORE_PASS"
trustStore="file:${activemq.base}/conf/server.ts"
trustStorePassword="$STORE_PASS" />
</sslContext>
<transportConnector
name="stomp+ssl" uri="stomp+ssl://0.0.0.0:61617?needClientAuth=true"/>
I also tried the ACTIVEMQ_SSL_OPTS approach. Both load fine when starting the server. Logs show Sll connector started. I also checked the php cli to make sure Sll is enabled on stomp installation
The problem I'm having is with the Php stomp client. First, these are the articles I read.
http://activemq.apache.org/how-do-i-use-ssl.html
http://php.net/manual/en/stomp.construct.php
https://github.com/stomp-php/stomp-php/wiki/Connectivity
From my understanding, there are two php stomp libs based on the documentation I can't figure out how to set all this up. The php site docs simply give an example of using the constructor with ssl protocol
$link = stomp_connect('ssl://localhost:61612', $user, $pass, $headers);
This doesn't work, I get a null cert error in the logs.
The other article that uses FuseSource stomp has options for including a client cert when establishing a connection but after getting further into the article it looks like it's just to authenticate via Sll cert and not with a user/pass.
https://github.com/rethab/php-stomp-cert-example/blob/master/README.md
So I went back to the previous stomp installation thinking there's a way to pass the client cert files but there doesn't seem to be an interface for it and no docs on the headers param which I'm assuming is not how to go about this.
Can someone shed some light on were in this complex mess I went wrong.
I don't know if you're still interested, but just in case someone stumbles upon this question hoping for an answer.
We're using https://github.com/stomp-php/stomp-php/ for our Stomp connection and this is roughly how we create the client:
function createClient($broker_url, $login, $password) {
$client = new \Stomp\Client($broker_url);
$sslContext = [
'ssl' => [
'cafile' => '/path/to/cert',
'verify_peer' => true,
'verify_peer_name' => false,
'ciphers' => 'HIGH',
],
];
$client->getConnection()->setContext($sslContext);
$client->setLogin($login, $password);
$client->connect();
return new \Stomp\StatefulStomp($client);
}
$broker_url should be in the format ssl://host:port.
I have a PHP Ratchet WebSocket server, running a custom chatroom on my website.
I would like to get the user's cookies when they connect to the server, so that I can get their session data and do something special if they are logged in / have specific permissions / etc.
In other posts (both on StackOverflow and otherwise), it is said that to get session data, you must get the client's cookies, which are supplied in their requests to the web server. The following line of code is meant to do this:
$conn->WebSocket->request->getCookies()
Where $conn is a ConnectionInterface.
My problem is, that when run this simply returns an empty array, even though the DevTools will show that there are indeed cookies.
Why might this not be returning a value?
just in case you're still searching for a solution:
1.In case your cookies only valid for a specific domain/subdomain - you should establish connection to your WebSocket server over the same address.
For example, cookies that only valid for admin.example.com won't be sent to a WebSocket server on your root domain (example.com).
2.In case your cookies only valid for a secure connection (https://), your WebSocket server should be over a secure connection too (wss://), Which is quite easy to achieve with the latest Ratchet version.
$webSock = new React\Socket\Server('0.0.0.0:8443', $loop);
$webSock = new React\Socket\SecureServer($webSock, $loop, [
'local_cert' => 'path_to_server_cert',
'local_pk' => 'path_to_private_key',
//'allow_self_signed' => TRUE,
'verify_peer' => FALSE
]);
3.With Ratchet 0.4.x, there is no longer a cookie parser.
You can only get it as a raw string and then parse it by yourself.
Get & Parse cookies with Ratchet 0.4.x :
$cookiesRaw = $conn->httpRequest->getHeader('Cookie');
if(count($cookiesRaw)) {
$cookiesArr = \GuzzleHttp\Psr7\parse_header($cookiesRaw)[0]; // Array of cookies
}
I am trying to make CCS server for the google cloud downstream and upstream messaging. I made a server using Java, it was working well before I wanted to shift it to php for my convenience.
I found out two library which is XMPPPHP and JAXL for XMPP connection.
I am trying to use JAXL first using the below code with SetTimeOut of php environment to more than 2 minutes.
<?php
include_once 'jaxl.php';
$client = new JAXL(array(
'jid'=>'<my_sender_ID>#gcm.googleapis.com',
'pass'=>'my_API_key',
'auth_type'=>'PLAIN',
'host' => 'gcm.googleapis.com',
'port' => '5235',
'force_tls' => true
));
$client->start();
echo "done";
?>
Studied the issue in the below url so changed the configuration too.
Link-1
Now I am getting:
Fatal error: Maximum execution time of 60 seconds exceeded in /var/www/vhosts/hostname/ccs-server/jaxl/core/jaxl_logger.php on line 51
When I tried my hands on XMPPPHP , I got the below link
Link-2
And got the same error as connecting to tcp://gcm.googleapis.com failed.
I am so worried if I could I transfer the server from Java or not.