fix(shadow): respect queue phases and compress input evidence

This commit is contained in:
zgw
2026-09-08 11:23:50 +08:00
parent 414b3bf4a9
commit af8b5f1830
40 changed files with 1035 additions and 46 deletions

View File

@@ -0,0 +1,55 @@
package com.ruoyi.shadow.startup;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.shadow.config.ShadowProperties;
import com.ruoyi.shadow.kernel.ShadowDispatchSnapshotAssembler;
import com.ruoyi.shadow.evidence.ShadowInputPayloadCodec;
import org.springframework.core.env.Environment;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
/** Identifies this source revision and the nonsecret dispatch/storage settings, not a built artifact. */
public final class ShadowRuntimeIdentity {
public static final String BUILD_ID = "ft546-shadow-20260908-phase-storage-v2";
private ShadowRuntimeIdentity() { }
public static Map<String, Object> describe(ShadowProperties properties, Environment env) {
Map<String, Object> settings = new TreeMap<String, Object>();
settings.put("enabled", properties.isEnabled());
settings.put("cycleDeadlineMillis", env.getProperty("shadow.cycle.deadline-ms", Long.class, 10000L));
settings.put("pollDelayMillis", env.getProperty("shadow.poll.fixed-delay-ms", Long.class, 5000L));
settings.put("initialDelayMillis", env.getProperty("shadow.poll.initial-delay-ms", Long.class, 5000L));
settings.put("maximumDatabaseBytes", properties.getEvidence().getMaximumDatabaseBytes());
settings.put("maximumBatchPayloadBytes", properties.getEvidence().getMaximumBatchPayloadBytes());
settings.put("minimumFreeBytes", properties.getEvidence().getMinimumFreeBytes());
settings.put("statusAddress", env.getProperty("server.address", "127.0.0.1"));
settings.put("statusPort", env.getProperty("server.port", Integer.class, 18091));
settings.put("safeWaitSites", ShadowDispatchSnapshotAssembler.safeSites(properties.getTraffic().getSafeWaitSites()));
settings.put("safeYieldSites", ShadowDispatchSnapshotAssembler.safeSites(properties.getTraffic().getSafeYieldSites()));
settings.put("inputStorageFormat", ShadowInputPayloadCodec.GZIP);
Map<String, Object> result = new TreeMap<String, Object>();
result.put("buildId", BUILD_ID);
result.put("effectiveSettings", Collections.unmodifiableMap(settings));
result.put("effectiveSettingsSha256", digest(settings));
result.put("identityScope", "SOURCE_BUILD_LABEL_AND_NONSECRET_DISPATCH_STORAGE_SETTINGS");
result.put("operatorArtifactSha256", properties.getEvidence().getRun().getArtifactSha256());
result.put("operatorConfigurationSha256", properties.getEvidence().getRun().getConfigurationSha256());
result.put("safePointConfiguration", properties.getTraffic().getSafeWaitSites().isEmpty()
&& properties.getTraffic().getSafeYieldSites().isEmpty() ? "UNCONFIGURED" : "CONFIGURED_REQUIRES_TOPOLOGY_VALIDATION");
return Collections.unmodifiableMap(result);
}
private static String digest(Map<String, Object> settings) {
try {
byte[] bytes = new ObjectMapper().writeValueAsString(settings).getBytes(StandardCharsets.UTF_8);
StringBuilder result = new StringBuilder();
for (byte b : MessageDigest.getInstance("SHA-256").digest(bytes))
result.append(String.format(Locale.ROOT, "%02x", b & 255));
return result.toString();
} catch (Exception impossible) { throw new IllegalStateException("RUNTIME_IDENTITY_FAILED", impossible); }
}
}