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

com.botscrew.botframework.plivo.service.impl.PlivoTokenizedSenderImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2019 BotsCrew
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.botscrew.botframework.plivo.service.impl;

import com.botscrew.botframework.plivo.config.property.PlivoProperties;
import com.botscrew.botframework.plivo.constant.ApiMethod;
import com.botscrew.botframework.plivo.domain.action.AfterSendMessage;
import com.botscrew.botframework.plivo.domain.action.BeforeSendMessage;
import com.botscrew.botframework.plivo.domain.internal.LockingQueue;
import com.botscrew.botframework.plivo.exception.InterceptorInterruptedException;
import com.botscrew.botframework.plivo.model.PlivoBot;
import com.botscrew.botframework.plivo.model.PlivoMessage;
import com.botscrew.botframework.plivo.model.PlivoUser;
import com.botscrew.botframework.plivo.model.outgoing.PlivoMessageSentResponse;
import com.botscrew.botframework.plivo.model.outgoing.PlivoOutgoingRequest;
import com.botscrew.botframework.plivo.service.InterceptorsTrigger;
import com.botscrew.botframework.plivo.service.PlivoTokenizedSender;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.task.TaskExecutor;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.client.RestTemplate;

import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

import static com.botscrew.botframework.plivo.util.PlivoHttpHeadersCreator.createHeaders;

@Slf4j
public class PlivoTokenizedSenderImpl implements PlivoTokenizedSender {

    private final RestTemplate restTemplate;
    private final PlivoProperties properties;
    private final InterceptorsTrigger interceptorsTrigger;
    private final TaskExecutor taskExecutor;
    private final ThreadPoolTaskScheduler scheduler;
    private final Map> lockingRequests;

    public PlivoTokenizedSenderImpl(RestTemplate restTemplate, PlivoProperties properties,
                                    InterceptorsTrigger interceptorsTrigger, TaskExecutor taskExecutor,
                                    ThreadPoolTaskScheduler scheduler) {
        this.restTemplate = restTemplate;
        this.properties = properties;
        this.interceptorsTrigger = interceptorsTrigger;
        this.lockingRequests = new ConcurrentHashMap<>();
        this.taskExecutor = taskExecutor;
        this.scheduler = scheduler;
    }

    @Override
    public void send(PlivoBot bot, PlivoMessage message) {
        send(bot.getAuthId(), bot.getAuthToken(), bot.getPhoneNumber(), message.getUser(),
                message.getText());
    }

    @Override
    public ScheduledFuture send(PlivoBot bot, PlivoMessage message, int delay) {
        return scheduler.schedule(() -> send(bot, message), currentDatePlusMillis(delay));
    }

    @Override
    public void send(String authId, String authToken, Long botPhoneNumber, PlivoMessage plivoMessage) {
        send(authId, authToken, botPhoneNumber, plivoMessage.getUser(), plivoMessage.getText());
    }

    @Override
    public void send(String authId, String authToken, Long botPhoneNumber, PlivoUser plivoUser, String text) {

        try {
            triggerBeforeMessageInterceptors(plivoUser, text);
        } catch (InterceptorInterruptedException e) {
            log.info(e.getMessage());
            return;
        }

        log.debug(String.format("Posting message: \"%s\" to user %d", text, plivoUser.getPhoneNumber()));
        PlivoOutgoingRequest request = convertToOutgoingRequest(plivoUser, text, botPhoneNumber);
        Long id = plivoUser.getPhoneNumber();
        LockingQueue queue = lockingRequests.computeIfAbsent(id, k -> new LockingQueue<>());
        queue.push(request);
        if (!queue.isLocked()) startSendRequests(authId, authToken, plivoUser, queue);
    }

    @Override
    public ScheduledFuture send(String authId, String authToken, Long botPhoneNumber, PlivoUser plivoUser, String text,
                                int delay) {
        return scheduler.schedule(() -> send(authId, authToken, botPhoneNumber, plivoUser, text),
                currentDatePlusMillis(delay));
    }

    private void startSendRequests(String authId, String authToken, PlivoUser plivoUser,
                                   LockingQueue lockingQueue) {
        taskExecutor.execute(() -> {
            if (lockingQueue.tryLock()) {
                while (true) {
                    Optional requestOpt = lockingQueue.getNextOrUnlock();
                    if (!requestOpt.isPresent()) break;

                    PlivoOutgoingRequest top = requestOpt.get();
                    sendRequest(authId, authToken, plivoUser, top);
                }
            }
        });
    }

    private void sendRequest(String authId, String authToken, PlivoUser plivoUser,
                             PlivoOutgoingRequest request) {
        String url = properties.makeRequestUrl(authId, ApiMethod.MESSAGE);
        HttpEntity httpEntity = new HttpEntity<>(request,
                createHeaders(authId, authToken));

        ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity,
                PlivoMessageSentResponse.class);

        try {
            triggerAfterMessageInterceptors(plivoUser, request.getText(), responseEntity.getBody());
        } catch (InterceptorInterruptedException e) {
            log.info(e.getMessage());
        }
    }

    private PlivoOutgoingRequest convertToOutgoingRequest(PlivoUser plivoUser, String text, Long botPhoneNumber) {
        return PlivoOutgoingRequest.builder()
                .src(botPhoneNumber)
                .dst(plivoUser.getPhoneNumber())
                .text(text)
                .build();
    }

    private void triggerBeforeMessageInterceptors(PlivoUser plivoUser, String text) {
        BeforeSendMessage beforeSendMessage = new BeforeSendMessage(plivoUser, text);
        interceptorsTrigger.trigger(beforeSendMessage);
    }

    private void triggerAfterMessageInterceptors(PlivoUser plivoUser, String text, PlivoMessageSentResponse response) {
        AfterSendMessage afterSendMessage = new AfterSendMessage(plivoUser, text, response);
        interceptorsTrigger.trigger(afterSendMessage);
    }

    private Date currentDatePlusMillis(Integer seconds) {
        return addToDate(new Date(), Calendar.SECOND, seconds);
    }

    private Date addToDate(Date date, int calendarField, int amount) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(calendarField, amount);
        return c.getTime();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy