1package sessionwire
2
3import (
4 "math"
5
6 "github.com/bnema/vev/internal/domain"
7 "github.com/bnema/vev/internal/protocol"
8 "github.com/bnema/vev/internal/protocol/wire"
9)
10
11func inputToWire(message protocol.Input) *wire.Input {
12 return &wire.Input{InputSeq: message.InputSeq, ActionId: message.ActionID, Data: append([]byte(nil), message.Data...)}
13}
14
15func inputFromWire(message *wire.Input) (protocol.Input, error) {
16 if message == nil {
17 return protocol.Input{}, errProtoConvertRange
18 }
19 return protocol.Input{InputSeq: message.GetInputSeq(), ActionID: message.GetActionId(), Data: append([]byte(nil), message.GetData()...)}, nil
20}
21
22func resizeToWire(message protocol.Resize) (*wire.Resize, error) {
23 cols, rows, pixelWidth, pixelHeight, err := geometryToWire(message.Size, message.PixelWidth, message.PixelHeight)
24 if err != nil {
25 return nil, err
26 }
27 if err := protocol.ValidateGeometry(domain.Geometry{Size: message.Size, PixelWidth: message.PixelWidth, PixelHeight: message.PixelHeight}); err != nil {
28 return nil, err
29 }
30 return &wire.Resize{Cols: cols, Rows: rows, PixelWidth: pixelWidth, PixelHeight: pixelHeight}, nil
31}
32
33func resizeFromWire(message *wire.Resize) (protocol.Resize, error) {
34 var resize protocol.Resize
35 if message == nil {
36 return resize, errProtoConvertRange
37 }
38 cols, err := mustUint16(message.GetCols())
39 if err != nil {
40 return protocol.Resize{}, err
41 }
42 rows, err := mustUint16(message.GetRows())
43 if err != nil {
44 return protocol.Resize{}, err
45 }
46 pixelWidth, err := mustUint16(message.GetPixelWidth())
47 if err != nil {
48 return protocol.Resize{}, err
49 }
50 pixelHeight, err := mustUint16(message.GetPixelHeight())
51 if err != nil {
52 return protocol.Resize{}, err
53 }
54 resize = protocol.Resize{Size: domain.Size{Cols: int(cols), Rows: int(rows)}, PixelWidth: int(pixelWidth), PixelHeight: int(pixelHeight)}
55 if err := protocol.ValidateGeometry(domain.Geometry{Size: resize.Size, PixelWidth: resize.PixelWidth, PixelHeight: resize.PixelHeight}); err != nil {
56 return protocol.Resize{}, err
57 }
58 return resize, nil
59}
60
61func themeToWire(message protocol.Theme) *wire.Theme {
62 palette := make([]*wire.RGB, 0, len(message.Palette))
63 for _, color := range message.Palette {
64 color := color
65 palette = append(palette, rgbToWire(color))
66 }
67 return &wire.Theme{
68 HasForeground: message.HasForeground,
69 Foreground: rgbToWire(message.Foreground),
70 HasBackground: message.HasBackground,
71 Background: rgbToWire(message.Background),
72 TrueColor: message.TrueColor,
73 SchemeKnown: message.SchemeKnown,
74 Light: message.Light,
75 PaletteKnown: uint32(message.PaletteKnown),
76 Palette: palette,
77 }
78}
79
80func themeFromWire(message *wire.Theme) (protocol.Theme, error) {
81 var theme protocol.Theme
82 if message == nil {
83 return theme, errProtoConvertRange
84 }
85 if len(message.GetPalette()) != len(theme.Palette) {
86 return protocol.Theme{}, errProtoConvertRange
87 }
88 foreground, err := rgbFromWire(message.GetForeground())
89 if err != nil {
90 return protocol.Theme{}, err
91 }
92 background, err := rgbFromWire(message.GetBackground())
93 if err != nil {
94 return protocol.Theme{}, err
95 }
96 theme.HasForeground = message.GetHasForeground()
97 theme.Foreground = foreground
98 theme.HasBackground = message.GetHasBackground()
99 theme.Background = background
100 theme.TrueColor = message.GetTrueColor()
101 theme.SchemeKnown = message.GetSchemeKnown()
102 theme.Light = message.GetLight()
103 known := message.GetPaletteKnown()
104 if known > 0xFFFF {
105 return protocol.Theme{}, errProtoConvertRange
106 }
107 theme.PaletteKnown = uint16(known)
108 for i, color := range message.GetPalette() {
109 converted, err := rgbFromWire(color)
110 if err != nil {
111 return protocol.Theme{}, err
112 }
113 theme.Palette[i] = converted
114 }
115 return theme, nil
116}
117
118func ackToWire(message protocol.Ack) (*wire.Ack, error) {
119 if err := protocol.ValidateAck(message); err != nil {
120 return nil, err
121 }
122 return &wire.Ack{Epoch: message.Epoch, State: message.State}, nil
123}
124
125func ackFromWire(message *wire.Ack) (protocol.Ack, error) {
126 if message == nil {
127 return protocol.Ack{}, protocol.ErrInvalidAck
128 }
129 ack := protocol.Ack{Epoch: message.GetEpoch(), State: message.GetState()}
130 if err := protocol.ValidateAck(ack); err != nil {
131 return protocol.Ack{}, err
132 }
133 return ack, nil
134}
135
136func imagePushToWire(message protocol.ImagePush) *wire.ImagePush {
137 return &wire.ImagePush{InputSeq: message.InputSeq, Mime: message.Mime, Data: append([]byte(nil), message.Data...)}
138}
139
140func imagePushFromWire(message *wire.ImagePush) (protocol.ImagePush, error) {
141 if message == nil {
142 return protocol.ImagePush{}, errProtoConvertRange
143 }
144 return protocol.ImagePush{InputSeq: message.GetInputSeq(), Mime: message.GetMime(), Data: append([]byte(nil), message.GetData()...)}, nil
145}
146
147func clientNoticeToWire(message protocol.ClientNotice) (*wire.ClientNotice, error) {
148 if err := protocol.ValidateClientNotice(message); err != nil {
149 return nil, err
150 }
151 return &wire.ClientNotice{Action: uint32(message.Action)}, nil
152}
153
154func clientNoticeFromWire(message *wire.ClientNotice) (protocol.ClientNotice, error) {
155 if message == nil {
156 return protocol.ClientNotice{}, protocol.ErrInvalidClientNotice
157 }
158 action, err := mustUint8(message.GetAction())
159 if err != nil {
160 return protocol.ClientNotice{}, protocol.ErrInvalidClientNotice
161 }
162 notice := protocol.ClientNotice{Action: action}
163 if err := protocol.ValidateClientNotice(notice); err != nil {
164 return protocol.ClientNotice{}, err
165 }
166 return notice, nil
167}
168
169func detachedToWire(message protocol.Detached) (*wire.Detached, error) {
170 if err := protocol.ValidateDetached(message); err != nil {
171 return nil, err
172 }
173 return &wire.Detached{Reason: uint32(message.Reason)}, nil
174}
175
176func detachedFromWire(message *wire.Detached) (protocol.Detached, error) {
177 if message == nil {
178 return protocol.Detached{}, protocol.ErrInvalidDetached
179 }
180 reason, err := mustUint8(message.GetReason())
181 if err != nil {
182 return protocol.Detached{}, protocol.ErrInvalidDetached
183 }
184 detached := protocol.Detached{Reason: reason}
185 if err := protocol.ValidateDetached(detached); err != nil {
186 return protocol.Detached{}, err
187 }
188 return detached, nil
189}
190
191func killToWire(message protocol.Kill) *wire.Kill {
192 return &wire.Kill{Name: message.Name, Scope: uint32(message.Scope), RequestId: message.RequestID}
193}
194
195func killFromWire(message *wire.Kill) (protocol.Kill, error) {
196 if message == nil {
197 return protocol.Kill{}, errProtoConvertRange
198 }
199 scope, err := enum8[protocol.KillScope](message.GetScope())
200 if err != nil {
201 return protocol.Kill{}, err
202 }
203 if scope != protocol.KillSession && scope != protocol.KillDaemon && scope != protocol.KillAll {
204 return protocol.Kill{}, errProtoConvertRange
205 }
206 if message.GetRequestId() == 0 {
207 return protocol.Kill{}, errProtoConvertRange
208 }
209 return protocol.Kill{RequestID: message.GetRequestId(), Name: message.GetName(), Scope: scope}, nil
210}
211
212func killResultToWire(message protocol.KillResult) *wire.KillResult {
213 out := &wire.KillResult{RequestId: message.RequestID, Outcome: uint32(message.Outcome), Code: uint32(message.Code), Text: message.Text}
214 for _, failure := range message.Failures {
215 out.Failures = append(out.Failures, &wire.KillFailure{Class: failure.Class, Name: failure.Name, Text: failure.Text})
216 }
217 return out
218}
219
220func killResultFromWire(message *wire.KillResult) (protocol.KillResult, error) {
221 if message == nil || message.GetRequestId() == 0 || message.GetOutcome() < uint32(protocol.KillSucceeded) || message.GetOutcome() > uint32(protocol.KillOutcomeUnknown) {
222 return protocol.KillResult{}, errProtoConvertRange
223 }
224 code, err := mustUint16(message.GetCode())
225 if err != nil {
226 return protocol.KillResult{}, err
227 }
228 out := protocol.KillResult{RequestID: message.GetRequestId(), Outcome: protocol.KillOutcome(message.GetOutcome()), Code: code, Text: message.GetText()}
229 for _, failure := range message.GetFailures() {
230 if failure == nil {
231 return protocol.KillResult{}, errProtoConvertRange
232 }
233 out.Failures = append(out.Failures, protocol.KillFailure{Class: failure.GetClass(), Name: failure.GetName(), Text: failure.GetText()})
234 }
235 return out, nil
236}
237
238func sessionsToWire(message protocol.Sessions) *wire.Sessions {
239 out := &wire.Sessions{}
240 for _, info := range message.Sessions {
241 out.Sessions = append(out.Sessions, &wire.SessionInfo{
242 SessionId: info.SessionID,
243 Name: info.Name,
244 State: uint32(info.State),
245 Ephemeral: info.Ephemeral,
246 Tabs: uint32(info.Tabs),
247 Attached: info.Attached,
248 })
249 }
250 return out
251}
252
253func sessionsFromWire(message *wire.Sessions) (protocol.Sessions, error) {
254 var sessions protocol.Sessions
255 if message == nil {
256 return sessions, nil
257 }
258 for _, info := range message.GetSessions() {
259 tabs := info.GetTabs()
260 if tabs > 0xFFFF {
261 return protocol.Sessions{}, errProtoConvertRange
262 }
263 state, err := enum8[protocol.SessionState](info.GetState())
264 if err != nil {
265 return protocol.Sessions{}, err
266 }
267 sessions.Sessions = append(sessions.Sessions, protocol.SessionInfo{
268 SessionID: info.GetSessionId(),
269 Name: info.GetName(),
270 State: state,
271 Ephemeral: info.GetEphemeral(),
272 Tabs: uint16(tabs),
273 Attached: info.GetAttached(),
274 })
275 }
276 return sessions, nil
277}
278
279func errorToWire(message protocol.ErrorMsg) *wire.ErrorMsg {
280 return &wire.ErrorMsg{Code: uint32(message.Code), Text: message.Text}
281}
282
283func errorFromWire(message *wire.ErrorMsg) (protocol.ErrorMsg, error) {
284 if message == nil {
285 return protocol.ErrorMsg{}, errProtoConvertRange
286 }
287 code, err := mustUint16(message.GetCode())
288 if err != nil {
289 return protocol.ErrorMsg{}, err
290 }
291 return protocol.ErrorMsg{Code: code, Text: message.GetText()}, nil
292}
293
294func commandResultToWire(message protocol.CommandResult) (*wire.CommandResult, error) {
295 if !message.Valid() {
296 return nil, errProtoConvertRange
297 }
298 return &wire.CommandResult{RequestId: message.RequestID, Outcome: wire.CommandOutcome(message.Outcome), Code: uint32(message.Code), Text: message.Text, Output: message.Output}, nil
299}
300
301func commandResultFromWire(message *wire.CommandResult) (protocol.CommandResult, error) {
302 // The outcome is narrowed through a closed-range check before the cast:
303 // a 32-bit wire value whose low byte would otherwise truncate into a valid
304 // outcome (257 -> Succeeded, 259 -> Unknown) is refused, not aliased.
305 if message == nil || message.GetOutcome() < wire.CommandOutcome_COMMAND_OUTCOME_SUCCEEDED || message.GetOutcome() > wire.CommandOutcome_COMMAND_OUTCOME_UNKNOWN {
306 return protocol.CommandResult{}, errProtoConvertRange
307 }
308 code, err := mustUint16(message.GetCode())
309 if err != nil {
310 return protocol.CommandResult{}, err
311 }
312 result := protocol.CommandResult{RequestID: message.GetRequestId(), Outcome: protocol.CommandOutcome(message.GetOutcome()), Code: code, Text: message.GetText(), Output: message.GetOutput()}
313 if !result.Valid() {
314 return protocol.CommandResult{}, errProtoConvertRange
315 }
316 return result, nil
317}
318
319func uiFenceToWire(message protocol.UIFence) *wire.UIFence {
320 return &wire.UIFence{ActionId: message.ActionID}
321}
322
323func uiFenceFromWire(message *wire.UIFence) (protocol.UIFence, error) {
324 if message == nil {
325 return protocol.UIFence{}, errProtoConvertRange
326 }
327 return protocol.UIFence{ActionID: message.GetActionId()}, nil
328}
329
330func selectTabToWire(message protocol.SelectTab) (*wire.SelectTab, error) {
331 if err := message.Validate(); err != nil {
332 return nil, err
333 }
334 return &wire.SelectTab{TabId: string(message.TabID)}, nil
335}
336
337func terminalFocusToWire(message protocol.TerminalFocus) (*wire.TerminalFocus, error) {
338 if err := message.Validate(); err != nil {
339 return nil, err
340 }
341 return &wire.TerminalFocus{Focus: uint32(message.Focus)}, nil
342}
343
344func terminalFocusFromWire(message *wire.TerminalFocus) (protocol.TerminalFocus, error) {
345 if message == nil || message.GetFocus() > math.MaxUint8 {
346 return protocol.TerminalFocus{}, errProtoConvertRange
347 }
348 focus := protocol.TerminalFocus{Focus: domain.TerminalFocus(message.GetFocus())}
349 if err := focus.Validate(); err != nil {
350 return protocol.TerminalFocus{}, err
351 }
352 return focus, nil
353}
354
355func selectTabFromWire(message *wire.SelectTab) (protocol.SelectTab, error) {
356 if message == nil {
357 return protocol.SelectTab{}, errProtoConvertRange
358 }
359 selected := protocol.SelectTab{TabID: domain.TabStableID(message.GetTabId())}
360 if err := selected.Validate(); err != nil {
361 return protocol.SelectTab{}, err
362 }
363 return selected, nil
364}
365
366func uiReceiptToWire(message protocol.UIReceipt) (*wire.UIReceipt, error) {
367 if err := message.Validate(); err != nil {
368 return nil, err
369 }
370 return &wire.UIReceipt{ActionId: message.ActionID, Epoch: message.Epoch, State: message.State, ViewPublication: message.ViewPublication, Outcome: uint32(message.Outcome)}, nil
371}
372
373func uiReceiptFromWire(message *wire.UIReceipt) (protocol.UIReceipt, error) {
374 if message == nil {
375 return protocol.UIReceipt{}, errProtoConvertRange
376 }
377 outcome, err := enum8[protocol.UIReceiptOutcome](message.GetOutcome())
378 if err != nil {
379 return protocol.UIReceipt{}, err
380 }
381 receipt := protocol.UIReceipt{
382 ActionID: message.GetActionId(),
383 Epoch: message.GetEpoch(),
384 State: message.GetState(),
385 ViewPublication: message.GetViewPublication(),
386 Outcome: outcome,
387 }
388 if err := receipt.Validate(); err != nil {
389 return protocol.UIReceipt{}, err
390 }
391 return receipt, nil
392}
393
394func uiViewUpdateToWire(message protocol.UIViewUpdate) (*wire.UIViewUpdate, error) {
395 context, err := viewContextToWire(message.Context)
396 if err != nil {
397 return nil, err
398 }
399 return &wire.UIViewUpdate{Epoch: message.Epoch, State: message.State, Context: context}, nil
400}
401
402func uiViewUpdateFromWire(message *wire.UIViewUpdate) (protocol.UIViewUpdate, error) {
403 if message == nil {
404 return protocol.UIViewUpdate{}, errProtoConvertRange
405 }
406 context, err := viewContextFromWire(message.GetContext())
407 if err != nil {
408 return protocol.UIViewUpdate{}, err
409 }
410 return protocol.UIViewUpdate{Epoch: message.GetEpoch(), State: message.GetState(), Context: context}, nil
411}