amphp / websocket-client

Async WebSocket client for PHP based on Amp.
https://amphp.org/websocket-client
MIT License
147 stars 17 forks source link

How to receive msg in a callback #51

Closed sacOO7 closed 4 months ago

sacOO7 commented 4 months ago

Currently library documentation provides a way to process messages inside a loop

foreach ($connection as $message) {
    $payload = $message->buffer();
    ....
}

I was curious why no callback is provided like https://github.com/sirn-se/websocket-php?tab=readme-ov-file#client With the given for loop, loop will go into blocking state, waiting for new messages to be processed

sacOO7 commented 4 months ago

Point is, new message should be posted on eventloop when received. There shouldn't be explicit polling behavior from client code that blocks existing eventloop

kelunik commented 4 months ago

It isn't polling. It's entirely non-blocking IO under the hood. You can use Amp\async() to start another coroutine, see https://amphp.org/architecture#coroutines

sacOO7 commented 4 months ago

I didn't quite get this. Documentation doesn't provide a way to return result from a coroutine. Can you post the code, it will be really helpful

kelunik commented 4 months ago

What kind of result do you want to return? You can just return from the callable passed to async() and await + unwrap that value using Future::await().

The callback version would look like this if you really want this:

$callback = function ($payload) {
    // ...
};

$connectionHandler = async(function () use ($callback) {
    foreach ($connection as $message) {
        $payload = $message->buffer();
        async($callback, $payload);
    }
});

// somewhere:
$connectionHandler->await();
sacOO7 commented 4 months ago

Thanks this is helpful. So, $connectionHandler->await() call is not blocking eventloop right? Or does it wait for at least one message to arrive ? I wanted a code to receive msg inside a callback like https://github.com/sirn-se/websocket-php?tab=readme-ov-file#client. This will not block eventloop as such

sacOO7 commented 4 months ago

What if I don't use $connectionHandler->await(); and instead use just $connectionHandler().

$callback = function ($payload) {
    // ...
};

$connectionHandler = async(function () use ($callback) {
        // This will run in a separate coroutine
    foreach ($connection as $message) {
        $payload = $message->buffer();
        async($callback, $payload); // $callback method will be called on the eventloop right?
    }
});
$connectionHandler() // dont want to wait on receive messages, it should happen asynchronously
kelunik commented 4 months ago

You can also avoid awaiting, but then you'll need to manually run the event loop using EventLoop::run()

await() or rather the suspension mechanism used internally automatically runs the event loop if invoked in the main context and interrupts it as soon as the operation finished.

sacOO7 commented 4 months ago

Thanks for the response! This is really helpful. I had one last request to make. Can we please update README with above code. I am sure lot of people will be interested to use the same. Also, looking at active issues, I had a question if library is actively maintained?

kelunik commented 4 months ago

Please send a PR! It's probably best if someone writes down everything you need to get started with a fresh mind.

What makes you think it isn't maintained?

sacOO7 commented 4 months ago

Thanks, I might as well create PR for the same 😀

sacOO7 commented 4 months ago

Actually there are lot of pending issues on the repo. Looks pretty old and aren't resolved yet, so I was wondering if issue still persist with the library.

kelunik commented 4 months ago

Most of them are questions rather than actual issues in the library, but we could likely close most of them. We do that from time to time, but working on code is much more effective than closing old question issues. Likely something we should automate.