Untitled

 avatar
unknown
plain_text
2 months ago
4.5 kB
2
Indexable
package ru.crystals.sco3.business.process.dialogs;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.crystals.sco3.business.entity.menu.RequestInformationFromUser;
import ru.crystals.sco3.business.entity.menu.UserInformationInputCompleted;
import ru.crystals.sco3.business.entity.menu.UserInformationType;
import ru.crystals.sco3.interfaces.process.api.ProcessAPI;
import ru.crystals.sco3.utilities.interfaces.service_executor.ServiceExecutor;

import javax.annotation.PostConstruct;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;

@Slf4j
@Service
@RequiredArgsConstructor
public class DialogManager {

    // нужен чтобы не допустить параллельного выполнения операций processAPI.runProcess(dialogProcess) и processAPI.endProcess(dialogProcess)
    private final Object lock = new Object();
    private final ServiceExecutor executor;
    private final ProcessAPI processAPI;
    private final Deque<DialogDescription> dialogs = new LinkedList<>();
    private final AtomicLong dialogId = new AtomicLong();

    private DialogProcess dialogProcess;
    private DialogDescription currentDialog;

    @PostConstruct
    private void postConstruct() {
        executor.execute(this::showDialogLoop, log, "ShowDialogLoop_Thread");
    }

    private void showDialogLoop() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                synchronized (lock) {
                    DialogDescription dd = null;
                    boolean empty = false;
                    while ((dd = currentDialog) != null || (empty = dialogs.isEmpty())) {
                        log.info("wait, currentDialog {}, dialogs.isEmpty() {}", dd, empty);
                        lock.wait();
                    }
                    DialogDescription dialog = dialogs.pollFirst();
                    log.info("Show dialog with id {}", dialog.request().id());
                    currentDialog = dialog;
                    processAPI.runProcess(null, dialogProcess, dialog);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            Thread.currentThread().interrupt();
        }
    }

    public void closeDialog(String id) {
        synchronized (lock) {
            DialogDescription current = currentDialog;
            if (current == null) {
                return;
            }
            if (current.request().id().equals(id)) {
                log.info("Close current dialog with id {}", id);
                currentDialog = null;
                processAPI.endProcess(dialogProcess, null);
                log.info("notify close current");
                lock.notify();
                return;
            }
            if (dialogs.removeIf(d -> d.request().id().equals(id))) {
                log.info("Close waiting dialog with id {}, removed from dialogs.", id);
                return;
            }
            log.warn("Trying to close not existing dialog, {}", id);
        }
    }

    public void showDialog(RequestInformationFromUser r, Consumer<UserInformationInputCompleted> answerCallback) {
        synchronized (lock) {
            boolean callAttendant = callAttendant(r);
            log.info("Dialog adding to queue, dialogId={}", r.id());
            dialogs.add(new DialogDescription(r, answerCallback, callAttendant));
            log.info("notify show");
            lock.notify();
        }
    }

    private boolean callAttendant(RequestInformationFromUser request) {
        return UserInformationType.REQUEST_AGE_CONFIRMATION == request.type() && Objects.isNull(request.requestAttendant());
    }

    public String getNextDialogId() {
        return String.valueOf(dialogId.getAndIncrement());
    }

    public void setDialogProcess(DialogProcess dialogProcess) {
        this.dialogProcess = dialogProcess;
    }

    public void reset() {
        synchronized (lock) {
            log.info("Reset dialog manager state");
            dialogs.clear();
            currentDialog = null;
            processAPI.endProcess(dialogProcess, null);
            lock.notify();
        }
    }

    public boolean isDialogExist(String dialogId) {
        return dialogs.stream().anyMatch(dd -> dd.request().id().equals(dialogId)) || currentDialog.request().id().equals(dialogId);
    }
}
Leave a Comment