broker_acquisition.go RawHistoryFolder
1package ports
2
3import (
4 "context"
5 "errors"
6 "fmt"
7
8 "github.com/bnema/vev/internal/domain"
9)
10
11// BrokerEndpointFence identifies the exact route authority used for one dial.
12// Remote registrations carry their full incarnation/generation; local routes
13// are explicit and never fabricate a registration.
14type BrokerEndpointFence struct {
15 Local bool
16 Registration domain.RemoteRegistration
17}
18
19func (f BrokerEndpointFence) Validate() error {
20 if f.Local {
21 if f.Registration != (domain.RemoteRegistration{}) {
22 return errors.New("ports: local endpoint fence carries a registration")
23 }
24 return nil
25 }
26 return f.Registration.Validate()
27}
28
29// BrokerDaemonStartMode is the closed, explicit authorization a caller attaches
30// to one acquisition: whether the transport may start the target daemon when it
31// is not already reachable, or must observe only what is already running.
32//
33// Purpose alone cannot carry this: a control stream that lists or mutates a
34// stopped daemon's persisted records is allowed to start it, while an
35// observation and the explicit daemon-stop itself must never start it. The mode
36// is an authorization, never an obligation: it can only narrow the configured
37// policy, and a policy that does not permit launching still refuses.
38type BrokerDaemonStartMode uint8
39
40const (
41 // BrokerDaemonExistingOnly authorizes only an already running daemon. A
42 // transport that carries this mode must never start a daemon, a broker, or
43 // any recursive helper process.
44 BrokerDaemonExistingOnly BrokerDaemonStartMode = iota + 1
45 // BrokerDaemonStartIfNeeded additionally authorizes starting the target
46 // daemon when it is not running, subject to the resolved policy's launch
47 // authority.
48 BrokerDaemonStartIfNeeded
49)
50
51func (m BrokerDaemonStartMode) String() string {
52 switch m {
53 case BrokerDaemonExistingOnly:
54 return "existing_only"
55 case BrokerDaemonStartIfNeeded:
56 return "start_if_needed"
57 default:
58 return fmt.Sprintf("invalid(%d)", uint8(m))
59 }
60}
61
62// Validate refuses the zero value: every acquisition states its start authority
63// explicitly rather than inheriting an implicit ability to start a daemon.
64func (m BrokerDaemonStartMode) Validate() error {
65 switch m {
66 case BrokerDaemonExistingOnly, BrokerDaemonStartIfNeeded:
67 return nil
68 default:
69 return errors.New("ports: invalid broker daemon start mode")
70 }
71}
72
73// BrokerExpectedIdentity is an explicit optional durable identity binding.
74// BrokerDaemonIdentity itself remains strict and is never valid when empty.
75type BrokerExpectedIdentity struct {
76 Identity BrokerDaemonIdentity
77 Bound bool
78}
79
80func (e BrokerExpectedIdentity) Validate() error {
81 if !e.Bound {
82 if e.Identity != "" {
83 return errors.New("ports: unbound expected identity carries a value")
84 }
85 return nil
86 }
87 return e.Identity.Validate()
88}
89
90// BrokerDialTarget authorizes one bounded dial before authentication. Address
91// selects the adapter route; ExpectedIdentity fences an existing durable
92// binding but may be explicitly unbound for first contact. StartMode is carried
93// over from the resolution request and must reach the transport before any
94// connect-or-spawn decision.
95type BrokerDialTarget struct {
96 Fence BrokerEndpointFence
97 Address string
98 Policy BrokerPolicy
99 StartMode BrokerDaemonStartMode
100 ExpectedIdentity BrokerExpectedIdentity
101}
102
103func (t BrokerDialTarget) Validate() error {
104 if err := t.Fence.Validate(); err != nil {
105 return err
106 }
107 if err := t.StartMode.Validate(); err != nil {
108 return err
109 }
110 if err := t.Policy.Validate(); err != nil {
111 return err
112 }
113 if err := t.ExpectedIdentity.Validate(); err != nil {
114 return err
115 }
116 return validateBrokerToken(t.Address, BrokerMaxAddressBytes, "dial target address")
117}
118
119// BrokerRouteAuthority resolves current membership and route authority. It
120// performs no network I/O and never invents a daemon identity. Resolution
121// propagates BrokerOpenStreamRequest.StartMode onto the returned dial target
122// unchanged, so the resolved authority and the requested start mode are decided
123// together and neither can be widened afterwards.
124type BrokerRouteAuthority interface {
125 ResolveDialTarget(context.Context, BrokerOpenStreamRequest) (BrokerDialTarget, error)
126}
127
128// BrokerIdentityBindingRequest asks the broker authority to adopt an identity
129// learned from an authenticated carriage under the exact resolution fence.
130type BrokerIdentityBindingRequest struct {
131 Fence BrokerEndpointFence
132 Policy BrokerPolicy
133 Identity BrokerDaemonIdentity
134}
135
136func (r BrokerIdentityBindingRequest) Validate() error {
137 if err := r.Fence.Validate(); err != nil {
138 return err
139 }
140 if err := r.Policy.Validate(); err != nil {
141 return err
142 }
143 return r.Identity.Validate()
144}
145
146// BrokerIdentityBinder commits first-contact identity authority before a
147// physical connection may be published or carry a logical stream.
148type BrokerIdentityBinder interface {
149 BindAuthenticatedIdentity(context.Context, BrokerIdentityBindingRequest) (BrokerDaemonIdentity, error)
150}