Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example of Server Sent Events with Coroutine #3377

Closed
ljfreelancer88 opened this issue Jun 10, 2020 · 5 comments
Closed

Example of Server Sent Events with Coroutine #3377

ljfreelancer88 opened this issue Jun 10, 2020 · 5 comments
Assignees

Comments

@ljfreelancer88
Copy link

Hi, I did checked the examples but I haven't seen any Server Sent Events with Coroutine using HTTP server. I'm trying to develop a simple PUB/SUB Server Sent Events using HTTP server.

Nice work for the Swoole by the way but the documentation needs a lot of improvement.

Thank you in advance

@huanghantao
Copy link
Member

Can you describe what you want to do with pseudo code first?

@ljfreelancer88
Copy link
Author

ljfreelancer88 commented Jun 11, 2020

I'll take the simple Chat app as an example scenario that compose of publisher and listener to a particular group or even a topic.

GROUP
Handsome, Beautiful and Married

PUBLISHERS & SUBSCRIBERS
John(Publisher & Subscriber to Handsome & Married group, meaning John can read and post messages to these 2 groups using the endpoints below)

Jane(Publisher & Subscriber to Beautiful group only, so she can read and post messages only to Beautiful group using the endpoint below. Jane can't post and read messages to Married group since She's not subscriber)

ENDPOINTS
GET|POST domain.com/group/handsome
GET|POST domain.com/group/beautiful
GET|POST domain.com/group/married

Enough for the scenario. Let's proceed to HTTP server. The default behavior of the S.S.E. keeps publishing/pushing "events" every 5sec if I'm not mistaken and I don't want that behavior. I want S.S.E. to publish only when there's a POST method that kicks. If there's no POST then sleep momentarily instead of keeps publishing. But if there's a better way, I'm open for changes.

For the storage, I'll try the coroutine Mysql client :) but it only fetch the data to particular subscribers at initial load and when there's a POST method that kicks.

I used the HTTP server sample from documentation with added S.S.E. header and tried to test and submit values using Curl POST and Curl GET but seems like it's not listening to these method because it keeps publishing without returning those values that has been submitted. That's why I'm seeking for a solution.

This was inspired by https://nchan.io, https://nats.io & https://mercure.rocks but it's overkill tool for a simple task and I want to leverage of using Swoole. And the idea of wrapping with coroutine was taken from this Golang package https://github.com/alexandrevicenzi/go-sse

If you have better implementation of S.S.E. PUB/SUB using HTTP or even TCP since you all know the in and out of Swoole. I'm very much open.

Thank you so much.

@ljfreelancer88
Copy link
Author

ljfreelancer88 commented Jun 14, 2020

Here is my code by the way.

$http->on('request', function ($request, $response) use ($messages, $http) {
    $response->header('Content-Type', 'text/event-stream');
    $response->header('Cache-Control', 'no-cache');
    $response->header('Connection', 'keep-alive');
    $response->header('X-Accel-Buffering', 'no');
    
    $startTime = time();
    $maxExecution = ini_get('max_execution_time');

    go(function() use ($response, $request, $startTime, $maxExecution, $http, $messages) {
    //while(true) {
        if (connection_aborted()) {
            // How to exit in Swoole way?
        }
            
        if (connection_status() !== 0) {
            // How to exit in Swoole way?
        }

        if (time() >= $startTime + $maxExecution) {
            // How to exit in Swoole way
        }

        // When I Curl POST with `event`. It is not getting the value from `event`
        $l = isset($request->post['event']) ? $request->post['event'] : 'Sleep for now;

        $date = date('H:i:s');
        $echo = json_encode(['time' => $date . $l]);        

        $response->end($echo);
       //co::sleep(1); 
    //}
    });
});

I can't even use the while loop inside the go to control the emitting time using sleep because of the detached error.

@doubaokun
Copy link
Contributor

@ljfreelancer88 as a library Swoole won't provide a whole solution of pubsub.

Use SSE in Swoole is nothing new compare with the other libraries.

$http->on('request', function ($request, $response) {
    $response->header('Content-Type', 'text/event-stream');
    $response->header('Cache-Control', 'no-cache');
    
    $counter = rand(1, 10);

    while (true) {
        $data = "event: ping\n";
        $response->write($data);
        $curDate = date(DATE_ISO8601);
        $data = 'data: {"time": "' . $curDate . '"}';
        $data .= "\n\n";
        $response->write($data);
        $counter--;
        if (!$counter) {
           $data = 'data: This is a message at time ' . $curDate . "\n\n";
           $response->end($data);
           break;
        }
        co::sleep(1);
    }
});

@andreybolonin
Copy link

@doubaokun Hi, any ideas how to implement pubsub on top of Swoole?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants