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