All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.viber.bot.api.ViberClient Maven / Gradle / Ivy

Go to download

Use this library to communicate with the Viber API to develop a bot for https://developers.viber.com/.

There is a newer version: 1.0.11
Show newest version
package com.viber.bot.api;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.viber.bot.ViberEnvironmentConfiguration;
import com.viber.bot.event.Event;
import com.viber.bot.message.Message;
import com.viber.bot.message.MessageKeyboard;
import com.viber.bot.message.TrackingData;
import com.viber.bot.profile.BotProfile;
import com.viber.bot.profile.UserProfile;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import java.util.*;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.viber.bot.Preconditions.checkNotEmpty;

@ThreadSafe
class ViberClient {

    static final String VIBER_AUTH_TOKEN_HEADER = "X-Viber-Auth-Token";
    static final String USER_AGENT_HEADER_FIELD = "User-Agent";
    static final String USER_AGENT_HEADER_VALUE = "ViberBot-Java/";

    private static final String STATUS = "status";
    private static final int MAX_GET_ONLINE_IDS = 100;

    private static final Logger logger = LoggerFactory.getLogger(ViberClient.class);
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    private static final ObjectMapper objectMapper = new ObjectMapper();

    private final OkHttpClient httpClient = new OkHttpClient();
    private final ListeningExecutorService ioThreadPool = ViberEnvironmentConfiguration.getExecutorService();

    private final String authToken;
    private final String apiUrl;
    private final String userAgent;

    ViberClient(final @Nonnull String apiUrl, final @Nonnull String authToken) {
        this.apiUrl = checkNotEmpty(apiUrl);
        this.authToken = checkNotEmpty(authToken);
        this.userAgent = String.format("%s%s", USER_AGENT_HEADER_VALUE, fetchUserAgentVersion());
    }

    ListenableFuture setWebhook(final @Nullable String url, final @Nonnull Collection events) {
        return sendRequest(Endpoint.SET_WEBHOOK, new HashMap() {{
            put("url", url);
            put("event_types", events.stream().map(Event::getServerEventName).filter(Objects::nonNull).collect(Collectors.toList()));
        }});
    }

    ListenableFuture sendMessage(final @Nonnull BotProfile from, final @Nonnull UserProfile to,
                                              final @Nonnull Message message, final @Nonnull Optional optionalKeyboard,
                                              final @Nonnull Optional optionalTrackingData) {
        return sendRequest(Endpoint.SEND_MESSAGE, MessageToMapConverter.mapMessage(from, to, message, optionalKeyboard, optionalTrackingData));
    }

    ListenableFuture getAccountInfo() {
        return sendRequest(Endpoint.GET_ACCOUNT_INFO, Maps.newHashMap());
    }

    ListenableFuture getUserDetails(final @Nonnull String userId) {
        return sendRequest(Endpoint.GET_USER_DETAILS, new HashMap() {{
            put("id", checkNotEmpty(userId));
        }});
    }

    ListenableFuture getOnlineStatus(final @Nonnull Collection userIds) {
        checkState(!userIds.isEmpty() && userIds.size() < MAX_GET_ONLINE_IDS, String.format("Maximum %d user ids per request are allowed", MAX_GET_ONLINE_IDS));
        return sendRequest(Endpoint.GET_ONLINE_STATUS, new HashMap() {{
            put("ids", userIds);
        }});
    }

    @VisibleForTesting
    String fetchUserAgentVersion() {
        Properties properties = new Properties();
        try {
            properties.load(getClass().getClassLoader().getResourceAsStream("./version.properties"));
            return properties.getProperty("version");
        } catch (Exception e) {
            logger.error("Could not fetch user agent", e);
            return "unknown";
        }
    }

    @VisibleForTesting
    Request createRequest(@Nonnull Endpoint endpoint, RequestBody body) {
        return new Request.Builder()
                .url(String.format("%s%s", apiUrl, endpoint.uri))
                .header(VIBER_AUTH_TOKEN_HEADER, authToken)
                .header(USER_AGENT_HEADER_FIELD, userAgent)
                .post(body)
                .build();
    }

    private ListenableFuture sendRequest(final @Nonnull Endpoint endpoint, final @Nonnull Map parameters) {
        parameters.put("auth_token", authToken);

        final String json;
        try {
            json = objectMapper.writeValueAsString(checkNotNull(parameters));
        } catch (final Exception e) {
            return Futures.immediateFailedFuture(e);
        }

        final RequestBody body = RequestBody.create(JSON, json);
        final Request request = createRequest(endpoint, body);

        logger.debug("Sending request {}: {}", request, json);

        return ioThreadPool.submit(() -> {
            final Response response = httpClient.newCall(request).execute();
            final String responseBody = response.body().string();
            logger.debug("Got response for request {}: {}", request, responseBody);

            final Map responseMap = objectMapper.readValue(responseBody, Map.class);
            if (isResponseFailed(responseMap)) throw new ApiException(responseMap);
            else return new ApiResponse(responseMap);
        });
    }

    private boolean isResponseFailed(final Map responseMap) {
        return Integer.parseInt(responseMap.get(STATUS).toString()) != 0;
    }

    @VisibleForTesting
    enum Endpoint {
        SET_WEBHOOK("/set_webhook"),
        SEND_MESSAGE("/send_message"),
        GET_ACCOUNT_INFO("/get_account_info"),
        GET_USER_DETAILS("/get_user_details"),
        GET_ONLINE_STATUS("/get_online");

        private final String uri;

        Endpoint(final @Nonnull String uri) {
            this.uri = checkNotNull(uri);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy