1package protoconv
2
3import (
4 "errors"
5 "strings"
6 "unicode"
7 "unicode/utf8"
8
9 "github.com/bnema/vev/internal/domain"
10 "github.com/bnema/vev/internal/ports"
11 "github.com/bnema/vev/internal/protocol"
12 "github.com/bnema/vev/internal/protocol/wire"
13)
14
15// ErrInvalid and ErrTooLarge distinguish semantic and byte-bound failures
16// from ErrOutOfRange; adapters translate them to their local sentinels.
17var (
18 ErrInvalid = errors.New("protoconv: invalid broker value")
19 ErrTooLarge = errors.New("protoconv: broker value exceeds bound")
20)
21
22func BrokerStartModeToWire(mode ports.BrokerDaemonStartMode) (uint32, error) {
23 switch mode {
24 case ports.BrokerDaemonExistingOnly:
25 return 1, nil
26 case ports.BrokerDaemonStartIfNeeded:
27 return 2, nil
28 default:
29 return 0, ErrOutOfRange
30 }
31}
32
33func BrokerStartModeFromWire(value uint32) (ports.BrokerDaemonStartMode, error) {
34 switch value {
35 case 1:
36 return ports.BrokerDaemonExistingOnly, nil
37 case 2:
38 return ports.BrokerDaemonStartIfNeeded, nil
39 default:
40 return 0, ErrOutOfRange
41 }
42}
43
44func BrokerRegistrationToWire(registration domain.RemoteRegistration) *wire.RemoteRegistration {
45 return &wire.RemoteRegistration{Endpoint: registration.Endpoint, Incarnation: append([]byte(nil), registration.Incarnation[:]...), Generation: uint64(registration.Generation)}
46}
47
48func BrokerRegistrationFromWire(message *wire.RemoteRegistration) (domain.RemoteRegistration, error) {
49 var registration domain.RemoteRegistration
50 if message == nil {
51 return registration, ErrOutOfRange
52 }
53 registration.Endpoint = message.GetEndpoint()
54 if err := domain.ValidateRemoteHostTarget(registration.Endpoint); err != nil {
55 return domain.RemoteRegistration{}, ErrOutOfRange
56 }
57 raw := message.GetIncarnation()
58 if len(raw) != len(registration.Incarnation) {
59 return domain.RemoteRegistration{}, ErrOutOfRange
60 }
61 copy(registration.Incarnation[:], raw)
62 registration.Generation = domain.RemoteGeneration(message.GetGeneration())
63 if err := registration.Validate(); err != nil {
64 return domain.RemoteRegistration{}, ErrOutOfRange
65 }
66 return registration, nil
67}
68
69func BrokerExactTargetToWire(target protocol.ExactSessionTarget) *wire.ExactTarget {
70 return &wire.ExactTarget{LifecycleId: &wire.LifecycleID{Value: append([]byte(nil), target.LifecycleID[:]...)}, SessionName: target.SessionName}
71}
72
73func BrokerExactTargetFromWire(message *wire.ExactTarget) (protocol.ExactSessionTarget, error) {
74 var target protocol.ExactSessionTarget
75 if message == nil {
76 return target, ErrOutOfRange
77 }
78 lifecycle := message.GetLifecycleId()
79 if lifecycle == nil || len(lifecycle.GetValue()) != len(target.LifecycleID) {
80 return protocol.ExactSessionTarget{}, ErrOutOfRange
81 }
82 copy(target.LifecycleID[:], lifecycle.GetValue())
83 target.SessionName = message.GetSessionName()
84 if err := target.Validate(); err != nil {
85 return protocol.ExactSessionTarget{}, ErrOutOfRange
86 }
87 return target, nil
88}
89
90func BrokerPolicyToWire(policy ports.BrokerPolicy) *wire.BrokerWirePolicy {
91 return &wire.BrokerWirePolicy{ProtocolVersion: uint32(policy.ProtocolVersion), CatalogueVersion: uint32(policy.CatalogSchemaVersion), EnvironmentPolicy: uint32(policy.EnvironmentPolicy), Transport: policy.Transport, Trust: policy.Trust, Launch: policy.Launch, Isolation: policy.Isolation}
92}
93
94func BrokerPolicyFromWire(message *wire.BrokerWirePolicy) (ports.BrokerPolicy, error) {
95 if message == nil {
96 return ports.BrokerPolicy{}, ErrOutOfRange
97 }
98 version, err := Uint16[uint16](message.GetProtocolVersion())
99 if err != nil {
100 return ports.BrokerPolicy{}, err
101 }
102 catalogue, err := Uint16[uint16](message.GetCatalogueVersion())
103 if err != nil {
104 return ports.BrokerPolicy{}, err
105 }
106 env, err := Uint8[protocol.EnvironmentPolicy](message.GetEnvironmentPolicy())
107 if err != nil {
108 return ports.BrokerPolicy{}, err
109 }
110 policy := ports.BrokerPolicy{ProtocolVersion: version, CatalogSchemaVersion: catalogue, EnvironmentPolicy: env, Transport: message.GetTransport(), Trust: message.GetTrust(), Launch: message.GetLaunch(), Isolation: message.GetIsolation()}
111 if err := policy.Validate(); err != nil {
112 return ports.BrokerPolicy{}, ErrInvalid
113 }
114 return policy, nil
115}
116
117func BrokerDisplayText(value string, maxBytes int) error {
118 if len(value) > maxBytes {
119 return ErrTooLarge
120 }
121 if !utf8.ValidString(value) {
122 return ErrInvalid
123 }
124 for _, r := range value {
125 if unicode.IsControl(r) || unicode.Is(unicode.Bidi_Control, r) || r == '\u2028' || r == '\u2029' {
126 return ErrInvalid
127 }
128 }
129 return nil
130}
131
132func BrokerEnvEntry(entry string) error {
133 if len(entry) > ports.BrokerMaxEnvEntryBytes {
134 return ErrTooLarge
135 }
136 if !utf8.ValidString(entry) || strings.ContainsRune(entry, 0) {
137 return ErrInvalid
138 }
139 return nil
140}
141
142func BrokerEnvEntries(env []string) error {
143 if len(env) > ports.BrokerMaxEnvEntries {
144 return ErrTooLarge
145 }
146 for _, entry := range env {
147 if err := BrokerEnvEntry(entry); err != nil {
148 return err
149 }
150 if !strings.Contains(entry, "=") {
151 return ErrInvalid
152 }
153 }
154 return nil
155}