main ece7682

convert.go RawHistoryFolder

1package daemonmux
2
3// Shared semantic converters.
4//
5// Conversion mirrors the port, domain, and protocol types losslessly and
6// validates every narrowing numeric cast before it happens. Wire uint32
7// taxonomy fields never truncate into a smaller semantic enum: values whose
8// high bits would alias a legitimate code are refused with errConvertRange
9// before any cast. Identity lengths are exact (16-byte connection,
10// incarnation, and lifecycle values); text fields enforce UTF-8,
11// control/bidi, and byte bounds.
12//
13// The daemonmux codec deliberately imports no brokerwire symbol: it reuses
14// the generated shared wire messages and the ports/domain semantic values
15// directly, so the two conversations stay independently evolvable.
16
17import (
18	"github.com/bnema/vev/internal/adapters/protoconv"
19	"github.com/bnema/vev/internal/domain"
20	"github.com/bnema/vev/internal/ports"
21	"github.com/bnema/vev/internal/protocol"
22	"github.com/bnema/vev/internal/protocol/wire"
23)
24
25// muxEnum8 maps shared narrowing failures to the local range sentinel.
26func muxEnum8[T ~uint8](value uint32) (T, error) {
27	v, err := protoconv.Uint8[T](value)
28	if err != nil {
29		return 0, errConvertRange
30	}
31	return v, nil
32}
33
34func startModeToWire(mode ports.BrokerDaemonStartMode) (uint32, error) {
35	v, err := protoconv.BrokerStartModeToWire(mode)
36	if err != nil {
37		return 0, errConvertRange
38	}
39	return v, nil
40}
41
42func startModeFromWire(value uint32) (ports.BrokerDaemonStartMode, error) {
43	v, err := protoconv.BrokerStartModeFromWire(value)
44	if err != nil {
45		return 0, errConvertRange
46	}
47	return v, nil
48}
49
50func physicalToWire(id PhysicalStreamID) uint64 { return uint64(id) }
51
52func physicalFromWire(value uint64) (PhysicalStreamID, error) {
53	id := PhysicalStreamID(value)
54	if err := id.Validate(); err != nil {
55		return 0, errConvertRange
56	}
57	return id, nil
58}
59
60func refToWire(ref StreamRef) *wire.MuxStreamRef {
61	return &wire.MuxStreamRef{
62		PhysicalStreamId: physicalToWire(ref.Physical),
63		BrokerEpoch:      uint64(ref.Epoch),
64		ConnectionId:     append([]byte(nil), ref.Connection[:]...),
65		ClientStreamId:   uint64(ref.Client),
66	}
67}
68
69func refFromWire(message *wire.MuxStreamRef) (StreamRef, error) {
70	var ref StreamRef
71	if message == nil {
72		return ref, errConvertRange
73	}
74	physical, err := physicalFromWire(message.GetPhysicalStreamId())
75	if err != nil {
76		return StreamRef{}, err
77	}
78	if message.GetBrokerEpoch() == 0 {
79		return StreamRef{}, errConvertRange
80	}
81	raw := message.GetConnectionId()
82	if len(raw) != len(ref.Connection) {
83		return StreamRef{}, errConvertRange
84	}
85	copy(ref.Connection[:], raw)
86	if err := ref.Connection.Validate(); err != nil {
87		return StreamRef{}, errConvertRange
88	}
89	client := ports.BrokerStreamID(message.GetClientStreamId())
90	if err := client.Validate(); err != nil {
91		return StreamRef{}, errConvertRange
92	}
93	return StreamRef{
94		Physical:   physical,
95		Epoch:      ports.BrokerEpoch(message.GetBrokerEpoch()),
96		Connection: ref.Connection,
97		Client:     client,
98	}, nil
99}
100
101func registrationToWire(v domain.RemoteRegistration) *wire.RemoteRegistration {
102	return protoconv.BrokerRegistrationToWire(v)
103}
104func registrationFromWire(v *wire.RemoteRegistration) (domain.RemoteRegistration, error) {
105	out, err := protoconv.BrokerRegistrationFromWire(v)
106	if err != nil {
107		return domain.RemoteRegistration{}, errConvertRange
108	}
109	return out, nil
110}
111
112func exactTargetToWire(v protocol.ExactSessionTarget) *wire.ExactTarget {
113	return protoconv.BrokerExactTargetToWire(v)
114}
115
116func exactTargetFromWire(v *wire.ExactTarget) (protocol.ExactSessionTarget, error) {
117	out, err := protoconv.BrokerExactTargetFromWire(v)
118	if err != nil {
119		return protocol.ExactSessionTarget{}, errConvertRange
120	}
121	return out, nil
122}
123
124func policyToWire(v ports.BrokerPolicy) *wire.BrokerWirePolicy {
125	return protoconv.BrokerPolicyToWire(v)
126}
127
128func policyFromWire(v *wire.BrokerWirePolicy) (ports.BrokerPolicy, error) {
129	out, err := protoconv.BrokerPolicyFromWire(v)
130	if err != nil {
131		return ports.BrokerPolicy{}, mapBrokerConversionError(err)
132	}
133	return out, nil
134}
135
136func mapBrokerConversionError(err error) error {
137	switch err {
138	case protoconv.ErrOutOfRange:
139		return errConvertRange
140	case protoconv.ErrTooLarge:
141		return ErrTooLarge
142	default:
143		return ErrInvalidMessage
144	}
145}
146
147func validateDisplayText(v string, max int) error {
148	return mapOptionalBrokerError(protoconv.BrokerDisplayText(v, max))
149}
150
151func mapOptionalBrokerError(err error) error {
152	if err == nil {
153		return nil
154	}
155	return mapBrokerConversionError(err)
156}
157
158func errorDetailToWire(detail ErrorDetail) *wire.BrokerErrorDetail {
159	return &wire.BrokerErrorDetail{
160		Code:          uint32(detail.Code),
161		Text:          detail.Text,
162		AdmissionCode: detail.AdmissionCode,
163		FailureKind:   uint32(detail.FailureKind),
164	}
165}
166
167func errorDetailFromWire(message *wire.BrokerErrorDetail) (ErrorDetail, error) {
168	var detail ErrorDetail
169	if message == nil {
170		return detail, errConvertRange
171	}
172	code, err := muxEnum8[ports.BrokerErrorCode](message.GetCode())
173	if err != nil {
174		return ErrorDetail{}, err
175	}
176	if err := code.Validate(); err != nil {
177		return ErrorDetail{}, ErrInvalidMessage
178	}
179	detail.Code = code
180	if err := validateDisplayText(message.GetText(), ports.BrokerMaxErrorBytes); err != nil {
181		return ErrorDetail{}, err
182	}
183	detail.Text = message.GetText()
184	admission := message.GetAdmissionCode()
185	if admission > MaxAdmissionCode {
186		return ErrorDetail{}, errConvertRange
187	}
188	detail.AdmissionCode = admission
189	kind, err := muxEnum8[domain.RemoteFailureKind](message.GetFailureKind())
190	if err != nil {
191		return ErrorDetail{}, err
192	}
193	if kind > MaxFailureKind {
194		return ErrorDetail{}, ErrInvalidMessage
195	}
196	detail.FailureKind = kind
197	failure := ports.BrokerError{Code: code, Text: detail.Text}
198	if err := failure.Validate(); err != nil {
199		return ErrorDetail{}, ErrInvalidMessage
200	}
201	return detail, nil
202}
203
204// checkEnvEntries keeps the local error taxonomy at the adapter boundary.
205func checkEnvEntries(env []string) error {
206	return mapOptionalBrokerError(protoconv.BrokerEnvEntries(env))
207}

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