XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEServerManager

【Java】我的世界XFE服务器管理器

公开
关注 0 Fork 0 Star 0
UTF-8
package com.xfestudio.xfeservermanager.core.rollback;

import java.time.Instant;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

/** Persistable execution checkpoint. Cursor points at the next plan item. */
public record RollbackOperation(
        UUID operationId,
        RollbackPlan plan,
        RollbackStatus status,
        int cursor,
        List<UUID> appliedEventIds,
        List<RollbackFailure> failures,
        UUID inFlightEventId,
        Instant updatedAt
) {
    public RollbackOperation(UUID operationId, RollbackPlan plan, RollbackStatus status, int cursor,
                             List<UUID> appliedEventIds, List<RollbackFailure> failures, Instant updatedAt) {
        this(operationId, plan, status, cursor, appliedEventIds, failures, null, updatedAt);
    }

    public RollbackOperation {
        Objects.requireNonNull(operationId, "operationId");
        Objects.requireNonNull(plan, "plan");
        Objects.requireNonNull(status, "status");
        if (cursor < 0 || cursor > plan.items().size()) throw new IllegalArgumentException("cursor out of range");
        appliedEventIds = List.copyOf(appliedEventIds);
        if (new java.util.HashSet<>(appliedEventIds).size() != appliedEventIds.size()) {
            throw new IllegalArgumentException("applied event ids must be unique");
        }
        var planEventIds = plan.items().stream().map(item -> item.entry().change().eventId())
                .collect(java.util.stream.Collectors.toSet());
        if (!planEventIds.containsAll(appliedEventIds)) {
            throw new IllegalArgumentException("applied event ids must belong to the plan");
        }
        failures = List.copyOf(failures);
        if (status == RollbackStatus.PREVIEWED && (cursor != 0 || !appliedEventIds.isEmpty())) {
            throw new IllegalArgumentException("previewed operations cannot contain execution progress");
        }
        if (status == RollbackStatus.COMPLETED && cursor != plan.items().size()) {
            throw new IllegalArgumentException("completed operations must reach the end of the plan");
        }
        if (inFlightEventId != null) {
            if (status != RollbackStatus.RUNNING && status != RollbackStatus.PAUSED) {
                throw new IllegalArgumentException("only active operations can have an in-flight event");
            }
            if (cursor >= plan.items().size()
                    || !plan.items().get(cursor).entry().change().eventId().equals(inFlightEventId)) {
                throw new IllegalArgumentException("in-flight event must identify the item at the cursor");
            }
            if (appliedEventIds.contains(inFlightEventId)) {
                throw new IllegalArgumentException("in-flight event cannot already be applied");
            }
        }
        Objects.requireNonNull(updatedAt, "updatedAt");
    }

    public double progress() {
        return plan.items().isEmpty() ? 1.0 : (double) cursor / plan.items().size();
    }
}