[agent/codex:gpt-5.4-mini] Read docs/RFC.md fully. Find ONE feature described in the sp... #41
3 changed files with 157 additions and 0 deletions
|
|
@ -35,6 +35,13 @@ type ActionRegistrar interface {
|
|||
RegisterAction(name string, invoke func(map[string]any) (any, bool, error))
|
||||
}
|
||||
|
||||
// ActionCaller resolves named actions from another Core surface.
|
||||
//
|
||||
// payload, ok, err := caller.CallAction(context.Background(), "blockchain.chain.aliases", nil)
|
||||
type ActionCaller interface {
|
||||
CallAction(ctx context.Context, name string, values map[string]any) (any, bool, error)
|
||||
}
|
||||
|
||||
// ActionDefinitions returns the complete DNS action surface in registration order.
|
||||
//
|
||||
// definitions := service.ActionDefinitions()
|
||||
|
|
|
|||
55
service.go
55
service.go
|
|
@ -50,6 +50,7 @@ type Service struct {
|
|||
zoneApex string
|
||||
hsdClient *HSDClient
|
||||
mainchainAliasClient *MainchainAliasClient
|
||||
chainAliasActionCaller ActionCaller
|
||||
chainAliasAction func(context.Context) ([]string, error)
|
||||
discoverer func() (map[string]NameRecords, error)
|
||||
fallbackDiscoverer func() (map[string]NameRecords, error)
|
||||
|
|
@ -66,6 +67,7 @@ type ServiceOptions struct {
|
|||
FallbackDiscoverer func() (map[string]NameRecords, error)
|
||||
MainchainAliasClient *MainchainAliasClient
|
||||
HSDClient *HSDClient
|
||||
ChainAliasActionCaller ActionCaller
|
||||
ChainAliasAction func(context.Context) ([]string, error)
|
||||
ChainAliasDiscoverer func(context.Context) ([]string, error)
|
||||
FallbackChainAliasDiscoverer func(context.Context) ([]string, error)
|
||||
|
|
@ -106,6 +108,7 @@ func NewService(options ServiceOptions) *Service {
|
|||
zoneApex: computeZoneApex(cached),
|
||||
hsdClient: options.HSDClient,
|
||||
mainchainAliasClient: options.MainchainAliasClient,
|
||||
chainAliasActionCaller: options.ChainAliasActionCaller,
|
||||
chainAliasAction: options.ChainAliasAction,
|
||||
discoverer: options.Discoverer,
|
||||
fallbackDiscoverer: options.FallbackDiscoverer,
|
||||
|
|
@ -133,6 +136,7 @@ func (service *Service) DiscoverFromChainAliases(ctx context.Context, client *HS
|
|||
|
||||
aliases, err := service.discoverAliasesFromSources(
|
||||
ctx,
|
||||
service.chainAliasActionCaller,
|
||||
service.chainAliasAction,
|
||||
service.chainAliasDiscoverer,
|
||||
service.fallbackChainAliasDiscoverer,
|
||||
|
|
@ -149,11 +153,16 @@ func (service *Service) DiscoverFromChainAliases(ctx context.Context, client *HS
|
|||
|
||||
func (service *Service) discoverAliasesFromSources(
|
||||
ctx context.Context,
|
||||
actionCaller ActionCaller,
|
||||
action func(context.Context) ([]string, error),
|
||||
discoverer func(context.Context) ([]string, error),
|
||||
fallback func(context.Context) ([]string, error),
|
||||
mainchainClient *MainchainAliasClient,
|
||||
) ([]string, error) {
|
||||
if aliases, ok := service.discoverAliasesFromActionCaller(ctx, actionCaller); ok {
|
||||
return aliases, nil
|
||||
}
|
||||
|
||||
if action != nil {
|
||||
aliases, err := action(ctx)
|
||||
if err == nil {
|
||||
|
|
@ -199,6 +208,51 @@ func (service *Service) discoverAliasesFromSources(
|
|||
return mainchainClient.GetAllAliasDetails(ctx)
|
||||
}
|
||||
|
||||
func (service *Service) discoverAliasesFromActionCaller(ctx context.Context, actionCaller ActionCaller) ([]string, bool) {
|
||||
if actionCaller == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
result, ok, err := actionCaller.CallAction(ctx, "blockchain.chain.aliases", map[string]any{})
|
||||
if err != nil || !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
aliases, err := parseActionAliasList(result)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return aliases, true
|
||||
}
|
||||
|
||||
func parseActionAliasList(value any) ([]string, error) {
|
||||
switch aliases := value.(type) {
|
||||
case nil:
|
||||
return nil, fmt.Errorf("blockchain.chain.aliases action returned no value")
|
||||
case []string:
|
||||
return normalizeAliasList(aliases), nil
|
||||
case []any:
|
||||
parsed := make([]string, 0, len(aliases))
|
||||
for _, item := range aliases {
|
||||
name, ok := item.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("blockchain.chain.aliases action returned non-string alias")
|
||||
}
|
||||
parsed = append(parsed, name)
|
||||
}
|
||||
return normalizeAliasList(parsed), nil
|
||||
case map[string]any:
|
||||
if rawAliases, ok := aliases["aliases"]; ok {
|
||||
return parseActionAliasList(rawAliases)
|
||||
}
|
||||
if rawResult, ok := aliases["result"]; ok {
|
||||
return parseActionAliasList(rawResult)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("blockchain.chain.aliases action returned unsupported result type %T", value)
|
||||
}
|
||||
|
||||
// DiscoverFromMainchainAliases updates records from main-chain aliases resolved through HSD.
|
||||
//
|
||||
// service.DiscoverFromMainchainAliases(context.Background(), dns.NewMainchainAliasClient(dns.MainchainClientOptions{
|
||||
|
|
@ -219,6 +273,7 @@ func (service *Service) DiscoverFromMainchainAliases(ctx context.Context, chainC
|
|||
|
||||
aliases, err := service.discoverAliasesFromSources(
|
||||
ctx,
|
||||
service.chainAliasActionCaller,
|
||||
nil,
|
||||
func(ctx context.Context) ([]string, error) {
|
||||
if service.chainAliasDiscoverer != nil {
|
||||
|
|
|
|||
|
|
@ -516,6 +516,95 @@ func TestServiceDiscoverAliasesUsesConfiguredAliasDiscovery(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestServiceDiscoverAliasesUsesConfiguredActionCaller(t *testing.T) {
|
||||
var treeRootCalls int32
|
||||
var nameResourceCalls int32
|
||||
actionCalled := false
|
||||
discovererCalled := false
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
|
||||
var payload struct {
|
||||
Method string `json:"method"`
|
||||
Params []any `json:"params"`
|
||||
}
|
||||
if err := json.NewDecoder(request.Body).Decode(&payload); err != nil {
|
||||
t.Fatalf("unexpected request payload: %v", err)
|
||||
}
|
||||
|
||||
switch payload.Method {
|
||||
case "getblockchaininfo":
|
||||
atomic.AddInt32(&treeRootCalls, 1)
|
||||
responseWriter.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(responseWriter).Encode(map[string]any{
|
||||
"result": map[string]any{
|
||||
"tree_root": "action-caller-root",
|
||||
},
|
||||
})
|
||||
case "getnameresource":
|
||||
atomic.AddInt32(&nameResourceCalls, 1)
|
||||
switch payload.Params[0] {
|
||||
case "gateway.charon.lthn":
|
||||
_ = json.NewEncoder(responseWriter).Encode(map[string]any{
|
||||
"result": map[string]any{
|
||||
"a": []string{"10.10.10.10"},
|
||||
},
|
||||
})
|
||||
case "node.charon.lthn":
|
||||
_ = json.NewEncoder(responseWriter).Encode(map[string]any{
|
||||
"result": map[string]any{
|
||||
"aaaa": []string{"2600:1f1c:7f0:4f01::2"},
|
||||
},
|
||||
})
|
||||
default:
|
||||
t.Fatalf("unexpected alias lookup: %#v", payload.Params)
|
||||
}
|
||||
default:
|
||||
t.Fatalf("unexpected method: %s", payload.Method)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
service := NewService(ServiceOptions{
|
||||
ChainAliasActionCaller: actionCallerFunc(func(ctx context.Context, name string, values map[string]any) (any, bool, error) {
|
||||
actionCalled = true
|
||||
if name != "blockchain.chain.aliases" {
|
||||
t.Fatalf("unexpected action name: %s", name)
|
||||
}
|
||||
return map[string]any{
|
||||
"aliases": []any{"gateway.charon.lthn", "node.charon.lthn"},
|
||||
}, true, nil
|
||||
}),
|
||||
ChainAliasDiscoverer: func(_ context.Context) ([]string, error) {
|
||||
discovererCalled = true
|
||||
return nil, errors.New("discoverer should not run when action caller succeeds")
|
||||
},
|
||||
HSDClient: NewHSDClient(HSDClientOptions{URL: server.URL}),
|
||||
})
|
||||
|
||||
if err := service.DiscoverAliases(context.Background()); err != nil {
|
||||
t.Fatalf("expected DiscoverAliases to complete through action caller: %v", err)
|
||||
}
|
||||
if !actionCalled {
|
||||
t.Fatal("expected action caller to be invoked")
|
||||
}
|
||||
if discovererCalled {
|
||||
t.Fatal("expected chain alias discoverer to be skipped after action caller success")
|
||||
}
|
||||
|
||||
gateway, ok := service.Resolve("gateway.charon.lthn")
|
||||
if !ok || len(gateway.A) != 1 || gateway.A[0] != "10.10.10.10" {
|
||||
t.Fatalf("expected gateway A record, got %#v (ok=%t)", gateway, ok)
|
||||
}
|
||||
node, ok := service.Resolve("node.charon.lthn")
|
||||
if !ok || len(node.AAAA) != 1 || node.AAAA[0] != "2600:1f1c:7f0:4f01::2" {
|
||||
t.Fatalf("expected node AAAA record, got %#v (ok=%t)", node, ok)
|
||||
}
|
||||
|
||||
if atomic.LoadInt32(&treeRootCalls) != 1 || atomic.LoadInt32(&nameResourceCalls) != 2 {
|
||||
t.Fatalf("expected discovery to perform chain and name-resource calls, got treeRoot=%d nameResource=%d", atomic.LoadInt32(&treeRootCalls), atomic.LoadInt32(&nameResourceCalls))
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceDiscoverAliasesUsesConfiguredChainAliasAction(t *testing.T) {
|
||||
var treeRootCalls int32
|
||||
var nameResourceCalls int32
|
||||
|
|
@ -1608,3 +1697,9 @@ func (recorder *actionRecorder) RegisterAction(name string, invoke func(map[stri
|
|||
recorder.names = append(recorder.names, name)
|
||||
recorder.handlers[name] = invoke
|
||||
}
|
||||
|
||||
type actionCallerFunc func(context.Context, string, map[string]any) (any, bool, error)
|
||||
|
||||
func (caller actionCallerFunc) CallAction(ctx context.Context, name string, values map[string]any) (any, bool, error) {
|
||||
return caller(ctx, name, values)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue