com.botscrew.messengercdk.service.impl.TokenizedSenderImpl Maven / Gradle / Ivy
/*
* Copyright 2018 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.messengercdk.service.impl;
import com.botscrew.messengercdk.config.property.MessengerProperties;
import com.botscrew.messengercdk.domain.action.AfterSendMessage;
import com.botscrew.messengercdk.domain.action.BeforeSendMessage;
import com.botscrew.messengercdk.domain.internal.LockingQueue;
import com.botscrew.messengercdk.exception.InterceptorInterruptedException;
import com.botscrew.messengercdk.model.MessengerBot;
import com.botscrew.messengercdk.model.MessengerUser;
import com.botscrew.messengercdk.model.incomming.Response;
import com.botscrew.messengercdk.model.outgoing.builder.GenericTemplate;
import com.botscrew.messengercdk.model.outgoing.builder.QuickReplies;
import com.botscrew.messengercdk.model.outgoing.builder.TextMessage;
import com.botscrew.messengercdk.model.outgoing.element.TemplateElement;
import com.botscrew.messengercdk.model.outgoing.element.quickreply.QuickReply;
import com.botscrew.messengercdk.model.outgoing.request.Request;
import com.botscrew.messengercdk.service.InterceptorsTrigger;
import com.botscrew.messengercdk.service.TokenizedSender;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
/**
* Implementation of {@link TokenizedSender} used by default
*/
@Slf4j
public class TokenizedSenderImpl implements TokenizedSender {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultReportHandler.class);
private final RestTemplate restTemplate;
private final MessengerProperties properties;
private final ThreadPoolTaskScheduler scheduler;
private final TaskExecutor taskExecutor;
private final InterceptorsTrigger interceptorsTrigger;
private final Map> lockingRequests;
public TokenizedSenderImpl(RestTemplate restTemplate,
MessengerProperties properties,
ThreadPoolTaskScheduler scheduler,
TaskExecutor taskExecutor,
InterceptorsTrigger interceptorsTrigger) {
this.restTemplate = restTemplate;
this.properties = properties;
this.scheduler = scheduler;
this.taskExecutor = taskExecutor;
this.interceptorsTrigger = interceptorsTrigger;
lockingRequests = new ConcurrentHashMap<>();
}
@Override
public void send(String token, Request request) {
post(token, request);
}
@Override
public void send(String token, MessengerUser recipient, String text) {
Request request = TextMessage.builder()
.user(recipient)
.text(text)
.build();
post(token, request);
}
@Override
public ScheduledFuture send(String token, MessengerUser recipient, String text, Integer delayMillis) {
return scheduler.schedule(() -> send(token, recipient, text), currentDatePlusMillis(delayMillis));
}
@Override
public void send(String token, MessengerUser recipient, String text, List quickReplies) {
Request request = QuickReplies.builder()
.user(recipient)
.quickReplies(quickReplies)
.text(text)
.build();
post(token, request);
}
@Override
public ScheduledFuture send(String token, MessengerUser recipient, String text, List quickReplies, Integer delayMillis) {
return scheduler.schedule(() -> send(token, recipient, text, quickReplies), currentDatePlusMillis(delayMillis));
}
@Override
public void send(String token, MessengerUser recipient, List elements) {
Request request = GenericTemplate.builder()
.user(recipient)
.elements(elements)
.build();
post(token, request);
}
@Override
public ScheduledFuture send(String token, MessengerUser recipient, List elements, Integer delayMillis) {
return scheduler.schedule(() -> send(token, recipient, elements), currentDatePlusMillis(delayMillis));
}
@Override
public void send(String token, MessengerUser recipient, List elements, List quickReplies) {
Request request = GenericTemplate.builder()
.user(recipient)
.elements(elements)
.quickReplies(quickReplies)
.build();
post(token, request);
}
@Override
public ScheduledFuture send(String token, MessengerUser recipient, List elements, List quickReplies, Integer delayMillis) {
return scheduler.schedule(() -> send(token, recipient, elements, quickReplies), currentDatePlusMillis(delayMillis));
}
@Override
public ScheduledFuture send(String token, Request request, Integer delayMillis) {
return scheduler.schedule(() -> send(token, request), currentDatePlusMillis(delayMillis));
}
private void post(String token, Request request) {
LOGGER.debug("Posting message: \n{}", request);
try {
triggerBeforeMessageInterceptors(token, request);
}
catch (InterceptorInterruptedException e) {
log.info(e.getMessage());
return;
}
Long id = request.getRecipient().getId();
LockingQueue queue = lockingRequests.computeIfAbsent(id, k -> new LockingQueue<>());
queue.push(request);
if (!queue.isLocked()) startSendRequests(token, queue);
}
private void startSendRequests(String token, LockingQueue lockingQueue) {
taskExecutor.execute(() -> {
if (lockingQueue.tryLock()) {
while (true) {
Optional requestOpt = lockingQueue.getNextOrUnlock();
if (!requestOpt.isPresent()) break;
Request top = requestOpt.get();
sendRequest(top, token);
}
}
});
}
private void sendRequest(Request request, String token) {
try {
Response response = restTemplate.postForObject(properties.getMessagingUrl(token), request, Response.class);
triggerAfterMessageInterceptors(token, request, response);
} catch (HttpClientErrorException | HttpServerErrorException e) {
LOGGER.error(e.getResponseBodyAsString() + " for request: " + request);
}
catch (Exception e) {
LOGGER.error(e.getMessage() + " for request: " + request);
}
}
private void triggerBeforeMessageInterceptors(String token, Request request) {
BeforeSendMessage beforeSendMessage = new BeforeSendMessage(token, request);
interceptorsTrigger.trigger(beforeSendMessage);
}
private void triggerAfterMessageInterceptors(String token, Request request, Response response) {
AfterSendMessage afterSendMessage = new AfterSendMessage(token, request, response);
interceptorsTrigger.trigger(afterSendMessage);
}
private Date currentDatePlusMillis(Integer millis) {
return addToDate(new Date(), Calendar.MILLISECOND, millis);
}
private Date addToDate(Date date, int calendarField, int amount) {
Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(calendarField, amount);
return c.getTime();
}
@Override
public void send(MessengerBot bot, Request request) {
post(bot.getAccessToken(), request);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy