#include "wallet/lite_backend_artifact_resolver.h" #include #include #include #include #include #include namespace dragonx::wallet { namespace { namespace fs = std::filesystem; struct CandidateInspectionResult { bool ok = false; LiteBackendArtifactResolverStatus status = LiteBackendArtifactResolverStatus::WaitingForArtifactCandidate; LiteBackendArtifactResolverIssue issue = LiteBackendArtifactResolverIssue::ArtifactMissing; std::string message; LiteBackendResolvedArtifact artifact; LiteWalletSdxlArtifactInput syncArtifactInput; }; void addIssue(LiteBackendArtifactResolverResult& result, LiteBackendArtifactResolverIssue issue, std::string message) { result.issues.push_back(LiteBackendArtifactResolverIssueInfo{issue, std::move(message)}); } void addIssue(LiteBackendActivationReadinessResult& result, LiteBackendActivationReadinessIssue issue, std::string message) { result.issues.push_back(LiteBackendActivationReadinessIssueInfo{issue, std::move(message)}); } LiteBackendArtifactResolverResult stoppedResolverResult( LiteBackendArtifactResolverResult result, LiteBackendArtifactResolverStatus status, LiteBackendArtifactResolverIssue issue, std::string message) { result.status = status; addIssue(result, issue, std::move(message)); result.error = result.issues.back().message; return result; } LiteBackendActivationReadinessResult stoppedActivationResult( LiteBackendActivationReadinessResult result, LiteBackendActivationReadinessStatus status, LiteBackendActivationReadinessIssue issue, std::string message, WalletBackendState backendState = WalletBackendState::Unavailable) { result.status = status; addIssue(result, issue, std::move(message)); result.error = result.issues.back().message; result.connectionStatus = WalletBackendStatus{backendState, result.error, {}, {}, 0.0}; return result; } std::string lowerCopy(const std::string& value) { std::string lowered; lowered.reserve(value.size()); for (const unsigned char character : value) { lowered.push_back(static_cast(std::tolower(character))); } return lowered; } std::string trimCopy(const std::string& value) { auto begin = value.begin(); while (begin != value.end() && std::isspace(static_cast(*begin))) ++begin; auto end = value.end(); while (end != begin && std::isspace(static_cast(*(end - 1)))) --end; return std::string(begin, end); } std::string baseNameLower(const std::string& path) { const auto slash = path.find_last_of("/\\"); const std::string name = slash == std::string::npos ? path : path.substr(slash + 1); return lowerCopy(name); } bool endsWith(const std::string& value, const char* suffix) { const std::string suffixValue(suffix); return value.size() >= suffixValue.size() && value.compare(value.size() - suffixValue.size(), suffixValue.size(), suffixValue) == 0; } LiteBackendArtifactPlatform normalizePlatform(LiteBackendArtifactPlatform platform) { return platform == LiteBackendArtifactPlatform::Current ? currentLiteBackendArtifactPlatform() : platform; } LiteBackendArtifactKind inferArtifactKind(const std::string& path) { const std::string name = baseNameLower(path); if (endsWith(name, ".a") || endsWith(name, ".lib")) return LiteBackendArtifactKind::StaticLibrary; if (endsWith(name, ".so") || endsWith(name, ".dll") || endsWith(name, ".dylib")) { return LiteBackendArtifactKind::SharedLibrary; } if (endsWith(name, ".exe") || name == "silentdragonxlite" || name == "silentdragonx-lite") { return LiteBackendArtifactKind::Executable; } return LiteBackendArtifactKind::Unknown; } bool artifactKindSupported(LiteBackendArtifactKind kind) { return kind == LiteBackendArtifactKind::StaticLibrary || kind == LiteBackendArtifactKind::SharedLibrary || kind == LiteBackendArtifactKind::Executable; } std::vector defaultArtifactNames(LiteBackendArtifactPlatform platform, LiteBackendArtifactKind kind) { const auto normalizedPlatform = normalizePlatform(platform); std::vector names; const auto addNamesForKind = [&](LiteBackendArtifactKind artifactKind) { switch (normalizedPlatform) { case LiteBackendArtifactPlatform::Windows: if (artifactKind == LiteBackendArtifactKind::StaticLibrary) { names.push_back("silentdragonxlite.lib"); names.push_back("libsilentdragonxlite.a"); } else if (artifactKind == LiteBackendArtifactKind::SharedLibrary) { names.push_back("silentdragonxlite.dll"); } else if (artifactKind == LiteBackendArtifactKind::Executable) { names.push_back("silentdragonxlite.exe"); names.push_back("silentdragonx-lite.exe"); } break; case LiteBackendArtifactPlatform::MacOS: if (artifactKind == LiteBackendArtifactKind::StaticLibrary) { names.push_back("libsilentdragonxlite.a"); names.push_back("silentdragonxlite.a"); } else if (artifactKind == LiteBackendArtifactKind::SharedLibrary) { names.push_back("libsilentdragonxlite.dylib"); names.push_back("silentdragonxlite.dylib"); } else if (artifactKind == LiteBackendArtifactKind::Executable) { names.push_back("silentdragonxlite"); names.push_back("silentdragonx-lite"); } break; case LiteBackendArtifactPlatform::Linux: case LiteBackendArtifactPlatform::Current: case LiteBackendArtifactPlatform::Unknown: if (artifactKind == LiteBackendArtifactKind::StaticLibrary) { names.push_back("silentdragonxlite.a"); names.push_back("libsilentdragonxlite.a"); } else if (artifactKind == LiteBackendArtifactKind::SharedLibrary) { names.push_back("libsilentdragonxlite.so"); names.push_back("silentdragonxlite.so"); } else if (artifactKind == LiteBackendArtifactKind::Executable) { names.push_back("silentdragonxlite"); names.push_back("silentdragonx-lite"); } break; } }; if (kind == LiteBackendArtifactKind::Unknown) { addNamesForKind(LiteBackendArtifactKind::StaticLibrary); addNamesForKind(LiteBackendArtifactKind::SharedLibrary); addNamesForKind(LiteBackendArtifactKind::Executable); } else { addNamesForKind(kind); } return names; } fs::path resolvePath(const std::string& projectRoot, const std::string& path) { const fs::path value(path); if (value.is_absolute()) return value; const fs::path root = projectRoot.empty() ? fs::path(".") : fs::path(projectRoot); return root / value; } std::vector expandSearchRoots( const LiteBackendArtifactResolverInput& input, LiteBackendArtifactResolverResult& result, LiteBackendArtifactResolverOptions options) { std::vector candidates; result.searchRootCount = input.searchRoots.size(); for (const auto& root : input.searchRoots) { if (options.requireArtifactCandidates && !root.configured) { result = stoppedResolverResult( std::move(result), LiteBackendArtifactResolverStatus::WaitingForArtifactSearchRoot, LiteBackendArtifactResolverIssue::ArtifactSearchRootNotConfigured, "lite backend artifact search root is not configured"); return {}; } if (trimCopy(root.rootPath).empty()) { result = stoppedResolverResult( std::move(result), LiteBackendArtifactResolverStatus::WaitingForArtifactSearchRoot, LiteBackendArtifactResolverIssue::ArtifactSearchRootMissing, "lite backend artifact search root path is missing"); return {}; } const fs::path rootPath = resolvePath(input.projectRoot, root.rootPath); std::error_code error; if (!fs::exists(rootPath, error) || error) { result = stoppedResolverResult( std::move(result), LiteBackendArtifactResolverStatus::WaitingForArtifactSearchRoot, LiteBackendArtifactResolverIssue::ArtifactSearchRootMissing, "lite backend artifact search root does not exist"); return {}; } if (!fs::is_directory(rootPath, error) || error) { result = stoppedResolverResult( std::move(result), LiteBackendArtifactResolverStatus::WaitingForArtifactSearchRoot, LiteBackendArtifactResolverIssue::ArtifactSearchRootNotDirectory, "lite backend artifact search root is not a directory"); return {}; } const auto names = root.expectedArtifactNames.empty() ? defaultArtifactNames(root.platform, root.kind) : root.expectedArtifactNames; for (const auto& artifactName : names) { LiteBackendArtifactCandidate candidate; candidate.configured = true; candidate.artifactPath = (rootPath / artifactName).string(); candidate.platform = root.platform; candidate.kind = root.kind; candidate.versionLabel = root.versionLabel; candidate.provenance = root.provenance; candidate.signatureVerification = root.signatureVerification; candidate.sdxlCompatible = root.sdxlCompatible; candidate.symbols = root.symbols; candidate.executableMetadataRequired = root.executableMetadataRequired; candidates.push_back(std::move(candidate)); } } result.artifactSearchRootsAccepted = true; return candidates; } bool coreSymbolsReady(const LiteWalletSdxlArtifactSymbolsInput& symbols) { return symbols.walletExists && symbols.initializeNew && symbols.initializeNewFromPhrase && symbols.initializeExisting && symbols.execute && symbols.checkServerOnline; } bool fileReadable(const fs::path& path) { std::ifstream input(path, std::ios::binary); return input.good(); } bool fileExecutable(const fs::path& path, LiteBackendArtifactPlatform platform) { const std::string name = baseNameLower(path.string()); if (normalizePlatform(platform) == LiteBackendArtifactPlatform::Windows && endsWith(name, ".exe")) return true; std::error_code error; const auto permissions = fs::status(path, error).permissions(); if (error) return false; return (permissions & fs::perms::owner_exec) != fs::perms::none || (permissions & fs::perms::group_exec) != fs::perms::none || (permissions & fs::perms::others_exec) != fs::perms::none; } bool provenanceComplete(const LiteBackendArtifactProvenanceMetadata& provenance) { return provenance.metadataProvided && !trimCopy(provenance.source).empty() && !trimCopy(provenance.builder).empty() && !trimCopy(provenance.sourceRevision).empty() && !trimCopy(provenance.artifactSetId).empty(); } CandidateInspectionResult inspectCandidate(const LiteBackendArtifactResolverInput& input, const LiteBackendArtifactCandidate& candidate, LiteBackendArtifactResolverOptions options) { CandidateInspectionResult inspection; if (options.requireArtifactCandidates && !candidate.configured) { inspection.issue = LiteBackendArtifactResolverIssue::ArtifactCandidateNotConfigured; inspection.message = "lite backend artifact candidate is not configured"; return inspection; } if (trimCopy(candidate.artifactPath).empty()) { inspection.issue = LiteBackendArtifactResolverIssue::ArtifactPathMissing; inspection.message = "lite backend artifact candidate path is missing"; return inspection; } const fs::path artifactPath = resolvePath(input.projectRoot, candidate.artifactPath); std::error_code error; if (!fs::exists(artifactPath, error) || error) { inspection.issue = LiteBackendArtifactResolverIssue::ArtifactMissing; inspection.message = "lite backend artifact candidate does not exist"; return inspection; } if (!fs::is_regular_file(artifactPath, error) || error) { inspection.issue = LiteBackendArtifactResolverIssue::ArtifactNotRegularFile; inspection.message = "lite backend artifact candidate is not a regular file"; return inspection; } if (!fileReadable(artifactPath)) { inspection.issue = LiteBackendArtifactResolverIssue::ArtifactUnreadable; inspection.message = "lite backend artifact candidate is not readable"; return inspection; } const auto candidatePlatform = normalizePlatform(candidate.platform); const auto expectedPlatform = normalizePlatform(input.expectedPlatform); if (candidatePlatform == LiteBackendArtifactPlatform::Unknown || candidatePlatform != expectedPlatform) { inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata; inspection.issue = LiteBackendArtifactResolverIssue::PlatformMismatch; inspection.message = "lite backend artifact platform metadata does not match the expected platform"; return inspection; } const auto kind = candidate.kind == LiteBackendArtifactKind::Unknown ? inferArtifactKind(candidate.artifactPath) : candidate.kind; if (!artifactKindSupported(kind)) { inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata; inspection.issue = LiteBackendArtifactResolverIssue::UnsupportedArtifactKind; inspection.message = "lite backend artifact kind is unsupported or unknown"; return inspection; } if (options.requireVersionMetadata && trimCopy(candidate.versionLabel).empty()) { inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata; inspection.issue = LiteBackendArtifactResolverIssue::VersionMissing; inspection.message = "lite backend artifact version metadata is missing"; return inspection; } if (options.requireProvenanceMetadata) { if (!candidate.provenance.ownerReady) { inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata; inspection.issue = LiteBackendArtifactResolverIssue::ProvenanceOwnerMissing; inspection.message = "lite backend artifact provenance owner is not ready"; return inspection; } if (!provenanceComplete(candidate.provenance)) { inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata; inspection.issue = LiteBackendArtifactResolverIssue::ProvenanceMetadataMissing; inspection.message = "lite backend artifact provenance metadata is incomplete"; return inspection; } } if (options.requireSdxlCompatibility && !candidate.sdxlCompatible) { inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata; inspection.issue = LiteBackendArtifactResolverIssue::ArtifactNotSdxlCompatible; inspection.message = "lite backend artifact is not marked SDXL-compatible"; return inspection; } if (options.requireSdxlSymbols) { if (!coreSymbolsReady(candidate.symbols)) { inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata; inspection.issue = LiteBackendArtifactResolverIssue::ArtifactSymbolsMissing; inspection.message = "lite backend artifact is missing required SDXL bridge symbol metadata"; return inspection; } if (!candidate.symbols.freeString) { inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata; inspection.issue = LiteBackendArtifactResolverIssue::ArtifactStringOwnershipUnverified; inspection.message = "lite backend artifact string cleanup symbol metadata is missing"; return inspection; } if (!candidate.symbols.shutdown) { inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata; inspection.issue = LiteBackendArtifactResolverIssue::ArtifactShutdownUnavailable; inspection.message = "lite backend artifact shutdown symbol metadata is missing"; return inspection; } } const bool executable = fileExecutable(artifactPath, candidatePlatform); if ((kind == LiteBackendArtifactKind::Executable || candidate.executableMetadataRequired) && !executable) { inspection.status = LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata; inspection.issue = LiteBackendArtifactResolverIssue::ExecutableMetadataMissing; inspection.message = "lite backend executable artifact is not marked executable"; return inspection; } std::size_t artifactSizeBytes = 0; const auto fileSize = fs::file_size(artifactPath, error); if (!error) artifactSizeBytes = static_cast(fileSize); inspection.ok = true; inspection.artifact.found = true; inspection.artifact.artifactPath = artifactPath.string(); inspection.artifact.platform = candidatePlatform; inspection.artifact.kind = kind; inspection.artifact.versionLabel = candidate.versionLabel; inspection.artifact.provenance = candidate.provenance; inspection.artifact.signatureVerification = candidate.signatureVerification; inspection.artifact.exists = true; inspection.artifact.regularFile = true; inspection.artifact.readable = true; inspection.artifact.executable = executable; inspection.artifact.sdxlCompatible = candidate.sdxlCompatible; inspection.artifact.symbols = candidate.symbols; inspection.artifact.artifactSizeBytes = artifactSizeBytes; inspection.syncArtifactInput.pathConfigured = true; inspection.syncArtifactInput.exists = true; inspection.syncArtifactInput.readable = true; inspection.syncArtifactInput.sdxlCompatible = candidate.sdxlCompatible; inspection.syncArtifactInput.artifactPath = artifactPath.string(); inspection.syncArtifactInput.versionLabel = candidate.versionLabel; inspection.syncArtifactInput.symbols = candidate.symbols; return inspection; } LiteBackendArtifactResolverResult rejectResolverRuntimeAction( LiteBackendArtifactResolverResult result, const LiteBackendArtifactResolverInput& input, LiteBackendArtifactResolverOptions options) { if (options.rejectArtifactMutation && input.artifactMutationRequested) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled, LiteBackendArtifactResolverIssue::ArtifactMutationRequested, "lite backend artifact mutation is disabled for artifact resolution"); } if (options.rejectSdxlApiCalls && input.sdxlApiRequested) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled, LiteBackendArtifactResolverIssue::SdxlApiRequested, "SDXL API calls are disabled for artifact resolution"); } if (options.rejectServerConnectivityChecks && input.serverConnectivityCheckRequested) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled, LiteBackendArtifactResolverIssue::ServerConnectivityCheckRequested, "server connectivity checks are disabled for artifact resolution"); } if (options.rejectWalletLifecycle && input.walletLifecycleRequested) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled, LiteBackendArtifactResolverIssue::WalletLifecycleRequested, "wallet lifecycle execution is disabled for artifact resolution"); } if (options.rejectSync && input.syncRequested) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled, LiteBackendArtifactResolverIssue::SyncRequested, "lite sync execution is disabled for artifact resolution"); } if (options.rejectSyncStatusPolling && input.syncStatusPollingRequested) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled, LiteBackendArtifactResolverIssue::SyncStatusPollingRequested, "lite syncstatus polling is disabled for artifact resolution"); } if (options.rejectWorkerQueue && input.workerQueueRequested) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled, LiteBackendArtifactResolverIssue::WorkerQueueRequested, "worker queue enqueue is disabled for artifact resolution"); } if (options.rejectWalletStateMutation && input.walletStateMutationRequested) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled, LiteBackendArtifactResolverIssue::WalletStateMutationRequested, "WalletState mutation is disabled for artifact resolution"); } if (options.rejectWalletPersistence && input.walletPersistenceRequested) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled, LiteBackendArtifactResolverIssue::WalletPersistenceRequested, "wallet persistence is disabled for artifact resolution"); } if (options.rejectUpload && input.uploadRequested) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled, LiteBackendArtifactResolverIssue::UploadRequested, "upload is disabled for artifact resolution"); } if (options.rejectSigning && input.signingRequested) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled, LiteBackendArtifactResolverIssue::SigningRequested, "signing is disabled for artifact resolution"); } if (options.rejectPublication && input.publicationRequested) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::RuntimeActionDisabled, LiteBackendArtifactResolverIssue::PublicationRequested, "publication is disabled for artifact resolution"); } return result; } LiteBackendActivationReadinessResult rejectActivationRuntimeAction( LiteBackendActivationReadinessResult result, const LiteBackendActivationReadinessInput& input, LiteBackendActivationReadinessOptions options) { if (options.rejectArtifactMutation && input.artifactMutationRequested) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled, LiteBackendActivationReadinessIssue::ArtifactMutationRequested, "lite backend artifact mutation is disabled for activation readiness"); } if (options.rejectSdxlApiCalls && input.sdxlApiRequested) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled, LiteBackendActivationReadinessIssue::SdxlApiRequested, "SDXL API calls are disabled for activation readiness"); } if (options.rejectServerConnectivityChecks && input.serverConnectivityCheckRequested) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled, LiteBackendActivationReadinessIssue::ServerConnectivityCheckRequested, "server connectivity checks are disabled for activation readiness"); } if (options.rejectWalletLifecycle && input.walletLifecycleRequested) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled, LiteBackendActivationReadinessIssue::WalletLifecycleRequested, "wallet lifecycle execution is disabled for activation readiness"); } if (options.rejectSync && input.syncRequested) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled, LiteBackendActivationReadinessIssue::SyncRequested, "lite sync execution is disabled for activation readiness"); } if (options.rejectSyncStatusPolling && input.syncStatusPollingRequested) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled, LiteBackendActivationReadinessIssue::SyncStatusPollingRequested, "lite syncstatus polling is disabled for activation readiness"); } if (options.rejectWorkerQueue && input.workerQueueRequested) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled, LiteBackendActivationReadinessIssue::WorkerQueueRequested, "worker queue enqueue is disabled for activation readiness"); } if (options.rejectWalletStateMutation && input.walletStateMutationRequested) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled, LiteBackendActivationReadinessIssue::WalletStateMutationRequested, "WalletState mutation is disabled for activation readiness"); } if (options.rejectWalletPersistence && input.walletPersistenceRequested) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled, LiteBackendActivationReadinessIssue::WalletPersistenceRequested, "wallet persistence is disabled for activation readiness"); } if (options.rejectUpload && input.uploadRequested) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled, LiteBackendActivationReadinessIssue::UploadRequested, "upload is disabled for activation readiness"); } if (options.rejectSigning && input.signingRequested) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled, LiteBackendActivationReadinessIssue::SigningRequested, "signing is disabled for activation readiness"); } if (options.rejectPublication && input.publicationRequested) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::RuntimeActionDisabled, LiteBackendActivationReadinessIssue::PublicationRequested, "publication is disabled for activation readiness"); } return result; } WalletBackendStatus backendStatusOrDefault(const LiteBackendBridgeReadinessInput& backend, const std::string& fallback) { if (!backend.status.message.empty()) return backend.status; return WalletBackendStatus{WalletBackendState::Unavailable, fallback, {}, {}, 0.0}; } WalletBackendStatus readyConnectionStatus(const LiteServerSelectionResult& selectedServer) { const std::string serverLabel = selectedServer.server.label.empty() ? selectedServer.server.url : selectedServer.server.label; return WalletBackendStatus{ WalletBackendState::Disconnected, "lite backend activation readiness accepted for " + serverLabel + "; bridge calls remain disabled here", {}, {}, 0.0 }; } } // namespace LiteBackendArtifactPlatform currentLiteBackendArtifactPlatform() { #if defined(_WIN32) return LiteBackendArtifactPlatform::Windows; #elif defined(__APPLE__) return LiteBackendArtifactPlatform::MacOS; #else return LiteBackendArtifactPlatform::Linux; #endif } const char* liteBackendArtifactPlatformName(LiteBackendArtifactPlatform platform) { switch (platform) { case LiteBackendArtifactPlatform::Current: return "Current"; case LiteBackendArtifactPlatform::Linux: return "Linux"; case LiteBackendArtifactPlatform::Windows: return "Windows"; case LiteBackendArtifactPlatform::MacOS: return "MacOS"; case LiteBackendArtifactPlatform::Unknown: return "Unknown"; } return "Unknown"; } const char* liteBackendArtifactKindName(LiteBackendArtifactKind kind) { switch (kind) { case LiteBackendArtifactKind::Unknown: return "Unknown"; case LiteBackendArtifactKind::StaticLibrary: return "StaticLibrary"; case LiteBackendArtifactKind::SharedLibrary: return "SharedLibrary"; case LiteBackendArtifactKind::Executable: return "Executable"; } return "Unknown"; } const char* liteBackendArtifactResolverStatusName(LiteBackendArtifactResolverStatus status) { switch (status) { case LiteBackendArtifactResolverStatus::ReadyForActivationReadiness: return "ReadyForActivationReadiness"; case LiteBackendArtifactResolverStatus::WaitingForResolverOwner: return "WaitingForResolverOwner"; case LiteBackendArtifactResolverStatus::WaitingForReadOnlyGate: return "WaitingForReadOnlyGate"; case LiteBackendArtifactResolverStatus::WaitingForArtifactSearchRoot: return "WaitingForArtifactSearchRoot"; case LiteBackendArtifactResolverStatus::WaitingForArtifactCandidate: return "WaitingForArtifactCandidate"; case LiteBackendArtifactResolverStatus::WaitingForArtifactMetadata: return "WaitingForArtifactMetadata"; case LiteBackendArtifactResolverStatus::RuntimeActionDisabled: return "RuntimeActionDisabled"; } return "Unknown"; } const char* liteBackendArtifactResolverIssueName(LiteBackendArtifactResolverIssue issue) { switch (issue) { case LiteBackendArtifactResolverIssue::ResolverOwnerMissing: return "ResolverOwnerMissing"; case LiteBackendArtifactResolverIssue::ReadOnlyGateMissing: return "ReadOnlyGateMissing"; case LiteBackendArtifactResolverIssue::ArtifactSearchRootMissing: return "ArtifactSearchRootMissing"; case LiteBackendArtifactResolverIssue::ArtifactSearchRootNotConfigured: return "ArtifactSearchRootNotConfigured"; case LiteBackendArtifactResolverIssue::ArtifactSearchRootNotDirectory: return "ArtifactSearchRootNotDirectory"; case LiteBackendArtifactResolverIssue::ArtifactCandidateMissing: return "ArtifactCandidateMissing"; case LiteBackendArtifactResolverIssue::ArtifactCandidateNotConfigured: return "ArtifactCandidateNotConfigured"; case LiteBackendArtifactResolverIssue::ArtifactPathMissing: return "ArtifactPathMissing"; case LiteBackendArtifactResolverIssue::ArtifactMissing: return "ArtifactMissing"; case LiteBackendArtifactResolverIssue::ArtifactNotRegularFile: return "ArtifactNotRegularFile"; case LiteBackendArtifactResolverIssue::ArtifactUnreadable: return "ArtifactUnreadable"; case LiteBackendArtifactResolverIssue::UnsupportedArtifactKind: return "UnsupportedArtifactKind"; case LiteBackendArtifactResolverIssue::PlatformMismatch: return "PlatformMismatch"; case LiteBackendArtifactResolverIssue::VersionMissing: return "VersionMissing"; case LiteBackendArtifactResolverIssue::ProvenanceOwnerMissing: return "ProvenanceOwnerMissing"; case LiteBackendArtifactResolverIssue::ProvenanceMetadataMissing: return "ProvenanceMetadataMissing"; case LiteBackendArtifactResolverIssue::ArtifactNotSdxlCompatible: return "ArtifactNotSdxlCompatible"; case LiteBackendArtifactResolverIssue::ArtifactSymbolsMissing: return "ArtifactSymbolsMissing"; case LiteBackendArtifactResolverIssue::ArtifactStringOwnershipUnverified: return "ArtifactStringOwnershipUnverified"; case LiteBackendArtifactResolverIssue::ArtifactShutdownUnavailable: return "ArtifactShutdownUnavailable"; case LiteBackendArtifactResolverIssue::ExecutableMetadataMissing: return "ExecutableMetadataMissing"; case LiteBackendArtifactResolverIssue::ArtifactMutationRequested: return "ArtifactMutationRequested"; case LiteBackendArtifactResolverIssue::SdxlApiRequested: return "SdxlApiRequested"; case LiteBackendArtifactResolverIssue::ServerConnectivityCheckRequested: return "ServerConnectivityCheckRequested"; case LiteBackendArtifactResolverIssue::WalletLifecycleRequested: return "WalletLifecycleRequested"; case LiteBackendArtifactResolverIssue::SyncRequested: return "SyncRequested"; case LiteBackendArtifactResolverIssue::SyncStatusPollingRequested: return "SyncStatusPollingRequested"; case LiteBackendArtifactResolverIssue::WorkerQueueRequested: return "WorkerQueueRequested"; case LiteBackendArtifactResolverIssue::WalletStateMutationRequested: return "WalletStateMutationRequested"; case LiteBackendArtifactResolverIssue::WalletPersistenceRequested: return "WalletPersistenceRequested"; case LiteBackendArtifactResolverIssue::UploadRequested: return "UploadRequested"; case LiteBackendArtifactResolverIssue::SigningRequested: return "SigningRequested"; case LiteBackendArtifactResolverIssue::PublicationRequested: return "PublicationRequested"; } return "Unknown"; } const char* liteBackendActivationReadinessStatusName(LiteBackendActivationReadinessStatus status) { switch (status) { case LiteBackendActivationReadinessStatus::ReadyForConnectionReadiness: return "ReadyForConnectionReadiness"; case LiteBackendActivationReadinessStatus::WaitingForActivationOwner: return "WaitingForActivationOwner"; case LiteBackendActivationReadinessStatus::WaitingForReadOnlyGate: return "WaitingForReadOnlyGate"; case LiteBackendActivationReadinessStatus::WaitingForLiteBuild: return "WaitingForLiteBuild"; case LiteBackendActivationReadinessStatus::WaitingForBackendCapability: return "WaitingForBackendCapability"; case LiteBackendActivationReadinessStatus::WaitingForArtifactResolver: return "WaitingForArtifactResolver"; case LiteBackendActivationReadinessStatus::WaitingForBackendLink: return "WaitingForBackendLink"; case LiteBackendActivationReadinessStatus::WaitingForBridge: return "WaitingForBridge"; case LiteBackendActivationReadinessStatus::WaitingForConnectionSettings: return "WaitingForConnectionSettings"; case LiteBackendActivationReadinessStatus::RuntimeActionDisabled: return "RuntimeActionDisabled"; } return "Unknown"; } const char* liteBackendActivationReadinessIssueName(LiteBackendActivationReadinessIssue issue) { switch (issue) { case LiteBackendActivationReadinessIssue::ActivationOwnerMissing: return "ActivationOwnerMissing"; case LiteBackendActivationReadinessIssue::ReadOnlyGateMissing: return "ReadOnlyGateMissing"; case LiteBackendActivationReadinessIssue::FullNodeBuild: return "FullNodeBuild"; case LiteBackendActivationReadinessIssue::LiteBackendCapabilityMissing: return "LiteBackendCapabilityMissing"; case LiteBackendActivationReadinessIssue::ArtifactResolverRejected: return "ArtifactResolverRejected"; case LiteBackendActivationReadinessIssue::BackendNotLinked: return "BackendNotLinked"; case LiteBackendActivationReadinessIssue::BridgeUnavailable: return "BridgeUnavailable"; case LiteBackendActivationReadinessIssue::ConnectionSettingsRejected: return "ConnectionSettingsRejected"; case LiteBackendActivationReadinessIssue::ArtifactMutationRequested: return "ArtifactMutationRequested"; case LiteBackendActivationReadinessIssue::SdxlApiRequested: return "SdxlApiRequested"; case LiteBackendActivationReadinessIssue::ServerConnectivityCheckRequested: return "ServerConnectivityCheckRequested"; case LiteBackendActivationReadinessIssue::WalletLifecycleRequested: return "WalletLifecycleRequested"; case LiteBackendActivationReadinessIssue::SyncRequested: return "SyncRequested"; case LiteBackendActivationReadinessIssue::SyncStatusPollingRequested: return "SyncStatusPollingRequested"; case LiteBackendActivationReadinessIssue::WorkerQueueRequested: return "WorkerQueueRequested"; case LiteBackendActivationReadinessIssue::WalletStateMutationRequested: return "WalletStateMutationRequested"; case LiteBackendActivationReadinessIssue::WalletPersistenceRequested: return "WalletPersistenceRequested"; case LiteBackendActivationReadinessIssue::UploadRequested: return "UploadRequested"; case LiteBackendActivationReadinessIssue::SigningRequested: return "SigningRequested"; case LiteBackendActivationReadinessIssue::PublicationRequested: return "PublicationRequested"; } return "Unknown"; } LiteBackendArtifactResolverResult evaluateLiteBackendArtifactResolver( const LiteBackendArtifactResolverInput& input, LiteBackendArtifactResolverOptions options) { LiteBackendArtifactResolverResult result; result = rejectResolverRuntimeAction(std::move(result), input, options); if (!result.issues.empty()) return result; if (options.requireResolverOwner && !input.resolverOwnerReady) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::WaitingForResolverOwner, LiteBackendArtifactResolverIssue::ResolverOwnerMissing, "lite backend artifact resolver owner is not ready"); } result.resolverOwnerAccepted = true; if (options.requireReadOnlyGate && !input.readOnlyGateReady) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::WaitingForReadOnlyGate, LiteBackendArtifactResolverIssue::ReadOnlyGateMissing, "lite backend artifact resolver read-only gate is not ready"); } result.readOnlyGateAccepted = true; auto candidates = expandSearchRoots(input, result, options); if (!result.issues.empty()) return result; for (const auto& candidate : input.candidates) candidates.push_back(candidate); result.candidateCount = candidates.size(); if (options.requireArtifactCandidates && candidates.empty()) { return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::WaitingForArtifactCandidate, LiteBackendArtifactResolverIssue::ArtifactCandidateMissing, "lite backend artifact resolver has no configured candidates"); } result.artifactCandidatesAccepted = true; CandidateInspectionResult firstRejected; bool haveRejectedCandidate = false; for (const auto& candidate : candidates) { ++result.checkedCandidateCount; auto inspection = inspectCandidate(input, candidate, options); if (!inspection.ok) { ++result.rejectedCandidateCount; if (!haveRejectedCandidate) { firstRejected = std::move(inspection); haveRejectedCandidate = true; } continue; } result.ok = true; result.status = LiteBackendArtifactResolverStatus::ReadyForActivationReadiness; result.artifact = std::move(inspection.artifact); result.syncArtifactInput = std::move(inspection.syncArtifactInput); result.artifactDiscovered = true; result.artifactMetadataAccepted = true; result.platformAccepted = true; result.versionAccepted = !options.requireVersionMetadata || !result.artifact.versionLabel.empty(); result.provenanceAccepted = !options.requireProvenanceMetadata || provenanceComplete(result.artifact.provenance); result.sdxlCompatibilityAccepted = !options.requireSdxlCompatibility || result.artifact.sdxlCompatible; result.symbolMetadataAccepted = !options.requireSdxlSymbols || (coreSymbolsReady(result.artifact.symbols) && result.artifact.symbols.freeString && result.artifact.symbols.shutdown); result.executableMetadataAccepted = true; result.syncArtifactInputProduced = true; return result; } if (haveRejectedCandidate) { return stoppedResolverResult(std::move(result), firstRejected.status, firstRejected.issue, firstRejected.message); } return stoppedResolverResult(std::move(result), LiteBackendArtifactResolverStatus::WaitingForArtifactCandidate, LiteBackendArtifactResolverIssue::ArtifactCandidateMissing, "lite backend artifact resolver did not find any artifact candidates"); } LiteBackendActivationReadinessResult evaluateLiteBackendActivationReadiness( const LiteBackendActivationReadinessInput& input, LiteBackendActivationReadinessOptions options) { LiteBackendActivationReadinessResult result; result.connectionAvailability = LiteConnectionAvailability::BackendUnavailable; result = rejectActivationRuntimeAction(std::move(result), input, options); if (!result.issues.empty()) return result; if (options.requireActivationOwner && !input.activationOwnerReady) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForActivationOwner, LiteBackendActivationReadinessIssue::ActivationOwnerMissing, "lite backend activation readiness owner is not ready"); } result.activationOwnerAccepted = true; if (options.requireReadOnlyGate && !input.readOnlyGateReady) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForReadOnlyGate, LiteBackendActivationReadinessIssue::ReadOnlyGateMissing, "lite backend activation readiness read-only gate is not ready"); } result.readOnlyGateAccepted = true; if (options.requireLiteBuild && !isLiteBuild(input.capabilities)) { result.connectionAvailability = LiteConnectionAvailability::UnsupportedBuild; return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForLiteBuild, LiteBackendActivationReadinessIssue::FullNodeBuild, "lite backend activation readiness requires a lite build"); } result.liteBuildAccepted = true; if (options.requireLiteBackendCapability && !supportsLiteBackend(input.capabilities)) { result.connectionAvailability = LiteConnectionAvailability::BackendUnavailable; return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForBackendCapability, LiteBackendActivationReadinessIssue::LiteBackendCapabilityMissing, "lite backend capability is not available for activation readiness"); } result.backendCapabilityAccepted = true; result.artifactResolverResult = evaluateLiteBackendArtifactResolver(input.artifactResolver, options.resolverOptions); if (options.requireResolvedArtifact && !result.artifactResolverResult.ok) { return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForArtifactResolver, LiteBackendActivationReadinessIssue::ArtifactResolverRejected, result.artifactResolverResult.error.empty() ? "lite backend artifact resolver did not produce a usable artifact" : result.artifactResolverResult.error); } result.artifactResolverAccepted = true; result.syncArtifactInput = result.artifactResolverResult.syncArtifactInput; if (options.requireLinkedBackend && !input.backend.linked) { result.connectionAvailability = LiteConnectionAvailability::BackendUnavailable; const auto status = backendStatusOrDefault(input.backend, "lite backend is not linked"); return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForBackendLink, LiteBackendActivationReadinessIssue::BackendNotLinked, status.message); } result.backendLinkedAccepted = true; if (options.requireBridgeAvailable && !input.backend.bridgeAvailable) { result.connectionAvailability = LiteConnectionAvailability::BridgeUnavailable; const std::string message = !input.backend.bridgeUnavailableReason.empty() ? input.backend.bridgeUnavailableReason : backendStatusOrDefault(input.backend, "lite client bridge is unavailable").message; return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForBridge, LiteBackendActivationReadinessIssue::BridgeUnavailable, message); } result.bridgeAccepted = true; result.selectedServer = selectLiteServer(input.connectionSettings); if (options.requireUsableServer && !result.selectedServer.ok) { result.connectionAvailability = LiteConnectionAvailability::NoUsableServer; return stoppedActivationResult(std::move(result), LiteBackendActivationReadinessStatus::WaitingForConnectionSettings, LiteBackendActivationReadinessIssue::ConnectionSettingsRejected, result.selectedServer.error.empty() ? "no usable lite server is configured for activation readiness" : result.selectedServer.error, WalletBackendState::Error); } result.connectionSettingsAccepted = true; result.syncBackendInput.linked = input.backend.linked; result.syncBackendInput.bridgeAvailable = input.backend.bridgeAvailable; result.syncBackendInput.status = input.backend.status.message.empty() ? WalletBackendStatus{WalletBackendState::Disconnected, "lite backend bridge readiness accepted", {}, {}, 0.0} : input.backend.status; result.syncBackendInput.bridgeUnavailableReason = input.backend.bridgeUnavailableReason; result.syncReadinessInputsProduced = true; result.ok = true; result.status = LiteBackendActivationReadinessStatus::ReadyForConnectionReadiness; result.connectionAvailability = LiteConnectionAvailability::Ready; result.connectionStatus = readyConnectionStatus(result.selectedServer); result.connectionServiceBoundaryAccepted = true; return result; } LiteBackendArtifactResolver::LiteBackendArtifactResolver(LiteBackendArtifactResolverOptions options) : options_(options) { } LiteBackendArtifactResolverResult LiteBackendArtifactResolver::resolve( const LiteBackendArtifactResolverInput& input) const { return evaluateLiteBackendArtifactResolver(input, options_); } } // namespace dragonx::wallet