v0.7.0 4c16dd8

resolver.go RawHistoryFolder

1package brokerconfig
2
3import (
4	"context"
5	"errors"
6
7	"github.com/bnema/vev/internal/ports"
8)
9
10// Resolver is the immutable ports.BrokerRouteAuthority over one parsed
11// offline configuration. It holds no mutable state and performs no I/O: every
12// Resolve call fences the request against the provisioned registration and
13// returns the configured identity, policy, and opaque route address. A request
14// can therefore never select an address, identity, or policy of its own.
15//
16// A remote request is fenced against its provisioned registration (endpoint,
17// incarnation, and generation) and policy. A local request carries no endpoint
18// and no registration, so it is fenced against the broker-owned local binding:
19// the configured local identity, policy, and Unix daemonmux route. Both paths
20// return authority chosen by the configuration alone, and neither can widen,
21// narrow, or replace the provisioned identity or policy.
22type Resolver struct {
23	byEndpoint map[string]Registration
24	local      *LocalBinding
25}
26
27var _ ports.BrokerRouteAuthority = (*Resolver)(nil)
28
29// Resolve fences one open-stream request against the immutable configuration.
30//
31// A remote request must name a configured endpoint, carry that endpoint's
32// exact registration (endpoint, incarnation, and generation), and request a
33// policy compatible with the provisioned policy. A local request must instead
34// carry an empty endpoint and zero registration (ports enforces that) and is
35// fenced against the provisioned local binding: without one it is refused, and
36// with one its requested policy must be exactly compatible with the
37// provisioned local policy. Either way the resolved identity, policy, and
38// opaque route address come from the configuration, never from the request.
39//
40// Unknown, stale, conflicting, or unprovisioned requests are refused with a
41// typed broker error and no dial is attempted; a cancelled context is reported
42// as such so the pool classifies it as cancellation rather than unavailability.
43func (r *Resolver) ResolveDialTarget(ctx context.Context, request ports.BrokerOpenStreamRequest) (ports.BrokerDialTarget, error) {
44	if err := ctx.Err(); err != nil {
45		return ports.BrokerDialTarget{}, err
46	}
47	if request.Local {
48		return r.resolveLocal(request)
49	}
50	provisioned, ok := r.byEndpoint[request.Endpoint]
51	if !ok {
52		return ports.BrokerDialTarget{}, ports.BrokerError{Code: ports.BrokerErrorUnavailable, Text: "unknown endpoint", Cause: errUnknownEndpoint}
53	}
54	if !request.Registration.Equal(provisioned.Registration) {
55		return ports.BrokerDialTarget{}, ports.BrokerError{Code: ports.BrokerErrorUnavailable, Text: "stale registration", Cause: errStaleRegistration}
56	}
57	if !provisioned.Policy.Compatible(request.Policy) {
58		return ports.BrokerDialTarget{}, ports.BrokerError{Code: ports.BrokerErrorConflictingPolicy, Cause: errors.New("brokerconfig: request policy conflicts with the provisioned policy")}
59	}
60	resolved := ports.BrokerDialTarget{
61		Fence: ports.BrokerEndpointFence{Registration: provisioned.Registration}, Policy: provisioned.Policy, Address: provisioned.Route.Address(),
62		StartMode:        request.StartMode,
63		ExpectedIdentity: ports.BrokerExpectedIdentity{Identity: provisioned.Identity, Bound: provisioned.Identity != ""},
64	}
65	if err := resolved.Validate(); err != nil {
66		return ports.BrokerDialTarget{}, ports.BrokerError{Code: ports.BrokerErrorIncompatible, Cause: err}
67	}
68	return resolved, nil
69}
70
71// resolveLocal fences one local request against the broker-owned local
72// binding. A configuration that provisions no local route refuses the request
73// as unavailable; a request whose policy is not exactly compatible with the
74// provisioned local policy is refused as a conflicting policy. The resolved
75// identity, policy, and address are the binding's own, so the request supplies
76// none of them.
77func (r *Resolver) resolveLocal(request ports.BrokerOpenStreamRequest) (ports.BrokerDialTarget, error) {
78	if r.local == nil {
79		return ports.BrokerDialTarget{}, ports.BrokerError{Code: ports.BrokerErrorUnavailable, Text: "local route is not provisioned", Cause: errNoLocalRoute}
80	}
81	if !r.local.Policy.Compatible(request.Policy) {
82		return ports.BrokerDialTarget{}, ports.BrokerError{Code: ports.BrokerErrorConflictingPolicy, Cause: errLocalPolicyConflict}
83	}
84	resolved := ports.BrokerDialTarget{
85		Fence: ports.BrokerEndpointFence{Local: true}, Policy: r.local.Policy, Address: r.local.Route.Address(),
86		StartMode:        request.StartMode,
87		ExpectedIdentity: ports.BrokerExpectedIdentity{Identity: r.local.Identity, Bound: r.local.Identity != ""},
88	}
89	if err := resolved.Validate(); err != nil {
90		return ports.BrokerDialTarget{}, ports.BrokerError{Code: ports.BrokerErrorIncompatible, Cause: err}
91	}
92	return resolved, nil
93}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close