56 lines
3.4 KiB
Java
56 lines
3.4 KiB
Java
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-20260910-source-recovery-v1";
|
|
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); }
|
|
}
|
|
}
|