Skip to content

Commit 783cf27

Browse files
committed
feat(project): add registry content routing and file transport
1 parent ed8c3d8 commit 783cf27

11 files changed

Lines changed: 938 additions & 38 deletions

‎include/vix/cli/project/native/PackageContentAcquisition.hpp‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,21 @@ namespace vix::cli::project::native
2323

2424
enum class PackageContentSourceStatus { available, unavailable, transport_failure };
2525

26+
enum class RegistryPackageContentSourceStatus
27+
{
28+
available,
29+
not_found,
30+
transport_failure,
31+
permission_denied,
32+
configuration_error,
33+
payload_too_large
34+
};
35+
2636
// `available` carries untrusted exact P10O canonical bytes. The provider
2737
// cannot mint a VerifiedPackageContent token.
2838
struct RegistryPackageContentSourceResult
2939
{
30-
PackageContentSourceStatus status{PackageContentSourceStatus::unavailable};
40+
RegistryPackageContentSourceStatus status{RegistryPackageContentSourceStatus::not_found};
3141
std::optional<std::string> canonicalBytes;
3242
std::string diagnostic;
3343
};
@@ -37,7 +47,7 @@ namespace vix::cli::project::native
3747
public:
3848
virtual ~RegistryPackageContentSource() = default;
3949
[[nodiscard]] virtual RegistryPackageContentSourceResult acquire(
40-
const RegistryLocation &location,
50+
const RegistryContentLocation &location,
4151
const RegistryPackageContentRequest &request) = 0;
4252
};
4353

@@ -83,14 +93,16 @@ namespace vix::cli::project::native
8393
package_content_transport_failure,
8494
package_content_integrity_failure,
8595
package_content_digest_mismatch,
96+
package_content_source_configuration_error,
97+
package_content_payload_too_large,
8698
package_content_git_source_failure,
8799
package_content_store_failure,
88100
};
89101

90102
struct RegistryLocationAcquisitionDiagnostic
91103
{
92104
std::string locationDescriptor;
93-
PackageContentSourceStatus status{PackageContentSourceStatus::unavailable};
105+
RegistryPackageContentSourceStatus status{RegistryPackageContentSourceStatus::not_found};
94106
std::string message;
95107
};
96108

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/** @file RegistryContentLayout.hpp
2+
* Registry format-1 immutable content-object addressing.
3+
*/
4+
#ifndef VIX_CLI_PROJECT_NATIVE_REGISTRY_CONTENT_LAYOUT_HPP
5+
#define VIX_CLI_PROJECT_NATIVE_REGISTRY_CONTENT_LAYOUT_HPP
6+
7+
#include <string>
8+
#include <string_view>
9+
10+
#include <vix/cli/project/native/PackageContentStore.hpp>
11+
12+
namespace vix::cli::project::native
13+
{
14+
// Registry mirror layout is independent from P10P's local filesystem layout.
15+
// PackageContentId can only be created after validated SHA-256 syntax, so the
16+
// resulting forward-slash path is safe and digest-derived.
17+
[[nodiscard]] inline std::string registry_format1_content_object_path(
18+
const PackageContentId &content)
19+
{
20+
const std::string &digest = content.digest();
21+
const std::string_view hex = std::string_view{digest}.substr(7);
22+
return "objects/sha256/" + std::string{hex.substr(0, 2)} + "/" +
23+
std::string{hex.substr(2)};
24+
}
25+
} // namespace vix::cli::project::native
26+
27+
#endif // VIX_CLI_PROJECT_NATIVE_REGISTRY_CONTENT_LAYOUT_HPP
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/** @file RegistryContentTransport.hpp
2+
* Local Registry format-1 content mirror transport.
3+
*/
4+
#ifndef VIX_CLI_PROJECT_NATIVE_REGISTRY_CONTENT_TRANSPORT_HPP
5+
#define VIX_CLI_PROJECT_NATIVE_REGISTRY_CONTENT_TRANSPORT_HPP
6+
7+
#include <cstdint>
8+
#include <optional>
9+
#include <string>
10+
#include <string_view>
11+
12+
#include <vix/cli/project/native/PackageContentAcquisition.hpp>
13+
14+
namespace vix::cli::project::native
15+
{
16+
inline constexpr std::uint64_t default_registry_content_maximum_bytes =
17+
1024ULL * 1024ULL * 1024ULL;
18+
19+
using RegistryContentTransportStatus = RegistryPackageContentSourceStatus;
20+
21+
struct RegistryContentTransportResult
22+
{
23+
RegistryContentTransportStatus status{RegistryContentTransportStatus::not_found};
24+
std::optional<std::string> bytes;
25+
std::string diagnostic;
26+
};
27+
28+
// Fetches one digest-addressed object from one configured mirror. It does
29+
// not iterate mirrors or validate P10O content.
30+
class RegistryContentTransport
31+
{
32+
public:
33+
virtual ~RegistryContentTransport() = default;
34+
[[nodiscard]] virtual RegistryContentTransportResult fetch(
35+
const RegistryContentLocation &location,
36+
std::string_view relativeObjectPath,
37+
std::uint64_t maximumBytes) = 0;
38+
};
39+
40+
class FileRegistryContentTransport final : public RegistryContentTransport
41+
{
42+
public:
43+
[[nodiscard]] RegistryContentTransportResult fetch(
44+
const RegistryContentLocation &location,
45+
std::string_view relativeObjectPath,
46+
std::uint64_t maximumBytes) override;
47+
};
48+
49+
// Adapts a single-location transport to the P10Q-A source boundary. P10Q-A
50+
// retains ownership of mirror fallback; P10O/P10P retain integrity/storage.
51+
class TransportRegistryPackageContentSource final : public RegistryPackageContentSource
52+
{
53+
public:
54+
explicit TransportRegistryPackageContentSource(
55+
RegistryContentTransport &transport,
56+
std::uint64_t maximumBytes = default_registry_content_maximum_bytes)
57+
: transport_(transport), maximumBytes_(maximumBytes) {}
58+
59+
[[nodiscard]] RegistryPackageContentSourceResult acquire(
60+
const RegistryContentLocation &location,
61+
const RegistryPackageContentRequest &request) override;
62+
63+
private:
64+
RegistryContentTransport &transport_;
65+
std::uint64_t maximumBytes_;
66+
};
67+
} // namespace vix::cli::project::native
68+
69+
#endif // VIX_CLI_PROJECT_NATIVE_REGISTRY_CONTENT_TRANSPORT_HPP

‎include/vix/cli/project/native/RegistryDirectory.hpp‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,22 @@ namespace vix::cli::project::native
2121
friend bool operator==(const RegistryLocation &, const RegistryLocation &) = default;
2222
};
2323

24+
// Opaque transport configuration for immutable Registry package content.
25+
// This is deliberately distinct from metadata-observation routing.
26+
struct RegistryContentLocation
27+
{
28+
std::string descriptor;
29+
friend bool operator==(const RegistryContentLocation &, const RegistryContentLocation &) = default;
30+
};
31+
2432
struct RegistryDefinition
2533
{
2634
std::string id;
2735
// Declaration order is fallback preference, not package semantics.
2836
std::vector<RegistryLocation> locations;
37+
// Independent content mirrors; declaration order is fallback preference.
38+
// Empty is valid when this Registry serves metadata but no content mirrors.
39+
std::vector<RegistryContentLocation> contentLocations;
2940
};
3041

3142
enum class RegistryDirectoryErrorCode
@@ -34,7 +45,9 @@ namespace vix::cli::project::native
3445
duplicate_registry_id,
3546
no_registry_locations,
3647
invalid_location,
37-
duplicate_location
48+
duplicate_location,
49+
invalid_content_location,
50+
duplicate_content_location
3851
};
3952

4053
struct RegistryDirectoryIssue

‎src/project/native/PackageContentAcquisition.cpp‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,33 @@ namespace vix::cli::project::native
8686
return failure(acquisition_issue(PackageContentAcquisitionIssueCode::unknown_registry,
8787
required, "locked Registry ID has no routing definition"));
8888

89+
if (definition->contentLocations.empty())
90+
return failure(acquisition_issue(PackageContentAcquisitionIssueCode::package_content_source_unavailable,
91+
required, "registry has no package content locations configured"));
92+
8993
const RegistryPackageContentRequest request{node.identity, node.version, required.id};
9094
std::vector<RegistryLocationAcquisitionDiagnostic> diagnostics;
9195
bool sawTransportFailure = false;
92-
for (const auto &location : definition->locations)
96+
for (const auto &location : definition->contentLocations)
9397
{
9498
const auto response = source.acquire(location, request);
95-
if (response.status != PackageContentSourceStatus::available)
99+
if (response.status == RegistryPackageContentSourceStatus::configuration_error ||
100+
response.status == RegistryPackageContentSourceStatus::payload_too_large)
101+
{
102+
diagnostics.push_back({location.descriptor, response.status, response.diagnostic});
103+
const auto code = response.status == RegistryPackageContentSourceStatus::configuration_error
104+
? PackageContentAcquisitionIssueCode::package_content_source_configuration_error
105+
: PackageContentAcquisitionIssueCode::package_content_payload_too_large;
106+
auto issue = acquisition_issue(code, required,
107+
response.diagnostic.empty() ? "Registry content transport failed terminally" : response.diagnostic);
108+
issue.registryLocations = std::move(diagnostics);
109+
return failure(std::move(issue));
110+
}
111+
if (response.status != RegistryPackageContentSourceStatus::available)
96112
{
97113
sawTransportFailure = sawTransportFailure ||
98-
response.status == PackageContentSourceStatus::transport_failure;
114+
response.status == RegistryPackageContentSourceStatus::transport_failure ||
115+
response.status == RegistryPackageContentSourceStatus::permission_denied;
99116
diagnostics.push_back({location.descriptor, response.status, response.diagnostic});
100117
continue;
101118
}

0 commit comments

Comments
 (0)