fed-sx-types Phase 3: /types/<cid> route + discovery_type_fetch
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 51s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 51s
Wire format for serving + fetching type docs (plans/fed-sx-host-types.md
step 3).
http_server.erl:
- new type_doc Accept format + content type
(application/vnd.fed-sx.type-doc), distinct from actor-doc.
- GET /types/<cid> -> the cached TypeRecord term_codec-encoded, 404 if
not in the peer_types cache. Reads peer_types via a Cfg
{peer_types, peer_types} guard (hardcoded registered atom, mirroring
the actor-doc route's kernel guard).
discovery_type_fetch.erl — sibling of discovery_fetch. make_fetch_fn
produces the fun/2 peer_types:lookup_or_fetch calls: GET
<base>/types/<cid> with the type-doc Accept header, returning the RAW
bytes (peer_types owns the term_codec decode, so the wire format lives
in one place — the route encodes, the cache decodes). Cfg carries
type_url / type_url_fn for TypeCid -> base URL resolution.
Tests: next/tests/peer_types_route.sh (13, in-process route dispatch),
next/tests/discovery_type_fetch.sh (9, closure vs a python type-doc
stub, end-to-end through peer_types:lookup_or_fetch).
No regression: http_accept, http_actors, http_get_format,
discovery_fetch all still green. Conformance 771/771.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
welcome_body/0, capabilities_body/0,
|
||||
capabilities_path/0,
|
||||
match_prefix/2, actors_prefix/0, actor_doc_response/1,
|
||||
types_prefix/0, type_doc_response_for/2,
|
||||
artifacts_prefix/0, artifact_response/1,
|
||||
projections_list_path/0, projections_prefix/0,
|
||||
projections_list_response/0, projection_response/1,
|
||||
@@ -156,7 +157,12 @@ dispatch(<<71, 69, 84>>, Path, F, Cfg) ->
|
||||
{ok, Name} when byte_size(Name) > 0 ->
|
||||
projection_response_for(Name, F);
|
||||
_ ->
|
||||
not_found_response()
|
||||
case match_prefix(types_prefix(), Path) of
|
||||
{ok, Cid} when byte_size(Cid) > 0 ->
|
||||
type_doc_response_for(Cid, Cfg);
|
||||
_ ->
|
||||
not_found_response()
|
||||
end
|
||||
end
|
||||
end
|
||||
end;
|
||||
@@ -289,6 +295,10 @@ artifact_response(Cid) ->
|
||||
Body = <<Pre/binary, Cid/binary, 10>>,
|
||||
ok_response(Body).
|
||||
|
||||
%% "/types/" — 7 bytes: 47 116 121 112 101 115 47 (host-type fed Step 3)
|
||||
types_prefix() ->
|
||||
<<47,116,121,112,101,115,47>>.
|
||||
|
||||
%% "/projections" — 12 bytes (no trailing slash; the list endpoint)
|
||||
projections_list_path() ->
|
||||
<<47,112,114,111,106,101,99,116,105,111,110,115>>.
|
||||
@@ -488,9 +498,20 @@ actor_doc_prefix() ->
|
||||
118,110,100,46,102,101,100,45,115,120,46,
|
||||
97,99,116,111,114,45,100,111,99>>.
|
||||
|
||||
%% "application/vnd.fed-sx.type-doc" — 31 bytes (host-type fed Step 3).
|
||||
%% Distinct from actor-doc: the body is a term_codec-encoded
|
||||
%% TypeRecord (peer_types cache entry), not a peer-actor-state.
|
||||
type_doc_prefix() ->
|
||||
<<97,112,112,108,105,99,97,116,105,111,110,47,
|
||||
118,110,100,46,102,101,100,45,115,120,46,
|
||||
116,121,112,101,45,100,111,99>>.
|
||||
|
||||
accept_format(nil) -> text;
|
||||
accept_format(<<>>) -> text;
|
||||
accept_format(V) when is_binary(V) ->
|
||||
case match_prefix(type_doc_prefix(), V) of
|
||||
{ok, _} -> type_doc;
|
||||
_ ->
|
||||
case match_prefix(actor_doc_prefix(), V) of
|
||||
{ok, _} -> actor_doc;
|
||||
_ ->
|
||||
@@ -510,6 +531,7 @@ accept_format(V) when is_binary(V) ->
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end;
|
||||
accept_format(_) -> text.
|
||||
|
||||
@@ -586,6 +608,11 @@ content_type_for(actor_doc) ->
|
||||
<<97,112,112,108,105,99,97,116,105,111,110,47,
|
||||
118,110,100,46,102,101,100,45,115,120,46,
|
||||
97,99,116,111,114,45,100,111,99>>;
|
||||
%% "application/vnd.fed-sx.type-doc" — 31 bytes (host-type fed Step 3).
|
||||
content_type_for(type_doc) ->
|
||||
<<97,112,112,108,105,99,97,116,105,111,110,47,
|
||||
118,110,100,46,102,101,100,45,115,120,46,
|
||||
116,121,112,101,45,100,111,99>>;
|
||||
content_type_for(_) ->
|
||||
content_type_for(text).
|
||||
|
||||
@@ -714,6 +741,42 @@ kernel_actor_state(_Kernel, Id) ->
|
||||
_ -> nil
|
||||
end.
|
||||
|
||||
%% ── host-type fed Step 3: GET /types/<cid> ──────────────────────
|
||||
%%
|
||||
%% Serves a TypeRecord the node has cached (its own published types or
|
||||
%% types fetched from peers) so a federated peer running
|
||||
%% discovery_type_fetch can decode it directly into the shape
|
||||
%% peer_types + the object-schema pipeline stage consume. The wire
|
||||
%% body is term_codec:encode(TypeRecord) under the
|
||||
%% application/vnd.fed-sx.type-doc content type; a cache miss is a 404.
|
||||
%%
|
||||
%% Cid is the path segment after "/types/" (the type's CID bytes). Cfg
|
||||
%% carries `{peer_types, peer_types}` to opt the route into the cache —
|
||||
%% absent (or the gen_server down) short-circuits to 404, matching the
|
||||
%% kernel_actor_state guard for the actor-doc route. This port can't
|
||||
%% dispatch `Mod:Fun` on a variable module, so the registered
|
||||
%% `peer_types` atom is hardcoded; the Cfg field flags "no cache wired".
|
||||
|
||||
type_doc_response_for(Cid, Cfg) ->
|
||||
case type_record_for(Cfg, Cid) of
|
||||
nil -> not_found_response();
|
||||
TR -> ok_response(term_codec:encode(TR), type_doc)
|
||||
end.
|
||||
|
||||
type_record_for(Cfg, Cid) ->
|
||||
case field(peer_types, Cfg) of
|
||||
nil -> nil;
|
||||
_ ->
|
||||
case erlang:whereis(peer_types) of
|
||||
undefined -> nil;
|
||||
_ ->
|
||||
case peer_types:lookup(Cid) of
|
||||
{ok, TR} -> TR;
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
end.
|
||||
|
||||
%% ── Step 4a: per-actor sub-resource stubs ──────────────────────
|
||||
%% Per design §16.1 each actor has /outbox /inbox /followers
|
||||
%% /following routes. v1 returns text-stub bodies so route resolution
|
||||
|
||||
Reference in New Issue
Block a user