Como alimentar EventSource de um HTML5 com um endpoint personalizado da API REST?

4

Então, nessa missão de criar um pseudo serviço de bate-papo da Web personalizado com o Telegram, estou tentando obter as mensagens que o Telegram envia para o servidor e redirecioná-las ao frontend. O SSE com o HTML5 EventSource parece a melhor e mais fácil solução para isso.

O problema é que o EventSource precisa de 'Content-Type: text/event-stream' e 'Cache-Control: no-cache' de cabeçalhos definidos na resposta do servidor.

Se um WP_REST_REQUEST for retornado na função que define a resposta ("set_telegram_response", abaixo), nada chegará no EventSource. Mas se a resposta for repetida, EventSource fechará a conexão, alegando que o servidor está enviando uma resposta JSON em vez de um text/event-stream one.

A seguir estão os barebones da classe que escrevi para isso. Se eu puxar um pedido GET nesse endpoint, ele retornará a string "Some text". Mas o script EventSource não imprime nada, como se a resposta estivesse vazia.

class Chat
{
    private static $token, $telegram, $chat_id;
    public $telegram_message;

    public function __construct()
    {
        self::$chat_id = "<TELEGRAM-CHAT-ID>";
        self::$token = "<TELEGRAM-TOKEN>";
        self::$telegram = "https://api.telegram.org:443/bot" . self::$token;

        add_action('rest_api_init', array( $this, 'set_telegram_message_endpoint' ));
        add_action('admin_post_chat_form', array( $this, 'chat_telegram' ));
        add_action('admin_post_nopriv_chat_form', array( $this, 'chat_telegram' ));
    }

    public function set_telegram_message_endpoint()
    {
        register_rest_route('mybot/v2', 'bot', array(
            array(
                'methods' => WP_REST_SERVER::CREATABLE,
                'callback' => array( $this, 'get_telegram_message' ),
            ),
            array(
                'methods' => WP_REST_SERVER::READABLE,
                'callback' => array( $this, 'set_telegram_message' ),
            ),
        ));
    }

    public function set_telegram_message( WP_REST_REQUEST $request )
    {
        $new_response = new WP_REST_Response( "Some text" . PHP_EOL . PHP_EOL, 200 );
        $new_response->header( 'Content-Type', 'text/event-stream' );
        $new_response->header( 'Cache-Control', 'no-cache' );
        ob_flush();
        return $new_response;
    }

    public function get_telegram_message( WP_REST_REQUEST $request )
    {
        $this->telegram_message = $request;
        //return rest_ensure_response( $request['message']['text'] );
    }

    public function chat_telegram( $input = null )
    {
        $mensaje = $input === '' ? $_POST['texto'] : $input;
        echo $mensaje;

        $query = http_build_query([
            'chat_id' => self::$chat_id,
            'text' => $mensaje,
            'parse_mode' => "Markdown",
        ]);

        $response = file_get_contents( self::$telegram . '/sendMessage?' . $query );
        return $response;
    }
}

Passei a tarde toda e parte desta manhã lendo a documentação da API REST, mas não encontrei nenhuma pista sobre o que poderia estar errado ou como fazer isso.

BTW, o servidor que estou implantando isso pode manipular solicitações EventSource - Eu tentei em um script PHP de teste e funcionou bem. Então eu realmente não sei o que está acontecendo aqui. Qualquer ajuda seria muito apreciada.

    
por acidrums4 13.10.2018 / 15:05

2 respostas

2

Isso ocorre porque a API restante usa internamente json_encode() para gerar os dados. Existem 2 maneiras de resolver isso.

1. Impedir que a API envie os dados

Isso pode ser um pouco estranho e gerar alguns problemas, mas você pode definir o tipo de cabeçalho e fazer eco do conteúdo antes de retornar os dados:

header( 'Content-Type: text/event-stream' );
header( 'Cache-Control: no-cache' );

// Echo whatever data you got here

// Prevent the API from continuing
exit();

Como essa não é a maneira padrão de usar a API, isso pode causar alguns problemas. Eu não tentei isso sozinho.

2. Use admin-ajax.php

Em vez da API restante, use o admin AJAX. A implementação é a mesma. Basicamente, se você usar json_encode() ao lado de die(); , obterá os mesmos resultados da API de descanso. A página do códice sobre este tópico abrange quase tudo. Usando o admin AJAX, você pode controlar totalmente os cabeçalhos e o tipo de saída.

    
por Jack Johansson 15.10.2018 / 18:25
0

Eu não posso testar isso, mas você pode tentar alterar os cabeçalhos de resposta usando este gancho:

add_action( 'rest_api_init', function() {

    remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );

    add_filter( 'rest_pre_serve_request', function( $value ) {

        header( 'Content-Type', 'text/event-stream' );
        header( 'Cache-Control', 'no-cache' );

        return $value;

    });
}, 15 );

Eu tive a idéia de aqui .

    
por dboris 16.10.2018 / 14:17

Tags