namespace Eis.Infrastructure.Administration; public sealed record AdminMigrationOptions( bool NativeReadsEnabled, bool NativeOrganizationWritesEnabled = false, bool NativeAccountBatchesEnabled = false, bool NativeConfigurationEnabled = false, bool NativeNoticeManagementEnabled = false, bool NativeCentersEnabled = false, bool NativeOperationalReadsEnabled = false, bool NativeCandidateManagementEnabled = false, bool NativeRegistrationPaymentWritesEnabled = false) { public static AdminMigrationOptions FromEnvironment( bool configuredNativeReadsEnabled, bool authenticationNativeEnabled, bool sharesLegacySessions, bool configuredNativeOrganizationWritesEnabled = false, bool configuredNativeAccountBatchesEnabled = false, bool configuredNativeConfigurationEnabled = false, bool configuredNativeNoticeManagementEnabled = false, bool configuredNativeCentersEnabled = false, bool configuredNativeOperationalReadsEnabled = false, bool configuredNativeCandidateManagementEnabled = false, bool configuredNativeRegistrationPaymentWritesEnabled = false) { var readsEnabled = ParseBoolean( Environment.GetEnvironmentVariable("ADMIN_NATIVE_READS_ENABLED"), configuredNativeReadsEnabled); var organizationWritesEnabled = ParseBoolean( Environment.GetEnvironmentVariable("ADMIN_NATIVE_ORGANIZATION_WRITES_ENABLED"), configuredNativeOrganizationWritesEnabled); var accountBatchesEnabled = ParseBoolean( Environment.GetEnvironmentVariable("ADMIN_NATIVE_ACCOUNT_BATCHES_ENABLED"), configuredNativeAccountBatchesEnabled); var configurationEnabled = ParseBoolean( Environment.GetEnvironmentVariable("ADMIN_NATIVE_CONFIGURATION_ENABLED"), configuredNativeConfigurationEnabled); var noticeManagementEnabled = ParseBoolean( Environment.GetEnvironmentVariable("ADMIN_NATIVE_NOTICE_MANAGEMENT_ENABLED") ?? Environment.GetEnvironmentVariable("ADMIN_NATIVE_NOTICE_WRITES_ENABLED"), configuredNativeNoticeManagementEnabled); var centersEnabled = ParseBoolean( Environment.GetEnvironmentVariable("ADMIN_NATIVE_CENTERS_ENABLED"), configuredNativeCentersEnabled); var operationalReadsEnabled = ParseBoolean( Environment.GetEnvironmentVariable("ADMIN_NATIVE_OPERATIONAL_READS_ENABLED"), configuredNativeOperationalReadsEnabled); var candidateManagementEnabled = ParseBoolean( Environment.GetEnvironmentVariable("ADMIN_NATIVE_CANDIDATE_MANAGEMENT_ENABLED"), configuredNativeCandidateManagementEnabled); var registrationPaymentWritesEnabled = ParseBoolean( Environment.GetEnvironmentVariable("ADMIN_NATIVE_REGISTRATION_PAYMENT_WRITES_ENABLED"), configuredNativeRegistrationPaymentWritesEnabled); if ((organizationWritesEnabled || accountBatchesEnabled || configurationEnabled || noticeManagementEnabled || centersEnabled || operationalReadsEnabled || candidateManagementEnabled || registrationPaymentWritesEnabled) && !readsEnabled) { throw new InvalidOperationException( "启用原生组织维护接口前必须同时设置 ADMIN_NATIVE_READS_ENABLED=true"); } if ((candidateManagementEnabled || registrationPaymentWritesEnabled) && !operationalReadsEnabled) { throw new InvalidOperationException( "启用原生考生、报名或缴费写接口前必须同时设置 ADMIN_NATIVE_OPERATIONAL_READS_ENABLED=true"); } var anyNativeAdminEndpointEnabled = readsEnabled || organizationWritesEnabled || accountBatchesEnabled || configurationEnabled || noticeManagementEnabled || centersEnabled || operationalReadsEnabled || candidateManagementEnabled || registrationPaymentWritesEnabled; if (anyNativeAdminEndpointEnabled && !authenticationNativeEnabled) { throw new InvalidOperationException( "启用原生管理端接口前必须同时设置 AUTH_NATIVE_ENABLED=true"); } var allowMemoryForIsolatedTesting = ParseBoolean( Environment.GetEnvironmentVariable("ADMIN_NATIVE_ALLOW_MEMORY"), fallback: false); if (anyNativeAdminEndpointEnabled && !sharesLegacySessions && !allowMemoryForIsolatedTesting) { throw new InvalidOperationException( "管理端仍有接口需要转发给 Node;启用原生管理端接口必须配置共享 Redis 会话"); } return new AdminMigrationOptions(readsEnabled, organizationWritesEnabled, accountBatchesEnabled, configurationEnabled, noticeManagementEnabled, centersEnabled, operationalReadsEnabled, candidateManagementEnabled, registrationPaymentWritesEnabled); } private static bool ParseBoolean(string? value, bool fallback) => value?.Trim().ToLowerInvariant() switch { "1" or "true" or "yes" or "on" => true, "0" or "false" or "no" or "off" => false, _ => fallback }; }