Добавил версию для реактивного Quarkus

This commit is contained in:
Struchkov Mark 2022-08-07 07:07:10 +03:00
parent d2cf3ed645
commit dd6b166506
163 changed files with 3524 additions and 1122 deletions

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>godfather-bot</artifactId>
<groupId>dev.struchkov.godfather</groupId>
<version>0.0.25</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bot-context-main</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-domain-main</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.haiti</groupId>
<artifactId>haiti-utils</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,8 +1,8 @@
package dev.struchkov.godfather.context.utils;
package dev.struchkov.godfather.main.context.utils;
import dev.struchkov.godfather.context.domain.keyboard.button.SimpleButton;
import dev.struchkov.godfather.context.domain.keyboard.simple.SimpleKeyBoard;
import dev.struchkov.godfather.context.domain.keyboard.simple.SimpleKeyBoardLine;
import dev.struchkov.godfather.main.domain.keyboard.button.SimpleButton;
import dev.struchkov.godfather.main.domain.keyboard.simple.SimpleKeyBoard;
import dev.struchkov.godfather.main.domain.keyboard.simple.SimpleKeyBoardLine;
import java.util.Arrays;
import java.util.List;

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-context</artifactId>
<version>0.0.25</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bot-context-quarkus</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-domain-main</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>smallrye-mutiny-vertx-core</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,10 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.content.Message;
import io.smallrye.mutiny.Uni;
public interface Accessibility {
Uni<Void> check(Message message);
}

View File

@ -0,0 +1,18 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.content.Message;
/**
* Используется для перехвата исключений, которые возникают при обработке юнитов.
*/
public interface ErrorHandler {
/**
* Метод, который должен как-то обработать исключение.
*
* @param message Сообщение, после которого возникло исключение.
* @param e Объект исключения.
*/
void handle(Message message, Throwable e);
}

View File

@ -0,0 +1,12 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.event.Event;
import io.smallrye.mutiny.Uni;
public interface EventHandler<T extends Event> {
Uni<Void> handle(T event);
String getEventType();
}

View File

@ -0,0 +1,18 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.content.Message;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
/**
* Интерфес для изменения запроса пользователя перед тем, как он попадет в подсистему обработки.
* Например можно исправить опечатки, перевести сообщение на другой язык и так далее.
*
* @author upagge [08/07/2019]
*/
@FunctionalInterface
public interface Modifiable<T extends Message> {
Uni<Void> change(@NotNull T content);
}

View File

@ -0,0 +1,18 @@
package dev.struchkov.godfather.quarkus.context.service;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
public interface PersonSettingService {
Uni<Set<Long>> getAllPersonIdDisableMessages(@NotNull Set<Long> personIds);
Uni<Boolean> getStateProcessingByPersonId(@NotNull Long personId);
Uni<Void> disableMessageProcessing(@NotNull Long personId);
Uni<Void> enableMessageProcessing(@NotNull Long personId);
}

View File

@ -0,0 +1,17 @@
package dev.struchkov.godfather.quarkus.context.service;
import io.smallrye.mutiny.Uni;
import java.util.Map;
/**
* TODO: Добавить описание класса.
*
* @author upagge [13/07/2019]
*/
@FunctionalInterface
public interface Pusher<D> {
Uni<Void> push(Long personId, Map<String, D> saveElement);
}

View File

@ -0,0 +1,29 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.SendType;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
/**
* Интерфейс для отправки ответов пользователю.
*
* @author upagge [08/07/2019]
*/
public interface Sending {
/**
* Отрпавляет ответ пользователю
*
* @param personId Идентификатор пользователя
* @param boxAnswer Объект с данными, которые необходимо отправить
*/
Uni<Void> send(@NotNull Long personId, @NotNull BoxAnswer boxAnswer);
/**
* Возвращает тип объекта отправляющего ответ пользователя. В зависимости от типа ответ будет отправлен с помощью
* разных методов.
*/
SendType getType();
}

View File

@ -0,0 +1,20 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.UnitPointer;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
/**
* Сервис для взаимодействия с сущностью {@link UnitPointer}.
*
* @author upagge [07/07/2019]
*/
public interface UnitPointerService {
Uni<UnitPointer> save(@NotNull UnitPointer unitPointer);
Uni<String> getUnitNameByPersonId(@NotNull Long personId);
Uni<Void> removeByPersonId(@NotNull Long personId);
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-context</artifactId>
<version>0.0.25</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bot-context-simple</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-domain-main</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,9 @@
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.main.domain.content.Message;
public interface Accessibility {
boolean check(Message message);
}

View File

@ -1,6 +1,6 @@
package dev.struchkov.godfather.core.service;
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.main.domain.content.Message;
/**
* Используется для перехвата исключений, которые возникают при обработке юнитов.

View File

@ -0,0 +1,11 @@
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.main.domain.event.Event;
public interface EventHandler<T extends Event> {
void handle(T event);
String getEventType();
}

View File

@ -1,6 +1,6 @@
package dev.struchkov.godfather.context.service;
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.main.domain.content.Message;
import org.jetbrains.annotations.NotNull;
/**

View File

@ -1,4 +1,4 @@
package dev.struchkov.godfather.context.service;
package dev.struchkov.godfather.simple.context.service;
import org.jetbrains.annotations.NotNull;

View File

@ -1,4 +1,4 @@
package dev.struchkov.godfather.context.service.save;
package dev.struchkov.godfather.simple.context.service;
import java.util.Map;

View File

@ -1,6 +1,7 @@
package dev.struchkov.godfather.context.service.sender;
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.context.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.SendType;
import org.jetbrains.annotations.NotNull;
/**

View File

@ -1,6 +1,6 @@
package dev.struchkov.godfather.context.service;
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.context.domain.UnitPointer;
import dev.struchkov.godfather.main.domain.UnitPointer;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;

View File

@ -10,6 +10,13 @@
</parent>
<artifactId>bot-context</artifactId>
<packaging>pom</packaging>
<modules>
<module>bot-context-main</module>
<module>bot-context-simple</module>
<module>bot-context-quarkus</module>
</modules>
<name>Bot Context</name>
<description>Доменные сущности, интерфейсы, для библиотеки Godfather</description>

View File

@ -1,27 +0,0 @@
package dev.struchkov.godfather.context.domain;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
/**
* Основная сущность для сокрытия id у других сущностей.
*
* @author upagge [28/07/2019]
*/
@MappedSuperclass
public class BasicEntity {
@Id
@GeneratedValue
protected Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}

View File

@ -1,21 +0,0 @@
package dev.struchkov.godfather.context.domain;
public class Clarification {
private BoxAnswer question;
private String value;
public Clarification(BoxAnswer question, String value) {
this.question = question;
this.value = value;
}
public BoxAnswer getQuestion() {
return question;
}
public String getValue() {
return value;
}
}

View File

@ -1,17 +0,0 @@
package dev.struchkov.godfather.context.domain.content.attachment;
import dev.struchkov.godfather.context.domain.BasicEntity;
import javax.persistence.Entity;
/**
* Абстрактная сущность, для всех вложений к сообщениям от пользователей.
*
* @author upagge [08/07/2019]
*/
@Entity
public abstract class Attachment extends BasicEntity {
public abstract String getType();
}

View File

@ -1,14 +0,0 @@
package dev.struchkov.godfather.context.exception;
/**
* Ошибка таймера.
*
* @author upagge [08/07/2019]
*/
public class TimerSettingException extends AppBotException {
public TimerSettingException(String message) {
super(message);
}
}

View File

@ -1,9 +0,0 @@
package dev.struchkov.godfather.context.service;
import dev.struchkov.godfather.context.domain.content.Message;
public interface Accessibility {
boolean check(Message message);
}

View File

@ -1,11 +0,0 @@
package dev.struchkov.godfather.context.service;
import dev.struchkov.godfather.context.domain.Clarification;
import dev.struchkov.godfather.context.domain.content.Message;
@FunctionalInterface
public interface ClarificationQuestion<C extends Message> {
Clarification getClarification(C message);
}

View File

@ -1,11 +0,0 @@
package dev.struchkov.godfather.context.service;
import dev.struchkov.godfather.context.domain.event.Event;
public interface EventHandler<T extends Event> {
void handle(T event);
String getEventType();
}

View File

@ -1,12 +0,0 @@
package dev.struchkov.godfather.context.service;
import dev.struchkov.godfather.context.domain.content.Mail;
/**
* Интерфейс для взаимодействия с личными сообщениями.
*
* @author upagge [08/07/2019]
*/
public interface MailService extends MessageService<Mail> {
}

View File

@ -1,49 +0,0 @@
package dev.struchkov.godfather.context.service;
import dev.struchkov.godfather.context.domain.content.Message;
import org.jetbrains.annotations.NotNull;
import java.time.LocalDateTime;
import java.util.List;
/**
* Интерфейс взаимодйствия с наследниками текстовых сообщений пользователей.
*
* @author upagge [08/07/2019]
*/
public interface MessageService<T extends Message> {
void add(@NotNull T event);
/**
* Получить список сообщений за заданный временной интервал
*
* @param dateFrom Начало интервала
* @param dateTo Конец интервала
* @return Список сообщений
*/
List<T> getByAddDateTime(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo);
/**
* Получить список ПОСЛЕДНИХ сообщений для каждого пользователя за заданных временной интервал
*
* @param dateFrom Начало интервала
* @param dateTo Конец интервала
* @return Список сообщений
*/
List<T> getLastEventByCreateDateTime(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo);
List<T> getLastEventByAddDateTime(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo);
/**
* Возвращает новые сообщения от последнего запроса.
*/
List<T> getNewMessage();
void deleteAllByAddDateBetween(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo);
void deleteAllByAddDateBefore(@NotNull LocalDateTime date);
void deleteAllByAddDateAfter(@NotNull LocalDateTime date);
}

View File

@ -1,10 +0,0 @@
package dev.struchkov.godfather.context.service;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.AnswerText;
public interface UnitContextFactory<M extends Message> {
AnswerText.Builder<M> createAnswerText();
}

View File

@ -1,10 +0,0 @@
package dev.struchkov.godfather.context.service.save;
import dev.struchkov.godfather.context.domain.content.Message;
@FunctionalInterface
public interface PreservableData<D, M extends Message> {
D getData(M content);
}

View File

@ -1,10 +0,0 @@
package dev.struchkov.godfather.context.service.usercode;
import dev.struchkov.godfather.context.domain.content.Message;
@FunctionalInterface
public interface CheckData<C extends Message> {
boolean checked(C content);
}

View File

@ -1,19 +0,0 @@
package dev.struchkov.godfather.context.utils;
import dev.struchkov.godfather.context.domain.content.EmptyMessage;
import dev.struchkov.godfather.context.domain.content.Message;
/**
* Класс для хранения объекта заглушки для {@link Message}.
*
* @author upagge [08/07/2019]
*/
public class MessageUtils {
public static final EmptyMessage EMPTY_MESSAGE = new EmptyMessage();
private MessageUtils() {
throw new IllegalStateException(Messages.UTILITY_CLASS);
}
}

View File

@ -1,16 +0,0 @@
package dev.struchkov.godfather.context.utils;
/**
* Класс утилита, содержащий сообщения об ошибках, и сообщения логирования.
*
* @author upagge [15/08/2019]
*/
public class Messages {
public static final String UTILITY_CLASS = "Класс утилита";
private Messages() {
throw new IllegalStateException(UTILITY_CLASS);
}
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-core</artifactId>
<version>0.0.25</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bot-core-main</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-domain-main</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,4 +1,4 @@
package dev.struchkov.godfather.context.domain;
package dev.struchkov.godfather.main.core.unit;
import static dev.struchkov.haiti.utils.Exceptions.utilityClass;
@ -13,10 +13,8 @@ public class TypeUnit {
public static final String SAVE = "SAVE";
public static final String TIMER = "TIMER";
public static final String CHECK = "CHECK";
public static final String VALIDITY = "VALIDITY";
public static final String BACK_CMD = "BACK_CMD";
public static final String TELEPORT_CMD = "TELEPORT_CMD";
public static final String REPLACE_CMD = "REPLACE_CMD";
private TypeUnit() {

View File

@ -1,4 +1,4 @@
package dev.struchkov.godfather.context.domain.unit;
package dev.struchkov.godfather.main.core.unit;
/**
* Тип активации Unit-а. Определяет порядок обработки Unit.

View File

@ -1,4 +1,4 @@
package dev.struchkov.godfather.context.utils;
package dev.struchkov.godfather.main.core.utils;
import org.jetbrains.annotations.NotNull;

View File

@ -0,0 +1,21 @@
package dev.struchkov.godfather.main.core.utils;
import dev.struchkov.godfather.main.domain.content.EmptyMessage;
import dev.struchkov.godfather.main.domain.content.Message;
import static dev.struchkov.haiti.utils.Exceptions.utilityClass;
/**
* Класс для хранения объекта заглушки для {@link Message}.
*
* @author upagge [08/07/2019]
*/
public final class MessageUtils {
public static final EmptyMessage EMPTY_MESSAGE = new EmptyMessage();
private MessageUtils() {
utilityClass();
}
}

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-core</artifactId>
<version>0.0.25</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bot-core-quarkus</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-core-main</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-context-quarkus</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-data-quarkus</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>smallrye-mutiny-vertx-core</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,221 @@
package dev.struchkov.godfather.quarkus.core;
import dev.struchkov.autoresponder.Responder;
import dev.struchkov.godfather.exception.ConfigAppException;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.ErrorHandler;
import dev.struchkov.godfather.quarkus.context.service.Modifiable;
import dev.struchkov.godfather.quarkus.context.service.PersonSettingService;
import dev.struchkov.godfather.quarkus.context.service.Sending;
import dev.struchkov.godfather.quarkus.core.action.ActionUnit;
import dev.struchkov.godfather.quarkus.core.action.AnswerCheckAction;
import dev.struchkov.godfather.quarkus.core.action.AnswerSaveAction;
import dev.struchkov.godfather.quarkus.core.action.AnswerTextAction;
import dev.struchkov.godfather.quarkus.core.action.cmd.ReplaceCmdAction;
import dev.struchkov.godfather.quarkus.core.service.StorylineService;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import dev.struchkov.haiti.context.exception.NotFoundException;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Checker.checkNull;
public class GeneralAutoResponder<M extends Message> {
private final PersonSettingService personSettingService;
private final StorylineService<M> storyLineService;
protected Map<String, ActionUnit> actionUnitMap = new HashMap<>();
protected List<Modifiable<M>> modifiable;
private ErrorHandler errorHandler;
protected GeneralAutoResponder(
Sending sending,
PersonSettingService personSettingService,
StorylineService<M> storyLineService
) {
this.personSettingService = personSettingService;
this.storyLineService = storyLineService;
init(sending);
}
private void init(Sending sending) {
actionUnitMap.put(TypeUnit.CHECK, new AnswerCheckAction<>());
actionUnitMap.put(TypeUnit.TEXT, new AnswerTextAction(sending));
actionUnitMap.put(TypeUnit.REPLACE_CMD, new ReplaceCmdAction());
}
public void initModifiable(List<Modifiable<M>> modifiable) {
this.modifiable = modifiable;
}
public void initActionUnit(String typeUnit, ActionUnit<? extends MainUnit<M>, M> actionUnit) {
if (!actionUnitMap.containsKey(typeUnit)) {
actionUnitMap.put(typeUnit, actionUnit);
} else {
throw new ConfigAppException("Обработка такого типа юнита уже зарегистрирована");
}
}
public void initSaveAction(AnswerSaveAction<M, ?> answerSaveAction) {
actionUnitMap.put(TypeUnit.SAVE, answerSaveAction);
}
/**
* Позволяет установить перехватчик и обработчик исключений, возникающих при обработке юнитов.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
public void setDefaultUnit(String unitName) {
storyLineService.setDefaultUnit(unitName);
}
public Uni<Void> processingNewMessage(M newMessage) {
if (newMessage != null) {
return personSettingService.getStateProcessingByPersonId(newMessage.getPersonId())
.onItem().transformToUni(
state -> {
if (checkNull(state) || state) {
return processing(newMessage);
}
return Uni.createFrom().voidItem();
}
);
}
return Uni.createFrom().voidItem();
}
public Uni<Void> processingNewMessages(List<M> newMessages) {
if (newMessages != null && !newMessages.isEmpty()) {
final Set<Long> personIds = newMessages.stream()
.map(Message::getPersonId)
.collect(Collectors.toSet());
return personSettingService.getAllPersonIdDisableMessages(personIds)
.onItem().transformToMulti(
disableIds -> {
final List<M> allowedMessages = newMessages.stream()
.filter(message -> !disableIds.contains(message.getPersonId()))
.toList();
return Multi.createFrom().iterable(allowedMessages);
}
)
.onItem().transform(this::processing)
.toUni().replaceWithVoid();
}
return Uni.createFrom().voidItem();
}
private Uni<Void> processing(M message) {
return Uni.createFrom().item(message)
.onItem().transformToUni(
mail -> {
if (checkNotEmpty(modifiable)) {
return Multi.createFrom().iterable(modifiable)
.onItem().transformToUni(m -> m.change(mail))
.concatenate().toUni().replaceWith(mail);
}
return Uni.createFrom().item(mail);
}
).onItem().transformToUni(
mail -> {
final Uni<Set<MainUnit<M>>> uniUnits = storyLineService.getNextUnitByPersonId(mail.getPersonId());
return Uni.combine().all().unis(uniUnits, Uni.createFrom().item(mail)).asTuple();
}
).onItem().transformToUni(
t -> {
final Set<MainUnit<M>> units = t.getItem1();
final M mail = t.getItem2();
final Optional<MainUnit<M>> optAnswer = Responder.nextUnit(mail, units).or(storyLineService::getDefaultUnit);
if (optAnswer.isPresent()) {
final MainUnit<M> answer = optAnswer.get();
//TODO [05.08.2022]: нужно ли проверку встраивать в поток?
// if (checkPermission(answer.getAccessibility(), message)) {
return answer(UnitRequest.of(answer, message));
// }
}
return Uni.createFrom().voidItem();
}
);
}
// private boolean checkPermission(Optional<Accessibility> accessibility, M message) {
// return accessibility.isEmpty() || accessibility.get().check(message);
// }
public Uni<Void> answer(UnitRequest<MainUnit, M> unitRequest) {
return getAction(unitRequest)
.onItem().transformToUni(
request -> activeUnitAfter(unitRequest)
)
.onFailure().invoke(
throwable -> {
if (errorHandler != null) {
errorHandler.handle(unitRequest.getMessage(), throwable);
}
}
)
.replaceWithVoid();
}
private Uni<UnitRequest<MainUnit, M>> activeUnitAfter(UnitRequest<MainUnit, M> unitRequest) {
final Set<MainUnit<M>> nextUnits = unitRequest.getUnit().getNextUnits();
if (checkNotNull(nextUnits)) {
Optional<MainUnit<M>> first = nextUnits.stream()
.filter(unit -> UnitActiveType.AFTER.equals(unit.getActiveType()))
.findFirst();
if (first.isPresent()) {
return Uni.createFrom().voidItem().onItem().transformToUni(
v-> getAction(UnitRequest.of(first.get(), unitRequest.getMessage()))
)
.onItem().transformToUni(
uR -> activeUnitAfter(UnitRequest.of(first.get(), unitRequest.getMessage()))
);
}
}
return Uni.createFrom().item(unitRequest);
}
private Uni<UnitRequest<MainUnit, M>> getAction(UnitRequest<MainUnit, M> unitRequest) {
final MainUnit<M> unit = unitRequest.getUnit();
final M message = unitRequest.getMessage();
final String typeUnit = unit.getType();
if (actionUnitMap.containsKey(typeUnit)) {
ActionUnit<MainUnit, M> actionUnit = actionUnitMap.get(typeUnit);
return actionUnit.action(unitRequest)
.onItem().transformToUni(
newUnitRequest -> {
final Optional<MainUnit<M>> optDefaultUnit = storyLineService.getDefaultUnit();
if (!unit.isNotSaveHistory() && (optDefaultUnit.isEmpty() || !optDefaultUnit.get().equals(unit))) {
return Uni.combine().all().unis(
Uni.createFrom().item(newUnitRequest),
storyLineService.save(message.getPersonId(), unit.getName(), message)
).asTuple();
}
return Uni.combine().all().unis(Uni.createFrom().item(newUnitRequest), Uni.createFrom().voidItem()).asTuple();
}
).onItem().transformToUni(
t -> {
final UnitRequest<MainUnit, M> newUnitRequest = t.getItem1();
final MainUnit<M> newUnit = newUnitRequest.getUnit();
return !unit.equals(newUnit) ? getAction(newUnitRequest) : Uni.createFrom().item(unitRequest);
}
);
} else {
throw new NotFoundException("ActionUnit для типа {0} не зарегистрирован", unit.getType());
}
}
}

View File

@ -0,0 +1,61 @@
package dev.struchkov.godfather.quarkus.core;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import static dev.struchkov.haiti.utils.Checker.checkNull;
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
public class Storyline<M extends Message> {
private final Set<MainUnit<M>> startingUnits = new HashSet<>();
private final Set<MainUnit<M>> globalUnits = new HashSet<>();
private final Map<String, MainUnit<M>> units = new HashMap<>();
public Storyline(Set<MainUnit<M>> startingUnits, Map<String, MainUnit<M>> units) {
this.startingUnits.addAll(startingUnits);
this.units.putAll(units);
}
public void addGlobalUnits(Set<MainUnit<M>> globalUnits) {
this.globalUnits.addAll(globalUnits);
}
public Set<MainUnit<M>> getGlobalUnits() {
return globalUnits;
}
/**
* Получить юнит по названию.
*
* @param unitName Название юнита.
*/
public Optional<MainUnit<M>> getUnit(String unitName) {
isNotNull(unitName);
return Optional.ofNullable(units.get(unitName));
}
public Set<MainUnit<M>> getStartingUnits() {
return startingUnits;
}
//TODO [22.06.2022]: Временное решение ленивой связки юнитов, пока не будет реализован нормальный механизм.
public void link(@NotNull String firstName, @NotNull String secondName) {
isNotNull(firstName, secondName);
final MainUnit<M> firstUnit = units.get(firstName);
final MainUnit<M> secondUnit = units.get(secondName);
isNotNull(firstUnit, secondUnit);
if (checkNull(firstUnit.getNextUnits())) {
firstUnit.setNextUnits(new HashSet<>());
}
firstUnit.getNextUnits().add(secondUnit);
}
}

View File

@ -1,10 +1,10 @@
package dev.struchkov.godfather.core;
package dev.struchkov.godfather.quarkus.core;
import dev.struchkov.godfather.context.domain.UnitDefinition;
import dev.struchkov.godfather.context.domain.annotation.Unit;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.context.exception.UnitConfigException;
import dev.struchkov.godfather.exception.UnitConfigException;
import dev.struchkov.godfather.main.domain.UnitDefinition;
import dev.struchkov.godfather.main.domain.annotation.Unit;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.haiti.utils.Inspector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -21,7 +21,7 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.godfather.context.exception.UnitConfigException.unitConfigException;
import static dev.struchkov.godfather.exception.UnitConfigException.unitConfigException;
public class StorylineFactory<M extends Message> {

View File

@ -0,0 +1,23 @@
package dev.struchkov.godfather.quarkus.core.action;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import io.smallrye.mutiny.Uni;
/**
* Интерфейс для обработки Unit-ов.
*
* @author upagge [11/07/2019]
*/
@FunctionalInterface
public interface ActionUnit<U extends MainUnit, M extends Message> {
/**
* Метод обработки Unit-а.
*
* @return Новый Unit, который может нуждаться в обработке
*/
Uni<UnitRequest<MainUnit, M>> action(UnitRequest<U, M> unitRequest);
}

View File

@ -0,0 +1,36 @@
package dev.struchkov.godfather.quarkus.core.action;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.AnswerCheck;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import io.smallrye.mutiny.Uni;
import java.util.Objects;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/**
* Обработчик Unit-а {@link AnswerCheck}.
*
* @author upagge [11/07/2019]
*/
public class AnswerCheckAction<M extends Message> implements ActionUnit<AnswerCheck<M>, M> {
@Override
public Uni<UnitRequest<MainUnit, M>> action(UnitRequest<AnswerCheck<M>, M> unitRequest) {
final AnswerCheck<M> unit = unitRequest.getUnit();
final M message = unitRequest.getMessage();
return unit.getCheck().checked(message)
.onItem().transform(
checkValue -> {
if (checkNotNull(checkValue) && checkValue) {
return UnitRequest.of(Objects.requireNonNullElse(unit.getUnitTrue(), unit), message);
} else {
return UnitRequest.of(Objects.requireNonNullElse(unit.getUnitFalse(), unit), message);
}
}
);
}
}

View File

@ -0,0 +1,75 @@
package dev.struchkov.godfather.quarkus.core.action;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Pusher;
import dev.struchkov.godfather.quarkus.core.unit.AnswerSave;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import dev.struchkov.godfather.quarkus.core.unit.func.CheckSave;
import dev.struchkov.godfather.quarkus.core.unit.func.PreservableData;
import dev.struchkov.godfather.quarkus.data.preser.AnswerSavePreservable;
import io.smallrye.mutiny.Uni;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/**
* Обработчик Unit-а {@link AnswerSave}.
*
* @author upagge [11/07/2019]
*/
public class AnswerSaveAction<M extends Message, D> implements ActionUnit<AnswerSave<M, D>, M> {
@Override
public Uni<UnitRequest<MainUnit, M>> action(UnitRequest<AnswerSave<M, D>, M> unitRequest) {
final AnswerSave<M, D> answerSave = unitRequest.getUnit();
final M message = unitRequest.getMessage();
final AnswerSavePreservable<D> preservable = answerSave.getPreservable();
final Long personId = message.getPersonId();
final CheckSave<M> checkSave = answerSave.getCheckSave();
if (checkNotNull(checkSave)) {
return Uni.createFrom().voidItem()
.onItem().transformToUni(
v -> checkSave.check(message)
.onItem().transform(
unit -> {
if (checkNotNull(unit)) {
return UnitRequest.of(unit, message);
}
return UnitRequest.of(answerSave, message);
}
)
);
}
final PreservableData<D, M> preservableData = answerSave.getPreservableData();
final Pusher<D> pusher = answerSave.getPusher();
return Uni.createFrom().voidItem()
.onItem().transformToUni(
v -> {
if (checkNotNull(preservableData)) {
return preservableData.getData(message);
}
return Uni.createFrom().nullItem();
}
).onItem().transformToUni(
dataFromSave -> {
if (checkNotNull(dataFromSave)) {
return preservable.save(personId, answerSave.getKey(), dataFromSave);
}
return Uni.createFrom().nullItem();
}
).onItem().transformToUni(
v -> {
if (checkNotNull(pusher)) {
return preservable.push(personId, pusher);
}
return Uni.createFrom().nullItem();
}
).onItem().transform(
v -> UnitRequest.of(answerSave, message)
);
}
}

View File

@ -0,0 +1,75 @@
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.quarkus.context.service.Sending;
import dev.struchkov.godfather.quarkus.core.unit.AnswerText;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import dev.struchkov.godfather.quarkus.core.utils.Sender;
import io.smallrye.mutiny.Uni;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/**
* Обработчик Unit-а {@link AnswerText}.
*
* @author upagge [11/07/2019]
*/
public class AnswerTextAction implements ActionUnit<AnswerText<Message>, Message> {
private final Sending sending;
public AnswerTextAction(Sending sending) {
this.sending = sending;
}
@Override
public Uni<UnitRequest<MainUnit, Message>> action(UnitRequest<AnswerText<Message>, Message> unitRequest) {
final AnswerText<Message> unit = unitRequest.getUnit();
final Message message = unitRequest.getMessage();
return unit.getAnswer().processing(message)
.onItem().transformToUni(
boxAnswer -> {
if (checkNotNull(boxAnswer)) {
return replaceMarkers(unit, message, boxAnswer);
}
return Uni.createFrom().nullItem();
}
).onItem().transformToUni(
boxAnswer -> {
if (checkNotNull(boxAnswer)) {
final Sending answerTextSending = unit.getSending();
if (answerTextSending != null) {
return Sender.sends(message, boxAnswer, answerTextSending);
} else {
return Sender.sends(message, boxAnswer, this.sending);
}
}
return Uni.createFrom().nullItem();
}
).onItem().transform(
v -> UnitRequest.of(unit, message)
);
}
private Uni<BoxAnswer> replaceMarkers(AnswerText<Message> answerText, Message message, BoxAnswer boxAnswer) {
if (answerText.getInsert() != null) {
return answerText.getInsert().insert(message.getPersonId())
.onItem().transformToUni(
words -> {
if (checkNotEmpty(words)) {
final String newMessage = InsertWords.insert(boxAnswer.getMessage(), words);
boxAnswer.setMessage(newMessage);
}
return Uni.createFrom().item(boxAnswer);
}
);
}
return Uni.createFrom().item(boxAnswer);
}
}

View File

@ -0,0 +1,19 @@
package dev.struchkov.godfather.quarkus.core.action.cmd;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.action.ActionUnit;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import dev.struchkov.godfather.quarkus.core.unit.cmd.ReplaceCmd;
import io.smallrye.mutiny.Uni;
public class ReplaceCmdAction implements ActionUnit<ReplaceCmd<Message>, Message> {
@Override
public Uni<UnitRequest<MainUnit, Message>> action(UnitRequest<ReplaceCmd<Message>, Message> unitRequest) {
final ReplaceCmd<Message> unit = unitRequest.getUnit();
final Message message = unitRequest.getMessage();
return Uni.createFrom().item(UnitRequest.of(unit.getThisUnit(), message));
}
}

View File

@ -0,0 +1,45 @@
package dev.struchkov.godfather.quarkus.core.action.cmd;
import dev.struchkov.godfather.main.domain.StorylineHistory;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.action.ActionUnit;
import dev.struchkov.godfather.quarkus.core.service.StorylineService;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import dev.struchkov.godfather.quarkus.core.unit.cmd.RollBackCmd;
import io.smallrye.mutiny.Uni;
import static dev.struchkov.godfather.exception.RollBackException.rollBackException;
public class RollBackCmdAction<M extends Message> implements ActionUnit<RollBackCmd<M>, M> {
private final StorylineService<M> storyLineService;
public RollBackCmdAction(StorylineService<M> storyLineService) {
this.storyLineService = storyLineService;
}
@Override
public Uni<UnitRequest<MainUnit, M>> action(UnitRequest<RollBackCmd<M>, M> unitRequest) {
final RollBackCmd<M> unit = unitRequest.getUnit();
final M message = unitRequest.getMessage();
final int countToBack = unit.getCountBack();
final String rollbackUnitName = unit.getRollbackUnitName();
final Uni<StorylineHistory> uniHistory = (rollbackUnitName != null)
? storyLineService.replaceUserToBack(message.getPersonId(), rollbackUnitName).onItem().ifNull().failWith(rollBackException("Юнит для возвращения не был найден"))
: storyLineService.replaceUserToBack(message.getPersonId(), countToBack).onItem().ifNull().failWith(rollBackException("Юнит для возвращения не был найден"));
return uniHistory
.onItem().transform(
history -> {
final String unitName = history.getUnitName();
final MainUnit<M> nextUnit = storyLineService.getUnitByName(unitName).orElse(unit);
final M oldMessage = (M) history.getMessage();
return UnitRequest.of(nextUnit, oldMessage);
}
);
}
}

View File

@ -0,0 +1,26 @@
package dev.struchkov.godfather.quarkus.core.provider;
import dev.struchkov.godfather.main.domain.content.Mail;
import dev.struchkov.godfather.quarkus.context.service.EventHandler;
import dev.struchkov.godfather.quarkus.core.GeneralAutoResponder;
import io.smallrye.mutiny.Uni;
public class StoryLineHandler implements EventHandler<Mail> {
private final GeneralAutoResponder<Mail> generalAutoResponder;
public StoryLineHandler(GeneralAutoResponder<Mail> generalAutoResponder) {
this.generalAutoResponder = generalAutoResponder;
}
@Override
public Uni<Void> handle(Mail message) {
return generalAutoResponder.processingNewMessage(message);
}
@Override
public String getEventType() {
return Mail.TYPE;
}
}

View File

@ -0,0 +1,42 @@
package dev.struchkov.godfather.quarkus.core.service;
import dev.struchkov.godfather.quarkus.context.service.PersonSettingService;
import dev.struchkov.godfather.quarkus.data.repository.PersonSettingRepository;
import dev.struchkov.haiti.utils.Inspector;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
public class PersonSettingServiceImpl implements PersonSettingService {
private final PersonSettingRepository personSettingRepository;
public PersonSettingServiceImpl(PersonSettingRepository personSettingRepository) {
this.personSettingRepository = personSettingRepository;
}
@Override
public Uni<Set<Long>> getAllPersonIdDisableMessages(@NotNull Set<Long> personIds) {
Inspector.isNotNull(personIds);
return personSettingRepository.findAllByAllowedProcessing(personIds);
}
@Override
public Uni<Boolean> getStateProcessingByPersonId(@NotNull Long personId) {
return personSettingRepository.findStateByPersonId(personId);
}
@Override
public Uni<Void> disableMessageProcessing(@NotNull Long personId) {
Inspector.isNotNull(personId);
return personSettingRepository.disableMessageProcessing(personId);
}
@Override
public Uni<Void> enableMessageProcessing(@NotNull Long personId) {
Inspector.isNotNull(personId);
return personSettingRepository.enableMessageProcessing(personId);
}
}

View File

@ -0,0 +1,59 @@
package dev.struchkov.godfather.quarkus.core.service;
import dev.struchkov.godfather.main.domain.ContextKey;
import dev.struchkov.godfather.quarkus.data.StorylineContext;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
public class StorylineContextMapImpl implements StorylineContext {
private final Map<Long, Map<String, Object>> map = new HashMap<>();
public Uni<Void> save(@NotNull Long personId, @NotNull ContextKey<?> key, Object objectForSave) {
isNotNull(personId, key);
map.computeIfAbsent(personId, k -> new HashMap<>()).put(key.getValue(), objectForSave);
return Uni.createFrom().voidItem();
}
public <T> Uni<T> getByKey(@NotNull Long 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 (object != null && object.getClass().equals(key.getType())) {
return Uni.createFrom().item(object);
}
}
return Uni.createFrom().nullItem();
}
@Override
public <T> Uni<T> getByKeyOrThrow(@NotNull Long personId, @NotNull ContextKey<T> key) {
return getByKey(personId, key)
.onItem().ifNull().failWith(notFoundException("Не найдено значение ключа {0}, для пользователя {1}", key.getValue(), personId));
}
public Uni<Map<String, Object>> getAllSaveElement(@NotNull Long personId) {
isNotNull(personId);
return Uni.createFrom().item(map.get(personId));
}
public Uni<Void> removeAll(@NotNull Long personId) {
isNotNull(personId);
map.remove(personId);
return Uni.createFrom().voidItem();
}
public Uni<Void> removeByKey(@NotNull Long personId, @NotNull ContextKey<?> key) {
isNotNull(personId, key);
map.computeIfAbsent(personId, k -> new HashMap<>()).remove(key.getValue());
return Uni.createFrom().voidItem();
}
}

View File

@ -0,0 +1,133 @@
package dev.struchkov.godfather.quarkus.core.service;
import dev.struchkov.godfather.main.domain.StorylineHistory;
import dev.struchkov.godfather.main.domain.UnitPointer;
import dev.struchkov.godfather.main.domain.content.Mail;
import dev.struchkov.godfather.quarkus.context.service.UnitPointerService;
import dev.struchkov.godfather.quarkus.core.Storyline;
import dev.struchkov.godfather.quarkus.core.StorylineFactory;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.data.repository.StorylineRepository;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import static dev.struchkov.haiti.utils.Checker.checkEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
/**
* Отвечает за работу со сценарием в личных сообщениях с пользователем.
*/
public class StorylineMailService implements StorylineService<Mail> {
private final UnitPointerService unitPointerService;
private final StorylineRepository storylineRepository;
private final Storyline<Mail> storyLine;
private String defaultUnitName;
public StorylineMailService(
UnitPointerService unitPointerService,
StorylineRepository storylineRepository,
List<Object> unitConfigurations
) {
this.storyLine = new StorylineFactory<Mail>(unitConfigurations).createStoryLine();
this.unitPointerService = unitPointerService;
this.storylineRepository = storylineRepository;
}
@Override
public Uni<Void> save(@NotNull StorylineHistory storylineHistory) {
isNotNull(storylineHistory);
return storylineRepository.save(storylineHistory);
}
@Override
public Uni<MainUnit<Mail>> getUnitNameByPersonId(@NotNull Long personId) {
isNotNull(personId);
return unitPointerService.getUnitNameByPersonId(personId)
.onItem().transform(
unitName -> {
if (checkNotNull(unitName)) {
return storyLine.getUnit(unitName).orElse(null);
} else {
return null;
}
}
);
}
@Override
public Uni<Set<MainUnit<Mail>>> getNextUnitByPersonId(@NotNull Long personId) {
return getUnitNameByPersonId(personId)
.flatMap(
unit -> {
if (checkNotNull(unit) && checkNotEmpty(unit.getNextUnits())) {
return Uni.createFrom().item(unit.getNextUnits());
} else {
return storylineRepository.cleanHistoryByPersonId(personId)
.onItem().transform(v -> storyLine.getStartingUnits());
}
}
).map(
nextUnits -> {
if (checkEmpty(nextUnits)) {
return storyLine.getGlobalUnits();
} else {
nextUnits.addAll(storyLine.getGlobalUnits());
return nextUnits;
}
}
);
}
@Override
public Uni<Void> save(Long personId, String unitName, Mail mail) {
isNotNull(personId, unitName, mail);
return unitPointerService.save(new UnitPointer(personId, unitName))
.map(u -> {
final StorylineHistory storylineHistory = new StorylineHistory();
storylineHistory.setPersonId(personId);
storylineHistory.setUnitName(unitName);
storylineHistory.setMessage(mail);
return storylineRepository.save(storylineHistory);
}).replaceWithVoid();
}
@Override
public Uni<StorylineHistory> replaceUserToBack(long personId, int countUnitsToBack) {
return storylineRepository.findByCountLast(personId, countUnitsToBack);
}
@Override
public Uni<StorylineHistory> replaceUserToBack(long personId, String unitName) {
return storylineRepository.findByCountLast(personId, unitName);
}
@Override
public Optional<MainUnit<Mail>> getDefaultUnit() {
if (defaultUnitName == null) return Optional.empty();
return storyLine.getUnit(defaultUnitName);
}
@Override
public void setDefaultUnit(String defaultUnit) {
defaultUnitName = defaultUnit;
}
//TODO [22.06.2022]: Временное решение для ленивой инициализации
@Override
public void lazyLink(String firstName, String secondName) {
storyLine.link(firstName, secondName);
}
@Override
public Optional<MainUnit<Mail>> getUnitByName(String unitName) {
return storyLine.getUnit(unitName);
}
}

View File

@ -0,0 +1,37 @@
package dev.struchkov.godfather.quarkus.core.service;
import dev.struchkov.godfather.main.domain.StorylineHistory;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
import java.util.Set;
public interface StorylineService<M extends Message> {
Uni<Void> save(@NotNull StorylineHistory storylineHistory);
Uni<MainUnit<M>> getUnitNameByPersonId(@NotNull Long personId);
Uni<Set<MainUnit<M>>> getNextUnitByPersonId(@NotNull Long personId);
Uni<Void> save(Long personId, String name, M message);
Uni<StorylineHistory> replaceUserToBack(long personId, int countUnitsToBack);
Uni<StorylineHistory> replaceUserToBack(long personId, String unitName);
Optional<MainUnit<M>> getDefaultUnit();
/**
* Ленивая (поздняя) связка юнитов между собой. Осуществляется уже после создания сценария. С помощью данного подхода можно реализовать циклические зависимости юнитов.
*/
void lazyLink(String firstName, String secondName);
Optional<MainUnit<M>> getUnitByName(String unitName);
void setDefaultUnit(String unitName);
}

View File

@ -0,0 +1,32 @@
package dev.struchkov.godfather.quarkus.core.service;
import dev.struchkov.godfather.main.domain.UnitPointer;
import dev.struchkov.godfather.quarkus.context.service.UnitPointerService;
import dev.struchkov.godfather.quarkus.data.repository.UnitPointerRepository;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
public class UnitPointerServiceImpl implements UnitPointerService {
private final UnitPointerRepository unitPointerRepository;
public UnitPointerServiceImpl(UnitPointerRepository unitPointerRepository) {
this.unitPointerRepository = unitPointerRepository;
}
@Override
public Uni<UnitPointer> save(@NotNull UnitPointer unitPointer) {
return unitPointerRepository.save(unitPointer);
}
@Override
public Uni<String> getUnitNameByPersonId(@NotNull Long personId) {
return unitPointerRepository.findUnitNameByPersonId(personId);
}
@Override
public Uni<Void> removeByPersonId(@NotNull Long personId) {
return unitPointerRepository.removeByPersonId(personId);
}
}

View File

@ -1,10 +1,11 @@
package dev.struchkov.godfather.context.domain.unit;
package dev.struchkov.godfather.quarkus.core.unit;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.context.domain.TypeUnit;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.service.Accessibility;
import dev.struchkov.godfather.context.service.usercode.CheckData;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Accessibility;
import dev.struchkov.godfather.quarkus.core.unit.func.CheckData;
import java.util.HashSet;
import java.util.Set;
@ -13,9 +14,8 @@ import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static dev.struchkov.godfather.context.exception.UnitConfigException.unitConfigException;
import static dev.struchkov.godfather.exception.UnitConfigException.unitConfigException;
import static dev.struchkov.haiti.utils.Inspector.isAnyNotNull;
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
/**
* Обработчик запроса, который реализует конструкцию IF в сценарии.
@ -213,7 +213,7 @@ public class AnswerCheck<M extends Message> extends MainUnit<M> {
}
public AnswerCheck<M> build() {
isNotNull(check, unitConfigException("Необходимо установить параметр проверки."));
// isNotNull(check, unitConfigException("Необходимо установить параметр проверки."));
isAnyNotNull(unitConfigException("Необходимо задать хотя бы один unit результата проверки."));
return new AnswerCheck<>(this);
}

View File

@ -1,13 +1,14 @@
package dev.struchkov.godfather.context.domain.unit;
package dev.struchkov.godfather.quarkus.core.unit;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.context.domain.TypeUnit;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.repository.preser.AnswerSavePreservable;
import dev.struchkov.godfather.context.service.Accessibility;
import dev.struchkov.godfather.context.service.save.CheckSave;
import dev.struchkov.godfather.context.service.save.PreservableData;
import dev.struchkov.godfather.context.service.save.Pusher;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Accessibility;
import dev.struchkov.godfather.quarkus.context.service.Pusher;
import dev.struchkov.godfather.quarkus.core.unit.func.CheckSave;
import dev.struchkov.godfather.quarkus.core.unit.func.PreservableData;
import dev.struchkov.godfather.quarkus.data.preser.AnswerSavePreservable;
import java.util.Collection;
import java.util.HashSet;
@ -18,7 +19,6 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Checker.checkNull;
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
/**
* Обработчик для сохранения ответов пользователя. Так же допускается скрытое сохранение.
@ -271,11 +271,11 @@ public class AnswerSave<M extends Message, D> extends MainUnit<M> {
}
public AnswerSave<M, D> build() {
isNotNull(preservable, "Не указан репозиторий для сохранения формы пользователя");
if (checkNull(pusher)) {
isNotNull(preservableData, "Не указаны данные для сохранения");
isNotNull(key, "Не указан ключ для сохранения");
}
// isNotNull(preservable, "Не указан репозиторий для сохранения формы пользователя");
// if (checkNull(pusher)) {
// isNotNull(preservableData, "Не указаны данные для сохранения");
// Inspector.isNotNull(key, "Не указан ключ для сохранения");
// }
return new AnswerSave<>(this);
}

View File

@ -0,0 +1,261 @@
package dev.struchkov.godfather.quarkus.core.unit;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message;
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 io.smallrye.mutiny.Uni;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Используется для отправки ответа пользователю.
*
* @author upagge [08/07/2019]
*/
public class AnswerText<M extends Message> extends MainUnit<M> {
/**
* Объект, который необходимо отправить пользователю.
*/
private final ProcessingData<M> answer;
/**
* Информация, которую необходимо вставить вместо маркеров в строку ответа.
*/
private final Insert insert;
/**
* Объект нестандартной отправки ответа.
*/
private final Sending sender;
private AnswerText(Builder<M> builder) {
super(
builder.name,
builder.description,
builder.triggerWords,
builder.triggerPhrases,
builder.triggerCheck,
builder.triggerPatterns,
builder.matchThreshold,
builder.priority,
builder.nextUnits,
builder.activeType,
builder.notSaveHistory,
builder.accessibility,
TypeUnit.TEXT
);
answer = builder.boxAnswer;
insert = builder.insert;
sender = builder.sending;
}
public static <M extends Message> AnswerText<M> of(String message) {
return AnswerText.<M>builder().answer(BoxAnswer.boxAnswer(message)).build();
}
public static <M extends Message> AnswerText<M> of(BoxAnswer boxAnswer) {
return AnswerText.<M>builder().answer(boxAnswer).build();
}
public static <M extends Message> Builder<M> builder() {
return new Builder<>();
}
public ProcessingData<M> getAnswer() {
return answer;
}
public Insert getInsert() {
return insert;
}
public Sending getSending() {
return sender;
}
public static final class Builder<M extends Message> {
private String name = UUID.randomUUID().toString();
private String description;
private Set<MainUnit<M>> nextUnits;
private Set<KeyWord> triggerWords;
private Set<String> triggerPhrases;
private Predicate<M> triggerCheck;
private Set<Pattern> triggerPatterns;
private Integer matchThreshold;
private Integer priority;
private UnitActiveType activeType;
private Accessibility accessibility;
private boolean notSaveHistory;
private ProcessingData<M> boxAnswer;
private Insert insert;
private Sending sending;
private Builder() {
}
public Builder<M> name(String name) {
this.name = name;
return this;
}
public Builder<M> description(String description) {
this.description = description;
return this;
}
public Builder<M> processing(Consumer<M> answer) {
this.boxAnswer = message -> {
answer.accept(message);
return null;
};
return this;
}
public Builder<M> answer(Function<M, Uni<BoxAnswer>> answer) {
this.boxAnswer = answer::apply;
return this;
}
public Builder<M> answer(BoxAnswer answer) {
this.boxAnswer = message -> Uni.createFrom().item(answer);
return this;
}
public Builder<M> answer(Supplier<BoxAnswer> answer) {
this.boxAnswer = message -> Uni.createFrom().item(answer.get());
return this;
}
public Builder<M> insert(Insert insert) {
this.insert = insert;
return this;
}
public Builder<M> sending(Sending sending) {
this.sending = sending;
return this;
}
public Builder<M> triggerWords(Set<KeyWord> val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val);
return this;
}
public Builder<M> triggerWord(KeyWord val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
}
triggerWords.add(val);
return this;
}
public Builder<M> triggerStringWords(Set<String> val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val.stream().map(KeyWord::of).collect(Collectors.toSet()));
return this;
}
public Builder<M> triggerWord(String val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
}
triggerWords.add(KeyWord.of(val));
return this;
}
public Builder<M> triggerPhrase(String... val) {
if (triggerPhrases == null) {
triggerPhrases = new HashSet<>();
}
if (val.length == 1) {
triggerPhrases.add(val[0]);
} else {
triggerPhrases.addAll(Set.of(val));
}
triggerPhrases.addAll(List.of(val));
return this;
}
public Builder<M> triggerPattern(Pattern... val) {
if (triggerPatterns == null) {
triggerPatterns = new HashSet<>();
}
if (val.length == 1) {
triggerPatterns.add(val[0]);
} else {
triggerPatterns.addAll(Set.of(val));
}
triggerPatterns.addAll(Set.of(val));
return this;
}
public Builder<M> triggerCheck(Predicate<M> trigger) {
triggerCheck = trigger;
return this;
}
public Builder<M> matchThreshold(Integer val) {
matchThreshold = val;
return this;
}
public Builder<M> priority(Integer val) {
priority = val;
return this;
}
public Builder<M> next(MainUnit<M> val) {
if (nextUnits == null) {
nextUnits = new HashSet<>();
}
nextUnits.add(val);
return this;
}
public Builder<M> accessibility(Accessibility val) {
accessibility = val;
return this;
}
public Builder<M> notSaveHistory() {
notSaveHistory = true;
return this;
}
public Builder<M> activeType(UnitActiveType val) {
activeType = val;
return this;
}
public AnswerText<M> build() {
// isNotNull(boxAnswer, UnitConfigException.unitConfigException("BoxAnswer обязательный параметр юнита"));
return new AnswerText<>(this);
}
}
}

View File

@ -0,0 +1,118 @@
package dev.struchkov.godfather.quarkus.core.unit;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.autoresponder.entity.Unit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Accessibility;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Pattern;
/**
* Главный обработчик {@link Unit}, от него наследуются все остальные Unit-ы.
*
* @author upagge [08/07/2019]
*/
public abstract class MainUnit<M extends Message> extends Unit<MainUnit<M>, M> {
/**
* Уникальное имя юнита
*/
private String name;
/**
* Описание юнита, что он делает. Никак не влияет на работу юнита и не участвует в ней. Возможно отображение этого текста в логах.
*/
private final String description;
/**
* Тип Unit-а.
*/
protected final String type;
/**
* Режим срабатывания Unit-а.
*/
protected UnitActiveType activeType;
/**
* Проверка доступа пользователя к юниту.
*/
private final Accessibility accessibility;
private final boolean notSaveHistory;
protected MainUnit(
String name,
String description,
Set<KeyWord> keyWords,
Set<String> phrases,
Predicate<M> triggerCheck,
Set<Pattern> patterns,
Integer matchThreshold,
Integer priority,
Set<MainUnit<M>> nextUnits,
UnitActiveType activeType,
boolean notSaveHistory,
Accessibility accessibility,
String type
) {
super(keyWords, phrases, triggerCheck, patterns, matchThreshold, priority, nextUnits);
this.name = name;
this.description = description;
this.activeType = Optional.ofNullable(activeType).orElse(UnitActiveType.DEFAULT);
this.accessibility = accessibility;
this.type = type;
this.notSaveHistory = notSaveHistory;
}
public String getType() {
return type;
}
public UnitActiveType getActiveType() {
return activeType;
}
public void setActiveType(UnitActiveType activeType) {
this.activeType = activeType;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public boolean isNotSaveHistory() {
return notSaveHistory;
}
public Optional<Accessibility> getAccessibility() {
return Optional.ofNullable(accessibility);
}
public String getDescription() {
return description;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MainUnit<?> unit = (MainUnit<?>) o;
return name.equals(unit.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}

View File

@ -1,7 +1,6 @@
package dev.struchkov.godfather.context.domain;
package dev.struchkov.godfather.quarkus.core.unit;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.main.domain.content.Message;
/**
* Сущность инкапсулирует в себе данные, необходимые для обработки сценария.

View File

@ -1,10 +1,10 @@
package dev.struchkov.godfather.context.domain.unit.cmd;
package dev.struchkov.godfather.quarkus.core.unit.cmd;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.context.domain.TypeUnit;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.context.domain.unit.UnitActiveType;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.haiti.utils.Checker;
import java.util.HashSet;

View File

@ -0,0 +1,212 @@
package dev.struchkov.godfather.quarkus.core.unit.cmd;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.exception.UnitConfigException;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Checker.checkNull;
/**
* Юнит, который позволяет откатить пользователя на предыдущие юниты в сценарии с сохранением ранее введенной информации в сообщениях.
*/
public class RollBackCmd<M extends Message> extends MainUnit<M> {
/**
* Количество юнитов, на которые можно откатиться назад.
*/
private final int countBack;
/**
* Имя юнита, на который нужно вернуть пользователя.
*/
private final String rollbackUnitName;
private RollBackCmd(Builder<M> builder) {
super(
builder.name,
builder.description,
builder.triggerWords,
builder.triggerPhrases,
builder.triggerCheck,
builder.triggerPatterns,
builder.matchThreshold,
builder.priority,
new HashSet<>(),
builder.activeType,
true,
null,
TypeUnit.BACK_CMD
);
this.countBack = builder.countBack;
this.rollbackUnitName = builder.rollbackUnitName;
}
public static <M extends Message> Builder<M> builder() {
return new Builder<>();
}
public static <M extends Message> RollBackCmd<M> rollBack(int countToBack) {
return RollBackCmd.<M>builder().countBack(countToBack).build();
}
public static <M extends Message> RollBackCmd<M> singleRollBack() {
return RollBackCmd.<M>builder().countBack(1).build();
}
public static <M extends Message> RollBackCmd<M> doubleRollBack() {
return RollBackCmd.<M>builder().countBack(2).build();
}
public static <M extends Message> RollBackCmd<M> rollBack(String unitName) {
return RollBackCmd.<M>builder().rollbackUnitName(unitName).build();
}
public static <M extends Message> RollBackCmd<M> rollBack(String phrase, String unitName) {
return RollBackCmd.<M>builder().triggerPhrase(phrase).rollbackUnitName(unitName).build();
}
public int getCountBack() {
return countBack;
}
public String getRollbackUnitName() {
return rollbackUnitName;
}
public static final class Builder<M extends Message> {
private String name = UUID.randomUUID().toString();
private String description;
private Set<String> triggerPhrases;
private Predicate<M> triggerCheck;
private Set<Pattern> triggerPatterns;
private Set<KeyWord> triggerWords;
private Integer matchThreshold;
private Integer priority;
private UnitActiveType activeType = UnitActiveType.DEFAULT;
private int countBack;
private String rollbackUnitName;
private Builder() {
}
public Builder<M> name(String name) {
this.name = name;
return this;
}
public Builder<M> description(String description) {
this.description = description;
return this;
}
public Builder<M> triggerWords(Set<KeyWord> val) {
if (checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val);
return this;
}
public Builder<M> triggerWord(KeyWord val) {
if (checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.add(val);
return this;
}
public Builder<M> triggerStringWords(Set<String> val) {
if (checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val.stream().map(KeyWord::of).collect(Collectors.toSet()));
return this;
}
public Builder<M> triggerWord(String val) {
if (checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.add(KeyWord.of(val));
return this;
}
public Builder<M> triggerPhrase(String... val) {
if (checkNull(triggerPhrases)) {
triggerPhrases = new HashSet<>();
}
if (val.length == 1) {
triggerPhrases.add(val[0]);
} else {
triggerPhrases.addAll(Set.of(val));
}
triggerPhrases.addAll(Set.of(val));
return this;
}
public Builder<M> triggerCheck(Predicate<M> trigger) {
triggerCheck = trigger;
return this;
}
public Builder<M> triggerPattern(Pattern... val) {
if (checkNull(triggerPatterns)) {
triggerPatterns = new HashSet<>();
}
if (val.length == 1) {
triggerPatterns.add(val[0]);
} else {
triggerPatterns.addAll(Set.of(val));
}
triggerPatterns.addAll(Set.of(val));
return this;
}
public Builder<M> matchThreshold(Integer val) {
matchThreshold = val;
return this;
}
public Builder<M> priority(Integer val) {
priority = val;
return this;
}
public Builder<M> activeType(UnitActiveType val) {
activeType = val;
return this;
}
public Builder<M> countBack(int val) {
countBack = val + 1;
return this;
}
public Builder<M> rollbackUnitName(String val) {
rollbackUnitName = val;
return this;
}
public RollBackCmd<M> build() {
if (rollbackUnitName == null && countBack < 2) {
throw new UnitConfigException("Ошибка конфигурирования юнита {0}: Количество юнитов для отката не должно быть меньше 1.", name);
}
return new RollBackCmd<M>(this);
}
}
}

View File

@ -0,0 +1,11 @@
package dev.struchkov.godfather.quarkus.core.unit.func;
import dev.struchkov.godfather.main.domain.content.Message;
import io.smallrye.mutiny.Uni;
@FunctionalInterface
public interface CheckData<C extends Message> {
Uni<Boolean> checked(C content);
}

View File

@ -0,0 +1,17 @@
package dev.struchkov.godfather.quarkus.core.unit.func;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import io.smallrye.mutiny.Uni;
/**
* TODO: Добавить описание интерфейса.
*
* @author upagge [04/08/2019]
*/
@FunctionalInterface
public interface CheckSave<M extends Message> {
Uni<MainUnit<M>> check(M content);
}

View File

@ -0,0 +1,12 @@
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(Long personId);
}

View File

@ -0,0 +1,11 @@
package dev.struchkov.godfather.quarkus.core.unit.func;
import dev.struchkov.godfather.main.domain.content.Message;
import io.smallrye.mutiny.Uni;
@FunctionalInterface
public interface PreservableData<D, M extends Message> {
Uni<D> getData(M content);
}

View File

@ -0,0 +1,11 @@
package dev.struchkov.godfather.quarkus.core.unit.func;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import io.smallrye.mutiny.Uni;
@FunctionalInterface
public interface ProcessingData<C> {
Uni<BoxAnswer> processing(C content);
}

View File

@ -0,0 +1,35 @@
package dev.struchkov.godfather.quarkus.core.utils;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Sending;
import io.smallrye.mutiny.Uni;
import static dev.struchkov.haiti.utils.Exceptions.utilityClass;
/**
* Используется для отправки сообщений определенного типа.
*
* @author upagge
*/
public class Sender {
private Sender() {
utilityClass();
}
public static Uni<Void> sends(Message message, BoxAnswer boxAnswer, Sending sending) {
switch (sending.getType()) {
case PUBLIC:
break;
case PRIVATE:
return privateSend(message, boxAnswer, sending);
}
return Uni.createFrom().voidItem();
}
private static Uni<Void> privateSend(Message message, BoxAnswer boxAnswer, Sending sending) {
return sending.send(message.getPersonId(), boxAnswer);
}
}

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>bot-core</artifactId>
<groupId>dev.struchkov.godfather</groupId>
<version>0.0.25</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bot-core-simple</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-core-main</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-context-simple</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-data-simple</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,25 +1,23 @@
package dev.struchkov.godfather.core;
package dev.struchkov.godfather.simple.core;
import dev.struchkov.autoresponder.Responder;
import dev.struchkov.godfather.context.domain.TypeUnit;
import dev.struchkov.godfather.context.domain.UnitRequest;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.context.domain.unit.UnitActiveType;
import dev.struchkov.godfather.context.exception.ConfigAppException;
import dev.struchkov.godfather.context.service.Accessibility;
import dev.struchkov.godfather.context.service.Modifiable;
import dev.struchkov.godfather.context.service.PersonSettingService;
import dev.struchkov.godfather.context.service.StorylineService;
import dev.struchkov.godfather.context.service.sender.Sending;
import dev.struchkov.godfather.core.service.ErrorHandler;
import dev.struchkov.godfather.core.service.action.ActionUnit;
import dev.struchkov.godfather.core.service.action.AnswerCheckAction;
import dev.struchkov.godfather.core.service.action.AnswerSaveAction;
import dev.struchkov.godfather.core.service.action.AnswerTextAction;
import dev.struchkov.godfather.core.service.action.AnswerTimerAction;
import dev.struchkov.godfather.core.service.action.cmd.ReplaceCmdAction;
import dev.struchkov.godfather.core.service.timer.TimerService;
import dev.struchkov.godfather.exception.ConfigAppException;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.context.service.Accessibility;
import dev.struchkov.godfather.simple.context.service.ErrorHandler;
import dev.struchkov.godfather.simple.context.service.Modifiable;
import dev.struchkov.godfather.simple.context.service.PersonSettingService;
import dev.struchkov.godfather.simple.context.service.Sending;
import dev.struchkov.godfather.simple.core.action.ActionUnit;
import dev.struchkov.godfather.simple.core.action.AnswerCheckAction;
import dev.struchkov.godfather.simple.core.action.AnswerSaveAction;
import dev.struchkov.godfather.simple.core.action.AnswerTextAction;
import dev.struchkov.godfather.simple.core.action.cmd.ReplaceCmdAction;
import dev.struchkov.godfather.simple.core.service.StorylineService;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import dev.struchkov.haiti.context.exception.NotFoundException;
import java.util.HashMap;
@ -69,10 +67,6 @@ public class GeneralAutoResponder<M extends Message> {
actionUnitMap.put(TypeUnit.SAVE, answerSaveAction);
}
public void initTimerAction(TimerService timerService) {
actionUnitMap.put(TypeUnit.TIMER, new AnswerTimerAction(timerService, this));
}
/**
* Позволяет установить перехватчик и обработчик исключений, возникающих при обработке юнитов.
*/

View File

@ -1,7 +1,7 @@
package dev.struchkov.godfather.core;
package dev.struchkov.godfather.simple.core;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.haiti.utils.Inspector;
import org.jetbrains.annotations.NotNull;

View File

@ -0,0 +1,167 @@
package dev.struchkov.godfather.simple.core;
import dev.struchkov.godfather.exception.UnitConfigException;
import dev.struchkov.godfather.main.domain.UnitDefinition;
import dev.struchkov.godfather.main.domain.annotation.Unit;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.haiti.utils.Inspector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.godfather.exception.UnitConfigException.unitConfigException;
public class StorylineFactory<M extends Message> {
private static final Logger log = LoggerFactory.getLogger(StorylineFactory.class);
private final List<Object> configurations = new ArrayList<>();
private final Map<String, UnitDefinition> unitDefinitions = new HashMap<>();
private final Map<String, MainUnit<M>> unitMap = new HashMap<>();
private final Set<String> mainUnits = new HashSet<>();
private final Set<String> globalUnits = new HashSet<>();
public StorylineFactory(List<Object> unitConfigurations) {
this.configurations.addAll(unitConfigurations);
}
public Map<String, UnitDefinition> getUnitDefinitions() {
return unitDefinitions;
}
public Map<String, MainUnit<M>> getUnitMap() {
return unitMap;
}
public Storyline<M> createStoryLine() {
generateUnitDefinitions();
try {
createUnitMap();
final Set<MainUnit<M>> mainUnit = getMainUnit();
final Set<MainUnit<M>> globalUnit = getGlobalUnit();
final Storyline<M> storyline = new Storyline<>(mainUnit, unitMap);
storyline.addGlobalUnits(globalUnit);
return storyline;
} catch (IllegalAccessException | InvocationTargetException e) {
log.error(e.getMessage(), e);
}
throw new UnitConfigException("Ошибка построения StoryLine");
}
private Set<MainUnit<M>> getMainUnit() {
Inspector.isNotEmpty(mainUnits, unitConfigException("Не задан ни один mainUnit. Установите хотя бы для одного Unit флаг mainUnit"));
return mainUnits.stream()
.map(unitMap::get)
.collect(Collectors.toSet());
}
private Set<MainUnit<M>> getGlobalUnit() {
return globalUnits.stream()
.map(unitMap::get)
.collect(Collectors.toSet());
}
private void createUnitMap() throws IllegalAccessException, InvocationTargetException {
for (UnitDefinition unitDefinition : unitDefinitions.values()) {
if (!unitMap.containsKey(unitDefinition.getName())) {
final Set<String> nextUnitNames = unitDefinition.getNextUnitNames();
if (nextUnitNames.isEmpty() || unitMap.keySet().containsAll(nextUnitNames)) {
createUnit(unitDefinition);
}
}
}
}
private MainUnit<M> createUnit(UnitDefinition unitDefinition) throws IllegalAccessException, InvocationTargetException {
final Object objectConfig = unitDefinition.getObjectConfig();
final String currentUnitName = unitDefinition.getName();
final Method method = unitDefinition.getMethod();
final Object[] nextUnits = Arrays.stream(method.getParameters())
.filter(parameter -> parameter.isAnnotationPresent(Unit.class))
.map(parameter -> parameter.getAnnotation(Unit.class))
.map(Unit::value)
.map(unitMap::get)
.toArray();
MainUnit<M> newUnit = (MainUnit<M>) method.invoke(objectConfig, nextUnits);
newUnit.setName(currentUnitName);
unitMap.put(currentUnitName, newUnit);
final Set<String> dependentUnitsName = unitDefinition.getDependentUnits();
for (String dependentUnitName : dependentUnitsName) {
final Set<String> dependentNextUnitNames = unitDefinitions.get(dependentUnitName).getNextUnitNames();
if (unitMap.keySet().containsAll(dependentNextUnitNames)) {
createUnit(unitDefinitions.get(dependentUnitName));
}
}
return newUnit;
}
private void generateUnitDefinitions() {
final Map<String, Set<String>> dependentUnits = new HashMap<>();
for (Object config : configurations) {
final Class<?> classUnitConfig = config.getClass();
for (Method method : classUnitConfig.getDeclaredMethods()) {
if (method.isAnnotationPresent(Unit.class)) {
final Unit unitConfig = method.getAnnotation(Unit.class);
final String unitName = unitConfig.value();
final UnitDefinition unitDefinition = new UnitDefinition();
unitDefinition.setName(unitName);
unitDefinition.setMethod(method);
unitDefinition.setObjectConfig(config);
if (unitConfig.main()) {
mainUnits.add(unitName);
}
if (unitConfig.global()) {
globalUnits.add(unitName);
}
final Parameter[] nextUnits = method.getParameters();
if (nextUnits.length > 0) {
for (Parameter nextUnit : nextUnits) {
if (nextUnit.isAnnotationPresent(Unit.class)) {
final Unit nextUnitConfig = nextUnit.getAnnotation(Unit.class);
final String nextUnitName = nextUnitConfig.value();
unitDefinition.setNextUnitName(nextUnitName);
dependentUnits.computeIfAbsent(nextUnitName, k -> new HashSet<>());
dependentUnits.get(nextUnitName).add(unitName);
}
}
}
unitDefinitions.put(unitDefinition.getName(), unitDefinition);
}
}
}
for (Map.Entry<String, Set<String>> entry : dependentUnits.entrySet()) {
final UnitDefinition unitDefinition = unitDefinitions.get(entry.getKey());
if (unitDefinition != null) {
unitDefinition.setDependentUnits(entry.getValue());
} else {
throw new UnitConfigException("Ошибка связи юнитов. Проблема с описанием {0} юнита. Возможно вы не указали класс конфигурации для этого юнита.", entry.getKey());
}
}
}
}

View File

@ -1,8 +1,8 @@
package dev.struchkov.godfather.core.service.action;
package dev.struchkov.godfather.simple.core.action;
import dev.struchkov.godfather.context.domain.UnitRequest;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
/**
* Интерфейс для обработки Unit-ов.

View File

@ -1,9 +1,9 @@
package dev.struchkov.godfather.core.service.action;
package dev.struchkov.godfather.simple.core.action;
import dev.struchkov.godfather.context.domain.UnitRequest;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.AnswerCheck;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.unit.AnswerCheck;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,13 +1,13 @@
package dev.struchkov.godfather.core.service.action;
package dev.struchkov.godfather.simple.core.action;
import dev.struchkov.godfather.context.domain.UnitRequest;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.AnswerSave;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.context.repository.preser.AnswerSavePreservable;
import dev.struchkov.godfather.context.service.save.CheckSave;
import dev.struchkov.godfather.context.service.save.PreservableData;
import dev.struchkov.godfather.context.service.save.Pusher;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.context.service.Pusher;
import dev.struchkov.godfather.simple.core.unit.AnswerSave;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import dev.struchkov.godfather.simple.core.unit.func.CheckSave;
import dev.struchkov.godfather.simple.core.unit.func.PreservableData;
import dev.struchkov.godfather.simple.data.preser.AnswerSavePreservable;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;

View File

@ -1,13 +1,13 @@
package dev.struchkov.godfather.core.service.action;
package dev.struchkov.godfather.simple.core.action;
import dev.struchkov.godfather.context.domain.BoxAnswer;
import dev.struchkov.godfather.context.domain.UnitRequest;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.AnswerText;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.context.service.sender.Sending;
import dev.struchkov.godfather.context.utils.InsertWords;
import dev.struchkov.godfather.context.utils.Sender;
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.simple.context.service.Sending;
import dev.struchkov.godfather.simple.core.unit.AnswerText;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import dev.struchkov.godfather.simple.core.utils.Sender;
import java.util.List;
import java.util.Optional;

View File

@ -0,0 +1,18 @@
package dev.struchkov.godfather.simple.core.action.cmd;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.action.ActionUnit;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import dev.struchkov.godfather.simple.core.unit.cmd.ReplaceCmd;
public class ReplaceCmdAction implements ActionUnit<ReplaceCmd<Message>, Message> {
@Override
public UnitRequest<MainUnit, Message> action(UnitRequest<ReplaceCmd<Message>, Message> unitRequest) {
final ReplaceCmd<Message> unit = unitRequest.getUnit();
final Message message = unitRequest.getMessage();
return UnitRequest.of(unit.getThisUnit(), message);
}
}

View File

@ -1,14 +1,14 @@
package dev.struchkov.godfather.core.service.action.cmd;
package dev.struchkov.godfather.simple.core.action.cmd;
import dev.struchkov.godfather.context.domain.StorylineHistory;
import dev.struchkov.godfather.context.domain.UnitRequest;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.context.domain.unit.cmd.RollBackCmd;
import dev.struchkov.godfather.context.service.StorylineService;
import dev.struchkov.godfather.core.service.action.ActionUnit;
import dev.struchkov.godfather.main.domain.StorylineHistory;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.action.ActionUnit;
import dev.struchkov.godfather.simple.core.service.StorylineService;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import dev.struchkov.godfather.simple.core.unit.cmd.RollBackCmd;
import static dev.struchkov.godfather.context.exception.RollBackException.rollBackException;
import static dev.struchkov.godfather.exception.RollBackException.rollBackException;
public class RollBackCmdAction<M extends Message> implements ActionUnit<RollBackCmd<M>, M> {

View File

@ -1,8 +1,8 @@
package dev.struchkov.godfather.core.service.provider;
package dev.struchkov.godfather.simple.core.provider;
import dev.struchkov.godfather.context.domain.content.Mail;
import dev.struchkov.godfather.context.service.EventHandler;
import dev.struchkov.godfather.core.GeneralAutoResponder;
import dev.struchkov.godfather.main.domain.content.Mail;
import dev.struchkov.godfather.simple.context.service.EventHandler;
import dev.struchkov.godfather.simple.core.GeneralAutoResponder;
public class StoryLineHandler implements EventHandler<Mail> {

View File

@ -1,11 +1,12 @@
package dev.struchkov.godfather.core.service.save.push;
package dev.struchkov.godfather.simple.core.pusher;
import dev.struchkov.godfather.context.domain.BoxAnswer;
import dev.struchkov.godfather.context.service.save.Pusher;
import dev.struchkov.godfather.context.service.sender.Sending;
import dev.struchkov.godfather.simple.context.service.Pusher;
import dev.struchkov.godfather.simple.context.service.Sending;
import java.util.Map;
import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer;
public class UserSanderPusher implements Pusher<String> {
private final Long personId;
@ -24,7 +25,7 @@ public class UserSanderPusher implements Pusher<String> {
stringBuilder.append("========= ").append(nameForm).append(" =========\n");
saveElement.forEach((key, value) -> stringBuilder.append(key).append(": ").append(value).append("\n"));
stringBuilder.append("====================");
sending.send(this.personId, BoxAnswer.builder().message(stringBuilder.toString()).build());
sending.send(this.personId, boxAnswer(stringBuilder.toString()));
}
}

View File

@ -1,7 +1,7 @@
package dev.struchkov.godfather.core.service;
package dev.struchkov.godfather.simple.core.service;
import dev.struchkov.godfather.context.repository.PersonSettingRepository;
import dev.struchkov.godfather.context.service.PersonSettingService;
import dev.struchkov.godfather.simple.context.service.PersonSettingService;
import dev.struchkov.godfather.simple.data.repository.PersonSettingRepository;
import dev.struchkov.haiti.utils.Inspector;
import org.jetbrains.annotations.NotNull;

View File

@ -1,7 +1,7 @@
package dev.struchkov.godfather.core.service;
package dev.struchkov.godfather.simple.core.service;
import dev.struchkov.godfather.context.domain.ContextKey;
import dev.struchkov.godfather.context.service.StorylineContext;
import dev.struchkov.godfather.main.domain.ContextKey;
import dev.struchkov.godfather.simple.data.StorylineContext;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;

View File

@ -1,16 +1,14 @@
package dev.struchkov.godfather.core.service;
package dev.struchkov.godfather.simple.core.service;
import dev.struchkov.autoresponder.entity.Unit;
import dev.struchkov.godfather.context.domain.StorylineHistory;
import dev.struchkov.godfather.context.domain.UnitPointer;
import dev.struchkov.godfather.context.domain.content.Mail;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.context.repository.StorylineRepository;
import dev.struchkov.godfather.context.service.StorylineService;
import dev.struchkov.godfather.context.service.UnitPointerService;
import dev.struchkov.godfather.core.Storyline;
import dev.struchkov.godfather.core.StorylineFactory;
import dev.struchkov.haiti.utils.Inspector;
import dev.struchkov.godfather.main.domain.StorylineHistory;
import dev.struchkov.godfather.main.domain.UnitPointer;
import dev.struchkov.godfather.main.domain.content.Mail;
import dev.struchkov.godfather.simple.context.service.UnitPointerService;
import dev.struchkov.godfather.simple.core.Storyline;
import dev.struchkov.godfather.simple.core.StorylineFactory;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.data.repository.StorylineRepository;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@ -42,13 +40,12 @@ public class StorylineMailService implements StorylineService<Mail> {
@Override
public void save(@NotNull StorylineHistory storylineHistory) {
isNotNull(storylineHistory);
storylineHistory.setId(null);
storylineRepository.save(storylineHistory);
}
@Override
public Optional<MainUnit<Mail>> getUnitNameByPersonId(@NotNull Long personId) {
Inspector.isNotNull(personId);
isNotNull(personId);
return unitPointerService.getUnitNameByPersonId(personId)
.flatMap(storyLine::getUnit);
}
@ -68,7 +65,7 @@ public class StorylineMailService implements StorylineService<Mail> {
@Override
public void save(Long personId, String unitName, Mail mail) {
Inspector.isNotNull(personId, unitName, mail);
isNotNull(personId, unitName, mail);
unitPointerService.save(new UnitPointer(personId, unitName));
final StorylineHistory storylineHistory = new StorylineHistory();

View File

@ -1,8 +1,8 @@
package dev.struchkov.godfather.context.service;
package dev.struchkov.godfather.simple.core.service;
import dev.struchkov.godfather.context.domain.StorylineHistory;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.main.domain.StorylineHistory;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;

View File

@ -1,8 +1,8 @@
package dev.struchkov.godfather.core.service;
package dev.struchkov.godfather.simple.core.service;
import dev.struchkov.godfather.context.domain.UnitPointer;
import dev.struchkov.godfather.context.repository.UnitPointerRepository;
import dev.struchkov.godfather.context.service.UnitPointerService;
import dev.struchkov.godfather.main.domain.UnitPointer;
import dev.struchkov.godfather.simple.context.service.UnitPointerService;
import dev.struchkov.godfather.simple.data.repository.UnitPointerRepository;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;

View File

@ -1,10 +1,11 @@
package dev.struchkov.godfather.context.domain.unit;
package dev.struchkov.godfather.simple.core.unit;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.context.domain.TypeUnit;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.service.Accessibility;
import dev.struchkov.godfather.context.service.usercode.CheckData;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.context.service.Accessibility;
import dev.struchkov.godfather.simple.core.unit.func.CheckData;
import java.util.HashSet;
import java.util.Set;
@ -13,37 +14,29 @@ import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static dev.struchkov.godfather.context.exception.UnitConfigException.unitConfigException;
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
/**
* Обработчик таймер, позволяющий отложить обработку других Unit-ов.
* Обработчик запроса, который реализует конструкцию IF в сценарии.
*
* @author upagge [08/07/2019]
*/
public class AnswerTimer<M extends Message> extends MainUnit<M> {
public class AnswerCheck<M extends Message> extends MainUnit<M> {
/**
* Unit обработку которого необходимо отложить.
* Unit для true.
*/
private final MainUnit<M> unitAnswer;
private final MainUnit unitTrue;
/**
* Задержка обработки в секундах.
* Unit для false.
*/
private final Integer timeDelaySec;
private final MainUnit unitFalse;
/**
* Время, через которое таймер будет удален в секундах.
* Условие проверки.
*/
private final Integer timeDeathSec;
private final CheckData<M> check;
/**
* Условие срабатывания отложенного Unit.
*/
private final CheckData<M> checkLoop;
private AnswerTimer(Builder<M> builder) {
private AnswerCheck(Builder<M> builder) {
super(
builder.name,
builder.description,
@ -53,36 +46,31 @@ public class AnswerTimer<M extends Message> extends MainUnit<M> {
builder.triggerPatterns,
builder.matchThreshold,
builder.priority,
null,
new HashSet<>(),
builder.activeType,
builder.notSaveHistory,
builder.accessibility,
TypeUnit.TIMER
TypeUnit.CHECK
);
unitAnswer = builder.unitAnswer;
timeDelaySec = builder.timeDelaySec;
timeDeathSec = builder.timeDeathSec;
checkLoop = builder.checkLoop;
unitTrue = builder.unitTrue;
unitFalse = builder.unitFalse;
check = builder.check;
}
public static <M extends Message> Builder<M> builder() {
return new Builder<>();
}
public MainUnit<M> getUnitAnswer() {
return unitAnswer;
public MainUnit getUnitTrue() {
return unitTrue;
}
public Integer getTimeDelaySec() {
return timeDelaySec;
public MainUnit getUnitFalse() {
return unitFalse;
}
public Integer getTimeDeathSec() {
return timeDeathSec;
}
public CheckData<M> getCheckLoop() {
return checkLoop;
public CheckData<M> getCheck() {
return check;
}
public static final class Builder<M extends Message> {
@ -96,14 +84,14 @@ public class AnswerTimer<M extends Message> extends MainUnit<M> {
private Integer matchThreshold;
private Integer priority;
private UnitActiveType activeType = UnitActiveType.AFTER;
private UnitActiveType activeType;
private Accessibility accessibility;
private boolean notSaveHistory;
private MainUnit<M> unitAnswer;
private Integer timeDelaySec;
private Integer timeDeathSec;
private CheckData<M> checkLoop;
private MainUnit unitTrue;
private MainUnit unitFalse;
private CheckData<M> check;
private Builder() {
}
@ -118,26 +106,6 @@ public class AnswerTimer<M extends Message> extends MainUnit<M> {
return this;
}
public Builder<M> unitAnswer(MainUnit<M> val) {
unitAnswer = val;
return this;
}
public Builder<M> timeDelaySec(Integer val) {
timeDelaySec = val;
return this;
}
public Builder<M> timeDeathSec(Integer val) {
timeDeathSec = val;
return this;
}
public Builder<M> checkLoop(CheckData<M> val) {
checkLoop = val;
return this;
}
public Builder<M> triggerWords(Set<KeyWord> val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
@ -196,7 +164,7 @@ public class AnswerTimer<M extends Message> extends MainUnit<M> {
return this;
}
public Builder<M> triggerCheck(Predicate<M> trigger) {
private Builder<M> triggerCheck(Predicate<M> trigger) {
triggerCheck = trigger;
return this;
}
@ -211,13 +179,23 @@ public class AnswerTimer<M extends Message> extends MainUnit<M> {
return this;
}
public Builder<M> accessibility(Accessibility val) {
accessibility = val;
public Builder<M> unitTrue(MainUnit unitTrue) {
this.unitTrue = unitTrue;
return this;
}
public Builder<M> notSaveHistory() {
notSaveHistory = true;
public Builder<M> unitFalse(MainUnit unitFalse) {
this.unitFalse = unitFalse;
return this;
}
public Builder<M> check(CheckData<M> check) {
this.check = check;
return this;
}
public Builder<M> accessibility(Accessibility val) {
accessibility = val;
return this;
}
@ -226,9 +204,15 @@ public class AnswerTimer<M extends Message> extends MainUnit<M> {
return this;
}
public AnswerTimer<M> build() {
isNotNull(unitAnswer, unitConfigException("Необходимо указать юнит, обработка которого будет отложена."));
return new AnswerTimer<>(this);
public Builder<M> notSaveHistory() {
notSaveHistory = true;
return this;
}
public AnswerCheck<M> build() {
// isNotNull(check, unitConfigException("Необходимо установить параметр проверки."));
// Inspector.isAnyNotNull(unitConfigException("Необходимо задать хотя бы один unit результата проверки."));
return new AnswerCheck<>(this);
}
}

View File

@ -0,0 +1,283 @@
package dev.struchkov.godfather.simple.core.unit;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.context.service.Accessibility;
import dev.struchkov.godfather.simple.context.service.Pusher;
import dev.struchkov.godfather.simple.core.unit.func.CheckSave;
import dev.struchkov.godfather.simple.core.unit.func.PreservableData;
import dev.struchkov.godfather.simple.data.preser.AnswerSavePreservable;
import dev.struchkov.haiti.utils.Checker;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Обработчик для сохранения ответов пользователя. Так же допускается скрытое сохранение.
*
* @author upagge [08/07/2019]
*/
public class AnswerSave<M extends Message, D> extends MainUnit<M> {
/**
* Объект отвечающий за сохранение - репозиторий.
*/
private final AnswerSavePreservable<D> preservable;
/**
* Ключ для данных.
*/
private final String key;
/**
* Отправка результатов.
*/
private final Pusher<D> pusher;
/**
* Данные для скрытого сохранения.
*/
private final PreservableData<D, M> preservableData;
/**
* Скрытое сохранение.
*/
private final boolean hidden;
private final CheckSave<M> checkSave;
private AnswerSave(Builder<M, D> builder) {
super(
builder.name,
builder.description,
builder.triggerWords,
builder.triggerPhrases,
builder.triggerCheck,
builder.triggerPatterns,
builder.matchThreshold,
builder.priority,
builder.nextUnits,
(builder.hidden) ? UnitActiveType.AFTER : UnitActiveType.DEFAULT,
builder.notSaveHistory,
builder.accessibility,
TypeUnit.SAVE
);
maintenanceNextUnit(nextUnits);
preservable = builder.preservable;
key = builder.key;
pusher = builder.pusher;
preservableData = builder.preservableData;
hidden = builder.hidden;
checkSave = builder.checkSave;
}
public static <M extends Message, D> Builder<M, D> builder() {
return new Builder<>();
}
private void maintenanceNextUnit(Collection<MainUnit<M>> units) {
if (units != null) {
units.forEach(mainUnit -> mainUnit.setActiveType(UnitActiveType.AFTER));
}
}
public AnswerSavePreservable<D> getPreservable() {
return preservable;
}
public String getKey() {
return key;
}
public Pusher<D> getPusher() {
return pusher;
}
public PreservableData<D, M> getPreservableData() {
return preservableData;
}
public boolean isHidden() {
return hidden;
}
public CheckSave<M> getCheckSave() {
return checkSave;
}
public static final class Builder<M extends Message, D> {
private String name = UUID.randomUUID().toString();
private String description;
private Set<MainUnit<M>> nextUnits;
private Set<KeyWord> triggerWords;
private Set<String> triggerPhrases;
private Set<Pattern> triggerPatterns;
private Predicate<M> triggerCheck;
private Integer matchThreshold;
private Integer priority;
private Accessibility accessibility;
private boolean notSaveHistory;
private AnswerSavePreservable<D> preservable;
private String key;
private Pusher<D> pusher;
private PreservableData<D, M> preservableData;
private boolean hidden;
private CheckSave<M> checkSave;
private Builder() {
}
public Builder<M, D> name(String name) {
this.name = name;
return this;
}
public Builder<M, D> description(String description) {
this.description = description;
return this;
}
public Builder<M, D> triggerWords(Set<KeyWord> val) {
if (Checker.checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val);
return this;
}
public Builder<M, D> triggerWord(KeyWord val) {
if (Checker.checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.add(val);
return this;
}
public Builder<M, D> triggerStringWords(Set<String> val) {
if (Checker.checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val.stream().map(KeyWord::of).collect(Collectors.toSet()));
return this;
}
public Builder<M, D> triggerWord(String val) {
if (Checker.checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.add(KeyWord.of(val));
return this;
}
public Builder<M, D> triggerPhrase(String... val) {
if (Checker.checkNull(triggerPhrases)) {
triggerPhrases = new HashSet<>();
}
if (val.length == 1) {
triggerPhrases.add(val[0]);
} else {
triggerPhrases.addAll(Set.of(val));
}
triggerPhrases.addAll(Set.of(val));
return this;
}
public Builder<M, D> triggerPattern(Pattern... val) {
if (Checker.checkNull(triggerPatterns)) {
triggerPatterns = new HashSet<>();
}
if (val.length == 1) {
triggerPatterns.add(val[0]);
} else {
triggerPatterns.addAll(Set.of(val));
}
triggerPatterns.addAll(Set.of(val));
return this;
}
public Builder<M, D> triggerCheck(Predicate<M> trigger) {
triggerCheck = trigger;
return this;
}
public Builder<M, D> matchThreshold(Integer val) {
matchThreshold = val;
return this;
}
public Builder<M, D> priority(Integer val) {
priority = val;
return this;
}
public Builder<M, D> next(MainUnit<M> val) {
if (Checker.checkNull(nextUnits)) {
nextUnits = new HashSet<>();
}
nextUnits.add(val);
return this;
}
public Builder<M, D> preservable(AnswerSavePreservable<D> val) {
this.preservable = val;
return this;
}
public Builder<M, D> key(String val) {
this.key = val;
return this;
}
public Builder<M, D> pusher(Pusher<D> val) {
this.pusher = val;
return this;
}
public Builder<M, D> preservableData(PreservableData<D, M> val) {
this.preservableData = val;
return this;
}
public Builder<M, D> hidden(boolean val) {
this.hidden = val;
return this;
}
public Builder<M, D> checkSave(CheckSave<M> val) {
this.checkSave = val;
return this;
}
public Builder<M, D> accessibility(Accessibility val) {
accessibility = val;
return this;
}
public Builder<M, D> notSaveHistory() {
notSaveHistory = true;
return this;
}
public AnswerSave<M, D> build() {
// Inspector.isNotNull(preservable, "Не указан репозиторий для сохранения формы пользователя");
// if (Checker.checkNull(pusher)) {
// Inspector.isNotNull(preservableData, "Не указаны данные для сохранения");
// isNotNull(key, "Не указан ключ для сохранения");
// }
return new AnswerSave<>(this);
}
}
}

View File

@ -1,14 +1,14 @@
package dev.struchkov.godfather.context.domain.unit;
package dev.struchkov.godfather.simple.core.unit;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.context.domain.BoxAnswer;
import dev.struchkov.godfather.context.domain.TypeUnit;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.exception.UnitConfigException;
import dev.struchkov.godfather.context.service.Accessibility;
import dev.struchkov.godfather.context.service.sender.Sending;
import dev.struchkov.godfather.context.service.usercode.Insert;
import dev.struchkov.godfather.context.service.usercode.ProcessingData;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message;
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 java.util.HashSet;
import java.util.List;
@ -22,8 +22,6 @@ import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
/**
* Используется для отправки ответа пользователю.
*
@ -128,23 +126,23 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
public Builder<M> processing(Consumer<M> answer) {
this.boxAnswer = message -> {
answer.accept(message);
return Optional.empty();
return null;
};
return this;
}
public Builder<M> answer(Function<M, BoxAnswer> answer) {
this.boxAnswer = message -> Optional.of(answer.apply(message));
this.boxAnswer = message -> Optional.ofNullable(answer.apply(message));
return this;
}
public Builder<M> answer(BoxAnswer answer) {
this.boxAnswer = message -> Optional.of(answer);
this.boxAnswer = message -> Optional.ofNullable(answer);
return this;
}
public Builder<M> answer(Supplier<BoxAnswer> answer) {
this.boxAnswer = message -> Optional.of(answer.get());
this.boxAnswer = message -> Optional.ofNullable(answer.get());
return this;
}
@ -255,7 +253,7 @@ public class AnswerText<M extends Message> extends MainUnit<M> {
}
public AnswerText<M> build() {
isNotNull(boxAnswer, UnitConfigException.unitConfigException("BoxAnswer обязательный параметр юнита"));
// isNotNull(boxAnswer, UnitConfigException.unitConfigException("BoxAnswer обязательный параметр юнита"));
return new AnswerText<>(this);
}

View File

@ -1,9 +1,10 @@
package dev.struchkov.godfather.context.domain.unit;
package dev.struchkov.godfather.simple.core.unit;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.autoresponder.entity.Unit;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.service.Accessibility;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.context.service.Accessibility;
import java.util.Objects;
import java.util.Optional;

View File

@ -0,0 +1,33 @@
package dev.struchkov.godfather.simple.core.unit;
import dev.struchkov.godfather.main.domain.content.Message;
/**
* Сущность инкапсулирует в себе данные, необходимые для обработки сценария.
*
* @param <U> Тип юнита
* @param <M> Тип сообщения
*/
public class UnitRequest<U extends MainUnit, M extends Message> {
private final U unit;
private final M message;
private UnitRequest(U unit, M message) {
this.unit = unit;
this.message = message;
}
public static <U extends MainUnit<M>, M extends Message> UnitRequest<U, M> of(U mainUnit, M message) {
return new UnitRequest<>(mainUnit, message);
}
public U getUnit() {
return unit;
}
public M getMessage() {
return message;
}
}

View File

@ -0,0 +1,164 @@
package dev.struchkov.godfather.simple.core.unit.cmd;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.haiti.utils.Checker;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class ReplaceCmd<M extends Message> extends MainUnit<M> {
private final MainUnit thisUnit;
private ReplaceCmd(Builder<M> builder) {
super(
builder.name,
builder.description,
builder.triggerWords,
builder.triggerPhrases,
builder.triggerCheck,
builder.triggerPatterns,
builder.matchThreshold,
builder.priority,
new HashSet<>(),
builder.activeType,
true,
null,
TypeUnit.REPLACE_CMD
);
this.thisUnit = builder.thisUnit;
}
public static <M extends Message> Builder<M> builder() {
return new Builder<>();
}
public MainUnit getThisUnit() {
return thisUnit;
}
public static final class Builder<M extends Message> {
private String name = UUID.randomUUID().toString();
private String description;
private Set<String> triggerPhrases;
private Predicate<M> triggerCheck;
private Set<Pattern> triggerPatterns;
private Set<KeyWord> triggerWords;
private Integer matchThreshold;
private Integer priority;
private UnitActiveType activeType = UnitActiveType.AFTER;
private MainUnit thisUnit;
private Builder() {
}
public Builder<M> name(String name) {
this.name = name;
return this;
}
public Builder<M> description(String description) {
this.description = description;
return this;
}
public Builder<M> triggerWords(Set<KeyWord> val) {
if (Checker.checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val);
return this;
}
public Builder<M> triggerWord(KeyWord val) {
if (Checker.checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.add(val);
return this;
}
public Builder<M> triggerStringWords(Set<String> val) {
if (Checker.checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val.stream().map(KeyWord::of).collect(Collectors.toSet()));
return this;
}
public Builder<M> triggerWord(String val) {
if (Checker.checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.add(KeyWord.of(val));
return this;
}
public Builder<M> triggerPhrase(String... val) {
if (Checker.checkNull(triggerPhrases)) {
triggerPhrases = new HashSet<>();
}
if (val.length == 1) {
triggerPhrases.add(val[0]);
} else {
triggerPhrases.addAll(Set.of(val));
}
return this;
}
public Builder<M> triggerPattern(Pattern... val) {
if (Checker.checkNull(triggerPatterns)) {
triggerPatterns = new HashSet<>();
}
if (val.length == 1) {
triggerPatterns.add(val[0]);
} else {
triggerPatterns.addAll(Set.of(val));
}
triggerPatterns.addAll(Set.of(val));
return this;
}
public Builder<M> triggerCheck(Predicate<M> trigger) {
triggerCheck = trigger;
return this;
}
public Builder<M> matchThreshold(Integer val) {
matchThreshold = val;
return this;
}
public Builder<M> priority(Integer val) {
priority = val;
return this;
}
public Builder<M> activeType(UnitActiveType val) {
activeType = val;
return this;
}
public Builder<M> thisUnit(MainUnit val) {
thisUnit = val;
return this;
}
public ReplaceCmd<M> build() {
return new ReplaceCmd<>(this);
}
}
}

View File

@ -1,11 +1,11 @@
package dev.struchkov.godfather.context.domain.unit.cmd;
package dev.struchkov.godfather.simple.core.unit.cmd;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.context.domain.TypeUnit;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.context.domain.unit.UnitActiveType;
import dev.struchkov.godfather.context.exception.UnitConfigException;
import dev.struchkov.godfather.exception.UnitConfigException;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import java.util.HashSet;
import java.util.Set;

View File

@ -0,0 +1,10 @@
package dev.struchkov.godfather.simple.core.unit.func;
import dev.struchkov.godfather.main.domain.content.Message;
@FunctionalInterface
public interface CheckData<C extends Message> {
boolean checked(C content);
}

View File

@ -1,7 +1,7 @@
package dev.struchkov.godfather.context.service.save;
package dev.struchkov.godfather.simple.core.unit.func;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.domain.unit.MainUnit;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
/**
* TODO: Добавить описание интерфейса.

View File

@ -1,4 +1,4 @@
package dev.struchkov.godfather.context.service.usercode;
package dev.struchkov.godfather.simple.core.unit.func;
import java.util.List;

View File

@ -0,0 +1,10 @@
package dev.struchkov.godfather.simple.core.unit.func;
import dev.struchkov.godfather.main.domain.content.Message;
@FunctionalInterface
public interface PreservableData<D, M extends Message> {
D getData(M content);
}

View File

@ -1,7 +1,6 @@
package dev.struchkov.godfather.core.service.save.data;
package dev.struchkov.godfather.simple.core.unit.func;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.service.save.PreservableData;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.haiti.utils.Pair;
/**

View File

@ -1,6 +1,6 @@
package dev.struchkov.godfather.context.service.usercode;
package dev.struchkov.godfather.simple.core.unit.func;
import dev.struchkov.godfather.context.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import java.util.Optional;

View File

@ -1,8 +1,8 @@
package dev.struchkov.godfather.context.utils;
package dev.struchkov.godfather.simple.core.utils;
import dev.struchkov.godfather.context.domain.BoxAnswer;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.service.sender.Sending;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.context.service.Sending;
import static dev.struchkov.haiti.utils.Exceptions.utilityClass;

Some files were not shown because too many files have changed in this diff Show More