Реализация функционала callback. Удален механизм InsertWords. Добавлено SendingService - расширение Sending.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Struchkov Mark 2023-01-15 11:33:45 +03:00
parent 3d62811e3c
commit 5e0b6f38d4
Signed by: upagge
GPG Key ID: D3018BE7BA428CA6
27 changed files with 298 additions and 225 deletions

View File

@ -2,6 +2,7 @@ package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.BoxAnswer; import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.SendType; import dev.struchkov.godfather.main.domain.SendType;
import dev.struchkov.godfather.main.domain.SentBox;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -10,16 +11,14 @@ import org.jetbrains.annotations.NotNull;
* *
* @author upagge [08/07/2019] * @author upagge [08/07/2019]
*/ */
public interface Sending { public interface Sending<MESSAGE_ID> {
/** /**
* Отправляет сообщение пользователю * Отправляет сообщение пользователю
* *
* @param boxAnswer Объект с данными, которые необходимо отправить * @param boxAnswer Объект с данными, которые необходимо отправить
*/ */
Uni<Void> send(@NotNull BoxAnswer boxAnswer); Uni<SentBox<MESSAGE_ID>> send(@NotNull BoxAnswer boxAnswer);
void addPreSendProcess(@NotNull PreSendProcessing processing);
/** /**
* Возвращает тип объекта отправляющего ответ пользователя. В зависимости от типа ответ будет отправлен с помощью * Возвращает тип объекта отправляющего ответ пользователя. В зависимости от типа ответ будет отправлен с помощью

View File

@ -0,0 +1,21 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.SentBox;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
/**
* Интерфейс для отправки ответов пользователю.
*
* @author upagge [08/07/2019]
*/
public interface SendingService<MESSAGE_ID> extends Sending<MESSAGE_ID> {
void addPreSendProcess(@NotNull PreSendProcessing processing);
Uni<Void> deleteMessage(@NotNull String personId, @NotNull MESSAGE_ID messageId);
Uni<SentBox<MESSAGE_ID>> replaceMessage(@NotNull String personId, @NotNull MESSAGE_ID messageId, @NotNull BoxAnswer newAnswer);
}

View File

@ -2,23 +2,24 @@ package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.main.domain.BoxAnswer; import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.SendType; import dev.struchkov.godfather.main.domain.SendType;
import dev.struchkov.godfather.main.domain.SentBox;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Optional;
/** /**
* Интерфейс для отправки ответов пользователю. * Интерфейс для отправки ответов пользователю.
* *
* @author upagge [08/07/2019] * @author upagge [08/07/2019]
*/ */
public interface Sending { public interface Sending<MESSAGE_ID> {
/** /**
* Отравляет сообщение пользователю. * Отравляет сообщение пользователю.
* *
* @param boxAnswer Объект с данными, которые необходимо отправить * @param boxAnswer Объект с данными, которые необходимо отправить
*/ */
void send(@NotNull BoxAnswer boxAnswer); Optional<SentBox<MESSAGE_ID>> send(@NotNull BoxAnswer boxAnswer);
void addPreSendProcess(@NotNull PreSendProcessing processing);
/** /**
* Возвращает тип объекта отправляющего ответ пользователя. В зависимости от типа ответ будет отправлен с помощью * Возвращает тип объекта отправляющего ответ пользователя. В зависимости от типа ответ будет отправлен с помощью

View File

@ -0,0 +1,22 @@
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.SentBox;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
/**
* Интерфейс для отправки ответов пользователю.
*
* @author upagge [08/07/2019]
*/
public interface SendingService<MESSAGE_ID> extends Sending<MESSAGE_ID> {
void addPreSendProcess(@NotNull PreSendProcessing processing);
void deleteMessage(@NotNull String personId, @NotNull MESSAGE_ID messageId);
Optional<SentBox<MESSAGE_ID>> replaceMessage(@NotNull String personId, @NotNull MESSAGE_ID messageId, @NotNull BoxAnswer newAnswer);
}

View File

@ -1,47 +0,0 @@
package dev.struchkov.godfather.main.core.utils;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static dev.struchkov.haiti.utils.Exceptions.utilityClass;
/**
* Класс для вставки слов в текстовую строку вместо подстрок - шаблонов маркеров.
*
* @author upagge [08/07/2019]
*/
public class InsertWords {
private static final Pattern pattern = Pattern.compile("\\{(\\d+)}");
private InsertWords() {
utilityClass();
}
/**
* Заменяет шаблон {n} в строке на слово из списка, где n - это порядковое число.
*
* @param text Текстовая строка
* @param words Список слов, которые необходимо поместить вместо шаблона
* @return Модифицированная строка
*/
public static String insert(@NotNull String text, List<String> words) {
final Matcher m = pattern.matcher(text);
final StringBuilder result = new StringBuilder();
while (m.find()) {
if (Integer.parseInt(m.group(1)) < words.size()) {
m.appendReplacement(result, words.get(Integer.parseInt(m.group(1))));
} else {
m.appendReplacement(result, m.group(0));
}
}
m.appendTail(result);
return result.toString();
}
}

View File

@ -36,14 +36,14 @@ import static java.util.Collections.emptySet;
public class GeneralAutoResponder<M extends Message> { public class GeneralAutoResponder<M extends Message> {
private final PersonSettingService personSettingService; protected final PersonSettingService personSettingService;
private final StorylineService<M> storyLineService; protected final StorylineService<M> storyLineService;
protected Map<String, ActionUnit> actionUnitMap = new HashMap<>(); protected Map<String, ActionUnit> actionUnitMap = new HashMap<>();
protected List<Modifiable<M>> modifiable; protected List<Modifiable<M>> modifiable;
private ErrorHandler errorHandler; protected ErrorHandler errorHandler;
protected GeneralAutoResponder( protected GeneralAutoResponder(
Sending sending, Sending<?> sending,
PersonSettingService personSettingService, PersonSettingService personSettingService,
StorylineService<M> storyLineService StorylineService<M> storyLineService
) { ) {
@ -52,7 +52,7 @@ public class GeneralAutoResponder<M extends Message> {
init(sending); init(sending);
} }
private void init(Sending sending) { private void init(Sending<?> sending) {
actionUnitMap.put(TypeUnit.CHECK, new AnswerCheckAction<>(sending)); actionUnitMap.put(TypeUnit.CHECK, new AnswerCheckAction<>(sending));
actionUnitMap.put(TypeUnit.TEXT, new AnswerTextAction(sending)); actionUnitMap.put(TypeUnit.TEXT, new AnswerTextAction(sending));
actionUnitMap.put(TypeUnit.REPLACE_CMD, new ReplaceCmdAction()); actionUnitMap.put(TypeUnit.REPLACE_CMD, new ReplaceCmdAction());

View File

@ -20,9 +20,9 @@ import static dev.struchkov.haiti.utils.Checker.checkTrue;
*/ */
public class AnswerCheckAction<M extends Message> implements ActionUnit<AnswerCheck<M>, M> { public class AnswerCheckAction<M extends Message> implements ActionUnit<AnswerCheck<M>, M> {
private final Sending sending; private final Sending<?> sending;
public AnswerCheckAction(Sending sending) { public AnswerCheckAction(Sending<?> sending) {
this.sending = sending; this.sending = sending;
} }

View File

@ -1,15 +1,13 @@
package dev.struchkov.godfather.quarkus.core.action; package dev.struchkov.godfather.quarkus.core.action;
import dev.struchkov.godfather.main.core.utils.InsertWords;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message; import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Sending; import dev.struchkov.godfather.quarkus.context.service.Sending;
import dev.struchkov.godfather.quarkus.core.unit.AnswerText; import dev.struchkov.godfather.quarkus.core.unit.AnswerText;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit; import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest; import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import dev.struchkov.godfather.quarkus.core.unit.func.collback.CallBackConsumer;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull; import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/** /**
@ -19,9 +17,9 @@ import static dev.struchkov.haiti.utils.Checker.checkNotNull;
*/ */
public class AnswerTextAction implements ActionUnit<AnswerText<Message>, Message> { public class AnswerTextAction implements ActionUnit<AnswerText<Message>, Message> {
private final Sending sending; private final Sending<?> sending;
public AnswerTextAction(Sending sending) { public AnswerTextAction(Sending<?> sending) {
this.sending = sending; this.sending = sending;
} }
@ -29,31 +27,20 @@ public class AnswerTextAction implements ActionUnit<AnswerText<Message>, Message
public Uni<UnitRequest<MainUnit, Message>> action(UnitRequest<AnswerText<Message>, Message> unitRequest) { public Uni<UnitRequest<MainUnit, Message>> action(UnitRequest<AnswerText<Message>, Message> unitRequest) {
final Message message = unitRequest.getMessage(); final Message message = unitRequest.getMessage();
final AnswerText<Message> unit = unitRequest.getUnit(); final AnswerText<Message> unit = unitRequest.getUnit();
return Uni.createFrom().voidItem()
.chain(request -> unit.getAnswer().processing(message))
.onItem().ifNotNull().transformToUni(boxAnswer -> replaceMarkers(unit, message, boxAnswer))
.onItem().ifNotNull().transformToUni(boxAnswer -> {
final Sending answerTextSending = unit.getSending();
boxAnswer.setRecipientIfNull(message.getPersonId());
if (checkNotNull(answerTextSending)) {
return answerTextSending.send(boxAnswer);
} else {
return sending.send(boxAnswer);
}
}).replaceWith(UnitRequest.of(unit, message));
}
private Uni<BoxAnswer> replaceMarkers(AnswerText<Message> answerText, Message message, BoxAnswer boxAnswer) { return unit.getAnswer().processing(message)
return Uni.createFrom().item(answerText.getInsert()) .onItem().ifNotNull().transformToUni(boxAnswer -> {
.onItem().ifNotNull().transformToUni(insert -> insert.insert(message.getPersonId())) boxAnswer.setRecipientIfNull(message.getPersonId());
.onItem().ifNotNull().transform(words -> { return sending.send(boxAnswer);
if (checkNotEmpty(words)) {
final String newMessage = InsertWords.insert(boxAnswer.getMessage(), words);
boxAnswer.setMessage(newMessage);
}
return boxAnswer;
}) })
.replaceIfNullWith(boxAnswer); .onItem().ifNotNull().transformToUni(sentBox -> {
final CallBackConsumer callBack = unit.getCallBack();
if (checkNotNull(callBack)) {
return callBack.processing(sentBox);
}
return Uni.createFrom().voidItem();
})
.replaceWith(UnitRequest.of(unit, message));
} }
} }

View File

@ -9,6 +9,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException; import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Inspector.isNotNull; import static dev.struchkov.haiti.utils.Inspector.isNotNull;
public class StorylineContextMapImpl implements StorylineContext { public class StorylineContextMapImpl implements StorylineContext {
@ -33,27 +34,37 @@ public class StorylineContextMapImpl implements StorylineContext {
return Uni.createFrom().nullItem(); return Uni.createFrom().nullItem();
} }
@Override
public <T> Uni<T> removeKey(@NotNull String personId, @NotNull ContextKey<?> key) {
isNotNull(personId, key);
if (map.containsKey(personId)) {
final Map<String, Object> storage = map.get(personId);
final T object = (T) storage.get(key.getValue());
if (checkNotNull(object) && object.getClass().equals(key.getType())) {
storage.remove(key.getValue());
return Uni.createFrom().item(object);
}
}
return Uni.createFrom().nullItem();
}
@Override @Override
public <T> Uni<T> getByKeyOrThrow(@NotNull String personId, @NotNull ContextKey<T> key) { public <T> Uni<T> getByKeyOrThrow(@NotNull String personId, @NotNull ContextKey<T> key) {
return getByKey(personId, key) return getByKey(personId, key)
.onItem().ifNull().failWith(notFoundException("Не найдено значение ключа {0}, для пользователя {1}", key.getValue(), personId)); .onItem().ifNull().failWith(notFoundException("Не найдено значение ключа {0}, для пользователя {1}", key.getValue(), personId));
} }
@Override
public Uni<Map<String, Object>> getAllSaveElement(@NotNull String personId) { public Uni<Map<String, Object>> getAllSaveElement(@NotNull String personId) {
isNotNull(personId); isNotNull(personId);
return Uni.createFrom().item(map.get(personId)); return Uni.createFrom().item(map.get(personId));
} }
@Override
public Uni<Void> removeAll(@NotNull String personId) { public Uni<Void> removeAll(@NotNull String personId) {
isNotNull(personId); isNotNull(personId);
map.remove(personId); map.remove(personId);
return Uni.createFrom().voidItem(); return Uni.createFrom().voidItem();
} }
public Uni<Void> removeByKey(@NotNull String personId, @NotNull ContextKey<?> key) {
isNotNull(personId, key);
map.computeIfAbsent(personId, k -> new HashMap<>()).remove(key.getValue());
return Uni.createFrom().voidItem();
}
} }

View File

@ -6,9 +6,8 @@ import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.BoxAnswer; import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message; import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Accessibility; import dev.struchkov.godfather.quarkus.context.service.Accessibility;
import dev.struchkov.godfather.quarkus.context.service.Sending;
import dev.struchkov.godfather.quarkus.core.unit.func.Insert;
import dev.struchkov.godfather.quarkus.core.unit.func.ProcessingData; import dev.struchkov.godfather.quarkus.core.unit.func.ProcessingData;
import dev.struchkov.godfather.quarkus.core.unit.func.collback.CallBackConsumer;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import java.util.HashSet; import java.util.HashSet;
@ -34,15 +33,10 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
*/ */
private final ProcessingData<M> answer; private final ProcessingData<M> answer;
/**
* Информация, которую необходимо вставить вместо маркеров в строку ответа.
*/
private final Insert insert;
/** /**
* Объект нестандартной отправки ответа. * Объект нестандартной отправки ответа.
*/ */
private final Sending sender; private final CallBackConsumer callBack;
private AnswerText(Builder<M> builder) { private AnswerText(Builder<M> builder) {
super( super(
@ -61,8 +55,7 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
TypeUnit.TEXT TypeUnit.TEXT
); );
answer = builder.boxAnswer; answer = builder.boxAnswer;
insert = builder.insert; callBack = builder.callBack;
sender = builder.sending;
} }
public static <M extends Message> AnswerText<M> of(String message) { public static <M extends Message> AnswerText<M> of(String message) {
@ -81,15 +74,12 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
return answer; return answer;
} }
public Insert getInsert() { public CallBackConsumer getCallBack() {
return insert; return callBack;
}
public Sending getSending() {
return sender;
} }
public static final class Builder<M extends Message> { public static final class Builder<M extends Message> {
private String name = UUID.randomUUID().toString(); private String name = UUID.randomUUID().toString();
private String description; private String description;
private Set<MainUnit<M>> nextUnits; private Set<MainUnit<M>> nextUnits;
@ -107,8 +97,7 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
private boolean notSaveHistory; private boolean notSaveHistory;
private ProcessingData<M> boxAnswer; private ProcessingData<M> boxAnswer;
private Insert insert; private CallBackConsumer callBack;
private Sending sending;
private Builder() { private Builder() {
} }
@ -123,10 +112,10 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
return this; return this;
} }
public Builder<M> processing(Consumer<M> answer) { public Builder<M> answer(Consumer<M> answer) {
this.boxAnswer = message -> { this.boxAnswer = message -> {
answer.accept(message); answer.accept(message);
return null; return Uni.createFrom().nullItem();
}; };
return this; return this;
} }
@ -146,13 +135,8 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
return this; return this;
} }
public Builder<M> insert(Insert insert) { public Builder<M> callBack(CallBackConsumer callBack) {
this.insert = insert; this.callBack = callBack;
return this;
}
public Builder<M> sending(Sending sending) {
this.sending = sending;
return this; return this;
} }

View File

@ -1,12 +0,0 @@
package dev.struchkov.godfather.quarkus.core.unit.func;
import io.smallrye.mutiny.Uni;
import java.util.List;
@FunctionalInterface
public interface Insert {
Uni<List<String>> insert(String personId);
}

View File

@ -0,0 +1,11 @@
package dev.struchkov.godfather.quarkus.core.unit.func.collback;
import dev.struchkov.godfather.main.domain.SentBox;
import io.smallrye.mutiny.Uni;
@FunctionalInterface
public interface CallBackConsumer<MESSAGE_ID> {
Uni<Void> processing(SentBox<MESSAGE_ID> sentBox);
}

View File

@ -0,0 +1,11 @@
package dev.struchkov.godfather.quarkus.core.unit.func.collback;
import dev.struchkov.godfather.main.domain.SentBox;
import io.smallrye.mutiny.Uni;
@FunctionalInterface
public interface IntegerCallBack extends CallBackConsumer<Integer> {
Uni<Void> processing(SentBox<Integer> sentBox);
}

View File

@ -0,0 +1,11 @@
package dev.struchkov.godfather.quarkus.core.unit.func.collback;
import dev.struchkov.godfather.main.domain.SentBox;
import io.smallrye.mutiny.Uni;
@FunctionalInterface
public interface StringCallBack extends CallBackConsumer<String> {
Uni<Void> processing(SentBox<String> sentBox);
}

View File

@ -25,18 +25,24 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
public class GeneralAutoResponder<M extends Message> { public class GeneralAutoResponder<M extends Message> {
private final PersonSettingService personSettingService; protected final PersonSettingService personSettingService;
private final StorylineService<M> storyLineService; protected final StorylineService<M> storyLineService;
protected Map<String, ActionUnit> actionUnitMap = new HashMap<>(); protected Map<String, ActionUnit> actionUnitMap = new HashMap<>();
protected List<Modifiable<M>> modifiable; protected List<Modifiable<M>> modifiable;
private ErrorHandler errorHandler; protected ErrorHandler errorHandler;
protected ExecutorService executorService;
protected GeneralAutoResponder( protected GeneralAutoResponder(
Sending sending, Sending<?> sending,
PersonSettingService personSettingService, PersonSettingService personSettingService,
StorylineService<M> storyLineService StorylineService<M> storyLineService
) { ) {
@ -45,7 +51,7 @@ public class GeneralAutoResponder<M extends Message> {
init(sending); init(sending);
} }
private void init(Sending sending) { private void init(Sending<?> sending) {
actionUnitMap.put(TypeUnit.CHECK, new AnswerCheckAction<>(sending)); actionUnitMap.put(TypeUnit.CHECK, new AnswerCheckAction<>(sending));
actionUnitMap.put(TypeUnit.TEXT, new AnswerTextAction(sending)); actionUnitMap.put(TypeUnit.TEXT, new AnswerTextAction(sending));
actionUnitMap.put(TypeUnit.REPLACE_CMD, new ReplaceCmdAction()); actionUnitMap.put(TypeUnit.REPLACE_CMD, new ReplaceCmdAction());
@ -74,21 +80,36 @@ public class GeneralAutoResponder<M extends Message> {
this.errorHandler = errorHandler; this.errorHandler = errorHandler;
} }
public void setExecutorService(ExecutorService executorService) {
this.executorService = executorService;
}
public void setDefaultUnit(String unitName) { public void setDefaultUnit(String unitName) {
storyLineService.setDefaultUnit(unitName); storyLineService.setDefaultUnit(unitName);
} }
public void processingNewMessage(M newMessage) { public void processingNewMessage(M newMessage) {
if (newMessage != null) { if (checkNotNull(newMessage)) {
final boolean state = personSettingService.getStateProcessingByPersonId(newMessage.getPersonId()).orElse(true); if (checkNotNull(executorService)) {
executorService.submit(() -> {
final boolean state = personSettingService.getStateProcessingByPersonId(newMessage.getPersonId())
.orElse(true);
if (state) {
processing(newMessage);
}
});
} else {
final boolean state = personSettingService.getStateProcessingByPersonId(newMessage.getPersonId())
.orElse(true);
if (state) { if (state) {
processing(newMessage); processing(newMessage);
} }
} }
} }
}
public void processingNewMessages(List<M> newMessages) { public void processingNewMessages(List<M> newMessages) {
if (newMessages != null && !newMessages.isEmpty()) { if (checkNotEmpty(newMessages)) {
final Set<String> personIds = newMessages.stream() final Set<String> personIds = newMessages.stream()
.map(Message::getPersonId) .map(Message::getPersonId)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
@ -96,12 +117,20 @@ public class GeneralAutoResponder<M extends Message> {
final List<M> allowedMessages = newMessages.stream() final List<M> allowedMessages = newMessages.stream()
.filter(message -> !disableIds.contains(message.getPersonId())) .filter(message -> !disableIds.contains(message.getPersonId()))
.toList(); .toList();
allowedMessages.parallelStream().forEach(this::processing); if (checkNotNull(executorService)) {
for (M allowedMessage : allowedMessages) {
executorService.submit(() -> processing(allowedMessage));
}
} else {
for (M allowedMessage : allowedMessages) {
processing(allowedMessage);
}
}
} }
} }
private void processing(M message) { private void processing(M message) {
if (modifiable != null) { if (checkNotEmpty(modifiable)) {
modifiable.forEach(m -> m.change(message)); modifiable.forEach(m -> m.change(message));
} }
final Set<MainUnit<M>> units = storyLineService.getNextUnitByPersonId(message.getPersonId()); final Set<MainUnit<M>> units = storyLineService.getNextUnitByPersonId(message.getPersonId());
@ -124,7 +153,7 @@ public class GeneralAutoResponder<M extends Message> {
unitRequest = getAction(unitRequest); unitRequest = getAction(unitRequest);
activeUnitAfter(unitRequest); activeUnitAfter(unitRequest);
} catch (Exception e) { } catch (Exception e) {
if (errorHandler != null) { if (checkNotNull(errorHandler)) {
errorHandler.handle(unitRequest.getMessage(), e); errorHandler.handle(unitRequest.getMessage(), e);
} else { } else {
throw e; throw e;
@ -134,7 +163,7 @@ public class GeneralAutoResponder<M extends Message> {
private UnitRequest<MainUnit<M>, M> activeUnitAfter(UnitRequest<MainUnit<M>, M> unitRequest) { private UnitRequest<MainUnit<M>, M> activeUnitAfter(UnitRequest<MainUnit<M>, M> unitRequest) {
final Set<MainUnit<M>> nextUnits = unitRequest.getUnit().getNextUnits(); final Set<MainUnit<M>> nextUnits = unitRequest.getUnit().getNextUnits();
if (nextUnits != null) { if (checkNotNull(nextUnits)) {
Optional<MainUnit<M>> first = nextUnits.stream() Optional<MainUnit<M>> first = nextUnits.stream()
.filter(unit -> UnitActiveType.AFTER.equals(unit.getActiveType())) .filter(unit -> UnitActiveType.AFTER.equals(unit.getActiveType()))
.findFirst(); .findFirst();

View File

@ -22,9 +22,9 @@ public class AnswerCheckAction<M extends Message> implements ActionUnit<AnswerCh
private static final Logger log = LoggerFactory.getLogger(AnswerCheckAction.class); private static final Logger log = LoggerFactory.getLogger(AnswerCheckAction.class);
private final Sending sending; private final Sending<?> sending;
public AnswerCheckAction(Sending sending) { public AnswerCheckAction(Sending<?> sending) {
this.sending = sending; this.sending = sending;
} }

View File

@ -1,16 +1,19 @@
package dev.struchkov.godfather.simple.core.action; package dev.struchkov.godfather.simple.core.action;
import dev.struchkov.godfather.main.core.utils.InsertWords;
import dev.struchkov.godfather.main.domain.BoxAnswer; import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.SentBox;
import dev.struchkov.godfather.main.domain.content.Message; import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.context.service.Sending; import dev.struchkov.godfather.simple.context.service.Sending;
import dev.struchkov.godfather.simple.core.unit.AnswerText; import dev.struchkov.godfather.simple.core.unit.AnswerText;
import dev.struchkov.godfather.simple.core.unit.MainUnit; import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest; import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import dev.struchkov.godfather.simple.core.unit.func.ProcessingData;
import dev.struchkov.godfather.simple.core.unit.func.collback.CallBackConsumer;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/** /**
* Обработчик Unit-а {@link AnswerText}. * Обработчик Unit-а {@link AnswerText}.
* *
@ -18,40 +21,34 @@ import java.util.Optional;
*/ */
public class AnswerTextAction implements ActionUnit<AnswerText<Message>, Message> { public class AnswerTextAction implements ActionUnit<AnswerText<Message>, Message> {
private final Sending sending; private final Sending<?> sending;
public AnswerTextAction(Sending sending) { public AnswerTextAction(Sending<?> sending) {
this.sending = sending; this.sending = sending;
} }
@Override @Override
public UnitRequest<MainUnit, Message> action(UnitRequest<AnswerText<Message>, Message> unitRequest) { public UnitRequest<MainUnit, Message> action(UnitRequest<AnswerText<Message>, Message> unitRequest) {
final AnswerText<Message> unit = unitRequest.getUnit();
final Message message = unitRequest.getMessage(); final Message message = unitRequest.getMessage();
final AnswerText<Message> unit = unitRequest.getUnit();
final Optional<BoxAnswer> optAnswer = unit.getAnswer().processing(message); final ProcessingData<Message> answerProcessing = unit.getAnswer();
if (checkNotNull(answerProcessing)) {
final Optional<BoxAnswer> optAnswer = answerProcessing.processing(message);
if (optAnswer.isPresent()) { if (optAnswer.isPresent()) {
final BoxAnswer answer = optAnswer.get(); final BoxAnswer answer = optAnswer.get();
replaceMarkers(unit, message, answer);
final Sending answerTextSending = unit.getSending();
answer.setRecipientIfNull(message.getPersonId()); answer.setRecipientIfNull(message.getPersonId());
if (answerTextSending != null) { final Optional<? extends SentBox<?>> optSentBox = sending.send(answer);
answerTextSending.send(answer); final CallBackConsumer callBack = unit.getCallBack();
} else { if (checkNotNull(callBack) && optAnswer.isPresent()) {
sending.send(answer); final SentBox<?> sentBox = optSentBox.get();
callBack.processing(sentBox);
}
} }
} }
return UnitRequest.of(unit, message); return UnitRequest.of(unit, message);
} }
private void replaceMarkers(AnswerText<Message> answerText, Message message, BoxAnswer boxAnswer) {
if (answerText.getInsert() != null) {
final List<String> words = answerText.getInsert().insert(message.getPersonId());
final String newMessage = InsertWords.insert(boxAnswer.getMessage(), words);
boxAnswer.setMessage(newMessage);
}
}
} }

View File

@ -12,9 +12,9 @@ public class UserSanderPusher implements Pusher<String> {
private final String personId; private final String personId;
private final String nameForm; private final String nameForm;
private final Sending sending; private final Sending<?> sending;
public UserSanderPusher(String personId, String nameForm, Sending sending) { public UserSanderPusher(String personId, String nameForm, Sending<?> sending) {
this.personId = personId; this.personId = personId;
this.nameForm = nameForm; this.nameForm = nameForm;
this.sending = sending; this.sending = sending;

View File

@ -9,17 +9,20 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException; import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Inspector.isNotNull; import static dev.struchkov.haiti.utils.Inspector.isNotNull;
public class StorylineContextMapImpl implements StorylineContext { public class StorylineContextMapImpl implements StorylineContext {
private final Map<String, Map<String, Object>> map = new HashMap<>(); private final Map<String, Map<String, Object>> map = new HashMap<>();
@Override
public void save(@NotNull String personId, @NotNull ContextKey<?> key, Object objectForSave) { public void save(@NotNull String personId, @NotNull ContextKey<?> key, Object objectForSave) {
isNotNull(personId, key); isNotNull(personId, key);
map.computeIfAbsent(personId, k -> new HashMap<>()).put(key.getValue(), objectForSave); map.computeIfAbsent(personId, k -> new HashMap<>()).put(key.getValue(), objectForSave);
} }
@Override
public <T> Optional<T> getByKey(@NotNull String personId, @NotNull ContextKey<T> key) { public <T> Optional<T> getByKey(@NotNull String personId, @NotNull ContextKey<T> key) {
isNotNull(personId, key); isNotNull(personId, key);
if (map.containsKey(personId)) { if (map.containsKey(personId)) {
@ -32,24 +35,35 @@ public class StorylineContextMapImpl implements StorylineContext {
return Optional.empty(); return Optional.empty();
} }
@Override
public <T> Optional<T> removeKey(@NotNull String personId, @NotNull ContextKey<T> key) {
isNotNull(personId, key);
if (map.containsKey(personId)) {
final Map<String, Object> storage = map.get(personId);
final T object = (T) storage.get(key.getValue());
if (checkNotNull(object) && object.getClass().equals(key.getType())) {
storage.remove(key.getValue());
return Optional.of(object);
}
}
return Optional.empty();
}
@Override @Override
public <T> T getByKeyOrThrow(@NotNull String personId, @NotNull ContextKey<T> key) { public <T> T getByKeyOrThrow(@NotNull String personId, @NotNull ContextKey<T> key) {
return getByKey(personId, key).orElseThrow(notFoundException("Не найдено значение ключа {0}, для пользователя {1}", key.getValue(), personId)); return getByKey(personId, key).orElseThrow(notFoundException("Не найдено значение ключа {0}, для пользователя {1}", key.getValue(), personId));
} }
@Override
public Map<String, Object> getAllSaveElement(@NotNull String personId) { public Map<String, Object> getAllSaveElement(@NotNull String personId) {
isNotNull(personId); isNotNull(personId);
return map.get(personId); return map.get(personId);
} }
@Override
public void removeAll(@NotNull String personId) { public void removeAll(@NotNull String personId) {
isNotNull(personId); isNotNull(personId);
map.remove(personId); map.remove(personId);
} }
public void removeByKey(@NotNull String personId, @NotNull ContextKey<?> key) {
isNotNull(personId, key);
map.computeIfAbsent(personId, k -> new HashMap<>()).remove(key.getValue());
}
} }

View File

@ -6,9 +6,8 @@ import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.BoxAnswer; import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message; import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.context.service.Accessibility; import dev.struchkov.godfather.simple.context.service.Accessibility;
import dev.struchkov.godfather.simple.context.service.Sending;
import dev.struchkov.godfather.simple.core.unit.func.Insert;
import dev.struchkov.godfather.simple.core.unit.func.ProcessingData; import dev.struchkov.godfather.simple.core.unit.func.ProcessingData;
import dev.struchkov.godfather.simple.core.unit.func.collback.CallBackConsumer;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -34,15 +33,7 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
*/ */
private final ProcessingData<M> answer; private final ProcessingData<M> answer;
/** private final CallBackConsumer callBack;
* Информация, которую необходимо вставить вместо маркеров в строку ответа.
*/
private final Insert insert;
/**
* Объект нестандартной отправки ответа.
*/
private final Sending sender;
private AnswerText(Builder<M> builder) { private AnswerText(Builder<M> builder) {
super( super(
@ -61,8 +52,7 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
TypeUnit.TEXT TypeUnit.TEXT
); );
answer = builder.boxAnswer; answer = builder.boxAnswer;
insert = builder.insert; callBack = builder.callBack;
sender = builder.sending;
} }
public static <M extends Message> AnswerText<M> of(String message) { public static <M extends Message> AnswerText<M> of(String message) {
@ -81,15 +71,12 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
return answer; return answer;
} }
public Insert getInsert() { public CallBackConsumer getCallBack() {
return insert; return callBack;
}
public Sending getSending() {
return sender;
} }
public static final class Builder<M extends Message> { public static final class Builder<M extends Message> {
private String name = UUID.randomUUID().toString(); private String name = UUID.randomUUID().toString();
private String description; private String description;
private Set<MainUnit<M>> nextUnits; private Set<MainUnit<M>> nextUnits;
@ -107,8 +94,7 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
private boolean notSaveHistory; private boolean notSaveHistory;
private ProcessingData<M> boxAnswer; private ProcessingData<M> boxAnswer;
private Insert insert; private CallBackConsumer callBack;
private Sending sending;
private Builder() { private Builder() {
} }
@ -123,10 +109,10 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
return this; return this;
} }
public Builder<M> processing(Consumer<M> answer) { public Builder<M> answer(Consumer<M> answer) {
this.boxAnswer = message -> { this.boxAnswer = message -> {
answer.accept(message); answer.accept(message);
return null; return Optional.empty();
}; };
return this; return this;
} }
@ -146,13 +132,8 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
return this; return this;
} }
public Builder<M> insert(Insert insert) { public Builder<M> callBack(CallBackConsumer callBack) {
this.insert = insert; this.callBack = callBack;
return this;
}
public Builder<M> sending(Sending sending) {
this.sending = sending;
return this; return this;
} }

View File

@ -1,10 +0,0 @@
package dev.struchkov.godfather.simple.core.unit.func;
import java.util.List;
@FunctionalInterface
public interface Insert {
List<String> insert(String personId);
}

View File

@ -0,0 +1,10 @@
package dev.struchkov.godfather.simple.core.unit.func.collback;
import dev.struchkov.godfather.main.domain.SentBox;
@FunctionalInterface
public interface CallBackConsumer<MESSAGE_ID> {
void processing(SentBox<MESSAGE_ID> sentBox);
}

View File

@ -0,0 +1,10 @@
package dev.struchkov.godfather.simple.core.unit.func.collback;
import dev.struchkov.godfather.main.domain.SentBox;
@FunctionalInterface
public interface IntegerCallBack extends CallBackConsumer<Integer> {
void processing(SentBox<Integer> sentBox);
}

View File

@ -0,0 +1,10 @@
package dev.struchkov.godfather.simple.core.unit.func.collback;
import dev.struchkov.godfather.main.domain.SentBox;
@FunctionalInterface
public interface StringCallBack extends CallBackConsumer<String> {
void processing(SentBox<String> sentBox);
}

View File

@ -12,12 +12,12 @@ public interface StorylineContext {
<T> Uni<T> getByKey(@NotNull String personId, @NotNull ContextKey<T> key); <T> Uni<T> getByKey(@NotNull String personId, @NotNull ContextKey<T> key);
<T> Uni<T> removeKey(@NotNull String personId, @NotNull ContextKey<?> key);
<T> Uni<T> getByKeyOrThrow(@NotNull String personId, @NotNull ContextKey<T> key); <T> Uni<T> getByKeyOrThrow(@NotNull String personId, @NotNull ContextKey<T> key);
Uni<Map<String, Object>> getAllSaveElement(@NotNull String personId); Uni<Map<String, Object>> getAllSaveElement(@NotNull String personId);
Uni<Void> removeAll(@NotNull String personId); Uni<Void> removeAll(@NotNull String personId);
Uni<Void> removeByKey(@NotNull String personId, @NotNull ContextKey<?> key);
} }

View File

@ -12,12 +12,12 @@ public interface StorylineContext {
<T> Optional<T> getByKey(@NotNull String personId, @NotNull ContextKey<T> key); <T> Optional<T> getByKey(@NotNull String personId, @NotNull ContextKey<T> key);
<T> Optional<T> removeKey(@NotNull String personId, @NotNull ContextKey<T> key);
<T> T getByKeyOrThrow(@NotNull String personId, @NotNull ContextKey<T> key); <T> T getByKeyOrThrow(@NotNull String personId, @NotNull ContextKey<T> key);
Map<String, Object> getAllSaveElement(@NotNull String personId); Map<String, Object> getAllSaveElement(@NotNull String personId);
void removeAll(@NotNull String personId); void removeAll(@NotNull String personId);
void removeByKey(@NotNull String personId, @NotNull ContextKey<?> key);
} }

View File

@ -0,0 +1,33 @@
package dev.struchkov.godfather.main.domain;
import java.util.Optional;
public class SentBox<T> {
private T messageId;
private BoxAnswer sentAnswer;
private BoxAnswer originalAnswer;
public SentBox(T messageId, BoxAnswer sentAnswer, BoxAnswer originalAnswer) {
this.messageId = messageId;
this.sentAnswer = sentAnswer;
this.originalAnswer = originalAnswer;
}
public static <T> Optional<SentBox<T>> optional(T messageId, BoxAnswer sentAnswer, BoxAnswer originalAnswer) {
return Optional.of(new SentBox<>(messageId, sentAnswer, originalAnswer));
}
public T getMessageId() {
return messageId;
}
public BoxAnswer getSentAnswer() {
return sentAnswer;
}
public BoxAnswer getOriginalAnswer() {
return originalAnswer;
}
}