br.com.jbugbrasil.bot.telegram.api.UpdatesReceiver.java Source code

Java tutorial

Introduction

Here is the source code for br.com.jbugbrasil.bot.telegram.api.UpdatesReceiver.java

Source

/*
 The MIT License (MIT)
    
 Copyright (c) 2017 JBug:Brasil <contato@jbugbrasil.com.br>
    
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
 the Software without restriction, including without limitation the rights to
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:
    
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
    
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package br.com.jbugbrasil.bot.telegram.api;

import br.com.jbugbrasil.bot.api.conf.systemproperties.BotProperty;
import br.com.jbugbrasil.bot.api.object.GetUpdatesConfProducer;
import br.com.jbugbrasil.bot.api.object.Message;
import br.com.jbugbrasil.bot.api.object.MessageUpdate;
import br.com.jbugbrasil.bot.api.object.TelegramResponse;
import br.com.jbugbrasil.bot.telegram.api.httpclient.BotCloseableHttpClient;

import br.com.jbugbrasil.bot.telegram.api.polling.JBugBrasilLongPoolingBot;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.lang.invoke.MethodHandles;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.logging.Logger;

@ApplicationScoped
public class UpdatesReceiver implements Runnable {

    private Logger log = Logger.getLogger(MethodHandles.lookup().lookupClass().getName());

    private final String TELEGRAM_UPDATE_ENDPOINT = "https://api.telegram.org/bot%s/getUpdates";

    @Inject
    @BotProperty(name = "br.com.jbugbrasil.bot.telegram.token", required = true)
    String botTokenId;

    @Inject
    @BotProperty(name = "br.com.jbugbrasil.bot.telegram.userId", required = true)
    String botUserId;

    @Inject
    private BotCloseableHttpClient httpClient;

    private Long lastUpdateId = 0L;

    private volatile boolean running = false;

    private RequestConfig requestConfig;

    private Thread currentThread;

    @Inject
    JBugBrasilLongPoolingBot callback;

    /**
     * Mtodo responsvel por configurar o HttpClient e iniciar o receiver chamando o mtodo <b>run</b> desta classe.
     */
    public synchronized void start() {
        requestConfig = RequestConfig.copy(RequestConfig.custom().build()).setSocketTimeout(75 * 1000)
                .setConnectTimeout(75 * 1000).setConnectionRequestTimeout(75 * 1000).build();
        running = true;
        currentThread = new Thread(this);
        currentThread.setDaemon(true);
        currentThread.setName("Telegram-" + botUserId);
        currentThread.start();
    }

    /**
     * Quando chamado, interrompe esta thread.
     */
    public void interrupt() {
        if (running) {
            running = false;
            currentThread.interrupt();
        }
    }

    /**
     * Inicia o Receiver, cada nova mensagem enviada a ser recebida e ir notificar os bots que implementam esta api atravs da
     * chamada <b>callback.onUpdateReceived(u);</b>
     * Sua configurao  feita atraes da classe {@link GetUpdatesConfProducer}
     *
     * Esta thread permanece em execuo juntamente com o bot que o implementa at o fim de seu ciclo de vida.
     * O intervalo de cada request  <b>600ms</b>
     *
     */
    @Override
    public synchronized void run() {
        ObjectMapper objectMapper = new ObjectMapper();
        while (running) {
            GetUpdatesConfProducer getUpdates = new GetUpdatesConfProducer().setLimit(100).setTimeout(10 * 1000)
                    .setOffset(lastUpdateId + 1);
            log.finest("receiver config -> " + getUpdates.toString());
            try {
                String url = String.format(TELEGRAM_UPDATE_ENDPOINT, botTokenId);

                HttpPost httpPost = new HttpPost(url);
                httpPost.addHeader("charset", StandardCharsets.UTF_8.name());
                httpPost.setConfig(requestConfig);
                httpPost.setEntity(new StringEntity(objectMapper.writeValueAsString(getUpdates),
                        ContentType.APPLICATION_JSON));

                try (CloseableHttpResponse response = httpClient.get().execute(httpPost)) {
                    HttpEntity responseEntity = response.getEntity();
                    BufferedHttpEntity buf = new BufferedHttpEntity(responseEntity);
                    String responseContent = EntityUtils.toString(buf, StandardCharsets.UTF_8);

                    if (response.getStatusLine().getStatusCode() != 200) {
                        log.warning("Erro ao receber resposta da API do Telegram, cdigo de status  "
                                + response.getStatusLine().getStatusCode());
                        synchronized (this) {
                            this.wait(600);
                        }
                    }

                    TelegramResponse<ArrayList<MessageUpdate>> updates = objectMapper.readValue(responseContent,
                            new TypeReference<TelegramResponse<ArrayList<MessageUpdate>>>() {
                            });

                    if (updates.getResult().isEmpty()) {
                        this.wait(600);
                    }

                    updates.getResult().removeIf(n -> n.getUpdateId() < lastUpdateId);
                    lastUpdateId = updates.getResult().parallelStream().map(MessageUpdate::getUpdateId)
                            .max(Long::compareTo).orElse(0L);
                    updates.getResult().stream().forEach(u -> {
                        // make sure that even edited messages will be intercepted by the bot.
                        if (null != u.getEditedMessage()) {
                            log.finest("is updated message? " + true);
                            Message msg = new Message();
                            msg.setChat(u.getEditedMessage().getChat());
                            msg.setDate(u.getEditedMessage().getDate());
                            msg.setEntities(u.getEditedMessage().getEntities());
                            msg.setFrom(u.getEditedMessage().getFrom());
                            msg.setMessageId(u.getEditedMessage().getMessageId());
                            msg.setText(u.getEditedMessage().getText());
                            u.setMessage(msg);
                        }
                        // notify the implementations of JBugBrasilLongPoolingBot about the received messages.
                        log.finest("Message is [ " + u.toString() + "]");
                        callback.onUpdateReceived(u);

                    });
                    // wait 600ms before check for updates
                    this.wait(600);

                }
            } catch (final Exception e) {
                e.printStackTrace();
                log.warning("Erro encontrado " + e.getMessage());
            }
        }
    }

}