refactor(protocol): isolate binary wire encoding (#228)
* refactor(protocol): isolate binary wire encoding * docs(architecture): record wire module ownership * docs(architecture): correct wire layer map
- commit
- f791584fd55cd239e4484d7ada11e6b587ec64ec
- author
- bnema · · 2026-08-28 13:03 UTC
- committer
- GitHub · · 2026-08-28 13:03 UTC
- parent
- b21386d
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
137 files · +1868 -1790
M AGENTS.md +4 -2
| @@ -37,7 +37,9 @@ Hexagonal boundaries are enforced by `boundary_test.go`. | |||
| 37 | 37 | Layer map: | |
| 38 | 38 | ||
| 39 | 39 | - `main.go` → `internal/app`: CLI parsing, wiring, daemon startup, hidden subcommands. | |
| 40 | - | - `internal/ports`: interfaces and wire protocol. | |
| 40 | + | - `internal/ports`: application and raw carriage interfaces. | |
| 41 | + | - `internal/protocol`: typed transport-neutral messages and negotiated session policy. | |
| 42 | + | - `internal/protocol/wire`: message IDs, frames, strict binary codecs, compression, and encoded bounds. | |
| 41 | 43 | - `internal/usecase/daemon`: sessions, tabs, panes, VT screens, renderer shadows, daemon features. | |
| 42 | 44 | - `internal/usecase/client`: raw-mode thin client; writes output bytes verbatim and interprets nothing. | |
| 43 | 45 | - `internal/adapters`: IPC, SSH stdio, PTY, terminal, and clock implementations. | |
| @@ -61,7 +63,7 @@ Before touching daemon teardown paths, read the lock-ordering notes at the top o | |||
| 61 | 63 | ||
| 62 | 64 | ## Wire protocol | |
| 63 | 65 | ||
| 64 | - | Semantic presentation, route, and session-control values live in `internal/protocol`. Frame IDs and codecs live in `internal/ports/frame.go`, `internal/ports/wire.go`, `internal/ports/routes_wire.go`, and `internal/ports/wire_command.go`. Connection framing lives in `internal/adapters/ipc/transport.go`. | |
| 66 | + | Typed messages and negotiated version live in `internal/protocol`. Message IDs, frames, strict codecs, compression, and encoded bounds live in `internal/protocol/wire`; raw carriage interfaces remain in `internal/ports`. Connection framing lives in concrete carriage adapters such as `internal/adapters/ipc`. | |
| 65 | 67 | ||
| 66 | 68 | - IPC frames on a connection are 4-byte big-endian length, 1 type byte, then payload. | |
| 67 | 69 | - Client message types occupy `1–13`, `15`, `32–33`, and `35` (`MsgParkedRouteRequest`); server types occupy `16–23`, `25–31`, `34`, and `36` (`MsgParkedRouteResponse`). Types `14` and `24` remain reserved. | |
M internal/adapters/dgram/control_plane_test.go +5 -4
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | 10 | "time" | |
| 11 | 11 | ||
| 12 | 12 | "github.com/bnema/vev/internal/ports" | |
| 13 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 14 | pdgram "github.com/bnema/vev/pkg/dgram" | |
| 14 | 15 | ) | |
| 15 | 16 | ||
| @@ -81,7 +82,7 @@ func TestReadLoopDoesNotWriteACKSynchronously(t *testing.T) { | |||
| 81 | 82 | a.diagnosticCh = make(chan Diagnostic, 1) | |
| 82 | 83 | a.mu.Unlock() | |
| 83 | 84 | ||
| 84 | - | if err := b.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("first")}); err != nil { | |
| 85 | + | if err := b.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("first")}); err != nil { | |
| 85 | 86 | t.Fatal(err) | |
| 86 | 87 | } | |
| 87 | 88 | awaitSignal(t, contacts, "first authenticated record") | |
| @@ -92,7 +93,7 @@ func TestReadLoopDoesNotWriteACKSynchronously(t *testing.T) { | |||
| 92 | 93 | awaitSignal(t, ackStarted, "blocked ACK") | |
| 93 | 94 | ||
| 94 | 95 | clk.advance(time.Second) | |
| 95 | - | if err := b.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("second")}); err != nil { | |
| 96 | + | if err := b.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("second")}); err != nil { | |
| 96 | 97 | t.Fatal(err) | |
| 97 | 98 | } | |
| 98 | 99 | awaitSignal(t, contacts, "second authenticated record while ACK write is blocked") | |
| @@ -471,7 +472,7 @@ func TestHeartbeatContinuesDuringRetransmitStorm(t *testing.T) { | |||
| 471 | 472 | a.mu.Lock() | |
| 472 | 473 | for seq := uint64(1); seq <= 64; seq++ { | |
| 473 | 474 | a.pending[seq] = &pending{ | |
| 474 | - | frame: ports.Frame{Type: ports.MsgInput, Payload: make([]byte, 24*a.mtu)}, | |
| 475 | + | frame: wire.Frame{Type: wire.MsgInput, Payload: make([]byte, 24*a.mtu)}, | |
| 475 | 476 | enqueued: now.Add(-time.Second), first: now.Add(-time.Second), last: now.Add(-time.Second), | |
| 476 | 477 | } | |
| 477 | 478 | } | |
| @@ -515,7 +516,7 @@ func TestHealthChecksContinueDuringRetransmitStorm(t *testing.T) { | |||
| 515 | 516 | now := clk.Now() | |
| 516 | 517 | a.mu.Lock() | |
| 517 | 518 | a.pending[1] = &pending{ | |
| 518 | - | frame: ports.Frame{Type: ports.MsgInput, Payload: make([]byte, 24*a.mtu)}, | |
| 519 | + | frame: wire.Frame{Type: wire.MsgInput, Payload: make([]byte, 24*a.mtu)}, | |
| 519 | 520 | enqueued: now.Add(-time.Second), first: now.Add(-time.Second), last: now.Add(-time.Second), | |
| 520 | 521 | } | |
| 521 | 522 | a.mu.Unlock() | |
M internal/adapters/dgram/diagnostics_test.go +3 -2
| @@ -6,6 +6,7 @@ import ( | |||
| 6 | 6 | "time" | |
| 7 | 7 | ||
| 8 | 8 | "github.com/bnema/vev/internal/ports" | |
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 9 | 10 | ) | |
| 10 | 11 | ||
| 11 | 12 | func TestDiagnosticSnapshotSeparatesProgressAges(t *testing.T) { | |
| @@ -20,8 +21,8 @@ func TestDiagnosticSnapshotSeparatesProgressAges(t *testing.T) { | |||
| 20 | 21 | retransmits: 64, | |
| 21 | 22 | reassemblyInflight: 2, | |
| 22 | 23 | pending: map[uint64]*pending{ | |
| 23 | - | 1: {frame: ports.Frame{Payload: make([]byte, 7)}}, | |
| 24 | - | 2: {frame: ports.Frame{Payload: make([]byte, 11)}}, | |
| 24 | + | 1: {frame: wire.Frame{Payload: make([]byte, 7)}}, | |
| 25 | + | 2: {frame: wire.Frame{Payload: make([]byte, 11)}}, | |
| 25 | 26 | }, | |
| 26 | 27 | diagnosticCh: make(chan Diagnostic, diagnosticBufferSize), | |
| 27 | 28 | done: make(chan struct{}), | |
M internal/adapters/dgram/network_sim_test.go +7 -6
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | 12 | "github.com/bnema/vev/internal/domain" | |
| 13 | 13 | "github.com/bnema/vev/internal/ports" | |
| 14 | 14 | "github.com/bnema/vev/internal/protocol" | |
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 15 | 16 | pdgram "github.com/bnema/vev/pkg/dgram" | |
| 16 | 17 | ) | |
| 17 | 18 | ||
| @@ -454,7 +455,7 @@ func TestTransportFloodClassification(t *testing.T) { | |||
| 454 | 455 | } | |
| 455 | 456 | b.mu.Unlock() | |
| 456 | 457 | primer := mustMarshalOutput(protocol.Output{Epoch: 1, Base: 0, New: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("primer")}) | |
| 457 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: primer}); err != nil { | |
| 458 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: primer}); err != nil { | |
| 458 | 459 | t.Fatal(err) | |
| 459 | 460 | } | |
| 460 | 461 | awaitSignal(t, primerWritten, "primer write") | |
| @@ -537,7 +538,7 @@ func TestTransportFloodClassification(t *testing.T) { | |||
| 537 | 538 | Size: domain.Size{Cols: 1, Rows: 1}, | |
| 538 | 539 | Data: bytes.Repeat([]byte{byte(state + 1)}, outputDataBytes), | |
| 539 | 540 | }) | |
| 540 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: payload}); err != nil { | |
| 541 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: payload}); err != nil { | |
| 541 | 542 | t.Fatal(err) | |
| 542 | 543 | } | |
| 543 | 544 | } | |
| @@ -631,7 +632,7 @@ func TestTransportFloodClassification(t *testing.T) { | |||
| 631 | 632 | for { | |
| 632 | 633 | select { | |
| 633 | 634 | case frame := <-b.in: | |
| 634 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 635 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 635 | 636 | if err != nil { | |
| 636 | 637 | t.Fatal(err) | |
| 637 | 638 | } | |
| @@ -795,7 +796,7 @@ func TestTransportFloodClassification(t *testing.T) { | |||
| 795 | 796 | // A fresh record queues behind the sole data sender while control traffic | |
| 796 | 797 | // remains independent of congestion tokens and the blocked data write. | |
| 797 | 798 | go func() { | |
| 798 | - | freshReturned <- a.Send(ports.Frame{Type: ports.MsgOutput, Payload: floodOutputPayload(floodRecordCount, 128)}) | |
| 799 | + | freshReturned <- a.Send(wire.Frame{Type: wire.MsgOutput, Payload: floodOutputPayload(floodRecordCount, 128)}) | |
| 799 | 800 | }() | |
| 800 | 801 | select { | |
| 801 | 802 | case err := <-freshReturned: | |
| @@ -869,7 +870,7 @@ func TestFloodOutputPayloadIsIncrementalStateBearingOutput(t *testing.T) { | |||
| 869 | 870 | const mtu = 128 | |
| 870 | 871 | for state := range floodRecordCount { | |
| 871 | 872 | payload := floodOutputPayload(state, mtu) | |
| 872 | - | output, err := ports.UnmarshalOutput(payload) | |
| 873 | + | output, err := wire.UnmarshalOutput(payload) | |
| 873 | 874 | if err != nil { | |
| 874 | 875 | t.Fatalf("state %d: %v", state, err) | |
| 875 | 876 | } | |
| @@ -889,7 +890,7 @@ func TestFloodOutputPayloadIsIncrementalStateBearingOutput(t *testing.T) { | |||
| 889 | 890 | func sendFloodOutputs(t *testing.T, sender *Transport, count, mtu int) { | |
| 890 | 891 | t.Helper() | |
| 891 | 892 | for state := range count { | |
| 892 | - | if err := sender.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: floodOutputPayload(state, mtu)}); err != nil { | |
| 893 | + | if err := sender.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: floodOutputPayload(state, mtu)}); err != nil { | |
| 893 | 894 | t.Fatal(err) | |
| 894 | 895 | } | |
| 895 | 896 | } | |
M internal/adapters/dgram/output_pacer.go +4 -4
| @@ -1,11 +1,11 @@ | |||
| 1 | 1 | package dgram | |
| 2 | 2 | ||
| 3 | - | import "github.com/bnema/vev/internal/ports" | |
| 3 | + | import "github.com/bnema/vev/internal/protocol/wire" | |
| 4 | 4 | ||
| 5 | 5 | type dataSendJob struct { | |
| 6 | 6 | seq uint64 | |
| 7 | 7 | reliable bool | |
| 8 | - | frame ports.Frame | |
| 8 | + | frame wire.Frame | |
| 9 | 9 | done chan error | |
| 10 | 10 | } | |
| 11 | 11 | ||
| @@ -52,8 +52,8 @@ func (t *Transport) notifyOutputPacerLocked() { | |||
| 52 | 52 | t.outputWake = make(chan struct{}) | |
| 53 | 53 | } | |
| 54 | 54 | ||
| 55 | - | func shouldPaceOutput(f ports.Frame) bool { | |
| 56 | - | return f.Type == ports.MsgOutput | |
| 55 | + | func shouldPaceOutput(f wire.Frame) bool { | |
| 56 | + | return f.Type == wire.MsgOutput | |
| 57 | 57 | } | |
| 58 | 58 | ||
| 59 | 59 | func (t *Transport) markPendingSent(seq uint64, reliable bool) { | |
M internal/adapters/dgram/proxy.go +6 -5
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | 8 | "time" | |
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/vev/internal/ports" | |
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 11 | 12 | ) | |
| 12 | 13 | ||
| 13 | 14 | const ( | |
| @@ -50,7 +51,7 @@ type proxyCopyDirection struct { | |||
| 50 | 51 | dst ports.Transport | |
| 51 | 52 | recvKind proxyCopyErrKind | |
| 52 | 53 | sendKind proxyCopyErrKind | |
| 53 | - | transform func(ports.Frame) ports.Frame | |
| 54 | + | transform func(wire.Frame) wire.Frame | |
| 54 | 55 | retryRecoverable bool | |
| 55 | 56 | } | |
| 56 | 57 | ||
| @@ -211,15 +212,15 @@ func recoverableClientLink(t ports.Transport, err error) bool { | |||
| 211 | 212 | // clampDatagramHelloOutputWindow enforces the datagram-safe state window at | |
| 212 | 213 | // the adapter boundary. Invalid Hello payloads pass through unchanged so the | |
| 213 | 214 | // daemon remains the single authority for strict decoding and version checks. | |
| 214 | - | func clampDatagramHelloOutputWindow(f ports.Frame) ports.Frame { | |
| 215 | - | if f.Type != ports.MsgHello { | |
| 215 | + | func clampDatagramHelloOutputWindow(f wire.Frame) wire.Frame { | |
| 216 | + | if f.Type != wire.MsgHello { | |
| 216 | 217 | return f | |
| 217 | 218 | } | |
| 218 | - | hello, err := ports.UnmarshalHello(f.Payload) | |
| 219 | + | hello, err := wire.UnmarshalHello(f.Payload) | |
| 219 | 220 | if err != nil { | |
| 220 | 221 | return f | |
| 221 | 222 | } | |
| 222 | 223 | hello.MaxOutputInFlight = 1 | |
| 223 | - | f.Payload = ports.MarshalHello(hello) | |
| 224 | + | f.Payload = wire.MarshalHello(hello) | |
| 224 | 225 | return f | |
| 225 | 226 | } | |
M internal/adapters/dgram/proxy_test.go +28 -27
| @@ -13,11 +13,12 @@ import ( | |||
| 13 | 13 | "github.com/bnema/vev/internal/domain" | |
| 14 | 14 | "github.com/bnema/vev/internal/ports" | |
| 15 | 15 | "github.com/bnema/vev/internal/protocol" | |
| 16 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 16 | 17 | ) | |
| 17 | 18 | ||
| 18 | 19 | type fakeTransport struct { | |
| 19 | 20 | recv chan recvResult | |
| 20 | - | sent chan ports.Frame | |
| 21 | + | sent chan wire.Frame | |
| 21 | 22 | sendErr chan error | |
| 22 | 23 | linkState ports.LinkState | |
| 23 | 24 | linkEvents chan ports.LinkEvent | |
| @@ -26,14 +27,14 @@ type fakeTransport struct { | |||
| 26 | 27 | } | |
| 27 | 28 | ||
| 28 | 29 | type recvResult struct { | |
| 29 | - | frame ports.Frame | |
| 30 | + | frame wire.Frame | |
| 30 | 31 | err error | |
| 31 | 32 | } | |
| 32 | 33 | ||
| 33 | 34 | func newFakeTransport() *fakeTransport { | |
| 34 | - | return &fakeTransport{recv: make(chan recvResult, 4), sent: make(chan ports.Frame, 4), sendErr: make(chan error, 4), linkEvents: make(chan ports.LinkEvent, 4), linkState: ports.LinkStateConnected, closed: make(chan struct{})} | |
| 35 | + | return &fakeTransport{recv: make(chan recvResult, 4), sent: make(chan wire.Frame, 4), sendErr: make(chan error, 4), linkEvents: make(chan ports.LinkEvent, 4), linkState: ports.LinkStateConnected, closed: make(chan struct{})} | |
| 35 | 36 | } | |
| 36 | - | func (f *fakeTransport) Send(fr ports.Frame) error { | |
| 37 | + | func (f *fakeTransport) Send(fr wire.Frame) error { | |
| 37 | 38 | select { | |
| 38 | 39 | case err := <-f.sendErr: | |
| 39 | 40 | return err | |
| @@ -42,12 +43,12 @@ func (f *fakeTransport) Send(fr ports.Frame) error { | |||
| 42 | 43 | f.sent <- fr | |
| 43 | 44 | return nil | |
| 44 | 45 | } | |
| 45 | - | func (f *fakeTransport) Recv() (ports.Frame, error) { | |
| 46 | + | func (f *fakeTransport) Recv() (wire.Frame, error) { | |
| 46 | 47 | select { | |
| 47 | 48 | case r := <-f.recv: | |
| 48 | 49 | return r.frame, r.err | |
| 49 | 50 | case <-f.closed: | |
| 50 | - | return ports.Frame{}, io.EOF | |
| 51 | + | return wire.Frame{}, io.EOF | |
| 51 | 52 | } | |
| 52 | 53 | } | |
| 53 | 54 | func (f *fakeTransport) Close() error { | |
| @@ -62,10 +63,10 @@ func TestProxyRuntimeCopiesFramesAndDaemonEOFIsTerminal(t *testing.T) { | |||
| 62 | 63 | daemon := newFakeTransport() | |
| 63 | 64 | errCh := make(chan error, 1) | |
| 64 | 65 | go func() { errCh <- ProxyRuntime{Client: client, Daemon: daemon, IdleTTL: time.Hour}.Run(t.Context()) }() | |
| 65 | - | client.recv <- recvResult{frame: ports.Frame{Type: ports.MsgInput, Payload: []byte("x")}} | |
| 66 | + | client.recv <- recvResult{frame: wire.Frame{Type: wire.MsgInput, Payload: []byte("x")}} | |
| 66 | 67 | select { | |
| 67 | 68 | case got := <-daemon.sent: | |
| 68 | - | if got.Type != ports.MsgInput { | |
| 69 | + | if got.Type != wire.MsgInput { | |
| 69 | 70 | t.Fatalf("daemon got type %v", got.Type) | |
| 70 | 71 | } | |
| 71 | 72 | case <-time.After(time.Second): | |
| @@ -90,11 +91,11 @@ func TestProxyRuntimeClampsDatagramHelloOutputWindowAndPreservesControl(t *testi | |||
| 90 | 91 | errCh := make(chan error, 1) | |
| 91 | 92 | go func() { errCh <- ProxyRuntime{Client: client, Daemon: daemon, IdleTTL: time.Hour}.Run(t.Context()) }() | |
| 92 | 93 | hello := protocol.Hello{Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, MaxOutputInFlight: requested} | |
| 93 | - | client.recv <- recvResult{frame: ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(hello)}} | |
| 94 | + | client.recv <- recvResult{frame: wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(hello)}} | |
| 94 | 95 | ||
| 95 | 96 | select { | |
| 96 | 97 | case frame := <-daemon.sent: | |
| 97 | - | got, err := ports.UnmarshalHello(frame.Payload) | |
| 98 | + | got, err := wire.UnmarshalHello(frame.Payload) | |
| 98 | 99 | if err != nil { | |
| 99 | 100 | t.Fatal(err) | |
| 100 | 101 | } | |
| @@ -105,11 +106,11 @@ func TestProxyRuntimeClampsDatagramHelloOutputWindowAndPreservesControl(t *testi | |||
| 105 | 106 | t.Fatal("timeout waiting for proxied Hello") | |
| 106 | 107 | } | |
| 107 | 108 | ||
| 108 | - | input := ports.Frame{Type: ports.MsgInput, Payload: []byte("still flowing")} | |
| 109 | - | ack := ports.Frame{Type: ports.MsgAck, Payload: mustMarshalAck(protocol.Ack{Epoch: 1, State: 7})} | |
| 109 | + | input := wire.Frame{Type: wire.MsgInput, Payload: []byte("still flowing")} | |
| 110 | + | ack := wire.Frame{Type: wire.MsgAck, Payload: mustMarshalAck(protocol.Ack{Epoch: 1, State: 7})} | |
| 110 | 111 | client.recv <- recvResult{frame: input} | |
| 111 | 112 | client.recv <- recvResult{frame: ack} | |
| 112 | - | for _, want := range []ports.Frame{input, ack} { | |
| 113 | + | for _, want := range []wire.Frame{input, ack} { | |
| 113 | 114 | select { | |
| 114 | 115 | case got := <-daemon.sent: | |
| 115 | 116 | if !reflect.DeepEqual(got, want) { | |
| @@ -149,10 +150,10 @@ func TestProxyRuntimeRetriesRecoverableClientSendWithoutDroppingFrame(t *testing | |||
| 149 | 150 | errCh <- ProxyRuntime{Client: client, Daemon: daemon, IdleTTL: time.Hour, RetryBackoff: time.Nanosecond}.Run(t.Context()) | |
| 150 | 151 | }() | |
| 151 | 152 | client.sendErr <- tt.err | |
| 152 | - | daemon.recv <- recvResult{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("preserved during outage")}} | |
| 153 | + | daemon.recv <- recvResult{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("preserved during outage")}} | |
| 153 | 154 | select { | |
| 154 | 155 | case got := <-client.sent: | |
| 155 | - | if got.Type != ports.MsgOutput || string(got.Payload) != "preserved during outage" { | |
| 156 | + | if got.Type != wire.MsgOutput || string(got.Payload) != "preserved during outage" { | |
| 156 | 157 | t.Fatalf("client got %+v, want retried output", got) | |
| 157 | 158 | } | |
| 158 | 159 | case <-time.After(time.Second): | |
| @@ -187,10 +188,10 @@ func TestProxyRuntimeSurvivesPendingFullAndPreservesOrder(t *testing.T) { | |||
| 187 | 188 | const frames = 4 | |
| 188 | 189 | for i := range frames { | |
| 189 | 190 | client.sendErr <- ErrPendingFull | |
| 190 | - | daemon.recv <- recvResult{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}}} | |
| 191 | + | daemon.recv <- recvResult{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}}} | |
| 191 | 192 | select { | |
| 192 | 193 | case got := <-client.sent: | |
| 193 | - | if got.Type != ports.MsgOutput || len(got.Payload) != 1 || got.Payload[0] != byte(i) { | |
| 194 | + | if got.Type != wire.MsgOutput || len(got.Payload) != 1 || got.Payload[0] != byte(i) { | |
| 194 | 195 | t.Fatalf("frame %d delivered out of order or dropped: %+v", i, got) | |
| 195 | 196 | } | |
| 196 | 197 | case <-time.After(time.Second): | |
| @@ -378,7 +379,7 @@ func TestProxyRuntimeClientSendDeadWaitsForIdleTTL(t *testing.T) { | |||
| 378 | 379 | }() | |
| 379 | 380 | ||
| 380 | 381 | client.sendErr <- ErrLinkDead | |
| 381 | - | daemon.recv <- recvResult{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("client is gone")}} | |
| 382 | + | daemon.recv <- recvResult{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("client is gone")}} | |
| 382 | 383 | waitForProxyManualTimers(t, clk, 1) | |
| 383 | 384 | select { | |
| 384 | 385 | case err := <-errCh: | |
| @@ -443,14 +444,14 @@ func newRetryingOfflineTransport() *retryingOfflineTransport { | |||
| 443 | 444 | return &retryingOfflineTransport{closed: make(chan struct{}), firstSend: make(chan struct{})} | |
| 444 | 445 | } | |
| 445 | 446 | ||
| 446 | - | func (t *retryingOfflineTransport) Send(ports.Frame) error { | |
| 447 | + | func (t *retryingOfflineTransport) Send(wire.Frame) error { | |
| 447 | 448 | t.firstSendOnce.Do(func() { close(t.firstSend) }) | |
| 448 | 449 | return errors.New("offline") | |
| 449 | 450 | } | |
| 450 | 451 | ||
| 451 | - | func (t *retryingOfflineTransport) Recv() (ports.Frame, error) { | |
| 452 | + | func (t *retryingOfflineTransport) Recv() (wire.Frame, error) { | |
| 452 | 453 | <-t.closed | |
| 453 | - | return ports.Frame{}, io.EOF | |
| 454 | + | return wire.Frame{}, io.EOF | |
| 454 | 455 | } | |
| 455 | 456 | ||
| 456 | 457 | func (t *retryingOfflineTransport) Close() error { | |
| @@ -474,7 +475,7 @@ func TestProxyCopierStopsRetryingWhenContextCanceled(t *testing.T) { | |||
| 474 | 475 | close(done) | |
| 475 | 476 | }() | |
| 476 | 477 | ||
| 477 | - | daemon.recv <- recvResult{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("retry until cancel")}} | |
| 478 | + | daemon.recv <- recvResult{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("retry until cancel")}} | |
| 478 | 479 | select { | |
| 479 | 480 | case <-client.firstSend: | |
| 480 | 481 | case <-time.After(time.Second): | |
| @@ -490,23 +491,23 @@ func TestProxyCopierStopsRetryingWhenContextCanceled(t *testing.T) { | |||
| 490 | 491 | ||
| 491 | 492 | func TestClampDatagramHelloOutputWindowPreservesProtocolValidation(t *testing.T) { | |
| 492 | 493 | t.Run("malformed payload remains malformed", func(t *testing.T) { | |
| 493 | - | payload := append(ports.MarshalHello(protocol.Hello{Version: protocol.Version, Size: domain.Size{Cols: 80, Rows: 24}, MaxOutputInFlight: 8}), 0xff) | |
| 494 | - | frame := ports.Frame{Type: ports.MsgHello, Payload: payload} | |
| 494 | + | payload := append(wire.MarshalHello(protocol.Hello{Version: protocol.Version, Size: domain.Size{Cols: 80, Rows: 24}, MaxOutputInFlight: 8}), 0xff) | |
| 495 | + | frame := wire.Frame{Type: wire.MsgHello, Payload: payload} | |
| 495 | 496 | got := clampDatagramHelloOutputWindow(frame) | |
| 496 | 497 | if !reflect.DeepEqual(got, frame) { | |
| 497 | 498 | t.Fatalf("malformed Hello changed: got %#v, want %#v", got, frame) | |
| 498 | 499 | } | |
| 499 | - | if _, err := ports.UnmarshalHello(got.Payload); err == nil { | |
| 500 | + | if _, err := wire.UnmarshalHello(got.Payload); err == nil { | |
| 500 | 501 | t.Fatal("malformed Hello became decodable") | |
| 501 | 502 | } | |
| 502 | 503 | }) | |
| 503 | 504 | ||
| 504 | 505 | t.Run("mismatched version remains mismatched", func(t *testing.T) { | |
| 505 | 506 | wantVersion := protocol.Version + 1 | |
| 506 | - | frame := ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(protocol.Hello{ | |
| 507 | + | frame := wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(protocol.Hello{ | |
| 507 | 508 | Version: wantVersion, Size: domain.Size{Cols: 80, Rows: 24}, MaxOutputInFlight: 8, | |
| 508 | 509 | })} | |
| 509 | - | got, err := ports.UnmarshalHello(clampDatagramHelloOutputWindow(frame).Payload) | |
| 510 | + | got, err := wire.UnmarshalHello(clampDatagramHelloOutputWindow(frame).Payload) | |
| 510 | 511 | if err != nil { | |
| 511 | 512 | t.Fatal(err) | |
| 512 | 513 | } | |
M internal/adapters/dgram/transport.go +5 -4
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | 9 | "time" | |
| 10 | 10 | ||
| 11 | 11 | "github.com/bnema/vev/internal/ports" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 12 | 13 | pdgram "github.com/bnema/vev/pkg/dgram" | |
| 13 | 14 | ) | |
| 14 | 15 | ||
| @@ -221,7 +222,7 @@ type Transport struct { | |||
| 221 | 222 | recvMu sync.Mutex | |
| 222 | 223 | replay *pdgram.ReplayWindow | |
| 223 | 224 | reasm *pdgram.Reassembler | |
| 224 | - | in chan ports.Frame | |
| 225 | + | in chan wire.Frame | |
| 225 | 226 | done chan struct{} | |
| 226 | 227 | ||
| 227 | 228 | // Connection replacement takes writeMu, controlConnMu, then mu. Data writes | |
| @@ -257,11 +258,11 @@ type Transport struct { | |||
| 257 | 258 | deliverMu sync.Mutex | |
| 258 | 259 | deliverCond *sync.Cond | |
| 259 | 260 | nextRecvSeq uint64 | |
| 260 | - | recvBuf map[uint64]ports.Frame | |
| 261 | + | recvBuf map[uint64]wire.Frame | |
| 261 | 262 | } | |
| 262 | 263 | ||
| 263 | 264 | type pending struct { | |
| 264 | - | frame ports.Frame | |
| 265 | + | frame wire.Frame | |
| 265 | 266 | enqueued time.Time | |
| 266 | 267 | first time.Time | |
| 267 | 268 | last time.Time | |
| @@ -273,7 +274,7 @@ type pending struct { | |||
| 273 | 274 | ||
| 274 | 275 | type retransmitRecord struct { | |
| 275 | 276 | seq uint64 | |
| 276 | - | f ports.Frame | |
| 277 | + | f wire.Frame | |
| 277 | 278 | } | |
| 278 | 279 | ||
| 279 | 280 | type writeDeadlineState struct { | |
M internal/adapters/dgram/transport_health_test.go +11 -10
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | 10 | "time" | |
| 11 | 11 | ||
| 12 | 12 | "github.com/bnema/vev/internal/ports" | |
| 13 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 14 | pdgram "github.com/bnema/vev/pkg/dgram" | |
| 14 | 15 | ) | |
| 15 | 16 | ||
| @@ -32,7 +33,7 @@ func TestPortHopPreservesPendingReliableMessages(t *testing.T) { | |||
| 32 | 33 | defer func() { _ = a.Close() }() | |
| 33 | 34 | defer func() { _ = b.Close() }() | |
| 34 | 35 | ||
| 35 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("survive")}); err != nil { | |
| 36 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("survive")}); err != nil { | |
| 36 | 37 | t.Fatal(err) | |
| 37 | 38 | } | |
| 38 | 39 | a.mu.Lock() | |
| @@ -44,7 +45,7 @@ func TestPortHopPreservesPendingReliableMessages(t *testing.T) { | |||
| 44 | 45 | } | |
| 45 | 46 | aPC.drop = nil | |
| 46 | 47 | got := recvWithin(t, b, time.Second) | |
| 47 | - | if got.Type != ports.MsgInput || string(got.Payload) != "survive" { | |
| 48 | + | if got.Type != wire.MsgInput || string(got.Payload) != "survive" { | |
| 48 | 49 | t.Fatalf("got=%+v, want pending reliable message", got) | |
| 49 | 50 | } | |
| 50 | 51 | select { | |
| @@ -151,8 +152,8 @@ func TestRecvUnblocksWhenPeerDeadAfter(t *testing.T) { | |||
| 151 | 152 | func TestPendingAttemptsResetWhenLinkRecovers(t *testing.T) { | |
| 152 | 153 | tr, _ := newResendTestTransport(t, 10) | |
| 153 | 154 | tr.linkState = ports.LinkStateDegraded | |
| 154 | - | tr.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("stale")}, attempts: 4} | |
| 155 | - | tr.pending[2] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("stale")}, attempts: 7} | |
| 155 | + | tr.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("stale")}, attempts: 4} | |
| 156 | + | tr.pending[2] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("stale")}, attempts: 7} | |
| 156 | 157 | ||
| 157 | 158 | tr.setLinkState(ports.LinkStateConnected, nil) | |
| 158 | 159 | ||
| @@ -200,12 +201,12 @@ func TestPendingReliableQueueReturnsWhenLinkDegrades(t *testing.T) { | |||
| 200 | 201 | defer func() { _ = a.Close() }() | |
| 201 | 202 | defer func() { _ = b.Close() }() | |
| 202 | 203 | ||
| 203 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("first")}); err != nil { | |
| 204 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("first")}); err != nil { | |
| 204 | 205 | t.Fatal(err) | |
| 205 | 206 | } | |
| 206 | 207 | done := make(chan error, 2) | |
| 207 | - | go func() { done <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("second")}) }() | |
| 208 | - | go func() { done <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("third")}) }() | |
| 208 | + | go func() { done <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("second")}) }() | |
| 209 | + | go func() { done <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("third")}) }() | |
| 209 | 210 | waitForManualTimers(t, clk, 2) | |
| 210 | 211 | a.setLinkState(ports.LinkStateDegraded, nil) | |
| 211 | 212 | for i := range 2 { | |
| @@ -313,7 +314,7 @@ func TestLinkHealthPendingStallWithFreshContactProbesOnceWithoutDying(t *testing | |||
| 313 | 314 | now := time.Now() | |
| 314 | 315 | a.mu.Lock() | |
| 315 | 316 | a.health = healthTracker{lastPacket: now, lastRecord: now.Add(-time.Minute), lastProgress: now.Add(-time.Minute)} | |
| 316 | - | a.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput}, enqueued: now.Add(-time.Minute), attempts: 3} | |
| 317 | + | a.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput}, enqueued: now.Add(-time.Minute), attempts: 3} | |
| 317 | 318 | a.mu.Unlock() | |
| 318 | 319 | ||
| 319 | 320 | a.checkSilence() | |
| @@ -347,7 +348,7 @@ func TestLinkHealthHeartbeatControlCannotMaskPendingACKStall(t *testing.T) { | |||
| 347 | 348 | } | |
| 348 | 349 | defer func() { _ = tr.Close() }() | |
| 349 | 350 | defer func() { _ = bPC.Close() }() | |
| 350 | - | if err := tr.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("unacked")}); err != nil { | |
| 351 | + | if err := tr.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("unacked")}); err != nil { | |
| 351 | 352 | t.Fatal(err) | |
| 352 | 353 | } | |
| 353 | 354 | ||
| @@ -417,7 +418,7 @@ func TestLinkHealthOnlyAckProgressThatRemovesPendingRestoresConnected(t *testing | |||
| 417 | 418 | now := tr.clock.Now() | |
| 418 | 419 | tr.linkState = ports.LinkStateDegraded | |
| 419 | 420 | tr.health = healthTracker{lastPacket: now, lastRecord: now.Add(-time.Minute), lastProgress: now.Add(-time.Minute)} | |
| 420 | - | tr.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput}, first: now, last: now} | |
| 421 | + | tr.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput}, first: now, last: now} | |
| 421 | 422 | ||
| 422 | 423 | tr.handleRecord(ackRecord(1)) | |
| 423 | 424 | if got := tr.LinkState(); got != ports.LinkStateConnected { | |
M internal/adapters/dgram/transport_lifecycle.go +6 -5
| @@ -6,6 +6,7 @@ import ( | |||
| 6 | 6 | "sync" | |
| 7 | 7 | ||
| 8 | 8 | "github.com/bnema/vev/internal/ports" | |
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 9 | 10 | pdgram "github.com/bnema/vev/pkg/dgram" | |
| 10 | 11 | ) | |
| 11 | 12 | ||
| @@ -29,7 +30,7 @@ func NewTransportWithOptions(pc net.PacketConn, peer net.Addr, key []byte, sendD | |||
| 29 | 30 | pending: make(map[uint64]*pending), | |
| 30 | 31 | replay: pdgram.NewReplayWindow(), | |
| 31 | 32 | reasm: pdgram.NewReassembler(), | |
| 32 | - | in: make(chan ports.Frame, 32), | |
| 33 | + | in: make(chan wire.Frame, 32), | |
| 33 | 34 | done: make(chan struct{}), | |
| 34 | 35 | health: newHealthTracker(opts.Clock.Now()), | |
| 35 | 36 | lastAuthenticatedPacket: opts.Clock.Now(), | |
| @@ -56,7 +57,7 @@ func NewTransportWithOptions(pc net.PacketConn, peer net.Addr, key []byte, sendD | |||
| 56 | 57 | probeWait: make(map[uint64]chan struct{}), | |
| 57 | 58 | rebind: opts.RebindPacketConn, | |
| 58 | 59 | nextRecvSeq: 1, | |
| 59 | - | recvBuf: make(map[uint64]ports.Frame), | |
| 60 | + | recvBuf: make(map[uint64]wire.Frame), | |
| 60 | 61 | } | |
| 61 | 62 | for _, opt := range runtimeOpts { | |
| 62 | 63 | if opt != nil { | |
| @@ -90,7 +91,7 @@ func NewTransportWithOptions(pc net.PacketConn, peer net.Addr, key []byte, sendD | |||
| 90 | 91 | return t, nil | |
| 91 | 92 | } | |
| 92 | 93 | ||
| 93 | - | func (t *Transport) Recv() (ports.Frame, error) { | |
| 94 | + | func (t *Transport) Recv() (wire.Frame, error) { | |
| 94 | 95 | end := t.beginRuntimeOperation(ports.RuntimeAdapterReceiveStart, 0) | |
| 95 | 96 | select { | |
| 96 | 97 | case f := <-t.in: | |
| @@ -102,11 +103,11 @@ func (t *Transport) Recv() (ports.Frame, error) { | |||
| 102 | 103 | t.mu.Unlock() | |
| 103 | 104 | if err != nil { | |
| 104 | 105 | end(false) | |
| 105 | - | return ports.Frame{}, err | |
| 106 | + | return wire.Frame{}, err | |
| 106 | 107 | } | |
| 107 | 108 | err = errors.New("dgram: closed") | |
| 108 | 109 | end(false) | |
| 109 | - | return ports.Frame{}, err | |
| 110 | + | return wire.Frame{}, err | |
| 110 | 111 | } | |
| 111 | 112 | } | |
| 112 | 113 | ||
M internal/adapters/dgram/transport_observability_test.go +4 -3
| @@ -13,6 +13,7 @@ import ( | |||
| 13 | 13 | ||
| 14 | 14 | "github.com/bnema/vev/internal/adapters/observability" | |
| 15 | 15 | "github.com/bnema/vev/internal/ports" | |
| 16 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 16 | 17 | ) | |
| 17 | 18 | ||
| 18 | 19 | func TestTransportObservabilityDgramFailedCloseEndsReceiveAndSend(t *testing.T) { | |
| @@ -33,7 +34,7 @@ func TestTransportObservabilityDgramFailedCloseEndsReceiveAndSend(t *testing.T) | |||
| 33 | 34 | if err != nil { | |
| 34 | 35 | t.Fatalf("NewTransportWithOptions() error = %v", err) | |
| 35 | 36 | } | |
| 36 | - | if err := transport.Send(ports.Frame{Type: ports.MsgOutput, Payload: []byte("write failure")}); err == nil { | |
| 37 | + | if err := transport.Send(wire.Frame{Type: wire.MsgOutput, Payload: []byte("write failure")}); err == nil { | |
| 37 | 38 | t.Fatal("Send() error = nil on packet write failure") | |
| 38 | 39 | } | |
| 39 | 40 | recvDone := make(chan error, 1) | |
| @@ -155,11 +156,11 @@ func TestTransportObservabilityDgramKeepsBehaviorClockSeparate(t *testing.T) { | |||
| 155 | 156 | } | |
| 156 | 157 | defer func() { _ = b.Close() }() | |
| 157 | 158 | ||
| 158 | - | want := ports.Frame{Type: ports.MsgOutput, Payload: []byte("datagram carriage remains exact")} | |
| 159 | + | want := wire.Frame{Type: wire.MsgOutput, Payload: []byte("datagram carriage remains exact")} | |
| 159 | 160 | if err := a.Send(want); err != nil { | |
| 160 | 161 | t.Fatalf("Send() error = %v", err) | |
| 161 | 162 | } | |
| 162 | - | gotCh := make(chan ports.Frame, 1) | |
| 163 | + | gotCh := make(chan wire.Frame, 1) | |
| 163 | 164 | errCh := make(chan error, 1) | |
| 164 | 165 | go func() { | |
| 165 | 166 | frame, recvErr := b.Recv() | |
M internal/adapters/dgram/transport_receive.go +8 -7
| @@ -5,6 +5,7 @@ import ( | |||
| 5 | 5 | "net" | |
| 6 | 6 | ||
| 7 | 7 | "github.com/bnema/vev/internal/ports" | |
| 8 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 8 | 9 | pdgram "github.com/bnema/vev/pkg/dgram" | |
| 9 | 10 | ) | |
| 10 | 11 | ||
| @@ -176,7 +177,7 @@ func (t *Transport) handleRecord(p []byte) { | |||
| 176 | 177 | } | |
| 177 | 178 | } | |
| 178 | 179 | ||
| 179 | - | func (t *Transport) enqueueReliable(seq uint64, f ports.Frame) (ackSeq uint64, ack bool, queued bool) { | |
| 180 | + | func (t *Transport) enqueueReliable(seq uint64, f wire.Frame) (ackSeq uint64, ack bool, queued bool) { | |
| 180 | 181 | t.deliverMu.Lock() | |
| 181 | 182 | defer t.deliverMu.Unlock() | |
| 182 | 183 | if seq < t.nextRecvSeq { | |
| @@ -235,14 +236,14 @@ func (t *Transport) isClosed() bool { | |||
| 235 | 236 | return t.closed | |
| 236 | 237 | } | |
| 237 | 238 | ||
| 238 | - | func (t *Transport) deliver(f ports.Frame) { | |
| 239 | + | func (t *Transport) deliver(f wire.Frame) { | |
| 239 | 240 | select { | |
| 240 | 241 | case t.in <- f: | |
| 241 | 242 | case <-t.done: | |
| 242 | 243 | } | |
| 243 | 244 | } | |
| 244 | 245 | ||
| 245 | - | func encodeData(seq uint64, reliable bool, f ports.Frame) []byte { | |
| 246 | + | func encodeData(seq uint64, reliable bool, f wire.Frame) []byte { | |
| 246 | 247 | b := make([]byte, dataRecordHeaderSize+len(f.Payload)) | |
| 247 | 248 | b[0] = recData | |
| 248 | 249 | binary.BigEndian.PutUint64(b[1:9], seq) | |
| @@ -253,12 +254,12 @@ func encodeData(seq uint64, reliable bool, f ports.Frame) []byte { | |||
| 253 | 254 | copy(b[dataRecordHeaderSize:], f.Payload) | |
| 254 | 255 | return b | |
| 255 | 256 | } | |
| 256 | - | func decodeData(b []byte) (uint64, bool, ports.Frame, bool) { | |
| 257 | + | func decodeData(b []byte) (uint64, bool, wire.Frame, bool) { | |
| 257 | 258 | if len(b) < dataRecordHeaderSize || b[0] != recData { | |
| 258 | - | return 0, false, ports.Frame{}, false | |
| 259 | + | return 0, false, wire.Frame{}, false | |
| 259 | 260 | } | |
| 260 | 261 | if b[11] != 0 { | |
| 261 | - | return 0, false, ports.Frame{}, false | |
| 262 | + | return 0, false, wire.Frame{}, false | |
| 262 | 263 | } | |
| 263 | - | return binary.BigEndian.Uint64(b[1:9]), b[9] == 1, ports.Frame{Type: ports.MsgType(b[10]), Payload: append([]byte(nil), b[dataRecordHeaderSize:]...)}, true | |
| 264 | + | return binary.BigEndian.Uint64(b[1:9]), b[9] == 1, wire.Frame{Type: wire.MsgType(b[10]), Payload: append([]byte(nil), b[dataRecordHeaderSize:]...)}, true | |
| 264 | 265 | } | |
M internal/adapters/dgram/transport_receive_test.go +18 -17
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | 8 | "time" | |
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/vev/internal/ports" | |
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 11 | 12 | pdgram "github.com/bnema/vev/pkg/dgram" | |
| 12 | 13 | ) | |
| 13 | 14 | ||
| @@ -35,11 +36,11 @@ func TestReliableDuplicateAckedButNotDeliveredTwice(t *testing.T) { | |||
| 35 | 36 | t.Errorf("close b: %v", err) | |
| 36 | 37 | } | |
| 37 | 38 | }() | |
| 38 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("typed")}); err != nil { | |
| 39 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("typed")}); err != nil { | |
| 39 | 40 | t.Fatal(err) | |
| 40 | 41 | } | |
| 41 | 42 | got := recvWithin(t, b, time.Second) | |
| 42 | - | if got.Type != ports.MsgInput || string(got.Payload) != "typed" { | |
| 43 | + | if got.Type != wire.MsgInput || string(got.Payload) != "typed" { | |
| 43 | 44 | t.Fatalf("got=%+v", got) | |
| 44 | 45 | } | |
| 45 | 46 | eventually(t, time.Second, droppedAck.Load) | |
| @@ -70,7 +71,7 @@ func TestAuthenticatedPeerChangeUpdatesPeerAndEmitsConnected(t *testing.T) { | |||
| 70 | 71 | t.Fatalf("unauthenticated packet changed peer to %v", a.Peer()) | |
| 71 | 72 | } | |
| 72 | 73 | c, _ := pdgram.NewCodec(key()) | |
| 73 | - | rec := encodeData(7, true, ports.Frame{Type: ports.MsgPing}) | |
| 74 | + | rec := encodeData(7, true, wire.Frame{Type: wire.MsgPing}) | |
| 74 | 75 | frags, _ := pdgram.FragmentPayload(9, rec, pdgram.DefaultMTU) | |
| 75 | 76 | raw, _ := pdgram.MarshalFragment(frags[0]) | |
| 76 | 77 | aPC.in <- packet{c.Seal(2, 99, raw, nil), testAddr("evil")} | |
| @@ -214,12 +215,12 @@ func TestAuthenticatedFragmentSeparatesContactProgressAndPeerEligibility(t *test | |||
| 214 | 215 | } | |
| 215 | 216 | ||
| 216 | 217 | func TestReliableReceiveBufferDoesNotDropAckedFutureFrame(t *testing.T) { | |
| 217 | - | tr := &Transport{maxRecvBuffer: 1, nextRecvSeq: 1, recvBuf: make(map[uint64]ports.Frame)} | |
| 218 | - | _, ack, queued := tr.enqueueReliable(2, ports.Frame{Type: ports.MsgOutput, Payload: []byte("future")}) | |
| 218 | + | tr := &Transport{maxRecvBuffer: 1, nextRecvSeq: 1, recvBuf: make(map[uint64]wire.Frame)} | |
| 219 | + | _, ack, queued := tr.enqueueReliable(2, wire.Frame{Type: wire.MsgOutput, Payload: []byte("future")}) | |
| 219 | 220 | if !ack || !queued { | |
| 220 | 221 | t.Fatalf("future enqueue ack=%v queued=%v, want true/true", ack, queued) | |
| 221 | 222 | } | |
| 222 | - | _, ack, queued = tr.enqueueReliable(1, ports.Frame{Type: ports.MsgOutput, Payload: []byte("next")}) | |
| 223 | + | _, ack, queued = tr.enqueueReliable(1, wire.Frame{Type: wire.MsgOutput, Payload: []byte("next")}) | |
| 223 | 224 | if !ack || !queued { | |
| 224 | 225 | t.Fatalf("next enqueue ack=%v queued=%v, want true/true", ack, queued) | |
| 225 | 226 | } | |
| @@ -229,19 +230,19 @@ func TestReliableReceiveBufferDoesNotDropAckedFutureFrame(t *testing.T) { | |||
| 229 | 230 | } | |
| 230 | 231 | ||
| 231 | 232 | func TestDataRecordWireEncoding(t *testing.T) { | |
| 232 | - | got := encodeData(5, true, ports.Frame{Type: ports.MsgOutput, Payload: []byte("x")}) | |
| 233 | - | want := []byte{recData, 0, 0, 0, 0, 0, 0, 0, 5, 1, byte(ports.MsgOutput), 0, 'x'} | |
| 233 | + | got := encodeData(5, true, wire.Frame{Type: wire.MsgOutput, Payload: []byte("x")}) | |
| 234 | + | want := []byte{recData, 0, 0, 0, 0, 0, 0, 0, 5, 1, byte(wire.MsgOutput), 0, 'x'} | |
| 234 | 235 | if !bytes.Equal(got, want) { | |
| 235 | 236 | t.Fatalf("encoded data=%v, want %v", got, want) | |
| 236 | 237 | } | |
| 237 | 238 | seq, reliable, frame, ok := decodeData(got) | |
| 238 | - | if !ok || seq != 5 || !reliable || frame.Type != ports.MsgOutput || string(frame.Payload) != "x" { | |
| 239 | + | if !ok || seq != 5 || !reliable || frame.Type != wire.MsgOutput || string(frame.Payload) != "x" { | |
| 239 | 240 | t.Fatalf("decoded seq=%d reliable=%v frame=%+v ok=%v", seq, reliable, frame, ok) | |
| 240 | 241 | } | |
| 241 | 242 | } | |
| 242 | 243 | ||
| 243 | 244 | func TestDataRecordWireDecodeRejectsUnknownFlags(t *testing.T) { | |
| 244 | - | withTrailingGarbage := []byte{recData, 0, 0, 0, 0, 0, 0, 0, 5, 1, byte(ports.MsgOutput), 1, 'x'} | |
| 245 | + | withTrailingGarbage := []byte{recData, 0, 0, 0, 0, 0, 0, 0, 5, 1, byte(wire.MsgOutput), 1, 'x'} | |
| 245 | 246 | if _, _, _, ok := decodeData(withTrailingGarbage); ok { | |
| 246 | 247 | t.Fatal("decodeData accepted unknown data-record flags with trailing garbage") | |
| 247 | 248 | } | |
| @@ -255,13 +256,13 @@ func TestReliableDeliveryPreservesInputSequenceOrder(t *testing.T) { | |||
| 255 | 256 | defer func() { _ = b.Close() }() | |
| 256 | 257 | ||
| 257 | 258 | for i := range 100 { | |
| 258 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte{byte(i)}}); err != nil { | |
| 259 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte{byte(i)}}); err != nil { | |
| 259 | 260 | t.Fatal(err) | |
| 260 | 261 | } | |
| 261 | 262 | } | |
| 262 | 263 | for i := range 100 { | |
| 263 | 264 | got := recvWithin(t, b, time.Second) | |
| 264 | - | if got.Type != ports.MsgInput || len(got.Payload) != 1 || got.Payload[0] != byte(i) { | |
| 265 | + | if got.Type != wire.MsgInput || len(got.Payload) != 1 || got.Payload[0] != byte(i) { | |
| 265 | 266 | t.Fatalf("frame %d delivered out of order: %+v", i, got) | |
| 266 | 267 | } | |
| 267 | 268 | } | |
| @@ -275,7 +276,7 @@ func TestAckProcessingContinuesWhenConsumerBackpressured(t *testing.T) { | |||
| 275 | 276 | defer func() { _ = b.Close() }() | |
| 276 | 277 | ||
| 277 | 278 | for i := range cap(b.in) + 20 { | |
| 278 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}}); err != nil { | |
| 279 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}}); err != nil { | |
| 279 | 280 | t.Fatal(err) | |
| 280 | 281 | } | |
| 281 | 282 | } | |
| @@ -296,9 +297,9 @@ func TestAckProcessingContinuesWhenConsumerBackpressured(t *testing.T) { | |||
| 296 | 297 | } | |
| 297 | 298 | ||
| 298 | 299 | func TestReliableReceiverAcksOnlyHighestContiguousSequence(t *testing.T) { | |
| 299 | - | tr := &Transport{maxRecvBuffer: maxRecvBuffer, nextRecvSeq: 1, recvBuf: make(map[uint64]ports.Frame)} | |
| 300 | + | tr := &Transport{maxRecvBuffer: maxRecvBuffer, nextRecvSeq: 1, recvBuf: make(map[uint64]wire.Frame)} | |
| 300 | 301 | ||
| 301 | - | ackSeq, ack, queued := tr.enqueueReliable(3, ports.Frame{Type: ports.MsgOutput, Payload: []byte("third")}) | |
| 302 | + | ackSeq, ack, queued := tr.enqueueReliable(3, wire.Frame{Type: wire.MsgOutput, Payload: []byte("third")}) | |
| 302 | 303 | if !ack || !queued { | |
| 303 | 304 | t.Fatalf("out-of-order enqueue ack=%v queued=%v, want true/true", ack, queued) | |
| 304 | 305 | } | |
| @@ -306,7 +307,7 @@ func TestReliableReceiverAcksOnlyHighestContiguousSequence(t *testing.T) { | |||
| 306 | 307 | t.Fatalf("out-of-order ack=%d, want highest contiguous %d", got, want) | |
| 307 | 308 | } | |
| 308 | 309 | ||
| 309 | - | ackSeq, ack, queued = tr.enqueueReliable(1, ports.Frame{Type: ports.MsgOutput, Payload: []byte("first")}) | |
| 310 | + | ackSeq, ack, queued = tr.enqueueReliable(1, wire.Frame{Type: wire.MsgOutput, Payload: []byte("first")}) | |
| 310 | 311 | if !ack || !queued { | |
| 311 | 312 | t.Fatalf("first enqueue ack=%v queued=%v, want true/true", ack, queued) | |
| 312 | 313 | } | |
| @@ -314,7 +315,7 @@ func TestReliableReceiverAcksOnlyHighestContiguousSequence(t *testing.T) { | |||
| 314 | 315 | t.Fatalf("first contiguous ack=%d, want %d", got, want) | |
| 315 | 316 | } | |
| 316 | 317 | ||
| 317 | - | ackSeq, ack, queued = tr.enqueueReliable(2, ports.Frame{Type: ports.MsgOutput, Payload: []byte("second")}) | |
| 318 | + | ackSeq, ack, queued = tr.enqueueReliable(2, wire.Frame{Type: wire.MsgOutput, Payload: []byte("second")}) | |
| 318 | 319 | if !ack || !queued { | |
| 319 | 320 | t.Fatalf("gap fill enqueue ack=%v queued=%v, want true/true", ack, queued) | |
| 320 | 321 | } | |
M internal/adapters/dgram/transport_replay_test.go +3 -3
| @@ -3,13 +3,13 @@ package dgram | |||
| 3 | 3 | import ( | |
| 4 | 4 | "testing" | |
| 5 | 5 | ||
| 6 | - | "github.com/bnema/vev/internal/ports" | |
| 6 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 7 | 7 | "github.com/bnema/vev/internal/testutil/replaytest" | |
| 8 | 8 | "github.com/stretchr/testify/require" | |
| 9 | 9 | ) | |
| 10 | 10 | ||
| 11 | 11 | func TestTransportReplay(t *testing.T) { | |
| 12 | - | replaytest.Run(t, func(t *testing.T, frames []ports.Frame) []ports.Frame { | |
| 12 | + | replaytest.Run(t, func(t *testing.T, frames []wire.Frame) []wire.Frame { | |
| 13 | 13 | link := newSimulatedLink(fixedClock{}, packetPolicy{}) | |
| 14 | 14 | leftPC, rightPC := newPairWithCapacity(link, 32) | |
| 15 | 15 | left, err := NewTransport(leftPC, testAddr("b"), key(), 1, 2) | |
| @@ -18,7 +18,7 @@ func TestTransportReplay(t *testing.T) { | |||
| 18 | 18 | require.NoError(t, err) | |
| 19 | 19 | t.Cleanup(func() { _ = left.Close(); _ = right.Close() }) | |
| 20 | 20 | ||
| 21 | - | got := make([]ports.Frame, 0, len(frames)) | |
| 21 | + | got := make([]wire.Frame, 0, len(frames)) | |
| 22 | 22 | for _, frame := range frames { | |
| 23 | 23 | require.NoError(t, left.Send(frame)) | |
| 24 | 24 | link.flush(rightPC) | |
M internal/adapters/dgram/transport_retransmit_test.go +21 -20
| @@ -7,11 +7,12 @@ import ( | |||
| 7 | 7 | "time" | |
| 8 | 8 | ||
| 9 | 9 | "github.com/bnema/vev/internal/ports" | |
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 10 | 11 | ) | |
| 11 | 12 | ||
| 12 | 13 | func TestResendSkipsQueuedOutputBeforeFirstWireAttempt(t *testing.T) { | |
| 13 | 14 | tr, writes := newResendTestTransport(t, 10) | |
| 14 | - | tr.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("queued")}} | |
| 15 | + | tr.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("queued")}} | |
| 15 | 16 | ||
| 16 | 17 | tr.resendPending() | |
| 17 | 18 | ||
| @@ -27,7 +28,7 @@ func TestResendSkipsOutputDuringFirstWireAttempt(t *testing.T) { | |||
| 27 | 28 | tr, writes := newResendTestTransport(t, 10) | |
| 28 | 29 | now := tr.clock.Now() | |
| 29 | 30 | tr.pending[1] = &pending{ | |
| 30 | - | frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("sending")}, | |
| 31 | + | frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("sending")}, | |
| 31 | 32 | first: now.Add(-time.Second), | |
| 32 | 33 | last: now.Add(-time.Second), | |
| 33 | 34 | initialInFlight: true, | |
| @@ -68,11 +69,11 @@ func TestReliableInputRetransmitsUntilAck(t *testing.T) { | |||
| 68 | 69 | t.Errorf("close b: %v", err) | |
| 69 | 70 | } | |
| 70 | 71 | }() | |
| 71 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("typed")}); err != nil { | |
| 72 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("typed")}); err != nil { | |
| 72 | 73 | t.Fatal(err) | |
| 73 | 74 | } | |
| 74 | 75 | got := recvWithin(t, b, time.Second) | |
| 75 | - | if got.Type != ports.MsgInput || string(got.Payload) != "typed" || !dropped.Load() { | |
| 76 | + | if got.Type != wire.MsgInput || string(got.Payload) != "typed" || !dropped.Load() { | |
| 76 | 77 | t.Fatalf("got=%+v dropped=%v", got, dropped.Load()) | |
| 77 | 78 | } | |
| 78 | 79 | } | |
| @@ -95,11 +96,11 @@ func TestOutputRetransmitsUntilAck(t *testing.T) { | |||
| 95 | 96 | t.Errorf("close b: %v", err) | |
| 96 | 97 | } | |
| 97 | 98 | }() | |
| 98 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("state1")}); err != nil { | |
| 99 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("state1")}); err != nil { | |
| 99 | 100 | t.Fatal(err) | |
| 100 | 101 | } | |
| 101 | 102 | got := recvWithin(t, b, time.Second) | |
| 102 | - | if got.Type != ports.MsgOutput || string(got.Payload) != "state1" || !dropped.Load() { | |
| 103 | + | if got.Type != wire.MsgOutput || string(got.Payload) != "state1" || !dropped.Load() { | |
| 103 | 104 | t.Fatalf("got=%+v dropped=%v", got, dropped.Load()) | |
| 104 | 105 | } | |
| 105 | 106 | } | |
| @@ -124,7 +125,7 @@ func TestImmediateLoopbackAckSamplesStampedFinalWrite(t *testing.T) { | |||
| 124 | 125 | t.Error("ACK did not retire pending frame before WriteTo returned") | |
| 125 | 126 | } | |
| 126 | 127 | ||
| 127 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("state")}); err != nil { | |
| 128 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("state")}); err != nil { | |
| 128 | 129 | t.Fatal(err) | |
| 129 | 130 | } | |
| 130 | 131 | eventually(t, time.Second, func() bool { | |
| @@ -155,14 +156,14 @@ func TestOutputDependencyChainRetransmitsDroppedPredecessors(t *testing.T) { | |||
| 155 | 156 | defer func() { _ = b.Close() }() | |
| 156 | 157 | ||
| 157 | 158 | for _, payload := range []string{"state1", "state2", "state3"} { | |
| 158 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte(payload)}); err != nil { | |
| 159 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte(payload)}); err != nil { | |
| 159 | 160 | t.Fatal(err) | |
| 160 | 161 | } | |
| 161 | 162 | } | |
| 162 | 163 | ||
| 163 | 164 | for _, want := range []string{"state1", "state2", "state3"} { | |
| 164 | 165 | got := recvWithin(t, b, time.Second) | |
| 165 | - | if got.Type != ports.MsgOutput || string(got.Payload) != want { | |
| 166 | + | if got.Type != wire.MsgOutput || string(got.Payload) != want { | |
| 166 | 167 | t.Fatalf("got=%+v, want ordered prerequisite output %q", got, want) | |
| 167 | 168 | } | |
| 168 | 169 | } | |
| @@ -175,7 +176,7 @@ func TestResendPendingCapsBurst(t *testing.T) { | |||
| 175 | 176 | tr, writes := newResendTestTransport(t, 2) | |
| 176 | 177 | now := tr.clock.Now() | |
| 177 | 178 | for i := range 5 { | |
| 178 | - | tr.pending[uint64(i+1)] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}}, last: now.Add(-time.Second)} | |
| 179 | + | tr.pending[uint64(i+1)] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}}, last: now.Add(-time.Second)} | |
| 179 | 180 | } | |
| 180 | 181 | ||
| 181 | 182 | tr.resendPending() | |
| @@ -189,7 +190,7 @@ func TestRetransmitBatchReducesCongestionWindowOnce(t *testing.T) { | |||
| 189 | 190 | now := tr.clock.Now() | |
| 190 | 191 | for seq := uint64(1); seq <= 3; seq++ { | |
| 191 | 192 | tr.pending[seq] = &pending{ | |
| 192 | - | frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(seq)}}, | |
| 193 | + | frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(seq)}}, | |
| 193 | 194 | last: now.Add(-time.Second), | |
| 194 | 195 | } | |
| 195 | 196 | } | |
| @@ -209,7 +210,7 @@ func TestACKBeforeQueuedRetransmitDoesNotReduceCongestionWindow(t *testing.T) { | |||
| 209 | 210 | tr, writes := newResendTestTransport(t, 1) | |
| 210 | 211 | now := tr.clock.Now() | |
| 211 | 212 | tr.pending[1] = &pending{ | |
| 212 | - | frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("acked")}, | |
| 213 | + | frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("acked")}, | |
| 213 | 214 | first: now.Add(-time.Second), | |
| 214 | 215 | last: now.Add(-time.Second), | |
| 215 | 216 | wireBytes: tr.mtu, | |
| @@ -244,7 +245,7 @@ func TestOversizedRetransmitHonorsPacketBudget(t *testing.T) { | |||
| 244 | 245 | tr.clock = clk | |
| 245 | 246 | tr.done = make(chan struct{}) | |
| 246 | 247 | tr.pending[1] = &pending{ | |
| 247 | - | frame: ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, 24*tr.mtu)}, | |
| 248 | + | frame: wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, 24*tr.mtu)}, | |
| 248 | 249 | last: clk.now.Add(-time.Second), | |
| 249 | 250 | } | |
| 250 | 251 | done := make(chan struct{}) | |
| @@ -274,9 +275,9 @@ func TestOversizedRetransmitHonorsPacketBudget(t *testing.T) { | |||
| 274 | 275 | func TestResendPendingUsesExponentialBackoffAndMaxDelay(t *testing.T) { | |
| 275 | 276 | tr, writes := newResendTestTransport(t, 10) | |
| 276 | 277 | now := tr.clock.Now() | |
| 277 | - | tr.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("too-soon")}, last: now.Add(-150 * time.Millisecond), attempts: 1} | |
| 278 | - | tr.pending[2] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("ready")}, last: now.Add(-250 * time.Millisecond), attempts: 1} | |
| 279 | - | tr.pending[3] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte("capped")}, last: now.Add(-time.Second), attempts: 10} | |
| 278 | + | tr.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("too-soon")}, last: now.Add(-150 * time.Millisecond), attempts: 1} | |
| 279 | + | tr.pending[2] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("ready")}, last: now.Add(-250 * time.Millisecond), attempts: 1} | |
| 280 | + | tr.pending[3] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte("capped")}, last: now.Add(-time.Second), attempts: 10} | |
| 280 | 281 | ||
| 281 | 282 | tr.resendPending() | |
| 282 | 283 | if got := writes.Load(); got != 2 { | |
| @@ -297,7 +298,7 @@ func TestCumulativeAckReleasesAllEarlierPendingFrames(t *testing.T) { | |||
| 297 | 298 | tr, _ := newResendTestTransport(t, 10) | |
| 298 | 299 | now := tr.clock.Now() | |
| 299 | 300 | for seq := uint64(1); seq <= 3; seq++ { | |
| 300 | - | tr.pending[seq] = &pending{frame: ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(seq)}}, first: now, last: now} | |
| 301 | + | tr.pending[seq] = &pending{frame: wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(seq)}}, first: now, last: now} | |
| 301 | 302 | } | |
| 302 | 303 | ||
| 303 | 304 | tr.handleRecord(ackRecord(3)) | |
| @@ -314,14 +315,14 @@ func TestRTTEstimatorUpdatesRTOFromAckSample(t *testing.T) { | |||
| 314 | 315 | tr.resendAfter = 100 * time.Millisecond | |
| 315 | 316 | tr.maxResendAfter = time.Second | |
| 316 | 317 | tr.rto = tr.resendAfter | |
| 317 | - | tr.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput}, first: clk.now.Add(-200 * time.Millisecond), last: clk.now.Add(-200 * time.Millisecond)} | |
| 318 | + | tr.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput}, first: clk.now.Add(-200 * time.Millisecond), last: clk.now.Add(-200 * time.Millisecond)} | |
| 318 | 319 | ||
| 319 | 320 | tr.handleRecord(ackRecord(1)) | |
| 320 | 321 | ||
| 321 | 322 | if tr.rto <= tr.resendAfter { | |
| 322 | 323 | t.Fatalf("rto=%v, want above initial resend after RTT sample", tr.rto) | |
| 323 | 324 | } | |
| 324 | - | tr.pending[2] = &pending{frame: ports.Frame{Type: ports.MsgOutput}, first: clk.now, last: clk.now.Add(-(tr.rto - time.Millisecond))} | |
| 325 | + | tr.pending[2] = &pending{frame: wire.Frame{Type: wire.MsgOutput}, first: clk.now, last: clk.now.Add(-(tr.rto - time.Millisecond))} | |
| 325 | 326 | tr.resendPending() | |
| 326 | 327 | if got := writes.Load(); got != 0 { | |
| 327 | 328 | t.Fatalf("writes before rto=%d, want 0", got) | |
| @@ -340,7 +341,7 @@ func TestRTTEstimatorIgnoresRetransmittedFramesAfterRecovery(t *testing.T) { | |||
| 340 | 341 | tr.resendAfter = 100 * time.Millisecond | |
| 341 | 342 | tr.maxResendAfter = time.Second | |
| 342 | 343 | tr.rto = tr.resendAfter | |
| 343 | - | tr.pending[1] = &pending{frame: ports.Frame{Type: ports.MsgOutput}, first: clk.now.Add(-200 * time.Millisecond), last: clk.now.Add(-tr.resendAfter)} | |
| 344 | + | tr.pending[1] = &pending{frame: wire.Frame{Type: wire.MsgOutput}, first: clk.now.Add(-200 * time.Millisecond), last: clk.now.Add(-tr.resendAfter)} | |
| 344 | 345 | tr.resendPending() | |
| 345 | 346 | tr.linkState = ports.LinkStateOffline | |
| 346 | 347 | ||
M internal/adapters/dgram/transport_send.go +5 -4
| @@ -6,16 +6,17 @@ import ( | |||
| 6 | 6 | "time" | |
| 7 | 7 | ||
| 8 | 8 | "github.com/bnema/vev/internal/ports" | |
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 9 | 10 | ) | |
| 10 | 11 | ||
| 11 | - | func (t *Transport) Send(f ports.Frame) error { | |
| 12 | + | func (t *Transport) Send(f wire.Frame) error { | |
| 12 | 13 | end := t.beginRuntimeOperation(ports.RuntimeAdapterSendStart, uint64(len(f.Payload))) | |
| 13 | 14 | err := t.send(f, false) | |
| 14 | 15 | end(err == nil) | |
| 15 | 16 | return err | |
| 16 | 17 | } | |
| 17 | 18 | ||
| 18 | - | func (t *Transport) SendAsync(f ports.Frame) error { | |
| 19 | + | func (t *Transport) SendAsync(f wire.Frame) error { | |
| 19 | 20 | end := t.beginRuntimeOperation(ports.RuntimeAdapterSendStart, uint64(len(f.Payload))) | |
| 20 | 21 | err := t.send(f, true) | |
| 21 | 22 | end(err == nil) | |
| @@ -24,9 +25,9 @@ func (t *Transport) SendAsync(f ports.Frame) error { | |||
| 24 | 25 | ||
| 25 | 26 | // SendSynchronous owns queue reservation, fragment pacing, per-write deadlines, | |
| 26 | 27 | // and close cancellation. Callers must not layer a shorter preflight timer over it. | |
| 27 | - | func (t *Transport) SendSynchronous(f ports.Frame) error { return t.Send(f) } | |
| 28 | + | func (t *Transport) SendSynchronous(f wire.Frame) error { return t.Send(f) } | |
| 28 | 29 | ||
| 29 | - | func (t *Transport) send(f ports.Frame, async bool) error { | |
| 30 | + | func (t *Transport) send(f wire.Frame, async bool) error { | |
| 30 | 31 | reliable := true | |
| 31 | 32 | if err := t.lockOutboundSlot(reliable); err != nil { | |
| 32 | 33 | return err | |
M internal/adapters/dgram/transport_send_test.go +31 -31
| @@ -8,8 +8,8 @@ import ( | |||
| 8 | 8 | "time" | |
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/vev/internal/domain" | |
| 11 | - | "github.com/bnema/vev/internal/ports" | |
| 12 | 11 | "github.com/bnema/vev/internal/protocol" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 13 | pdgram "github.com/bnema/vev/pkg/dgram" | |
| 14 | 14 | "github.com/stretchr/testify/require" | |
| 15 | 15 | ) | |
| @@ -26,7 +26,7 @@ func TestPendingWireBytesMatchSealedDatagrams(t *testing.T) { | |||
| 26 | 26 | defer func() { _ = a.Close() }() | |
| 27 | 27 | ||
| 28 | 28 | maxFragmentData := mtu - pdgram.HeaderSize - a.codec.Overhead() - 16 | |
| 29 | - | frame := ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, maxFragmentData-dataRecordHeaderSize+1)} | |
| 29 | + | frame := wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, maxFragmentData-dataRecordHeaderSize+1)} | |
| 30 | 30 | if err := a.Send(frame); err != nil { | |
| 31 | 31 | t.Fatal(err) | |
| 32 | 32 | } | |
| @@ -69,7 +69,7 @@ func TestSendAsyncTransfersFragmentedRecordToBytePacedSender(t *testing.T) { | |||
| 69 | 69 | defer func() { _ = a.Close() }() | |
| 70 | 70 | ||
| 71 | 71 | maxFragmentData := mtu - pdgram.HeaderSize - a.codec.Overhead() | |
| 72 | - | frame := ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, 2*maxFragmentData)} | |
| 72 | + | frame := wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, 2*maxFragmentData)} | |
| 73 | 73 | if err := a.SendAsync(frame); err != nil { | |
| 74 | 74 | t.Fatal(err) | |
| 75 | 75 | } | |
| @@ -92,12 +92,12 @@ func TestSmallOutputsShareInitialByteBurst(t *testing.T) { | |||
| 92 | 92 | defer func() { _ = a.Close() }() | |
| 93 | 93 | ||
| 94 | 94 | for i := range 3 { | |
| 95 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}}); err != nil { | |
| 95 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}}); err != nil { | |
| 96 | 96 | t.Fatal(err) | |
| 97 | 97 | } | |
| 98 | 98 | } | |
| 99 | 99 | eventuallyPacketCount(t, bPC, 3) | |
| 100 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("next")}); err != nil { | |
| 100 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("next")}); err != nil { | |
| 101 | 101 | t.Fatal(err) | |
| 102 | 102 | } | |
| 103 | 103 | eventuallyPacketCount(t, bPC, 4) | |
| @@ -112,12 +112,12 @@ func TestOutputPacingSendsAtMostOneOversizedFramePerTick(t *testing.T) { | |||
| 112 | 112 | } | |
| 113 | 113 | defer func() { _ = a.Close() }() | |
| 114 | 114 | ||
| 115 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("prime")}); err != nil { | |
| 115 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("prime")}); err != nil { | |
| 116 | 116 | t.Fatal(err) | |
| 117 | 117 | } | |
| 118 | 118 | large := mustMarshalOutput(protocol.Output{Epoch: 1, Base: 1, New: 2, Size: domain.Size{Cols: 1, Rows: 1}, Data: make([]byte, 24*a.mtu)}) | |
| 119 | 119 | for range 2 { | |
| 120 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: large}); err != nil { | |
| 120 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: large}); err != nil { | |
| 121 | 121 | t.Fatal(err) | |
| 122 | 122 | } | |
| 123 | 123 | } | |
| @@ -152,7 +152,7 @@ func TestPacedInitialSendTimestampsFinalFragmentCompletion(t *testing.T) { | |||
| 152 | 152 | t.Fatal(err) | |
| 153 | 153 | } | |
| 154 | 154 | defer func() { _ = a.Close() }() | |
| 155 | - | large := ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, 24*a.mtu)} | |
| 155 | + | large := wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, 24*a.mtu)} | |
| 156 | 156 | done := make(chan error, 1) | |
| 157 | 157 | go func() { done <- a.Send(large) }() | |
| 158 | 158 | start := clk.Now() | |
| @@ -209,7 +209,7 @@ func TestOwnedSynchronousMaxSideEffectCompletesThroughConcurrentPacedWork(t *tes | |||
| 209 | 209 | a.srtt = 500 * time.Millisecond | |
| 210 | 210 | a.mu.Unlock() | |
| 211 | 211 | for i := range 8 { | |
| 212 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}}); err != nil { | |
| 212 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}}); err != nil { | |
| 213 | 213 | t.Fatal(err) | |
| 214 | 214 | } | |
| 215 | 215 | } | |
| @@ -217,13 +217,13 @@ func TestOwnedSynchronousMaxSideEffectCompletesThroughConcurrentPacedWork(t *tes | |||
| 217 | 217 | a.mu.Lock() | |
| 218 | 218 | for _, seq := range []uint64{100, 101} { | |
| 219 | 219 | a.pending[seq] = &pending{ | |
| 220 | - | frame: ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, 20*a.mtu)}, | |
| 220 | + | frame: wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, 20*a.mtu)}, | |
| 221 | 221 | enqueued: now.Add(-time.Second), first: now.Add(-time.Second), last: now.Add(-time.Second), | |
| 222 | 222 | } | |
| 223 | 223 | } | |
| 224 | 224 | a.mu.Unlock() | |
| 225 | 225 | go a.resendPending() | |
| 226 | - | sideEffect := ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Data: make([]byte, 100*1024)})} | |
| 226 | + | sideEffect := wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Data: make([]byte, 100*1024)})} | |
| 227 | 227 | done := make(chan error, 1) | |
| 228 | 228 | go func() { done <- a.SendSynchronous(sideEffect) }() | |
| 229 | 229 | ||
| @@ -256,12 +256,12 @@ func TestInputWaitsForDequeuedOutputBatch(t *testing.T) { | |||
| 256 | 256 | ||
| 257 | 257 | a.writeMu.Lock() | |
| 258 | 258 | for _, payload := range []string{"first", "queued"} { | |
| 259 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte(payload)}); err != nil { | |
| 259 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte(payload)}); err != nil { | |
| 260 | 260 | t.Fatal(err) | |
| 261 | 261 | } | |
| 262 | 262 | } | |
| 263 | 263 | done := make(chan error, 1) | |
| 264 | - | go func() { done <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("typed")}) }() | |
| 264 | + | go func() { done <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("typed")}) }() | |
| 265 | 265 | select { | |
| 266 | 266 | case err := <-done: | |
| 267 | 267 | a.writeMu.Unlock() | |
| @@ -295,7 +295,7 @@ func TestPacedControlQueueFailureClosesTransport(t *testing.T) { | |||
| 295 | 295 | t.Fatal(err) | |
| 296 | 296 | } | |
| 297 | 297 | inputDone := make(chan error, 1) | |
| 298 | - | go func() { inputDone <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("typed")}) }() | |
| 298 | + | go func() { inputDone <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("typed")}) }() | |
| 299 | 299 | if err := <-inputDone; err == nil { | |
| 300 | 300 | t.Fatal("data send succeeded after paced wire failure") | |
| 301 | 301 | } | |
| @@ -328,10 +328,10 @@ func TestRemoveQueuedPendingResolvesSynchronousWaiters(t *testing.T) { | |||
| 328 | 328 | func TestCloseUnblocksQueuedSynchronousFrames(t *testing.T) { | |
| 329 | 329 | frames := []struct { | |
| 330 | 330 | name string | |
| 331 | - | frame ports.Frame | |
| 331 | + | frame wire.Frame | |
| 332 | 332 | }{ | |
| 333 | - | {name: "control", frame: ports.Frame{Type: ports.MsgPing}}, | |
| 334 | - | {name: "terminal side effect", frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("osc")})}}, | |
| 333 | + | {name: "control", frame: wire.Frame{Type: wire.MsgPing}}, | |
| 334 | + | {name: "terminal side effect", frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("osc")})}}, | |
| 335 | 335 | } | |
| 336 | 336 | for _, tt := range frames { | |
| 337 | 337 | t.Run(tt.name, func(t *testing.T) { | |
| @@ -341,7 +341,7 @@ func TestCloseUnblocksQueuedSynchronousFrames(t *testing.T) { | |||
| 341 | 341 | if err != nil { | |
| 342 | 342 | t.Fatal(err) | |
| 343 | 343 | } | |
| 344 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, 3*a.mtu)}); err != nil { | |
| 344 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, 3*a.mtu)}); err != nil { | |
| 345 | 345 | t.Fatal(err) | |
| 346 | 346 | } | |
| 347 | 347 | done := make(chan error, 1) | |
| @@ -371,7 +371,7 @@ func TestOutputPaceFailureClosesTransportWithWriteError(t *testing.T) { | |||
| 371 | 371 | if err := bPC.Close(); err != nil { | |
| 372 | 372 | t.Fatal(err) | |
| 373 | 373 | } | |
| 374 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("fails")}); err != nil { | |
| 374 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("fails")}); err != nil { | |
| 375 | 375 | t.Fatal(err) | |
| 376 | 376 | } | |
| 377 | 377 | ||
| @@ -380,7 +380,7 @@ func TestOutputPaceFailureClosesTransportWithWriteError(t *testing.T) { | |||
| 380 | 380 | case <-time.After(time.Second): | |
| 381 | 381 | t.Fatal("transport remained open after paced output write failed") | |
| 382 | 382 | } | |
| 383 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput}); err == nil || err.Error() != "peer closed" { | |
| 383 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput}); err == nil || err.Error() != "peer closed" { | |
| 384 | 384 | t.Fatalf("send after paced write failure err=%v, want peer closed", err) | |
| 385 | 385 | } | |
| 386 | 386 | } | |
| @@ -394,24 +394,24 @@ func TestInputAndControlRemainOrderedInBoundedPacedQueue(t *testing.T) { | |||
| 394 | 394 | } | |
| 395 | 395 | defer func() { _ = a.Close() }() | |
| 396 | 396 | ||
| 397 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("output")}); err != nil { | |
| 397 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("output")}); err != nil { | |
| 398 | 398 | t.Fatal(err) | |
| 399 | 399 | } | |
| 400 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("queued")}); err != nil { | |
| 400 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("queued")}); err != nil { | |
| 401 | 401 | t.Fatal(err) | |
| 402 | 402 | } | |
| 403 | 403 | eventuallyPacketCount(t, bPC, 2) | |
| 404 | 404 | inputDone := make(chan error, 1) | |
| 405 | - | go func() { inputDone <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("typed")}) }() | |
| 405 | + | go func() { inputDone <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("typed")}) }() | |
| 406 | 406 | eventuallyPacketCount(t, bPC, 3) | |
| 407 | 407 | if err := <-inputDone; err != nil { | |
| 408 | 408 | t.Fatal(err) | |
| 409 | 409 | } | |
| 410 | - | if err := a.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("queued-before-control")}); err != nil { | |
| 410 | + | if err := a.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("queued-before-control")}); err != nil { | |
| 411 | 411 | t.Fatal(err) | |
| 412 | 412 | } | |
| 413 | 413 | controlDone := make(chan error, 1) | |
| 414 | - | go func() { controlDone <- a.Send(ports.Frame{Type: ports.MsgPing}) }() | |
| 414 | + | go func() { controlDone <- a.Send(wire.Frame{Type: wire.MsgPing}) }() | |
| 415 | 415 | eventuallyPacketCount(t, bPC, 5) | |
| 416 | 416 | if err := <-controlDone; err != nil { | |
| 417 | 417 | t.Fatal(err) | |
| @@ -431,7 +431,7 @@ func TestSendWriteTimeoutBoundsBlockedPacketConn(t *testing.T) { | |||
| 431 | 431 | defer func() { _ = tr.Close() }() | |
| 432 | 432 | ||
| 433 | 433 | done := make(chan error, 1) | |
| 434 | - | go func() { done <- tr.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("blocked")}) }() | |
| 434 | + | go func() { done <- tr.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("blocked")}) }() | |
| 435 | 435 | select { | |
| 436 | 436 | case err := <-done: | |
| 437 | 437 | if err == nil { | |
| @@ -460,11 +460,11 @@ func TestPendingReliableQueueBackpressuresUntilAck(t *testing.T) { | |||
| 460 | 460 | defer func() { _ = a.Close() }() | |
| 461 | 461 | defer func() { _ = b.Close() }() | |
| 462 | 462 | ||
| 463 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("first")}); err != nil { | |
| 463 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("first")}); err != nil { | |
| 464 | 464 | t.Fatal(err) | |
| 465 | 465 | } | |
| 466 | 466 | done := make(chan error, 1) | |
| 467 | - | go func() { done <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("second")}) }() | |
| 467 | + | go func() { done <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("second")}) }() | |
| 468 | 468 | ||
| 469 | 469 | select { | |
| 470 | 470 | case err := <-done: | |
| @@ -498,11 +498,11 @@ func TestPendingReliableQueueReturnsErrPendingFullWhileConnected(t *testing.T) { | |||
| 498 | 498 | defer func() { _ = a.Close() }() | |
| 499 | 499 | defer func() { _ = b.Close() }() | |
| 500 | 500 | ||
| 501 | - | if err := a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("first")}); err != nil { | |
| 501 | + | if err := a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("first")}); err != nil { | |
| 502 | 502 | t.Fatal(err) | |
| 503 | 503 | } | |
| 504 | 504 | done := make(chan error, 1) | |
| 505 | - | go func() { done <- a.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("second")}) }() | |
| 505 | + | go func() { done <- a.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("second")}) }() | |
| 506 | 506 | waitForManualTimers(t, clk, 4) | |
| 507 | 507 | ||
| 508 | 508 | clk.advance(50 * time.Millisecond) | |
| @@ -530,7 +530,7 @@ func TestWritePacketDeadlineUsesTransportClock(t *testing.T) { | |||
| 530 | 530 | } | |
| 531 | 531 | defer func() { _ = tr.Close() }() | |
| 532 | 532 | ||
| 533 | - | if err := tr.Send(ports.Frame{Type: ports.MsgInput, Payload: []byte("deadline")}); err != nil { | |
| 533 | + | if err := tr.Send(wire.Frame{Type: wire.MsgInput, Payload: []byte("deadline")}); err != nil { | |
| 534 | 534 | t.Fatal(err) | |
| 535 | 535 | } | |
| 536 | 536 | got, _ := pc.deadline.Load().(time.Time) | |
M internal/adapters/dgram/transport_test_helpers_test.go +19 -18
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | 10 | "time" | |
| 11 | 11 | ||
| 12 | 12 | "github.com/bnema/vev/internal/ports" | |
| 13 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 14 | pdgram "github.com/bnema/vev/pkg/dgram" | |
| 14 | 15 | ) | |
| 15 | 16 | ||
| @@ -309,15 +310,15 @@ func probeRecord(kind byte, id uint64) []byte { | |||
| 309 | 310 | } | |
| 310 | 311 | ||
| 311 | 312 | func TestReliableRecvBufferBoundedForFarFutureSequences(t *testing.T) { | |
| 312 | - | tr := &Transport{nextRecvSeq: 1, recvBuf: make(map[uint64]ports.Frame), maxRecvBuffer: maxRecvBuffer, done: make(chan struct{})} | |
| 313 | + | tr := &Transport{nextRecvSeq: 1, recvBuf: make(map[uint64]wire.Frame), maxRecvBuffer: maxRecvBuffer, done: make(chan struct{})} | |
| 313 | 314 | tr.deliverCond = sync.NewCond(&tr.deliverMu) | |
| 314 | 315 | for i := range maxRecvBuffer + 100 { | |
| 315 | - | tr.enqueueReliable(uint64(1000+i), ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}}) | |
| 316 | + | tr.enqueueReliable(uint64(1000+i), wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}}) | |
| 316 | 317 | } | |
| 317 | 318 | if got := len(tr.recvBuf); got != maxRecvBuffer { | |
| 318 | 319 | t.Fatalf("recvBuf len=%d, want %d", got, maxRecvBuffer) | |
| 319 | 320 | } | |
| 320 | - | tr.enqueueReliable(1, ports.Frame{Type: ports.MsgOutput, Payload: []byte("next")}) | |
| 321 | + | tr.enqueueReliable(1, wire.Frame{Type: wire.MsgOutput, Payload: []byte("next")}) | |
| 321 | 322 | if _, ok := tr.recvBuf[1]; !ok { | |
| 322 | 323 | t.Fatalf("next expected sequence was dropped when far-future buffer was full") | |
| 323 | 324 | } | |
| @@ -329,13 +330,13 @@ func TestReliableRecvBufferBoundedForFarFutureSequences(t *testing.T) { | |||
| 329 | 330 | func TestOutputPrerequisitesRemainInFullReceiveBuffer(t *testing.T) { | |
| 330 | 331 | tr := &Transport{ | |
| 331 | 332 | nextRecvSeq: 1, | |
| 332 | - | recvBuf: map[uint64]ports.Frame{2: {Type: ports.MsgOutput, Payload: []byte("stale")}}, | |
| 333 | + | recvBuf: map[uint64]wire.Frame{2: {Type: wire.MsgOutput, Payload: []byte("stale")}}, | |
| 333 | 334 | maxRecvBuffer: 1, | |
| 334 | 335 | done: make(chan struct{}), | |
| 335 | 336 | } | |
| 336 | 337 | tr.deliverCond = sync.NewCond(&tr.deliverMu) | |
| 337 | 338 | ||
| 338 | - | ackSeq, ack, queued := tr.enqueueReliable(3, ports.Frame{Type: ports.MsgOutput, Payload: []byte("replacement")}) | |
| 339 | + | ackSeq, ack, queued := tr.enqueueReliable(3, wire.Frame{Type: wire.MsgOutput, Payload: []byte("replacement")}) | |
| 339 | 340 | if ack || queued || ackSeq != 0 { | |
| 340 | 341 | t.Fatalf("replacement ackSeq=%d ack=%v queued=%v, want output rejected while prerequisite buffer is full", ackSeq, ack, queued) | |
| 341 | 342 | } | |
| @@ -353,22 +354,22 @@ func TestReliableFullRecvBufferDoesNotAckDroppedFarFutureFrame(t *testing.T) { | |||
| 353 | 354 | if err != nil { | |
| 354 | 355 | t.Fatal(err) | |
| 355 | 356 | } | |
| 356 | - | tr := &Transport{pc: aPC, peer: testAddr("b"), codec: codec, sendDir: 1, mtu: pdgram.DefaultMTU, nextRecvSeq: 1, recvBuf: make(map[uint64]ports.Frame), maxRecvBuffer: maxRecvBuffer, clock: realClock{}, done: make(chan struct{})} | |
| 357 | + | tr := &Transport{pc: aPC, peer: testAddr("b"), codec: codec, sendDir: 1, mtu: pdgram.DefaultMTU, nextRecvSeq: 1, recvBuf: make(map[uint64]wire.Frame), maxRecvBuffer: maxRecvBuffer, clock: realClock{}, done: make(chan struct{})} | |
| 357 | 358 | tr.deliverCond = sync.NewCond(&tr.deliverMu) | |
| 358 | 359 | defer func() { _ = aPC.Close() }() | |
| 359 | 360 | defer func() { _ = bPC.Close() }() | |
| 360 | 361 | ||
| 361 | 362 | for i := range maxRecvBuffer { | |
| 362 | - | tr.recvBuf[uint64(1000+i)] = ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}} | |
| 363 | + | tr.recvBuf[uint64(1000+i)] = wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}} | |
| 363 | 364 | } | |
| 364 | - | tr.handleRecord(encodeData(9999, true, ports.Frame{Type: ports.MsgOutput, Payload: []byte("dropped")})) | |
| 365 | + | tr.handleRecord(encodeData(9999, true, wire.Frame{Type: wire.MsgOutput, Payload: []byte("dropped")})) | |
| 365 | 366 | select { | |
| 366 | 367 | case pkt := <-bPC.in: | |
| 367 | 368 | t.Fatalf("unexpected ACK packet for dropped frame: %x", pkt.b) | |
| 368 | 369 | case <-time.After(25 * time.Millisecond): | |
| 369 | 370 | } | |
| 370 | 371 | ||
| 371 | - | tr.handleRecord(encodeData(1, true, ports.Frame{Type: ports.MsgOutput, Payload: []byte("next")})) | |
| 372 | + | tr.handleRecord(encodeData(1, true, wire.Frame{Type: wire.MsgOutput, Payload: []byte("next")})) | |
| 372 | 373 | select { | |
| 373 | 374 | case <-bPC.in: | |
| 374 | 375 | case <-time.After(time.Second): | |
| @@ -376,27 +377,27 @@ func TestReliableFullRecvBufferDoesNotAckDroppedFarFutureFrame(t *testing.T) { | |||
| 376 | 377 | } | |
| 377 | 378 | } | |
| 378 | 379 | ||
| 379 | - | func recvMaybe(tr *Transport, d time.Duration) (ports.Frame, bool) { | |
| 380 | - | ch := make(chan ports.Frame, 1) | |
| 380 | + | func recvMaybe(tr *Transport, d time.Duration) (wire.Frame, bool) { | |
| 381 | + | ch := make(chan wire.Frame, 1) | |
| 381 | 382 | go func() { f, _ := tr.Recv(); ch <- f }() | |
| 382 | 383 | select { | |
| 383 | 384 | case f := <-ch: | |
| 384 | 385 | return f, true | |
| 385 | 386 | case <-time.After(d): | |
| 386 | - | return ports.Frame{}, false | |
| 387 | + | return wire.Frame{}, false | |
| 387 | 388 | } | |
| 388 | 389 | } | |
| 389 | 390 | ||
| 390 | - | func recvWithin(t *testing.T, tr *Transport, d time.Duration) ports.Frame { | |
| 391 | + | func recvWithin(t *testing.T, tr *Transport, d time.Duration) wire.Frame { | |
| 391 | 392 | t.Helper() | |
| 392 | - | ch := make(chan ports.Frame, 1) | |
| 393 | + | ch := make(chan wire.Frame, 1) | |
| 393 | 394 | go func() { f, _ := tr.Recv(); ch <- f }() | |
| 394 | 395 | select { | |
| 395 | 396 | case f := <-ch: | |
| 396 | 397 | return f | |
| 397 | 398 | case <-time.After(d): | |
| 398 | 399 | t.Fatal("timeout") | |
| 399 | - | return ports.Frame{} | |
| 400 | + | return wire.Frame{} | |
| 400 | 401 | } | |
| 401 | 402 | } | |
| 402 | 403 | ||
| @@ -412,10 +413,10 @@ func waitPeer(t *testing.T, tr *Transport, want string) { | |||
| 412 | 413 | t.Fatalf("peer=%v, want %s", tr.Peer(), want) | |
| 413 | 414 | } | |
| 414 | 415 | ||
| 415 | - | func recvErrWithin(t *testing.T, tr *Transport, d time.Duration) (ports.Frame, error) { | |
| 416 | + | func recvErrWithin(t *testing.T, tr *Transport, d time.Duration) (wire.Frame, error) { | |
| 416 | 417 | t.Helper() | |
| 417 | 418 | type result struct { | |
| 418 | - | f ports.Frame | |
| 419 | + | f wire.Frame | |
| 419 | 420 | err error | |
| 420 | 421 | } | |
| 421 | 422 | ch := make(chan result, 1) | |
| @@ -428,6 +429,6 @@ func recvErrWithin(t *testing.T, tr *Transport, d time.Duration) (ports.Frame, e | |||
| 428 | 429 | return r.f, r.err | |
| 429 | 430 | case <-time.After(d): | |
| 430 | 431 | t.Fatal("timeout") | |
| 431 | - | return ports.Frame{}, nil | |
| 432 | + | return wire.Frame{}, nil | |
| 432 | 433 | } | |
| 433 | 434 | } | |
M internal/adapters/dgram/wire_test_helpers_test.go +3 -3
| @@ -1,12 +1,12 @@ | |||
| 1 | 1 | package dgram | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | - | "github.com/bnema/vev/internal/ports" | |
| 5 | 4 | "github.com/bnema/vev/internal/protocol" | |
| 5 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 6 | 6 | ) | |
| 7 | 7 | ||
| 8 | 8 | func mustMarshalOutput(m protocol.Output) []byte { | |
| 9 | - | payload, err := ports.MarshalOutput(m) | |
| 9 | + | payload, err := wire.MarshalOutput(m) | |
| 10 | 10 | if err != nil { | |
| 11 | 11 | panic(err) | |
| 12 | 12 | } | |
| @@ -14,7 +14,7 @@ func mustMarshalOutput(m protocol.Output) []byte { | |||
| 14 | 14 | } | |
| 15 | 15 | ||
| 16 | 16 | func mustMarshalAck(m protocol.Ack) []byte { | |
| 17 | - | payload, err := ports.MarshalAck(m) | |
| 17 | + | payload, err := wire.MarshalAck(m) | |
| 18 | 18 | if err != nil { | |
| 19 | 19 | panic(err) | |
| 20 | 20 | } | |
M internal/adapters/ipc/listener_test.go +3 -3
| @@ -9,7 +9,7 @@ import ( | |||
| 9 | 9 | "strings" | |
| 10 | 10 | "testing" | |
| 11 | 11 | ||
| 12 | - | "github.com/bnema/vev/internal/ports" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 13 | ) | |
| 14 | 14 | ||
| 15 | 15 | func TestListenAcceptRoundTrip(t *testing.T) { | |
| @@ -43,7 +43,7 @@ func TestListenAcceptRoundTrip(t *testing.T) { | |||
| 43 | 43 | } | |
| 44 | 44 | defer func() { _ = conn.Close() }() | |
| 45 | 45 | client := NewTransport(conn) | |
| 46 | - | errCh <- client.Send(ports.Frame{Type: ports.MsgPing}) | |
| 46 | + | errCh <- client.Send(wire.Frame{Type: wire.MsgPing}) | |
| 47 | 47 | }() | |
| 48 | 48 | ||
| 49 | 49 | transport, err := ln.Accept() | |
| @@ -56,7 +56,7 @@ func TestListenAcceptRoundTrip(t *testing.T) { | |||
| 56 | 56 | if err != nil { | |
| 57 | 57 | t.Fatalf("Recv() error = %v", err) | |
| 58 | 58 | } | |
| 59 | - | if got.Type != ports.MsgPing { | |
| 59 | + | if got.Type != wire.MsgPing { | |
| 60 | 60 | t.Fatalf("Recv() type = %v, want MsgPing", got.Type) | |
| 61 | 61 | } | |
| 62 | 62 | if err := <-errCh; err != nil { | |
M internal/adapters/ipc/transport.go +13 -12
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | 8 | "sync" | |
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/vev/internal/ports" | |
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 11 | 12 | ) | |
| 12 | 13 | ||
| 13 | 14 | // frameHeaderLen is the size, in bytes, of the length prefix that precedes | |
| @@ -19,7 +20,7 @@ const frameHeaderLen = 4 | |||
| 19 | 20 | var ErrZeroLengthFrame = errors.New("ipc: zero-length frame") | |
| 20 | 21 | ||
| 21 | 22 | // ErrFrameTooLarge is returned by Recv when a frame's length field exceeds | |
| 22 | - | // ports.MaxFrameLen, and by Send when a payload is too large to encode. | |
| 23 | + | // wire.MaxFrameLen, and by Send when a payload is too large to encode. | |
| 23 | 24 | var ErrFrameTooLarge = errors.New("ipc: frame exceeds maximum length") | |
| 24 | 25 | ||
| 25 | 26 | // ErrBackpressure means the bounded IPC egress queue is full. Callers using | |
| @@ -103,7 +104,7 @@ type sendRequest struct { | |||
| 103 | 104 | } | |
| 104 | 105 | ||
| 105 | 106 | // Send queues f for the sole writer and waits for its wire attempt. | |
| 106 | - | func (t *unixTransport) Send(f ports.Frame) error { | |
| 107 | + | func (t *unixTransport) Send(f wire.Frame) error { | |
| 107 | 108 | data, err := marshalFrame(f) | |
| 108 | 109 | if err != nil { | |
| 109 | 110 | return err | |
| @@ -124,7 +125,7 @@ func (t *unixTransport) Send(f ports.Frame) error { | |||
| 124 | 125 | ||
| 125 | 126 | // SendAsync accepts f for ordered background transmission without waiting for | |
| 126 | 127 | // a socket write. The queue is bounded and ownership includes a payload copy. | |
| 127 | - | func (t *unixTransport) SendAsync(f ports.Frame) error { | |
| 128 | + | func (t *unixTransport) SendAsync(f wire.Frame) error { | |
| 128 | 129 | data, err := marshalFrame(f) | |
| 129 | 130 | if err != nil { | |
| 130 | 131 | return err | |
| @@ -137,9 +138,9 @@ func (t *unixTransport) SendAsync(f ports.Frame) error { | |||
| 137 | 138 | return nil | |
| 138 | 139 | } | |
| 139 | 140 | ||
| 140 | - | func marshalFrame(f ports.Frame) ([]byte, error) { | |
| 141 | + | func marshalFrame(f wire.Frame) ([]byte, error) { | |
| 141 | 142 | n := 1 + len(f.Payload) // type + payload | |
| 142 | - | if n > ports.MaxFrameLen { | |
| 143 | + | if n > wire.MaxFrameLen { | |
| 143 | 144 | return nil, ErrFrameTooLarge | |
| 144 | 145 | } | |
| 145 | 146 | buf := make([]byte, frameHeaderLen+n) | |
| @@ -256,22 +257,22 @@ func writeAll(w io.Writer, data []byte) error { | |||
| 256 | 257 | // Recv reads one frame: a 4-byte length, then a body of that many bytes | |
| 257 | 258 | // (type byte + payload). It blocks until a full frame arrives, the | |
| 258 | 259 | // connection is closed (io.EOF), or an error occurs. | |
| 259 | - | func (t *unixTransport) Recv() (ports.Frame, error) { | |
| 260 | + | func (t *unixTransport) Recv() (wire.Frame, error) { | |
| 260 | 261 | end := t.beginOperation(ports.RuntimeAdapterReceiveStart, 0) | |
| 261 | 262 | var hdr [frameHeaderLen]byte | |
| 262 | 263 | if _, err := io.ReadFull(t.conn, hdr[:]); err != nil { | |
| 263 | 264 | end(false) | |
| 264 | - | return ports.Frame{}, err | |
| 265 | + | return wire.Frame{}, err | |
| 265 | 266 | } | |
| 266 | 267 | ||
| 267 | 268 | n := binary.BigEndian.Uint32(hdr[:]) | |
| 268 | 269 | if n == 0 { | |
| 269 | 270 | end(false) | |
| 270 | - | return ports.Frame{}, ErrZeroLengthFrame | |
| 271 | + | return wire.Frame{}, ErrZeroLengthFrame | |
| 271 | 272 | } | |
| 272 | - | if n > ports.MaxFrameLen { | |
| 273 | + | if n > wire.MaxFrameLen { | |
| 273 | 274 | end(false) | |
| 274 | - | return ports.Frame{}, ErrFrameTooLarge | |
| 275 | + | return wire.Frame{}, ErrFrameTooLarge | |
| 275 | 276 | } | |
| 276 | 277 | ||
| 277 | 278 | if cap(t.readBuf) < int(n) { | |
| @@ -281,7 +282,7 @@ func (t *unixTransport) Recv() (ports.Frame, error) { | |||
| 281 | 282 | } | |
| 282 | 283 | if _, err := io.ReadFull(t.conn, t.readBuf); err != nil { | |
| 283 | 284 | end(false) | |
| 284 | - | return ports.Frame{}, err | |
| 285 | + | return wire.Frame{}, err | |
| 285 | 286 | } | |
| 286 | 287 | ||
| 287 | 288 | var payload []byte | |
| @@ -290,7 +291,7 @@ func (t *unixTransport) Recv() (ports.Frame, error) { | |||
| 290 | 291 | copy(payload, t.readBuf[1:]) | |
| 291 | 292 | } | |
| 292 | 293 | end(true) | |
| 293 | - | return ports.Frame{Type: ports.MsgType(t.readBuf[0]), Payload: payload}, nil | |
| 294 | + | return wire.Frame{Type: wire.MsgType(t.readBuf[0]), Payload: payload}, nil | |
| 294 | 295 | } | |
| 295 | 296 | ||
| 296 | 297 | func (t *unixTransport) beginOperation(start ports.RuntimeMarkKind, bytes uint64) func(bool) { | |
M internal/adapters/ipc/transport_benchmark_test.go +4 -4
| @@ -7,14 +7,14 @@ import ( | |||
| 7 | 7 | "testing" | |
| 8 | 8 | "time" | |
| 9 | 9 | ||
| 10 | - | "github.com/bnema/vev/internal/ports" | |
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 11 | 11 | ) | |
| 12 | 12 | ||
| 13 | 13 | func BenchmarkTransportSend(b *testing.B) { | |
| 14 | 14 | conn := discardConn{} | |
| 15 | 15 | tr := NewTransport(conn) | |
| 16 | 16 | payload := []byte("payload payload payload") | |
| 17 | - | frame := ports.Frame{Type: ports.MsgOutput, Payload: payload} | |
| 17 | + | frame := wire.Frame{Type: wire.MsgOutput, Payload: payload} | |
| 18 | 18 | ||
| 19 | 19 | b.ReportAllocs() | |
| 20 | 20 | for b.Loop() { | |
| @@ -26,7 +26,7 @@ func BenchmarkTransportSend(b *testing.B) { | |||
| 26 | 26 | ||
| 27 | 27 | func BenchmarkTransportRecvReuse(b *testing.B) { | |
| 28 | 28 | payload := []byte("payload payload payload") | |
| 29 | - | encoded := encodeBenchmarkFrame(ports.Frame{Type: ports.MsgOutput, Payload: payload}) | |
| 29 | + | encoded := encodeBenchmarkFrame(wire.Frame{Type: wire.MsgOutput, Payload: payload}) | |
| 30 | 30 | recv := &unixTransport{conn: &loopingReaderConn{data: encoded}} | |
| 31 | 31 | ||
| 32 | 32 | b.ReportAllocs() | |
| @@ -37,7 +37,7 @@ func BenchmarkTransportRecvReuse(b *testing.B) { | |||
| 37 | 37 | } | |
| 38 | 38 | } | |
| 39 | 39 | ||
| 40 | - | func encodeBenchmarkFrame(f ports.Frame) []byte { | |
| 40 | + | func encodeBenchmarkFrame(f wire.Frame) []byte { | |
| 41 | 41 | n := 1 + len(f.Payload) | |
| 42 | 42 | buf := make([]byte, frameHeaderLen+n) | |
| 43 | 43 | binary.BigEndian.PutUint32(buf[:frameHeaderLen], uint32(n)) | |
M internal/adapters/ipc/transport_observability_test.go +3 -2
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | 12 | ||
| 13 | 13 | "github.com/bnema/vev/internal/adapters/observability" | |
| 14 | 14 | "github.com/bnema/vev/internal/ports" | |
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 15 | 16 | ) | |
| 16 | 17 | ||
| 17 | 18 | func TestTransportObservabilityIPCEOFAndCloseEndFailedSpans(t *testing.T) { | |
| @@ -55,7 +56,7 @@ func TestTransportObservabilityIPCEOFAndCloseEndFailedSpans(t *testing.T) { | |||
| 55 | 56 | left, right := net.Pipe() | |
| 56 | 57 | transport := NewTransport(left, WithRuntimeObserver(reporter)) | |
| 57 | 58 | _ = right.Close() | |
| 58 | - | if err := transport.Send(ports.Frame{Type: ports.MsgOutput, Payload: []byte("failed")}); err == nil { | |
| 59 | + | if err := transport.Send(wire.Frame{Type: wire.MsgOutput, Payload: []byte("failed")}); err == nil { | |
| 59 | 60 | t.Fatal("Send() error = nil after peer close") | |
| 60 | 61 | } | |
| 61 | 62 | _ = transport.Close() | |
| @@ -152,7 +153,7 @@ func TestTransportObservabilityIPCMarksCarriageWithoutChangingBytes(t *testing.T | |||
| 152 | 153 | defer func() { _ = right.Close() }() | |
| 153 | 154 | client := NewTransport(left, WithRuntimeObserver(reporter)) | |
| 154 | 155 | server := NewTransport(right, WithRuntimeObserver(reporter)) | |
| 155 | - | want := ports.Frame{Type: ports.MsgOutput, Payload: []byte("wire bytes stay exact")} | |
| 156 | + | want := wire.Frame{Type: wire.MsgOutput, Payload: []byte("wire bytes stay exact")} | |
| 156 | 157 | ||
| 157 | 158 | var wg sync.WaitGroup | |
| 158 | 159 | wg.Go(func() { | |
M internal/adapters/ipc/transport_replay_test.go +3 -3
| @@ -5,12 +5,12 @@ import ( | |||
| 5 | 5 | "sync" | |
| 6 | 6 | "testing" | |
| 7 | 7 | ||
| 8 | - | "github.com/bnema/vev/internal/ports" | |
| 8 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 9 | 9 | "github.com/bnema/vev/internal/testutil/replaytest" | |
| 10 | 10 | ) | |
| 11 | 11 | ||
| 12 | 12 | func TestTransportReplay(t *testing.T) { | |
| 13 | - | replaytest.Run(t, func(t *testing.T, frames []ports.Frame) []ports.Frame { | |
| 13 | + | replaytest.Run(t, func(t *testing.T, frames []wire.Frame) []wire.Frame { | |
| 14 | 14 | left, right := net.Pipe() | |
| 15 | 15 | t.Cleanup(func() { _ = left.Close(); _ = right.Close() }) | |
| 16 | 16 | sender, receiver := NewTransport(left), NewTransport(right) | |
| @@ -24,7 +24,7 @@ func TestTransportReplay(t *testing.T) { | |||
| 24 | 24 | } | |
| 25 | 25 | } | |
| 26 | 26 | }) | |
| 27 | - | got := make([]ports.Frame, 0, len(frames)) | |
| 27 | + | got := make([]wire.Frame, 0, len(frames)) | |
| 28 | 28 | for range frames { | |
| 29 | 29 | frame, err := receiver.Recv() | |
| 30 | 30 | if err != nil { | |
M internal/adapters/ipc/transport_test.go +27 -26
| @@ -14,6 +14,7 @@ import ( | |||
| 14 | 14 | "github.com/bnema/vev/internal/domain" | |
| 15 | 15 | "github.com/bnema/vev/internal/ports" | |
| 16 | 16 | "github.com/bnema/vev/internal/protocol" | |
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 17 | 18 | ) | |
| 18 | 19 | ||
| 19 | 20 | func TestTransportSendRecvBothDirections(t *testing.T) { | |
| @@ -24,8 +25,8 @@ func TestTransportSendRecvBothDirections(t *testing.T) { | |||
| 24 | 25 | client := NewTransport(c1) | |
| 25 | 26 | server := NewTransport(c2) | |
| 26 | 27 | ||
| 27 | - | clientToServer := ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(protocol.Hello{Version: 1, Intent: protocol.IntentNew, Name: "w0"})} | |
| 28 | - | serverToClient := ports.Frame{Type: ports.MsgWelcome, Payload: ports.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: "main"})} | |
| 28 | + | clientToServer := wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(protocol.Hello{Version: 1, Intent: protocol.IntentNew, Name: "w0"})} | |
| 29 | + | serverToClient := wire.Frame{Type: wire.MsgWelcome, Payload: wire.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: "main"})} | |
| 29 | 30 | ||
| 30 | 31 | var wg sync.WaitGroup | |
| 31 | 32 | wg.Go(func() { | |
| @@ -97,12 +98,12 @@ func TestTransportLargeFrameNearCap(t *testing.T) { | |||
| 97 | 98 | server := NewTransport(c2) | |
| 98 | 99 | ||
| 99 | 100 | // Largest payload whose frame length (1 + len(payload)) still fits | |
| 100 | - | // exactly at ports.MaxFrameLen. | |
| 101 | - | payload := make([]byte, ports.MaxFrameLen-1) | |
| 101 | + | // exactly at wire.MaxFrameLen. | |
| 102 | + | payload := make([]byte, wire.MaxFrameLen-1) | |
| 102 | 103 | for i := range payload { | |
| 103 | 104 | payload[i] = byte(i) | |
| 104 | 105 | } | |
| 105 | - | want := ports.Frame{Type: ports.MsgOutput, Payload: payload} | |
| 106 | + | want := wire.Frame{Type: wire.MsgOutput, Payload: payload} | |
| 106 | 107 | ||
| 107 | 108 | var wg sync.WaitGroup | |
| 108 | 109 | wg.Go(func() { | |
| @@ -135,13 +136,13 @@ func TestTransportManySmallFramesBackToBack(t *testing.T) { | |||
| 135 | 136 | server := NewTransport(c2) | |
| 136 | 137 | ||
| 137 | 138 | const count = 200 | |
| 138 | - | frames := make([]ports.Frame, count) | |
| 139 | + | frames := make([]wire.Frame, count) | |
| 139 | 140 | for i := range frames { | |
| 140 | - | frames[i] = ports.Frame{Type: ports.MsgPing, Payload: nil} | |
| 141 | + | frames[i] = wire.Frame{Type: wire.MsgPing, Payload: nil} | |
| 141 | 142 | } | |
| 142 | 143 | // Vary a couple to prove ordering and content are both preserved. | |
| 143 | - | frames[7] = ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("hop")})} | |
| 144 | - | frames[150] = ports.Frame{Type: ports.MsgResize, Payload: mustMarshalResize(protocol.Resize{Size: domain.Size{Cols: 5, Rows: 6}})} | |
| 144 | + | frames[7] = wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("hop")})} | |
| 145 | + | frames[150] = wire.Frame{Type: wire.MsgResize, Payload: mustMarshalResize(protocol.Resize{Size: domain.Size{Cols: 5, Rows: 6}})} | |
| 145 | 146 | ||
| 146 | 147 | var wg sync.WaitGroup | |
| 147 | 148 | wg.Go(func() { | |
| @@ -178,7 +179,7 @@ func TestTransportRecvOversizeFrame(t *testing.T) { | |||
| 178 | 179 | ||
| 179 | 180 | go func() { | |
| 180 | 181 | var hdr [4]byte | |
| 181 | - | binary.BigEndian.PutUint32(hdr[:], ports.MaxFrameLen+1) | |
| 182 | + | binary.BigEndian.PutUint32(hdr[:], wire.MaxFrameLen+1) | |
| 182 | 183 | _, _ = c1.Write(hdr[:]) | |
| 183 | 184 | }() | |
| 184 | 185 | ||
| @@ -228,8 +229,8 @@ func TestTransportSendOversizePayloadRejected(t *testing.T) { | |||
| 228 | 229 | defer func() { _ = c2.Close() }() | |
| 229 | 230 | ||
| 230 | 231 | client := NewTransport(c1) | |
| 231 | - | payload := make([]byte, ports.MaxFrameLen) // +1 byte type => exceeds max | |
| 232 | - | err := client.Send(ports.Frame{Type: ports.MsgOutput, Payload: payload}) | |
| 232 | + | payload := make([]byte, wire.MaxFrameLen) // +1 byte type => exceeds max | |
| 233 | + | err := client.Send(wire.Frame{Type: wire.MsgOutput, Payload: payload}) | |
| 233 | 234 | if !errors.Is(err, ErrFrameTooLarge) { | |
| 234 | 235 | t.Fatalf("client.Send() error = %v, want ErrFrameTooLarge", err) | |
| 235 | 236 | } | |
| @@ -257,7 +258,7 @@ func TestTransportAsyncEgressPreservesWelcomeBeforeOutput(t *testing.T) { | |||
| 257 | 258 | t.Fatal("IPC transport does not implement AsyncTransport") | |
| 258 | 259 | } | |
| 259 | 260 | ||
| 260 | - | welcome := ports.Frame{Type: ports.MsgWelcome, Payload: []byte("welcome")} | |
| 261 | + | welcome := wire.Frame{Type: wire.MsgWelcome, Payload: []byte("welcome")} | |
| 261 | 262 | sent := make(chan error, 1) | |
| 262 | 263 | go func() { sent <- server.Send(welcome) }() | |
| 263 | 264 | got, err := client.Recv() | |
| @@ -277,16 +278,16 @@ func TestTransportAsyncEgressPreservesWelcomeBeforeOutput(t *testing.T) { | |||
| 277 | 278 | } | |
| 278 | 279 | ||
| 279 | 280 | payload := []byte("first") | |
| 280 | - | if err := async.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: payload}); err != nil { | |
| 281 | + | if err := async.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: payload}); err != nil { | |
| 281 | 282 | t.Fatalf("SendAsync first output: %v", err) | |
| 282 | 283 | } | |
| 283 | 284 | payload[0] = 'X' // async ownership must not retain caller memory. | |
| 284 | - | if err := async.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("second")}); err != nil { | |
| 285 | + | if err := async.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("second")}); err != nil { | |
| 285 | 286 | t.Fatalf("SendAsync second output: %v", err) | |
| 286 | 287 | } | |
| 287 | - | for _, want := range []ports.Frame{ | |
| 288 | - | {Type: ports.MsgOutput, Payload: []byte("first")}, | |
| 289 | - | {Type: ports.MsgOutput, Payload: []byte("second")}, | |
| 288 | + | for _, want := range []wire.Frame{ | |
| 289 | + | {Type: wire.MsgOutput, Payload: []byte("first")}, | |
| 290 | + | {Type: wire.MsgOutput, Payload: []byte("second")}, | |
| 290 | 291 | } { | |
| 291 | 292 | got, err := client.Recv() | |
| 292 | 293 | if err != nil { | |
| @@ -322,7 +323,7 @@ func TestTransportSendWaitsForEgressCapacity(t *testing.T) { | |||
| 322 | 323 | } | |
| 323 | 324 | ||
| 324 | 325 | queued := fillAsyncEgress(t, transport, async, timeout) | |
| 325 | - | want := ports.Frame{Type: ports.MsgOutput, Payload: []byte("synchronous")} | |
| 326 | + | want := wire.Frame{Type: wire.MsgOutput, Payload: []byte("synchronous")} | |
| 326 | 327 | sent := make(chan error, 1) | |
| 327 | 328 | go func() { sent <- server.Send(want) }() | |
| 328 | 329 | waitForEgressSender(t, transport, timeout) | |
| @@ -371,7 +372,7 @@ func TestTransportCloseInterruptsSendWaitingForEgressCapacity(t *testing.T) { | |||
| 371 | 372 | fillAsyncEgress(t, transport, async, timeout) | |
| 372 | 373 | ||
| 373 | 374 | sent := make(chan error, 1) | |
| 374 | - | go func() { sent <- server.Send(ports.Frame{Type: ports.MsgOutput, Payload: []byte("synchronous")}) }() | |
| 375 | + | go func() { sent <- server.Send(wire.Frame{Type: wire.MsgOutput, Payload: []byte("synchronous")}) }() | |
| 375 | 376 | waitForEgressSender(t, transport, timeout) | |
| 376 | 377 | ||
| 377 | 378 | closeTransport(t, server) | |
| @@ -421,18 +422,18 @@ func closeTransport(t *testing.T, transport ports.Transport) { | |||
| 421 | 422 | } | |
| 422 | 423 | } | |
| 423 | 424 | ||
| 424 | - | func fillAsyncEgress(t *testing.T, transport *unixTransport, async ports.AsyncTransport, timeout time.Duration) []ports.Frame { | |
| 425 | + | func fillAsyncEgress(t *testing.T, transport *unixTransport, async ports.AsyncTransport, timeout time.Duration) []wire.Frame { | |
| 425 | 426 | t.Helper() | |
| 426 | 427 | ||
| 427 | - | first := ports.Frame{Type: ports.MsgOutput, Payload: []byte{0}} | |
| 428 | + | first := wire.Frame{Type: wire.MsgOutput, Payload: []byte{0}} | |
| 428 | 429 | if err := async.SendAsync(first); err != nil { | |
| 429 | 430 | t.Fatalf("SendAsync blocked frame: %v", err) | |
| 430 | 431 | } | |
| 431 | 432 | waitForEgressDequeue(t, transport, timeout) | |
| 432 | 433 | ||
| 433 | - | queued := []ports.Frame{first} | |
| 434 | + | queued := []wire.Frame{first} | |
| 434 | 435 | for i := 1; ; i++ { | |
| 435 | - | frame := ports.Frame{Type: ports.MsgOutput, Payload: []byte{byte(i)}} | |
| 436 | + | frame := wire.Frame{Type: wire.MsgOutput, Payload: []byte{byte(i)}} | |
| 436 | 437 | err := async.SendAsync(frame) | |
| 437 | 438 | switch { | |
| 438 | 439 | case err == nil: | |
| @@ -479,12 +480,12 @@ func TestTransportAsyncEgressIsBoundedAndCloseInterruptsWorkers(t *testing.T) { | |||
| 479 | 480 | } | |
| 480 | 481 | ||
| 481 | 482 | // The first write blocks in net.Pipe because the peer never drains it. | |
| 482 | - | if err := async.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("blocked")}); err != nil { | |
| 483 | + | if err := async.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("blocked")}); err != nil { | |
| 483 | 484 | t.Fatalf("SendAsync blocked frame: %v", err) | |
| 484 | 485 | } | |
| 485 | 486 | var backpressure error | |
| 486 | 487 | for range sendQueueCapacity + 2 { | |
| 487 | - | err := async.SendAsync(ports.Frame{Type: ports.MsgOutput, Payload: []byte("queued")}) | |
| 488 | + | err := async.SendAsync(wire.Frame{Type: wire.MsgOutput, Payload: []byte("queued")}) | |
| 488 | 489 | if errors.Is(err, ErrBackpressure) { | |
| 489 | 490 | backpressure = err | |
| 490 | 491 | break | |
M internal/adapters/ipc/wire_test_helpers_test.go +2 -2
| @@ -1,12 +1,12 @@ | |||
| 1 | 1 | package ipc | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | - | "github.com/bnema/vev/internal/ports" | |
| 5 | 4 | "github.com/bnema/vev/internal/protocol" | |
| 5 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 6 | 6 | ) | |
| 7 | 7 | ||
| 8 | 8 | func mustMarshalResize(m protocol.Resize) []byte { | |
| 9 | - | payload, err := ports.MarshalResize(m) | |
| 9 | + | payload, err := wire.MarshalResize(m) | |
| 10 | 10 | if err != nil { | |
| 11 | 11 | panic(err) | |
| 12 | 12 | } | |
M internal/adapters/remote/preview.go +3 -2
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | 12 | "github.com/bnema/vev/internal/domain" | |
| 13 | 13 | "github.com/bnema/vev/internal/ports" | |
| 14 | 14 | "github.com/bnema/vev/internal/protocol" | |
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 15 | 16 | ) | |
| 16 | 17 | ||
| 17 | 18 | const ( | |
| @@ -42,7 +43,7 @@ func NewPreviewClient() ports.RemotePreviewClient { | |||
| 42 | 43 | ||
| 43 | 44 | func (c *PreviewClient) Preview(ctx context.Context, target domain.RemoteSessionTarget, width, height uint16) (protocol.RemotePreview, error) { | |
| 44 | 45 | request := protocol.RemotePreviewRequest{Version: protocol.RemotePreviewSchemaVersion, Target: target, Width: width, Height: height} | |
| 45 | - | payload := ports.MarshalRemotePreviewRequest(request) | |
| 46 | + | payload := wire.MarshalRemotePreviewRequest(request) | |
| 46 | 47 | if payload == nil { | |
| 47 | 48 | return protocol.RemotePreview{}, protocol.ErrInvalidRemotePreviewRequest | |
| 48 | 49 | } | |
| @@ -78,7 +79,7 @@ func (c *PreviewClient) Preview(ctx context.Context, target domain.RemoteSession | |||
| 78 | 79 | if stdout.overflow || stderr.overflow { | |
| 79 | 80 | return protocol.RemotePreview{}, errRemotePreviewTooLarge | |
| 80 | 81 | } | |
| 81 | - | preview, err := ports.UnmarshalRemotePreview(stdout.Bytes()) | |
| 82 | + | preview, err := wire.UnmarshalRemotePreview(stdout.Bytes()) | |
| 82 | 83 | if err != nil { | |
| 83 | 84 | return protocol.RemotePreview{}, err | |
| 84 | 85 | } | |
M internal/adapters/remote/preview_test.go +4 -4
| @@ -15,8 +15,8 @@ import ( | |||
| 15 | 15 | renderer "github.com/bnema/vev-vt" | |
| 16 | 16 | "github.com/bnema/vev/internal/adapters/sshstdio" | |
| 17 | 17 | "github.com/bnema/vev/internal/domain" | |
| 18 | - | "github.com/bnema/vev/internal/ports" | |
| 19 | 18 | "github.com/bnema/vev/internal/protocol" | |
| 19 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 20 | 20 | ) | |
| 21 | 21 | ||
| 22 | 22 | func previewClientTargetForTest() domain.RemoteSessionTarget { | |
| @@ -37,7 +37,7 @@ func TestRemotePreviewClientBuildsExactSSHCommandAndDecodesResponse(t *testing.T | |||
| 37 | 37 | LifecycleID: lifecycle, TabID: target.LiveTabID, Revision: 7, Width: 1, Height: 1, | |
| 38 | 38 | Cells: []renderer.Cell{{Rune: 'x', Style: renderer.DefaultStyle()}}, | |
| 39 | 39 | } | |
| 40 | - | payload := ports.MarshalRemotePreview(want) | |
| 40 | + | payload := wire.MarshalRemotePreview(want) | |
| 41 | 41 | require.NotNil(t, payload) | |
| 42 | 42 | ||
| 43 | 43 | var gotPath string | |
| @@ -57,7 +57,7 @@ func TestRemotePreviewClientBuildsExactSSHCommandAndDecodesResponse(t *testing.T | |||
| 57 | 57 | if err != nil { | |
| 58 | 58 | t.Fatalf("decode request: %v", err) | |
| 59 | 59 | } | |
| 60 | - | request, err := ports.UnmarshalRemotePreviewRequest(requestPayload) | |
| 60 | + | request, err := wire.UnmarshalRemotePreviewRequest(requestPayload) | |
| 61 | 61 | if err != nil { | |
| 62 | 62 | t.Fatalf("decode request payload: %v", err) | |
| 63 | 63 | } | |
| @@ -96,7 +96,7 @@ func TestRemotePreviewClientRejectsMismatchedResponseIdentity(t *testing.T) { | |||
| 96 | 96 | t.Run(tt.name, func(t *testing.T) { | |
| 97 | 97 | preview := valid | |
| 98 | 98 | tt.mutate(&preview) | |
| 99 | - | payload := ports.MarshalRemotePreview(preview) | |
| 99 | + | payload := wire.MarshalRemotePreview(preview) | |
| 100 | 100 | require.NotNil(t, payload) | |
| 101 | 101 | ||
| 102 | 102 | client := &PreviewClient{command: func(ctx context.Context, _ string, _ ...string) *exec.Cmd { | |
M internal/adapters/sshstdio/transport.go +9 -8
| @@ -19,10 +19,11 @@ import ( | |||
| 19 | 19 | "time" | |
| 20 | 20 | ||
| 21 | 21 | "github.com/bnema/vev/internal/ports" | |
| 22 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 22 | 23 | ) | |
| 23 | 24 | ||
| 24 | 25 | const ( | |
| 25 | - | maxFrameLen = ports.MaxFrameLen | |
| 26 | + | maxFrameLen = wire.MaxFrameLen | |
| 26 | 27 | frameHeaderLen = 4 | |
| 27 | 28 | sshCloseTimeout = 3 * time.Second | |
| 28 | 29 | ) | |
| @@ -260,7 +261,7 @@ func (r processStdinReader) Read(dst []byte) (int, error) { | |||
| 260 | 261 | return r.pump.read(r.done, dst) | |
| 261 | 262 | } | |
| 262 | 263 | ||
| 263 | - | func (t *transport) Send(f ports.Frame) error { | |
| 264 | + | func (t *transport) Send(f wire.Frame) error { | |
| 264 | 265 | end := t.beginOperation(ports.RuntimeAdapterSendStart, uint64(len(f.Payload))) | |
| 265 | 266 | n := 1 + len(f.Payload) | |
| 266 | 267 | if n > maxFrameLen { | |
| @@ -280,23 +281,23 @@ func (t *transport) Send(f ports.Frame) error { | |||
| 280 | 281 | return err | |
| 281 | 282 | } | |
| 282 | 283 | ||
| 283 | - | func (t *transport) Recv() (ports.Frame, error) { | |
| 284 | + | func (t *transport) Recv() (wire.Frame, error) { | |
| 284 | 285 | end := t.beginOperation(ports.RuntimeAdapterReceiveStart, 0) | |
| 285 | 286 | var hdr [frameHeaderLen]byte | |
| 286 | 287 | if _, err := io.ReadFull(t.r, hdr[:]); err != nil { | |
| 287 | 288 | err = t.mapEOFError(err) | |
| 288 | 289 | end(false) | |
| 289 | - | return ports.Frame{}, err | |
| 290 | + | return wire.Frame{}, err | |
| 290 | 291 | } | |
| 291 | 292 | ||
| 292 | 293 | n := binary.BigEndian.Uint32(hdr[:]) | |
| 293 | 294 | if n == 0 { | |
| 294 | 295 | end(false) | |
| 295 | - | return ports.Frame{}, ErrZeroLengthFrame | |
| 296 | + | return wire.Frame{}, ErrZeroLengthFrame | |
| 296 | 297 | } | |
| 297 | 298 | if n > maxFrameLen { | |
| 298 | 299 | end(false) | |
| 299 | - | return ports.Frame{}, ErrFrameTooLarge | |
| 300 | + | return wire.Frame{}, ErrFrameTooLarge | |
| 300 | 301 | } | |
| 301 | 302 | ||
| 302 | 303 | if cap(t.readBuf) < int(n) { | |
| @@ -307,12 +308,12 @@ func (t *transport) Recv() (ports.Frame, error) { | |||
| 307 | 308 | if _, err := io.ReadFull(t.r, t.readBuf); err != nil { | |
| 308 | 309 | err = t.mapEOFError(err) | |
| 309 | 310 | end(false) | |
| 310 | - | return ports.Frame{}, err | |
| 311 | + | return wire.Frame{}, err | |
| 311 | 312 | } | |
| 312 | 313 | ||
| 313 | 314 | payload := append([]byte(nil), t.readBuf[1:]...) | |
| 314 | 315 | end(true) | |
| 315 | - | return ports.Frame{Type: ports.MsgType(t.readBuf[0]), Payload: payload}, nil | |
| 316 | + | return wire.Frame{Type: wire.MsgType(t.readBuf[0]), Payload: payload}, nil | |
| 316 | 317 | } | |
| 317 | 318 | ||
| 318 | 319 | func (t *transport) beginOperation(start ports.RuntimeMarkKind, bytes uint64) func(bool) { | |
M internal/adapters/sshstdio/transport_observability_test.go +2 -1
| @@ -13,6 +13,7 @@ import ( | |||
| 13 | 13 | ||
| 14 | 14 | "github.com/bnema/vev/internal/adapters/observability" | |
| 15 | 15 | "github.com/bnema/vev/internal/ports" | |
| 16 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 16 | 17 | ) | |
| 17 | 18 | ||
| 18 | 19 | func TestTransportObservabilitySSHStdioEOFEndsReceive(t *testing.T) { | |
| @@ -212,7 +213,7 @@ func TestTransportObservabilitySSHStdioPreservesCarriage(t *testing.T) { | |||
| 212 | 213 | reporter := ports.NewSerializedRuntimeObserver(observer, 64) | |
| 213 | 214 | defer reporter.Close() | |
| 214 | 215 | ||
| 215 | - | frame := ports.Frame{Type: ports.MsgOutput, Payload: []byte("stdio bytes stay exact")} | |
| 216 | + | frame := wire.Frame{Type: wire.MsgOutput, Payload: []byte("stdio bytes stay exact")} | |
| 216 | 217 | var observed, baseline bytes.Buffer | |
| 217 | 218 | if err := NewTransport(bytes.NewReader(nil), &observed, nil, WithRuntimeObserver(reporter)).Send(frame); err != nil { | |
| 218 | 219 | t.Fatalf("observed Send() error = %v", err) | |
M internal/adapters/sshstdio/transport_replay_test.go +3 -3
| @@ -5,12 +5,12 @@ import ( | |||
| 5 | 5 | "sync" | |
| 6 | 6 | "testing" | |
| 7 | 7 | ||
| 8 | - | "github.com/bnema/vev/internal/ports" | |
| 8 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 9 | 9 | "github.com/bnema/vev/internal/testutil/replaytest" | |
| 10 | 10 | ) | |
| 11 | 11 | ||
| 12 | 12 | func TestTransportReplay(t *testing.T) { | |
| 13 | - | replaytest.Run(t, func(t *testing.T, frames []ports.Frame) []ports.Frame { | |
| 13 | + | replaytest.Run(t, func(t *testing.T, frames []wire.Frame) []wire.Frame { | |
| 14 | 14 | clientRead, serverWrite := io.Pipe() | |
| 15 | 15 | serverRead, clientWrite := io.Pipe() | |
| 16 | 16 | sender := NewTransport(clientRead, clientWrite, func() error { return clientWrite.Close() }) | |
| @@ -26,7 +26,7 @@ func TestTransportReplay(t *testing.T) { | |||
| 26 | 26 | } | |
| 27 | 27 | } | |
| 28 | 28 | }) | |
| 29 | - | got := make([]ports.Frame, 0, len(frames)) | |
| 29 | + | got := make([]wire.Frame, 0, len(frames)) | |
| 30 | 30 | for range frames { | |
| 31 | 31 | frame, err := receiver.Recv() | |
| 32 | 32 | if err != nil { | |
M internal/adapters/sshstdio/transport_test.go +15 -15
| @@ -14,8 +14,8 @@ import ( | |||
| 14 | 14 | "time" | |
| 15 | 15 | ||
| 16 | 16 | "github.com/bnema/vev/internal/domain" | |
| 17 | - | "github.com/bnema/vev/internal/ports" | |
| 18 | 17 | "github.com/bnema/vev/internal/protocol" | |
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 19 | 19 | ) | |
| 20 | 20 | ||
| 21 | 21 | func TestBuildCommandUsesExecArgs(t *testing.T) { | |
| @@ -114,7 +114,7 @@ func TestCloseInterruptsBlockedSend(t *testing.T) { | |||
| 114 | 114 | transport := NewTransport(nil, writer, nil) | |
| 115 | 115 | ||
| 116 | 116 | sendDone := make(chan error, 1) | |
| 117 | - | go func() { sendDone <- transport.Send(ports.Frame{Type: ports.MsgOutput, Payload: []byte("blocked")}) }() | |
| 117 | + | go func() { sendDone <- transport.Send(wire.Frame{Type: wire.MsgOutput, Payload: []byte("blocked")}) }() | |
| 118 | 118 | <-writer.started | |
| 119 | 119 | if err := transport.Close(); err != nil { | |
| 120 | 120 | t.Fatalf("Close() error = %v", err) | |
| @@ -166,7 +166,7 @@ func TestTransportRoundTripAndVersionMismatchFrame(t *testing.T) { | |||
| 166 | 166 | t.Errorf("server Recv: %v", err) | |
| 167 | 167 | return | |
| 168 | 168 | } | |
| 169 | - | got, err := ports.UnmarshalHello(f.Payload) | |
| 169 | + | got, err := wire.UnmarshalHello(f.Payload) | |
| 170 | 170 | if err != nil { | |
| 171 | 171 | t.Errorf("UnmarshalHello: %v", err) | |
| 172 | 172 | return | |
| @@ -174,20 +174,20 @@ func TestTransportRoundTripAndVersionMismatchFrame(t *testing.T) { | |||
| 174 | 174 | if got.Version == protocol.Version { | |
| 175 | 175 | t.Errorf("test did not send a mismatched version") | |
| 176 | 176 | } | |
| 177 | - | _ = server.Send(ports.Frame{Type: ports.MsgError, Payload: ports.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "protocol version mismatch"})}) | |
| 177 | + | _ = server.Send(wire.Frame{Type: wire.MsgError, Payload: wire.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "protocol version mismatch"})}) | |
| 178 | 178 | }() | |
| 179 | 179 | ||
| 180 | - | if err := client.Send(ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(hello)}); err != nil { | |
| 180 | + | if err := client.Send(wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(hello)}); err != nil { | |
| 181 | 181 | t.Fatalf("client Send: %v", err) | |
| 182 | 182 | } | |
| 183 | 183 | reply, err := client.Recv() | |
| 184 | 184 | if err != nil { | |
| 185 | 185 | t.Fatalf("client Recv: %v", err) | |
| 186 | 186 | } | |
| 187 | - | if reply.Type != ports.MsgError { | |
| 187 | + | if reply.Type != wire.MsgError { | |
| 188 | 188 | t.Fatalf("reply type = %d, want MsgError", reply.Type) | |
| 189 | 189 | } | |
| 190 | - | em, err := ports.UnmarshalErrorMsg(reply.Payload) | |
| 190 | + | em, err := wire.UnmarshalErrorMsg(reply.Payload) | |
| 191 | 191 | if err != nil { | |
| 192 | 192 | t.Fatalf("UnmarshalErrorMsg: %v", err) | |
| 193 | 193 | } | |
| @@ -205,35 +205,35 @@ func TestTransportRejectsZeroLengthFrame(t *testing.T) { | |||
| 205 | 205 | } | |
| 206 | 206 | ||
| 207 | 207 | func TestTransportUsesCanonicalFrameMaximum(t *testing.T) { | |
| 208 | - | boundaryPayload := make([]byte, ports.MaxFrameLen-1) | |
| 208 | + | boundaryPayload := make([]byte, wire.MaxFrameLen-1) | |
| 209 | 209 | boundaryWire := &bytes.Buffer{} | |
| 210 | 210 | boundarySend := NewTransport(nil, boundaryWire, nil) | |
| 211 | - | if err := boundarySend.Send(ports.Frame{Type: ports.MsgOutput, Payload: boundaryPayload}); err != nil { | |
| 211 | + | if err := boundarySend.Send(wire.Frame{Type: wire.MsgOutput, Payload: boundaryPayload}); err != nil { | |
| 212 | 212 | t.Fatalf("boundary Send error = %v", err) | |
| 213 | 213 | } | |
| 214 | - | if got := binary.BigEndian.Uint32(boundaryWire.Bytes()[:frameHeaderLen]); got != ports.MaxFrameLen { | |
| 215 | - | t.Fatalf("boundary frame length = %d, want %d", got, ports.MaxFrameLen) | |
| 214 | + | if got := binary.BigEndian.Uint32(boundaryWire.Bytes()[:frameHeaderLen]); got != wire.MaxFrameLen { | |
| 215 | + | t.Fatalf("boundary frame length = %d, want %d", got, wire.MaxFrameLen) | |
| 216 | 216 | } | |
| 217 | 217 | boundaryRecv := NewTransport(bytes.NewReader(boundaryWire.Bytes()), io.Discard, nil) | |
| 218 | 218 | boundaryFrame, err := boundaryRecv.Recv() | |
| 219 | 219 | if err != nil { | |
| 220 | 220 | t.Fatalf("boundary Recv error = %v", err) | |
| 221 | 221 | } | |
| 222 | - | if boundaryFrame.Type != ports.MsgOutput || len(boundaryFrame.Payload) != len(boundaryPayload) { | |
| 223 | - | t.Fatalf("boundary frame = type %d, payload %d bytes; want type %d, payload %d bytes", boundaryFrame.Type, len(boundaryFrame.Payload), ports.MsgOutput, len(boundaryPayload)) | |
| 222 | + | if boundaryFrame.Type != wire.MsgOutput || len(boundaryFrame.Payload) != len(boundaryPayload) { | |
| 223 | + | t.Fatalf("boundary frame = type %d, payload %d bytes; want type %d, payload %d bytes", boundaryFrame.Type, len(boundaryFrame.Payload), wire.MsgOutput, len(boundaryPayload)) | |
| 224 | 224 | } | |
| 225 | 225 | if !bytes.Equal(boundaryFrame.Payload, boundaryPayload) { | |
| 226 | 226 | t.Fatal("boundary payload was corrupted") | |
| 227 | 227 | } | |
| 228 | 228 | ||
| 229 | 229 | send := NewTransport(nil, io.Discard, nil) | |
| 230 | - | err = send.Send(ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, ports.MaxFrameLen)}) | |
| 230 | + | err = send.Send(wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, wire.MaxFrameLen)}) | |
| 231 | 231 | if !errors.Is(err, ErrFrameTooLarge) { | |
| 232 | 232 | t.Fatalf("Send error = %v, want ErrFrameTooLarge", err) | |
| 233 | 233 | } | |
| 234 | 234 | ||
| 235 | 235 | var header [frameHeaderLen]byte | |
| 236 | - | binary.BigEndian.PutUint32(header[:], ports.MaxFrameLen+1) | |
| 236 | + | binary.BigEndian.PutUint32(header[:], wire.MaxFrameLen+1) | |
| 237 | 237 | recv := NewTransport(bytes.NewReader(header[:]), io.Discard, nil) | |
| 238 | 238 | _, err = recv.Recv() | |
| 239 | 239 | if !errors.Is(err, ErrFrameTooLarge) { | |
M internal/app/cmd.go +6 -5
| @@ -14,6 +14,7 @@ import ( | |||
| 14 | 14 | "github.com/bnema/vev/internal/adapters/ipc" | |
| 15 | 15 | "github.com/bnema/vev/internal/ports" | |
| 16 | 16 | "github.com/bnema/vev/internal/protocol" | |
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 17 | 18 | commandusecase "github.com/bnema/vev/internal/usecase/command" | |
| 18 | 19 | "github.com/bnema/vev/internal/usecase/daemon" | |
| 19 | 20 | ) | |
| @@ -170,7 +171,7 @@ func runCmdWithDeps(ctx context.Context, invocation cmdInvocation, deps cmdDeps) | |||
| 170 | 171 | return usagef("--self requires running inside a vev pane") | |
| 171 | 172 | } | |
| 172 | 173 | ||
| 173 | - | if _, err := ports.MarshalCommandRequest(request); errors.Is(err, ports.ErrTooManyCommandArgs) { | |
| 174 | + | if _, err := wire.MarshalCommandRequest(request); errors.Is(err, wire.ErrTooManyCommandArgs) { | |
| 174 | 175 | return usagef("too many command arguments") | |
| 175 | 176 | } else if err != nil { | |
| 176 | 177 | return fmt.Errorf("encoding command: %w", err) | |
| @@ -190,12 +191,12 @@ func runCmdWithDeps(ctx context.Context, invocation cmdInvocation, deps cmdDeps) | |||
| 190 | 191 | const generation = uint64(1) | |
| 191 | 192 | requestID, outcome := tracker.Publish(generation) | |
| 192 | 193 | request.RequestID = requestID | |
| 193 | - | payload, err := ports.MarshalCommandRequest(request) | |
| 194 | + | payload, err := wire.MarshalCommandRequest(request) | |
| 194 | 195 | if err != nil { | |
| 195 | 196 | tracker.Remove(requestID, generation) | |
| 196 | 197 | return fmt.Errorf("encoding command: %w", err) | |
| 197 | 198 | } | |
| 198 | - | if err := transport.Send(ports.Frame{Type: ports.MsgCommand, Payload: payload}); err != nil { | |
| 199 | + | if err := transport.Send(wire.Frame{Type: wire.MsgCommand, Payload: payload}); err != nil { | |
| 199 | 200 | tracker.Remove(requestID, generation) | |
| 200 | 201 | return &exitCoded{code: 3, err: fmt.Errorf("sending command: %w", err)} | |
| 201 | 202 | } | |
| @@ -205,11 +206,11 @@ func runCmdWithDeps(ctx context.Context, invocation cmdInvocation, deps cmdDeps) | |||
| 205 | 206 | tracker.Fail(requestID, generation, fmt.Errorf("reading command reply: %w", recvErr)) | |
| 206 | 207 | return | |
| 207 | 208 | } | |
| 208 | - | if reply.Type != ports.MsgCommandResult { | |
| 209 | + | if reply.Type != wire.MsgCommandResult { | |
| 209 | 210 | tracker.Fail(requestID, generation, fmt.Errorf("unexpected command reply type %d", reply.Type)) | |
| 210 | 211 | return | |
| 211 | 212 | } | |
| 212 | - | result, decodeErr := ports.UnmarshalCommandResult(reply.Payload) | |
| 213 | + | result, decodeErr := wire.UnmarshalCommandResult(reply.Payload) | |
| 213 | 214 | if decodeErr != nil { | |
| 214 | 215 | tracker.Fail(requestID, generation, fmt.Errorf("decoding command reply: %w", decodeErr)) | |
| 215 | 216 | return | |
M internal/app/cmd_test.go +21 -20
| @@ -14,6 +14,7 @@ import ( | |||
| 14 | 14 | "github.com/bnema/vev/internal/ports" | |
| 15 | 15 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 16 | 16 | "github.com/bnema/vev/internal/protocol" | |
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 17 | 18 | "github.com/bnema/vev/internal/usecase/daemon" | |
| 18 | 19 | "github.com/stretchr/testify/mock" | |
| 19 | 20 | "github.com/stretchr/testify/require" | |
| @@ -141,14 +142,14 @@ func TestMoveCmdPreservesPositionalArguments(t *testing.T) { | |||
| 141 | 142 | t.Run(tt.slug, func(t *testing.T) { | |
| 142 | 143 | parsed, err := parseArgs(append([]string{"cmd", tt.slug}, tt.args...)) | |
| 143 | 144 | require.NoError(t, err) | |
| 144 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{OK: true})}} | |
| 145 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{OK: true})}} | |
| 145 | 146 | require.NoError(t, runCmdWithDeps(context.Background(), parsed.cmd, cmdDeps{ | |
| 146 | 147 | stdout: io.Discard, | |
| 147 | 148 | getenv: func(string) string { return "" }, | |
| 148 | 149 | dial: func(context.Context, string) (ports.Transport, error) { return transport, nil }, | |
| 149 | 150 | })) | |
| 150 | 151 | require.Len(t, transport.sent, 1) | |
| 151 | - | request, err := ports.UnmarshalCommandRequest(transport.sent[0].Payload) | |
| 152 | + | request, err := wire.UnmarshalCommandRequest(transport.sent[0].Payload) | |
| 152 | 153 | require.NoError(t, err) | |
| 153 | 154 | require.Equal(t, tt.slug, request.Slug) | |
| 154 | 155 | require.Equal(t, tt.args, request.Args) | |
| @@ -158,7 +159,7 @@ func TestMoveCmdPreservesPositionalArguments(t *testing.T) { | |||
| 158 | 159 | } | |
| 159 | 160 | ||
| 160 | 161 | func TestRemoteCatalogCommandEnsuresDaemon(t *testing.T) { | |
| 161 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{OK: true})}} | |
| 162 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{OK: true})}} | |
| 162 | 163 | ensureCalls := 0 | |
| 163 | 164 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "remote-catalog", jsonOut: true}, cmdDeps{ | |
| 164 | 165 | stdout: io.Discard, | |
| @@ -184,7 +185,7 @@ func TestMoveCmdInvalidArgumentResultExitsTwo(t *testing.T) { | |||
| 184 | 185 | {slug: "move-tab", args: []string{"work", "extra"}}, | |
| 185 | 186 | } { | |
| 186 | 187 | t.Run(invocation.slug+"/"+strconv.Itoa(len(invocation.args)), func(t *testing.T) { | |
| 187 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{ | |
| 188 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{ | |
| 188 | 189 | Code: protocol.ErrInvalidCommandArgs, Text: "invalid command arguments", | |
| 189 | 190 | })}} | |
| 190 | 191 | err := runCmdWithDeps(context.Background(), invocation, cmdDeps{ | |
| @@ -207,14 +208,14 @@ func TestTargetPaneCmdsParseAndUseSelfTarget(t *testing.T) { | |||
| 207 | 208 | t.Run(slug, func(t *testing.T) { | |
| 208 | 209 | invocation, err := parseArgs([]string{"cmd", "--self", slug}) | |
| 209 | 210 | require.NoError(t, err) | |
| 210 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{OK: true})}} | |
| 211 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{OK: true})}} | |
| 211 | 212 | require.NoError(t, runCmdWithDeps(context.Background(), invocation.cmd, cmdDeps{ | |
| 212 | 213 | stdout: io.Discard, | |
| 213 | 214 | getenv: func(string) string { return "session=work,tab=t_abc,pane=p_def" }, | |
| 214 | 215 | dial: func(context.Context, string) (ports.Transport, error) { return transport, nil }, | |
| 215 | 216 | })) | |
| 216 | 217 | require.Len(t, transport.sent, 1) | |
| 217 | - | request, err := ports.UnmarshalCommandRequest(transport.sent[0].Payload) | |
| 218 | + | request, err := wire.UnmarshalCommandRequest(transport.sent[0].Payload) | |
| 218 | 219 | require.NoError(t, err) | |
| 219 | 220 | require.Equal(t, slug, request.Slug) | |
| 220 | 221 | require.True(t, request.Self) | |
| @@ -226,7 +227,7 @@ func TestTargetPaneCmdsParseAndUseSelfTarget(t *testing.T) { | |||
| 226 | 227 | } | |
| 227 | 228 | ||
| 228 | 229 | func TestRunCmdBuildsOneShotTargetedRequest(t *testing.T) { | |
| 229 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{OK: true, Output: "done"})}} | |
| 230 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{OK: true, Output: "done"})}} | |
| 230 | 231 | out := new(strings.Builder) | |
| 231 | 232 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "split-right", self: true}, cmdDeps{ | |
| 232 | 233 | stdout: out, | |
| @@ -239,11 +240,11 @@ func TestRunCmdBuildsOneShotTargetedRequest(t *testing.T) { | |||
| 239 | 240 | if len(transport.sent) != 1 || transport.recvCalls != 1 || transport.closeCalls != 1 { | |
| 240 | 241 | t.Fatalf("transport calls: sent=%d recv=%d close=%d", len(transport.sent), transport.recvCalls, transport.closeCalls) | |
| 241 | 242 | } | |
| 242 | - | req, err := ports.UnmarshalCommandRequest(transport.sent[0].Payload) | |
| 243 | + | req, err := wire.UnmarshalCommandRequest(transport.sent[0].Payload) | |
| 243 | 244 | if err != nil { | |
| 244 | 245 | t.Fatalf("decode request: %v", err) | |
| 245 | 246 | } | |
| 246 | - | if transport.sent[0].Type != ports.MsgCommand || req.Slug != "split-right" || !req.Self || req.TargetSession != "old" || req.TargetTab != "t_abc" || req.TargetPane != "p_def" { | |
| 247 | + | if transport.sent[0].Type != wire.MsgCommand || req.Slug != "split-right" || !req.Self || req.TargetSession != "old" || req.TargetTab != "t_abc" || req.TargetPane != "p_def" { | |
| 247 | 248 | t.Fatalf("request = type %d %+v", transport.sent[0].Type, req) | |
| 248 | 249 | } | |
| 249 | 250 | if out.String() != "done\n" { | |
| @@ -252,7 +253,7 @@ func TestRunCmdBuildsOneShotTargetedRequest(t *testing.T) { | |||
| 252 | 253 | } | |
| 253 | 254 | ||
| 254 | 255 | func TestRunCmdVEVWithoutSelfUsesIDsOnlyAsSessionLocator(t *testing.T) { | |
| 255 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{OK: true})}} | |
| 256 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{OK: true})}} | |
| 256 | 257 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "split-right"}, cmdDeps{ | |
| 257 | 258 | stdout: io.Discard, | |
| 258 | 259 | getenv: func(string) string { return "session=old,tab=t_abc,pane=p_def" }, | |
| @@ -261,7 +262,7 @@ func TestRunCmdVEVWithoutSelfUsesIDsOnlyAsSessionLocator(t *testing.T) { | |||
| 261 | 262 | if err != nil { | |
| 262 | 263 | t.Fatalf("runCmdWithDeps: %v", err) | |
| 263 | 264 | } | |
| 264 | - | req, err := ports.UnmarshalCommandRequest(transport.sent[0].Payload) | |
| 265 | + | req, err := wire.UnmarshalCommandRequest(transport.sent[0].Payload) | |
| 265 | 266 | if err != nil { | |
| 266 | 267 | t.Fatalf("decode request: %v", err) | |
| 267 | 268 | } | |
| @@ -271,7 +272,7 @@ func TestRunCmdVEVWithoutSelfUsesIDsOnlyAsSessionLocator(t *testing.T) { | |||
| 271 | 272 | } | |
| 272 | 273 | ||
| 273 | 274 | func TestRunCmdExplicitSessionDoesNotUseEnvIDsWithoutSelf(t *testing.T) { | |
| 274 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{OK: true})}} | |
| 275 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{OK: true})}} | |
| 275 | 276 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "new-tab", session: "current"}, cmdDeps{ | |
| 276 | 277 | stdout: io.Discard, | |
| 277 | 278 | getenv: func(string) string { return "session=old,tab=t_abc,pane=p_def" }, | |
| @@ -280,7 +281,7 @@ func TestRunCmdExplicitSessionDoesNotUseEnvIDsWithoutSelf(t *testing.T) { | |||
| 280 | 281 | if err != nil { | |
| 281 | 282 | t.Fatalf("runCmdWithDeps: %v", err) | |
| 282 | 283 | } | |
| 283 | - | req, err := ports.UnmarshalCommandRequest(transport.sent[0].Payload) | |
| 284 | + | req, err := wire.UnmarshalCommandRequest(transport.sent[0].Payload) | |
| 284 | 285 | if err != nil { | |
| 285 | 286 | t.Fatalf("decode request: %v", err) | |
| 286 | 287 | } | |
| @@ -343,7 +344,7 @@ func TestRunCmdTimesOutPendingRequest(t *testing.T) { | |||
| 343 | 344 | if ExitCode(err) != 3 || !errors.Is(err, daemon.ErrCommandRequestTimeout) { | |
| 344 | 345 | t.Fatalf("timeout error=%v code=%d", err, ExitCode(err)) | |
| 345 | 346 | } | |
| 346 | - | request, decodeErr := ports.UnmarshalCommandRequest(transport.sent[0].Payload) | |
| 347 | + | request, decodeErr := wire.UnmarshalCommandRequest(transport.sent[0].Payload) | |
| 347 | 348 | if decodeErr != nil || request.RequestID == 0 { | |
| 348 | 349 | t.Fatalf("request=%+v decode=%v, want non-zero request ID", request, decodeErr) | |
| 349 | 350 | } | |
| @@ -351,7 +352,7 @@ func TestRunCmdTimesOutPendingRequest(t *testing.T) { | |||
| 351 | 352 | ||
| 352 | 353 | func TestRunCmdZeroRequestIDReplyReturnsDaemonError(t *testing.T) { | |
| 353 | 354 | const want = "daemon error" | |
| 354 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(protocol.CommandResult{ | |
| 355 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(protocol.CommandResult{ | |
| 355 | 356 | Code: protocol.ErrInternal, Text: want, | |
| 356 | 357 | })}} | |
| 357 | 358 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "split-right"}, cmdDeps{ | |
| @@ -415,7 +416,7 @@ func TestRunCmdClassifiesDaemonCommandErrors(t *testing.T) { | |||
| 415 | 416 | } | |
| 416 | 417 | for _, tt := range tests { | |
| 417 | 418 | t.Run(tt.name, func(t *testing.T) { | |
| 418 | - | transport := &cmdTestTransport{recv: ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(tt.result)}} | |
| 419 | + | transport := &cmdTestTransport{recv: wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(tt.result)}} | |
| 419 | 420 | err := runCmdWithDeps(context.Background(), cmdInvocation{slug: "split-right"}, cmdDeps{ | |
| 420 | 421 | stdout: io.Discard, | |
| 421 | 422 | getenv: func(string) string { return "" }, | |
| @@ -429,8 +430,8 @@ func TestRunCmdClassifiesDaemonCommandErrors(t *testing.T) { | |||
| 429 | 430 | } | |
| 430 | 431 | ||
| 431 | 432 | type cmdTestTransport struct { | |
| 432 | - | sent []ports.Frame | |
| 433 | - | recv ports.Frame | |
| 433 | + | sent []wire.Frame | |
| 434 | + | recv wire.Frame | |
| 434 | 435 | recvErr error | |
| 435 | 436 | recvCalls int | |
| 436 | 437 | closeCalls int | |
| @@ -438,12 +439,12 @@ type cmdTestTransport struct { | |||
| 438 | 439 | recvGate <-chan struct{} | |
| 439 | 440 | } | |
| 440 | 441 | ||
| 441 | - | func (t *cmdTestTransport) Send(frame ports.Frame) error { | |
| 442 | + | func (t *cmdTestTransport) Send(frame wire.Frame) error { | |
| 442 | 443 | t.sent = append(t.sent, frame) | |
| 443 | 444 | return nil | |
| 444 | 445 | } | |
| 445 | 446 | ||
| 446 | - | func (t *cmdTestTransport) Recv() (ports.Frame, error) { | |
| 447 | + | func (t *cmdTestTransport) Recv() (wire.Frame, error) { | |
| 447 | 448 | t.recvCalls++ | |
| 448 | 449 | if t.recvStarted != nil { | |
| 449 | 450 | close(t.recvStarted) | |
M internal/app/daemon_integration_test.go +38 -37
| @@ -29,6 +29,7 @@ import ( | |||
| 29 | 29 | "github.com/bnema/vev/internal/persist" | |
| 30 | 30 | "github.com/bnema/vev/internal/ports" | |
| 31 | 31 | "github.com/bnema/vev/internal/protocol" | |
| 32 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 32 | 33 | "github.com/bnema/vev/internal/usecase/daemon" | |
| 33 | 34 | "github.com/bnema/vev/internal/usecase/recovery" | |
| 34 | 35 | ) | |
| @@ -64,10 +65,10 @@ func startDaemonInDir(t *testing.T, dir string, opts ...daemon.Option) (string, | |||
| 64 | 65 | ||
| 65 | 66 | // pump wires a background Recv pump to a transport so tests can await frames | |
| 66 | 67 | // with a timeout (ports.Transport has no read deadline). | |
| 67 | - | type pump struct{ ch chan ports.Frame } | |
| 68 | + | type pump struct{ ch chan wire.Frame } | |
| 68 | 69 | ||
| 69 | 70 | func recvPump(tr ports.Transport) *pump { | |
| 70 | - | p := &pump{ch: make(chan ports.Frame, 128)} | |
| 71 | + | p := &pump{ch: make(chan wire.Frame, 128)} | |
| 71 | 72 | go func() { | |
| 72 | 73 | for { | |
| 73 | 74 | f, err := tr.Recv() | |
| @@ -92,12 +93,12 @@ func attachWithEnvironment(t *testing.T, dir string, intent uint8, name string, | |||
| 92 | 93 | tr, err := ipc.DialContext(context.Background(), dir) | |
| 93 | 94 | require.NoError(t, err) | |
| 94 | 95 | hello := protocol.Hello{Version: protocol.Version, Intent: intent, Name: name, Size: sz, TermEnv: "xterm-256color", TrueColor: true, Env: env} | |
| 95 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(hello)})) | |
| 96 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(hello)})) | |
| 96 | 97 | p := recvPump(tr) | |
| 97 | 98 | select { | |
| 98 | 99 | case f, ok := <-p.ch: | |
| 99 | 100 | require.True(t, ok, "connection closed before welcome") | |
| 100 | - | require.Equal(t, ports.MsgWelcome, f.Type) | |
| 101 | + | require.Equal(t, wire.MsgWelcome, f.Type) | |
| 101 | 102 | case <-time.After(3 * time.Second): | |
| 102 | 103 | t.Fatal("timed out waiting for welcome") | |
| 103 | 104 | } | |
| @@ -109,11 +110,11 @@ func listRemoteSessions(t *testing.T, dir string) protocol.Sessions { | |||
| 109 | 110 | tr, err := ipc.DialContext(context.Background(), dir) | |
| 110 | 111 | require.NoError(t, err) | |
| 111 | 112 | defer func() { _ = tr.Close() }() | |
| 112 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgList, Payload: ports.MarshalList(protocol.List{})})) | |
| 113 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgList, Payload: wire.MarshalList(protocol.List{})})) | |
| 113 | 114 | f, err := tr.Recv() | |
| 114 | 115 | require.NoError(t, err) | |
| 115 | - | require.Equal(t, ports.MsgSessions, f.Type) | |
| 116 | - | sessions, err := ports.UnmarshalSessions(f.Payload) | |
| 116 | + | require.Equal(t, wire.MsgSessions, f.Type) | |
| 117 | + | sessions, err := wire.UnmarshalSessions(f.Payload) | |
| 117 | 118 | require.NoError(t, err) | |
| 118 | 119 | return sessions | |
| 119 | 120 | } | |
| @@ -124,7 +125,7 @@ func killAll(dir string) error { | |||
| 124 | 125 | return err | |
| 125 | 126 | } | |
| 126 | 127 | defer func() { _ = tr.Close() }() | |
| 127 | - | if err := tr.Send(ports.Frame{Type: ports.MsgKill, Payload: ports.MarshalKill(protocol.Kill{All: true})}); err != nil { | |
| 128 | + | if err := tr.Send(wire.Frame{Type: wire.MsgKill, Payload: wire.MarshalKill(protocol.Kill{All: true})}); err != nil { | |
| 128 | 129 | return err | |
| 129 | 130 | } | |
| 130 | 131 | _, err = tr.Recv() | |
| @@ -153,8 +154,8 @@ func awaitScreenText(t *testing.T, p *pump, sz domain.Size, want string) string | |||
| 153 | 154 | if !ok { | |
| 154 | 155 | t.Fatalf("connection closed before %q appeared; screen=%q", want, screenText(screen)) | |
| 155 | 156 | } | |
| 156 | - | if f.Type == ports.MsgOutput { | |
| 157 | - | o, err := ports.UnmarshalOutput(f.Payload) | |
| 157 | + | if f.Type == wire.MsgOutput { | |
| 158 | + | o, err := wire.UnmarshalOutput(f.Payload) | |
| 158 | 159 | require.NoError(t, err) | |
| 159 | 160 | screen.Write(o.Data) | |
| 160 | 161 | text := screenText(screen) | |
| @@ -178,8 +179,8 @@ func assertNoTextAfterInput(t *testing.T, p *pump, sz domain.Size, absent string | |||
| 178 | 179 | if !ok { | |
| 179 | 180 | return | |
| 180 | 181 | } | |
| 181 | - | if f.Type == ports.MsgOutput { | |
| 182 | - | o, err := ports.UnmarshalOutput(f.Payload) | |
| 182 | + | if f.Type == wire.MsgOutput { | |
| 183 | + | o, err := wire.UnmarshalOutput(f.Payload) | |
| 183 | 184 | require.NoError(t, err) | |
| 184 | 185 | screen.Write(o.Data) | |
| 185 | 186 | require.NotContains(t, screenText(screen), absent) | |
| @@ -214,7 +215,7 @@ func shellFixture(t *testing.T, label string) string { | |||
| 214 | 215 | func assertChildEnvironment(t *testing.T, tr ports.Transport, p *pump, sz domain.Size, wantTestEnv, wantShell, wantRuntimeDir, wantWayland string) { | |
| 215 | 216 | t.Helper() | |
| 216 | 217 | command := "printf '\\033[2J\\033[H'; printf 'VEV_TEST_ENV=%s SHELL=%s XDG_RUNTIME_DIR=%s WAYLAND_DISPLAY=%s TERM=%s COLORTERM=%s TERM_PROGRAM=%s VEV_PREFIX=%.24s\\n' \"$VEV_TEST_ENV\" \"${SHELL##*/}\" \"$XDG_RUNTIME_DIR\" \"$WAYLAND_DISPLAY\" \"$TERM\" \"$COLORTERM\" \"$TERM_PROGRAM\" \"$VEV\"\n" | |
| 217 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte(command)})})) | |
| 218 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte(command)})})) | |
| 218 | 219 | text := awaitScreenText(t, p, sz, "TERM_PROGRAM=vev") | |
| 219 | 220 | for _, want := range []string{ | |
| 220 | 221 | "VEV_TEST_ENV=" + wantTestEnv, | |
| @@ -255,9 +256,9 @@ func TestIntegration_AttachEnvironmentRefreshesFuturePTYChildren(t *testing.T) { | |||
| 255 | 256 | // The first shell was already running, so it retains its original environment. | |
| 256 | 257 | assertChildEnvironment(t, tr2, p2, sz, "first", firstShell, "/run/first", "wayland-first") | |
| 257 | 258 | ||
| 258 | - | require.NoError(t, tr2.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) | |
| 259 | + | require.NoError(t, tr2.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) | |
| 259 | 260 | awaitText(t, p2, sz, "Commands") | |
| 260 | - | require.NoError(t, tr2.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("CNT\r")})})) | |
| 261 | + | require.NoError(t, tr2.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("CNT\r")})})) | |
| 261 | 262 | awaitText(t, p2, sz, "SHELL_COMMAND=second") | |
| 262 | 263 | assertChildEnvironment(t, tr2, p2, sz, "second", secondShell, "/run/second", "wayland-second") | |
| 263 | 264 | } | |
| @@ -288,17 +289,17 @@ func TestIntegration_TwoAttachmentsReceiveSharedMutationPTYOutput(t *testing.T) | |||
| 288 | 289 | ||
| 289 | 290 | // The second attachment mutates shared tab state. Its newly opened PTY must | |
| 290 | 291 | // also be rendered to that attachment, not only to the coordinator primary. | |
| 291 | - | require.NoError(t, tr2.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) | |
| 292 | + | require.NoError(t, tr2.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) | |
| 292 | 293 | awaitText(t, p2, sz, "Commands") | |
| 293 | - | require.NoError(t, tr2.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("CNT\r")})})) | |
| 294 | + | require.NoError(t, tr2.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("CNT\r")})})) | |
| 294 | 295 | awaitText(t, p2, sz, "SHELL_COMMAND=second") | |
| 295 | 296 | ||
| 296 | 297 | // Each attachment owns its selected tab. Move the first attachment to the | |
| 297 | 298 | // new PTY before releasing its gate, so the fresh PTY output must reach both | |
| 298 | 299 | // views rather than only being recovered by a later first paint. | |
| 299 | - | require.NoError(t, tr1.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x1b2")})})) | |
| 300 | + | require.NoError(t, tr1.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x1b2")})})) | |
| 300 | 301 | awaitText(t, p1, sz, "SHELL_COMMAND=second") | |
| 301 | - | require.NoError(t, tr1.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("go\n")})})) | |
| 302 | + | require.NoError(t, tr1.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("go\n")})})) | |
| 302 | 303 | awaitText(t, p2, sz, sharedOutput) | |
| 303 | 304 | awaitText(t, p1, sz, sharedOutput) | |
| 304 | 305 | } | |
| @@ -320,7 +321,7 @@ func TestIntegration_InputRoundtrip(t *testing.T) { | |||
| 320 | 321 | tr, p := attach(t, dir, protocol.IntentEphemeral, "", sz) | |
| 321 | 322 | defer func() { _ = tr.Close() }() | |
| 322 | 323 | ||
| 323 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("PINGPONG\n")})})) | |
| 324 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("PINGPONG\n")})})) | |
| 324 | 325 | awaitText(t, p, sz, "PINGPONG") | |
| 325 | 326 | } | |
| 326 | 327 | ||
| @@ -332,10 +333,10 @@ func TestIntegration_CommandPaletteCreatesTab(t *testing.T) { | |||
| 332 | 333 | defer func() { _ = tr.Close() }() | |
| 333 | 334 | awaitText(t, p, sz, "READY") | |
| 334 | 335 | ||
| 335 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) | |
| 336 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) | |
| 336 | 337 | awaitText(t, p, sz, "Commands") | |
| 337 | 338 | ||
| 338 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("CNT\r")})})) | |
| 339 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("CNT\r")})})) | |
| 339 | 340 | // Tab labels are enriched with the focused pane's title; with no process | |
| 340 | 341 | // inspector wired in this test, that title falls back to the shell's | |
| 341 | 342 | // basename ("sh"). | |
| @@ -352,24 +353,24 @@ func TestIntegration_CommandPaletteRenamesEphemeralSession(t *testing.T) { | |||
| 352 | 353 | text := awaitScreenText(t, p, sz, "READY") | |
| 353 | 354 | require.Contains(t, text, " 0* ") | |
| 354 | 355 | ||
| 355 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) | |
| 356 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x1b ")})})) | |
| 356 | 357 | awaitText(t, p, sz, "Commands") | |
| 357 | 358 | ||
| 358 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("RNS\r")})})) | |
| 359 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("RNS\r")})})) | |
| 359 | 360 | awaitText(t, p, sz, "Rename session") | |
| 360 | 361 | ||
| 361 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x7fwork\r")})})) | |
| 362 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x7fwork\r")})})) | |
| 362 | 363 | text = awaitScreenText(t, p, sz, " work ") | |
| 363 | 364 | require.NotContains(t, text, "work*") | |
| 364 | 365 | ||
| 365 | 366 | listTr, err := ipc.DialContext(context.Background(), dir) | |
| 366 | 367 | require.NoError(t, err) | |
| 367 | 368 | defer func() { _ = listTr.Close() }() | |
| 368 | - | require.NoError(t, listTr.Send(ports.Frame{Type: ports.MsgList, Payload: ports.MarshalList(protocol.List{})})) | |
| 369 | + | require.NoError(t, listTr.Send(wire.Frame{Type: wire.MsgList, Payload: wire.MarshalList(protocol.List{})})) | |
| 369 | 370 | f, err := listTr.Recv() | |
| 370 | 371 | require.NoError(t, err) | |
| 371 | - | require.Equal(t, ports.MsgSessions, f.Type) | |
| 372 | - | sessions, err := ports.UnmarshalSessions(f.Payload) | |
| 372 | + | require.Equal(t, wire.MsgSessions, f.Type) | |
| 373 | + | sessions, err := wire.UnmarshalSessions(f.Payload) | |
| 373 | 374 | require.NoError(t, err) | |
| 374 | 375 | require.NotEmpty(t, sessions.Sessions) | |
| 375 | 376 | require.Equal(t, "work", sessions.Sessions[0].Name) | |
| @@ -385,7 +386,7 @@ func TestIntegration_AltCWithoutPaletteDoesNotCreateTab(t *testing.T) { | |||
| 385 | 386 | text := awaitScreenText(t, p, sz, "READY") | |
| 386 | 387 | require.NotContains(t, text, " 1 2 ") | |
| 387 | 388 | ||
| 388 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("\x1bc")})})) | |
| 389 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("\x1bc")})})) | |
| 389 | 390 | assertNoTextAfterInput(t, p, sz, " 1 2 ") | |
| 390 | 391 | } | |
| 391 | 392 | ||
| @@ -802,7 +803,7 @@ func publishRestorableCheckpoint(t *testing.T, stateDir string, repository *snap | |||
| 802 | 803 | go func() { served <- d.Serve(ctx, listener) }() | |
| 803 | 804 | ||
| 804 | 805 | tr, _ := attach(t, runtimeDir, protocol.IntentNew, name, domain.Size{Cols: 80, Rows: 24}) | |
| 805 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("checkpoint me\n")})})) | |
| 806 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("checkpoint me\n")})})) | |
| 806 | 807 | require.Eventually(t, func() bool { | |
| 807 | 808 | record, ok, _ := opened.Catalogue.Record(name) | |
| 808 | 809 | return ok && record.Committed != nil && record.DegradedReason == "" | |
| @@ -888,7 +889,7 @@ func runBlockedSnapshotWriterShutdown(t *testing.T) blockedSnapshotWriterShutdow | |||
| 888 | 889 | ||
| 889 | 890 | awaitLifecycleStage(t, listenerReady, "daemon listener") | |
| 890 | 891 | tr, _ := attach(t, runtimeDir, protocol.IntentNew, "work", domain.Size{Cols: 80, Rows: 24}) | |
| 891 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte("dirty state\n")})})) | |
| 892 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte("dirty state\n")})})) | |
| 892 | 893 | awaitLifecycleStage(t, repository.entered, "snapshot publication") | |
| 893 | 894 | require.NoError(t, tr.Close()) | |
| 894 | 895 | require.Eventually(t, func() bool { | |
| @@ -1240,11 +1241,11 @@ func (c *lifecycleControlledCatalogue) Close() error { | |||
| 1240 | 1241 | ||
| 1241 | 1242 | type integrationTransport struct{} | |
| 1242 | 1243 | ||
| 1243 | - | func (*integrationTransport) Send(ports.Frame) error { return nil } | |
| 1244 | - | func (*integrationTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 1245 | - | func (*integrationTransport) Close() error { return nil } | |
| 1246 | - | func (*integrationTransport) LocalAddr() net.Addr { return nil } | |
| 1247 | - | func (*integrationTransport) RemoteAddr() net.Addr { return nil } | |
| 1244 | + | func (*integrationTransport) Send(wire.Frame) error { return nil } | |
| 1245 | + | func (*integrationTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 1246 | + | func (*integrationTransport) Close() error { return nil } | |
| 1247 | + | func (*integrationTransport) LocalAddr() net.Addr { return nil } | |
| 1248 | + | func (*integrationTransport) RemoteAddr() net.Addr { return nil } | |
| 1248 | 1249 | ||
| 1249 | 1250 | func TestIntegration_KillAllShutsDownDaemon(t *testing.T) { | |
| 1250 | 1251 | sz := domain.Size{Cols: 80, Rows: 24} | |
| @@ -1258,7 +1259,7 @@ func TestIntegration_KillAllShutsDownDaemon(t *testing.T) { | |||
| 1258 | 1259 | killTr, err := ipc.DialContext(context.Background(), dir) | |
| 1259 | 1260 | require.NoError(t, err) | |
| 1260 | 1261 | defer func() { _ = killTr.Close() }() | |
| 1261 | - | require.NoError(t, killTr.Send(ports.Frame{Type: ports.MsgKill, Payload: ports.MarshalKill(protocol.Kill{All: true})})) | |
| 1262 | + | require.NoError(t, killTr.Send(wire.Frame{Type: wire.MsgKill, Payload: wire.MarshalKill(protocol.Kill{All: true})})) | |
| 1262 | 1263 | ||
| 1263 | 1264 | _, err = killTr.Recv() | |
| 1264 | 1265 | require.ErrorIs(t, err, io.EOF) | |
M internal/app/final_acceptance_test.go +17 -16
| @@ -9,16 +9,17 @@ import ( | |||
| 9 | 9 | "github.com/bnema/vev/internal/domain" | |
| 10 | 10 | "github.com/bnema/vev/internal/ports" | |
| 11 | 11 | "github.com/bnema/vev/internal/protocol" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 12 | 13 | "github.com/bnema/vev/internal/usecase/daemon" | |
| 13 | 14 | "github.com/stretchr/testify/require" | |
| 14 | 15 | ) | |
| 15 | 16 | ||
| 16 | 17 | func sendAcceptanceInput(t *testing.T, tr ports.Transport, data string) { | |
| 17 | 18 | t.Helper() | |
| 18 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte(data)})})) | |
| 19 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte(data)})})) | |
| 19 | 20 | } | |
| 20 | 21 | ||
| 21 | - | func awaitAcceptanceFrame(t *testing.T, p *pump, typ ports.MsgType, predicate func(ports.Frame) bool) ports.Frame { | |
| 22 | + | func awaitAcceptanceFrame(t *testing.T, p *pump, typ wire.MsgType, predicate func(wire.Frame) bool) wire.Frame { | |
| 22 | 23 | t.Helper() | |
| 23 | 24 | deadline := time.NewTimer(5 * time.Second) | |
| 24 | 25 | defer deadline.Stop() | |
| @@ -37,35 +38,35 @@ func awaitAcceptanceFrame(t *testing.T, p *pump, typ ports.MsgType, predicate fu | |||
| 37 | 38 | ||
| 38 | 39 | func awaitAcceptanceCommand(t *testing.T, p *pump, requestID uint64) protocol.CommandResult { | |
| 39 | 40 | t.Helper() | |
| 40 | - | frame := awaitAcceptanceFrame(t, p, ports.MsgCommandResult, func(frame ports.Frame) bool { | |
| 41 | - | result, err := ports.UnmarshalCommandResult(frame.Payload) | |
| 41 | + | frame := awaitAcceptanceFrame(t, p, wire.MsgCommandResult, func(frame wire.Frame) bool { | |
| 42 | + | result, err := wire.UnmarshalCommandResult(frame.Payload) | |
| 42 | 43 | require.NoError(t, err) | |
| 43 | 44 | return result.RequestID == requestID | |
| 44 | 45 | }) | |
| 45 | - | result, err := ports.UnmarshalCommandResult(frame.Payload) | |
| 46 | + | result, err := wire.UnmarshalCommandResult(frame.Payload) | |
| 46 | 47 | require.NoError(t, err) | |
| 47 | 48 | return result | |
| 48 | 49 | } | |
| 49 | 50 | ||
| 50 | 51 | func awaitAcceptanceOutput(t *testing.T, p *pump, predicate func(protocol.Output) bool) protocol.Output { | |
| 51 | 52 | t.Helper() | |
| 52 | - | frame := awaitAcceptanceFrame(t, p, ports.MsgOutput, func(frame ports.Frame) bool { | |
| 53 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 53 | + | frame := awaitAcceptanceFrame(t, p, wire.MsgOutput, func(frame wire.Frame) bool { | |
| 54 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 54 | 55 | require.NoError(t, err) | |
| 55 | 56 | return predicate(output) | |
| 56 | 57 | }) | |
| 57 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 58 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 58 | 59 | require.NoError(t, err) | |
| 59 | 60 | return output | |
| 60 | 61 | } | |
| 61 | 62 | ||
| 62 | 63 | func awaitAcceptanceCommandResult(t *testing.T, tr ports.Transport, p *pump, requestID uint64, slug string) protocol.CommandResult { | |
| 63 | 64 | t.Helper() | |
| 64 | - | payload, err := ports.MarshalCommandRequest(protocol.CommandRequest{ | |
| 65 | + | payload, err := wire.MarshalCommandRequest(protocol.CommandRequest{ | |
| 65 | 66 | Version: protocol.Version, RequestID: requestID, Attached: true, Slug: slug, | |
| 66 | 67 | }) | |
| 67 | 68 | require.NoError(t, err) | |
| 68 | - | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgCommand, Payload: payload})) | |
| 69 | + | require.NoError(t, tr.Send(wire.Frame{Type: wire.MsgCommand, Payload: payload})) | |
| 69 | 70 | return awaitAcceptanceCommand(t, p, requestID) | |
| 70 | 71 | } | |
| 71 | 72 | ||
| @@ -114,25 +115,25 @@ func TestAcceptanceTwoLocalAttachmentsKeepViewsOverTransports(t *testing.T) { | |||
| 114 | 115 | // The resize keeps its attachment-local output stream while recalculating | |
| 115 | 116 | // shared PTY/content geometry from the latest valid attachment claim; the | |
| 116 | 117 | // peer stream remains independent. | |
| 117 | - | resizePayload, err := ports.MarshalResize(protocol.Resize{Size: domain.Size{Cols: 100, Rows: 30}}) | |
| 118 | + | resizePayload, err := wire.MarshalResize(protocol.Resize{Size: domain.Size{Cols: 100, Rows: 30}}) | |
| 118 | 119 | require.NoError(t, err) | |
| 119 | - | require.NoError(t, first.Send(ports.Frame{Type: ports.MsgResize, Payload: resizePayload})) | |
| 120 | + | require.NoError(t, first.Send(wire.Frame{Type: wire.MsgResize, Payload: resizePayload})) | |
| 120 | 121 | resized := awaitAcceptanceOutput(t, firstPump, func(output protocol.Output) bool { return output.Size == (domain.Size{Cols: 100, Rows: 30}) }) | |
| 121 | 122 | require.Equal(t, domain.Size{Cols: 100, Rows: 30}, resized.Size) | |
| 122 | 123 | assertNoTextAfterInput(t, secondPump, size, "FIRST_PANE_INPUT") | |
| 123 | 124 | ||
| 124 | - | require.NoError(t, first.Send(ports.Frame{Type: ports.MsgOutputResetRequest, Payload: ports.MarshalOutputResetRequest(protocol.OutputResetRequest{})})) | |
| 125 | + | require.NoError(t, first.Send(wire.Frame{Type: wire.MsgOutputResetRequest, Payload: wire.MarshalOutputResetRequest(protocol.OutputResetRequest{})})) | |
| 125 | 126 | reset := awaitAcceptanceOutput(t, firstPump, func(output protocol.Output) bool { return output.Base == 0 && output.Full }) | |
| 126 | 127 | require.True(t, reset.Full) | |
| 127 | 128 | assertNoTextAfterInput(t, secondPump, size, "FIRST_PANE_INPUT") | |
| 128 | 129 | ||
| 129 | - | require.NoError(t, first.Send(ports.Frame{Type: ports.MsgDetach, Payload: ports.MarshalDetach(protocol.Detach{})})) | |
| 130 | + | require.NoError(t, first.Send(wire.Frame{Type: wire.MsgDetach, Payload: wire.MarshalDetach(protocol.Detach{})})) | |
| 130 | 131 | deadline := time.NewTimer(5 * time.Second) | |
| 131 | 132 | defer deadline.Stop() | |
| 132 | 133 | for { | |
| 133 | 134 | select { | |
| 134 | 135 | case frame := <-firstPump.ch: | |
| 135 | - | if frame.Type == ports.MsgDetached { | |
| 136 | + | if frame.Type == wire.MsgDetached { | |
| 136 | 137 | goto detached | |
| 137 | 138 | } | |
| 138 | 139 | case <-deadline.C: | |
| @@ -173,7 +174,7 @@ func TestAcceptanceAttachedCommandUsesItsConnectionOnly(t *testing.T) { | |||
| 173 | 174 | } | |
| 174 | 175 | ||
| 175 | 176 | drained: | |
| 176 | - | require.NoError(t, first.Send(ports.Frame{Type: ports.MsgOutputResetRequest, Payload: ports.MarshalOutputResetRequest(protocol.OutputResetRequest{})})) | |
| 177 | + | require.NoError(t, first.Send(wire.Frame{Type: wire.MsgOutputResetRequest, Payload: wire.MarshalOutputResetRequest(protocol.OutputResetRequest{})})) | |
| 177 | 178 | awaitAcceptanceOutput(t, firstPump, func(output protocol.Output) bool { return output.Full && output.Base == 0 }) | |
| 178 | 179 | assertNoTextAfterInput(t, secondPump, size, "Commands") | |
| 179 | 180 | } | |
M internal/app/remote_final_acceptance_test.go +12 -11
| @@ -16,6 +16,7 @@ import ( | |||
| 16 | 16 | "github.com/bnema/vev/internal/ports" | |
| 17 | 17 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 18 | 18 | "github.com/bnema/vev/internal/protocol" | |
| 19 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 19 | 20 | "github.com/bnema/vev/internal/usecase/client" | |
| 20 | 21 | "github.com/stretchr/testify/require" | |
| 21 | 22 | ) | |
| @@ -58,17 +59,17 @@ func serveAcceptanceRemote(tr ports.Transport, target string, handoff protocol.A | |||
| 58 | 59 | return | |
| 59 | 60 | } | |
| 60 | 61 | if !welcomed { | |
| 61 | - | if frame.Type != ports.MsgHello { | |
| 62 | + | if frame.Type != wire.MsgHello { | |
| 62 | 63 | continue | |
| 63 | 64 | } | |
| 64 | - | if err := tr.Send(ports.Frame{Type: ports.MsgWelcome, Payload: ports.MarshalWelcome(protocol.Welcome{SessionID: target})}); err != nil { | |
| 65 | + | if err := tr.Send(wire.Frame{Type: wire.MsgWelcome, Payload: wire.MarshalWelcome(protocol.Welcome{SessionID: target})}); err != nil { | |
| 65 | 66 | return | |
| 66 | 67 | } | |
| 67 | 68 | welcomed = true | |
| 68 | 69 | continue | |
| 69 | 70 | } | |
| 70 | 71 | if handoff.Endpoint != "" { | |
| 71 | - | _ = tr.Send(ports.Frame{Type: ports.MsgAttachTarget, Payload: ports.MarshalAttachTarget(handoff)}) | |
| 72 | + | _ = tr.Send(wire.Frame{Type: wire.MsgAttachTarget, Payload: wire.MarshalAttachTarget(handoff)}) | |
| 72 | 73 | for { | |
| 73 | 74 | if _, err := tr.Recv(); err != nil { | |
| 74 | 75 | return | |
| @@ -79,16 +80,16 @@ func serveAcceptanceRemote(tr ports.Transport, target string, handoff protocol.A | |||
| 79 | 80 | if outputs != nil { | |
| 80 | 81 | outputs <- string(data) | |
| 81 | 82 | } | |
| 82 | - | payload, err := ports.MarshalOutput(protocol.Output{ | |
| 83 | + | payload, err := wire.MarshalOutput(protocol.Output{ | |
| 83 | 84 | Epoch: 1, New: 1, Full: true, Size: domain.Size{Cols: 80, Rows: 24}, Data: data, | |
| 84 | 85 | }) | |
| 85 | 86 | if err != nil { | |
| 86 | 87 | return | |
| 87 | 88 | } | |
| 88 | - | if err := tr.Send(ports.Frame{Type: ports.MsgOutput, Payload: payload}); err != nil { | |
| 89 | + | if err := tr.Send(wire.Frame{Type: wire.MsgOutput, Payload: payload}); err != nil { | |
| 89 | 90 | return | |
| 90 | 91 | } | |
| 91 | - | _ = tr.Send(ports.Frame{Type: ports.MsgDetached, Payload: ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})}) | |
| 92 | + | _ = tr.Send(wire.Frame{Type: wire.MsgDetached, Payload: wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})}) | |
| 92 | 93 | for { | |
| 93 | 94 | if _, err := tr.Recv(); err != nil { | |
| 94 | 95 | return | |
| @@ -150,18 +151,18 @@ func TestAcceptanceRemoteDirectAndPickerUseOnlyRemoteTransports(t *testing.T) { | |||
| 150 | 151 | handoff: protocol.AttachTarget{Endpoint: "picked.example", Session: "picked", Intent: protocol.IntentAttach}, | |
| 151 | 152 | }).Dial(context.Background()) | |
| 152 | 153 | require.NoError(t, err) | |
| 153 | - | require.NoError(t, wireTransport.Send(ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(protocol.Hello{ | |
| 154 | + | require.NoError(t, wireTransport.Send(wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(protocol.Hello{ | |
| 154 | 155 | Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, | |
| 155 | 156 | })})) | |
| 156 | 157 | welcome, err := wireTransport.Recv() | |
| 157 | 158 | require.NoError(t, err) | |
| 158 | - | require.Equal(t, ports.MsgWelcome, welcome.Type) | |
| 159 | - | require.NoError(t, wireTransport.Send(ports.Frame{Type: ports.MsgTheme, Payload: ports.MarshalTheme(protocol.Theme{})})) | |
| 159 | + | require.Equal(t, wire.MsgWelcome, welcome.Type) | |
| 160 | + | require.NoError(t, wireTransport.Send(wire.Frame{Type: wire.MsgTheme, Payload: wire.MarshalTheme(protocol.Theme{})})) | |
| 160 | 161 | attachTarget, err := wireTransport.Recv() | |
| 161 | 162 | require.NoError(t, err) | |
| 162 | - | target, err := ports.UnmarshalAttachTarget(attachTarget.Payload) | |
| 163 | + | target, err := wire.UnmarshalAttachTarget(attachTarget.Payload) | |
| 163 | 164 | require.NoError(t, err) | |
| 164 | - | require.Equal(t, ports.MsgAttachTarget, attachTarget.Type) | |
| 165 | + | require.Equal(t, wire.MsgAttachTarget, attachTarget.Type) | |
| 165 | 166 | require.Equal(t, "picked.example", target.Endpoint) | |
| 166 | 167 | require.NoError(t, wireTransport.Close()) | |
| 167 | 168 | ||
M internal/app/remote_preview.go +8 -8
| @@ -8,8 +8,8 @@ import ( | |||
| 8 | 8 | "os" | |
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/vev/internal/adapters/ipc" | |
| 11 | - | "github.com/bnema/vev/internal/ports" | |
| 12 | 11 | "github.com/bnema/vev/internal/protocol" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 13 | ) | |
| 14 | 14 | ||
| 15 | 15 | // runRemotePreview is the hidden SSH-side carriage. The request is encoded in | |
| @@ -20,7 +20,7 @@ func runRemotePreview(ctx context.Context, encoded string) error { | |||
| 20 | 20 | if err != nil { | |
| 21 | 21 | return fmt.Errorf("vev: invalid remote preview request: %w", err) | |
| 22 | 22 | } | |
| 23 | - | if _, err := ports.UnmarshalRemotePreviewRequest(request); err != nil { | |
| 23 | + | if _, err := wire.UnmarshalRemotePreviewRequest(request); err != nil { | |
| 24 | 24 | return fmt.Errorf("vev: invalid remote preview request: %w", err) | |
| 25 | 25 | } | |
| 26 | 26 | transport, err := ipc.DialContext(ctx, ipc.SocketDir()) | |
| @@ -31,17 +31,17 @@ func runRemotePreview(ctx context.Context, encoded string) error { | |||
| 31 | 31 | return writeRemotePreviewStatus(protocol.RemotePreviewUnavailable) | |
| 32 | 32 | } | |
| 33 | 33 | defer func() { _ = transport.Close() }() | |
| 34 | - | if err := transport.Send(ports.Frame{Type: ports.MsgRemotePreviewRequest, Payload: request}); err != nil { | |
| 34 | + | if err := transport.Send(wire.Frame{Type: wire.MsgRemotePreviewRequest, Payload: request}); err != nil { | |
| 35 | 35 | return fmt.Errorf("vev: sending remote preview request: %w", err) | |
| 36 | 36 | } | |
| 37 | 37 | frameCh := make(chan struct { | |
| 38 | - | frame ports.Frame | |
| 38 | + | frame wire.Frame | |
| 39 | 39 | err error | |
| 40 | 40 | }, 1) | |
| 41 | 41 | go func() { | |
| 42 | 42 | frame, err := transport.Recv() | |
| 43 | 43 | frameCh <- struct { | |
| 44 | - | frame ports.Frame | |
| 44 | + | frame wire.Frame | |
| 45 | 45 | err error | |
| 46 | 46 | }{frame: frame, err: err} | |
| 47 | 47 | }() | |
| @@ -53,10 +53,10 @@ func runRemotePreview(ctx context.Context, encoded string) error { | |||
| 53 | 53 | if result.err != nil { | |
| 54 | 54 | return fmt.Errorf("vev: receiving remote preview: %w", result.err) | |
| 55 | 55 | } | |
| 56 | - | if result.frame.Type != ports.MsgRemotePreviewResponse { | |
| 56 | + | if result.frame.Type != wire.MsgRemotePreviewResponse { | |
| 57 | 57 | return fmt.Errorf("vev: unexpected remote preview response %d", result.frame.Type) | |
| 58 | 58 | } | |
| 59 | - | if _, err := ports.UnmarshalRemotePreview(result.frame.Payload); err != nil { | |
| 59 | + | if _, err := wire.UnmarshalRemotePreview(result.frame.Payload); err != nil { | |
| 60 | 60 | return fmt.Errorf("vev: malformed remote preview response: %w", err) | |
| 61 | 61 | } | |
| 62 | 62 | _, err := os.Stdout.Write(result.frame.Payload) | |
| @@ -65,7 +65,7 @@ func runRemotePreview(ctx context.Context, encoded string) error { | |||
| 65 | 65 | } | |
| 66 | 66 | ||
| 67 | 67 | func writeRemotePreviewStatus(status protocol.RemotePreviewStatus) error { | |
| 68 | - | payload := ports.MarshalRemotePreview(protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: status}) | |
| 68 | + | payload := wire.MarshalRemotePreview(protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: status}) | |
| 69 | 69 | if payload == nil { | |
| 70 | 70 | return errors.New("vev: failed to encode remote preview status") | |
| 71 | 71 | } | |
M internal/app/remote_test.go +5 -4
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | 12 | "github.com/bnema/vev/internal/ports" | |
| 13 | 13 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 14 | 14 | "github.com/bnema/vev/internal/protocol" | |
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 15 | 16 | "github.com/bnema/vev/internal/usecase/client" | |
| 16 | 17 | "github.com/stretchr/testify/mock" | |
| 17 | 18 | "github.com/stretchr/testify/require" | |
| @@ -56,15 +57,15 @@ func TestRemoteHostDepsDefaultsStore(t *testing.T) { | |||
| 56 | 57 | ||
| 57 | 58 | func TestDecodeSessionListErrorReply(t *testing.T) { | |
| 58 | 59 | t.Run("valid", func(t *testing.T) { | |
| 59 | - | _, err := decodeSessionListReply(ports.Frame{ | |
| 60 | - | Type: ports.MsgError, | |
| 61 | - | Payload: ports.MarshalErrorMsg(protocol.ErrorMsg{Text: "denied"}), | |
| 60 | + | _, err := decodeSessionListReply(wire.Frame{ | |
| 61 | + | Type: wire.MsgError, | |
| 62 | + | Payload: wire.MarshalErrorMsg(protocol.ErrorMsg{Text: "denied"}), | |
| 62 | 63 | }) | |
| 63 | 64 | require.EqualError(t, err, "vev: denied") | |
| 64 | 65 | }) | |
| 65 | 66 | ||
| 66 | 67 | t.Run("malformed", func(t *testing.T) { | |
| 67 | - | _, err := decodeSessionListReply(ports.Frame{Type: ports.MsgError, Payload: []byte{0}}) | |
| 68 | + | _, err := decodeSessionListReply(wire.Frame{Type: wire.MsgError, Payload: []byte{0}}) | |
| 68 | 69 | require.ErrorContains(t, err, "vev: decoding error reply") | |
| 69 | 70 | }) | |
| 70 | 71 | } | |
M internal/app/run.go +16 -15
| @@ -47,6 +47,7 @@ import ( | |||
| 47 | 47 | "github.com/bnema/vev/internal/platform" | |
| 48 | 48 | "github.com/bnema/vev/internal/ports" | |
| 49 | 49 | "github.com/bnema/vev/internal/protocol" | |
| 50 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 50 | 51 | "github.com/bnema/vev/internal/usecase/client" | |
| 51 | 52 | "github.com/bnema/vev/internal/usecase/daemon" | |
| 52 | 53 | "github.com/bnema/vev/internal/usecase/recovery" | |
| @@ -1077,12 +1078,12 @@ func createDetachedLocalSession(ctx context.Context, name string) error { | |||
| 1077 | 1078 | cwd = "" | |
| 1078 | 1079 | } | |
| 1079 | 1080 | hello := detachedLocalHello(name, cwd) | |
| 1080 | - | if err := transport.Send(ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(hello)}); err != nil { | |
| 1081 | + | if err := transport.Send(wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(hello)}); err != nil { | |
| 1081 | 1082 | return fmt.Errorf("vev: creating detached session: %w", err) | |
| 1082 | 1083 | } | |
| 1083 | 1084 | ||
| 1084 | 1085 | type detachedReply struct { | |
| 1085 | - | frame ports.Frame | |
| 1086 | + | frame wire.Frame | |
| 1086 | 1087 | err error | |
| 1087 | 1088 | } | |
| 1088 | 1089 | replyCh := make(chan detachedReply, 1) | |
| @@ -1100,10 +1101,10 @@ func createDetachedLocalSession(ctx context.Context, name string) error { | |||
| 1100 | 1101 | return fmt.Errorf("vev: awaiting detached session creation: %w", reply.err) | |
| 1101 | 1102 | } | |
| 1102 | 1103 | switch reply.frame.Type { | |
| 1103 | - | case ports.MsgWelcome: | |
| 1104 | + | case wire.MsgWelcome: | |
| 1104 | 1105 | return nil | |
| 1105 | - | case ports.MsgError: | |
| 1106 | - | em, derr := ports.UnmarshalErrorMsg(reply.frame.Payload) | |
| 1106 | + | case wire.MsgError: | |
| 1107 | + | em, derr := wire.UnmarshalErrorMsg(reply.frame.Payload) | |
| 1107 | 1108 | if derr != nil { | |
| 1108 | 1109 | return fmt.Errorf("vev: decoding error reply: %w", derr) | |
| 1109 | 1110 | } | |
| @@ -1126,7 +1127,7 @@ func requestDaemonStop(ctx context.Context) error { | |||
| 1126 | 1127 | return errors.Join(errors.New("vev: no daemon running"), owner.Release()) | |
| 1127 | 1128 | } | |
| 1128 | 1129 | defer func() { _ = transport.Close() }() | |
| 1129 | - | if err := transport.Send(ports.Frame{Type: ports.MsgKill, Payload: ports.MarshalKill(protocol.Kill{All: true})}); err != nil { | |
| 1130 | + | if err := transport.Send(wire.Frame{Type: wire.MsgKill, Payload: wire.MarshalKill(protocol.Kill{All: true})}); err != nil { | |
| 1130 | 1131 | return fmt.Errorf("vev: requesting daemon stop: %w", err) | |
| 1131 | 1132 | } | |
| 1132 | 1133 | if _, err := transport.Recv(); err != nil && !errors.Is(err, io.EOF) { | |
| @@ -1482,7 +1483,7 @@ func listLocalSessions(ctx context.Context) (_ []protocol.SessionInfo, retErr er | |||
| 1482 | 1483 | } | |
| 1483 | 1484 | defer func() { _ = transport.Close() }() | |
| 1484 | 1485 | ||
| 1485 | - | if err := transport.Send(ports.Frame{Type: ports.MsgList, Payload: ports.MarshalList(protocol.List{})}); err != nil { | |
| 1486 | + | if err := transport.Send(wire.Frame{Type: wire.MsgList, Payload: wire.MarshalList(protocol.List{})}); err != nil { | |
| 1486 | 1487 | return nil, fmt.Errorf("vev: requesting session list: %w", err) | |
| 1487 | 1488 | } | |
| 1488 | 1489 | reply, err := transport.Recv() | |
| @@ -1492,18 +1493,18 @@ func listLocalSessions(ctx context.Context) (_ []protocol.SessionInfo, retErr er | |||
| 1492 | 1493 | return decodeSessionListReply(reply) | |
| 1493 | 1494 | } | |
| 1494 | 1495 | ||
| 1495 | - | func decodeSessionListReply(reply ports.Frame) ([]protocol.SessionInfo, error) { | |
| 1496 | - | if reply.Type == ports.MsgError { | |
| 1497 | - | em, err := ports.UnmarshalErrorMsg(reply.Payload) | |
| 1496 | + | func decodeSessionListReply(reply wire.Frame) ([]protocol.SessionInfo, error) { | |
| 1497 | + | if reply.Type == wire.MsgError { | |
| 1498 | + | em, err := wire.UnmarshalErrorMsg(reply.Payload) | |
| 1498 | 1499 | if err != nil { | |
| 1499 | 1500 | return nil, fmt.Errorf("vev: decoding error reply: %w", err) | |
| 1500 | 1501 | } | |
| 1501 | 1502 | return nil, fmt.Errorf("vev: %s", em.Text) | |
| 1502 | 1503 | } | |
| 1503 | - | if reply.Type != ports.MsgSessions { | |
| 1504 | + | if reply.Type != wire.MsgSessions { | |
| 1504 | 1505 | return nil, fmt.Errorf("vev: unexpected reply type %d to list", reply.Type) | |
| 1505 | 1506 | } | |
| 1506 | - | sessions, err := ports.UnmarshalSessions(reply.Payload) | |
| 1507 | + | sessions, err := wire.UnmarshalSessions(reply.Payload) | |
| 1507 | 1508 | if err != nil { | |
| 1508 | 1509 | return nil, fmt.Errorf("vev: decoding session list: %w", err) | |
| 1509 | 1510 | } | |
| @@ -1596,7 +1597,7 @@ func runKill(ctx context.Context, name string, all, daemon bool) (retErr error) | |||
| 1596 | 1597 | } | |
| 1597 | 1598 | defer func() { _ = transport.Close() }() | |
| 1598 | 1599 | ||
| 1599 | - | if err := transport.Send(ports.Frame{Type: ports.MsgKill, Payload: ports.MarshalKill(protocol.Kill{Name: name, All: all || daemon})}); err != nil { | |
| 1600 | + | if err := transport.Send(wire.Frame{Type: wire.MsgKill, Payload: wire.MarshalKill(protocol.Kill{Name: name, All: all || daemon})}); err != nil { | |
| 1600 | 1601 | return fmt.Errorf("vev: requesting kill: %w", err) | |
| 1601 | 1602 | } | |
| 1602 | 1603 | reply, err := transport.Recv() | |
| @@ -1609,8 +1610,8 @@ func runKill(ctx context.Context, name string, all, daemon bool) (retErr error) | |||
| 1609 | 1610 | } | |
| 1610 | 1611 | return fmt.Errorf("vev: reading kill reply: %w", err) | |
| 1611 | 1612 | } | |
| 1612 | - | if reply.Type == ports.MsgError { | |
| 1613 | - | em, _ := ports.UnmarshalErrorMsg(reply.Payload) | |
| 1613 | + | if reply.Type == wire.MsgError { | |
| 1614 | + | em, _ := wire.UnmarshalErrorMsg(reply.Payload) | |
| 1614 | 1615 | return fmt.Errorf("vev: %s", em.Text) | |
| 1615 | 1616 | } | |
| 1616 | 1617 | printKillSuccess(name, all, daemon) | |
M internal/ports/mocks/transport_mock.go +43 -42
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | 8 | "context" | |
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/vev/internal/ports" | |
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 11 | 12 | mock "github.com/stretchr/testify/mock" | |
| 12 | 13 | ) | |
| 13 | 14 | ||
| @@ -83,22 +84,22 @@ func (_c *MockTransport_Close_Call) RunAndReturn(run func() error) *MockTranspor | |||
| 83 | 84 | } | |
| 84 | 85 | ||
| 85 | 86 | // Recv provides a mock function for the type MockTransport | |
| 86 | - | func (_mock *MockTransport) Recv() (ports.Frame, error) { | |
| 87 | + | func (_mock *MockTransport) Recv() (wire.Frame, error) { | |
| 87 | 88 | ret := _mock.Called() | |
| 88 | 89 | ||
| 89 | 90 | if len(ret) == 0 { | |
| 90 | 91 | panic("no return value specified for Recv") | |
| 91 | 92 | } | |
| 92 | 93 | ||
| 93 | - | var r0 ports.Frame | |
| 94 | + | var r0 wire.Frame | |
| 94 | 95 | var r1 error | |
| 95 | - | if returnFunc, ok := ret.Get(0).(func() (ports.Frame, error)); ok { | |
| 96 | + | if returnFunc, ok := ret.Get(0).(func() (wire.Frame, error)); ok { | |
| 96 | 97 | return returnFunc() | |
| 97 | 98 | } | |
| 98 | - | if returnFunc, ok := ret.Get(0).(func() ports.Frame); ok { | |
| 99 | + | if returnFunc, ok := ret.Get(0).(func() wire.Frame); ok { | |
| 99 | 100 | r0 = returnFunc() | |
| 100 | 101 | } else { | |
| 101 | - | r0 = ret.Get(0).(ports.Frame) | |
| 102 | + | r0 = ret.Get(0).(wire.Frame) | |
| 102 | 103 | } | |
| 103 | 104 | if returnFunc, ok := ret.Get(1).(func() error); ok { | |
| 104 | 105 | r1 = returnFunc() | |
| @@ -125,18 +126,18 @@ func (_c *MockTransport_Recv_Call) Run(run func()) *MockTransport_Recv_Call { | |||
| 125 | 126 | return _c | |
| 126 | 127 | } | |
| 127 | 128 | ||
| 128 | - | func (_c *MockTransport_Recv_Call) Return(frame ports.Frame, err error) *MockTransport_Recv_Call { | |
| 129 | + | func (_c *MockTransport_Recv_Call) Return(frame wire.Frame, err error) *MockTransport_Recv_Call { | |
| 129 | 130 | _c.Call.Return(frame, err) | |
| 130 | 131 | return _c | |
| 131 | 132 | } | |
| 132 | 133 | ||
| 133 | - | func (_c *MockTransport_Recv_Call) RunAndReturn(run func() (ports.Frame, error)) *MockTransport_Recv_Call { | |
| 134 | + | func (_c *MockTransport_Recv_Call) RunAndReturn(run func() (wire.Frame, error)) *MockTransport_Recv_Call { | |
| 134 | 135 | _c.Call.Return(run) | |
| 135 | 136 | return _c | |
| 136 | 137 | } | |
| 137 | 138 | ||
| 138 | 139 | // Send provides a mock function for the type MockTransport | |
| 139 | - | func (_mock *MockTransport) Send(frame ports.Frame) error { | |
| 140 | + | func (_mock *MockTransport) Send(frame wire.Frame) error { | |
| 140 | 141 | ret := _mock.Called(frame) | |
| 141 | 142 | ||
| 142 | 143 | if len(ret) == 0 { | |
| @@ -144,7 +145,7 @@ func (_mock *MockTransport) Send(frame ports.Frame) error { | |||
| 144 | 145 | } | |
| 145 | 146 | ||
| 146 | 147 | var r0 error | |
| 147 | - | if returnFunc, ok := ret.Get(0).(func(ports.Frame) error); ok { | |
| 148 | + | if returnFunc, ok := ret.Get(0).(func(wire.Frame) error); ok { | |
| 148 | 149 | r0 = returnFunc(frame) | |
| 149 | 150 | } else { | |
| 150 | 151 | r0 = ret.Error(0) | |
| @@ -158,16 +159,16 @@ type MockTransport_Send_Call struct { | |||
| 158 | 159 | } | |
| 159 | 160 | ||
| 160 | 161 | // Send is a helper method to define mock.On call | |
| 161 | - | // - frame ports.Frame | |
| 162 | + | // - frame wire.Frame | |
| 162 | 163 | func (_e *MockTransport_Expecter) Send(frame any) *MockTransport_Send_Call { | |
| 163 | 164 | return &MockTransport_Send_Call{Call: _e.mock.On("Send", frame)} | |
| 164 | 165 | } | |
| 165 | 166 | ||
| 166 | - | func (_c *MockTransport_Send_Call) Run(run func(frame ports.Frame)) *MockTransport_Send_Call { | |
| 167 | + | func (_c *MockTransport_Send_Call) Run(run func(frame wire.Frame)) *MockTransport_Send_Call { | |
| 167 | 168 | _c.Call.Run(func(args mock.Arguments) { | |
| 168 | - | var arg0 ports.Frame | |
| 169 | + | var arg0 wire.Frame | |
| 169 | 170 | if args[0] != nil { | |
| 170 | - | arg0 = args[0].(ports.Frame) | |
| 171 | + | arg0 = args[0].(wire.Frame) | |
| 171 | 172 | } | |
| 172 | 173 | run( | |
| 173 | 174 | arg0, | |
| @@ -181,7 +182,7 @@ func (_c *MockTransport_Send_Call) Return(err error) *MockTransport_Send_Call { | |||
| 181 | 182 | return _c | |
| 182 | 183 | } | |
| 183 | 184 | ||
| 184 | - | func (_c *MockTransport_Send_Call) RunAndReturn(run func(frame ports.Frame) error) *MockTransport_Send_Call { | |
| 185 | + | func (_c *MockTransport_Send_Call) RunAndReturn(run func(frame wire.Frame) error) *MockTransport_Send_Call { | |
| 185 | 186 | _c.Call.Return(run) | |
| 186 | 187 | return _c | |
| 187 | 188 | } | |
| @@ -291,22 +292,22 @@ func (_c *MockDatagramTransport_DatagramTransport_Call) RunAndReturn(run func()) | |||
| 291 | 292 | } | |
| 292 | 293 | ||
| 293 | 294 | // Recv provides a mock function for the type MockDatagramTransport | |
| 294 | - | func (_mock *MockDatagramTransport) Recv() (ports.Frame, error) { | |
| 295 | + | func (_mock *MockDatagramTransport) Recv() (wire.Frame, error) { | |
| 295 | 296 | ret := _mock.Called() | |
| 296 | 297 | ||
| 297 | 298 | if len(ret) == 0 { | |
| 298 | 299 | panic("no return value specified for Recv") | |
| 299 | 300 | } | |
| 300 | 301 | ||
| 301 | - | var r0 ports.Frame | |
| 302 | + | var r0 wire.Frame | |
| 302 | 303 | var r1 error | |
| 303 | - | if returnFunc, ok := ret.Get(0).(func() (ports.Frame, error)); ok { | |
| 304 | + | if returnFunc, ok := ret.Get(0).(func() (wire.Frame, error)); ok { | |
| 304 | 305 | return returnFunc() | |
| 305 | 306 | } | |
| 306 | - | if returnFunc, ok := ret.Get(0).(func() ports.Frame); ok { | |
| 307 | + | if returnFunc, ok := ret.Get(0).(func() wire.Frame); ok { | |
| 307 | 308 | r0 = returnFunc() | |
| 308 | 309 | } else { | |
| 309 | - | r0 = ret.Get(0).(ports.Frame) | |
| 310 | + | r0 = ret.Get(0).(wire.Frame) | |
| 310 | 311 | } | |
| 311 | 312 | if returnFunc, ok := ret.Get(1).(func() error); ok { | |
| 312 | 313 | r1 = returnFunc() | |
| @@ -333,18 +334,18 @@ func (_c *MockDatagramTransport_Recv_Call) Run(run func()) *MockDatagramTranspor | |||
| 333 | 334 | return _c | |
| 334 | 335 | } | |
| 335 | 336 | ||
| 336 | - | func (_c *MockDatagramTransport_Recv_Call) Return(frame ports.Frame, err error) *MockDatagramTransport_Recv_Call { | |
| 337 | + | func (_c *MockDatagramTransport_Recv_Call) Return(frame wire.Frame, err error) *MockDatagramTransport_Recv_Call { | |
| 337 | 338 | _c.Call.Return(frame, err) | |
| 338 | 339 | return _c | |
| 339 | 340 | } | |
| 340 | 341 | ||
| 341 | - | func (_c *MockDatagramTransport_Recv_Call) RunAndReturn(run func() (ports.Frame, error)) *MockDatagramTransport_Recv_Call { | |
| 342 | + | func (_c *MockDatagramTransport_Recv_Call) RunAndReturn(run func() (wire.Frame, error)) *MockDatagramTransport_Recv_Call { | |
| 342 | 343 | _c.Call.Return(run) | |
| 343 | 344 | return _c | |
| 344 | 345 | } | |
| 345 | 346 | ||
| 346 | 347 | // Send provides a mock function for the type MockDatagramTransport | |
| 347 | - | func (_mock *MockDatagramTransport) Send(frame ports.Frame) error { | |
| 348 | + | func (_mock *MockDatagramTransport) Send(frame wire.Frame) error { | |
| 348 | 349 | ret := _mock.Called(frame) | |
| 349 | 350 | ||
| 350 | 351 | if len(ret) == 0 { | |
| @@ -352,7 +353,7 @@ func (_mock *MockDatagramTransport) Send(frame ports.Frame) error { | |||
| 352 | 353 | } | |
| 353 | 354 | ||
| 354 | 355 | var r0 error | |
| 355 | - | if returnFunc, ok := ret.Get(0).(func(ports.Frame) error); ok { | |
| 356 | + | if returnFunc, ok := ret.Get(0).(func(wire.Frame) error); ok { | |
| 356 | 357 | r0 = returnFunc(frame) | |
| 357 | 358 | } else { | |
| 358 | 359 | r0 = ret.Error(0) | |
| @@ -366,16 +367,16 @@ type MockDatagramTransport_Send_Call struct { | |||
| 366 | 367 | } | |
| 367 | 368 | ||
| 368 | 369 | // Send is a helper method to define mock.On call | |
| 369 | - | // - frame ports.Frame | |
| 370 | + | // - frame wire.Frame | |
| 370 | 371 | func (_e *MockDatagramTransport_Expecter) Send(frame any) *MockDatagramTransport_Send_Call { | |
| 371 | 372 | return &MockDatagramTransport_Send_Call{Call: _e.mock.On("Send", frame)} | |
| 372 | 373 | } | |
| 373 | 374 | ||
| 374 | - | func (_c *MockDatagramTransport_Send_Call) Run(run func(frame ports.Frame)) *MockDatagramTransport_Send_Call { | |
| 375 | + | func (_c *MockDatagramTransport_Send_Call) Run(run func(frame wire.Frame)) *MockDatagramTransport_Send_Call { | |
| 375 | 376 | _c.Call.Run(func(args mock.Arguments) { | |
| 376 | - | var arg0 ports.Frame | |
| 377 | + | var arg0 wire.Frame | |
| 377 | 378 | if args[0] != nil { | |
| 378 | - | arg0 = args[0].(ports.Frame) | |
| 379 | + | arg0 = args[0].(wire.Frame) | |
| 379 | 380 | } | |
| 380 | 381 | run( | |
| 381 | 382 | arg0, | |
| @@ -389,7 +390,7 @@ func (_c *MockDatagramTransport_Send_Call) Return(err error) *MockDatagramTransp | |||
| 389 | 390 | return _c | |
| 390 | 391 | } | |
| 391 | 392 | ||
| 392 | - | func (_c *MockDatagramTransport_Send_Call) RunAndReturn(run func(frame ports.Frame) error) *MockDatagramTransport_Send_Call { | |
| 393 | + | func (_c *MockDatagramTransport_Send_Call) RunAndReturn(run func(frame wire.Frame) error) *MockDatagramTransport_Send_Call { | |
| 393 | 394 | _c.Call.Return(run) | |
| 394 | 395 | return _c | |
| 395 | 396 | } | |
| @@ -422,7 +423,7 @@ func (_m *MockAsyncTransport) EXPECT() *MockAsyncTransport_Expecter { | |||
| 422 | 423 | } | |
| 423 | 424 | ||
| 424 | 425 | // SendAsync provides a mock function for the type MockAsyncTransport | |
| 425 | - | func (_mock *MockAsyncTransport) SendAsync(frame ports.Frame) error { | |
| 426 | + | func (_mock *MockAsyncTransport) SendAsync(frame wire.Frame) error { | |
| 426 | 427 | ret := _mock.Called(frame) | |
| 427 | 428 | ||
| 428 | 429 | if len(ret) == 0 { | |
| @@ -430,7 +431,7 @@ func (_mock *MockAsyncTransport) SendAsync(frame ports.Frame) error { | |||
| 430 | 431 | } | |
| 431 | 432 | ||
| 432 | 433 | var r0 error | |
| 433 | - | if returnFunc, ok := ret.Get(0).(func(ports.Frame) error); ok { | |
| 434 | + | if returnFunc, ok := ret.Get(0).(func(wire.Frame) error); ok { | |
| 434 | 435 | r0 = returnFunc(frame) | |
| 435 | 436 | } else { | |
| 436 | 437 | r0 = ret.Error(0) | |
| @@ -444,16 +445,16 @@ type MockAsyncTransport_SendAsync_Call struct { | |||
| 444 | 445 | } | |
| 445 | 446 | ||
| 446 | 447 | // SendAsync is a helper method to define mock.On call | |
| 447 | - | // - frame ports.Frame | |
| 448 | + | // - frame wire.Frame | |
| 448 | 449 | func (_e *MockAsyncTransport_Expecter) SendAsync(frame any) *MockAsyncTransport_SendAsync_Call { | |
| 449 | 450 | return &MockAsyncTransport_SendAsync_Call{Call: _e.mock.On("SendAsync", frame)} | |
| 450 | 451 | } | |
| 451 | 452 | ||
| 452 | - | func (_c *MockAsyncTransport_SendAsync_Call) Run(run func(frame ports.Frame)) *MockAsyncTransport_SendAsync_Call { | |
| 453 | + | func (_c *MockAsyncTransport_SendAsync_Call) Run(run func(frame wire.Frame)) *MockAsyncTransport_SendAsync_Call { | |
| 453 | 454 | _c.Call.Run(func(args mock.Arguments) { | |
| 454 | - | var arg0 ports.Frame | |
| 455 | + | var arg0 wire.Frame | |
| 455 | 456 | if args[0] != nil { | |
| 456 | - | arg0 = args[0].(ports.Frame) | |
| 457 | + | arg0 = args[0].(wire.Frame) | |
| 457 | 458 | } | |
| 458 | 459 | run( | |
| 459 | 460 | arg0, | |
| @@ -467,7 +468,7 @@ func (_c *MockAsyncTransport_SendAsync_Call) Return(err error) *MockAsyncTranspo | |||
| 467 | 468 | return _c | |
| 468 | 469 | } | |
| 469 | 470 | ||
| 470 | - | func (_c *MockAsyncTransport_SendAsync_Call) RunAndReturn(run func(frame ports.Frame) error) *MockAsyncTransport_SendAsync_Call { | |
| 471 | + | func (_c *MockAsyncTransport_SendAsync_Call) RunAndReturn(run func(frame wire.Frame) error) *MockAsyncTransport_SendAsync_Call { | |
| 471 | 472 | _c.Call.Return(run) | |
| 472 | 473 | return _c | |
| 473 | 474 | } | |
| @@ -500,7 +501,7 @@ func (_m *MockOwnedSynchronousTransport) EXPECT() *MockOwnedSynchronousTransport | |||
| 500 | 501 | } | |
| 501 | 502 | ||
| 502 | 503 | // SendSynchronous provides a mock function for the type MockOwnedSynchronousTransport | |
| 503 | - | func (_mock *MockOwnedSynchronousTransport) SendSynchronous(frame ports.Frame) error { | |
| 504 | + | func (_mock *MockOwnedSynchronousTransport) SendSynchronous(frame wire.Frame) error { | |
| 504 | 505 | ret := _mock.Called(frame) | |
| 505 | 506 | ||
| 506 | 507 | if len(ret) == 0 { | |
| @@ -508,7 +509,7 @@ func (_mock *MockOwnedSynchronousTransport) SendSynchronous(frame ports.Frame) e | |||
| 508 | 509 | } | |
| 509 | 510 | ||
| 510 | 511 | var r0 error | |
| 511 | - | if returnFunc, ok := ret.Get(0).(func(ports.Frame) error); ok { | |
| 512 | + | if returnFunc, ok := ret.Get(0).(func(wire.Frame) error); ok { | |
| 512 | 513 | r0 = returnFunc(frame) | |
| 513 | 514 | } else { | |
| 514 | 515 | r0 = ret.Error(0) | |
| @@ -522,16 +523,16 @@ type MockOwnedSynchronousTransport_SendSynchronous_Call struct { | |||
| 522 | 523 | } | |
| 523 | 524 | ||
| 524 | 525 | // SendSynchronous is a helper method to define mock.On call | |
| 525 | - | // - frame ports.Frame | |
| 526 | + | // - frame wire.Frame | |
| 526 | 527 | func (_e *MockOwnedSynchronousTransport_Expecter) SendSynchronous(frame any) *MockOwnedSynchronousTransport_SendSynchronous_Call { | |
| 527 | 528 | return &MockOwnedSynchronousTransport_SendSynchronous_Call{Call: _e.mock.On("SendSynchronous", frame)} | |
| 528 | 529 | } | |
| 529 | 530 | ||
| 530 | - | func (_c *MockOwnedSynchronousTransport_SendSynchronous_Call) Run(run func(frame ports.Frame)) *MockOwnedSynchronousTransport_SendSynchronous_Call { | |
| 531 | + | func (_c *MockOwnedSynchronousTransport_SendSynchronous_Call) Run(run func(frame wire.Frame)) *MockOwnedSynchronousTransport_SendSynchronous_Call { | |
| 531 | 532 | _c.Call.Run(func(args mock.Arguments) { | |
| 532 | - | var arg0 ports.Frame | |
| 533 | + | var arg0 wire.Frame | |
| 533 | 534 | if args[0] != nil { | |
| 534 | - | arg0 = args[0].(ports.Frame) | |
| 535 | + | arg0 = args[0].(wire.Frame) | |
| 535 | 536 | } | |
| 536 | 537 | run( | |
| 537 | 538 | arg0, | |
| @@ -545,7 +546,7 @@ func (_c *MockOwnedSynchronousTransport_SendSynchronous_Call) Return(err error) | |||
| 545 | 546 | return _c | |
| 546 | 547 | } | |
| 547 | 548 | ||
| 548 | - | func (_c *MockOwnedSynchronousTransport_SendSynchronous_Call) RunAndReturn(run func(frame ports.Frame) error) *MockOwnedSynchronousTransport_SendSynchronous_Call { | |
| 549 | + | func (_c *MockOwnedSynchronousTransport_SendSynchronous_Call) RunAndReturn(run func(frame wire.Frame) error) *MockOwnedSynchronousTransport_SendSynchronous_Call { | |
| 549 | 550 | _c.Call.Return(run) | |
| 550 | 551 | return _c | |
| 551 | 552 | } | |
M internal/ports/transport.go +9 -5
| @@ -1,13 +1,17 @@ | |||
| 1 | 1 | package ports | |
| 2 | 2 | ||
| 3 | - | import "context" | |
| 3 | + | import ( | |
| 4 | + | "context" | |
| 5 | + | ||
| 6 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 7 | + | ) | |
| 4 | 8 | ||
| 5 | 9 | // Transport is a framed message channel over a single connection. Close must | |
| 6 | 10 | // be safe to call concurrently with Send and Recv, and must unblock active | |
| 7 | 11 | // Send and Recv calls. | |
| 8 | 12 | type Transport interface { | |
| 9 | - | Send(Frame) error | |
| 10 | - | Recv() (Frame, error) // blocking; io.EOF on close | |
| 13 | + | Send(wire.Frame) error | |
| 14 | + | Recv() (wire.Frame, error) // blocking; io.EOF on close | |
| 11 | 15 | Close() error | |
| 12 | 16 | } | |
| 13 | 17 | ||
| @@ -22,13 +26,13 @@ type DatagramTransport interface { | |||
| 22 | 26 | // returns once the adapter owns the frame; Send retains its synchronous wire- | |
| 23 | 27 | // attempt contract. Daemon paint output may use this capability to pipeline. | |
| 24 | 28 | type AsyncTransport interface { | |
| 25 | - | SendAsync(Frame) error | |
| 29 | + | SendAsync(wire.Frame) error | |
| 26 | 30 | } | |
| 27 | 31 | ||
| 28 | 32 | // OwnedSynchronousTransport owns the complete bounded synchronous operation, | |
| 29 | 33 | // including adapter queues, pacing, write deadlines, and close cancellation. | |
| 30 | 34 | type OwnedSynchronousTransport interface { | |
| 31 | - | SendSynchronous(Frame) error | |
| 35 | + | SendSynchronous(wire.Frame) error | |
| 32 | 36 | } | |
| 33 | 37 | ||
| 34 | 38 | // Dialer establishes outbound Transport connections. | |
R internal/ports/frame.go → internal/protocol/wire/frame.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | // MaxFrameLen is the largest permitted frame length, including the type byte | |
| 4 | 4 | // and excluding the four-byte length prefix. | |
R internal/ports/frame_test.go → internal/protocol/wire/frame_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "testing" | |
R internal/ports/navigation_test.go → internal/protocol/wire/navigation_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "encoding/hex" | |
R internal/ports/output_compression_test.go → internal/protocol/wire/output_compression_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "bytes" | |
R internal/ports/remote_preview_hardening_test.go → internal/protocol/wire/remote_preview_hardening_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "bytes" | |
R internal/ports/remote_preview_test.go → internal/protocol/wire/remote_preview_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "testing" | |
R internal/ports/remote_target_wire_test.go → internal/protocol/wire/remote_target_wire_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "bytes" | |
R internal/ports/routes_test.go → internal/protocol/wire/routes_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "encoding/hex" | |
R internal/ports/routes_wire.go → internal/protocol/wire/routes_wire.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "fmt" | |
R internal/ports/same_peer_switch_test.go → internal/protocol/wire/same_peer_switch_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "bytes" | |
R internal/ports/wire.go → internal/protocol/wire/wire.go +3 -6 renamed, 99% similar
| @@ -1,10 +1,7 @@ | |||
| 1 | - | // Wire codecs for vev's IPC message payloads. They live in ports (alongside | |
| 2 | - | // Frame and the MsgType constants) because wire encoding is protocol | |
| 3 | - | // surface, not I/O: everything here is pure, stdlib-only byte marshalling. | |
| 4 | - | // Adapters keep what actually performs I/O (framing over a connection, | |
| 5 | - | // listening on a socket) and import these types for the payloads they carry. | |
| 1 | + | // Package wire owns vev's binary frame representation and strict payload | |
| 2 | + | // codecs. It performs no I/O; carriage adapters transport Frame values. | |
| 6 | 3 | ||
| 7 | - | package ports | |
| 4 | + | package wire | |
| 8 | 5 | ||
| 9 | 6 | import ( | |
| 10 | 7 | "bytes" | |
R internal/ports/wire_command.go → internal/protocol/wire/wire_command.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "encoding/binary" | |
R internal/ports/wire_final_test.go → internal/protocol/wire/wire_final_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "bytes" | |
R internal/ports/wire_test.go → internal/protocol/wire/wire_test.go +1 -1 renamed, 99% similar
| @@ -1,4 +1,4 @@ | |||
| 1 | - | package ports | |
| 1 | + | package wire | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "bytes" | |
M internal/testutil/replaytest/replay.go +12 -12
| @@ -8,31 +8,31 @@ import ( | |||
| 8 | 8 | "testing" | |
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/vev/internal/domain" | |
| 11 | - | "github.com/bnema/vev/internal/ports" | |
| 12 | 11 | "github.com/bnema/vev/internal/protocol" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 13 | ) | |
| 14 | 14 | ||
| 15 | 15 | func mustMarshalOutput(m protocol.Output) []byte { | |
| 16 | - | payload, err := ports.MarshalOutput(m) | |
| 16 | + | payload, err := wire.MarshalOutput(m) | |
| 17 | 17 | if err != nil { | |
| 18 | 18 | panic(err) | |
| 19 | 19 | } | |
| 20 | 20 | return payload | |
| 21 | 21 | } | |
| 22 | 22 | ||
| 23 | - | var transcript = []ports.Frame{ | |
| 24 | - | {Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Base: 0, New: 1, Size: domain.Size{Cols: 80, Rows: 24}, Full: true, Data: []byte("\x1b[2J\x1b[Hone\r\ntwo")})}, | |
| 25 | - | {Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Base: 1, New: 2, Echo: 7, Size: domain.Size{Cols: 80, Rows: 24}, Data: []byte("\x1b[2;1HTWO")})}, | |
| 23 | + | var transcript = []wire.Frame{ | |
| 24 | + | {Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Base: 0, New: 1, Size: domain.Size{Cols: 80, Rows: 24}, Full: true, Data: []byte("\x1b[2J\x1b[Hone\r\ntwo")})}, | |
| 25 | + | {Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{Epoch: 1, Base: 1, New: 2, Echo: 7, Size: domain.Size{Cols: 80, Rows: 24}, Data: []byte("\x1b[2;1HTWO")})}, | |
| 26 | 26 | } | |
| 27 | 27 | ||
| 28 | 28 | // Transcript returns a deep copy of the canonical replay transcript so an | |
| 29 | 29 | // adapter cannot mutate the fixture observed by another adapter. | |
| 30 | - | func Transcript() []ports.Frame { | |
| 30 | + | func Transcript() []wire.Frame { | |
| 31 | 31 | return cloneFrames(transcript) | |
| 32 | 32 | } | |
| 33 | 33 | ||
| 34 | 34 | // Exchange carries already-composed frames through one transport adapter. | |
| 35 | - | type Exchange func(t *testing.T, frames []ports.Frame) []ports.Frame | |
| 35 | + | type Exchange func(t *testing.T, frames []wire.Frame) []wire.Frame | |
| 36 | 36 | ||
| 37 | 37 | // Run verifies that an adapter preserves the canonical transcript exactly. | |
| 38 | 38 | func Run(t *testing.T, exchange Exchange) { | |
| @@ -50,12 +50,12 @@ func Run(t *testing.T, exchange Exchange) { | |||
| 50 | 50 | t.Errorf("frame %d payload = %x, want byte-for-byte %x", i, got[i].Payload, want[i].Payload) | |
| 51 | 51 | continue | |
| 52 | 52 | } | |
| 53 | - | gotOutput, err := ports.UnmarshalOutput(got[i].Payload) | |
| 53 | + | gotOutput, err := wire.UnmarshalOutput(got[i].Payload) | |
| 54 | 54 | if err != nil { | |
| 55 | 55 | t.Errorf("frame %d output decode: %v", i, err) | |
| 56 | 56 | continue | |
| 57 | 57 | } | |
| 58 | - | wantOutput, err := ports.UnmarshalOutput(want[i].Payload) | |
| 58 | + | wantOutput, err := wire.UnmarshalOutput(want[i].Payload) | |
| 59 | 59 | if err != nil { | |
| 60 | 60 | t.Fatalf("canonical frame %d output decode: %v", i, err) | |
| 61 | 61 | } | |
| @@ -65,10 +65,10 @@ func Run(t *testing.T, exchange Exchange) { | |||
| 65 | 65 | } | |
| 66 | 66 | } | |
| 67 | 67 | ||
| 68 | - | func cloneFrames(frames []ports.Frame) []ports.Frame { | |
| 69 | - | cloned := make([]ports.Frame, len(frames)) | |
| 68 | + | func cloneFrames(frames []wire.Frame) []wire.Frame { | |
| 69 | + | cloned := make([]wire.Frame, len(frames)) | |
| 70 | 70 | for i, frame := range frames { | |
| 71 | - | cloned[i] = ports.Frame{Type: frame.Type, Payload: append([]byte(nil), frame.Payload...)} | |
| 71 | + | cloned[i] = wire.Frame{Type: frame.Type, Payload: append([]byte(nil), frame.Payload...)} | |
| 72 | 72 | } | |
| 73 | 73 | return cloned | |
| 74 | 74 | } | |
M internal/usecase/client/ack_queue_test.go +26 -26
| @@ -7,20 +7,20 @@ import ( | |||
| 7 | 7 | "testing" | |
| 8 | 8 | "time" | |
| 9 | 9 | ||
| 10 | - | "github.com/bnema/vev/internal/ports" | |
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 11 | 11 | "github.com/stretchr/testify/require" | |
| 12 | 12 | ) | |
| 13 | 13 | ||
| 14 | - | type ackRecordingTransport struct{ sent chan ports.Frame } | |
| 14 | + | type ackRecordingTransport struct{ sent chan wire.Frame } | |
| 15 | 15 | ||
| 16 | - | func (t *ackRecordingTransport) Send(f ports.Frame) error { t.sent <- f; return nil } | |
| 17 | - | func (t *ackRecordingTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 18 | - | func (t *ackRecordingTransport) Close() error { return nil } | |
| 16 | + | func (t *ackRecordingTransport) Send(f wire.Frame) error { t.sent <- f; return nil } | |
| 17 | + | func (t *ackRecordingTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 18 | + | func (t *ackRecordingTransport) Close() error { return nil } | |
| 19 | 19 | ||
| 20 | 20 | func TestCumulativeAckBypassesFullNormalSendQueue(t *testing.T) { | |
| 21 | - | normal := make(chan ports.Frame, sendQueueDepth) | |
| 21 | + | normal := make(chan wire.Frame, sendQueueDepth) | |
| 22 | 22 | for range cap(normal) { | |
| 23 | - | normal <- ports.Frame{Type: ports.MsgInput} | |
| 23 | + | normal <- wire.Frame{Type: wire.MsgInput} | |
| 24 | 24 | } | |
| 25 | 25 | const epoch = 7 | |
| 26 | 26 | acks := newCumulativeAckQueue() | |
| @@ -30,13 +30,13 @@ func TestCumulativeAckBypassesFullNormalSendQueue(t *testing.T) { | |||
| 30 | 30 | ||
| 31 | 31 | ctx, cancel := context.WithCancel(context.Background()) | |
| 32 | 32 | defer cancel() | |
| 33 | - | tr := &ackRecordingTransport{sent: make(chan ports.Frame, sendQueueDepth+1)} | |
| 33 | + | tr := &ackRecordingTransport{sent: make(chan wire.Frame, sendQueueDepth+1)} | |
| 34 | 34 | errCh := make(chan error, 1) | |
| 35 | 35 | go runSender(ctx, cancel, tr, nil, nil, normal, nil, acks, errCh, slog.Default()) | |
| 36 | 36 | ||
| 37 | 37 | first := <-tr.sent | |
| 38 | - | require.Equal(t, ports.MsgAck, first.Type) | |
| 39 | - | ack, err := ports.UnmarshalAck(first.Payload) | |
| 38 | + | require.Equal(t, wire.MsgAck, first.Type) | |
| 39 | + | ack, err := wire.UnmarshalAck(first.Payload) | |
| 40 | 40 | require.NoError(t, err) | |
| 41 | 41 | require.Equal(t, uint64(epoch), ack.Epoch) | |
| 42 | 42 | require.Equal(t, uint64(maxUnackedOutputStatesForTest), ack.State) | |
| @@ -45,21 +45,21 @@ func TestCumulativeAckBypassesFullNormalSendQueue(t *testing.T) { | |||
| 45 | 45 | func TestSamePeerSwitchControlBypassesHeldInput(t *testing.T) { | |
| 46 | 46 | ctx, cancel := context.WithCancel(context.Background()) | |
| 47 | 47 | defer cancel() | |
| 48 | - | normal := make(chan ports.Frame, 1) | |
| 49 | - | control := make(chan ports.Frame, 1) | |
| 48 | + | normal := make(chan wire.Frame, 1) | |
| 49 | + | control := make(chan wire.Frame, 1) | |
| 50 | 50 | gate := newSamePeerInputGate() | |
| 51 | 51 | gate.setPaused(true) | |
| 52 | 52 | held := make(chan struct{}) | |
| 53 | 53 | gate.afterInputHeld = func() { close(held) } | |
| 54 | - | transport := &ackRecordingTransport{sent: make(chan ports.Frame, 2)} | |
| 54 | + | transport := &ackRecordingTransport{sent: make(chan wire.Frame, 2)} | |
| 55 | 55 | acks := newCumulativeAckQueue() | |
| 56 | 56 | errs := make(chan error, 1) | |
| 57 | 57 | go runSender(ctx, cancel, transport, control, nil, normal, gate, acks, errs, slog.Default()) | |
| 58 | 58 | ||
| 59 | - | normal <- ports.Frame{Type: ports.MsgInput, Payload: []byte("held")} | |
| 59 | + | normal <- wire.Frame{Type: wire.MsgInput, Payload: []byte("held")} | |
| 60 | 60 | awaitSenderSignal(t, held) | |
| 61 | - | control <- ports.Frame{Type: ports.MsgSamePeerSwitchRequest, Payload: []byte("switch")} | |
| 62 | - | if got := awaitSenderFrame(t, transport.sent); got.Type != ports.MsgSamePeerSwitchRequest { | |
| 61 | + | control <- wire.Frame{Type: wire.MsgSamePeerSwitchRequest, Payload: []byte("switch")} | |
| 62 | + | if got := awaitSenderFrame(t, transport.sent); got.Type != wire.MsgSamePeerSwitchRequest { | |
| 63 | 63 | t.Fatalf("first frame = %d, want same-peer switch request", got.Type) | |
| 64 | 64 | } | |
| 65 | 65 | select { | |
| @@ -68,7 +68,7 @@ func TestSamePeerSwitchControlBypassesHeldInput(t *testing.T) { | |||
| 68 | 68 | default: | |
| 69 | 69 | } | |
| 70 | 70 | gate.setPaused(false) | |
| 71 | - | if got := awaitSenderFrame(t, transport.sent); got.Type != ports.MsgInput { | |
| 71 | + | if got := awaitSenderFrame(t, transport.sent); got.Type != wire.MsgInput { | |
| 72 | 72 | t.Fatalf("released frame = %d, want input", got.Type) | |
| 73 | 73 | } | |
| 74 | 74 | } | |
| @@ -76,14 +76,14 @@ func TestSamePeerSwitchControlBypassesHeldInput(t *testing.T) { | |||
| 76 | 76 | func TestSenderBarrierLeavesPausedInputQueued(t *testing.T) { | |
| 77 | 77 | ctx, cancel := context.WithCancel(context.Background()) | |
| 78 | 78 | defer cancel() | |
| 79 | - | normal := make(chan ports.Frame, 1) | |
| 79 | + | normal := make(chan wire.Frame, 1) | |
| 80 | 80 | barriers := make(chan chan struct{}) | |
| 81 | 81 | gate := newSamePeerInputGate() | |
| 82 | 82 | gate.setPaused(true) | |
| 83 | - | transport := &ackRecordingTransport{sent: make(chan ports.Frame, 1)} | |
| 83 | + | transport := &ackRecordingTransport{sent: make(chan wire.Frame, 1)} | |
| 84 | 84 | go runSender(ctx, cancel, transport, nil, barriers, normal, gate, newCumulativeAckQueue(), make(chan error, 1), slog.Default()) | |
| 85 | 85 | ||
| 86 | - | normal <- ports.Frame{Type: ports.MsgInput, Payload: []byte("held")} | |
| 86 | + | normal <- wire.Frame{Type: wire.MsgInput, Payload: []byte("held")} | |
| 87 | 87 | barrierDone := make(chan struct{}) | |
| 88 | 88 | barriers <- barrierDone | |
| 89 | 89 | awaitSenderSignal(t, barrierDone) | |
| @@ -94,7 +94,7 @@ func TestSenderBarrierLeavesPausedInputQueued(t *testing.T) { | |||
| 94 | 94 | } | |
| 95 | 95 | ||
| 96 | 96 | gate.setPaused(false) | |
| 97 | - | if got := awaitSenderFrame(t, transport.sent); got.Type != ports.MsgInput { | |
| 97 | + | if got := awaitSenderFrame(t, transport.sent); got.Type != wire.MsgInput { | |
| 98 | 98 | t.Fatalf("released frame = %d, want input", got.Type) | |
| 99 | 99 | } | |
| 100 | 100 | } | |
| @@ -104,14 +104,14 @@ func TestSenderBarrierFlushesPendingAck(t *testing.T) { | |||
| 104 | 104 | defer cancel() | |
| 105 | 105 | acks := newCumulativeAckQueue() | |
| 106 | 106 | acks.offer(3, 9) | |
| 107 | - | transport := &ackRecordingTransport{sent: make(chan ports.Frame, 1)} | |
| 107 | + | transport := &ackRecordingTransport{sent: make(chan wire.Frame, 1)} | |
| 108 | 108 | barriers := make(chan chan struct{}) | |
| 109 | - | go runSender(ctx, cancel, transport, nil, barriers, make(chan ports.Frame, 1), newSamePeerInputGate(), acks, make(chan error, 1), slog.Default()) | |
| 109 | + | go runSender(ctx, cancel, transport, nil, barriers, make(chan wire.Frame, 1), newSamePeerInputGate(), acks, make(chan error, 1), slog.Default()) | |
| 110 | 110 | ||
| 111 | 111 | done := make(chan struct{}) | |
| 112 | 112 | barriers <- done | |
| 113 | 113 | frame := awaitSenderFrame(t, transport.sent) | |
| 114 | - | require.Equal(t, ports.MsgAck, frame.Type) | |
| 114 | + | require.Equal(t, wire.MsgAck, frame.Type) | |
| 115 | 115 | awaitSenderSignal(t, done) | |
| 116 | 116 | } | |
| 117 | 117 | ||
| @@ -124,14 +124,14 @@ func awaitSenderSignal(t *testing.T, signal <-chan struct{}) { | |||
| 124 | 124 | } | |
| 125 | 125 | } | |
| 126 | 126 | ||
| 127 | - | func awaitSenderFrame(t *testing.T, frames <-chan ports.Frame) ports.Frame { | |
| 127 | + | func awaitSenderFrame(t *testing.T, frames <-chan wire.Frame) wire.Frame { | |
| 128 | 128 | t.Helper() | |
| 129 | 129 | select { | |
| 130 | 130 | case frame := <-frames: | |
| 131 | 131 | return frame | |
| 132 | 132 | case <-time.After(time.Second): | |
| 133 | 133 | t.Fatal("sender did not emit frame") | |
| 134 | - | return ports.Frame{} | |
| 134 | + | return wire.Frame{} | |
| 135 | 135 | } | |
| 136 | 136 | } | |
| 137 | 137 | ||
M internal/usecase/client/client.go +74 -73
| @@ -24,6 +24,7 @@ import ( | |||
| 24 | 24 | "github.com/bnema/vev/internal/domain" | |
| 25 | 25 | "github.com/bnema/vev/internal/ports" | |
| 26 | 26 | "github.com/bnema/vev/internal/protocol" | |
| 27 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 27 | 28 | "github.com/bnema/vev/internal/usecase/theme" | |
| 28 | 29 | ) | |
| 29 | 30 | ||
| @@ -1243,14 +1244,14 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1243 | 1244 | Remote: remote, | |
| 1244 | 1245 | } | |
| 1245 | 1246 | if err := sendHandshake(func() error { | |
| 1246 | - | return transport.Send(ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(hello)}) | |
| 1247 | + | return transport.Send(wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(hello)}) | |
| 1247 | 1248 | }); err != nil { | |
| 1248 | 1249 | return handshakeFailure("sending hello", err) | |
| 1249 | 1250 | } | |
| 1250 | 1251 | ms.helloSent = true | |
| 1251 | 1252 | ||
| 1252 | 1253 | // 2. Await Welcome or a typed rejection. | |
| 1253 | - | var reply ports.Frame | |
| 1254 | + | var reply wire.Frame | |
| 1254 | 1255 | if err := boundedHandshakeOperationWithTransition(handshakeCtx, transport, func() error { | |
| 1255 | 1256 | var recvErr error | |
| 1256 | 1257 | reply, recvErr = transport.Recv() | |
| @@ -1271,8 +1272,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1271 | 1272 | } | |
| 1272 | 1273 | } | |
| 1273 | 1274 | switch reply.Type { | |
| 1274 | - | case ports.MsgWelcome: | |
| 1275 | - | welcome, derr := ports.UnmarshalWelcome(reply.Payload) | |
| 1275 | + | case wire.MsgWelcome: | |
| 1276 | + | welcome, derr := wire.UnmarshalWelcome(reply.Payload) | |
| 1276 | 1277 | if derr != nil { | |
| 1277 | 1278 | return result(false, fmt.Errorf("vev: decoding welcome: %w", derr)) | |
| 1278 | 1279 | } | |
| @@ -1286,8 +1287,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1286 | 1287 | remember() | |
| 1287 | 1288 | } | |
| 1288 | 1289 | } | |
| 1289 | - | case ports.MsgError: | |
| 1290 | - | em, derr := ports.UnmarshalErrorMsg(reply.Payload) | |
| 1290 | + | case wire.MsgError: | |
| 1291 | + | em, derr := wire.UnmarshalErrorMsg(reply.Payload) | |
| 1291 | 1292 | if derr != nil { | |
| 1292 | 1293 | return result(false, fmt.Errorf("vev: decoding error reply: %w", derr)) | |
| 1293 | 1294 | } | |
| @@ -1319,30 +1320,30 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1319 | 1320 | return welcomedResult(fmt.Errorf("vev: committing route identity: %w", commitErr)) | |
| 1320 | 1321 | } | |
| 1321 | 1322 | } | |
| 1322 | - | snapshotPayload, err := ports.MarshalRecentRouteSnapshot(a.runner.ledger.snapshot()) | |
| 1323 | + | snapshotPayload, err := wire.MarshalRecentRouteSnapshot(a.runner.ledger.snapshot()) | |
| 1323 | 1324 | if err != nil { | |
| 1324 | 1325 | return welcomedResult(fmt.Errorf("vev: encoding route snapshot: %w", err)) | |
| 1325 | 1326 | } | |
| 1326 | - | attentionPayload, err := ports.MarshalRouteAttentionSubscription(a.runner.ledger.attentionSubscription()) | |
| 1327 | + | attentionPayload, err := wire.MarshalRouteAttentionSubscription(a.runner.ledger.attentionSubscription()) | |
| 1327 | 1328 | if err != nil { | |
| 1328 | 1329 | return welcomedResult(fmt.Errorf("vev: encoding route attention subscription: %w", err)) | |
| 1329 | 1330 | } | |
| 1330 | 1331 | if err := sendHandshake(func() error { | |
| 1331 | - | if err := transport.Send(ports.Frame{Type: ports.MsgRecentRouteSnapshot, Payload: snapshotPayload}); err != nil { | |
| 1332 | + | if err := transport.Send(wire.Frame{Type: wire.MsgRecentRouteSnapshot, Payload: snapshotPayload}); err != nil { | |
| 1332 | 1333 | return err | |
| 1333 | 1334 | } | |
| 1334 | - | return transport.Send(ports.Frame{Type: ports.MsgRouteAttentionSubscription, Payload: attentionPayload}) | |
| 1335 | + | return transport.Send(wire.Frame{Type: wire.MsgRouteAttentionSubscription, Payload: attentionPayload}) | |
| 1335 | 1336 | }); err != nil { | |
| 1336 | 1337 | return welcomedResult(fmt.Errorf("vev: publishing route snapshot: %w", err)) | |
| 1337 | 1338 | } | |
| 1338 | 1339 | } | |
| 1339 | 1340 | if a.runner.routeFailure != nil { | |
| 1340 | - | payload, err := ports.MarshalRouteNavigationFailure(*a.runner.routeFailure) | |
| 1341 | + | payload, err := wire.MarshalRouteNavigationFailure(*a.runner.routeFailure) | |
| 1341 | 1342 | if err != nil { | |
| 1342 | 1343 | return welcomedResult(fmt.Errorf("vev: encoding route navigation failure: %w", err)) | |
| 1343 | 1344 | } | |
| 1344 | 1345 | if err := sendHandshake(func() error { | |
| 1345 | - | return transport.Send(ports.Frame{Type: ports.MsgRouteNavigationFailure, Payload: payload}) | |
| 1346 | + | return transport.Send(wire.Frame{Type: wire.MsgRouteNavigationFailure, Payload: payload}) | |
| 1346 | 1347 | }); err != nil { | |
| 1347 | 1348 | return welcomedResult(fmt.Errorf("vev: publishing route navigation failure: %w", err)) | |
| 1348 | 1349 | } | |
| @@ -1369,8 +1370,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1369 | 1370 | input.start() | |
| 1370 | 1371 | defer input.stop() | |
| 1371 | 1372 | } | |
| 1372 | - | sendCh := make(chan ports.Frame, sendQueueDepth) | |
| 1373 | - | controlCh := make(chan ports.Frame, 1) | |
| 1373 | + | sendCh := make(chan wire.Frame, sendQueueDepth) | |
| 1374 | + | controlCh := make(chan wire.Frame, 1) | |
| 1374 | 1375 | barrierCh := make(chan chan struct{}) | |
| 1375 | 1376 | inputGate := newSamePeerInputGate() | |
| 1376 | 1377 | ackQueue := newCumulativeAckQueue() | |
| @@ -1393,7 +1394,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1393 | 1394 | } | |
| 1394 | 1395 | } | |
| 1395 | 1396 | publish := func(snapshot protocol.Theme) error { | |
| 1396 | - | frame := ports.Frame{Type: ports.MsgTheme, Payload: ports.MarshalTheme(snapshot)} | |
| 1397 | + | frame := wire.Frame{Type: wire.MsgTheme, Payload: wire.MarshalTheme(snapshot)} | |
| 1397 | 1398 | // The initial cleared snapshot is sent before the sender exists. This | |
| 1398 | 1399 | // keeps the generation publication ordered before the first query and | |
| 1399 | 1400 | // avoids leaving a queued Theme behind an immediate detach. | |
| @@ -1503,11 +1504,11 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1503 | 1504 | // Before the asynchronous sender starts, preserve transport ordering by | |
| 1504 | 1505 | // requesting the reset synchronously after the initial Theme publication. | |
| 1505 | 1506 | resetErr := sendHandshake(func() error { | |
| 1506 | - | payload, err := ports.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) | |
| 1507 | + | payload, err := wire.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) | |
| 1507 | 1508 | if err != nil { | |
| 1508 | 1509 | return err | |
| 1509 | 1510 | } | |
| 1510 | - | return transport.Send(ports.Frame{Type: ports.MsgResize, Payload: payload}) | |
| 1511 | + | return transport.Send(wire.Frame{Type: wire.MsgResize, Payload: payload}) | |
| 1511 | 1512 | }) | |
| 1512 | 1513 | if resetErr != nil { | |
| 1513 | 1514 | resetErr = handshakeContextError(ctx, handshakeTimedOut, resetErr) | |
| @@ -1629,12 +1630,12 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1629 | 1630 | return fmt.Errorf("reading terminal geometry for parked route: %w", err) | |
| 1630 | 1631 | } | |
| 1631 | 1632 | geometry = geometry.NormalizePixels() | |
| 1632 | - | payload, err := ports.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) | |
| 1633 | + | payload, err := wire.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) | |
| 1633 | 1634 | if err != nil { | |
| 1634 | 1635 | return fmt.Errorf("encoding terminal size for parked route: %w", err) | |
| 1635 | 1636 | } | |
| 1636 | 1637 | select { | |
| 1637 | - | case controlCh <- ports.Frame{Type: ports.MsgResize, Payload: payload}: | |
| 1638 | + | case controlCh <- wire.Frame{Type: wire.MsgResize, Payload: payload}: | |
| 1638 | 1639 | return nil | |
| 1639 | 1640 | case <-loopCtx.Done(): | |
| 1640 | 1641 | return context.Canceled | |
| @@ -1646,12 +1647,12 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1646 | 1647 | } | |
| 1647 | 1648 | nextParkedRequestID++ | |
| 1648 | 1649 | request := protocol.ParkedRouteRequest{RequestID: nextParkedRequestID, LeaseID: leaseID, Action: action, Target: target} | |
| 1649 | - | payload := ports.MarshalParkedRouteRequest(request) | |
| 1650 | + | payload := wire.MarshalParkedRouteRequest(request) | |
| 1650 | 1651 | if payload == nil { | |
| 1651 | 1652 | return errors.New("vev: invalid parked-route request") | |
| 1652 | 1653 | } | |
| 1653 | 1654 | select { | |
| 1654 | - | case controlCh <- ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: payload}: | |
| 1655 | + | case controlCh <- wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: payload}: | |
| 1655 | 1656 | parkedPending = &parkedRoutePending{ | |
| 1656 | 1657 | requestID: request.RequestID, action: action, leaseID: leaseID, | |
| 1657 | 1658 | timer: clk.NewTimer(protocol.HandshakeTimeout), | |
| @@ -1726,12 +1727,12 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1726 | 1727 | return fmt.Errorf("reading terminal geometry for reconnect reconciliation: %w", serr) | |
| 1727 | 1728 | } | |
| 1728 | 1729 | geometry = geometry.NormalizePixels() | |
| 1729 | - | payload, err := ports.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) | |
| 1730 | + | payload, err := wire.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) | |
| 1730 | 1731 | if err != nil { | |
| 1731 | 1732 | return fmt.Errorf("encoding terminal size for reconnect reconciliation: %w", err) | |
| 1732 | 1733 | } | |
| 1733 | 1734 | select { | |
| 1734 | - | case sendCh <- ports.Frame{Type: ports.MsgResize, Payload: payload}: | |
| 1735 | + | case sendCh <- wire.Frame{Type: wire.MsgResize, Payload: payload}: | |
| 1735 | 1736 | awaitingReconnectReset = true | |
| 1736 | 1737 | return nil | |
| 1737 | 1738 | case <-loopCtx.Done(): | |
| @@ -1742,17 +1743,17 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1742 | 1743 | if a.runner.ledger == nil { | |
| 1743 | 1744 | return errors.New("vev: route ledger unavailable") | |
| 1744 | 1745 | } | |
| 1745 | - | snapshotPayload, err := ports.MarshalRecentRouteSnapshot(a.runner.ledger.snapshot()) | |
| 1746 | + | snapshotPayload, err := wire.MarshalRecentRouteSnapshot(a.runner.ledger.snapshot()) | |
| 1746 | 1747 | if err != nil { | |
| 1747 | 1748 | return err | |
| 1748 | 1749 | } | |
| 1749 | - | attentionPayload, err := ports.MarshalRouteAttentionSubscription(a.runner.ledger.attentionSubscription()) | |
| 1750 | + | attentionPayload, err := wire.MarshalRouteAttentionSubscription(a.runner.ledger.attentionSubscription()) | |
| 1750 | 1751 | if err != nil { | |
| 1751 | 1752 | return err | |
| 1752 | 1753 | } | |
| 1753 | - | for _, frame := range []ports.Frame{ | |
| 1754 | - | {Type: ports.MsgRecentRouteSnapshot, Payload: snapshotPayload}, | |
| 1755 | - | {Type: ports.MsgRouteAttentionSubscription, Payload: attentionPayload}, | |
| 1754 | + | for _, frame := range []wire.Frame{ | |
| 1755 | + | {Type: wire.MsgRecentRouteSnapshot, Payload: snapshotPayload}, | |
| 1756 | + | {Type: wire.MsgRouteAttentionSubscription, Payload: attentionPayload}, | |
| 1756 | 1757 | } { | |
| 1757 | 1758 | select { | |
| 1758 | 1759 | case sendCh <- frame: | |
| @@ -1763,7 +1764,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1763 | 1764 | return nil | |
| 1764 | 1765 | } | |
| 1765 | 1766 | sendRouteFailure := func(action protocol.RouteNavigationAction, code protocol.RouteFailureCode) error { | |
| 1766 | - | payload, err := ports.MarshalRouteNavigationFailure(protocol.RouteNavigationFailure{ | |
| 1767 | + | payload, err := wire.MarshalRouteNavigationFailure(protocol.RouteNavigationFailure{ | |
| 1767 | 1768 | Key: action.Key, | |
| 1768 | 1769 | Generation: action.Generation, | |
| 1769 | 1770 | Code: code, | |
| @@ -1772,7 +1773,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1772 | 1773 | return err | |
| 1773 | 1774 | } | |
| 1774 | 1775 | select { | |
| 1775 | - | case sendCh <- ports.Frame{Type: ports.MsgRouteNavigationFailure, Payload: payload}: | |
| 1776 | + | case sendCh <- wire.Frame{Type: wire.MsgRouteNavigationFailure, Payload: payload}: | |
| 1776 | 1777 | return nil | |
| 1777 | 1778 | case <-loopCtx.Done(): | |
| 1778 | 1779 | return context.Canceled | |
| @@ -1827,7 +1828,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1827 | 1828 | return welcomedResult(fmt.Errorf("dismissing reconnect toast: %w", err)) | |
| 1828 | 1829 | } | |
| 1829 | 1830 | select { | |
| 1830 | - | case sendCh <- ports.Frame{Type: ports.MsgClientNotice, Payload: ports.MarshalClientNotice(protocol.ClientNotice{Action: protocol.ClientNoticeLinkConnected})}: | |
| 1831 | + | case sendCh <- wire.Frame{Type: wire.MsgClientNotice, Payload: wire.MarshalClientNotice(protocol.ClientNotice{Action: protocol.ClientNoticeLinkConnected})}: | |
| 1831 | 1832 | case <-loopCtx.Done(): | |
| 1832 | 1833 | return welcomedResult(nil) | |
| 1833 | 1834 | } | |
| @@ -1836,7 +1837,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1836 | 1837 | if ev.State == ports.LinkStateDegraded { | |
| 1837 | 1838 | log.Warn("UDP link degraded") | |
| 1838 | 1839 | select { | |
| 1839 | - | case sendCh <- ports.Frame{Type: ports.MsgClientNotice, Payload: ports.MarshalClientNotice(protocol.ClientNotice{Action: protocol.ClientNoticeLinkDegraded})}: | |
| 1840 | + | case sendCh <- wire.Frame{Type: wire.MsgClientNotice, Payload: wire.MarshalClientNotice(protocol.ClientNotice{Action: protocol.ClientNoticeLinkDegraded})}: | |
| 1840 | 1841 | case <-loopCtx.Done(): | |
| 1841 | 1842 | return welcomedResult(nil) | |
| 1842 | 1843 | } | |
| @@ -1884,8 +1885,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1884 | 1885 | return welcomedResult(fmt.Errorf("vev: receiving from daemon: %w", r.err)) | |
| 1885 | 1886 | } | |
| 1886 | 1887 | switch r.frame.Type { | |
| 1887 | - | case ports.MsgOutput: | |
| 1888 | - | o, derr := ports.UnmarshalOutput(r.frame.Payload) | |
| 1888 | + | case wire.MsgOutput: | |
| 1889 | + | o, derr := wire.UnmarshalOutput(r.frame.Payload) | |
| 1889 | 1890 | if derr != nil { | |
| 1890 | 1891 | return welcomedResult(fmt.Errorf("vev: decoding output: %w", derr)) | |
| 1891 | 1892 | } | |
| @@ -1896,7 +1897,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1896 | 1897 | // repeated gaps while that reset is in flight. | |
| 1897 | 1898 | if !outputResetRequested { | |
| 1898 | 1899 | select { | |
| 1899 | - | case sendCh <- ports.Frame{Type: ports.MsgOutputResetRequest, Payload: ports.MarshalOutputResetRequest(protocol.OutputResetRequest{})}: | |
| 1900 | + | case sendCh <- wire.Frame{Type: wire.MsgOutputResetRequest, Payload: wire.MarshalOutputResetRequest(protocol.OutputResetRequest{})}: | |
| 1900 | 1901 | outputResetRequested = true | |
| 1901 | 1902 | case <-loopCtx.Done(): | |
| 1902 | 1903 | return loopCanceledResult() | |
| @@ -1946,8 +1947,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1946 | 1947 | log.Debug("received first output") | |
| 1947 | 1948 | endHandshake() | |
| 1948 | 1949 | } | |
| 1949 | - | case ports.MsgAttachTarget: | |
| 1950 | - | target, derr := ports.UnmarshalAttachTarget(r.frame.Payload) | |
| 1950 | + | case wire.MsgAttachTarget: | |
| 1951 | + | target, derr := wire.UnmarshalAttachTarget(r.frame.Payload) | |
| 1951 | 1952 | if derr != nil { | |
| 1952 | 1953 | return welcomedResult(fmt.Errorf("vev: decoding attach target: %w", derr)) | |
| 1953 | 1954 | } | |
| @@ -1966,7 +1967,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1966 | 1967 | } | |
| 1967 | 1968 | nextSamePeerRequestID++ | |
| 1968 | 1969 | request := a.runner.ledger.samePeerHandoff(request, target) | |
| 1969 | - | payload, err := ports.MarshalSamePeerSwitchRequest(protocol.SamePeerSwitchRequest{ | |
| 1970 | + | payload, err := wire.MarshalSamePeerSwitchRequest(protocol.SamePeerSwitchRequest{ | |
| 1970 | 1971 | RequestID: nextSamePeerRequestID, | |
| 1971 | 1972 | Target: *target.ExactTarget, | |
| 1972 | 1973 | PreferredTabID: request.PreferredTabID, | |
| @@ -1977,7 +1978,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1977 | 1978 | samePeerSwitch = &samePeerSwitchPending{requestID: nextSamePeerRequestID, target: *target.ExactTarget} | |
| 1978 | 1979 | inputGate.setPaused(true) | |
| 1979 | 1980 | select { | |
| 1980 | - | case controlCh <- ports.Frame{Type: ports.MsgSamePeerSwitchRequest, Payload: payload}: | |
| 1981 | + | case controlCh <- wire.Frame{Type: wire.MsgSamePeerSwitchRequest, Payload: payload}: | |
| 1981 | 1982 | continue | |
| 1982 | 1983 | case <-loopCtx.Done(): | |
| 1983 | 1984 | return loopCanceledResult() | |
| @@ -1986,8 +1987,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 1986 | 1987 | handoff := welcomedResult(nil) | |
| 1987 | 1988 | handoff.target = &target | |
| 1988 | 1989 | return handoff | |
| 1989 | - | case ports.MsgParkedRouteResponse: | |
| 1990 | - | response, derr := ports.UnmarshalParkedRouteResponse(r.frame.Payload) | |
| 1990 | + | case wire.MsgParkedRouteResponse: | |
| 1991 | + | response, derr := wire.UnmarshalParkedRouteResponse(r.frame.Payload) | |
| 1991 | 1992 | if derr != nil { | |
| 1992 | 1993 | return welcomedResult(fmt.Errorf("vev: decoding parked-route response: %w", derr)) | |
| 1993 | 1994 | } | |
| @@ -2033,8 +2034,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 2033 | 2034 | return fallback | |
| 2034 | 2035 | } | |
| 2035 | 2036 | } | |
| 2036 | - | case ports.MsgNavigationAction: | |
| 2037 | - | directive, derr := ports.UnmarshalNavigationDirective(r.frame.Payload) | |
| 2037 | + | case wire.MsgNavigationAction: | |
| 2038 | + | directive, derr := wire.UnmarshalNavigationDirective(r.frame.Payload) | |
| 2038 | 2039 | if derr != nil { | |
| 2039 | 2040 | return welcomedResult(fmt.Errorf("vev: decoding navigation action: %w", derr)) | |
| 2040 | 2041 | } | |
| @@ -2052,8 +2053,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 2052 | 2053 | navigation := welcomedResult(nil) | |
| 2053 | 2054 | navigation.action = directive.Action | |
| 2054 | 2055 | return navigation | |
| 2055 | - | case ports.MsgNavigateRecentRoute: | |
| 2056 | - | action, derr := ports.UnmarshalRouteNavigationAction(r.frame.Payload) | |
| 2056 | + | case wire.MsgNavigateRecentRoute: | |
| 2057 | + | action, derr := wire.UnmarshalRouteNavigationAction(r.frame.Payload) | |
| 2057 | 2058 | if derr != nil { | |
| 2058 | 2059 | return welcomedResult(fmt.Errorf("vev: decoding route navigation action: %w", derr)) | |
| 2059 | 2060 | } | |
| @@ -2076,8 +2077,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 2076 | 2077 | navigation := welcomedResult(nil) | |
| 2077 | 2078 | navigation.routeAction = &action | |
| 2078 | 2079 | return navigation | |
| 2079 | - | case ports.MsgCommittedRouteIdentity: | |
| 2080 | - | identity, derr := ports.UnmarshalCommittedRouteIdentity(r.frame.Payload) | |
| 2080 | + | case wire.MsgCommittedRouteIdentity: | |
| 2081 | + | identity, derr := wire.UnmarshalCommittedRouteIdentity(r.frame.Payload) | |
| 2081 | 2082 | if derr != nil { | |
| 2082 | 2083 | return welcomedResult(fmt.Errorf("vev: decoding committed route identity: %w", derr)) | |
| 2083 | 2084 | } | |
| @@ -2099,8 +2100,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 2099 | 2100 | samePeerSwitch = nil | |
| 2100 | 2101 | inputGate.setPaused(false) | |
| 2101 | 2102 | } | |
| 2102 | - | case ports.MsgSamePeerSwitchFailure: | |
| 2103 | - | failure, derr := ports.UnmarshalSamePeerSwitchFailure(r.frame.Payload) | |
| 2103 | + | case wire.MsgSamePeerSwitchFailure: | |
| 2104 | + | failure, derr := wire.UnmarshalSamePeerSwitchFailure(r.frame.Payload) | |
| 2104 | 2105 | if derr != nil { | |
| 2105 | 2106 | return welcomedResult(fmt.Errorf("vev: decoding same-peer switch failure: %w", derr)) | |
| 2106 | 2107 | } | |
| @@ -2111,7 +2112,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 2111 | 2112 | transitionWaitingFull = true | |
| 2112 | 2113 | if !outputResetRequested { | |
| 2113 | 2114 | select { | |
| 2114 | - | case sendCh <- ports.Frame{Type: ports.MsgOutputResetRequest, Payload: ports.MarshalOutputResetRequest(protocol.OutputResetRequest{})}: | |
| 2115 | + | case sendCh <- wire.Frame{Type: wire.MsgOutputResetRequest, Payload: wire.MarshalOutputResetRequest(protocol.OutputResetRequest{})}: | |
| 2115 | 2116 | outputResetRequested = true | |
| 2116 | 2117 | case <-loopCtx.Done(): | |
| 2117 | 2118 | return loopCanceledResult() | |
| @@ -2121,8 +2122,8 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 2121 | 2122 | transition.stop() | |
| 2122 | 2123 | } | |
| 2123 | 2124 | } | |
| 2124 | - | case ports.MsgRoutePosition: | |
| 2125 | - | position, derr := ports.UnmarshalRoutePosition(r.frame.Payload) | |
| 2125 | + | case wire.MsgRoutePosition: | |
| 2126 | + | position, derr := wire.UnmarshalRoutePosition(r.frame.Payload) | |
| 2126 | 2127 | if derr != nil { | |
| 2127 | 2128 | return welcomedResult(fmt.Errorf("vev: decoding route position: %w", derr)) | |
| 2128 | 2129 | } | |
| @@ -2133,14 +2134,14 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 2133 | 2134 | return welcomedResult(fmt.Errorf("vev: remembering route position: %w", derr)) | |
| 2134 | 2135 | } | |
| 2135 | 2136 | routePosition = cloneRoutePosition(&position) | |
| 2136 | - | case ports.MsgRouteNavigationFailure: | |
| 2137 | - | failure, derr := ports.UnmarshalRouteNavigationFailure(r.frame.Payload) | |
| 2137 | + | case wire.MsgRouteNavigationFailure: | |
| 2138 | + | failure, derr := wire.UnmarshalRouteNavigationFailure(r.frame.Payload) | |
| 2138 | 2139 | if derr != nil { | |
| 2139 | 2140 | return welcomedResult(fmt.Errorf("vev: decoding route navigation failure: %w", derr)) | |
| 2140 | 2141 | } | |
| 2141 | 2142 | log.Warn("route navigation rejected", "key", failure.Key, "generation", failure.Generation, "code", failure.Code) | |
| 2142 | - | case ports.MsgDetached: | |
| 2143 | - | d, derr := ports.UnmarshalDetached(r.frame.Payload) | |
| 2143 | + | case wire.MsgDetached: | |
| 2144 | + | d, derr := wire.UnmarshalDetached(r.frame.Payload) | |
| 2144 | 2145 | if derr != nil { | |
| 2145 | 2146 | return welcomedResult(fmt.Errorf("vev: decoding detached: %w", derr)) | |
| 2146 | 2147 | } | |
| @@ -2151,7 +2152,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 2151 | 2152 | log.Warn("detached by daemon", "reason", d.Reason) | |
| 2152 | 2153 | } | |
| 2153 | 2154 | return welcomedResult(detachedResult(d.Reason)) | |
| 2154 | - | case ports.MsgPong: | |
| 2155 | + | case wire.MsgPong: | |
| 2155 | 2156 | // Liveness reply; nothing to do. | |
| 2156 | 2157 | default: | |
| 2157 | 2158 | // Unknown/out-of-band message types are ignored so a newer | |
| @@ -2164,7 +2165,7 @@ func (a *attachAttempt) run(ctx context.Context) attachResult { | |||
| 2164 | 2165 | // recvResult carries one framed message (or a read error) from the receive | |
| 2165 | 2166 | // pump to the main loop. | |
| 2166 | 2167 | type recvResult struct { | |
| 2167 | - | frame ports.Frame | |
| 2168 | + | frame wire.Frame | |
| 2168 | 2169 | err error | |
| 2169 | 2170 | } | |
| 2170 | 2171 | ||
| @@ -2227,9 +2228,9 @@ func (q *cumulativeAckQueue) take() (uint64, uint64) { | |||
| 2227 | 2228 | ||
| 2228 | 2229 | // runSender preserves normal-frame order while allowing switch control and | |
| 2229 | 2230 | // output ACKs to make progress when raw input is held for a same-peer switch. | |
| 2230 | - | func runSender(ctx context.Context, cancel context.CancelFunc, transport ports.Transport, control <-chan ports.Frame, barriers <-chan chan struct{}, in <-chan ports.Frame, inputGate *samePeerInputGate, acks *cumulativeAckQueue, errCh chan<- error, log *slog.Logger) { | |
| 2231 | + | func runSender(ctx context.Context, cancel context.CancelFunc, transport ports.Transport, control <-chan wire.Frame, barriers <-chan chan struct{}, in <-chan wire.Frame, inputGate *samePeerInputGate, acks *cumulativeAckQueue, errCh chan<- error, log *slog.Logger) { | |
| 2231 | 2232 | defer log.Debug("sender pump exited") | |
| 2232 | - | send := func(f ports.Frame) bool { | |
| 2233 | + | send := func(f wire.Frame) bool { | |
| 2233 | 2234 | if err := transport.Send(f); err != nil { | |
| 2234 | 2235 | select { | |
| 2235 | 2236 | case errCh <- err: | |
| @@ -2245,7 +2246,7 @@ func runSender(ctx context.Context, cancel context.CancelFunc, transport ports.T | |||
| 2245 | 2246 | if state == 0 { | |
| 2246 | 2247 | return true | |
| 2247 | 2248 | } | |
| 2248 | - | payload, err := ports.MarshalAck(protocol.Ack{Epoch: epoch, State: state}) | |
| 2249 | + | payload, err := wire.MarshalAck(protocol.Ack{Epoch: epoch, State: state}) | |
| 2249 | 2250 | if err != nil { | |
| 2250 | 2251 | select { | |
| 2251 | 2252 | case errCh <- fmt.Errorf("encoding output ACK: %w", err): | |
| @@ -2254,7 +2255,7 @@ func runSender(ctx context.Context, cancel context.CancelFunc, transport ports.T | |||
| 2254 | 2255 | cancel() | |
| 2255 | 2256 | return false | |
| 2256 | 2257 | } | |
| 2257 | - | return send(ports.Frame{Type: ports.MsgAck, Payload: payload}) | |
| 2258 | + | return send(wire.Frame{Type: wire.MsgAck, Payload: payload}) | |
| 2258 | 2259 | } | |
| 2259 | 2260 | flushPending := func() bool { | |
| 2260 | 2261 | for { | |
| @@ -2286,7 +2287,7 @@ func runSender(ctx context.Context, cancel context.CancelFunc, transport ports.T | |||
| 2286 | 2287 | close(done) | |
| 2287 | 2288 | return true | |
| 2288 | 2289 | } | |
| 2289 | - | var heldInput *ports.Frame | |
| 2290 | + | var heldInput *wire.Frame | |
| 2290 | 2291 | for { | |
| 2291 | 2292 | if heldInput != nil { | |
| 2292 | 2293 | paused, changed := inputGate.snapshot() | |
| @@ -2353,7 +2354,7 @@ func runSender(ctx context.Context, cancel context.CancelFunc, transport ports.T | |||
| 2353 | 2354 | return | |
| 2354 | 2355 | default: | |
| 2355 | 2356 | } | |
| 2356 | - | if frame.Type == ports.MsgInput || frame.Type == ports.MsgImagePush { | |
| 2357 | + | if frame.Type == wire.MsgInput || frame.Type == wire.MsgImagePush { | |
| 2357 | 2358 | if paused, _ := inputGate.snapshot(); paused { | |
| 2358 | 2359 | held := frame | |
| 2359 | 2360 | heldInput = &held | |
| @@ -2725,7 +2726,7 @@ type stdinPump struct { | |||
| 2725 | 2726 | in io.Reader // compatibility for isolated scanner tests | |
| 2726 | 2727 | input *terminalInputPump | |
| 2727 | 2728 | consumer uint64 | |
| 2728 | - | out chan<- ports.Frame | |
| 2729 | + | out chan<- wire.Frame | |
| 2729 | 2730 | clock ports.Clock | |
| 2730 | 2731 | clipboard ports.ClipboardReader | |
| 2731 | 2732 | logger *slog.Logger | |
| @@ -2746,7 +2747,7 @@ func (p *stdinPump) run() { | |||
| 2746 | 2747 | var undeliveredMu sync.Mutex | |
| 2747 | 2748 | var undelivered []byte | |
| 2748 | 2749 | sendOK.Store(true) | |
| 2749 | - | send := func(frame ports.Frame) bool { | |
| 2750 | + | send := func(frame wire.Frame) bool { | |
| 2750 | 2751 | if !sendOK.Load() { | |
| 2751 | 2752 | return false | |
| 2752 | 2753 | } | |
| @@ -2785,7 +2786,7 @@ func (p *stdinPump) run() { | |||
| 2785 | 2786 | return | |
| 2786 | 2787 | } | |
| 2787 | 2788 | inputSeq++ | |
| 2788 | - | if !send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{InputSeq: inputSeq, Data: append([]byte(nil), data...)})}) { | |
| 2789 | + | if !send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{InputSeq: inputSeq, Data: append([]byte(nil), data...)})}) { | |
| 2789 | 2790 | undeliveredMu.Lock() | |
| 2790 | 2791 | undelivered = append(undelivered, data...) | |
| 2791 | 2792 | undeliveredMu.Unlock() | |
| @@ -2799,11 +2800,11 @@ func (p *stdinPump) run() { | |||
| 2799 | 2800 | reader: p.clipboard, | |
| 2800 | 2801 | log: p.logger, | |
| 2801 | 2802 | sendNotice: func(action uint8) { | |
| 2802 | - | send(ports.Frame{Type: ports.MsgClientNotice, Payload: ports.MarshalClientNotice(protocol.ClientNotice{Action: action})}) | |
| 2803 | + | send(wire.Frame{Type: wire.MsgClientNotice, Payload: wire.MarshalClientNotice(protocol.ClientNotice{Action: action})}) | |
| 2803 | 2804 | }, | |
| 2804 | 2805 | sendImage: func(mime string, data []byte) { | |
| 2805 | 2806 | inputSeq++ | |
| 2806 | - | send(ports.Frame{Type: ports.MsgImagePush, Payload: ports.MarshalImagePush(protocol.ImagePush{InputSeq: inputSeq, Mime: mime, Data: data})}) | |
| 2807 | + | send(wire.Frame{Type: wire.MsgImagePush, Payload: wire.MarshalImagePush(protocol.ImagePush{InputSeq: inputSeq, Mime: mime, Data: data})}) | |
| 2807 | 2808 | }, | |
| 2808 | 2809 | next: coalescer.Scan, | |
| 2809 | 2810 | } | |
| @@ -2945,7 +2946,7 @@ func (p *stdinPump) run() { | |||
| 2945 | 2946 | disarmMarkerDeadline() | |
| 2946 | 2947 | markers.flush(sink) | |
| 2947 | 2948 | select { | |
| 2948 | - | case p.out <- ports.Frame{Type: ports.MsgDetach, Payload: ports.MarshalDetach(protocol.Detach{})}: | |
| 2949 | + | case p.out <- wire.Frame{Type: wire.MsgDetach, Payload: wire.MarshalDetach(protocol.Detach{})}: | |
| 2949 | 2950 | case <-p.ctx.Done(): | |
| 2950 | 2951 | } | |
| 2951 | 2952 | p.cancel() | |
| @@ -2966,7 +2967,7 @@ func (p *stdinPump) run() { | |||
| 2966 | 2967 | // runResize forwards coalesced terminal resize events to the daemon. It | |
| 2967 | 2968 | // tolerates an already-closed resize channel (which the terminal adapter | |
| 2968 | 2969 | // hands back when restore ran before ResizeEvents was first called). | |
| 2969 | - | func runResize(ctx context.Context, events <-chan domain.Geometry, out chan<- ports.Frame, sendLease *foregroundSendLease, log *slog.Logger) { | |
| 2970 | + | func runResize(ctx context.Context, events <-chan domain.Geometry, out chan<- wire.Frame, sendLease *foregroundSendLease, log *slog.Logger) { | |
| 2970 | 2971 | defer log.Debug("resize pump exited") | |
| 2971 | 2972 | for { | |
| 2972 | 2973 | select { | |
| @@ -2975,12 +2976,12 @@ func runResize(ctx context.Context, events <-chan domain.Geometry, out chan<- po | |||
| 2975 | 2976 | return | |
| 2976 | 2977 | } | |
| 2977 | 2978 | geometry = geometry.NormalizePixels() | |
| 2978 | - | payload, err := ports.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) | |
| 2979 | + | payload, err := wire.MarshalResize(protocol.Resize{Size: geometry.Size, PixelWidth: geometry.PixelWidth, PixelHeight: geometry.PixelHeight}) | |
| 2979 | 2980 | if err != nil { | |
| 2980 | 2981 | log.Error("encoding terminal resize", "error", err) | |
| 2981 | 2982 | continue | |
| 2982 | 2983 | } | |
| 2983 | - | frame := ports.Frame{Type: ports.MsgResize, Payload: payload} | |
| 2984 | + | frame := wire.Frame{Type: wire.MsgResize, Payload: payload} | |
| 2984 | 2985 | if !sendLease.send(func() bool { | |
| 2985 | 2986 | select { | |
| 2986 | 2987 | case out <- frame: | |
M internal/usecase/client/client_test.go +198 -197
| @@ -19,6 +19,7 @@ import ( | |||
| 19 | 19 | "github.com/bnema/vev/internal/ports" | |
| 20 | 20 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 21 | 21 | "github.com/bnema/vev/internal/protocol" | |
| 22 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 22 | 23 | "github.com/bnema/vev/internal/usecase/client" | |
| 23 | 24 | ) | |
| 24 | 25 | ||
| @@ -117,7 +118,7 @@ func (t *reconnectTestTimer) Stop() bool { | |||
| 117 | 118 | ||
| 118 | 119 | // recvItem is one scripted Recv result. | |
| 119 | 120 | type recvItem struct { | |
| 120 | - | f ports.Frame | |
| 121 | + | f wire.Frame | |
| 121 | 122 | err error | |
| 122 | 123 | wait <-chan struct{} | |
| 123 | 124 | } | |
| @@ -135,26 +136,26 @@ func scriptRecv(tr *portsmocks.MockTransport, items ...recvItem) func() { | |||
| 135 | 136 | ch <- it | |
| 136 | 137 | } | |
| 137 | 138 | done := make(chan struct{}) | |
| 138 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | |
| 139 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { | |
| 139 | 140 | select { | |
| 140 | 141 | case it := <-ch: | |
| 141 | 142 | if it.wait != nil { | |
| 142 | 143 | select { | |
| 143 | 144 | case <-it.wait: | |
| 144 | 145 | case <-done: | |
| 145 | - | return ports.Frame{}, io.EOF | |
| 146 | + | return wire.Frame{}, io.EOF | |
| 146 | 147 | } | |
| 147 | 148 | } | |
| 148 | 149 | return it.f, it.err | |
| 149 | 150 | case <-done: | |
| 150 | - | return ports.Frame{}, io.EOF | |
| 151 | + | return wire.Frame{}, io.EOF | |
| 151 | 152 | } | |
| 152 | 153 | }).Maybe() | |
| 153 | 154 | return func() { close(done) } | |
| 154 | 155 | } | |
| 155 | 156 | ||
| 156 | - | func frameOf(t ports.MsgType, payload []byte) ports.Frame { | |
| 157 | - | return ports.Frame{Type: t, Payload: payload} | |
| 157 | + | func frameOf(t wire.MsgType, payload []byte) wire.Frame { | |
| 158 | + | return wire.Frame{Type: t, Payload: payload} | |
| 158 | 159 | } | |
| 159 | 160 | ||
| 160 | 161 | // blockingReader blocks on Read until closed, then returns EOF. Stands in | |
| @@ -234,8 +235,8 @@ func newHappyTerminal(t *testing.T, out *bytes.Buffer, restoreCount *atomic.Int3 | |||
| 234 | 235 | return tm, in | |
| 235 | 236 | } | |
| 236 | 237 | ||
| 237 | - | func isType(typ ports.MsgType) any { | |
| 238 | - | return mock.MatchedBy(func(f ports.Frame) bool { return f.Type == typ }) | |
| 238 | + | func isType(typ wire.MsgType) any { | |
| 239 | + | return mock.MatchedBy(func(f wire.Frame) bool { return f.Type == typ }) | |
| 239 | 240 | } | |
| 240 | 241 | ||
| 241 | 242 | // transportDialer adapts one already-open test transport to the Runner API. | |
| @@ -339,13 +340,13 @@ func TestRunBoundsPreWelcomeOperations(t *testing.T) { | |||
| 339 | 340 | return io.ErrClosedPipe | |
| 340 | 341 | } | |
| 341 | 342 | if tt.phase == "send" { | |
| 342 | - | tr.EXPECT().Send(isType(ports.MsgHello)).RunAndReturn(func(ports.Frame) error { | |
| 343 | + | tr.EXPECT().Send(isType(wire.MsgHello)).RunAndReturn(func(wire.Frame) error { | |
| 343 | 344 | return block() | |
| 344 | 345 | }).Once() | |
| 345 | 346 | } else { | |
| 346 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 347 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | |
| 348 | - | return ports.Frame{}, block() | |
| 347 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 348 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { | |
| 349 | + | return wire.Frame{}, block() | |
| 349 | 350 | }).Once() | |
| 350 | 351 | } | |
| 351 | 352 | dialer := portsmocks.NewMockDialer(t) | |
| @@ -384,7 +385,7 @@ func TestRunBoundsPreWelcomeOperations(t *testing.T) { | |||
| 384 | 385 | case <-time.After(time.Second): | |
| 385 | 386 | t.Fatal("handshake operation leaked after Run returned") | |
| 386 | 387 | } | |
| 387 | - | tr.AssertNotCalled(t, "Send", isType(ports.MsgTheme)) | |
| 388 | + | tr.AssertNotCalled(t, "Send", isType(wire.MsgTheme)) | |
| 388 | 389 | }) | |
| 389 | 390 | } | |
| 390 | 391 | } | |
| @@ -401,17 +402,17 @@ func TestAttachHelloIncludesTrueColor(t *testing.T) { | |||
| 401 | 402 | ||
| 402 | 403 | gotHello := make(chan protocol.Hello, 1) | |
| 403 | 404 | tr := portsmocks.NewMockTransport(t) | |
| 404 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 405 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 406 | - | tr.EXPECT().Send(isType(ports.MsgHello)).RunAndReturn(func(f ports.Frame) error { | |
| 407 | - | hello, err := ports.UnmarshalHello(f.Payload) | |
| 405 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 406 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 407 | + | tr.EXPECT().Send(isType(wire.MsgHello)).RunAndReturn(func(f wire.Frame) error { | |
| 408 | + | hello, err := wire.UnmarshalHello(f.Payload) | |
| 408 | 409 | require.NoError(t, err) | |
| 409 | 410 | gotHello <- hello | |
| 410 | 411 | return nil | |
| 411 | 412 | }).Once() | |
| 412 | 413 | unblock := scriptRecv(tr, | |
| 413 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 414 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 414 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 415 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 415 | 416 | ) | |
| 416 | 417 | defer unblock() | |
| 417 | 418 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -434,14 +435,14 @@ func TestAttachPublishesCommittedRouteSnapshot(t *testing.T) { | |||
| 434 | 435 | defer term.in.unblock() | |
| 435 | 436 | lifecycle := domain.SessionLifecycleID{9, 8, 7} | |
| 436 | 437 | tr := &recordingTransport{recvs: []recvItem{ | |
| 437 | - | {f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | |
| 438 | + | {f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ | |
| 438 | 439 | SessionID: "s1", | |
| 439 | 440 | SessionName: "main", | |
| 440 | 441 | CommittedIdentity: &protocol.CommittedRouteIdentity{ | |
| 441 | 442 | Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "main"}, | |
| 442 | 443 | }, | |
| 443 | 444 | }))}, | |
| 444 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 445 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 445 | 446 | }} | |
| 446 | 447 | ||
| 447 | 448 | err := runTestClient(context.Background(), attachTestDependencies(tr, term, realClock{}), client.AttachRequest{ | |
| @@ -458,14 +459,14 @@ func TestAttachPublishesCommittedRouteSnapshot(t *testing.T) { | |||
| 458 | 459 | foundSubscription := false | |
| 459 | 460 | for _, frame := range tr.Sends() { | |
| 460 | 461 | switch frame.Type { | |
| 461 | - | case ports.MsgRecentRouteSnapshot: | |
| 462 | + | case wire.MsgRecentRouteSnapshot: | |
| 462 | 463 | var err error | |
| 463 | - | snapshot, err = ports.UnmarshalRecentRouteSnapshot(frame.Payload) | |
| 464 | + | snapshot, err = wire.UnmarshalRecentRouteSnapshot(frame.Payload) | |
| 464 | 465 | require.NoError(t, err) | |
| 465 | 466 | foundSnapshot = true | |
| 466 | - | case ports.MsgRouteAttentionSubscription: | |
| 467 | + | case wire.MsgRouteAttentionSubscription: | |
| 467 | 468 | var err error | |
| 468 | - | subscription, err = ports.UnmarshalRouteAttentionSubscription(frame.Payload) | |
| 469 | + | subscription, err = wire.UnmarshalRouteAttentionSubscription(frame.Payload) | |
| 469 | 470 | require.NoError(t, err) | |
| 470 | 471 | foundSubscription = true | |
| 471 | 472 | } | |
| @@ -484,8 +485,8 @@ func TestLocalOnlyHandoffBetweenLocalSessionsKeepsClientRunning(t *testing.T) { | |||
| 484 | 485 | ||
| 485 | 486 | firstLifecycle := domain.SessionLifecycleID{1} | |
| 486 | 487 | secondLifecycle := domain.SessionLifecycleID{2} | |
| 487 | - | welcome := func(name string, lifecycle domain.SessionLifecycleID) ports.Frame { | |
| 488 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | |
| 488 | + | welcome := func(name string, lifecycle domain.SessionLifecycleID) wire.Frame { | |
| 489 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ | |
| 489 | 490 | SessionID: name, SessionName: name, ResumeToken: 1, Capabilities: protocol.CapabilityResume, | |
| 490 | 491 | CommittedIdentity: &protocol.CommittedRouteIdentity{ | |
| 491 | 492 | Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}, | |
| @@ -495,12 +496,12 @@ func TestLocalOnlyHandoffBetweenLocalSessionsKeepsClientRunning(t *testing.T) { | |||
| 495 | 496 | secondTarget := protocol.ExactSessionTarget{LifecycleID: secondLifecycle, SessionName: "second"} | |
| 496 | 497 | first := &recordingTransport{recvs: []recvItem{ | |
| 497 | 498 | {f: welcome("first", firstLifecycle)}, | |
| 498 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | |
| 499 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ | |
| 499 | 500 | Session: "second", Intent: protocol.IntentAttach, ExactTarget: &secondTarget, | |
| 500 | 501 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, SamePeer: true, | |
| 501 | 502 | }))}, | |
| 502 | - | {f: frameOf(ports.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{Target: secondTarget}))}, | |
| 503 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 503 | + | {f: frameOf(wire.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{Target: secondTarget}))}, | |
| 504 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 504 | 505 | }} | |
| 505 | 506 | dialer := &sequenceDialer{trs: []ports.Transport{first}} | |
| 506 | 507 | ||
| @@ -530,7 +531,7 @@ func TestAttachHelloPreservesCompleteAttachRequest(t *testing.T) { | |||
| 530 | 531 | } | |
| 531 | 532 | tr := &recordingTransport{recvs: []recvItem{ | |
| 532 | 533 | {f: welcomeFrame(0)}, | |
| 533 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 534 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 534 | 535 | }} | |
| 535 | 536 | ||
| 536 | 537 | require.NoError(t, runTestClient(context.Background(), attachTestDependencies(tr, term, realClock{}), request)) | |
| @@ -550,8 +551,8 @@ func TestStoppedLocalHandoffDialsReplacementTransport(t *testing.T) { | |||
| 550 | 551 | sourceLifecycle := domain.SessionLifecycleID{1} | |
| 551 | 552 | targetLifecycle := domain.SessionLifecycleID{2} | |
| 552 | 553 | target := protocol.ExactSessionTarget{LifecycleID: targetLifecycle, SessionName: "stopped"} | |
| 553 | - | welcome := func(name string, lifecycle domain.SessionLifecycleID) ports.Frame { | |
| 554 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | |
| 554 | + | welcome := func(name string, lifecycle domain.SessionLifecycleID) wire.Frame { | |
| 555 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ | |
| 555 | 556 | SessionID: name, SessionName: name, ResumeToken: 1, Capabilities: protocol.CapabilityResume, | |
| 556 | 557 | CommittedIdentity: &protocol.CommittedRouteIdentity{ | |
| 557 | 558 | Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}, | |
| @@ -560,14 +561,14 @@ func TestStoppedLocalHandoffDialsReplacementTransport(t *testing.T) { | |||
| 560 | 561 | } | |
| 561 | 562 | first := &recordingTransport{recvs: []recvItem{ | |
| 562 | 563 | {f: welcome("source", sourceLifecycle)}, | |
| 563 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | |
| 564 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ | |
| 564 | 565 | Session: "stopped", Intent: protocol.IntentAttach, ExactTarget: &target, | |
| 565 | 566 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | |
| 566 | 567 | }))}, | |
| 567 | 568 | }} | |
| 568 | 569 | second := &recordingTransport{recvs: []recvItem{ | |
| 569 | 570 | {f: welcome("stopped", targetLifecycle)}, | |
| 570 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 571 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 571 | 572 | }} | |
| 572 | 573 | dialer := &sequenceDialer{trs: []ports.Transport{first, second}} | |
| 573 | 574 | ||
| @@ -587,8 +588,8 @@ func TestAcceptedHomeActionUsesCapturedRouteAfterRequestMetadataRebase(t *testin | |||
| 587 | 588 | defer term.in.unblock() | |
| 588 | 589 | localLifecycle := domain.SessionLifecycleID{1} | |
| 589 | 590 | remoteLifecycle := domain.SessionLifecycleID{2} | |
| 590 | - | welcome := func(name string, lifecycle domain.SessionLifecycleID) ports.Frame { | |
| 591 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | |
| 591 | + | welcome := func(name string, lifecycle domain.SessionLifecycleID) wire.Frame { | |
| 592 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ | |
| 592 | 593 | SessionID: name, SessionName: name, ResumeToken: 1, Capabilities: protocol.CapabilityResume, | |
| 593 | 594 | CommittedIdentity: &protocol.CommittedRouteIdentity{Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}}, | |
| 594 | 595 | })) | |
| @@ -599,7 +600,7 @@ func TestAcceptedHomeActionUsesCapturedRouteAfterRequestMetadataRebase(t *testin | |||
| 599 | 600 | } | |
| 600 | 601 | local1 := &recordingTransport{recvs: []recvItem{ | |
| 601 | 602 | {f: welcome("local", localLifecycle)}, | |
| 602 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | |
| 603 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ | |
| 603 | 604 | Endpoint: "remote", Session: "work", Intent: protocol.IntentAttach, | |
| 604 | 605 | RemoteTarget: &remoteTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | |
| 605 | 606 | }))}, | |
| @@ -610,7 +611,7 @@ func TestAcceptedHomeActionUsesCapturedRouteAfterRequestMetadataRebase(t *testin | |||
| 610 | 611 | }} | |
| 611 | 612 | local2 := &recordingTransport{recvs: []recvItem{ | |
| 612 | 613 | {f: welcome("local", localLifecycle)}, | |
| 613 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 614 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 614 | 615 | }} | |
| 615 | 616 | localDialer := &sequenceDialer{trs: []ports.Transport{local1, local2}} | |
| 616 | 617 | remoteDialer := &sequenceDialer{trs: []ports.Transport{remote}} | |
| @@ -632,8 +633,8 @@ func TestAcceptedHomeActionUsesCapturedRouteAfterRequestMetadataRebase(t *testin | |||
| 632 | 633 | require.Equal(t, protocol.StartupOverlaySessionPicker, helloFromSend(t, local2).StartupOverlay) | |
| 633 | 634 | } | |
| 634 | 635 | ||
| 635 | - | func hybridWelcomeFrame(name string, lifecycle domain.SessionLifecycleID) ports.Frame { | |
| 636 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | |
| 636 | + | func hybridWelcomeFrame(name string, lifecycle domain.SessionLifecycleID) wire.Frame { | |
| 637 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ | |
| 637 | 638 | SessionID: name, SessionName: name, ResumeToken: 1, Capabilities: protocol.CapabilityResume, | |
| 638 | 639 | CommittedIdentity: &protocol.CommittedRouteIdentity{Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}}, | |
| 639 | 640 | })) | |
| @@ -642,7 +643,7 @@ func hybridWelcomeFrame(name string, lifecycle domain.SessionLifecycleID) ports. | |||
| 642 | 643 | func hybridLocalBootstrap(lifecycle domain.SessionLifecycleID, target domain.RemoteSessionTarget) *recordingTransport { | |
| 643 | 644 | return &recordingTransport{recvs: []recvItem{ | |
| 644 | 645 | {f: hybridWelcomeFrame("local", lifecycle)}, | |
| 645 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | |
| 646 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ | |
| 646 | 647 | Endpoint: target.Endpoint, Session: target.SessionName, Intent: protocol.IntentAttach, | |
| 647 | 648 | RemoteTarget: &target, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | |
| 648 | 649 | }))}, | |
| @@ -669,16 +670,16 @@ func hybridPickerDependencies(localDialer ports.Dialer, term ports.Terminal, clo | |||
| 669 | 670 | return deps | |
| 670 | 671 | } | |
| 671 | 672 | ||
| 672 | - | func hybridParkedRequestHandler(requests chan<- protocol.ParkedRouteRequest, requestErrors chan<- error, signals map[protocol.ParkedRouteAction]chan struct{}) func(ports.Frame) { | |
| 673 | + | func hybridParkedRequestHandler(requests chan<- protocol.ParkedRouteRequest, requestErrors chan<- error, signals map[protocol.ParkedRouteAction]chan struct{}) func(wire.Frame) { | |
| 673 | 674 | once := make(map[protocol.ParkedRouteAction]*sync.Once, len(signals)) | |
| 674 | 675 | for action := range signals { | |
| 675 | 676 | once[action] = &sync.Once{} | |
| 676 | 677 | } | |
| 677 | - | return func(frame ports.Frame) { | |
| 678 | - | if frame.Type != ports.MsgParkedRouteRequest { | |
| 678 | + | return func(frame wire.Frame) { | |
| 679 | + | if frame.Type != wire.MsgParkedRouteRequest { | |
| 679 | 680 | return | |
| 680 | 681 | } | |
| 681 | - | request, err := ports.UnmarshalParkedRouteRequest(frame.Payload) | |
| 682 | + | request, err := wire.UnmarshalParkedRouteRequest(frame.Payload) | |
| 682 | 683 | if err != nil { | |
| 683 | 684 | if requestErrors != nil { | |
| 684 | 685 | requestErrors <- err | |
| @@ -717,11 +718,11 @@ func TestHybridPickerSameHostSwitchReusesRemoteTransport(t *testing.T) { | |||
| 717 | 718 | remote := &recordingTransport{recvs: []recvItem{ | |
| 718 | 719 | {f: hybridWelcomeFrame("source", remoteSourceLifecycle)}, | |
| 719 | 720 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | |
| 720 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: parkSent}, | |
| 721 | - | {f: frameOf(ports.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{Target: protocol.ExactSessionTarget{LifecycleID: remoteTargetLifecycle, SessionName: "target"}})), wait: switchSent}, | |
| 722 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteSwitched}))}, | |
| 723 | - | {f: frameOf(ports.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 2, New: 1, Size: domain.Size{Cols: 80, Rows: 24}, Full: true, Data: []byte("target frame")}))}, | |
| 724 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 721 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: parkSent}, | |
| 722 | + | {f: frameOf(wire.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{Target: protocol.ExactSessionTarget{LifecycleID: remoteTargetLifecycle, SessionName: "target"}})), wait: switchSent}, | |
| 723 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteSwitched}))}, | |
| 724 | + | {f: frameOf(wire.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 2, New: 1, Size: domain.Size{Cols: 80, Rows: 24}, Full: true, Data: []byte("target frame")}))}, | |
| 725 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 725 | 726 | }} | |
| 726 | 727 | remote.onSend = hybridParkedRequestHandler(parkedRequests, parkedRequestErrors, map[protocol.ParkedRouteAction]chan struct{}{ | |
| 727 | 728 | protocol.ParkedRoutePrepare: parkSent, | |
| @@ -729,14 +730,14 @@ func TestHybridPickerSameHostSwitchReusesRemoteTransport(t *testing.T) { | |||
| 729 | 730 | }) | |
| 730 | 731 | localPicker := &recordingTransport{recvs: []recvItem{ | |
| 731 | 732 | {f: hybridWelcomeFrame("local", localLifecycle)}, | |
| 732 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | |
| 733 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ | |
| 733 | 734 | Endpoint: "remote", Session: "target", Intent: protocol.IntentAttach, | |
| 734 | 735 | RemoteTarget: &targetTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | |
| 735 | 736 | }))}, | |
| 736 | 737 | }} | |
| 737 | 738 | var resizeOnce sync.Once | |
| 738 | - | localPicker.onSend = func(frame ports.Frame) { | |
| 739 | - | if frame.Type == ports.MsgHello { | |
| 739 | + | localPicker.onSend = func(frame wire.Frame) { | |
| 740 | + | if frame.Type == wire.MsgHello { | |
| 740 | 741 | resizeOnce.Do(func() { term.setSize(domain.Size{Cols: 100, Rows: 40}) }) | |
| 741 | 742 | } | |
| 742 | 743 | } | |
| @@ -763,10 +764,10 @@ func TestHybridPickerSameHostSwitchReusesRemoteTransport(t *testing.T) { | |||
| 763 | 764 | frames := remote.Sends() | |
| 764 | 765 | switchIndex := -1 | |
| 765 | 766 | for i, frame := range frames { | |
| 766 | - | if frame.Type != ports.MsgParkedRouteRequest { | |
| 767 | + | if frame.Type != wire.MsgParkedRouteRequest { | |
| 767 | 768 | continue | |
| 768 | 769 | } | |
| 769 | - | request, requestErr := ports.UnmarshalParkedRouteRequest(frame.Payload) | |
| 770 | + | request, requestErr := wire.UnmarshalParkedRouteRequest(frame.Payload) | |
| 770 | 771 | require.NoError(t, requestErr) | |
| 771 | 772 | if request.Action == protocol.ParkedRouteSwitch { | |
| 772 | 773 | switchIndex = i | |
| @@ -774,8 +775,8 @@ func TestHybridPickerSameHostSwitchReusesRemoteTransport(t *testing.T) { | |||
| 774 | 775 | } | |
| 775 | 776 | } | |
| 776 | 777 | require.Positive(t, switchIndex) | |
| 777 | - | require.Equal(t, ports.MsgResize, frames[switchIndex-1].Type, "current size must precede the parked switch") | |
| 778 | - | resize, resizeErr := ports.UnmarshalResize(frames[switchIndex-1].Payload) | |
| 778 | + | require.Equal(t, wire.MsgResize, frames[switchIndex-1].Type, "current size must precede the parked switch") | |
| 779 | + | resize, resizeErr := wire.UnmarshalResize(frames[switchIndex-1].Payload) | |
| 779 | 780 | require.NoError(t, resizeErr) | |
| 780 | 781 | require.Equal(t, domain.Size{Cols: 100, Rows: 40}, resize.Size) | |
| 781 | 782 | require.Equal(t, int32(1), remoteDialer.calls.Load(), "same-host picker switch must retain the authenticated remote transport") | |
| @@ -803,8 +804,8 @@ func TestHybridPickerExpiredSwitchFallsBackToNewDial(t *testing.T) { | |||
| 803 | 804 | sourceRemote := &recordingTransport{recvs: []recvItem{ | |
| 804 | 805 | {f: hybridWelcomeFrame("source", sourceLifecycle)}, | |
| 805 | 806 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | |
| 806 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: prepareSent}, | |
| 807 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteExpired})), wait: switchSent}, | |
| 807 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: prepareSent}, | |
| 808 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteExpired})), wait: switchSent}, | |
| 808 | 809 | }} | |
| 809 | 810 | sourceRemote.onSend = hybridParkedRequestHandler(nil, parkedRequestErrors, map[protocol.ParkedRouteAction]chan struct{}{ | |
| 810 | 811 | protocol.ParkedRoutePrepare: prepareSent, | |
| @@ -812,14 +813,14 @@ func TestHybridPickerExpiredSwitchFallsBackToNewDial(t *testing.T) { | |||
| 812 | 813 | }) | |
| 813 | 814 | localPicker := &recordingTransport{recvs: []recvItem{ | |
| 814 | 815 | {f: hybridWelcomeFrame("local", localLifecycle)}, | |
| 815 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | |
| 816 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ | |
| 816 | 817 | Endpoint: "remote", Session: "target", Intent: protocol.IntentAttach, | |
| 817 | 818 | RemoteTarget: &targetTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | |
| 818 | 819 | }))}, | |
| 819 | 820 | }} | |
| 820 | 821 | targetRemote := &recordingTransport{recvs: []recvItem{ | |
| 821 | 822 | {f: hybridWelcomeFrame("target", targetLifecycle)}, | |
| 822 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 823 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 823 | 824 | }} | |
| 824 | 825 | localDialer := &sequenceDialer{trs: []ports.Transport{localInitial, localPicker}} | |
| 825 | 826 | remoteDialer := &sequenceDialer{trs: []ports.Transport{ | |
| @@ -951,10 +952,10 @@ func TestHybridPickerBackResumesRetainedRemoteTransport(t *testing.T) { | |||
| 951 | 952 | remote := &recordingTransport{recvs: []recvItem{ | |
| 952 | 953 | {f: hybridWelcomeFrame("work", remoteLifecycle)}, | |
| 953 | 954 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | |
| 954 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: parkSent}, | |
| 955 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteResumed})), wait: resumeSent}, | |
| 956 | - | {f: frameOf(ports.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, New: 1, Size: domain.Size{Cols: 80, Rows: 24}, Full: true, Data: []byte("source frame")}))}, | |
| 957 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 955 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: parkSent}, | |
| 956 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteResumed})), wait: resumeSent}, | |
| 957 | + | {f: frameOf(wire.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, New: 1, Size: domain.Size{Cols: 80, Rows: 24}, Full: true, Data: []byte("source frame")}))}, | |
| 958 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 958 | 959 | }} | |
| 959 | 960 | remote.onSend = hybridParkedRequestHandler(nil, parkedRequestErrors, map[protocol.ParkedRouteAction]chan struct{}{ | |
| 960 | 961 | protocol.ParkedRoutePrepare: parkSent, | |
| @@ -1002,7 +1003,7 @@ func TestHybridPickerDifferentHostFallsBackToNewRemoteDial(t *testing.T) { | |||
| 1002 | 1003 | sourceRemote := &recordingTransport{recvs: []recvItem{ | |
| 1003 | 1004 | {f: hybridWelcomeFrame("source", sourceLifecycle)}, | |
| 1004 | 1005 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | |
| 1005 | - | {f: frameOf(ports.MsgParkedRouteResponse, ports.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: parkSent}, | |
| 1006 | + | {f: frameOf(wire.MsgParkedRouteResponse, wire.MarshalParkedRouteResponse(protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady})), wait: parkSent}, | |
| 1006 | 1007 | {err: io.EOF, wait: keepSourceOpen}, | |
| 1007 | 1008 | }} | |
| 1008 | 1009 | sourceRemote.onSend = hybridParkedRequestHandler(nil, parkedRequestErrors, map[protocol.ParkedRouteAction]chan struct{}{ | |
| @@ -1010,14 +1011,14 @@ func TestHybridPickerDifferentHostFallsBackToNewRemoteDial(t *testing.T) { | |||
| 1010 | 1011 | }) | |
| 1011 | 1012 | localPicker := &recordingTransport{recvs: []recvItem{ | |
| 1012 | 1013 | {f: hybridWelcomeFrame("local", localLifecycle)}, | |
| 1013 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(protocol.AttachTarget{ | |
| 1014 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(protocol.AttachTarget{ | |
| 1014 | 1015 | Endpoint: targetTarget.Endpoint, Session: targetTarget.SessionName, Intent: protocol.IntentAttach, | |
| 1015 | 1016 | RemoteTarget: &targetTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | |
| 1016 | 1017 | }))}, | |
| 1017 | 1018 | }} | |
| 1018 | 1019 | targetRemote := &recordingTransport{recvs: []recvItem{ | |
| 1019 | 1020 | {f: hybridWelcomeFrame("target", targetLifecycle)}, | |
| 1020 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1021 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1021 | 1022 | }} | |
| 1022 | 1023 | localDialer := &sequenceDialer{trs: []ports.Transport{localInitial, localPicker}} | |
| 1023 | 1024 | sourceDialer := &sequenceDialer{trs: []ports.Transport{markedDatagramTransport{Transport: sourceRemote}}} | |
| @@ -1048,8 +1049,8 @@ func TestRouteNavigationPreservesRemoteHomePickerAcrossLocalReturn(t *testing.T) | |||
| 1048 | 1049 | remoteLifecycle := domain.SessionLifecycleID{2, 2, 2} | |
| 1049 | 1050 | newLifecycle := domain.SessionLifecycleID{3, 3, 3} | |
| 1050 | 1051 | remoteNewLifecycle := domain.SessionLifecycleID{4, 4, 4} | |
| 1051 | - | welcome := func(name string, lifecycle domain.SessionLifecycleID, token uint64) ports.Frame { | |
| 1052 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | |
| 1052 | + | welcome := func(name string, lifecycle domain.SessionLifecycleID, token uint64) wire.Frame { | |
| 1053 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ | |
| 1053 | 1054 | SessionID: name + "-id", | |
| 1054 | 1055 | SessionName: name, | |
| 1055 | 1056 | ResumeToken: token, | |
| @@ -1073,14 +1074,14 @@ func TestRouteNavigationPreservesRemoteHomePickerAcrossLocalReturn(t *testing.T) | |||
| 1073 | 1074 | ||
| 1074 | 1075 | local1 := &recordingTransport{recvs: []recvItem{ | |
| 1075 | 1076 | {f: welcome("test", localLifecycle, 11)}, | |
| 1076 | - | {f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(remoteHandoff))}, | |
| 1077 | + | {f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(remoteHandoff))}, | |
| 1077 | 1078 | }} | |
| 1078 | 1079 | local2 := &recordingTransport{recvs: []recvItem{ | |
| 1079 | 1080 | {f: welcome("test", localLifecycle, 11)}, | |
| 1080 | - | {f: frameOf(ports.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{ | |
| 1081 | + | {f: frameOf(wire.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{ | |
| 1081 | 1082 | Target: protocol.ExactSessionTarget{LifecycleID: newLifecycle, SessionName: "new"}, | |
| 1082 | 1083 | }))}, | |
| 1083 | - | {f: frameOf(ports.MsgNavigateRecentRoute, mustMarshalRouteAction(protocol.RouteNavigationAction{SnapshotGeneration: 4, Key: 2, Generation: 2}))}, | |
| 1084 | + | {f: frameOf(wire.MsgNavigateRecentRoute, mustMarshalRouteAction(protocol.RouteNavigationAction{SnapshotGeneration: 4, Key: 2, Generation: 2}))}, | |
| 1084 | 1085 | }} | |
| 1085 | 1086 | local3 := &recordingTransport{recvs: []recvItem{ | |
| 1086 | 1087 | {f: welcome("test", localLifecycle, 11)}, | |
| @@ -1088,21 +1089,21 @@ func TestRouteNavigationPreservesRemoteHomePickerAcrossLocalReturn(t *testing.T) | |||
| 1088 | 1089 | }} | |
| 1089 | 1090 | remote1 := &recordingTransport{recvs: []recvItem{ | |
| 1090 | 1091 | {f: welcome("remote-manual", remoteLifecycle, 22)}, | |
| 1091 | - | {f: frameOf(ports.MsgNavigateRecentRoute, mustMarshalRouteAction(protocol.RouteNavigationAction{SnapshotGeneration: 2, Key: 1, Generation: 1}))}, | |
| 1092 | + | {f: frameOf(wire.MsgNavigateRecentRoute, mustMarshalRouteAction(protocol.RouteNavigationAction{SnapshotGeneration: 2, Key: 1, Generation: 1}))}, | |
| 1092 | 1093 | }} | |
| 1093 | 1094 | remote2 := &recordingTransport{recvs: []recvItem{ | |
| 1094 | 1095 | {f: welcome("remote-manual", remoteLifecycle, 22)}, | |
| 1095 | - | {f: frameOf(ports.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{ | |
| 1096 | + | {f: frameOf(wire.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{ | |
| 1096 | 1097 | Target: protocol.ExactSessionTarget{LifecycleID: remoteNewLifecycle, SessionName: "remote-new"}, | |
| 1097 | 1098 | }))}, | |
| 1098 | - | {f: frameOf(ports.MsgRoutePosition, mustMarshalRoutePosition(protocol.RoutePosition{ | |
| 1099 | + | {f: frameOf(wire.MsgRoutePosition, mustMarshalRoutePosition(protocol.RoutePosition{ | |
| 1099 | 1100 | Target: protocol.ExactSessionTarget{LifecycleID: remoteNewLifecycle, SessionName: "remote-new"}, ActiveTabID: "tab-2", | |
| 1100 | 1101 | }))}, | |
| 1101 | 1102 | {f: navigationDirectiveFrame(protocol.NavigationOpenHomePicker)}, | |
| 1102 | 1103 | }} | |
| 1103 | 1104 | remote3 := &recordingTransport{recvs: []recvItem{ | |
| 1104 | 1105 | {f: welcome("remote-new", remoteNewLifecycle, 22)}, | |
| 1105 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1106 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1106 | 1107 | }} | |
| 1107 | 1108 | localDialer := &sequenceDialer{trs: []ports.Transport{local1, local2, local3}} | |
| 1108 | 1109 | remoteDialer := &sequenceDialer{trs: []ports.Transport{remote1, remote2, remote3}} | |
| @@ -1129,16 +1130,16 @@ func TestRouteNavigationPreservesRemoteHomePickerAcrossLocalReturn(t *testing.T) | |||
| 1129 | 1130 | require.Equal(t, &protocol.ExactSessionTarget{LifecycleID: remoteNewLifecycle, SessionName: "remote-new"}, remoteNewHello.ExactTarget) | |
| 1130 | 1131 | } | |
| 1131 | 1132 | ||
| 1132 | - | func navigationDirectiveFrame(action protocol.NavigationAction) ports.Frame { | |
| 1133 | + | func navigationDirectiveFrame(action protocol.NavigationAction) wire.Frame { | |
| 1133 | 1134 | directive := protocol.NavigationDirective{Action: action} | |
| 1134 | 1135 | if action == protocol.NavigationOpenHomePicker { | |
| 1135 | 1136 | directive.LeaseID = protocol.ParkedRouteLeaseID{1} | |
| 1136 | 1137 | } | |
| 1137 | - | return frameOf(ports.MsgNavigationAction, ports.MarshalNavigationDirective(directive)) | |
| 1138 | + | return frameOf(wire.MsgNavigationAction, wire.MarshalNavigationDirective(directive)) | |
| 1138 | 1139 | } | |
| 1139 | 1140 | ||
| 1140 | 1141 | func mustMarshalCommittedIdentity(identity protocol.CommittedRouteIdentity) []byte { | |
| 1141 | - | payload, err := ports.MarshalCommittedRouteIdentity(identity) | |
| 1142 | + | payload, err := wire.MarshalCommittedRouteIdentity(identity) | |
| 1142 | 1143 | if err != nil { | |
| 1143 | 1144 | panic(err) | |
| 1144 | 1145 | } | |
| @@ -1146,7 +1147,7 @@ func mustMarshalCommittedIdentity(identity protocol.CommittedRouteIdentity) []by | |||
| 1146 | 1147 | } | |
| 1147 | 1148 | ||
| 1148 | 1149 | func mustMarshalRouteAction(action protocol.RouteNavigationAction) []byte { | |
| 1149 | - | payload, err := ports.MarshalRouteNavigationAction(action) | |
| 1150 | + | payload, err := wire.MarshalRouteNavigationAction(action) | |
| 1150 | 1151 | if err != nil { | |
| 1151 | 1152 | panic(err) | |
| 1152 | 1153 | } | |
| @@ -1154,7 +1155,7 @@ func mustMarshalRouteAction(action protocol.RouteNavigationAction) []byte { | |||
| 1154 | 1155 | } | |
| 1155 | 1156 | ||
| 1156 | 1157 | func mustMarshalRoutePosition(position protocol.RoutePosition) []byte { | |
| 1157 | - | payload, err := ports.MarshalRoutePosition(position) | |
| 1158 | + | payload, err := wire.MarshalRoutePosition(position) | |
| 1158 | 1159 | if err != nil { | |
| 1159 | 1160 | panic(err) | |
| 1160 | 1161 | } | |
| @@ -1170,11 +1171,11 @@ func TestAttachTargetHandoffReturnsValidatedTargetAndClosesTransport(t *testing. | |||
| 1170 | 1171 | ||
| 1171 | 1172 | target := protocol.AttachTarget{Endpoint: "remote.example", Session: "work", Intent: protocol.IntentAttach} | |
| 1172 | 1173 | tr := portsmocks.NewMockTransport(t) | |
| 1173 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1174 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 1174 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1175 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 1175 | 1176 | unblock := scriptRecv(tr, | |
| 1176 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "local"}))}, | |
| 1177 | - | recvItem{f: frameOf(ports.MsgAttachTarget, ports.MarshalAttachTarget(target))}, | |
| 1177 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "local"}))}, | |
| 1178 | + | recvItem{f: frameOf(wire.MsgAttachTarget, wire.MarshalAttachTarget(target))}, | |
| 1178 | 1179 | ) | |
| 1179 | 1180 | defer unblock() | |
| 1180 | 1181 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -1197,10 +1198,10 @@ func TestAttachHelloIncludesCompleteLocalEnvironment(t *testing.T) { | |||
| 1197 | 1198 | ||
| 1198 | 1199 | gotHello := make(chan protocol.Hello, 1) | |
| 1199 | 1200 | tr := portsmocks.NewMockTransport(t) | |
| 1200 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1201 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1202 | - | tr.EXPECT().Send(isType(ports.MsgHello)).RunAndReturn(func(f ports.Frame) error { | |
| 1203 | - | hello, err := ports.UnmarshalHello(f.Payload) | |
| 1201 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1202 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1203 | + | tr.EXPECT().Send(isType(wire.MsgHello)).RunAndReturn(func(f wire.Frame) error { | |
| 1204 | + | hello, err := wire.UnmarshalHello(f.Payload) | |
| 1204 | 1205 | if err != nil { | |
| 1205 | 1206 | return err | |
| 1206 | 1207 | } | |
| @@ -1208,8 +1209,8 @@ func TestAttachHelloIncludesCompleteLocalEnvironment(t *testing.T) { | |||
| 1208 | 1209 | return nil | |
| 1209 | 1210 | }).Once() | |
| 1210 | 1211 | unblock := scriptRecv(tr, | |
| 1211 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1212 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1212 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1213 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1213 | 1214 | ) | |
| 1214 | 1215 | defer unblock() | |
| 1215 | 1216 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -1226,17 +1227,17 @@ func TestAttachHelloRequestsSingleOutputForDatagramTransport(t *testing.T) { | |||
| 1226 | 1227 | defer in.unblock() | |
| 1227 | 1228 | ||
| 1228 | 1229 | tr := portsmocks.NewMockTransport(t) | |
| 1229 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1230 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1231 | - | tr.EXPECT().Send(isType(ports.MsgHello)).RunAndReturn(func(f ports.Frame) error { | |
| 1232 | - | hello, err := ports.UnmarshalHello(f.Payload) | |
| 1230 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1231 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1232 | + | tr.EXPECT().Send(isType(wire.MsgHello)).RunAndReturn(func(f wire.Frame) error { | |
| 1233 | + | hello, err := wire.UnmarshalHello(f.Payload) | |
| 1233 | 1234 | require.NoError(t, err) | |
| 1234 | 1235 | require.Equal(t, uint8(1), hello.MaxOutputInFlight) | |
| 1235 | 1236 | return nil | |
| 1236 | 1237 | }).Once() | |
| 1237 | 1238 | unblock := scriptRecv(tr, | |
| 1238 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1239 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1239 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1240 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1240 | 1241 | ) | |
| 1241 | 1242 | defer unblock() | |
| 1242 | 1243 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -1252,13 +1253,13 @@ func TestAttachHappyPath(t *testing.T) { | |||
| 1252 | 1253 | defer in.unblock() | |
| 1253 | 1254 | ||
| 1254 | 1255 | tr := portsmocks.NewMockTransport(t) | |
| 1255 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1256 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1257 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 1256 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1257 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1258 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 1258 | 1259 | unblock := scriptRecv(tr, | |
| 1259 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: "main"}))}, | |
| 1260 | - | recvItem{f: frameOf(ports.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("hello world")}))}, | |
| 1261 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1260 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: "main"}))}, | |
| 1261 | + | recvItem{f: frameOf(wire.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("hello world")}))}, | |
| 1262 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1262 | 1263 | ) | |
| 1263 | 1264 | defer unblock() | |
| 1264 | 1265 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -1275,9 +1276,9 @@ func TestAttachVersionMismatch(t *testing.T) { | |||
| 1275 | 1276 | // EnterRaw must NOT be called on the error-before-welcome path. | |
| 1276 | 1277 | ||
| 1277 | 1278 | tr := portsmocks.NewMockTransport(t) | |
| 1278 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 1279 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 1279 | 1280 | tr.EXPECT().Recv().Return( | |
| 1280 | - | frameOf(ports.MsgError, ports.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "version mismatch"})), | |
| 1281 | + | frameOf(wire.MsgError, wire.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "version mismatch"})), | |
| 1281 | 1282 | nil, | |
| 1282 | 1283 | ).Once() | |
| 1283 | 1284 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -1287,7 +1288,7 @@ func TestAttachVersionMismatch(t *testing.T) { | |||
| 1287 | 1288 | var pe *client.ProtocolError | |
| 1288 | 1289 | require.True(t, errors.As(err, &pe), "want *client.ProtocolError, got %T", err) | |
| 1289 | 1290 | require.Equal(t, protocol.ErrVersionMismatch, pe.Code) | |
| 1290 | - | tr.AssertNotCalled(t, "Send", isType(ports.MsgTheme)) | |
| 1291 | + | tr.AssertNotCalled(t, "Send", isType(wire.MsgTheme)) | |
| 1291 | 1292 | } | |
| 1292 | 1293 | ||
| 1293 | 1294 | func TestAttachRestoredOnRecvErrorMidStream(t *testing.T) { | |
| @@ -1298,12 +1299,12 @@ func TestAttachRestoredOnRecvErrorMidStream(t *testing.T) { | |||
| 1298 | 1299 | defer in.unblock() | |
| 1299 | 1300 | ||
| 1300 | 1301 | tr := portsmocks.NewMockTransport(t) | |
| 1301 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1302 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1303 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 1302 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1303 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1304 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 1304 | 1305 | boom := errors.New("connection reset") | |
| 1305 | 1306 | unblock := scriptRecv(tr, | |
| 1306 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1307 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1307 | 1308 | recvItem{err: boom}, | |
| 1308 | 1309 | ) | |
| 1309 | 1310 | defer unblock() | |
| @@ -1322,11 +1323,11 @@ func TestAttachDaemonVanishedOnEOF(t *testing.T) { | |||
| 1322 | 1323 | defer in.unblock() | |
| 1323 | 1324 | ||
| 1324 | 1325 | tr := portsmocks.NewMockTransport(t) | |
| 1325 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1326 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1327 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 1326 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1327 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1328 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 1328 | 1329 | unblock := scriptRecv(tr, | |
| 1329 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1330 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1330 | 1331 | recvItem{err: io.EOF}, | |
| 1331 | 1332 | ) | |
| 1332 | 1333 | defer unblock() | |
| @@ -1356,35 +1357,35 @@ func TestAttachStdinForwardsSGRMouseReportAsSingleFrame(t *testing.T) { | |||
| 1356 | 1357 | gotInput := make(chan []byte, 2) | |
| 1357 | 1358 | allowDetach := make(chan struct{}) | |
| 1358 | 1359 | tr := portsmocks.NewMockTransport(t) | |
| 1359 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1360 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1361 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 1362 | - | tr.EXPECT().Send(isType(ports.MsgInput)).RunAndReturn(func(f ports.Frame) error { | |
| 1363 | - | in, err := ports.UnmarshalInput(f.Payload) | |
| 1360 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1361 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1362 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 1363 | + | tr.EXPECT().Send(isType(wire.MsgInput)).RunAndReturn(func(f wire.Frame) error { | |
| 1364 | + | in, err := wire.UnmarshalInput(f.Payload) | |
| 1364 | 1365 | require.NoError(t, err) | |
| 1365 | 1366 | gotInput <- in.Data | |
| 1366 | 1367 | close(allowDetach) | |
| 1367 | 1368 | return nil | |
| 1368 | 1369 | }).Once() | |
| 1369 | - | welcome := frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | |
| 1370 | - | detached := frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | |
| 1370 | + | welcome := frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | |
| 1371 | + | detached := frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | |
| 1371 | 1372 | recvCh := make(chan recvItem, 1) | |
| 1372 | 1373 | recvCh <- recvItem{f: welcome} | |
| 1373 | 1374 | closed := make(chan struct{}) | |
| 1374 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | |
| 1375 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { | |
| 1375 | 1376 | select { | |
| 1376 | 1377 | case it := <-recvCh: | |
| 1377 | 1378 | return it.f, it.err | |
| 1378 | 1379 | case <-allowDetach: | |
| 1379 | 1380 | select { | |
| 1380 | 1381 | case <-closed: | |
| 1381 | - | return ports.Frame{}, io.EOF | |
| 1382 | + | return wire.Frame{}, io.EOF | |
| 1382 | 1383 | default: | |
| 1383 | 1384 | close(closed) | |
| 1384 | 1385 | return detached, nil | |
| 1385 | 1386 | } | |
| 1386 | 1387 | case <-closed: | |
| 1387 | - | return ports.Frame{}, io.EOF | |
| 1388 | + | return wire.Frame{}, io.EOF | |
| 1388 | 1389 | } | |
| 1389 | 1390 | }).Maybe() | |
| 1390 | 1391 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -1418,35 +1419,35 @@ func TestAttachStdinCoalescesSplitBracketedPaste(t *testing.T) { | |||
| 1418 | 1419 | gotInput := make(chan []byte, 1) | |
| 1419 | 1420 | allowDetach := make(chan struct{}) | |
| 1420 | 1421 | tr := portsmocks.NewMockTransport(t) | |
| 1421 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1422 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1423 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 1424 | - | tr.EXPECT().Send(isType(ports.MsgInput)).RunAndReturn(func(f ports.Frame) error { | |
| 1425 | - | in, err := ports.UnmarshalInput(f.Payload) | |
| 1422 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1423 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1424 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 1425 | + | tr.EXPECT().Send(isType(wire.MsgInput)).RunAndReturn(func(f wire.Frame) error { | |
| 1426 | + | in, err := wire.UnmarshalInput(f.Payload) | |
| 1426 | 1427 | require.NoError(t, err) | |
| 1427 | 1428 | gotInput <- in.Data | |
| 1428 | 1429 | close(allowDetach) | |
| 1429 | 1430 | return nil | |
| 1430 | 1431 | }).Once() | |
| 1431 | - | welcome := frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | |
| 1432 | - | detached := frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | |
| 1432 | + | welcome := frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | |
| 1433 | + | detached := frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | |
| 1433 | 1434 | recvCh := make(chan recvItem, 1) | |
| 1434 | 1435 | recvCh <- recvItem{f: welcome} | |
| 1435 | 1436 | closed := make(chan struct{}) | |
| 1436 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | |
| 1437 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { | |
| 1437 | 1438 | select { | |
| 1438 | 1439 | case it := <-recvCh: | |
| 1439 | 1440 | return it.f, it.err | |
| 1440 | 1441 | case <-allowDetach: | |
| 1441 | 1442 | select { | |
| 1442 | 1443 | case <-closed: | |
| 1443 | - | return ports.Frame{}, io.EOF | |
| 1444 | + | return wire.Frame{}, io.EOF | |
| 1444 | 1445 | default: | |
| 1445 | 1446 | close(closed) | |
| 1446 | 1447 | return detached, nil | |
| 1447 | 1448 | } | |
| 1448 | 1449 | case <-closed: | |
| 1449 | - | return ports.Frame{}, io.EOF | |
| 1450 | + | return wire.Frame{}, io.EOF | |
| 1450 | 1451 | } | |
| 1451 | 1452 | }).Maybe() | |
| 1452 | 1453 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -1473,24 +1474,24 @@ func TestAttachForwardsResize(t *testing.T) { | |||
| 1473 | 1474 | var firstRecvOnce sync.Once | |
| 1474 | 1475 | ||
| 1475 | 1476 | tr := portsmocks.NewMockTransport(t) | |
| 1476 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1477 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1478 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 1477 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1478 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1479 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 1479 | 1480 | // The resize frame is forwarded via the sender goroutine. | |
| 1480 | 1481 | gotResize := make(chan protocol.Resize, 1) | |
| 1481 | - | tr.EXPECT().Send(isType(ports.MsgResize)).RunAndReturn(func(f ports.Frame) error { | |
| 1482 | - | r, _ := ports.UnmarshalResize(f.Payload) | |
| 1482 | + | tr.EXPECT().Send(isType(wire.MsgResize)).RunAndReturn(func(f wire.Frame) error { | |
| 1483 | + | r, _ := wire.UnmarshalResize(f.Payload) | |
| 1483 | 1484 | gotResize <- r | |
| 1484 | 1485 | close(detachAfterResize) | |
| 1485 | 1486 | return nil | |
| 1486 | 1487 | }).Once() | |
| 1487 | 1488 | ||
| 1488 | - | welcome := frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | |
| 1489 | - | detached := frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | |
| 1489 | + | welcome := frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | |
| 1490 | + | detached := frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | |
| 1490 | 1491 | recvCh := make(chan recvItem, 2) | |
| 1491 | 1492 | recvCh <- recvItem{f: welcome} | |
| 1492 | 1493 | done := make(chan struct{}) | |
| 1493 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | |
| 1494 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { | |
| 1494 | 1495 | firstRecvOnce.Do(func() { close(firstRecv) }) | |
| 1495 | 1496 | select { | |
| 1496 | 1497 | case it := <-recvCh: | |
| @@ -1499,13 +1500,13 @@ func TestAttachForwardsResize(t *testing.T) { | |||
| 1499 | 1500 | // Deliver the detach once the resize has been observed. | |
| 1500 | 1501 | select { | |
| 1501 | 1502 | case <-done: | |
| 1502 | - | return ports.Frame{}, io.EOF | |
| 1503 | + | return wire.Frame{}, io.EOF | |
| 1503 | 1504 | default: | |
| 1504 | 1505 | close(done) | |
| 1505 | 1506 | return detached, nil | |
| 1506 | 1507 | } | |
| 1507 | 1508 | case <-done: | |
| 1508 | - | return ports.Frame{}, io.EOF | |
| 1509 | + | return wire.Frame{}, io.EOF | |
| 1509 | 1510 | } | |
| 1510 | 1511 | }).Maybe() | |
| 1511 | 1512 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -1534,12 +1535,12 @@ func TestRunRestoresRawModeAfterAttachError(t *testing.T) { | |||
| 1534 | 1535 | defer in.unblock() | |
| 1535 | 1536 | ||
| 1536 | 1537 | tr := portsmocks.NewMockTransport(t) | |
| 1537 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1538 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1539 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 1538 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1539 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1540 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 1540 | 1541 | boom := errors.New("connection reset") | |
| 1541 | 1542 | unblock := scriptRecv(tr, | |
| 1542 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1543 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1543 | 1544 | recvItem{err: boom}, | |
| 1544 | 1545 | ) | |
| 1545 | 1546 | defer unblock() | |
| @@ -1558,9 +1559,9 @@ func TestRunDoesNotEnterRawBeforePreWelcomeError(t *testing.T) { | |||
| 1558 | 1559 | // EnterRaw must NOT be called when the daemon rejects Hello before Welcome. | |
| 1559 | 1560 | ||
| 1560 | 1561 | tr := portsmocks.NewMockTransport(t) | |
| 1561 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 1562 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 1562 | 1563 | tr.EXPECT().Recv().Return( | |
| 1563 | - | frameOf(ports.MsgError, ports.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "version mismatch"})), | |
| 1564 | + | frameOf(wire.MsgError, wire.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "version mismatch"})), | |
| 1564 | 1565 | nil, | |
| 1565 | 1566 | ).Once() | |
| 1566 | 1567 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -1571,7 +1572,7 @@ func TestRunDoesNotEnterRawBeforePreWelcomeError(t *testing.T) { | |||
| 1571 | 1572 | require.Error(t, err) | |
| 1572 | 1573 | var pe *client.ProtocolError | |
| 1573 | 1574 | require.True(t, errors.As(err, &pe), "want *client.ProtocolError, got %T", err) | |
| 1574 | - | tr.AssertNotCalled(t, "Send", isType(ports.MsgTheme)) | |
| 1575 | + | tr.AssertNotCalled(t, "Send", isType(wire.MsgTheme)) | |
| 1575 | 1576 | } | |
| 1576 | 1577 | ||
| 1577 | 1578 | func TestRunPhaseASingleAttempt(t *testing.T) { | |
| @@ -1604,14 +1605,14 @@ func (d *sequenceDialer) Dial(context.Context) (ports.Transport, error) { | |||
| 1604 | 1605 | type recordingTransport struct { | |
| 1605 | 1606 | mu sync.Mutex | |
| 1606 | 1607 | recvs []recvItem | |
| 1607 | - | sends []ports.Frame | |
| 1608 | + | sends []wire.Frame | |
| 1608 | 1609 | closed atomic.Int32 | |
| 1609 | 1610 | stall <-chan struct{} | |
| 1610 | - | onSend func(ports.Frame) | |
| 1611 | + | onSend func(wire.Frame) | |
| 1611 | 1612 | onClose func() | |
| 1612 | 1613 | } | |
| 1613 | 1614 | ||
| 1614 | - | func (t *recordingTransport) Send(f ports.Frame) error { | |
| 1615 | + | func (t *recordingTransport) Send(f wire.Frame) error { | |
| 1615 | 1616 | t.mu.Lock() | |
| 1616 | 1617 | t.sends = append(t.sends, f) | |
| 1617 | 1618 | onSend := t.onSend | |
| @@ -1622,18 +1623,18 @@ func (t *recordingTransport) Send(f ports.Frame) error { | |||
| 1622 | 1623 | return nil | |
| 1623 | 1624 | } | |
| 1624 | 1625 | ||
| 1625 | - | func (t *recordingTransport) Sends() []ports.Frame { | |
| 1626 | + | func (t *recordingTransport) Sends() []wire.Frame { | |
| 1626 | 1627 | t.mu.Lock() | |
| 1627 | 1628 | defer t.mu.Unlock() | |
| 1628 | - | return append([]ports.Frame(nil), t.sends...) | |
| 1629 | + | return append([]wire.Frame(nil), t.sends...) | |
| 1629 | 1630 | } | |
| 1630 | 1631 | ||
| 1631 | - | func (t *recordingTransport) Recv() (ports.Frame, error) { | |
| 1632 | + | func (t *recordingTransport) Recv() (wire.Frame, error) { | |
| 1632 | 1633 | if len(t.recvs) == 0 { | |
| 1633 | 1634 | if t.stall != nil { | |
| 1634 | 1635 | <-t.stall | |
| 1635 | 1636 | } | |
| 1636 | - | return ports.Frame{}, io.EOF | |
| 1637 | + | return wire.Frame{}, io.EOF | |
| 1637 | 1638 | } | |
| 1638 | 1639 | it := t.recvs[0] | |
| 1639 | 1640 | t.recvs = t.recvs[1:] | |
| @@ -1692,14 +1693,14 @@ func helloFromSend(t *testing.T, tr *recordingTransport) protocol.Hello { | |||
| 1692 | 1693 | t.Helper() | |
| 1693 | 1694 | sends := tr.Sends() | |
| 1694 | 1695 | require.NotEmpty(t, sends) | |
| 1695 | - | require.Equal(t, ports.MsgHello, sends[0].Type) | |
| 1696 | - | h, err := ports.UnmarshalHello(sends[0].Payload) | |
| 1696 | + | require.Equal(t, wire.MsgHello, sends[0].Type) | |
| 1697 | + | h, err := wire.UnmarshalHello(sends[0].Payload) | |
| 1697 | 1698 | require.NoError(t, err) | |
| 1698 | 1699 | return h | |
| 1699 | 1700 | } | |
| 1700 | 1701 | ||
| 1701 | - | func welcomeFrame(token uint64) ports.Frame { | |
| 1702 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: "main", ResumeToken: token, Capabilities: protocol.CapabilityResume})) | |
| 1702 | + | func welcomeFrame(token uint64) wire.Frame { | |
| 1703 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: "main", ResumeToken: token, Capabilities: protocol.CapabilityResume})) | |
| 1703 | 1704 | } | |
| 1704 | 1705 | ||
| 1705 | 1706 | func TestRunReconnectsWithRotatedTokenAndSameClientID(t *testing.T) { | |
| @@ -1707,7 +1708,7 @@ func TestRunReconnectsWithRotatedTokenAndSameClientID(t *testing.T) { | |||
| 1707 | 1708 | defer term.in.unblock() | |
| 1708 | 1709 | tr1 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(11)}, {err: io.EOF}}} | |
| 1709 | 1710 | tr2 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(22)}, {err: io.EOF}}} | |
| 1710 | - | tr3 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(33)}, {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}}} | |
| 1711 | + | tr3 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(33)}, {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}}} | |
| 1711 | 1712 | d := &sequenceDialer{trs: []ports.Transport{tr1, tr2, tr3}} | |
| 1712 | 1713 | clock := &reconnectTestClock{} | |
| 1713 | 1714 | result := make(chan error, 1) | |
| @@ -1741,20 +1742,20 @@ func TestReconnectRestoresLastPublishedRouteTab(t *testing.T) { | |||
| 1741 | 1742 | defer term.in.unblock() | |
| 1742 | 1743 | lifecycle := domain.SessionLifecycleID{7, 8, 9} | |
| 1743 | 1744 | target := protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "work"} | |
| 1744 | - | welcome := func(token uint64) ports.Frame { | |
| 1745 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | |
| 1745 | + | welcome := func(token uint64) wire.Frame { | |
| 1746 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ | |
| 1746 | 1747 | SessionID: "work", SessionName: "work", ResumeToken: token, Capabilities: protocol.CapabilityResume, | |
| 1747 | 1748 | CommittedIdentity: &protocol.CommittedRouteIdentity{Target: target}, | |
| 1748 | 1749 | })) | |
| 1749 | 1750 | } | |
| 1750 | 1751 | tr1 := &recordingTransport{recvs: []recvItem{ | |
| 1751 | 1752 | {f: welcome(11)}, | |
| 1752 | - | {f: frameOf(ports.MsgRoutePosition, mustMarshalRoutePosition(protocol.RoutePosition{Target: target, ActiveTabID: "tab-2"}))}, | |
| 1753 | + | {f: frameOf(wire.MsgRoutePosition, mustMarshalRoutePosition(protocol.RoutePosition{Target: target, ActiveTabID: "tab-2"}))}, | |
| 1753 | 1754 | {err: io.EOF}, | |
| 1754 | 1755 | }} | |
| 1755 | 1756 | tr2 := &recordingTransport{recvs: []recvItem{ | |
| 1756 | 1757 | {f: welcome(22)}, | |
| 1757 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1758 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1758 | 1759 | }} | |
| 1759 | 1760 | dialer := &sequenceDialer{trs: []ports.Transport{tr1, tr2}} | |
| 1760 | 1761 | clock := &reconnectTestClock{} | |
| @@ -1780,8 +1781,8 @@ func TestRemoteReconnectDropsStalePickerTargetAfterDaemonSessionSwitch(t *testin | |||
| 1780 | 1781 | Endpoint: "remote", DisplayOrigin: "remote", LifecycleID: oldLifecycle, | |
| 1781 | 1782 | SessionName: "old", LiveTabID: "tab-1", | |
| 1782 | 1783 | } | |
| 1783 | - | welcome := func(name string, lifecycle domain.SessionLifecycleID, token uint64) ports.Frame { | |
| 1784 | - | return frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{ | |
| 1784 | + | welcome := func(name string, lifecycle domain.SessionLifecycleID, token uint64) wire.Frame { | |
| 1785 | + | return frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{ | |
| 1785 | 1786 | SessionID: name, SessionName: name, ResumeToken: token, Capabilities: protocol.CapabilityResume, | |
| 1786 | 1787 | CommittedIdentity: &protocol.CommittedRouteIdentity{ | |
| 1787 | 1788 | Target: protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: name}, | |
| @@ -1790,14 +1791,14 @@ func TestRemoteReconnectDropsStalePickerTargetAfterDaemonSessionSwitch(t *testin | |||
| 1790 | 1791 | } | |
| 1791 | 1792 | tr1 := &recordingTransport{recvs: []recvItem{ | |
| 1792 | 1793 | {f: welcome("old", oldLifecycle, 11)}, | |
| 1793 | - | {f: frameOf(ports.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{ | |
| 1794 | + | {f: frameOf(wire.MsgCommittedRouteIdentity, mustMarshalCommittedIdentity(protocol.CommittedRouteIdentity{ | |
| 1794 | 1795 | Target: protocol.ExactSessionTarget{LifecycleID: newLifecycle, SessionName: "new"}, | |
| 1795 | 1796 | }))}, | |
| 1796 | 1797 | {err: io.EOF}, | |
| 1797 | 1798 | }} | |
| 1798 | 1799 | tr2 := &recordingTransport{recvs: []recvItem{ | |
| 1799 | 1800 | {f: welcome("new", newLifecycle, 22)}, | |
| 1800 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1801 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1801 | 1802 | }} | |
| 1802 | 1803 | dialer := &sequenceDialer{trs: []ports.Transport{tr1, tr2}} | |
| 1803 | 1804 | clock := &reconnectTestClock{} | |
| @@ -1838,8 +1839,8 @@ func TestAttachRememberRemoteHost(t *testing.T) { | |||
| 1838 | 1839 | }, | |
| 1839 | 1840 | remember: func() error { return nil }, | |
| 1840 | 1841 | recv: []recvItem{ | |
| 1841 | - | {f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1842 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1842 | + | {f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1843 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1843 | 1844 | }, | |
| 1844 | 1845 | wantCalled: true, | |
| 1845 | 1846 | }, | |
| @@ -1852,8 +1853,8 @@ func TestAttachRememberRemoteHost(t *testing.T) { | |||
| 1852 | 1853 | }, | |
| 1853 | 1854 | remember: func() error { return errors.New("disk full") }, | |
| 1854 | 1855 | recv: []recvItem{ | |
| 1855 | - | {f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1856 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1856 | + | {f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1857 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1857 | 1858 | }, | |
| 1858 | 1859 | wantCalled: true, | |
| 1859 | 1860 | }, | |
| @@ -1869,8 +1870,8 @@ func TestAttachRememberRemoteHost(t *testing.T) { | |||
| 1869 | 1870 | return nil | |
| 1870 | 1871 | }, | |
| 1871 | 1872 | recv: []recvItem{ | |
| 1872 | - | {f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1873 | - | {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1873 | + | {f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1874 | + | {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 1874 | 1875 | }, | |
| 1875 | 1876 | }, | |
| 1876 | 1877 | { | |
| @@ -1885,7 +1886,7 @@ func TestAttachRememberRemoteHost(t *testing.T) { | |||
| 1885 | 1886 | return nil | |
| 1886 | 1887 | }, | |
| 1887 | 1888 | recv: []recvItem{ | |
| 1888 | - | {f: frameOf(ports.MsgError, ports.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "version mismatch"}))}, | |
| 1889 | + | {f: frameOf(wire.MsgError, wire.MarshalErrorMsg(protocol.ErrorMsg{Code: protocol.ErrVersionMismatch, Text: "version mismatch"}))}, | |
| 1889 | 1890 | }, | |
| 1890 | 1891 | preWelcomeReject: true, | |
| 1891 | 1892 | wantErr: true, | |
| @@ -1899,7 +1900,7 @@ func TestAttachRememberRemoteHost(t *testing.T) { | |||
| 1899 | 1900 | }, | |
| 1900 | 1901 | remember: func() error { return nil }, | |
| 1901 | 1902 | recv: []recvItem{ | |
| 1902 | - | {f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1903 | + | {f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 1903 | 1904 | {err: errors.New("connection reset")}, | |
| 1904 | 1905 | }, | |
| 1905 | 1906 | wantCalled: true, | |
| @@ -1940,9 +1941,9 @@ func TestAttachRememberRemoteHost(t *testing.T) { | |||
| 1940 | 1941 | ||
| 1941 | 1942 | tr := portsmocks.NewMockTransport(t) | |
| 1942 | 1943 | if !tt.preWelcomeReject { | |
| 1943 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 1944 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 1944 | 1945 | } | |
| 1945 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 1946 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 1946 | 1947 | if tt.preWelcomeReject { | |
| 1947 | 1948 | tr.EXPECT().Recv().Return(tt.recv[0].f, tt.recv[0].err).Once() | |
| 1948 | 1949 | } else { | |
| @@ -1984,7 +1985,7 @@ func TestRunRememberRemoteHostAtMostOnceAcrossReconnects(t *testing.T) { | |||
| 1984 | 1985 | learnerDone := make(chan struct{}) | |
| 1985 | 1986 | ||
| 1986 | 1987 | tr1 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(11)}, {err: io.EOF}}} | |
| 1987 | - | tr2 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(22)}, {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}}} | |
| 1988 | + | tr2 := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(22)}, {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}}} | |
| 1988 | 1989 | d := &sequenceDialer{trs: []ports.Transport{tr1, tr2}} | |
| 1989 | 1990 | ||
| 1990 | 1991 | deps := testDependencies(d, term, realClock{}, nil, nil) | |
| @@ -2033,11 +2034,11 @@ func TestAttachRememberRemoteHostDoesNotBlockAfterWelcome(t *testing.T) { | |||
| 2033 | 2034 | learnerDone := make(chan struct{}) | |
| 2034 | 2035 | ||
| 2035 | 2036 | tr := portsmocks.NewMockTransport(t) | |
| 2036 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 2037 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 2037 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 2038 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 2038 | 2039 | unblock := scriptRecv(tr, | |
| 2039 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 2040 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 2040 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 2041 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 2041 | 2042 | ) | |
| 2042 | 2043 | defer unblock() | |
| 2043 | 2044 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -2114,11 +2115,11 @@ func TestRunRestoresTerminalBeforeWaitingForLearner(t *testing.T) { | |||
| 2114 | 2115 | learnerDone := make(chan struct{}) | |
| 2115 | 2116 | ||
| 2116 | 2117 | tr := portsmocks.NewMockTransport(t) | |
| 2117 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 2118 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 2118 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 2119 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 2119 | 2120 | unblock := scriptRecv(tr, | |
| 2120 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 2121 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 2121 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 2122 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 2122 | 2123 | ) | |
| 2123 | 2124 | defer unblock() | |
| 2124 | 2125 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -2211,11 +2212,11 @@ func TestRunReturnsWhenRemoteHostLearnerStalls(t *testing.T) { | |||
| 2211 | 2212 | }).Maybe() | |
| 2212 | 2213 | ||
| 2213 | 2214 | tr := portsmocks.NewMockTransport(t) | |
| 2214 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 2215 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 2215 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 2216 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 2216 | 2217 | unblock := scriptRecv(tr, | |
| 2217 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 2218 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 2218 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 2219 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 2219 | 2220 | ) | |
| 2220 | 2221 | defer unblock() | |
| 2221 | 2222 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -2267,7 +2268,7 @@ func TestRunReturnsWhenRemoteHostLearnerStalls(t *testing.T) { | |||
| 2267 | 2268 | func TestRunDoesNotRetryTerminalDetachedError(t *testing.T) { | |
| 2268 | 2269 | term := newRunTerminal() | |
| 2269 | 2270 | defer term.in.unblock() | |
| 2270 | - | tr := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(11)}, {f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonSessionKilled}))}}} | |
| 2271 | + | tr := &recordingTransport{recvs: []recvItem{{f: welcomeFrame(11)}, {f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonSessionKilled}))}}} | |
| 2271 | 2272 | d := &sequenceDialer{trs: []ports.Transport{tr}} | |
| 2272 | 2273 | ||
| 2273 | 2274 | err := runTestClient(context.Background(), testDependencies(d, term, realClock{}, nil, nil), client.AttachRequest{Intent: protocol.IntentAttach, SessionName: "main", Remote: false}) | |
M internal/usecase/client/clipboard_intercept_test.go +25 -24
| @@ -15,6 +15,7 @@ import ( | |||
| 15 | 15 | "github.com/bnema/vev/internal/ports" | |
| 16 | 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 17 | 17 | "github.com/bnema/vev/internal/protocol" | |
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 18 | 19 | "github.com/bnema/vev/internal/usecase/client" | |
| 19 | 20 | ) | |
| 20 | 21 | ||
| @@ -44,11 +45,11 @@ func runRemoteClipboardTest(t *testing.T, remote bool, clip ports.ClipboardReade | |||
| 44 | 45 | allowDetach := make(chan struct{}) | |
| 45 | 46 | ||
| 46 | 47 | tr := portsmocks.NewMockTransport(t) | |
| 47 | - | tr.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 48 | - | tr.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 49 | - | tr.EXPECT().Send(isType(ports.MsgResize)).Return(nil).Maybe() | |
| 50 | - | tr.EXPECT().Send(isType(ports.MsgInput)).RunAndReturn(func(f ports.Frame) error { | |
| 51 | - | in, err := ports.UnmarshalInput(f.Payload) | |
| 48 | + | tr.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 49 | + | tr.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 50 | + | tr.EXPECT().Send(isType(wire.MsgResize)).Return(nil).Maybe() | |
| 51 | + | tr.EXPECT().Send(isType(wire.MsgInput)).RunAndReturn(func(f wire.Frame) error { | |
| 52 | + | in, err := wire.UnmarshalInput(f.Payload) | |
| 52 | 53 | require.NoError(t, err) | |
| 53 | 54 | gotInput <- append([]byte(nil), in.Data...) | |
| 54 | 55 | if bytes.IndexByte(in.Data, triggerByte) >= 0 { | |
| @@ -56,33 +57,33 @@ func runRemoteClipboardTest(t *testing.T, remote bool, clip ports.ClipboardReade | |||
| 56 | 57 | } | |
| 57 | 58 | return nil | |
| 58 | 59 | }).Maybe() | |
| 59 | - | tr.EXPECT().Send(isType(ports.MsgImagePush)).RunAndReturn(func(f ports.Frame) error { | |
| 60 | - | ip, err := ports.UnmarshalImagePush(f.Payload) | |
| 60 | + | tr.EXPECT().Send(isType(wire.MsgImagePush)).RunAndReturn(func(f wire.Frame) error { | |
| 61 | + | ip, err := wire.UnmarshalImagePush(f.Payload) | |
| 61 | 62 | require.NoError(t, err) | |
| 62 | 63 | gotImage <- ip | |
| 63 | 64 | return nil | |
| 64 | 65 | }).Maybe() | |
| 65 | - | tr.EXPECT().Send(isType(ports.MsgClientNotice)).Return(nil).Maybe() | |
| 66 | + | tr.EXPECT().Send(isType(wire.MsgClientNotice)).Return(nil).Maybe() | |
| 66 | 67 | ||
| 67 | - | welcome := frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | |
| 68 | - | detached := frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | |
| 68 | + | welcome := frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | |
| 69 | + | detached := frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | |
| 69 | 70 | recvCh := make(chan recvItem, 1) | |
| 70 | 71 | recvCh <- recvItem{f: welcome} | |
| 71 | 72 | closed := make(chan struct{}) | |
| 72 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | |
| 73 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { | |
| 73 | 74 | select { | |
| 74 | 75 | case it := <-recvCh: | |
| 75 | 76 | return it.f, it.err | |
| 76 | 77 | case <-allowDetach: | |
| 77 | 78 | select { | |
| 78 | 79 | case <-closed: | |
| 79 | - | return ports.Frame{}, io.EOF | |
| 80 | + | return wire.Frame{}, io.EOF | |
| 80 | 81 | default: | |
| 81 | 82 | close(closed) | |
| 82 | 83 | return detached, nil | |
| 83 | 84 | } | |
| 84 | 85 | case <-closed: | |
| 85 | - | return ports.Frame{}, io.EOF | |
| 86 | + | return wire.Frame{}, io.EOF | |
| 86 | 87 | } | |
| 87 | 88 | }).Maybe() | |
| 88 | 89 | tr.EXPECT().Close().Return(nil).Once() | |
| @@ -142,17 +143,17 @@ func TestRunRemoteClipboardCtrlVWithNoImageForwardsCtrlV(t *testing.T) { | |||
| 142 | 143 | } | |
| 143 | 144 | ||
| 144 | 145 | type clipboardToastLifecycleTransport struct { | |
| 145 | - | recv chan ports.Frame | |
| 146 | - | sends chan ports.Frame | |
| 146 | + | recv chan wire.Frame | |
| 147 | + | sends chan wire.Frame | |
| 147 | 148 | } | |
| 148 | 149 | ||
| 149 | - | func (t *clipboardToastLifecycleTransport) Send(f ports.Frame) error { | |
| 150 | + | func (t *clipboardToastLifecycleTransport) Send(f wire.Frame) error { | |
| 150 | 151 | t.sends <- f | |
| 151 | 152 | return nil | |
| 152 | 153 | } | |
| 153 | 154 | ||
| 154 | - | func (t *clipboardToastLifecycleTransport) Recv() (ports.Frame, error) { return <-t.recv, nil } | |
| 155 | - | func (*clipboardToastLifecycleTransport) Close() error { return nil } | |
| 155 | + | func (t *clipboardToastLifecycleTransport) Recv() (wire.Frame, error) { return <-t.recv, nil } | |
| 156 | + | func (*clipboardToastLifecycleTransport) Close() error { return nil } | |
| 156 | 157 | ||
| 157 | 158 | type clipboardToastLifecycleDialer struct{ transport ports.Transport } | |
| 158 | 159 | ||
| @@ -175,8 +176,8 @@ func TestRunRemoteClipboardFailureNotifiesDaemonAndWritesOutputVerbatim(t *testi | |||
| 175 | 176 | ||
| 176 | 177 | clipboard := portsmocks.NewMockClipboardReader(t) | |
| 177 | 178 | clipboard.EXPECT().ReadImage(mock.Anything).Return("", nil, errors.New("read failed")).Once() | |
| 178 | - | transport := &clipboardToastLifecycleTransport{recv: make(chan ports.Frame, 8), sends: make(chan ports.Frame, 16)} | |
| 179 | - | transport.recv <- frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | |
| 179 | + | transport := &clipboardToastLifecycleTransport{recv: make(chan wire.Frame, 8), sends: make(chan wire.Frame, 16)} | |
| 180 | + | transport.recv <- frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"})) | |
| 180 | 181 | ||
| 181 | 182 | result := make(chan error, 1) | |
| 182 | 183 | go func() { | |
| @@ -187,10 +188,10 @@ func TestRunRemoteClipboardFailureNotifiesDaemonAndWritesOutputVerbatim(t *testi | |||
| 187 | 188 | for !gotNotice { | |
| 188 | 189 | select { | |
| 189 | 190 | case sent := <-transport.sends: | |
| 190 | - | if sent.Type != ports.MsgClientNotice { | |
| 191 | + | if sent.Type != wire.MsgClientNotice { | |
| 191 | 192 | continue | |
| 192 | 193 | } | |
| 193 | - | notice, err := ports.UnmarshalClientNotice(sent.Payload) | |
| 194 | + | notice, err := wire.UnmarshalClientNotice(sent.Payload) | |
| 194 | 195 | require.NoError(t, err) | |
| 195 | 196 | require.Equal(t, protocol.ClientNoticeClipboardFallback, notice.Action) | |
| 196 | 197 | gotNotice = true | |
| @@ -199,8 +200,8 @@ func TestRunRemoteClipboardFailureNotifiesDaemonAndWritesOutputVerbatim(t *testi | |||
| 199 | 200 | } | |
| 200 | 201 | } | |
| 201 | 202 | beforeOutput := out.String() | |
| 202 | - | transport.recv <- frameOf(ports.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Base: 0, New: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("incremental")})) | |
| 203 | - | transport.recv <- frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | |
| 203 | + | transport.recv <- frameOf(wire.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Base: 0, New: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("incremental")})) | |
| 204 | + | transport.recv <- frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})) | |
| 204 | 205 | ||
| 205 | 206 | select { | |
| 206 | 207 | case err := <-result: | |
M internal/usecase/client/palette_attach_generation_test.go +14 -13
| @@ -17,6 +17,7 @@ import ( | |||
| 17 | 17 | "github.com/bnema/vev/internal/domain" | |
| 18 | 18 | "github.com/bnema/vev/internal/ports" | |
| 19 | 19 | "github.com/bnema/vev/internal/protocol" | |
| 20 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 20 | 21 | ) | |
| 21 | 22 | ||
| 22 | 23 | // attachPaletteClock deliberately exposes each independently-created timer. | |
| @@ -115,11 +116,11 @@ func (*attachPaletteTerminalHarness) Flush() error { r | |||
| 115 | 116 | ||
| 116 | 117 | type attachPaletteTransport struct { | |
| 117 | 118 | mu sync.Mutex | |
| 118 | - | frames []ports.Frame | |
| 119 | + | frames []wire.Frame | |
| 119 | 120 | themes []protocol.Theme | |
| 120 | 121 | themeCh chan protocol.Theme | |
| 121 | 122 | inputCh chan protocol.Input | |
| 122 | - | detached chan ports.Frame | |
| 123 | + | detached chan wire.Frame | |
| 123 | 124 | themeSendErr error | |
| 124 | 125 | welcomed bool | |
| 125 | 126 | } | |
| @@ -128,20 +129,20 @@ func newAttachPaletteTransport() *attachPaletteTransport { | |||
| 128 | 129 | return &attachPaletteTransport{ | |
| 129 | 130 | themeCh: make(chan protocol.Theme, 16), | |
| 130 | 131 | inputCh: make(chan protocol.Input, 16), | |
| 131 | - | detached: make(chan ports.Frame, 1), | |
| 132 | + | detached: make(chan wire.Frame, 1), | |
| 132 | 133 | } | |
| 133 | 134 | } | |
| 134 | - | func (t *attachPaletteTransport) Send(frame ports.Frame) error { | |
| 135 | + | func (t *attachPaletteTransport) Send(frame wire.Frame) error { | |
| 135 | 136 | t.mu.Lock() | |
| 136 | 137 | t.frames = append(t.frames, frame) | |
| 137 | 138 | themeSendErr := t.themeSendErr | |
| 138 | 139 | t.mu.Unlock() | |
| 139 | 140 | switch frame.Type { | |
| 140 | - | case ports.MsgTheme: | |
| 141 | + | case wire.MsgTheme: | |
| 141 | 142 | if themeSendErr != nil { | |
| 142 | 143 | return themeSendErr | |
| 143 | 144 | } | |
| 144 | - | got, err := ports.UnmarshalTheme(frame.Payload) | |
| 145 | + | got, err := wire.UnmarshalTheme(frame.Payload) | |
| 145 | 146 | if err != nil { | |
| 146 | 147 | return err | |
| 147 | 148 | } | |
| @@ -149,8 +150,8 @@ func (t *attachPaletteTransport) Send(frame ports.Frame) error { | |||
| 149 | 150 | t.themes = append(t.themes, got) | |
| 150 | 151 | t.mu.Unlock() | |
| 151 | 152 | t.themeCh <- got | |
| 152 | - | case ports.MsgInput: | |
| 153 | - | got, err := ports.UnmarshalInput(frame.Payload) | |
| 153 | + | case wire.MsgInput: | |
| 154 | + | got, err := wire.UnmarshalInput(frame.Payload) | |
| 154 | 155 | if err != nil { | |
| 155 | 156 | return err | |
| 156 | 157 | } | |
| @@ -158,12 +159,12 @@ func (t *attachPaletteTransport) Send(frame ports.Frame) error { | |||
| 158 | 159 | } | |
| 159 | 160 | return nil | |
| 160 | 161 | } | |
| 161 | - | func (t *attachPaletteTransport) Recv() (ports.Frame, error) { | |
| 162 | + | func (t *attachPaletteTransport) Recv() (wire.Frame, error) { | |
| 162 | 163 | t.mu.Lock() | |
| 163 | 164 | if !t.welcomed { | |
| 164 | 165 | t.welcomed = true | |
| 165 | 166 | t.mu.Unlock() | |
| 166 | - | return ports.Frame{Type: ports.MsgWelcome, Payload: ports.MarshalWelcome(protocol.Welcome{SessionID: "s"})}, nil | |
| 167 | + | return wire.Frame{Type: wire.MsgWelcome, Payload: wire.MarshalWelcome(protocol.Welcome{SessionID: "s"})}, nil | |
| 167 | 168 | } | |
| 168 | 169 | t.mu.Unlock() | |
| 169 | 170 | return <-t.detached, nil | |
| @@ -239,7 +240,7 @@ func (h *attachPaletteHarness) nextTimer(t *testing.T) *attachPaletteTimer { | |||
| 239 | 240 | } | |
| 240 | 241 | func (h *attachPaletteHarness) detach(t *testing.T) { | |
| 241 | 242 | t.Helper() | |
| 242 | - | h.transport.detached <- ports.Frame{Type: ports.MsgDetached, Payload: ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})} | |
| 243 | + | h.transport.detached <- wire.Frame{Type: wire.MsgDetached, Payload: wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})} | |
| 243 | 244 | result := <-h.done | |
| 244 | 245 | require.NoError(t, result.err) | |
| 245 | 246 | select { | |
| @@ -325,7 +326,7 @@ func TestAttachReconnectPreservesStandaloneEscapeBeforeClaimRevocation(t *testin | |||
| 325 | 326 | ||
| 326 | 327 | // Detach starts reconnect teardown. The residual must already be owned by | |
| 327 | 328 | // the lifecycle reader at the precise point the old claim is revoked. | |
| 328 | - | first.transport.detached <- ports.Frame{Type: ports.MsgDetached, Payload: ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})} | |
| 329 | + | first.transport.detached <- wire.Frame{Type: wire.MsgDetached, Payload: wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})} | |
| 329 | 330 | require.Equal(t, []byte("\x1b"), <-revoked) | |
| 330 | 331 | release() | |
| 331 | 332 | require.NoError(t, (<-first.done).err) | |
| @@ -437,7 +438,7 @@ func TestStdinPumpSameReadSchemeAndOldMarkerCannotAdvanceReplacement(t *testing. | |||
| 437 | 438 | // notification and publish its replacement generation before the scanner | |
| 438 | 439 | // can deliver the old marker from the same terminal Read. | |
| 439 | 440 | events := make(chan paletteGenerationEvent) | |
| 440 | - | out := make(chan ports.Frame, 1) | |
| 441 | + | out := make(chan wire.Frame, 1) | |
| 441 | 442 | schemeHandled := make(chan struct{}) | |
| 442 | 443 | pump := &stdinPump{ | |
| 443 | 444 | ctx: ctx, | |
M internal/usecase/client/palette_attach_test.go +9 -8
| @@ -15,6 +15,7 @@ import ( | |||
| 15 | 15 | "github.com/bnema/vev/internal/domain" | |
| 16 | 16 | "github.com/bnema/vev/internal/ports" | |
| 17 | 17 | "github.com/bnema/vev/internal/protocol" | |
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 18 | 19 | ) | |
| 19 | 20 | ||
| 20 | 21 | type paletteAttachClock struct{} | |
| @@ -78,18 +79,18 @@ func (t *paletteAttachTerminal) Flush() error { return n | |||
| 78 | 79 | ||
| 79 | 80 | type paletteAttachTransport struct { | |
| 80 | 81 | mu sync.Mutex | |
| 81 | - | sent []ports.Frame | |
| 82 | + | sent []wire.Frame | |
| 82 | 83 | themes []protocol.Theme | |
| 83 | 84 | finals int | |
| 84 | 85 | finalSet chan struct{} | |
| 85 | 86 | } | |
| 86 | 87 | ||
| 87 | - | func (t *paletteAttachTransport) Send(frame ports.Frame) error { | |
| 88 | + | func (t *paletteAttachTransport) Send(frame wire.Frame) error { | |
| 88 | 89 | t.mu.Lock() | |
| 89 | 90 | defer t.mu.Unlock() | |
| 90 | 91 | t.sent = append(t.sent, frame) | |
| 91 | - | if frame.Type == ports.MsgTheme { | |
| 92 | - | theme, err := ports.UnmarshalTheme(frame.Payload) | |
| 92 | + | if frame.Type == wire.MsgTheme { | |
| 93 | + | theme, err := wire.UnmarshalTheme(frame.Payload) | |
| 93 | 94 | if err != nil { | |
| 94 | 95 | return err | |
| 95 | 96 | } | |
| @@ -104,15 +105,15 @@ func (t *paletteAttachTransport) Send(frame ports.Frame) error { | |||
| 104 | 105 | return nil | |
| 105 | 106 | } | |
| 106 | 107 | ||
| 107 | - | func (t *paletteAttachTransport) Recv() (ports.Frame, error) { | |
| 108 | + | func (t *paletteAttachTransport) Recv() (wire.Frame, error) { | |
| 108 | 109 | t.mu.Lock() | |
| 109 | 110 | first := len(t.sent) == 1 | |
| 110 | 111 | t.mu.Unlock() | |
| 111 | 112 | if first { | |
| 112 | - | return ports.Frame{Type: ports.MsgWelcome, Payload: ports.MarshalWelcome(protocol.Welcome{SessionID: "s"})}, nil | |
| 113 | + | return wire.Frame{Type: wire.MsgWelcome, Payload: wire.MarshalWelcome(protocol.Welcome{SessionID: "s"})}, nil | |
| 113 | 114 | } | |
| 114 | 115 | <-t.finalSet | |
| 115 | - | return ports.Frame{Type: ports.MsgDetached, Payload: ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})}, nil | |
| 116 | + | return wire.Frame{Type: wire.MsgDetached, Payload: wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach})}, nil | |
| 116 | 117 | } | |
| 117 | 118 | func (*paletteAttachTransport) Close() error { return nil } | |
| 118 | 119 | ||
| @@ -155,7 +156,7 @@ func TestAttachPublishesOnlyClearedAndDefinitiveInitialPalette(t *testing.T) { | |||
| 155 | 156 | transport.mu.Lock() | |
| 156 | 157 | defer transport.mu.Unlock() | |
| 157 | 158 | require.Len(t, transport.sent, 3) | |
| 158 | - | require.Equal(t, []ports.MsgType{ports.MsgHello, ports.MsgTheme, ports.MsgTheme}, []ports.MsgType{ | |
| 159 | + | require.Equal(t, []wire.MsgType{wire.MsgHello, wire.MsgTheme, wire.MsgTheme}, []wire.MsgType{ | |
| 159 | 160 | transport.sent[0].Type, transport.sent[1].Type, transport.sent[2].Type, | |
| 160 | 161 | }, "the protocol requires Hello before the two palette publications") | |
| 161 | 162 | require.Len(t, transport.themes, 2) | |
M internal/usecase/client/reconnect_toast_test.go +61 -60
| @@ -21,6 +21,7 @@ import ( | |||
| 21 | 21 | "github.com/bnema/vev/internal/ports" | |
| 22 | 22 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 23 | 23 | "github.com/bnema/vev/internal/protocol" | |
| 24 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 24 | 25 | ) | |
| 25 | 26 | ||
| 26 | 27 | type reconnectToastTerminalHarness struct { | |
| @@ -129,20 +130,20 @@ func (r *reconnectToastOutputRecorder) String() string { | |||
| 129 | 130 | return r.all.String() | |
| 130 | 131 | } | |
| 131 | 132 | ||
| 132 | - | func reconnectToastWelcome(token uint64) ports.Frame { | |
| 133 | + | func reconnectToastWelcome(token uint64) wire.Frame { | |
| 133 | 134 | return reconnectToastWelcomeNamed("", token) | |
| 134 | 135 | } | |
| 135 | 136 | ||
| 136 | - | func reconnectToastWelcomeNamed(name string, token uint64) ports.Frame { | |
| 137 | - | return ports.Frame{Type: ports.MsgWelcome, Payload: ports.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: name, ResumeToken: token, Capabilities: protocol.CapabilityResume})} | |
| 137 | + | func reconnectToastWelcomeNamed(name string, token uint64) wire.Frame { | |
| 138 | + | return wire.Frame{Type: wire.MsgWelcome, Payload: wire.MarshalWelcome(protocol.Welcome{SessionID: "s1", SessionName: name, ResumeToken: token, Capabilities: protocol.CapabilityResume})} | |
| 138 | 139 | } | |
| 139 | 140 | ||
| 140 | - | func reconnectToastDetach(reason uint8) ports.Frame { | |
| 141 | - | return ports.Frame{Type: ports.MsgDetached, Payload: ports.MarshalDetached(protocol.Detached{Reason: reason})} | |
| 141 | + | func reconnectToastDetach(reason uint8) wire.Frame { | |
| 142 | + | return wire.Frame{Type: wire.MsgDetached, Payload: wire.MarshalDetached(protocol.Detached{Reason: reason})} | |
| 142 | 143 | } | |
| 143 | 144 | ||
| 144 | 145 | type reconnectToastRecv struct { | |
| 145 | - | frame ports.Frame | |
| 146 | + | frame wire.Frame | |
| 146 | 147 | err error | |
| 147 | 148 | } | |
| 148 | 149 | ||
| @@ -163,7 +164,7 @@ func (d *reconnectToastSequenceDialer) Dial(context.Context) (ports.Transport, e | |||
| 163 | 164 | type reconnectToastRecordingTransport struct { | |
| 164 | 165 | mu sync.Mutex | |
| 165 | 166 | recvs []reconnectToastRecv | |
| 166 | - | sends []ports.Frame | |
| 167 | + | sends []wire.Frame | |
| 167 | 168 | closed bool | |
| 168 | 169 | } | |
| 169 | 170 | ||
| @@ -173,7 +174,7 @@ func newReconnectToastRecordingTransport(recvs ...reconnectToastRecv) *reconnect | |||
| 173 | 174 | ||
| 174 | 175 | type reconnectToastSentFrames struct { | |
| 175 | 176 | mu sync.Mutex | |
| 176 | - | frames []ports.Frame | |
| 177 | + | frames []wire.Frame | |
| 177 | 178 | changed chan struct{} | |
| 178 | 179 | } | |
| 179 | 180 | ||
| @@ -181,7 +182,7 @@ func newReconnectToastSentFrames() *reconnectToastSentFrames { | |||
| 181 | 182 | return &reconnectToastSentFrames{changed: make(chan struct{}, 1)} | |
| 182 | 183 | } | |
| 183 | 184 | ||
| 184 | - | func (s *reconnectToastSentFrames) record(frame ports.Frame) { | |
| 185 | + | func (s *reconnectToastSentFrames) record(frame wire.Frame) { | |
| 185 | 186 | s.mu.Lock() | |
| 186 | 187 | s.frames = append(s.frames, frame) | |
| 187 | 188 | s.mu.Unlock() | |
| @@ -191,7 +192,7 @@ func (s *reconnectToastSentFrames) record(frame ports.Frame) { | |||
| 191 | 192 | } | |
| 192 | 193 | } | |
| 193 | 194 | ||
| 194 | - | func (s *reconnectToastSentFrames) find(match func(ports.Frame) bool) (ports.Frame, bool) { | |
| 195 | + | func (s *reconnectToastSentFrames) find(match func(wire.Frame) bool) (wire.Frame, bool) { | |
| 195 | 196 | s.mu.Lock() | |
| 196 | 197 | defer s.mu.Unlock() | |
| 197 | 198 | for _, frame := range s.frames { | |
| @@ -199,7 +200,7 @@ func (s *reconnectToastSentFrames) find(match func(ports.Frame) bool) (ports.Fra | |||
| 199 | 200 | return frame, true | |
| 200 | 201 | } | |
| 201 | 202 | } | |
| 202 | - | return ports.Frame{}, false | |
| 203 | + | return wire.Frame{}, false | |
| 203 | 204 | } | |
| 204 | 205 | ||
| 205 | 206 | type reconnectToastLinkTransport struct { | |
| @@ -220,12 +221,12 @@ func newReconnectToastLinkTransport() *reconnectToastLinkTransport { | |||
| 220 | 221 | } | |
| 221 | 222 | } | |
| 222 | 223 | ||
| 223 | - | func (t *reconnectToastLinkTransport) Send(f ports.Frame) error { | |
| 224 | + | func (t *reconnectToastLinkTransport) Send(f wire.Frame) error { | |
| 224 | 225 | t.sends.record(f) | |
| 225 | - | if f.Type != ports.MsgClientNotice { | |
| 226 | + | if f.Type != wire.MsgClientNotice { | |
| 226 | 227 | return nil | |
| 227 | 228 | } | |
| 228 | - | notice, err := ports.UnmarshalClientNotice(f.Payload) | |
| 229 | + | notice, err := wire.UnmarshalClientNotice(f.Payload) | |
| 229 | 230 | if err != nil { | |
| 230 | 231 | return err | |
| 231 | 232 | } | |
| @@ -233,7 +234,7 @@ func (t *reconnectToastLinkTransport) Send(f ports.Frame) error { | |||
| 233 | 234 | return nil | |
| 234 | 235 | } | |
| 235 | 236 | ||
| 236 | - | func (t *reconnectToastLinkTransport) Recv() (ports.Frame, error) { | |
| 237 | + | func (t *reconnectToastLinkTransport) Recv() (wire.Frame, error) { | |
| 237 | 238 | recv := <-t.recvCh | |
| 238 | 239 | return recv.frame, recv.err | |
| 239 | 240 | } | |
| @@ -244,18 +245,18 @@ func (t *reconnectToastLinkTransport) LinkEvents() <-chan ports.LinkEvent { retu | |||
| 244 | 245 | ||
| 245 | 246 | func (t *reconnectToastLinkTransport) LinkState() ports.LinkState { return t.state } | |
| 246 | 247 | ||
| 247 | - | func (t *reconnectToastRecordingTransport) Send(f ports.Frame) error { | |
| 248 | + | func (t *reconnectToastRecordingTransport) Send(f wire.Frame) error { | |
| 248 | 249 | t.mu.Lock() | |
| 249 | 250 | defer t.mu.Unlock() | |
| 250 | 251 | t.sends = append(t.sends, f) | |
| 251 | 252 | return nil | |
| 252 | 253 | } | |
| 253 | 254 | ||
| 254 | - | func (t *reconnectToastRecordingTransport) Recv() (ports.Frame, error) { | |
| 255 | + | func (t *reconnectToastRecordingTransport) Recv() (wire.Frame, error) { | |
| 255 | 256 | t.mu.Lock() | |
| 256 | 257 | defer t.mu.Unlock() | |
| 257 | 258 | if len(t.recvs) == 0 { | |
| 258 | - | return ports.Frame{}, io.EOF | |
| 259 | + | return wire.Frame{}, io.EOF | |
| 259 | 260 | } | |
| 260 | 261 | recv := t.recvs[0] | |
| 261 | 262 | t.recvs = t.recvs[1:] | |
| @@ -269,10 +270,10 @@ func (t *reconnectToastRecordingTransport) Close() error { | |||
| 269 | 270 | return nil | |
| 270 | 271 | } | |
| 271 | 272 | ||
| 272 | - | func (t *reconnectToastRecordingTransport) sentFrames() []ports.Frame { | |
| 273 | + | func (t *reconnectToastRecordingTransport) sentFrames() []wire.Frame { | |
| 273 | 274 | t.mu.Lock() | |
| 274 | 275 | defer t.mu.Unlock() | |
| 275 | - | return append([]ports.Frame(nil), t.sends...) | |
| 276 | + | return append([]wire.Frame(nil), t.sends...) | |
| 276 | 277 | } | |
| 277 | 278 | ||
| 278 | 279 | func (t *reconnectToastRecordingTransport) wasClosed() bool { | |
| @@ -288,9 +289,9 @@ func assertReconnectToastAttemptPublishesOnlyClearedTheme(t *testing.T, tr *reco | |||
| 288 | 289 | t.Helper() | |
| 289 | 290 | frames := tr.sentFrames() | |
| 290 | 291 | require.GreaterOrEqual(t, len(frames), 2) | |
| 291 | - | require.Equal(t, ports.MsgHello, frames[0].Type) | |
| 292 | - | require.Equal(t, ports.MsgTheme, frames[1].Type) | |
| 293 | - | theme, err := ports.UnmarshalTheme(frames[1].Payload) | |
| 292 | + | require.Equal(t, wire.MsgHello, frames[0].Type) | |
| 293 | + | require.Equal(t, wire.MsgTheme, frames[1].Type) | |
| 294 | + | theme, err := wire.UnmarshalTheme(frames[1].Payload) | |
| 294 | 295 | require.NoError(t, err) | |
| 295 | 296 | require.False(t, theme.HasForeground) | |
| 296 | 297 | require.False(t, theme.HasBackground) | |
| @@ -302,8 +303,8 @@ func reconnectToastHelloFromSend(t *testing.T, tr *reconnectToastRecordingTransp | |||
| 302 | 303 | t.Helper() | |
| 303 | 304 | frames := tr.sentFrames() | |
| 304 | 305 | require.NotEmpty(t, frames) | |
| 305 | - | require.Equal(t, ports.MsgHello, frames[0].Type) | |
| 306 | - | hello, err := ports.UnmarshalHello(frames[0].Payload) | |
| 306 | + | require.Equal(t, wire.MsgHello, frames[0].Type) | |
| 307 | + | hello, err := wire.UnmarshalHello(frames[0].Payload) | |
| 307 | 308 | require.NoError(t, err) | |
| 308 | 309 | return hello | |
| 309 | 310 | } | |
| @@ -394,7 +395,7 @@ func TestProbingToastReconcilesDaemonOutputAndDismissal(t *testing.T) { | |||
| 394 | 395 | require.Contains(t, firstToast, "┌") | |
| 395 | 396 | require.Contains(t, firstToast, "probing UDP path") | |
| 396 | 397 | ||
| 397 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 398 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 398 | 399 | Epoch: 1, | |
| 399 | 400 | Base: 0, | |
| 400 | 401 | New: 2, | |
| @@ -413,7 +414,7 @@ func TestProbingToastReconcilesDaemonOutputAndDismissal(t *testing.T) { | |||
| 413 | 414 | ||
| 414 | 415 | beforeAwaitingReset := out.String() | |
| 415 | 416 | beforeStatelessFlushes := flushes.Load() | |
| 416 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 417 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 417 | 418 | Epoch: 1, | |
| 418 | 419 | Base: 0, | |
| 419 | 420 | New: 0, | |
| @@ -425,7 +426,7 @@ func TestProbingToastReconcilesDaemonOutputAndDismissal(t *testing.T) { | |||
| 425 | 426 | }, time.Second, time.Millisecond) | |
| 426 | 427 | ||
| 427 | 428 | afterStateless := out.String() | |
| 428 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 429 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 429 | 430 | Epoch: 1, | |
| 430 | 431 | Base: 2, | |
| 431 | 432 | New: 3, | |
| @@ -436,7 +437,7 @@ func TestProbingToastReconcilesDaemonOutputAndDismissal(t *testing.T) { | |||
| 436 | 437 | require.Contains(t, out.String(), "intervening incremental") | |
| 437 | 438 | require.Contains(t, afterStateless[len(beforeAwaitingReset):], "stateless side effect") | |
| 438 | 439 | ||
| 439 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 440 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 440 | 441 | Epoch: 2, | |
| 441 | 442 | Base: 0, | |
| 442 | 443 | New: 4, | |
| @@ -449,7 +450,7 @@ func TestProbingToastReconcilesDaemonOutputAndDismissal(t *testing.T) { | |||
| 449 | 450 | require.NotContains(t, out.String()[len(beforeAwaitingReset):], strings.Repeat(" ", reconnectToastBoundsFor(term.size, "probing UDP path").Width)) | |
| 450 | 451 | ||
| 451 | 452 | beforeIncrementFlushes := flushes.Load() | |
| 452 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 453 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 453 | 454 | Epoch: 2, | |
| 454 | 455 | Base: 4, | |
| 455 | 456 | New: 5, | |
| @@ -496,30 +497,30 @@ func TestActiveReconnectToastStageTransitionReconcilesBeforeRedraw(t *testing.T) | |||
| 496 | 497 | {Epoch: 1, Base: 1, New: 2, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("first skipped increment")}, | |
| 497 | 498 | {Epoch: 1, Base: 2, New: 3, Size: domain.Size{Cols: 1, Rows: 1}, Data: []byte("second skipped increment")}, | |
| 498 | 499 | } { | |
| 499 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(output)}} | |
| 500 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(output)}} | |
| 500 | 501 | require.Equal(t, beforeReset, out.String()) | |
| 501 | 502 | } | |
| 502 | - | requireSentFrame(t, tr.sends, "output reset request", func(frame ports.Frame) bool { | |
| 503 | - | return frame.Type == ports.MsgOutputResetRequest | |
| 503 | + | requireSentFrame(t, tr.sends, "output reset request", func(frame wire.Frame) bool { | |
| 504 | + | return frame.Type == wire.MsgOutputResetRequest | |
| 504 | 505 | }) | |
| 505 | - | _, sentAck := tr.sends.find(func(frame ports.Frame) bool { return frame.Type == ports.MsgAck }) | |
| 506 | + | _, sentAck := tr.sends.find(func(frame wire.Frame) bool { return frame.Type == wire.MsgAck }) | |
| 506 | 507 | require.False(t, sentAck, "discarded output must not be ACKed") | |
| 507 | 508 | ||
| 508 | 509 | // Handoff cleanup is an ordered terminal side effect, not a replay state. | |
| 509 | 510 | // It must cross the outstanding reset gate, flush before the control handoff, | |
| 510 | 511 | // and must not manufacture an independent ACK. | |
| 511 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 512 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 512 | 513 | Epoch: 2, | |
| 513 | 514 | Size: domain.Size{Cols: 1, Rows: 1}, | |
| 514 | 515 | Data: []byte("handoff graphics cleanup"), | |
| 515 | 516 | })}} | |
| 516 | 517 | cleanup := requireReconnectToastOutput(t, out.completed) | |
| 517 | 518 | require.Contains(t, cleanup, "handoff graphics cleanup") | |
| 518 | - | _, sentAck = tr.sends.find(func(frame ports.Frame) bool { return frame.Type == ports.MsgAck }) | |
| 519 | + | _, sentAck = tr.sends.find(func(frame wire.Frame) bool { return frame.Type == wire.MsgAck }) | |
| 519 | 520 | require.False(t, sentAck, "state-independent cleanup must not be ACKed") | |
| 520 | 521 | ||
| 521 | 522 | beforeResetFlushes := flushes.Load() | |
| 522 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 523 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 523 | 524 | Epoch: 2, | |
| 524 | 525 | Base: 0, | |
| 525 | 526 | New: 4, | |
| @@ -534,7 +535,7 @@ func TestActiveReconnectToastStageTransitionReconcilesBeforeRedraw(t *testing.T) | |||
| 534 | 535 | requireAckedState(t, tr.sends, 2, 4) | |
| 535 | 536 | ||
| 536 | 537 | beforeIncrementFlushes := flushes.Load() | |
| 537 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 538 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 538 | 539 | Epoch: 2, | |
| 539 | 540 | Base: 4, | |
| 540 | 541 | New: 5, | |
| @@ -563,7 +564,7 @@ func requireReconnectToastOutput(t *testing.T, completed <-chan string) string { | |||
| 563 | 564 | } | |
| 564 | 565 | } | |
| 565 | 566 | ||
| 566 | - | func requireSentFrame(t *testing.T, sends *reconnectToastSentFrames, description string, match func(ports.Frame) bool) ports.Frame { | |
| 567 | + | func requireSentFrame(t *testing.T, sends *reconnectToastSentFrames, description string, match func(wire.Frame) bool) wire.Frame { | |
| 567 | 568 | t.Helper() | |
| 568 | 569 | timer := time.NewTimer(time.Second) | |
| 569 | 570 | defer timer.Stop() | |
| @@ -575,31 +576,31 @@ func requireSentFrame(t *testing.T, sends *reconnectToastSentFrames, description | |||
| 575 | 576 | case <-sends.changed: | |
| 576 | 577 | case <-timer.C: | |
| 577 | 578 | t.Fatalf("timed out waiting for %s", description) | |
| 578 | - | return ports.Frame{} | |
| 579 | + | return wire.Frame{} | |
| 579 | 580 | } | |
| 580 | 581 | } | |
| 581 | 582 | } | |
| 582 | 583 | ||
| 583 | 584 | func requireResize(t *testing.T, sends *reconnectToastSentFrames) protocol.Resize { | |
| 584 | 585 | t.Helper() | |
| 585 | - | frame := requireSentFrame(t, sends, "Resize frame", func(frame ports.Frame) bool { | |
| 586 | - | return frame.Type == ports.MsgResize | |
| 586 | + | frame := requireSentFrame(t, sends, "Resize frame", func(frame wire.Frame) bool { | |
| 587 | + | return frame.Type == wire.MsgResize | |
| 587 | 588 | }) | |
| 588 | - | resize, err := ports.UnmarshalResize(frame.Payload) | |
| 589 | + | resize, err := wire.UnmarshalResize(frame.Payload) | |
| 589 | 590 | require.NoError(t, err) | |
| 590 | 591 | return resize | |
| 591 | 592 | } | |
| 592 | 593 | ||
| 593 | 594 | func requireAckedState(t *testing.T, sends *reconnectToastSentFrames, epoch, state uint64) { | |
| 594 | 595 | t.Helper() | |
| 595 | - | frame := requireSentFrame(t, sends, fmt.Sprintf("ACK for epoch %d state %d", epoch, state), func(frame ports.Frame) bool { | |
| 596 | - | if frame.Type != ports.MsgAck { | |
| 596 | + | frame := requireSentFrame(t, sends, fmt.Sprintf("ACK for epoch %d state %d", epoch, state), func(frame wire.Frame) bool { | |
| 597 | + | if frame.Type != wire.MsgAck { | |
| 597 | 598 | return false | |
| 598 | 599 | } | |
| 599 | - | ack, err := ports.UnmarshalAck(frame.Payload) | |
| 600 | + | ack, err := wire.UnmarshalAck(frame.Payload) | |
| 600 | 601 | return err == nil && ack.Epoch == epoch && ack.State >= state | |
| 601 | 602 | }) | |
| 602 | - | ack, err := ports.UnmarshalAck(frame.Payload) | |
| 603 | + | ack, err := wire.UnmarshalAck(frame.Payload) | |
| 603 | 604 | require.NoError(t, err) | |
| 604 | 605 | require.Equal(t, epoch, ack.Epoch) | |
| 605 | 606 | require.GreaterOrEqual(t, ack.State, state) | |
| @@ -707,7 +708,7 @@ func TestLocalReconnectStatusFlushesDaemonOutputBeforeObservationAndAck(t *testi | |||
| 707 | 708 | require.Eventually(t, func() bool { return flushes.Load() > beforeStatus }, time.Second, time.Millisecond) | |
| 708 | 709 | beforeOutput := flushes.Load() | |
| 709 | 710 | ||
| 710 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 711 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 711 | 712 | Epoch: 1, | |
| 712 | 713 | Base: 0, | |
| 713 | 714 | New: 2, | |
| @@ -759,7 +760,7 @@ func TestLocalReconnectStatusTransitionsDoNotRequestAuthoritativeReset(t *testin | |||
| 759 | 760 | } | |
| 760 | 761 | ||
| 761 | 762 | const output = "local status output remains visible" | |
| 762 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 763 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 763 | 764 | Epoch: 1, | |
| 764 | 765 | Base: 0, | |
| 765 | 766 | New: 2, | |
| @@ -769,7 +770,7 @@ func TestLocalReconnectStatusTransitionsDoNotRequestAuthoritativeReset(t *testin | |||
| 769 | 770 | })}} | |
| 770 | 771 | require.Eventually(t, func() bool { return strings.Contains(out.String(), output) }, time.Second, time.Millisecond) | |
| 771 | 772 | requireAckedState(t, tr.sends, 1, 2) | |
| 772 | - | _, sentResize := tr.sends.find(func(frame ports.Frame) bool { return frame.Type == ports.MsgResize }) | |
| 773 | + | _, sentResize := tr.sends.find(func(frame wire.Frame) bool { return frame.Type == wire.MsgResize }) | |
| 773 | 774 | require.False(t, sentResize, "local reconnect status must not request a daemon reset") | |
| 774 | 775 | ||
| 775 | 776 | tr.recvCh <- reconnectToastRecv{frame: reconnectToastDetach(protocol.ReasonDetach)} | |
| @@ -827,7 +828,7 @@ func TestReconnectOverlayRedrawFailureDoesNotObserveOrAckOutput(t *testing.T) { | |||
| 827 | 828 | tr.events <- ports.LinkEvent{State: ports.LinkStateProbing} | |
| 828 | 829 | requireReconnectToastOutput(t, out.completed) | |
| 829 | 830 | arm() | |
| 830 | - | tr.recvCh <- reconnectToastRecv{frame: ports.Frame{Type: ports.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 831 | + | tr.recvCh <- reconnectToastRecv{frame: wire.Frame{Type: wire.MsgOutput, Payload: mustMarshalOutput(protocol.Output{ | |
| 831 | 832 | Epoch: 1, | |
| 832 | 833 | Base: 0, | |
| 833 | 834 | New: 2, | |
| @@ -932,8 +933,8 @@ func newReconnectResetBlockingTransport() *reconnectResetBlockingTransport { | |||
| 932 | 933 | } | |
| 933 | 934 | } | |
| 934 | 935 | ||
| 935 | - | func (t *reconnectResetBlockingTransport) Send(frame ports.Frame) error { | |
| 936 | - | if frame.Type != ports.MsgResize { | |
| 936 | + | func (t *reconnectResetBlockingTransport) Send(frame wire.Frame) error { | |
| 937 | + | if frame.Type != wire.MsgResize { | |
| 937 | 938 | return nil | |
| 938 | 939 | } | |
| 939 | 940 | t.enterOnce.Do(func() { close(t.entered) }) | |
| @@ -941,11 +942,11 @@ func (t *reconnectResetBlockingTransport) Send(frame ports.Frame) error { | |||
| 941 | 942 | return io.ErrClosedPipe | |
| 942 | 943 | } | |
| 943 | 944 | ||
| 944 | - | func (t *reconnectResetBlockingTransport) Recv() (ports.Frame, error) { | |
| 945 | + | func (t *reconnectResetBlockingTransport) Recv() (wire.Frame, error) { | |
| 945 | 946 | t.mu.Lock() | |
| 946 | 947 | defer t.mu.Unlock() | |
| 947 | 948 | if len(t.recvs) == 0 { | |
| 948 | - | return ports.Frame{}, io.EOF | |
| 949 | + | return wire.Frame{}, io.EOF | |
| 949 | 950 | } | |
| 950 | 951 | recv := t.recvs[0] | |
| 951 | 952 | t.recvs = t.recvs[1:] | |
| @@ -1014,7 +1015,7 @@ func TestPreSenderReconnectResetIsBounded(t *testing.T) { | |||
| 1014 | 1015 | type reconnectToastBlockingSendTransport struct { | |
| 1015 | 1016 | *reconnectToastLinkTransport | |
| 1016 | 1017 | armed atomic.Bool | |
| 1017 | - | blockType ports.MsgType | |
| 1018 | + | blockType wire.MsgType | |
| 1018 | 1019 | sendErr error | |
| 1019 | 1020 | entered chan struct{} | |
| 1020 | 1021 | release chan struct{} | |
| @@ -1025,13 +1026,13 @@ type reconnectToastBlockingSendTransport struct { | |||
| 1025 | 1026 | func newReconnectToastBlockingSendTransport() *reconnectToastBlockingSendTransport { | |
| 1026 | 1027 | return &reconnectToastBlockingSendTransport{ | |
| 1027 | 1028 | reconnectToastLinkTransport: newReconnectToastLinkTransport(), | |
| 1028 | - | blockType: ports.MsgClientNotice, | |
| 1029 | + | blockType: wire.MsgClientNotice, | |
| 1029 | 1030 | entered: make(chan struct{}), | |
| 1030 | 1031 | release: make(chan struct{}), | |
| 1031 | 1032 | } | |
| 1032 | 1033 | } | |
| 1033 | 1034 | ||
| 1034 | - | func (t *reconnectToastBlockingSendTransport) Send(frame ports.Frame) error { | |
| 1035 | + | func (t *reconnectToastBlockingSendTransport) Send(frame wire.Frame) error { | |
| 1035 | 1036 | if err := t.reconnectToastLinkTransport.Send(frame); err != nil { | |
| 1036 | 1037 | return err | |
| 1037 | 1038 | } | |
| @@ -1083,7 +1084,7 @@ func TestReconnectResetEnqueueCancellationExitsCleanly(t *testing.T) { | |||
| 1083 | 1084 | ||
| 1084 | 1085 | tr.events <- ports.LinkEvent{State: ports.LinkStateProbing} | |
| 1085 | 1086 | requireTerminalSizeCalls(t, term, 2) | |
| 1086 | - | tr.blockType = ports.MsgResize | |
| 1087 | + | tr.blockType = wire.MsgResize | |
| 1087 | 1088 | tr.armed.Store(true) | |
| 1088 | 1089 | term.resizeCh <- domain.Geometry{Size: term.size} | |
| 1089 | 1090 | select { | |
| @@ -1123,7 +1124,7 @@ func TestReconnectResetCancellationPreservesQueuedSenderError(t *testing.T) { | |||
| 1123 | 1124 | ||
| 1124 | 1125 | tr.events <- ports.LinkEvent{State: ports.LinkStateProbing} | |
| 1125 | 1126 | requireTerminalSizeCalls(t, term, 2) | |
| 1126 | - | tr.blockType = ports.MsgResize | |
| 1127 | + | tr.blockType = wire.MsgResize | |
| 1127 | 1128 | tr.armed.Store(true) | |
| 1128 | 1129 | term.resizeCh <- domain.Geometry{Size: term.size} | |
| 1129 | 1130 | select { | |
M internal/usecase/client/same_peer_switch_test.go +5 -5
| @@ -8,8 +8,8 @@ import ( | |||
| 8 | 8 | "github.com/stretchr/testify/require" | |
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/vev/internal/domain" | |
| 11 | - | "github.com/bnema/vev/internal/ports" | |
| 12 | 11 | "github.com/bnema/vev/internal/protocol" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 13 | ) | |
| 14 | 14 | ||
| 15 | 15 | func TestCloseAndDialAttachTargetSkipsSamePeerSwitch(t *testing.T) { | |
| @@ -39,8 +39,8 @@ func TestCloseAndDialAttachTargetSkipsSamePeerSwitch(t *testing.T) { | |||
| 39 | 39 | Session: "stopped", Intent: protocol.IntentAttach, ExactTarget: &exact, | |
| 40 | 40 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | |
| 41 | 41 | } | |
| 42 | - | transport.recvCh <- reconnectToastRecv{frame: ports.Frame{ | |
| 43 | - | Type: ports.MsgAttachTarget, Payload: ports.MarshalAttachTarget(target), | |
| 42 | + | transport.recvCh <- reconnectToastRecv{frame: wire.Frame{ | |
| 43 | + | Type: wire.MsgAttachTarget, Payload: wire.MarshalAttachTarget(target), | |
| 44 | 44 | }} | |
| 45 | 45 | ||
| 46 | 46 | select { | |
| @@ -50,8 +50,8 @@ func TestCloseAndDialAttachTargetSkipsSamePeerSwitch(t *testing.T) { | |||
| 50 | 50 | case <-time.After(time.Second): | |
| 51 | 51 | t.Fatal("close-and-dial target did not return a handoff") | |
| 52 | 52 | } | |
| 53 | - | _, sentSamePeer := transport.sends.find(func(frame ports.Frame) bool { | |
| 54 | - | return frame.Type == ports.MsgSamePeerSwitchRequest | |
| 53 | + | _, sentSamePeer := transport.sends.find(func(frame wire.Frame) bool { | |
| 54 | + | return frame.Type == wire.MsgSamePeerSwitchRequest | |
| 55 | 55 | }) | |
| 56 | 56 | require.False(t, sentSamePeer) | |
| 57 | 57 | } | |
M internal/usecase/client/terminal_input_pump_test.go +23 -22
| @@ -13,6 +13,7 @@ import ( | |||
| 13 | 13 | ||
| 14 | 14 | "github.com/bnema/vev/internal/domain" | |
| 15 | 15 | "github.com/bnema/vev/internal/ports" | |
| 16 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 16 | 17 | ) | |
| 17 | 18 | ||
| 18 | 19 | type lifecycleReader struct { | |
| @@ -81,14 +82,14 @@ func requireSignal(t *testing.T, ch <-chan struct{}, message string) { | |||
| 81 | 82 | } | |
| 82 | 83 | } | |
| 83 | 84 | ||
| 84 | - | func requireFrame(t *testing.T, ch <-chan ports.Frame, message string) ports.Frame { | |
| 85 | + | func requireFrame(t *testing.T, ch <-chan wire.Frame, message string) wire.Frame { | |
| 85 | 86 | t.Helper() | |
| 86 | 87 | select { | |
| 87 | 88 | case frame := <-ch: | |
| 88 | 89 | return frame | |
| 89 | 90 | case <-time.After(time.Second): | |
| 90 | 91 | t.Fatal(message) | |
| 91 | - | return ports.Frame{} | |
| 92 | + | return wire.Frame{} | |
| 92 | 93 | } | |
| 93 | 94 | } | |
| 94 | 95 | ||
| @@ -181,7 +182,7 @@ func TestTerminalInputPumpCancellationHandoffPreservesQueuedBytes(t *testing.T) | |||
| 181 | 182 | go func() { | |
| 182 | 183 | (&stdinPump{ | |
| 183 | 184 | ctx: cancelledCtx, cancel: cancelCancelled, input: input, | |
| 184 | - | out: make(chan ports.Frame, 1), clock: newAttachPaletteClock(), | |
| 185 | + | out: make(chan wire.Frame, 1), clock: newAttachPaletteClock(), | |
| 185 | 186 | logger: slog.New(slog.DiscardHandler), paletteEvents: make(chan paletteGenerationEvent), | |
| 186 | 187 | activeGeneration: &activeGeneration, | |
| 187 | 188 | }).run() | |
| @@ -191,7 +192,7 @@ func TestTerminalInputPumpCancellationHandoffPreservesQueuedBytes(t *testing.T) | |||
| 191 | 192 | ||
| 192 | 193 | replacementCtx, cancelReplacement := context.WithCancel(context.Background()) | |
| 193 | 194 | defer cancelReplacement() | |
| 194 | - | out := make(chan ports.Frame, len(want)) | |
| 195 | + | out := make(chan wire.Frame, len(want)) | |
| 195 | 196 | replacementDone := make(chan struct{}) | |
| 196 | 197 | go func() { | |
| 197 | 198 | (&stdinPump{ | |
| @@ -206,7 +207,7 @@ func TestTerminalInputPumpCancellationHandoffPreservesQueuedBytes(t *testing.T) | |||
| 206 | 207 | var got []byte | |
| 207 | 208 | for len(got) < len(want) { | |
| 208 | 209 | frame := <-out | |
| 209 | - | input, err := ports.UnmarshalInput(frame.Payload) | |
| 210 | + | input, err := wire.UnmarshalInput(frame.Payload) | |
| 210 | 211 | require.NoError(t, err) | |
| 211 | 212 | got = append(got, input.Data...) | |
| 212 | 213 | } | |
| @@ -229,7 +230,7 @@ func TestTerminalInputPumpCancellationAfterTakeRequeuesRawRead(t *testing.T) { | |||
| 229 | 230 | go func() { | |
| 230 | 231 | (&stdinPump{ | |
| 231 | 232 | ctx: ctx, cancel: cancel, input: input, consumer: consumer, | |
| 232 | - | out: make(chan ports.Frame, 1), clock: newAttachPaletteClock(), | |
| 233 | + | out: make(chan wire.Frame, 1), clock: newAttachPaletteClock(), | |
| 233 | 234 | logger: slog.New(slog.DiscardHandler), paletteEvents: make(chan paletteGenerationEvent), | |
| 234 | 235 | afterInputTake: func() { | |
| 235 | 236 | close(taken) | |
| @@ -263,7 +264,7 @@ func TestTerminalInputPumpCancellationPreservesStandaloneEscapeForReplacement(t | |||
| 263 | 264 | oldDone := make(chan struct{}) | |
| 264 | 265 | go func() { | |
| 265 | 266 | (&stdinPump{ | |
| 266 | - | ctx: oldCtx, cancel: cancelOld, input: input, out: make(chan ports.Frame, 1), | |
| 267 | + | ctx: oldCtx, cancel: cancelOld, input: input, out: make(chan wire.Frame, 1), | |
| 267 | 268 | clock: oldClock, logger: slog.New(slog.DiscardHandler), paletteEvents: make(chan paletteGenerationEvent), | |
| 268 | 269 | activeGeneration: &activeGeneration, | |
| 269 | 270 | }).run() | |
| @@ -278,7 +279,7 @@ func TestTerminalInputPumpCancellationPreservesStandaloneEscapeForReplacement(t | |||
| 278 | 279 | newCtx, cancelNew := context.WithCancel(context.Background()) | |
| 279 | 280 | defer cancelNew() | |
| 280 | 281 | newClock := newAttachPaletteClock() | |
| 281 | - | out := make(chan ports.Frame, 1) | |
| 282 | + | out := make(chan wire.Frame, 1) | |
| 282 | 283 | newDone := make(chan struct{}) | |
| 283 | 284 | go func() { | |
| 284 | 285 | (&stdinPump{ | |
| @@ -291,7 +292,7 @@ func TestTerminalInputPumpCancellationPreservesStandaloneEscapeForReplacement(t | |||
| 291 | 292 | (<-newClock.timers).fire() // marker ambiguity deadline | |
| 292 | 293 | (<-newClock.timers).fire() // paste coalescer's lone-ESC deadline | |
| 293 | 294 | frame := <-out | |
| 294 | - | got, err := ports.UnmarshalInput(frame.Payload) | |
| 295 | + | got, err := wire.UnmarshalInput(frame.Payload) | |
| 295 | 296 | require.NoError(t, err) | |
| 296 | 297 | require.Equal(t, []byte("\x1b"), got.Data) | |
| 297 | 298 | ||
| @@ -306,7 +307,7 @@ func TestTerminalInputPumpCancellationAfterInputBeforeOSCPreservesOnlyUndelivere | |||
| 306 | 307 | ctx, cancel := context.WithCancel(context.Background()) | |
| 307 | 308 | delivered := make(chan struct{}) | |
| 308 | 309 | done := make(chan struct{}) | |
| 309 | - | out := make(chan ports.Frame, 1) | |
| 310 | + | out := make(chan wire.Frame, 1) | |
| 310 | 311 | go func() { | |
| 311 | 312 | (&stdinPump{ | |
| 312 | 313 | ctx: ctx, cancel: cancel, input: input, out: out, clock: newAttachPaletteClock(), | |
| @@ -320,14 +321,14 @@ func TestTerminalInputPumpCancellationAfterInputBeforeOSCPreservesOnlyUndelivere | |||
| 320 | 321 | close(done) | |
| 321 | 322 | }() | |
| 322 | 323 | frame := requireFrame(t, out, "timed out waiting for delivered input prefix") | |
| 323 | - | got, err := ports.UnmarshalInput(frame.Payload) | |
| 324 | + | got, err := wire.UnmarshalInput(frame.Payload) | |
| 324 | 325 | require.NoError(t, err) | |
| 325 | 326 | require.Equal(t, []byte("x"), got.Data) | |
| 326 | 327 | requireSignal(t, delivered, "timed out waiting for cancellation after input delivery") | |
| 327 | 328 | requireSignal(t, done, "timed out waiting for cancelled stdin pump") | |
| 328 | 329 | ||
| 329 | 330 | replacementCtx, cancelReplacement := context.WithCancel(context.Background()) | |
| 330 | - | replacementOut := make(chan ports.Frame, 1) | |
| 331 | + | replacementOut := make(chan wire.Frame, 1) | |
| 331 | 332 | replacementDone := make(chan struct{}) | |
| 332 | 333 | go func() { | |
| 333 | 334 | (&stdinPump{ | |
| @@ -339,7 +340,7 @@ func TestTerminalInputPumpCancellationAfterInputBeforeOSCPreservesOnlyUndelivere | |||
| 339 | 340 | close(replacementDone) | |
| 340 | 341 | }() | |
| 341 | 342 | frame = requireFrame(t, replacementOut, "timed out waiting for undelivered input suffix") | |
| 342 | - | got, err = ports.UnmarshalInput(frame.Payload) | |
| 343 | + | got, err = wire.UnmarshalInput(frame.Payload) | |
| 343 | 344 | require.NoError(t, err) | |
| 344 | 345 | require.Equal(t, []byte("y"), got.Data, "replacement must receive only the undelivered ordinary suffix") | |
| 345 | 346 | ||
| @@ -354,7 +355,7 @@ func TestTerminalInputPumpCancellationPreservesCoalescerHeldSuffix(t *testing.T) | |||
| 354 | 355 | input.enqueue(terminalReadResult{data: raw}, 1) | |
| 355 | 356 | var activeGeneration atomic.Uint64 | |
| 356 | 357 | ctx, cancel := context.WithCancel(context.Background()) | |
| 357 | - | out := make(chan ports.Frame, 1) | |
| 358 | + | out := make(chan wire.Frame, 1) | |
| 358 | 359 | done := make(chan struct{}) | |
| 359 | 360 | go func() { | |
| 360 | 361 | (&stdinPump{ | |
| @@ -366,14 +367,14 @@ func TestTerminalInputPumpCancellationPreservesCoalescerHeldSuffix(t *testing.T) | |||
| 366 | 367 | close(done) | |
| 367 | 368 | }() | |
| 368 | 369 | frame := requireFrame(t, out, "timed out waiting for delivered input prefix") | |
| 369 | - | got, err := ports.UnmarshalInput(frame.Payload) | |
| 370 | + | got, err := wire.UnmarshalInput(frame.Payload) | |
| 370 | 371 | require.NoError(t, err) | |
| 371 | 372 | require.Equal(t, []byte("x"), got.Data) | |
| 372 | 373 | requireSignal(t, done, "timed out waiting for cancelled stdin pump") | |
| 373 | 374 | ||
| 374 | 375 | replacementCtx, cancelReplacement := context.WithCancel(context.Background()) | |
| 375 | 376 | replacementClock := newAttachPaletteClock() | |
| 376 | - | replacementOut := make(chan ports.Frame, 1) | |
| 377 | + | replacementOut := make(chan wire.Frame, 1) | |
| 377 | 378 | replacementDone := make(chan struct{}) | |
| 378 | 379 | go func() { | |
| 379 | 380 | (&stdinPump{ | |
| @@ -386,7 +387,7 @@ func TestTerminalInputPumpCancellationPreservesCoalescerHeldSuffix(t *testing.T) | |||
| 386 | 387 | }() | |
| 387 | 388 | requireTimer(t, replacementClock.timers, "timed out waiting for paste-prefix ambiguity timer").fire() | |
| 388 | 389 | frame = requireFrame(t, replacementOut, "timed out waiting for coalescer-held suffix") | |
| 389 | - | got, err = ports.UnmarshalInput(frame.Payload) | |
| 390 | + | got, err = wire.UnmarshalInput(frame.Payload) | |
| 390 | 391 | require.NoError(t, err) | |
| 391 | 392 | require.Equal(t, held, got.Data, "replacement must receive the coalescer-held suffix exactly once") | |
| 392 | 393 | ||
| @@ -424,7 +425,7 @@ func TestTerminalInputPumpCancellationAfterDeliveredCallbackDoesNotReplay(t *tes | |||
| 424 | 425 | ctx, cancel := context.WithCancel(context.Background()) | |
| 425 | 426 | delivered := make(chan struct{}) | |
| 426 | 427 | done := make(chan struct{}) | |
| 427 | - | out := make(chan ports.Frame, 1) | |
| 428 | + | out := make(chan wire.Frame, 1) | |
| 428 | 429 | go func() { | |
| 429 | 430 | (&stdinPump{ | |
| 430 | 431 | ctx: ctx, cancel: cancel, input: input, out: out, clock: newAttachPaletteClock(), | |
| @@ -438,7 +439,7 @@ func TestTerminalInputPumpCancellationAfterDeliveredCallbackDoesNotReplay(t *tes | |||
| 438 | 439 | close(done) | |
| 439 | 440 | }() | |
| 440 | 441 | frame := <-out | |
| 441 | - | got, err := ports.UnmarshalInput(frame.Payload) | |
| 442 | + | got, err := wire.UnmarshalInput(frame.Payload) | |
| 442 | 443 | require.NoError(t, err) | |
| 443 | 444 | require.Equal(t, []byte("x"), got.Data) | |
| 444 | 445 | <-delivered | |
| @@ -463,7 +464,7 @@ func TestTerminalInputPumpReusesOneReaderAcrossCancelledAttempts(t *testing.T) { | |||
| 463 | 464 | go func() { | |
| 464 | 465 | (&stdinPump{ | |
| 465 | 466 | ctx: firstCtx, cancel: cancelFirst, input: input, | |
| 466 | - | out: make(chan ports.Frame), clock: newAttachPaletteClock(), | |
| 467 | + | out: make(chan wire.Frame), clock: newAttachPaletteClock(), | |
| 467 | 468 | logger: slog.New(slog.DiscardHandler), paletteEvents: make(chan paletteGenerationEvent), | |
| 468 | 469 | activeGeneration: &activeGeneration, | |
| 469 | 470 | }).run() | |
| @@ -474,7 +475,7 @@ func TestTerminalInputPumpReusesOneReaderAcrossCancelledAttempts(t *testing.T) { | |||
| 474 | 475 | ||
| 475 | 476 | secondCtx, cancelSecond := context.WithCancel(context.Background()) | |
| 476 | 477 | defer cancelSecond() | |
| 477 | - | out := make(chan ports.Frame, 1) | |
| 478 | + | out := make(chan wire.Frame, 1) | |
| 478 | 479 | secondDone := make(chan struct{}) | |
| 479 | 480 | go func() { | |
| 480 | 481 | (&stdinPump{ | |
| @@ -488,7 +489,7 @@ func TestTerminalInputPumpReusesOneReaderAcrossCancelledAttempts(t *testing.T) { | |||
| 488 | 489 | ||
| 489 | 490 | reader.chunks <- []byte("x") | |
| 490 | 491 | frame := <-out | |
| 491 | - | got, err := ports.UnmarshalInput(frame.Payload) | |
| 492 | + | got, err := wire.UnmarshalInput(frame.Payload) | |
| 492 | 493 | require.NoError(t, err) | |
| 493 | 494 | require.Equal(t, []byte("x"), got.Data) | |
| 494 | 495 | require.Equal(t, 1, reader.maxActive(), "cancelled attempts must not leave competing reads") | |
M internal/usecase/client/transport_observability_test.go +12 -11
| @@ -15,6 +15,7 @@ import ( | |||
| 15 | 15 | "github.com/bnema/vev/internal/ports" | |
| 16 | 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 17 | 17 | "github.com/bnema/vev/internal/protocol" | |
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 18 | 19 | "github.com/bnema/vev/internal/usecase/client" | |
| 19 | 20 | ) | |
| 20 | 21 | ||
| @@ -46,12 +47,12 @@ func TestBlockingRuntimeObserverDoesNotDelayTerminalFlushOrACK(t *testing.T) { | |||
| 46 | 47 | defer reporter.Close() | |
| 47 | 48 | acked := make(chan struct{}) | |
| 48 | 49 | transport := portsmocks.NewMockTransport(t) | |
| 49 | - | transport.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 50 | - | transport.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 51 | - | transport.EXPECT().Send(isType(ports.MsgAck)).Run(func(ports.Frame) { close(acked) }).Return(nil).Once() | |
| 50 | + | transport.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 51 | + | transport.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 52 | + | transport.EXPECT().Send(isType(wire.MsgAck)).Run(func(wire.Frame) { close(acked) }).Return(nil).Once() | |
| 52 | 53 | unblock := scriptRecv(transport, | |
| 53 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 54 | - | recvItem{f: frameOf(ports.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("flush-before-observe"), New: 3}))}, | |
| 54 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 55 | + | recvItem{f: frameOf(wire.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("flush-before-observe"), New: 3}))}, | |
| 55 | 56 | ) | |
| 56 | 57 | defer unblock() | |
| 57 | 58 | transport.EXPECT().Close().Return(nil).Once() | |
| @@ -87,15 +88,15 @@ func TestTerminalFlushBoundaryTransportObservability(t *testing.T) { | |||
| 87 | 88 | reporter := ports.NewSerializedRuntimeObserver(observer, 64) | |
| 88 | 89 | defer reporter.Close() | |
| 89 | 90 | transport := portsmocks.NewMockTransport(t) | |
| 90 | - | transport.EXPECT().Send(isType(ports.MsgHello)).Return(nil).Once() | |
| 91 | - | transport.EXPECT().Send(isType(ports.MsgTheme)).Return(nil).Maybe() | |
| 91 | + | transport.EXPECT().Send(isType(wire.MsgHello)).Return(nil).Once() | |
| 92 | + | transport.EXPECT().Send(isType(wire.MsgTheme)).Return(nil).Maybe() | |
| 92 | 93 | unblock := scriptRecv(transport, | |
| 93 | - | recvItem{f: frameOf(ports.MsgWelcome, ports.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 94 | - | recvItem{f: frameOf(ports.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("unchanged-by-observer"), New: 3}))}, | |
| 95 | - | recvItem{f: frameOf(ports.MsgDetached, ports.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 94 | + | recvItem{f: frameOf(wire.MsgWelcome, wire.MarshalWelcome(protocol.Welcome{SessionID: "s1"}))}, | |
| 95 | + | recvItem{f: frameOf(wire.MsgOutput, mustMarshalOutput(protocol.Output{Epoch: 1, Size: domain.Size{Cols: 1, Rows: 1}, Full: true, Data: []byte("unchanged-by-observer"), New: 3}))}, | |
| 96 | + | recvItem{f: frameOf(wire.MsgDetached, wire.MarshalDetached(protocol.Detached{Reason: protocol.ReasonDetach}))}, | |
| 96 | 97 | ) | |
| 97 | 98 | defer unblock() | |
| 98 | - | transport.EXPECT().Send(isType(ports.MsgAck)).Return(nil).Maybe() | |
| 99 | + | transport.EXPECT().Send(isType(wire.MsgAck)).Return(nil).Maybe() | |
| 99 | 100 | transport.EXPECT().Close().Return(nil).Once() | |
| 100 | 101 | ||
| 101 | 102 | err := runTestClient(context.Background(), testDependencies(transportDialer{transport: transport}, term, realClock{}, nil, reporter), client.AttachRequest{Intent: protocol.IntentEphemeral}) | |
M internal/usecase/client/wire_external_test_helpers_test.go +2 -2
| @@ -1,12 +1,12 @@ | |||
| 1 | 1 | package client_test | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | - | "github.com/bnema/vev/internal/ports" | |
| 5 | 4 | "github.com/bnema/vev/internal/protocol" | |
| 5 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 6 | 6 | ) | |
| 7 | 7 | ||
| 8 | 8 | func mustMarshalOutput(m protocol.Output) []byte { | |
| 9 | - | payload, err := ports.MarshalOutput(m) | |
| 9 | + | payload, err := wire.MarshalOutput(m) | |
| 10 | 10 | if err != nil { | |
| 11 | 11 | panic(err) | |
| 12 | 12 | } | |
M internal/usecase/client/wire_test_helpers_test.go +2 -2
| @@ -1,12 +1,12 @@ | |||
| 1 | 1 | package client | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | - | "github.com/bnema/vev/internal/ports" | |
| 5 | 4 | "github.com/bnema/vev/internal/protocol" | |
| 5 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 6 | 6 | ) | |
| 7 | 7 | ||
| 8 | 8 | func mustMarshalOutput(m protocol.Output) []byte { | |
| 9 | - | payload, err := ports.MarshalOutput(m) | |
| 9 | + | payload, err := wire.MarshalOutput(m) | |
| 10 | 10 | if err != nil { | |
| 11 | 11 | panic(err) | |
| 12 | 12 | } | |
M internal/usecase/daemon/attachment_effect_gate.go +2 -1
| @@ -6,6 +6,7 @@ import ( | |||
| 6 | 6 | "sync/atomic" | |
| 7 | 7 | ||
| 8 | 8 | "github.com/bnema/vev/internal/ports" | |
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 9 | 10 | ) | |
| 10 | 11 | ||
| 11 | 12 | type attachmentEffectPhase uint8 | |
| @@ -188,7 +189,7 @@ func (t *attachmentEffect) endTransportSend() { | |||
| 188 | 189 | g.mu.Unlock() | |
| 189 | 190 | } | |
| 190 | 191 | ||
| 191 | - | func (t *attachmentEffect) sendControl(frame ports.Frame) error { | |
| 192 | + | func (t *attachmentEffect) sendControl(frame wire.Frame) error { | |
| 192 | 193 | if !t.current() || t.ac == nil || t.transport.transport == nil { | |
| 193 | 194 | return errAttachmentTransition | |
| 194 | 195 | } | |
M internal/usecase/daemon/attachment_effect_gate_test.go +17 -17
| @@ -11,8 +11,8 @@ import ( | |||
| 11 | 11 | ||
| 12 | 12 | renderer "github.com/bnema/vev-vt" | |
| 13 | 13 | "github.com/bnema/vev/internal/domain" | |
| 14 | - | "github.com/bnema/vev/internal/ports" | |
| 15 | 14 | "github.com/bnema/vev/internal/protocol" | |
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 16 | 16 | "github.com/bnema/vev/internal/usecase/keys" | |
| 17 | 17 | ) | |
| 18 | 18 | ||
| @@ -44,14 +44,14 @@ func newBlockedRenderReplacementTransport(d *Daemon, sess *session) *blockedRend | |||
| 44 | 44 | } | |
| 45 | 45 | } | |
| 46 | 46 | ||
| 47 | - | func (t *blockedRenderReplacementTransport) Send(ports.Frame) error { | |
| 47 | + | func (t *blockedRenderReplacementTransport) Send(wire.Frame) error { | |
| 48 | 48 | t.sendOnce.Do(func() { close(t.sendEntered) }) | |
| 49 | 49 | <-t.closed | |
| 50 | 50 | return errors.New("transport closed") | |
| 51 | 51 | } | |
| 52 | 52 | ||
| 53 | - | func (*blockedRenderReplacementTransport) Recv() (ports.Frame, error) { | |
| 54 | - | return ports.Frame{}, io.EOF | |
| 53 | + | func (*blockedRenderReplacementTransport) Recv() (wire.Frame, error) { | |
| 54 | + | return wire.Frame{}, io.EOF | |
| 55 | 55 | } | |
| 56 | 56 | ||
| 57 | 57 | func (t *blockedRenderReplacementTransport) Close() error { | |
| @@ -97,13 +97,13 @@ func newTeardownBlockingTransport() *teardownBlockingTransport { | |||
| 97 | 97 | return &teardownBlockingTransport{sendEntered: make(chan struct{}), closed: make(chan struct{})} | |
| 98 | 98 | } | |
| 99 | 99 | ||
| 100 | - | func (t *teardownBlockingTransport) Send(ports.Frame) error { | |
| 100 | + | func (t *teardownBlockingTransport) Send(wire.Frame) error { | |
| 101 | 101 | t.sendOnce.Do(func() { close(t.sendEntered) }) | |
| 102 | 102 | <-t.closed | |
| 103 | 103 | return errors.New("transport closed") | |
| 104 | 104 | } | |
| 105 | 105 | ||
| 106 | - | func (*teardownBlockingTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 106 | + | func (*teardownBlockingTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 107 | 107 | ||
| 108 | 108 | func (t *teardownBlockingTransport) Close() error { | |
| 109 | 109 | t.closeOnce.Do(func() { close(t.closed) }) | |
| @@ -568,7 +568,7 @@ func TestAttachmentEffectGateAdmittedActiveEffectsFinishBeforeReplacement(t *tes | |||
| 568 | 568 | tests := []struct { | |
| 569 | 569 | name string | |
| 570 | 570 | setup func(*Daemon, *session, *attachedClient, *transactionalResizePTY) | |
| 571 | - | frame ports.Frame | |
| 571 | + | frame wire.Frame | |
| 572 | 572 | assert func(*testing.T, *attachedClient, *transactionalResizePTY) | |
| 573 | 573 | }{ | |
| 574 | 574 | { | |
| @@ -612,7 +612,7 @@ func TestAttachmentEffectGateAdmittedActiveEffectsFinishBeforeReplacement(t *tes | |||
| 612 | 612 | }, | |
| 613 | 613 | { | |
| 614 | 614 | name: "theme", | |
| 615 | - | frame: ports.Frame{Type: ports.MsgTheme, Payload: ports.MarshalTheme(protocol.Theme{ | |
| 615 | + | frame: wire.Frame{Type: wire.MsgTheme, Payload: wire.MarshalTheme(protocol.Theme{ | |
| 616 | 616 | HasForeground: true, Foreground: renderer.RGB{R: 1, G: 2, B: 3}, | |
| 617 | 617 | HasBackground: true, Background: renderer.RGB{R: 4, G: 5, B: 6}, | |
| 618 | 618 | })}, | |
| @@ -625,7 +625,7 @@ func TestAttachmentEffectGateAdmittedActiveEffectsFinishBeforeReplacement(t *tes | |||
| 625 | 625 | setup: func(_ *Daemon, _ *session, ac *attachedClient, _ *transactionalResizePTY) { | |
| 626 | 626 | ac.output.next = 3 | |
| 627 | 627 | }, | |
| 628 | - | frame: ports.Frame{Type: ports.MsgAck, Payload: mustMarshalAck(protocol.Ack{Epoch: 1, State: 1})}, | |
| 628 | + | frame: wire.Frame{Type: wire.MsgAck, Payload: mustMarshalAck(protocol.Ack{Epoch: 1, State: 1})}, | |
| 629 | 629 | assert: func(t *testing.T, ac *attachedClient, _ *transactionalResizePTY) { | |
| 630 | 630 | ac.sendMu.Lock() | |
| 631 | 631 | defer ac.sendMu.Unlock() | |
| @@ -697,10 +697,10 @@ func TestAttachedRouteSnapshotIsAcceptedAsAnAttachmentValue(t *testing.T) { | |||
| 697 | 697 | Home: activeRef, | |
| 698 | 698 | Entries: []protocol.RecentRouteEntry{testRouteEntry(7, 3, "previous", 7, protocol.RouteKindLocal)}, | |
| 699 | 699 | } | |
| 700 | - | payload, err := ports.MarshalRecentRouteSnapshot(snapshot) | |
| 700 | + | payload, err := wire.MarshalRecentRouteSnapshot(snapshot) | |
| 701 | 701 | require.NoError(t, err) | |
| 702 | 702 | ||
| 703 | - | require.False(t, d.handleAttachmentClientFrame(token, ports.Frame{Type: ports.MsgRecentRouteSnapshot, Payload: payload})) | |
| 703 | + | require.False(t, d.handleAttachmentClientFrame(token, wire.Frame{Type: wire.MsgRecentRouteSnapshot, Payload: payload})) | |
| 704 | 704 | require.Equal(t, snapshot, ac.routeSnapshotCopy()) | |
| 705 | 705 | } | |
| 706 | 706 | ||
| @@ -726,31 +726,31 @@ func TestAttachedNavigationCommandSendsResultAfterLocalTransition(t *testing.T) | |||
| 726 | 726 | token := source.captureAttachmentCapability(ac, transport) | |
| 727 | 727 | token.lease = rc.attachmentLease(ac) | |
| 728 | 728 | ac.installTestAttachmentCapability(token) | |
| 729 | - | payload, err := ports.MarshalCommandRequest(protocol.CommandRequest{ | |
| 729 | + | payload, err := wire.MarshalCommandRequest(protocol.CommandRequest{ | |
| 730 | 730 | Version: protocol.Version, RequestID: 1, Slug: "back-session", Attached: true, | |
| 731 | 731 | }) | |
| 732 | 732 | require.NoError(t, err) | |
| 733 | 733 | ||
| 734 | - | require.False(t, d.handleAttachmentClientFrame(token, ports.Frame{Type: ports.MsgCommand, Payload: payload})) | |
| 734 | + | require.False(t, d.handleAttachmentClientFrame(token, wire.Frame{Type: wire.MsgCommand, Payload: payload})) | |
| 735 | 735 | require.Same(t, source, ac.currentAttachmentSession()) | |
| 736 | 736 | frames := transport.Sends() | |
| 737 | 737 | require.NotEmpty(t, frames) | |
| 738 | 738 | var result protocol.CommandResult | |
| 739 | 739 | for _, frame := range frames { | |
| 740 | - | if frame.Type != ports.MsgCommandResult { | |
| 740 | + | if frame.Type != wire.MsgCommandResult { | |
| 741 | 741 | continue | |
| 742 | 742 | } | |
| 743 | - | result, err = ports.UnmarshalCommandResult(frame.Payload) | |
| 743 | + | result, err = wire.UnmarshalCommandResult(frame.Payload) | |
| 744 | 744 | require.NoError(t, err) | |
| 745 | 745 | break | |
| 746 | 746 | } | |
| 747 | 747 | require.True(t, result.OK, result.Text) | |
| 748 | 748 | var action protocol.RouteNavigationAction | |
| 749 | 749 | for _, frame := range frames { | |
| 750 | - | if frame.Type != ports.MsgNavigateRecentRoute { | |
| 750 | + | if frame.Type != wire.MsgNavigateRecentRoute { | |
| 751 | 751 | continue | |
| 752 | 752 | } | |
| 753 | - | action, err = ports.UnmarshalRouteNavigationAction(frame.Payload) | |
| 753 | + | action, err = wire.UnmarshalRouteNavigationAction(frame.Payload) | |
| 754 | 754 | require.NoError(t, err) | |
| 755 | 755 | } | |
| 756 | 756 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 2, Key: 1, Generation: 1}, action) | |
M internal/usecase/daemon/attachment_output.go +10 -9
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | 10 | "github.com/bnema/vev/internal/domain" | |
| 11 | 11 | "github.com/bnema/vev/internal/ports" | |
| 12 | 12 | "github.com/bnema/vev/internal/protocol" | |
| 13 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 14 | ) | |
| 14 | 15 | ||
| 15 | 16 | // attachmentOutput owns the terminal-output dependency chain and emitted | |
| @@ -153,13 +154,13 @@ func (o *attachmentOutput) prepareFrame(d *Daemon, state *capturedRenderState, f | |||
| 153 | 154 | return &preparedAttachmentOutput{output: o, ansi: ansi, graphics: preparedGraphics, cursor: cursor, data: data}, nil | |
| 154 | 155 | } | |
| 155 | 156 | ||
| 156 | - | func (p *preparedAttachmentOutput) send(echoAck uint64, send func(ports.Frame) error) error { | |
| 157 | + | func (p *preparedAttachmentOutput) send(echoAck uint64, send func(wire.Frame) error) error { | |
| 157 | 158 | if p == nil || p.ansi == nil { | |
| 158 | 159 | return nil | |
| 159 | 160 | } | |
| 160 | 161 | sendFrame := send | |
| 161 | 162 | if p.graphics != nil { | |
| 162 | - | sendFrame = func(frame ports.Frame) error { | |
| 163 | + | sendFrame = func(frame wire.Frame) error { | |
| 163 | 164 | p.graphics.markSendAttempted() | |
| 164 | 165 | return send(frame) | |
| 165 | 166 | } | |
| @@ -285,7 +286,7 @@ func (s *attachmentOutput) prepare(frame renderer.Frame, damage []renderer.Damag | |||
| 285 | 286 | }, nil | |
| 286 | 287 | } | |
| 287 | 288 | ||
| 288 | - | func (p *preparedOutput) send(data []byte, echoAck uint64, send func(ports.Frame) error) error { | |
| 289 | + | func (p *preparedOutput) send(data []byte, echoAck uint64, send func(wire.Frame) error) error { | |
| 289 | 290 | if p == nil || p.stream == nil || p.attempted { | |
| 290 | 291 | return nil | |
| 291 | 292 | } | |
| @@ -379,21 +380,21 @@ func (p *preparedOutput) currentLocked() bool { | |||
| 379 | 380 | (p.stream.attachment == nil || p.stream.attachment.lifecycle.generationValue() == p.connectionGeneration) | |
| 380 | 381 | } | |
| 381 | 382 | ||
| 382 | - | func marshalOutputState(data []byte, epoch, base, next, echoAck, viewRevision uint64, size domain.Size, full bool) (ports.Frame, error) { | |
| 383 | - | payload, err := ports.MarshalOutput(protocol.Output{ | |
| 383 | + | func marshalOutputState(data []byte, epoch, base, next, echoAck, viewRevision uint64, size domain.Size, full bool) (wire.Frame, error) { | |
| 384 | + | payload, err := wire.MarshalOutput(protocol.Output{ | |
| 384 | 385 | Epoch: epoch, Base: base, New: next, Echo: echoAck, ViewRevision: viewRevision, | |
| 385 | 386 | Size: size, Full: full, Data: data, | |
| 386 | 387 | }) | |
| 387 | 388 | if err != nil { | |
| 388 | - | return ports.Frame{}, err | |
| 389 | + | return wire.Frame{}, err | |
| 389 | 390 | } | |
| 390 | - | return ports.Frame{Type: ports.MsgOutput, Payload: payload}, nil | |
| 391 | + | return wire.Frame{Type: wire.MsgOutput, Payload: payload}, nil | |
| 391 | 392 | } | |
| 392 | 393 | ||
| 393 | 394 | // sideEffect builds an output frame without advancing the state stream. When | |
| 394 | 395 | // an attachment is present, callers must hold its sendMu; attachment-bound | |
| 395 | 396 | // sends use sideEffectLocked after validating their transport incarnation. | |
| 396 | - | func (s *attachmentOutput) sideEffect(data []byte, echoAck uint64) (ports.Frame, error) { | |
| 397 | + | func (s *attachmentOutput) sideEffect(data []byte, echoAck uint64) (wire.Frame, error) { | |
| 397 | 398 | s.lockView() | |
| 398 | 399 | defer s.unlockView() | |
| 399 | 400 | return s.sideEffectLocked(data, echoAck) | |
| @@ -402,7 +403,7 @@ func (s *attachmentOutput) sideEffect(data []byte, echoAck uint64) (ports.Frame, | |||
| 402 | 403 | // sideEffectLocked requires the attachment view lock for both frame creation | |
| 403 | 404 | // and transport emission. Keeping that lock across the send prevents a view | |
| 404 | 405 | // publication from overtaking a frame that was fenced just before it. | |
| 405 | - | func (s *attachmentOutput) sideEffectLocked(data []byte, echoAck uint64) (ports.Frame, error) { | |
| 406 | + | func (s *attachmentOutput) sideEffectLocked(data []byte, echoAck uint64) (wire.Frame, error) { | |
| 406 | 407 | _, epoch, viewRevision := s.fenceLocked() | |
| 407 | 408 | size := domain.Size{Cols: 1, Rows: 1} | |
| 408 | 409 | if s != nil && s.attachment != nil { | |
M internal/usecase/daemon/attachment_output_test.go +32 -31
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | 11 | "github.com/bnema/vev/internal/domain" | |
| 12 | 12 | "github.com/bnema/vev/internal/ports" | |
| 13 | 13 | "github.com/bnema/vev/internal/protocol" | |
| 14 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 14 | 15 | "github.com/bnema/vev/internal/usecase/layout" | |
| 15 | 16 | "github.com/stretchr/testify/require" | |
| 16 | 17 | ) | |
| @@ -22,7 +23,7 @@ func TestAttachmentOutputBuildsPipelinedDependencyChain(t *testing.T) { | |||
| 22 | 23 | first, ok, err := drawOutputState(t, stream, firstFrame, nil, true, 7) | |
| 23 | 24 | require.NoError(t, err) | |
| 24 | 25 | require.True(t, ok) | |
| 25 | - | firstOut, err := ports.UnmarshalOutput(first.Payload) | |
| 26 | + | firstOut, err := wire.UnmarshalOutput(first.Payload) | |
| 26 | 27 | require.NoError(t, err) | |
| 27 | 28 | require.Equal(t, uint64(0), firstOut.Base) | |
| 28 | 29 | require.Equal(t, uint64(1), firstOut.New) | |
| @@ -33,7 +34,7 @@ func TestAttachmentOutputBuildsPipelinedDependencyChain(t *testing.T) { | |||
| 33 | 34 | second, ok, err := drawOutputState(t, stream, secondFrame, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false, 8) | |
| 34 | 35 | require.NoError(t, err) | |
| 35 | 36 | require.True(t, ok) | |
| 36 | - | secondOut, err := ports.UnmarshalOutput(second.Payload) | |
| 37 | + | secondOut, err := wire.UnmarshalOutput(second.Payload) | |
| 37 | 38 | require.NoError(t, err) | |
| 38 | 39 | require.Equal(t, firstOut.New, secondOut.Base) | |
| 39 | 40 | require.Equal(t, uint64(2), secondOut.New) | |
| @@ -91,7 +92,7 @@ func TestAttachmentOutputCapacityProbeDoesNotRaceWithSend(t *testing.T) { | |||
| 91 | 92 | release := make(chan struct{}) | |
| 92 | 93 | sendDone := make(chan error, 1) | |
| 93 | 94 | go func() { | |
| 94 | - | sendDone <- prepared.send(prepared.data, 0, func(ports.Frame) error { | |
| 95 | + | sendDone <- prepared.send(prepared.data, 0, func(wire.Frame) error { | |
| 95 | 96 | close(entered) | |
| 96 | 97 | <-release | |
| 97 | 98 | return nil | |
| @@ -132,12 +133,12 @@ func TestAttachmentOutputEpochsAreAttachmentLocalAndPreparedFramesAreFenced(t *t | |||
| 132 | 133 | second := newAttachment() | |
| 133 | 134 | firstPrepared, err := first.prepare(frame, nil, true) | |
| 134 | 135 | require.NoError(t, err) | |
| 135 | - | var firstFrame ports.Frame | |
| 136 | - | require.NoError(t, firstPrepared.send(firstPrepared.data, 0, func(frame ports.Frame) error { | |
| 136 | + | var firstFrame wire.Frame | |
| 137 | + | require.NoError(t, firstPrepared.send(firstPrepared.data, 0, func(frame wire.Frame) error { | |
| 137 | 138 | firstFrame = frame | |
| 138 | 139 | return nil | |
| 139 | 140 | })) | |
| 140 | - | firstOutput, err := ports.UnmarshalOutput(firstFrame.Payload) | |
| 141 | + | firstOutput, err := wire.UnmarshalOutput(firstFrame.Payload) | |
| 141 | 142 | require.NoError(t, err) | |
| 142 | 143 | require.Equal(t, uint64(1), firstOutput.Epoch) | |
| 143 | 144 | require.Equal(t, uint64(1), firstOutput.New) | |
| @@ -146,7 +147,7 @@ func TestAttachmentOutputEpochsAreAttachmentLocalAndPreparedFramesAreFenced(t *t | |||
| 146 | 147 | ||
| 147 | 148 | secondPrepared, err := second.prepare(frame, nil, true) | |
| 148 | 149 | require.NoError(t, err) | |
| 149 | - | require.NoError(t, secondPrepared.send(secondPrepared.data, 0, func(ports.Frame) error { return nil })) | |
| 150 | + | require.NoError(t, secondPrepared.send(secondPrepared.data, 0, func(wire.Frame) error { return nil })) | |
| 150 | 151 | require.Equal(t, uint64(1), second.epoch) | |
| 151 | 152 | require.Equal(t, uint64(1), second.next) | |
| 152 | 153 | require.Equal(t, uint64(1), first.next) | |
| @@ -160,7 +161,7 @@ func TestAttachmentOutputEpochsAreAttachmentLocalAndPreparedFramesAreFenced(t *t | |||
| 160 | 161 | require.Zero(t, first.next) | |
| 161 | 162 | require.Zero(t, first.acked) | |
| 162 | 163 | var staleSent bool | |
| 163 | - | require.NoError(t, pending.send(pending.data, 0, func(ports.Frame) error { | |
| 164 | + | require.NoError(t, pending.send(pending.data, 0, func(wire.Frame) error { | |
| 164 | 165 | staleSent = true | |
| 165 | 166 | return nil | |
| 166 | 167 | })) | |
| @@ -171,12 +172,12 @@ func TestAttachmentOutputEpochsAreAttachmentLocalAndPreparedFramesAreFenced(t *t | |||
| 171 | 172 | ||
| 172 | 173 | reset, err := first.prepare(changed, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false) | |
| 173 | 174 | require.NoError(t, err) | |
| 174 | - | var resetFrame ports.Frame | |
| 175 | - | require.NoError(t, reset.send(reset.data, 0, func(frame ports.Frame) error { | |
| 175 | + | var resetFrame wire.Frame | |
| 176 | + | require.NoError(t, reset.send(reset.data, 0, func(frame wire.Frame) error { | |
| 176 | 177 | resetFrame = frame | |
| 177 | 178 | return nil | |
| 178 | 179 | })) | |
| 179 | - | resetOutput, err := ports.UnmarshalOutput(resetFrame.Payload) | |
| 180 | + | resetOutput, err := wire.UnmarshalOutput(resetFrame.Payload) | |
| 180 | 181 | require.NoError(t, err) | |
| 181 | 182 | require.Equal(t, uint64(2), resetOutput.Epoch) | |
| 182 | 183 | require.Zero(t, resetOutput.Base) | |
| @@ -204,14 +205,14 @@ func TestPreparedOutputDropsReplacedConnectionAndView(t *testing.T) { | |||
| 204 | 205 | fillOutputStateRows(frame, []string{"abc"}) | |
| 205 | 206 | initial, err := stream.prepare(frame, nil, true) | |
| 206 | 207 | require.NoError(t, err) | |
| 207 | - | require.NoError(t, initial.send(initial.data, 0, func(ports.Frame) error { return nil })) | |
| 208 | + | require.NoError(t, initial.send(initial.data, 0, func(wire.Frame) error { return nil })) | |
| 208 | 209 | changed := frame.Clone() | |
| 209 | 210 | changed.Set(0, 0, renderer.Cell{Rune: 'x', Style: renderer.DefaultStyle()}) | |
| 210 | 211 | pending, err := stream.prepare(changed, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false) | |
| 211 | 212 | require.NoError(t, err) | |
| 212 | 213 | tt.change(ac) | |
| 213 | 214 | var sent bool | |
| 214 | - | require.NoError(t, pending.send(pending.data, 0, func(ports.Frame) error { | |
| 215 | + | require.NoError(t, pending.send(pending.data, 0, func(wire.Frame) error { | |
| 215 | 216 | sent = true | |
| 216 | 217 | return nil | |
| 217 | 218 | })) | |
| @@ -220,7 +221,7 @@ func TestPreparedOutputDropsReplacedConnectionAndView(t *testing.T) { | |||
| 220 | 221 | ||
| 221 | 222 | retry, err := stream.prepare(changed, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false) | |
| 222 | 223 | require.NoError(t, err) | |
| 223 | - | require.NoError(t, retry.send(retry.data, 0, func(ports.Frame) error { return nil })) | |
| 224 | + | require.NoError(t, retry.send(retry.data, 0, func(wire.Frame) error { return nil })) | |
| 224 | 225 | require.Equal(t, uint64(2), stream.next) | |
| 225 | 226 | }) | |
| 226 | 227 | } | |
| @@ -243,7 +244,7 @@ func TestOutputStateSideEffectsDoNotAdvanceEpochStateOrACK(t *testing.T) { | |||
| 243 | 244 | beforeEpoch, beforeNext, beforeAck := stream.epoch, stream.next, stream.acked | |
| 244 | 245 | frame, err := stream.sideEffect([]byte("pty"), 9) | |
| 245 | 246 | require.NoError(t, err) | |
| 246 | - | out, err := ports.UnmarshalOutput(frame.Payload) | |
| 247 | + | out, err := wire.UnmarshalOutput(frame.Payload) | |
| 247 | 248 | require.NoError(t, err) | |
| 248 | 249 | require.Equal(t, beforeEpoch, out.Epoch) | |
| 249 | 250 | require.Zero(t, out.Base) | |
| @@ -260,7 +261,7 @@ func TestAttachmentOutputFailedSendRetriesSnapshotWithoutAdvancing(t *testing.T) | |||
| 260 | 261 | fillOutputStateRows(initial, []string{"abc"}) | |
| 261 | 262 | first, err := stream.prepare(initial, nil, true) | |
| 262 | 263 | require.NoError(t, err) | |
| 263 | - | require.NoError(t, first.send(first.data, 0, func(ports.Frame) error { return nil })) | |
| 264 | + | require.NoError(t, first.send(first.data, 0, func(wire.Frame) error { return nil })) | |
| 264 | 265 | require.Equal(t, uint64(1), stream.next) | |
| 265 | 266 | ||
| 266 | 267 | changed := initial.Clone() | |
| @@ -272,7 +273,7 @@ func TestAttachmentOutputFailedSendRetriesSnapshotWithoutAdvancing(t *testing.T) | |||
| 272 | 273 | require.Empty(t, probe.Bytes(), "preparation must not advance the renderer shadow") | |
| 273 | 274 | ||
| 274 | 275 | sendErr := errors.New("send failed") | |
| 275 | - | require.ErrorIs(t, pending.send(pending.data, 0, func(ports.Frame) error { return sendErr }), sendErr) | |
| 276 | + | require.ErrorIs(t, pending.send(pending.data, 0, func(wire.Frame) error { return sendErr }), sendErr) | |
| 276 | 277 | require.Equal(t, uint64(1), stream.next, "failed send must not advance the state chain") | |
| 277 | 278 | pending.commitNoSend() | |
| 278 | 279 | probe, err = stream.renderer.Prepare(initial, nil, false) | |
| @@ -281,17 +282,17 @@ func TestAttachmentOutputFailedSendRetriesSnapshotWithoutAdvancing(t *testing.T) | |||
| 281 | 282 | ||
| 282 | 283 | retry, err := stream.prepare(changed, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false) | |
| 283 | 284 | require.NoError(t, err) | |
| 284 | - | var sent ports.Frame | |
| 285 | - | require.NoError(t, retry.send(retry.data, 0, func(frame ports.Frame) error { | |
| 285 | + | var sent wire.Frame | |
| 286 | + | require.NoError(t, retry.send(retry.data, 0, func(frame wire.Frame) error { | |
| 286 | 287 | sent = frame | |
| 287 | 288 | return nil | |
| 288 | 289 | })) | |
| 289 | - | out, err := ports.UnmarshalOutput(sent.Payload) | |
| 290 | + | out, err := wire.UnmarshalOutput(sent.Payload) | |
| 290 | 291 | require.NoError(t, err) | |
| 291 | 292 | require.Zero(t, out.Base, "retry after ambiguous send failure must be dependency-free") | |
| 292 | 293 | require.Equal(t, uint64(2), out.New, "state numbers remain monotonic across rebases") | |
| 293 | 294 | require.Equal(t, uint64(2), stream.next, "successful retry advances the chain exactly once") | |
| 294 | - | require.NoError(t, retry.send(retry.data, 0, func(ports.Frame) error { | |
| 295 | + | require.NoError(t, retry.send(retry.data, 0, func(wire.Frame) error { | |
| 295 | 296 | t.Fatal("completed output sent twice") | |
| 296 | 297 | return nil | |
| 297 | 298 | })) | |
| @@ -307,7 +308,7 @@ func TestAttachmentOutputNoByteCommitAdvancesShadowWithoutState(t *testing.T) { | |||
| 307 | 308 | fillOutputStateRows(frame, []string{"abc"}) | |
| 308 | 309 | initial, err := stream.prepare(frame, nil, true) | |
| 309 | 310 | require.NoError(t, err) | |
| 310 | - | require.NoError(t, initial.send(initial.data, 0, func(ports.Frame) error { return nil })) | |
| 311 | + | require.NoError(t, initial.send(initial.data, 0, func(wire.Frame) error { return nil })) | |
| 311 | 312 | ||
| 312 | 313 | noOp, err := stream.prepare(frame, nil, false) | |
| 313 | 314 | require.NoError(t, err) | |
| @@ -371,7 +372,7 @@ func (s *attachmentOutput) render(frame renderer.Frame, damage []renderer.Damage | |||
| 371 | 372 | return prepared.data, nil | |
| 372 | 373 | } | |
| 373 | 374 | ||
| 374 | - | func outputStateFrame(stream *attachmentOutput, data []byte, reset bool, echoAck uint64) ports.Frame { | |
| 375 | + | func outputStateFrame(stream *attachmentOutput, data []byte, reset bool, echoAck uint64) wire.Frame { | |
| 375 | 376 | stream.next++ | |
| 376 | 377 | base := stream.next - 1 | |
| 377 | 378 | if reset { | |
| @@ -384,22 +385,22 @@ func outputStateFrame(stream *attachmentOutput, data []byte, reset bool, echoAck | |||
| 384 | 385 | return frame | |
| 385 | 386 | } | |
| 386 | 387 | ||
| 387 | - | func drawOutputState(t *testing.T, stream *attachmentOutput, frame renderer.Frame, damage []renderer.Damage, reset bool, echoAck uint64) (ports.Frame, bool, error) { | |
| 388 | + | func drawOutputState(t *testing.T, stream *attachmentOutput, frame renderer.Frame, damage []renderer.Damage, reset bool, echoAck uint64) (wire.Frame, bool, error) { | |
| 388 | 389 | t.Helper() | |
| 389 | 390 | prepared, err := stream.prepare(frame, damage, reset) | |
| 390 | 391 | if err != nil || len(prepared.data) == 0 { | |
| 391 | 392 | if prepared != nil { | |
| 392 | 393 | prepared.commitNoSend() | |
| 393 | 394 | } | |
| 394 | - | return ports.Frame{}, false, err | |
| 395 | + | return wire.Frame{}, false, err | |
| 395 | 396 | } | |
| 396 | - | var output ports.Frame | |
| 397 | - | err = prepared.send(prepared.data, echoAck, func(frame ports.Frame) error { | |
| 397 | + | var output wire.Frame | |
| 398 | + | err = prepared.send(prepared.data, echoAck, func(frame wire.Frame) error { | |
| 398 | 399 | output = frame | |
| 399 | 400 | return nil | |
| 400 | 401 | }) | |
| 401 | 402 | if err != nil { | |
| 402 | - | return ports.Frame{}, false, err | |
| 403 | + | return wire.Frame{}, false, err | |
| 403 | 404 | } | |
| 404 | 405 | return output, true, nil | |
| 405 | 406 | } | |
| @@ -416,7 +417,7 @@ func TestAttachmentOutputResizeFrameThenNoopAndDamageAreDifferential(t *testing. | |||
| 416 | 417 | resized, ok, err := drawOutputState(t, stream, screen.Frame, screen.Damage(), true, 0) | |
| 417 | 418 | require.NoError(t, err) | |
| 418 | 419 | require.True(t, ok) | |
| 419 | - | resizeOutput, err := ports.UnmarshalOutput(resized.Payload) | |
| 420 | + | resizeOutput, err := wire.UnmarshalOutput(resized.Payload) | |
| 420 | 421 | require.NoError(t, err) | |
| 421 | 422 | require.Zero(t, resizeOutput.Base, "resize must emit the one reset frame") | |
| 422 | 423 | screen.ClearDamage() | |
| @@ -429,7 +430,7 @@ func TestAttachmentOutputResizeFrameThenNoopAndDamageAreDifferential(t *testing. | |||
| 429 | 430 | damaged, ok, err := drawOutputState(t, stream, screen.Frame, []renderer.Damage{{Kind: renderer.DamageText, Width: 1, Height: 1}}, false, 0) | |
| 430 | 431 | require.NoError(t, err) | |
| 431 | 432 | require.True(t, ok) | |
| 432 | - | damageOutput, err := ports.UnmarshalOutput(damaged.Payload) | |
| 433 | + | damageOutput, err := wire.UnmarshalOutput(damaged.Payload) | |
| 433 | 434 | require.NoError(t, err) | |
| 434 | 435 | require.Equal(t, resizeOutput.New, damageOutput.Base, "later damage must remain incremental") | |
| 435 | 436 | } | |
| @@ -455,7 +456,7 @@ func TestAttachmentOutputFailedSendKeepsTextCursorAndGraphicsSpeculative(t *test | |||
| 455 | 456 | require.NoError(t, err) | |
| 456 | 457 | ||
| 457 | 458 | sendErr := errors.New("send failed") | |
| 458 | - | require.ErrorIs(t, prepared.send(0, func(ports.Frame) error { return sendErr }), sendErr) | |
| 459 | + | require.ErrorIs(t, prepared.send(0, func(wire.Frame) error { return sendErr }), sendErr) | |
| 459 | 460 | ||
| 460 | 461 | require.Equal(t, cursorOut{valid: true, row: 1, col: 1}, output.lastCursor) | |
| 461 | 462 | require.Empty(t, graphicsState.assets) | |
M internal/usecase/daemon/attachment_parking_test.go +5 -5
| @@ -6,15 +6,15 @@ import ( | |||
| 6 | 6 | ||
| 7 | 7 | "github.com/stretchr/testify/require" | |
| 8 | 8 | ||
| 9 | - | "github.com/bnema/vev/internal/ports" | |
| 10 | 9 | "github.com/bnema/vev/internal/protocol" | |
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 11 | 11 | ) | |
| 12 | 12 | ||
| 13 | 13 | type resumeWelcomeFailureTransport struct { | |
| 14 | 14 | closeTrackingTransport | |
| 15 | 15 | } | |
| 16 | 16 | ||
| 17 | - | func (*resumeWelcomeFailureTransport) Send(ports.Frame) error { return errWelcomeSendFailed } | |
| 17 | + | func (*resumeWelcomeFailureTransport) Send(wire.Frame) error { return errWelcomeSendFailed } | |
| 18 | 18 | ||
| 19 | 19 | var errWelcomeSendFailed = errors.New("welcome send failed") | |
| 20 | 20 | ||
| @@ -142,7 +142,7 @@ func TestSuccessfulResumeRejectsOldCredentialAfterWelcome(t *testing.T) { | |||
| 142 | 142 | d.clientGone(sess, ac, oldTransport, false) | |
| 143 | 143 | ||
| 144 | 144 | resumedTransport := &closeTrackingTransport{} | |
| 145 | - | d.handleHello(resumedTransport, ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(helloResumeCapable(protocol.IntentResume, "work", oldToken))}) | |
| 145 | + | d.handleHello(resumedTransport, wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(helloResumeCapable(protocol.IntentResume, "work", oldToken))}) | |
| 146 | 146 | newToken := ac.resumeToken | |
| 147 | 147 | require.NotEqual(t, oldToken, newToken) | |
| 148 | 148 | d.mu.Lock() | |
| @@ -152,7 +152,7 @@ func TestSuccessfulResumeRejectsOldCredentialAfterWelcome(t *testing.T) { | |||
| 152 | 152 | require.False(t, oldRetained) | |
| 153 | 153 | require.NotNil(t, newParked) | |
| 154 | 154 | require.NotEmpty(t, resumedTransport.Sends()) | |
| 155 | - | require.Equal(t, ports.MsgWelcome, resumedTransport.Sends()[0].Type, "Welcome must remain the first server frame after Hello") | |
| 155 | + | require.Equal(t, wire.MsgWelcome, resumedTransport.Sends()[0].Type, "Welcome must remain the first server frame after Hello") | |
| 156 | 156 | } | |
| 157 | 157 | ||
| 158 | 158 | func TestFailedResumeHandshakeKeepsParkedCredential(t *testing.T) { | |
| @@ -166,7 +166,7 @@ func TestFailedResumeHandshakeKeepsParkedCredential(t *testing.T) { | |||
| 166 | 166 | d.clientGone(sess, ac, oldTransport, false) | |
| 167 | 167 | ||
| 168 | 168 | failed := &resumeWelcomeFailureTransport{} | |
| 169 | - | d.handleHello(failed, ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(helloResumeCapable(protocol.IntentResume, "work", token))}) | |
| 169 | + | d.handleHello(failed, wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(helloResumeCapable(protocol.IntentResume, "work", token))}) | |
| 170 | 170 | require.Nil(t, ac.transport()) | |
| 171 | 171 | d.mu.Lock() | |
| 172 | 172 | parked := d.parked[token] | |
M internal/usecase/daemon/attachment_registry_test.go +3 -3
| @@ -5,7 +5,7 @@ import ( | |||
| 5 | 5 | "testing" | |
| 6 | 6 | ||
| 7 | 7 | "github.com/bnema/vev/internal/domain" | |
| 8 | - | "github.com/bnema/vev/internal/ports" | |
| 8 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 9 | 9 | "github.com/stretchr/testify/require" | |
| 10 | 10 | ) | |
| 11 | 11 | ||
| @@ -99,7 +99,7 @@ func TestTabForAttachmentRepairRebasesOutputBeforePublishingRevision(t *testing. | |||
| 99 | 99 | require.Greater(t, ac.output.currentEpoch(), beforeEpoch) | |
| 100 | 100 | frame, err := ac.output.sideEffect([]byte("x"), 0) | |
| 101 | 101 | require.NoError(t, err) | |
| 102 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 102 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 103 | 103 | require.NoError(t, err) | |
| 104 | 104 | require.Equal(t, after.revision, output.ViewRevision) | |
| 105 | 105 | require.Equal(t, ac.output.currentEpoch(), output.Epoch) | |
| @@ -129,7 +129,7 @@ func TestPrepareRemovedTabViewRebasesOutputBeforeSideEffect(t *testing.T) { | |||
| 129 | 129 | ||
| 130 | 130 | frame, err := ac.output.sideEffect([]byte("replacement"), 0) | |
| 131 | 131 | require.NoError(t, err) | |
| 132 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 132 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 133 | 133 | require.NoError(t, err) | |
| 134 | 134 | require.Equal(t, after.revision, output.ViewRevision) | |
| 135 | 135 | require.NotEqual(t, beforeEpoch, output.Epoch) | |
M internal/usecase/daemon/attachment_render_test.go +22 -21
| @@ -10,27 +10,28 @@ import ( | |||
| 10 | 10 | "github.com/bnema/vev/internal/domain" | |
| 11 | 11 | "github.com/bnema/vev/internal/ports" | |
| 12 | 12 | "github.com/bnema/vev/internal/protocol" | |
| 13 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 14 | "github.com/stretchr/testify/require" | |
| 14 | 15 | ) | |
| 15 | 16 | ||
| 16 | 17 | type blockedAttachmentTransport struct { | |
| 17 | 18 | entered chan struct{} | |
| 18 | 19 | release chan struct{} | |
| 19 | - | sends chan ports.Frame | |
| 20 | + | sends chan wire.Frame | |
| 20 | 21 | blocked atomic.Bool | |
| 21 | 22 | once sync.Once | |
| 22 | 23 | } | |
| 23 | 24 | ||
| 24 | - | func (t *blockedAttachmentTransport) Send(frame ports.Frame) error { | |
| 25 | - | if frame.Type == ports.MsgOutput && t.blocked.Load() { | |
| 25 | + | func (t *blockedAttachmentTransport) Send(frame wire.Frame) error { | |
| 26 | + | if frame.Type == wire.MsgOutput && t.blocked.Load() { | |
| 26 | 27 | t.once.Do(func() { close(t.entered) }) | |
| 27 | 28 | <-t.release | |
| 28 | 29 | } | |
| 29 | 30 | t.sends <- frame | |
| 30 | 31 | return nil | |
| 31 | 32 | } | |
| 32 | - | func (*blockedAttachmentTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 33 | - | func (*blockedAttachmentTransport) Close() error { return nil } | |
| 33 | + | func (*blockedAttachmentTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 34 | + | func (*blockedAttachmentTransport) Close() error { return nil } | |
| 34 | 35 | ||
| 35 | 36 | func TestStaleCapacityReadinessRequeuesWithoutAnotherInvalidation(t *testing.T) { | |
| 36 | 37 | d, sess, ac, sends := newManualSessionWithPTYs(t, nil) | |
| @@ -85,8 +86,8 @@ func TestStaleCapacityReadinessRequeuesWithoutAnotherInvalidation(t *testing.T) | |||
| 85 | 86 | ac.output.syncCapacityLocked() | |
| 86 | 87 | ac.sendMu.Unlock() | |
| 87 | 88 | close(releaseRetry) | |
| 88 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | |
| 89 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 89 | + | frame := awaitFrame(t, sends, wire.MsgOutput) | |
| 90 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 90 | 91 | require.NoError(t, err) | |
| 91 | 92 | require.Contains(t, string(output.Data), "capacity race") | |
| 92 | 93 | awaitTestCompletion(t, fireDone, "initial fire did not finish") | |
| @@ -146,10 +147,10 @@ func TestAttachmentFirstPaintDoesNotWaitForBlockedPeer(t *testing.T) { | |||
| 146 | 147 | defer releasePTY() | |
| 147 | 148 | clock := &signalClock{timers: make(chan *signalTimer, 16)} | |
| 148 | 149 | d := newTestDaemon(t, newFactory(t, pty), clock) | |
| 149 | - | oldTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan ports.Frame, 8)} | |
| 150 | + | oldTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan wire.Frame, 8)} | |
| 150 | 151 | sess, old, err := d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentNew, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{1}}, oldTransport) | |
| 151 | 152 | require.NoError(t, err) | |
| 152 | - | newTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan ports.Frame, 8)} | |
| 153 | + | newTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan wire.Frame, 8)} | |
| 153 | 154 | _, fresh, err := d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{2}}, newTransport) | |
| 154 | 155 | require.NoError(t, err) | |
| 155 | 156 | ||
| @@ -172,7 +173,7 @@ func TestAttachmentFirstPaintDoesNotWaitForBlockedPeer(t *testing.T) { | |||
| 172 | 173 | painted := make(chan bool, 1) | |
| 173 | 174 | go func() { painted <- d.firstPaintForTransition(token) }() | |
| 174 | 175 | frame := awaitTestValue(t, newTransport.sends, "healthy attachment first paint was gated by slow peer") | |
| 175 | - | require.Equal(t, ports.MsgOutput, frame.Type) | |
| 176 | + | require.Equal(t, wire.MsgOutput, frame.Type) | |
| 176 | 177 | require.True(t, <-painted) | |
| 177 | 178 | close(oldTransport.release) | |
| 178 | 179 | } | |
| @@ -182,7 +183,7 @@ func TestMultiAttachmentHandshakeFirstPaintNotGatedByBlockedPeer(t *testing.T) { | |||
| 182 | 183 | defer releasePTY() | |
| 183 | 184 | clock := &signalClock{timers: make(chan *signalTimer, 16)} | |
| 184 | 185 | d := newTestDaemon(t, newFactory(t, pty), clock) | |
| 185 | - | oldTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan ports.Frame, 8)} | |
| 186 | + | oldTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan wire.Frame, 8)} | |
| 186 | 187 | sess, old, err := d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentNew, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{1}}, oldTransport) | |
| 187 | 188 | require.NoError(t, err) | |
| 188 | 189 | rc := sess.renderCoordinator() | |
| @@ -202,16 +203,16 @@ func TestMultiAttachmentHandshakeFirstPaintNotGatedByBlockedPeer(t *testing.T) { | |||
| 202 | 203 | awaitTestCompletion(t, oldTransport.entered, "slow attachment did not begin its blocked output") | |
| 203 | 204 | ||
| 204 | 205 | hello := protocol.Hello{Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{2}} | |
| 205 | - | tr, sends, releaseConn := newConn(t, ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(hello)}) | |
| 206 | + | tr, sends, releaseConn := newConn(t, wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(hello)}) | |
| 206 | 207 | defer releaseConn() | |
| 207 | 208 | handshakeDone := make(chan struct{}) | |
| 208 | 209 | go func() { | |
| 209 | 210 | d.handleConn(tr) | |
| 210 | 211 | close(handshakeDone) | |
| 211 | 212 | }() | |
| 212 | - | awaitFrame(t, sends, ports.MsgWelcome) | |
| 213 | - | firstPaint := awaitFrame(t, sends, ports.MsgOutput) | |
| 214 | - | require.Equal(t, ports.MsgOutput, firstPaint.Type) | |
| 213 | + | awaitFrame(t, sends, wire.MsgWelcome) | |
| 214 | + | firstPaint := awaitFrame(t, sends, wire.MsgOutput) | |
| 215 | + | require.Equal(t, wire.MsgOutput, firstPaint.Type) | |
| 215 | 216 | releaseConn() | |
| 216 | 217 | awaitTestCompletion(t, handshakeDone, "multi-attachment handshake did not complete after first paint") | |
| 217 | 218 | close(oldTransport.release) | |
| @@ -222,10 +223,10 @@ func TestAttachmentPaintFanoutDoesNotWaitForBlockedPeer(t *testing.T) { | |||
| 222 | 223 | pty, releasePTY := newBlockingPTY(t) | |
| 223 | 224 | defer releasePTY() | |
| 224 | 225 | d := newTestDaemon(t, newFactory(t, pty), stubClock{}) | |
| 225 | - | firstTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan ports.Frame, 8)} | |
| 226 | + | firstTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan wire.Frame, 8)} | |
| 226 | 227 | sess, _, err := d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentNew, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{1}}, firstTransport) | |
| 227 | 228 | require.NoError(t, err) | |
| 228 | - | secondTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan ports.Frame, 8)} | |
| 229 | + | secondTransport := &blockedAttachmentTransport{entered: make(chan struct{}), release: make(chan struct{}), sends: make(chan wire.Frame, 8)} | |
| 229 | 230 | _, _, err = d.route(protocol.Hello{Version: protocol.Version, Intent: protocol.IntentAttach, Name: "work", Size: domain.Size{Cols: 80, Rows: 24}, ClientID: [16]byte{2}}, secondTransport) | |
| 230 | 231 | require.NoError(t, err) | |
| 231 | 232 | rc := sess.renderCoordinator() | |
| @@ -244,8 +245,8 @@ func TestAttachmentPaintFanoutDoesNotWaitForBlockedPeer(t *testing.T) { | |||
| 244 | 245 | } | |
| 245 | 246 | select { | |
| 246 | 247 | case frame := <-secondTransport.sends: | |
| 247 | - | require.Equal(t, ports.MsgOutput, frame.Type) | |
| 248 | - | out, err := ports.UnmarshalOutput(frame.Payload) | |
| 248 | + | require.Equal(t, wire.MsgOutput, frame.Type) | |
| 249 | + | out, err := wire.UnmarshalOutput(frame.Payload) | |
| 249 | 250 | require.NoError(t, err) | |
| 250 | 251 | require.True(t, out.Full, "fan-out peers must send a fresh first frame even after another attachment acknowledges shared damage") | |
| 251 | 252 | case <-time.After(time.Second): | |
| @@ -284,8 +285,8 @@ func TestAttachmentResizeUsesLatestClaimedSessionGeometry(t *testing.T) { | |||
| 284 | 285 | require.True(t, rc.markAttachmentReady(secondLease)) | |
| 285 | 286 | resize := func(ac *attachedClient, tr ports.Transport, size domain.Size) { | |
| 286 | 287 | token := sess.captureAttachmentCapability(ac, tr) | |
| 287 | - | d.handleAttachmentClientFrame(token, ports.Frame{ | |
| 288 | - | Type: ports.MsgResize, | |
| 288 | + | d.handleAttachmentClientFrame(token, wire.Frame{ | |
| 289 | + | Type: wire.MsgResize, | |
| 289 | 290 | Payload: mustMarshalResize(protocol.Resize{Size: size}), | |
| 290 | 291 | }) | |
| 291 | 292 | } | |
M internal/usecase/daemon/attachment_route_identity_test.go +5 -5
| @@ -5,8 +5,8 @@ import ( | |||
| 5 | 5 | "testing" | |
| 6 | 6 | ||
| 7 | 7 | "github.com/bnema/vev/internal/domain" | |
| 8 | - | "github.com/bnema/vev/internal/ports" | |
| 9 | 8 | "github.com/bnema/vev/internal/protocol" | |
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 10 | 10 | "github.com/stretchr/testify/require" | |
| 11 | 11 | ) | |
| 12 | 12 | ||
| @@ -14,8 +14,8 @@ type committedIdentityErrorTransport struct { | |||
| 14 | 14 | closeTrackingTransport | |
| 15 | 15 | } | |
| 16 | 16 | ||
| 17 | - | func (t *committedIdentityErrorTransport) Send(frame ports.Frame) error { | |
| 18 | - | if frame.Type == ports.MsgCommittedRouteIdentity { | |
| 17 | + | func (t *committedIdentityErrorTransport) Send(frame wire.Frame) error { | |
| 18 | + | if frame.Type == wire.MsgCommittedRouteIdentity { | |
| 19 | 19 | return errors.New("committed identity send failed") | |
| 20 | 20 | } | |
| 21 | 21 | return t.closeTrackingTransport.Send(frame) | |
| @@ -58,11 +58,11 @@ func TestAttachmentTransitionPublishesCommittedRouteIdentity(t *testing.T) { | |||
| 58 | 58 | var identity protocol.CommittedRouteIdentity | |
| 59 | 59 | found := false | |
| 60 | 60 | for _, frame := range transport.Sends() { | |
| 61 | - | if frame.Type != ports.MsgCommittedRouteIdentity { | |
| 61 | + | if frame.Type != wire.MsgCommittedRouteIdentity { | |
| 62 | 62 | continue | |
| 63 | 63 | } | |
| 64 | 64 | var decodeErr error | |
| 65 | - | identity, decodeErr = ports.UnmarshalCommittedRouteIdentity(frame.Payload) | |
| 65 | + | identity, decodeErr = wire.UnmarshalCommittedRouteIdentity(frame.Payload) | |
| 66 | 66 | require.NoError(t, decodeErr) | |
| 67 | 67 | found = true | |
| 68 | 68 | } | |
M internal/usecase/daemon/attention_test.go +2 -1
| @@ -14,6 +14,7 @@ import ( | |||
| 14 | 14 | "github.com/bnema/vev/internal/domain" | |
| 15 | 15 | "github.com/bnema/vev/internal/ports" | |
| 16 | 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 17 | 18 | "github.com/bnema/vev/internal/usecase/keys" | |
| 18 | 19 | "github.com/bnema/vev/internal/usecase/layout" | |
| 19 | 20 | "github.com/bnema/vev/internal/usecase/ui" | |
| @@ -166,7 +167,7 @@ func TestNoteAttentionDoesNotBlockOnWedgedOtherClient(t *testing.T) { | |||
| 166 | 167 | trW := portsmocks.NewMockTransport(t) | |
| 167 | 168 | block := make(chan struct{}) | |
| 168 | 169 | t.Cleanup(func() { close(block) }) | |
| 169 | - | trW.EXPECT().Send(mock.Anything).RunAndReturn(func(ports.Frame) error { | |
| 170 | + | trW.EXPECT().Send(mock.Anything).RunAndReturn(func(wire.Frame) error { | |
| 170 | 171 | <-block | |
| 171 | 172 | return nil | |
| 172 | 173 | }).Maybe() | |
M internal/usecase/daemon/client.go +5 -4
| @@ -14,6 +14,7 @@ import ( | |||
| 14 | 14 | "github.com/bnema/vev/internal/domain" | |
| 15 | 15 | "github.com/bnema/vev/internal/ports" | |
| 16 | 16 | "github.com/bnema/vev/internal/protocol" | |
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 17 | 18 | "github.com/bnema/vev/internal/usecase/keys" | |
| 18 | 19 | "github.com/bnema/vev/internal/usecase/mouse" | |
| 19 | 20 | themeui "github.com/bnema/vev/internal/usecase/theme" | |
| @@ -409,7 +410,7 @@ var errTransportReplaced = errors.New("client transport was replaced") | |||
| 409 | 410 | ||
| 410 | 411 | // sendExpectedTransport writes only when expected is still the attachment's | |
| 411 | 412 | // current transport incarnation. It preserves sendMu -> linkMu lock ordering. | |
| 412 | - | func (ac *attachedClient) sendExpectedTransport(expected transportSnapshot, f ports.Frame) error { | |
| 413 | + | func (ac *attachedClient) sendExpectedTransport(expected transportSnapshot, f wire.Frame) error { | |
| 413 | 414 | ac.sendMu.Lock() | |
| 414 | 415 | defer ac.sendMu.Unlock() | |
| 415 | 416 | if !ac.transportSnapshotCurrent(expected) { | |
| @@ -435,7 +436,7 @@ func (ac *attachedClient) beginExpectedTransportSendLocked(expected transportSna | |||
| 435 | 436 | return nil | |
| 436 | 437 | } | |
| 437 | 438 | ||
| 438 | - | func (ac *attachedClient) sendExpectedTransportForAttachment(expected transportSnapshot, f ports.Frame, ticket *attachmentEffect) error { | |
| 439 | + | func (ac *attachedClient) sendExpectedTransportForAttachment(expected transportSnapshot, f wire.Frame, ticket *attachmentEffect) error { | |
| 439 | 440 | ac.sendMu.Lock() | |
| 440 | 441 | defer ac.sendMu.Unlock() | |
| 441 | 442 | // A attachment-bound send requires a live ticket, and reports every rejection, | |
| @@ -459,11 +460,11 @@ func (ac *attachedClient) sendExpectedTransportForAttachment(expected transportS | |||
| 459 | 460 | // detachNotifyTimeout, the transport is force-closed, failing the in-flight | |
| 460 | 461 | // write. Detach/kill/shutdown paths use this so they are never gated on a | |
| 461 | 462 | // client that has stopped draining its socket. | |
| 462 | - | func (d *Daemon) boundedSend(ac *attachedClient, f ports.Frame) { | |
| 463 | + | func (d *Daemon) boundedSend(ac *attachedClient, f wire.Frame) { | |
| 463 | 464 | _ = d.boundedSendErr(ac, f) | |
| 464 | 465 | } | |
| 465 | 466 | ||
| 466 | - | func (d *Daemon) boundedSendErr(ac *attachedClient, f ports.Frame) error { | |
| 467 | + | func (d *Daemon) boundedSendErr(ac *attachedClient, f wire.Frame) error { | |
| 467 | 468 | expected := ac.transportSnapshot() | |
| 468 | 469 | if expected.transport == nil { | |
| 469 | 470 | return errors.New("client transport is nil") | |
M internal/usecase/daemon/client_frame_routing.go +30 -29
| @@ -7,6 +7,7 @@ import ( | |||
| 7 | 7 | "github.com/bnema/vev/internal/domain" | |
| 8 | 8 | "github.com/bnema/vev/internal/ports" | |
| 9 | 9 | "github.com/bnema/vev/internal/protocol" | |
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 10 | 11 | "github.com/bnema/vev/internal/usecase/command" | |
| 11 | 12 | ) | |
| 12 | 13 | ||
| @@ -75,7 +76,7 @@ func (d *Daemon) runConnLoop(ac *attachedClient) { | |||
| 75 | 76 | } | |
| 76 | 77 | ||
| 77 | 78 | // handleAttachmentClientFrame owns the attached-client protocol. | |
| 78 | - | func (d *Daemon) handleAttachmentClientFrame(capability attachmentCapability, f ports.Frame) bool { | |
| 79 | + | func (d *Daemon) handleAttachmentClientFrame(capability attachmentCapability, f wire.Frame) bool { | |
| 79 | 80 | if !capability.current() { | |
| 80 | 81 | return false | |
| 81 | 82 | } | |
| @@ -91,57 +92,57 @@ func (d *Daemon) handleAttachmentClientFrame(capability attachmentCapability, f | |||
| 91 | 92 | d.afterAttachmentEffectAdmitted(effect.capability()) | |
| 92 | 93 | } | |
| 93 | 94 | switch f.Type { | |
| 94 | - | case ports.MsgInput: | |
| 95 | - | if in, derr := ports.UnmarshalInput(f.Payload); derr == nil { | |
| 95 | + | case wire.MsgInput: | |
| 96 | + | if in, derr := wire.UnmarshalInput(f.Payload); derr == nil { | |
| 96 | 97 | d.handleSequencedInputForAttachment(effect, in.InputSeq, in.Data) | |
| 97 | 98 | } | |
| 98 | - | case ports.MsgResize: | |
| 99 | - | if rz, derr := ports.UnmarshalResize(f.Payload); derr == nil && effect.current() { | |
| 99 | + | case wire.MsgResize: | |
| 100 | + | if rz, derr := wire.UnmarshalResize(f.Payload); derr == nil && effect.current() { | |
| 100 | 101 | d.resizeAttachmentGeometryForLease(effect, rz.Geometry()) | |
| 101 | 102 | } | |
| 102 | - | case ports.MsgTheme: | |
| 103 | - | if th, derr := ports.UnmarshalTheme(f.Payload); derr == nil { | |
| 103 | + | case wire.MsgTheme: | |
| 104 | + | if th, derr := wire.UnmarshalTheme(f.Payload); derr == nil { | |
| 104 | 105 | d.applyThemeForAttachment(effect, th) | |
| 105 | 106 | } | |
| 106 | - | case ports.MsgImagePush: | |
| 107 | - | if ip, derr := ports.UnmarshalImagePush(f.Payload); derr == nil { | |
| 107 | + | case wire.MsgImagePush: | |
| 108 | + | if ip, derr := wire.UnmarshalImagePush(f.Payload); derr == nil { | |
| 108 | 109 | d.handleSequencedImagePushForAttachment(effect, ip.InputSeq, ip) | |
| 109 | 110 | } | |
| 110 | - | case ports.MsgClientNotice: | |
| 111 | - | if notice, derr := ports.UnmarshalClientNotice(f.Payload); derr == nil { | |
| 111 | + | case wire.MsgClientNotice: | |
| 112 | + | if notice, derr := wire.UnmarshalClientNotice(f.Payload); derr == nil { | |
| 112 | 113 | d.handleClientNoticeForAttachment(effect, notice) | |
| 113 | 114 | } else { | |
| 114 | 115 | d.log.Warn("malformed client notice", "err", derr) | |
| 115 | 116 | } | |
| 116 | - | case ports.MsgDetach: | |
| 117 | + | case wire.MsgDetach: | |
| 117 | 118 | if effect.current() { | |
| 118 | 119 | d.clientGoneForAttachment(effect, true) | |
| 119 | 120 | return true | |
| 120 | 121 | } | |
| 121 | - | case ports.MsgAck: | |
| 122 | - | if ack, derr := ports.UnmarshalAck(f.Payload); derr == nil { | |
| 122 | + | case wire.MsgAck: | |
| 123 | + | if ack, derr := wire.UnmarshalAck(f.Payload); derr == nil { | |
| 123 | 124 | d.ackOutput(effect, ack.Epoch, ack.State) | |
| 124 | 125 | } | |
| 125 | - | case ports.MsgOutputResetRequest: | |
| 126 | - | if _, derr := ports.UnmarshalOutputResetRequest(f.Payload); derr == nil { | |
| 126 | + | case wire.MsgOutputResetRequest: | |
| 127 | + | if _, derr := wire.UnmarshalOutputResetRequest(f.Payload); derr == nil { | |
| 127 | 128 | d.resetOutput(effect) | |
| 128 | 129 | } | |
| 129 | - | case ports.MsgSamePeerSwitchRequest: | |
| 130 | - | request, derr := ports.UnmarshalSamePeerSwitchRequest(f.Payload) | |
| 130 | + | case wire.MsgSamePeerSwitchRequest: | |
| 131 | + | request, derr := wire.UnmarshalSamePeerSwitchRequest(f.Payload) | |
| 131 | 132 | if derr != nil { | |
| 132 | 133 | d.log.Warn("malformed same-peer switch request", "err", derr) | |
| 133 | 134 | break | |
| 134 | 135 | } | |
| 135 | 136 | d.switchSamePeerForAttachment(effect, request) | |
| 136 | - | case ports.MsgParkedRouteRequest: | |
| 137 | - | request, derr := ports.UnmarshalParkedRouteRequest(f.Payload) | |
| 137 | + | case wire.MsgParkedRouteRequest: | |
| 138 | + | request, derr := wire.UnmarshalParkedRouteRequest(f.Payload) | |
| 138 | 139 | if derr != nil { | |
| 139 | 140 | d.log.Warn("malformed parked-route request", "err", derr) | |
| 140 | 141 | break | |
| 141 | 142 | } | |
| 142 | 143 | d.handleParkedRouteRequest(effect, request) | |
| 143 | - | case ports.MsgRecentRouteSnapshot: | |
| 144 | - | snapshot, derr := ports.UnmarshalRecentRouteSnapshot(f.Payload) | |
| 144 | + | case wire.MsgRecentRouteSnapshot: | |
| 145 | + | snapshot, derr := wire.UnmarshalRecentRouteSnapshot(f.Payload) | |
| 145 | 146 | if derr != nil { | |
| 146 | 147 | d.log.Warn("malformed recent route snapshot", "err", derr) | |
| 147 | 148 | break | |
| @@ -154,16 +155,16 @@ func (d *Daemon) handleAttachmentClientFrame(capability attachmentCapability, f | |||
| 154 | 155 | if err := d.sendCommittedRouteIdentityForAttachment(effect); err != nil { | |
| 155 | 156 | d.detachOnAttachmentSendError(effect.capability(), effect.transport.transport) | |
| 156 | 157 | } | |
| 157 | - | case ports.MsgRouteAttentionSubscription: | |
| 158 | - | subscription, derr := ports.UnmarshalRouteAttentionSubscription(f.Payload) | |
| 158 | + | case wire.MsgRouteAttentionSubscription: | |
| 159 | + | subscription, derr := wire.UnmarshalRouteAttentionSubscription(f.Payload) | |
| 159 | 160 | if derr != nil { | |
| 160 | 161 | d.log.Warn("malformed route attention subscription", "err", derr) | |
| 161 | 162 | break | |
| 162 | 163 | } | |
| 163 | 164 | effect.ac.setRouteAttentionSubscription(subscription) | |
| 164 | 165 | d.invalidateRender(effect.sess, effect.ac, false, "client_frame_routing.go:route-attention") | |
| 165 | - | case ports.MsgRouteNavigationFailure: | |
| 166 | - | failure, derr := ports.UnmarshalRouteNavigationFailure(f.Payload) | |
| 166 | + | case wire.MsgRouteNavigationFailure: | |
| 167 | + | failure, derr := wire.UnmarshalRouteNavigationFailure(f.Payload) | |
| 167 | 168 | if derr != nil { | |
| 168 | 169 | d.log.Warn("malformed route navigation failure", "err", derr) | |
| 169 | 170 | break | |
| @@ -182,8 +183,8 @@ func (d *Daemon) handleAttachmentClientFrame(capability attachmentCapability, f | |||
| 182 | 183 | message = "that recent route no longer exists" | |
| 183 | 184 | } | |
| 184 | 185 | d.notify(effect.sess, domain.NoticeWarn, domain.NoticeSessionUnavailable, message, nil) | |
| 185 | - | case ports.MsgCommand: | |
| 186 | - | request, derr := ports.UnmarshalCommandRequest(f.Payload) | |
| 186 | + | case wire.MsgCommand: | |
| 187 | + | request, derr := wire.UnmarshalCommandRequest(f.Payload) | |
| 187 | 188 | if derr != nil { | |
| 188 | 189 | return false | |
| 189 | 190 | } | |
| @@ -200,7 +201,7 @@ func (d *Daemon) handleAttachmentClientFrame(capability attachmentCapability, f | |||
| 200 | 201 | return true | |
| 201 | 202 | } | |
| 202 | 203 | resultEffect.End() | |
| 203 | - | case ports.MsgPing: | |
| 204 | + | case wire.MsgPing: | |
| 204 | 205 | if err := effect.sendControl(framePong()); err != nil { | |
| 205 | 206 | effect.End() | |
| 206 | 207 | d.detachOnAttachmentSendError(effect.capability(), effect.transport.transport) | |
M internal/usecase/daemon/clipboard_test.go +14 -13
| @@ -19,6 +19,7 @@ import ( | |||
| 19 | 19 | "github.com/bnema/vev/internal/ports" | |
| 20 | 20 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 21 | 21 | "github.com/bnema/vev/internal/protocol" | |
| 22 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 22 | 23 | scopy "github.com/bnema/vev/internal/usecase/copy" | |
| 23 | 24 | ) | |
| 24 | 25 | ||
| @@ -243,8 +244,8 @@ func TestPTYReaderForwardsOSC52ClipboardToAttachedClient(t *testing.T) { | |||
| 243 | 244 | ||
| 244 | 245 | var clipboardOutput string | |
| 245 | 246 | for range 3 { | |
| 246 | - | f := awaitFrame(t, sends, ports.MsgOutput) | |
| 247 | - | out, err := ports.UnmarshalOutput(f.Payload) | |
| 247 | + | f := awaitFrame(t, sends, wire.MsgOutput) | |
| 248 | + | out, err := wire.UnmarshalOutput(f.Payload) | |
| 248 | 249 | require.NoError(t, err) | |
| 249 | 250 | clipboardOutput = string(out.Data) | |
| 250 | 251 | if strings.Contains(clipboardOutput, "\x1b]52;c;aGVsbG8=\x07") { | |
| @@ -276,7 +277,7 @@ func TestPTYReaderDropsOversizedClipboardPayload(t *testing.T) { | |||
| 276 | 277 | ||
| 277 | 278 | select { | |
| 278 | 279 | case f := <-sends: | |
| 279 | - | require.NotEqual(t, ports.MsgOutput, f.Type) | |
| 280 | + | require.NotEqual(t, wire.MsgOutput, f.Type) | |
| 280 | 281 | default: | |
| 281 | 282 | } | |
| 282 | 283 | } | |
| @@ -301,7 +302,7 @@ func TestPTYReaderDropsInvalidBase64Clipboard(t *testing.T) { | |||
| 301 | 302 | ||
| 302 | 303 | select { | |
| 303 | 304 | case f := <-sends: | |
| 304 | - | require.NotEqual(t, ports.MsgOutput, f.Type) | |
| 305 | + | require.NotEqual(t, wire.MsgOutput, f.Type) | |
| 305 | 306 | default: | |
| 306 | 307 | } | |
| 307 | 308 | } | |
| @@ -328,15 +329,15 @@ type staleClipboardErrorTransport struct { | |||
| 328 | 329 | sends int | |
| 329 | 330 | } | |
| 330 | 331 | ||
| 331 | - | func (t *staleClipboardErrorTransport) Send(ports.Frame) error { | |
| 332 | + | func (t *staleClipboardErrorTransport) Send(wire.Frame) error { | |
| 332 | 333 | t.mu.Lock() | |
| 333 | 334 | t.sends++ | |
| 334 | 335 | t.mu.Unlock() | |
| 335 | 336 | return errors.New("stale clipboard send") | |
| 336 | 337 | } | |
| 337 | 338 | ||
| 338 | - | func (*staleClipboardErrorTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 339 | - | func (*staleClipboardErrorTransport) Close() error { return nil } | |
| 339 | + | func (*staleClipboardErrorTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 340 | + | func (*staleClipboardErrorTransport) Close() error { return nil } | |
| 340 | 341 | ||
| 341 | 342 | func (t *staleClipboardErrorTransport) sendCount() int { | |
| 342 | 343 | t.mu.Lock() | |
| @@ -383,13 +384,13 @@ func newMovingClipboardErrorTransport() *movingClipboardErrorTransport { | |||
| 383 | 384 | } | |
| 384 | 385 | } | |
| 385 | 386 | ||
| 386 | - | func (t *movingClipboardErrorTransport) Send(ports.Frame) error { | |
| 387 | + | func (t *movingClipboardErrorTransport) Send(wire.Frame) error { | |
| 387 | 388 | t.startedOnce.Do(func() { close(t.started) }) | |
| 388 | 389 | <-t.release | |
| 389 | 390 | return errors.New("clipboard send failed after pane move") | |
| 390 | 391 | } | |
| 391 | 392 | ||
| 392 | - | func (*movingClipboardErrorTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 393 | + | func (*movingClipboardErrorTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 393 | 394 | ||
| 394 | 395 | func (t *movingClipboardErrorTransport) Close() error { | |
| 395 | 396 | t.closeOnce.Do(func() { close(t.closed) }) | |
| @@ -509,8 +510,8 @@ func newBlockingClipboardTransport() *blockingClipboardTransport { | |||
| 509 | 510 | } | |
| 510 | 511 | } | |
| 511 | 512 | ||
| 512 | - | func (tr *blockingClipboardTransport) Send(f ports.Frame) error { | |
| 513 | - | out, err := ports.UnmarshalOutput(f.Payload) | |
| 513 | + | func (tr *blockingClipboardTransport) Send(f wire.Frame) error { | |
| 514 | + | out, err := wire.UnmarshalOutput(f.Payload) | |
| 514 | 515 | if err != nil { | |
| 515 | 516 | return err | |
| 516 | 517 | } | |
| @@ -532,5 +533,5 @@ func (tr *blockingClipboardTransport) Send(f ports.Frame) error { | |||
| 532 | 533 | return nil | |
| 533 | 534 | } | |
| 534 | 535 | ||
| 535 | - | func (tr *blockingClipboardTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 536 | - | func (tr *blockingClipboardTransport) Close() error { return nil } | |
| 536 | + | func (tr *blockingClipboardTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 537 | + | func (tr *blockingClipboardTransport) Close() error { return nil } | |
M internal/usecase/daemon/config_test.go +5 -5
| @@ -8,8 +8,8 @@ import ( | |||
| 8 | 8 | ||
| 9 | 9 | renderer "github.com/bnema/vev-vt" | |
| 10 | 10 | "github.com/bnema/vev/internal/domain" | |
| 11 | - | "github.com/bnema/vev/internal/ports" | |
| 12 | 11 | "github.com/bnema/vev/internal/protocol" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 13 | "github.com/bnema/vev/internal/usecase/keys" | |
| 14 | 14 | themeui "github.com/bnema/vev/internal/usecase/theme" | |
| 15 | 15 | ) | |
| @@ -318,11 +318,11 @@ func TestApplyConfigRepaintsActivePaletteWithoutReplacingModel(t *testing.T) { | |||
| 318 | 318 | defer release() | |
| 319 | 319 | d, sess, ac, sends := newManualSessionWithPTYs(t, p) | |
| 320 | 320 | d.enterPalette(sess, ac) | |
| 321 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 321 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 322 | 322 | d.handlePaletteInput(ac, []byte("new")) | |
| 323 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 323 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 324 | 324 | d.handlePaletteInput(ac, []byte{0x0e}) | |
| 325 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 325 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 326 | 326 | ||
| 327 | 327 | ac.overlays.paletteMu.Lock() | |
| 328 | 328 | model := ac.overlays.palette | |
| @@ -334,7 +334,7 @@ func TestApplyConfigRepaintsActivePaletteWithoutReplacingModel(t *testing.T) { | |||
| 334 | 334 | cfg := domain.Defaults() | |
| 335 | 335 | cfg.Palette = domain.PaletteConfig{Anchor: domain.AnchorTopLeft, AnchorSet: true} | |
| 336 | 336 | d.ApplyConfig(cfg) | |
| 337 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 337 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 338 | 338 | ||
| 339 | 339 | ac.overlays.paletteMu.Lock() | |
| 340 | 340 | defer ac.overlays.paletteMu.Unlock() | |
M internal/usecase/daemon/control.go +7 -6
| @@ -13,19 +13,20 @@ import ( | |||
| 13 | 13 | "github.com/bnema/vev/internal/domain" | |
| 14 | 14 | "github.com/bnema/vev/internal/ports" | |
| 15 | 15 | "github.com/bnema/vev/internal/protocol" | |
| 16 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 16 | 17 | "github.com/bnema/vev/internal/usecase/command" | |
| 17 | 18 | "github.com/bnema/vev/internal/usecase/layout" | |
| 18 | 19 | ) | |
| 19 | 20 | ||
| 20 | 21 | // handleCommand serves one one-shot control request. The leading version is | |
| 21 | 22 | // checked before decoding the versioned body so newer layouts fail cleanly. | |
| 22 | - | func (d *Daemon) handleCommand(tr ports.Transport, f ports.Frame) error { | |
| 23 | + | func (d *Daemon) handleCommand(tr ports.Transport, f wire.Frame) error { | |
| 23 | 24 | defer func() { _ = tr.Close() }() | |
| 24 | 25 | ||
| 25 | - | if version, ok := ports.PeekCommandVersion(f.Payload); !ok || version != protocol.Version { | |
| 26 | + | if version, ok := wire.PeekCommandVersion(f.Payload); !ok || version != protocol.Version { | |
| 26 | 27 | return d.sendCommandResult(tr, protocol.CommandResult{Code: protocol.ErrVersionMismatch, Text: "protocol version mismatch"}) | |
| 27 | 28 | } | |
| 28 | - | request, err := ports.UnmarshalCommandRequest(f.Payload) | |
| 29 | + | request, err := wire.UnmarshalCommandRequest(f.Payload) | |
| 29 | 30 | if err != nil { | |
| 30 | 31 | return d.sendCommandResult(tr, protocol.CommandResult{Code: protocol.ErrInternal, Text: "malformed command request"}) | |
| 31 | 32 | } | |
| @@ -79,7 +80,7 @@ func (d *Daemon) sendCommandResult(tr ports.Transport, result protocol.CommandRe | |||
| 79 | 80 | // boundedControlSend keeps one-shot control handlers from waiting forever on a | |
| 80 | 81 | // client that stopped reading. A timeout closes the exact transport so a | |
| 81 | 82 | // blocked Send can unwind before the handler returns. | |
| 82 | - | func (d *Daemon) boundedControlSend(tr ports.Transport, frame ports.Frame) error { | |
| 83 | + | func (d *Daemon) boundedControlSend(tr ports.Transport, frame wire.Frame) error { | |
| 83 | 84 | _, err := d.boundedSendWith(tr, func() error { return tr.Send(frame) }) | |
| 84 | 85 | if errors.Is(err, errSendTimedOut) { | |
| 85 | 86 | _ = tr.Close() | |
| @@ -87,8 +88,8 @@ func (d *Daemon) boundedControlSend(tr ports.Transport, frame ports.Frame) error | |||
| 87 | 88 | return err | |
| 88 | 89 | } | |
| 89 | 90 | ||
| 90 | - | func frameCommandResult(result protocol.CommandResult) ports.Frame { | |
| 91 | - | return ports.Frame{Type: ports.MsgCommandResult, Payload: ports.MarshalCommandResult(result)} | |
| 91 | + | func frameCommandResult(result protocol.CommandResult) wire.Frame { | |
| 92 | + | return wire.Frame{Type: wire.MsgCommandResult, Payload: wire.MarshalCommandResult(result)} | |
| 92 | 93 | } | |
| 93 | 94 | ||
| 94 | 95 | func (d *Daemon) dispatchCommand(ctx context.Context, request protocol.CommandRequest) protocol.CommandResult { | |
M internal/usecase/daemon/control_test.go +16 -15
| @@ -17,6 +17,7 @@ import ( | |||
| 17 | 17 | "github.com/bnema/vev/internal/ports" | |
| 18 | 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 19 | 19 | "github.com/bnema/vev/internal/protocol" | |
| 20 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 20 | 21 | "github.com/bnema/vev/internal/usecase/command" | |
| 21 | 22 | "github.com/bnema/vev/internal/usecase/layout" | |
| 22 | 23 | "github.com/stretchr/testify/require" | |
| @@ -196,7 +197,7 @@ func TestHandleCommandAttachedRejectionReturnsSendFailure(t *testing.T) { | |||
| 196 | 197 | func TestHandleCommandRejectsVersionBeforeDecodeOrDispatch(t *testing.T) { | |
| 197 | 198 | // The version prefix is valid and mismatched, while the remainder is not a | |
| 198 | 199 | // decodable request. The daemon must still return ErrVersionMismatch. | |
| 199 | - | frame := ports.Frame{Type: ports.MsgCommand, Payload: []byte{0, byte(protocol.Version + 1)}} | |
| 200 | + | frame := wire.Frame{Type: wire.MsgCommand, Payload: []byte{0, byte(protocol.Version + 1)}} | |
| 200 | 201 | tr, sends, _ := newConn(t, frame) | |
| 201 | 202 | ||
| 202 | 203 | d := newTestDaemon(t, nil, stubClock{}) | |
| @@ -210,9 +211,9 @@ func TestHandleCommandRejectsVersionBeforeDecodeOrDispatch(t *testing.T) { | |||
| 210 | 211 | func TestHandleConnRoutesCommand(t *testing.T) { | |
| 211 | 212 | d := newTestDaemon(t, nil, stubClock{}) | |
| 212 | 213 | request := protocol.CommandRequest{Version: protocol.Version, Slug: "list-sessions"} | |
| 213 | - | payload, err := ports.MarshalCommandRequest(request) | |
| 214 | + | payload, err := wire.MarshalCommandRequest(request) | |
| 214 | 215 | require.NoError(t, err) | |
| 215 | - | frame := ports.Frame{Type: ports.MsgCommand, Payload: payload} | |
| 216 | + | frame := wire.Frame{Type: wire.MsgCommand, Payload: payload} | |
| 216 | 217 | tr, sends, _ := newConn(t, frame) | |
| 217 | 218 | ||
| 218 | 219 | d.handleConn(tr) | |
| @@ -1299,7 +1300,7 @@ func TestHandleCommandOppositeMoveCommandsDoNotDeadlock(t *testing.T) { | |||
| 1299 | 1300 | done <- struct{}{} | |
| 1300 | 1301 | }() | |
| 1301 | 1302 | close(start) | |
| 1302 | - | for _, sends := range []chan ports.Frame{leftSends, rightSends} { | |
| 1303 | + | for _, sends := range []chan wire.Frame{leftSends, rightSends} { | |
| 1303 | 1304 | select { | |
| 1304 | 1305 | case <-done: | |
| 1305 | 1306 | result := awaitCommandResult(t, sends) | |
| @@ -1324,14 +1325,14 @@ func addNamedMoveDestination(d *Daemon, name, tabID, paneID string) *session { | |||
| 1324 | 1325 | return sess | |
| 1325 | 1326 | } | |
| 1326 | 1327 | ||
| 1327 | - | func commandFrame(t *testing.T, request protocol.CommandRequest) ports.Frame { | |
| 1328 | + | func commandFrame(t *testing.T, request protocol.CommandRequest) wire.Frame { | |
| 1328 | 1329 | t.Helper() | |
| 1329 | 1330 | if request.Version == 0 { | |
| 1330 | 1331 | request.Version = protocol.Version | |
| 1331 | 1332 | } | |
| 1332 | - | payload, err := ports.MarshalCommandRequest(request) | |
| 1333 | + | payload, err := wire.MarshalCommandRequest(request) | |
| 1333 | 1334 | require.NoError(t, err) | |
| 1334 | - | return ports.Frame{Type: ports.MsgCommand, Payload: payload} | |
| 1335 | + | return wire.Frame{Type: wire.MsgCommand, Payload: payload} | |
| 1335 | 1336 | } | |
| 1336 | 1337 | ||
| 1337 | 1338 | func sendCommand(t *testing.T, d *Daemon, request protocol.CommandRequest) protocol.CommandResult { | |
| @@ -1342,10 +1343,10 @@ func sendCommand(t *testing.T, d *Daemon, request protocol.CommandRequest) proto | |||
| 1342 | 1343 | return awaitCommandResult(t, sends) | |
| 1343 | 1344 | } | |
| 1344 | 1345 | ||
| 1345 | - | func awaitCommandResult(t *testing.T, sends chan ports.Frame) protocol.CommandResult { | |
| 1346 | + | func awaitCommandResult(t *testing.T, sends chan wire.Frame) protocol.CommandResult { | |
| 1346 | 1347 | t.Helper() | |
| 1347 | - | reply := awaitFrame(t, sends, ports.MsgCommandResult) | |
| 1348 | - | result, err := ports.UnmarshalCommandResult(reply.Payload) | |
| 1348 | + | reply := awaitFrame(t, sends, wire.MsgCommandResult) | |
| 1349 | + | result, err := wire.UnmarshalCommandResult(reply.Payload) | |
| 1349 | 1350 | require.NoError(t, err) | |
| 1350 | 1351 | return result | |
| 1351 | 1352 | } | |
| @@ -1397,13 +1398,13 @@ func newBlockingControlSendTransport() *blockingControlSendTransport { | |||
| 1397 | 1398 | return &blockingControlSendTransport{started: make(chan struct{}), closed: make(chan struct{})} | |
| 1398 | 1399 | } | |
| 1399 | 1400 | ||
| 1400 | - | func (tr *blockingControlSendTransport) Send(ports.Frame) error { | |
| 1401 | + | func (tr *blockingControlSendTransport) Send(wire.Frame) error { | |
| 1401 | 1402 | tr.once.Do(func() { close(tr.started) }) | |
| 1402 | 1403 | <-tr.closed | |
| 1403 | 1404 | return io.ErrClosedPipe | |
| 1404 | 1405 | } | |
| 1405 | 1406 | ||
| 1406 | - | func (*blockingControlSendTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 1407 | + | func (*blockingControlSendTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 1407 | 1408 | func (tr *blockingControlSendTransport) Close() error { | |
| 1408 | 1409 | tr.once.Do(func() { close(tr.started) }) | |
| 1409 | 1410 | select { | |
| @@ -1419,9 +1420,9 @@ type commandSendErrorTransport struct { | |||
| 1419 | 1420 | closed bool | |
| 1420 | 1421 | } | |
| 1421 | 1422 | ||
| 1422 | - | func (tr *commandSendErrorTransport) Send(ports.Frame) error { return tr.err } | |
| 1423 | - | func (*commandSendErrorTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 1424 | - | func (tr *commandSendErrorTransport) Close() error { tr.closed = true; return nil } | |
| 1423 | + | func (tr *commandSendErrorTransport) Send(wire.Frame) error { return tr.err } | |
| 1424 | + | func (*commandSendErrorTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 1425 | + | func (tr *commandSendErrorTransport) Close() error { tr.closed = true; return nil } | |
| 1425 | 1426 | ||
| 1426 | 1427 | func addControlSession(d *Daemon, name, tabID, paneID string) *session { | |
| 1427 | 1428 | tb := newTabWithStableID(tabID, paneID, newQuietPTY(), domain.Size{Cols: 80, Rows: 22}) | |
M internal/usecase/daemon/copymode_test.go +72 -71
| @@ -19,6 +19,7 @@ import ( | |||
| 19 | 19 | "github.com/bnema/vev/internal/ports" | |
| 20 | 20 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 21 | 21 | "github.com/bnema/vev/internal/protocol" | |
| 22 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 22 | 23 | scopy "github.com/bnema/vev/internal/usecase/copy" | |
| 23 | 24 | "github.com/bnema/vev/internal/usecase/layout" | |
| 24 | 25 | "github.com/bnema/vev/internal/usecase/ui" | |
| @@ -47,7 +48,7 @@ func TestOwnedSynchronousSendReturnsCapturedTransportAcrossReplacement(t *testin | |||
| 47 | 48 | replacement := &closeTrackingTransport{} | |
| 48 | 49 | sendErr := errors.New("owned send failed") | |
| 49 | 50 | ac := &attachedClient{output: newOutputStateStream()} | |
| 50 | - | failed := &ownedSwapErrorTransport{ac: ac, replacement: replacement, err: sendErr, sent: make(chan ports.Frame, 1)} | |
| 51 | + | failed := &ownedSwapErrorTransport{ac: ac, replacement: replacement, err: sendErr, sent: make(chan wire.Frame, 1)} | |
| 51 | 52 | ac.replaceTransport(failed) | |
| 52 | 53 | sess := &session{sessionCore: sessionCore{name: "work", attachments: map[*attachedClient]struct{}{ac: {}}}} | |
| 53 | 54 | ac.setSession(sess) | |
| @@ -57,7 +58,7 @@ func TestOwnedSynchronousSendReturnsCapturedTransportAcrossReplacement(t *testin | |||
| 57 | 58 | require.ErrorIs(t, err, sendErr) | |
| 58 | 59 | require.Same(t, failed, used) | |
| 59 | 60 | require.Same(t, replacement, ac.transport()) | |
| 60 | - | out, decodeErr := ports.UnmarshalOutput((<-failed.sent).Payload) | |
| 61 | + | out, decodeErr := wire.UnmarshalOutput((<-failed.sent).Payload) | |
| 61 | 62 | require.NoError(t, decodeErr) | |
| 62 | 63 | require.Equal(t, []byte("copy"), out.Data) | |
| 63 | 64 | d.detachOnSendError(sess, ac, used) | |
| @@ -71,29 +72,29 @@ type swapErrorTransport struct { | |||
| 71 | 72 | err error | |
| 72 | 73 | } | |
| 73 | 74 | ||
| 74 | - | func (t *swapErrorTransport) Send(ports.Frame) error { | |
| 75 | + | func (t *swapErrorTransport) Send(wire.Frame) error { | |
| 75 | 76 | t.ac.replaceTransport(t.replacement) | |
| 76 | 77 | return t.err | |
| 77 | 78 | } | |
| 78 | 79 | ||
| 79 | - | func (t *swapErrorTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 80 | - | func (t *swapErrorTransport) Close() error { return nil } | |
| 80 | + | func (t *swapErrorTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 81 | + | func (t *swapErrorTransport) Close() error { return nil } | |
| 81 | 82 | ||
| 82 | 83 | type ownedSwapErrorTransport struct { | |
| 83 | 84 | ac *attachedClient | |
| 84 | 85 | replacement ports.Transport | |
| 85 | 86 | err error | |
| 86 | - | sent chan ports.Frame | |
| 87 | + | sent chan wire.Frame | |
| 87 | 88 | } | |
| 88 | 89 | ||
| 89 | - | func (t *ownedSwapErrorTransport) Send(f ports.Frame) error { return t.SendSynchronous(f) } | |
| 90 | - | func (t *ownedSwapErrorTransport) SendSynchronous(f ports.Frame) error { | |
| 90 | + | func (t *ownedSwapErrorTransport) Send(f wire.Frame) error { return t.SendSynchronous(f) } | |
| 91 | + | func (t *ownedSwapErrorTransport) SendSynchronous(f wire.Frame) error { | |
| 91 | 92 | t.sent <- f | |
| 92 | 93 | t.ac.replaceTransport(t.replacement) | |
| 93 | 94 | return t.err | |
| 94 | 95 | } | |
| 95 | - | func (t *ownedSwapErrorTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 96 | - | func (t *ownedSwapErrorTransport) Close() error { return nil } | |
| 96 | + | func (t *ownedSwapErrorTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 97 | + | func (t *ownedSwapErrorTransport) Close() error { return nil } | |
| 97 | 98 | ||
| 98 | 99 | // stubClock returns timers whose channel never fires, so a scheduler under it | |
| 99 | 100 | // blocks in its debounce loop until the session context is cancelled. Used by | |
| @@ -117,7 +118,7 @@ func TestCopyModeDocumentCarriesPaneRowIDs(t *testing.T) { | |||
| 117 | 118 | require.NotEqual(t, historyID, liveID) | |
| 118 | 119 | ||
| 119 | 120 | d.enterCopyMode(sess, ac) | |
| 120 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 121 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 121 | 122 | doc := ac.overlays.copyDocument | |
| 122 | 123 | ||
| 123 | 124 | require.Equal(t, 0, doc.FindRowID(historyID)) | |
| @@ -197,7 +198,7 @@ func TestCopyModePaletteCommandEntersAndDoesNotForward(t *testing.T) { | |||
| 197 | 198 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | |
| 198 | 199 | ||
| 199 | 200 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 200 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 201 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 201 | 202 | d.handleInput(sess, ac, []byte("VIS\r")) | |
| 202 | 203 | ||
| 203 | 204 | if ac.overlays.copyMode == nil { | |
| @@ -208,16 +209,16 @@ func TestCopyModePaletteCommandEntersAndDoesNotForward(t *testing.T) { | |||
| 208 | 209 | t.Fatalf("scrollback binding forwarded to PTY: %q", got) | |
| 209 | 210 | default: | |
| 210 | 211 | } | |
| 211 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 212 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 212 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 213 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 213 | 214 | require.NoError(t, err) | |
| 214 | 215 | if got := string(msg.Data); !strings.Contains(got, "[SCROLL]") || strings.Contains(got, "[SELECT]") || strings.Contains(got, "[COPY]") { | |
| 215 | 216 | t.Fatalf("passive scrollback paint = %q, want [SCROLL] without [SELECT]/[COPY]", got) | |
| 216 | 217 | } | |
| 217 | 218 | ||
| 218 | 219 | d.handleInput(sess, ac, []byte(" ")) | |
| 219 | - | out = awaitFrame(t, sends, ports.MsgOutput) | |
| 220 | - | msg, err = ports.UnmarshalOutput(out.Payload) | |
| 220 | + | out = awaitFrame(t, sends, wire.MsgOutput) | |
| 221 | + | msg, err = wire.UnmarshalOutput(out.Payload) | |
| 221 | 222 | require.NoError(t, err) | |
| 222 | 223 | if got := string(msg.Data); !strings.Contains(got, "[SELECT]") || strings.Contains(got, "[SCROLL]") { | |
| 223 | 224 | t.Fatalf("visual selection paint = %q, want [SELECT] without [SCROLL]", got) | |
| @@ -233,9 +234,9 @@ func TestCopyModeSearchModalRoutesBatchedInputAfterSlash(t *testing.T) { | |||
| 233 | 234 | copy(pane.screen.Frame.Row(1), testRow("beta alpha")) | |
| 234 | 235 | ||
| 235 | 236 | d.enterCopyMode(sess, ac) | |
| 236 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 237 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 237 | 238 | d.handleInput(sess, ac, []byte("/alpha\r")) | |
| 238 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 239 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 239 | 240 | ||
| 240 | 241 | require.Nil(t, ac.overlays.copySearch) | |
| 241 | 242 | require.NotNil(t, ac.overlays.copyMode) | |
| @@ -257,32 +258,32 @@ func TestCopyModeSearchModalJumpsAndKeepsNavigation(t *testing.T) { | |||
| 257 | 258 | copy(pane.screen.Frame.Row(2), testRow("gamma")) | |
| 258 | 259 | ||
| 259 | 260 | d.enterCopyMode(sess, ac) | |
| 260 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 261 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 261 | 262 | d.handleInput(sess, ac, []byte("/")) | |
| 262 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 263 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 263 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 264 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 264 | 265 | require.NoError(t, err) | |
| 265 | 266 | require.Contains(t, string(msg.Data), "Search") | |
| 266 | 267 | require.NotNil(t, ac.overlays.copySearch) | |
| 267 | 268 | ||
| 268 | 269 | d.handleInput(sess, ac, []byte("alpha")) | |
| 269 | - | out = awaitFrame(t, sends, ports.MsgOutput) | |
| 270 | - | msg, err = ports.UnmarshalOutput(out.Payload) | |
| 270 | + | out = awaitFrame(t, sends, wire.MsgOutput) | |
| 271 | + | msg, err = wire.UnmarshalOutput(out.Payload) | |
| 271 | 272 | require.NoError(t, err) | |
| 272 | 273 | require.Contains(t, string(msg.Data), "/alpha") | |
| 273 | 274 | require.Contains(t, string(msg.Data), "1:1 alpha") | |
| 274 | 275 | require.Contains(t, string(msg.Data), "2:6 beta alpha") | |
| 275 | 276 | ||
| 276 | 277 | d.handleInput(sess, ac, []byte("\r")) | |
| 277 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 278 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 278 | 279 | require.Nil(t, ac.overlays.copySearch) | |
| 279 | 280 | require.Equal(t, 0, ac.overlays.copyMode.Cursor().Row) | |
| 280 | 281 | ||
| 281 | 282 | d.handleInput(sess, ac, []byte("n")) | |
| 282 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 283 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 283 | 284 | require.Equal(t, 1, ac.overlays.copyMode.Cursor().Row) | |
| 284 | 285 | d.handleInput(sess, ac, []byte("N")) | |
| 285 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 286 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 286 | 287 | require.Equal(t, 0, ac.overlays.copyMode.Cursor().Row) | |
| 287 | 288 | ||
| 288 | 289 | select { | |
| @@ -301,17 +302,17 @@ func TestCopyModeSearchModalSelectionPreviewsBehindModal(t *testing.T) { | |||
| 301 | 302 | copy(pane.screen.Frame.Row(2), testRow("gamma")) | |
| 302 | 303 | ||
| 303 | 304 | d.enterCopyMode(sess, ac) | |
| 304 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 305 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 305 | 306 | ||
| 306 | 307 | d.handleInput(sess, ac, []byte("/")) | |
| 307 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 308 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 308 | 309 | d.handleInput(sess, ac, []byte("alpha")) | |
| 309 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 310 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 310 | 311 | require.NotNil(t, ac.overlays.copySearch) | |
| 311 | 312 | require.Equal(t, 0, ac.overlays.copyMode.Cursor().Row, "typing a query previews the selected first result behind the modal") | |
| 312 | 313 | ||
| 313 | 314 | d.handleInput(sess, ac, []byte{0x0e}) | |
| 314 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 315 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 315 | 316 | require.NotNil(t, ac.overlays.copySearch) | |
| 316 | 317 | require.Equal(t, 1, ac.overlays.copyMode.Cursor().Row, "moving modal selection previews that result without Enter") | |
| 317 | 318 | } | |
| @@ -325,9 +326,9 @@ func TestCopyModeSearchModalCapturesMouseAndClearsOnExit(t *testing.T) { | |||
| 325 | 326 | copy(pane.screen.Frame.Row(0), testRow("live alpha")) | |
| 326 | 327 | ||
| 327 | 328 | d.enterCopyMode(sess, ac) | |
| 328 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 329 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 329 | 330 | d.handleInput(sess, ac, []byte("/alpha")) | |
| 330 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 331 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 331 | 332 | require.NotNil(t, ac.overlays.copySearch) | |
| 332 | 333 | cursor := ac.overlays.copyMode.Cursor().Row | |
| 333 | 334 | ||
| @@ -336,11 +337,11 @@ func TestCopyModeSearchModalCapturesMouseAndClearsOnExit(t *testing.T) { | |||
| 336 | 337 | require.Equal(t, cursor, ac.overlays.copyMode.Cursor().Row) | |
| 337 | 338 | ||
| 338 | 339 | d.handleInput(sess, ac, []byte("\x1b")) | |
| 339 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 340 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 340 | 341 | require.Nil(t, ac.overlays.copySearch) | |
| 341 | 342 | require.NotNil(t, ac.overlays.copyMode) | |
| 342 | 343 | d.handleInput(sess, ac, []byte("q")) | |
| 343 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 344 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 344 | 345 | require.Nil(t, ac.overlays.copySearch) | |
| 345 | 346 | require.Nil(t, ac.overlays.copyMode) | |
| 346 | 347 | } | |
| @@ -355,7 +356,7 @@ func TestCopyModeInputNotForwardedAndOSC52Copy(t *testing.T) { | |||
| 355 | 356 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | |
| 356 | 357 | ||
| 357 | 358 | d.enterCopyMode(sess, ac) | |
| 358 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 359 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 359 | 360 | d.handleInput(sess, ac, []byte{'g', ' ', 'j', 'y'}) | |
| 360 | 361 | ||
| 361 | 362 | select { | |
| @@ -363,8 +364,8 @@ func TestCopyModeInputNotForwardedAndOSC52Copy(t *testing.T) { | |||
| 363 | 364 | t.Fatalf("copy-mode navigation forwarded to PTY: %q", got) | |
| 364 | 365 | default: | |
| 365 | 366 | } | |
| 366 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 367 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 367 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 368 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 368 | 369 | require.NoError(t, err) | |
| 369 | 370 | if got, want := string(msg.Data), "\x1b]52;c;b2xkMQpvbGQy\x07"; got != want { | |
| 370 | 371 | t.Fatalf("OSC52 = %q, want %q", got, want) | |
| @@ -372,8 +373,8 @@ func TestCopyModeInputNotForwardedAndOSC52Copy(t *testing.T) { | |||
| 372 | 373 | if ac.overlays.copyMode != nil { | |
| 373 | 374 | t.Fatal("copy mode still active after yank") | |
| 374 | 375 | } | |
| 375 | - | live := awaitFrame(t, sends, ports.MsgOutput) | |
| 376 | - | liveMsg, err := ports.UnmarshalOutput(live.Payload) | |
| 376 | + | live := awaitFrame(t, sends, wire.MsgOutput) | |
| 377 | + | liveMsg, err := wire.UnmarshalOutput(live.Payload) | |
| 377 | 378 | require.NoError(t, err) | |
| 378 | 379 | if strings.Contains(string(liveMsg.Data), "[COPY]") || strings.Contains(string(liveMsg.Data), "[SCROLL]") { | |
| 379 | 380 | t.Fatalf("live repaint still contains copy/scroll status: %q", string(liveMsg.Data)) | |
| @@ -386,8 +387,8 @@ func TestCopyModeInputNotForwardedAndOSC52Copy(t *testing.T) { | |||
| 386 | 387 | } | |
| 387 | 388 | ||
| 388 | 389 | d.paint(sess, ac, true, nil) | |
| 389 | - | followup := awaitFrame(t, sends, ports.MsgOutput) | |
| 390 | - | followupMsg, err := ports.UnmarshalOutput(followup.Payload) | |
| 390 | + | followup := awaitFrame(t, sends, wire.MsgOutput) | |
| 391 | + | followupMsg, err := wire.UnmarshalOutput(followup.Payload) | |
| 391 | 392 | require.NoError(t, err) | |
| 392 | 393 | if strings.Contains(string(followupMsg.Data), "copied 9 chars to clipboard") { | |
| 393 | 394 | t.Fatalf("copy feedback persisted after next repaint: %q", string(followupMsg.Data)) | |
| @@ -430,9 +431,9 @@ func TestScrollbackEvictionFeedsCopyModeYank(t *testing.T) { | |||
| 430 | 431 | } | |
| 431 | 432 | var hg sync.WaitGroup | |
| 432 | 433 | hg.Go(func() { d.handleConn(tr) }) | |
| 433 | - | awaitFrame(t, sends, ports.MsgWelcome) | |
| 434 | + | awaitFrame(t, sends, wire.MsgWelcome) | |
| 434 | 435 | advanceRender() // initial coordinator invalidation | |
| 435 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 436 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 436 | 437 | ||
| 437 | 438 | for i := range 12 { | |
| 438 | 439 | reads <- fmt.Appendf(nil, "line-%02d\r\n", i) | |
| @@ -469,8 +470,8 @@ func TestScrollbackEvictionFeedsCopyModeYank(t *testing.T) { | |||
| 469 | 470 | ||
| 470 | 471 | var payload string | |
| 471 | 472 | require.Eventually(t, func() bool { | |
| 472 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 473 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 473 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 474 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 474 | 475 | require.NoError(t, err) | |
| 475 | 476 | payload = string(msg.Data) | |
| 476 | 477 | return strings.HasPrefix(payload, "\x1b]52;c;") | |
| @@ -495,14 +496,14 @@ func TestCopyModeEscapeRestoresLiveFullRepaint(t *testing.T) { | |||
| 495 | 496 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | |
| 496 | 497 | ||
| 497 | 498 | d.enterCopyMode(sess, ac) | |
| 498 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 499 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 499 | 500 | d.handleInput(sess, ac, []byte("q")) | |
| 500 | 501 | ||
| 501 | 502 | if ac.overlays.copyMode != nil { | |
| 502 | 503 | t.Fatal("copy mode still active after q") | |
| 503 | 504 | } | |
| 504 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 505 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 505 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 506 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 506 | 507 | require.NoError(t, err) | |
| 507 | 508 | if strings.Contains(string(msg.Data), "[COPY]") || !strings.Contains(string(msg.Data), "live") { | |
| 508 | 509 | t.Fatalf("exit repaint = %q, want live full repaint without copy status", string(msg.Data)) | |
| @@ -531,7 +532,7 @@ func TestCopyModeSplitArrowDoesNotExit(t *testing.T) { | |||
| 531 | 532 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | |
| 532 | 533 | ||
| 533 | 534 | d.enterCopyMode(sess, ac) | |
| 534 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 535 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 535 | 536 | for _, input := range tc.input { | |
| 536 | 537 | d.handleInput(sess, ac, input) | |
| 537 | 538 | } | |
| @@ -551,11 +552,11 @@ func TestCopyModeOversizedYankShowsTooLargeFeedback(t *testing.T) { | |||
| 551 | 552 | copy(sess.tabs[0].focusedPane().screen.Frame.Row(0), testRow(longLine)) | |
| 552 | 553 | ||
| 553 | 554 | d.enterCopyMode(sess, ac) | |
| 554 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 555 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 555 | 556 | d.handleInput(sess, ac, []byte{' ', 'y'}) | |
| 556 | 557 | ||
| 557 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 558 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 558 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 559 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 559 | 560 | require.NoError(t, err) | |
| 560 | 561 | if strings.Contains(string(msg.Data), "\x1b]52;") { | |
| 561 | 562 | t.Fatalf("oversized yank emitted OSC52: %q", string(msg.Data)) | |
| @@ -574,7 +575,7 @@ func TestCopyModeLoneEscapeExitsAfterDelay(t *testing.T) { | |||
| 574 | 575 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | |
| 575 | 576 | ||
| 576 | 577 | d.enterCopyMode(sess, ac) | |
| 577 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 578 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 578 | 579 | d.handleInput(sess, ac, []byte("\x1b")) | |
| 579 | 580 | timer := <-clk.timers | |
| 580 | 581 | ac.overlays.copyMu.Lock() | |
| @@ -598,11 +599,11 @@ func TestCopyModePendingEscapeDoesNotCloseNewMode(t *testing.T) { | |||
| 598 | 599 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | |
| 599 | 600 | ||
| 600 | 601 | d.enterCopyMode(sess, ac) | |
| 601 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 602 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 602 | 603 | d.handleInput(sess, ac, []byte("\x1b")) | |
| 603 | 604 | timer := <-clk.timers | |
| 604 | 605 | d.enterCopyMode(sess, ac) | |
| 605 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 606 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 606 | 607 | ||
| 607 | 608 | ac.overlays.copyMu.Lock() | |
| 608 | 609 | require.Nil(t, ac.overlays.copyESC.timer) | |
| @@ -641,14 +642,14 @@ func TestCopyModeEmptyYankDoesNotClearClipboard(t *testing.T) { | |||
| 641 | 642 | sess.tabs[0].focusedPane().screen.Write([]byte("live")) | |
| 642 | 643 | ||
| 643 | 644 | d.enterCopyMode(sess, ac) | |
| 644 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 645 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 645 | 646 | d.handleInput(sess, ac, tc.input) | |
| 646 | 647 | ||
| 647 | 648 | if ac.overlays.copyMode != nil { | |
| 648 | 649 | t.Fatal("copy mode still active after empty yank") | |
| 649 | 650 | } | |
| 650 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 651 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 651 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 652 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 652 | 653 | require.NoError(t, err) | |
| 653 | 654 | if strings.Contains(string(msg.Data), "\x1b]52;") { | |
| 654 | 655 | t.Fatalf("empty yank emitted OSC52 clipboard clear: %q", string(msg.Data)) | |
| @@ -667,7 +668,7 @@ func TestHandleCopyInputUsesImmutableSnapshotWithoutPaneLock(t *testing.T) { | |||
| 667 | 668 | pane := testAttachmentTab(sess).focusedPane() | |
| 668 | 669 | pane.screen.Write([]byte("live")) | |
| 669 | 670 | d.enterCopyMode(sess, ac) | |
| 670 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 671 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 671 | 672 | ||
| 672 | 673 | pane.mu.Lock() | |
| 673 | 674 | defer pane.mu.Unlock() | |
| @@ -769,7 +770,7 @@ func TestCopyModeCapturesSourceAndRetainsItAcrossFocusMove(t *testing.T) { | |||
| 769 | 770 | } | |
| 770 | 771 | ||
| 771 | 772 | d.enterCopyMode(sess, ac) | |
| 772 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 773 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 773 | 774 | ac.overlays.copyMu.Lock() | |
| 774 | 775 | captured := ac.overlays.copyPane | |
| 775 | 776 | ac.overlays.copyMu.Unlock() | |
| @@ -780,8 +781,8 @@ func TestCopyModeCapturesSourceAndRetainsItAcrossFocusMove(t *testing.T) { | |||
| 780 | 781 | tb.mu.Unlock() | |
| 781 | 782 | ||
| 782 | 783 | d.handleInput(sess, ac, []byte{'g', ' ', 'j', 'y'}) | |
| 783 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 784 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 784 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 785 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 785 | 786 | require.NoError(t, err) | |
| 786 | 787 | wantOSC := "\x1b]52;c;" + base64.StdEncoding.EncodeToString([]byte(tc.wantText)) + "\x07" | |
| 787 | 788 | require.Equal(t, wantOSC, string(msg.Data)) | |
| @@ -809,15 +810,15 @@ func TestFloatingCopyModeWheelUsesCapturedSnapshot(t *testing.T) { | |||
| 809 | 810 | fp.mu.Unlock() | |
| 810 | 811 | ||
| 811 | 812 | d.enterCopyMode(sess, ac) | |
| 812 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 813 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 813 | 814 | require.Equal(t, total-1, ac.overlays.copyMode.Cursor().Row) | |
| 814 | 815 | ||
| 815 | 816 | d.copyWheel(sess, ac, -3) | |
| 816 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 817 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 817 | 818 | require.Equal(t, total-4, ac.overlays.copyMode.Cursor().Row) | |
| 818 | 819 | ||
| 819 | 820 | d.copyWheel(sess, ac, 3) | |
| 820 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 821 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 821 | 822 | require.Nil(t, ac.overlays.copyMode, "wheel down reaching the captured bottom exits copy mode") | |
| 822 | 823 | } | |
| 823 | 824 | ||
| @@ -832,7 +833,7 @@ func TestFloatingCopyModeMouseSelectsFloatingRows(t *testing.T) { | |||
| 832 | 833 | fp.screen.Write([]byte("live")) | |
| 833 | 834 | ||
| 834 | 835 | d.enterCopyMode(sess, ac) | |
| 835 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 836 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 836 | 837 | ac.overlays.copyMu.Lock() | |
| 837 | 838 | viewportTop := ac.overlays.copyMode.ViewportTop | |
| 838 | 839 | ac.overlays.copyMu.Unlock() | |
| @@ -842,12 +843,12 @@ func TestFloatingCopyModeMouseSelectsFloatingRows(t *testing.T) { | |||
| 842 | 843 | // offset); clicking a row must select exactly that row. | |
| 843 | 844 | press := fmt.Sprintf("\x1b[<0;%d;%dM", inner.X+3, inner.Y+3) | |
| 844 | 845 | d.handleInput(sess, ac, []byte(press)) | |
| 845 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 846 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 846 | 847 | require.Equal(t, viewportTop+1, ac.overlays.copyMode.Cursor().Row) | |
| 847 | 848 | ||
| 848 | 849 | motion := fmt.Sprintf("\x1b[<32;%d;%dM", inner.X+3, inner.Y+4) | |
| 849 | 850 | d.handleInput(sess, ac, []byte(motion)) | |
| 850 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 851 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 851 | 852 | selection := ac.overlays.copyMode.Selection() | |
| 852 | 853 | require.True(t, selection.Enabled) | |
| 853 | 854 | require.Equal(t, viewportTop+1, selection.Anchor.Row) | |
| @@ -863,7 +864,7 @@ func TestFloatingExitClearsCopyModeBeforeRepaint(t *testing.T) { | |||
| 863 | 864 | fp.screen.Write([]byte("flt-live")) | |
| 864 | 865 | ||
| 865 | 866 | d.enterCopyMode(sess, ac) | |
| 866 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 867 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 867 | 868 | tb.mu.Lock() | |
| 868 | 869 | generation := tb.floating.generation | |
| 869 | 870 | publishPaneOwner(fp, sess, tb, generation) | |
| @@ -896,8 +897,8 @@ func TestMouseDragCopyEntryCapturesSourceForYank(t *testing.T) { | |||
| 896 | 897 | require.Same(t, pane, captured, "drag entry must capture the copy source pane") | |
| 897 | 898 | ||
| 898 | 899 | d.handleInput(sess, ac, []byte("y")) | |
| 899 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 900 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 900 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 901 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 901 | 902 | require.NoError(t, err) | |
| 902 | 903 | want := "\x1b]52;c;" + base64.StdEncoding.EncodeToString([]byte("alpha\nb")) + "\x07" | |
| 903 | 904 | require.Equal(t, want, string(msg.Data)) | |
M internal/usecase/daemon/daemon.go +14 -13
| @@ -18,6 +18,7 @@ import ( | |||
| 18 | 18 | "github.com/bnema/vev/internal/domain" | |
| 19 | 19 | "github.com/bnema/vev/internal/ports" | |
| 20 | 20 | "github.com/bnema/vev/internal/protocol" | |
| 21 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 21 | 22 | "github.com/bnema/vev/internal/usecase/keys" | |
| 22 | 23 | recoveryusecase "github.com/bnema/vev/internal/usecase/recovery" | |
| 23 | 24 | ) | |
| @@ -1020,7 +1021,7 @@ func (d *Daemon) handleConn(tr ports.Transport) { | |||
| 1020 | 1021 | defer finishHandshake() | |
| 1021 | 1022 | defer stopTransport() | |
| 1022 | 1023 | ||
| 1023 | - | var first ports.Frame | |
| 1024 | + | var first wire.Frame | |
| 1024 | 1025 | err := boundedHandshakeOperation(handshakeCtx, tr, func() error { | |
| 1025 | 1026 | var recvErr error | |
| 1026 | 1027 | first, recvErr = tr.Recv() | |
| @@ -1033,27 +1034,27 @@ func (d *Daemon) handleConn(tr ports.Transport) { | |||
| 1033 | 1034 | return | |
| 1034 | 1035 | } | |
| 1035 | 1036 | switch first.Type { | |
| 1036 | - | case ports.MsgList: | |
| 1037 | + | case wire.MsgList: | |
| 1037 | 1038 | stopTransport() | |
| 1038 | 1039 | finishHandshake() | |
| 1039 | 1040 | d.handleList(tr) | |
| 1040 | - | case ports.MsgCommand: | |
| 1041 | + | case wire.MsgCommand: | |
| 1041 | 1042 | stopTransport() | |
| 1042 | 1043 | finishHandshake() | |
| 1043 | 1044 | if err := d.handleCommand(tr, first); err != nil { | |
| 1044 | 1045 | d.log.Warn("command handler failed", "err", err) | |
| 1045 | 1046 | } | |
| 1046 | - | case ports.MsgRemotePreviewRequest: | |
| 1047 | + | case wire.MsgRemotePreviewRequest: | |
| 1047 | 1048 | stopTransport() | |
| 1048 | 1049 | finishHandshake() | |
| 1049 | 1050 | if err := d.handleRemotePreview(tr, first); err != nil { | |
| 1050 | 1051 | d.log.Warn("remote preview handler failed", "err", err) | |
| 1051 | 1052 | } | |
| 1052 | - | case ports.MsgKill: | |
| 1053 | + | case wire.MsgKill: | |
| 1053 | 1054 | stopTransport() | |
| 1054 | 1055 | finishHandshake() | |
| 1055 | 1056 | d.handleKill(tr, first) | |
| 1056 | - | case ports.MsgHello: | |
| 1057 | + | case wire.MsgHello: | |
| 1057 | 1058 | d.handleHelloWithContext(handshakeCtx, timedOut, stopTransport, finishHandshake, tr, first) | |
| 1058 | 1059 | default: | |
| 1059 | 1060 | d.log.Warn("hello rejected", "err", "expected hello", "type", first.Type) | |
| @@ -1110,10 +1111,10 @@ func (d *Daemon) handleList(tr ports.Transport) { | |||
| 1110 | 1111 | // handleKill terminates the requested live session or stopped named session, | |
| 1111 | 1112 | // or all sessions, and closes the control connection; the resulting EOF is the | |
| 1112 | 1113 | // client's success signal. | |
| 1113 | - | func (d *Daemon) handleKill(tr ports.Transport, f ports.Frame) { | |
| 1114 | + | func (d *Daemon) handleKill(tr ports.Transport, f wire.Frame) { | |
| 1114 | 1115 | defer func() { _ = tr.Close() }() | |
| 1115 | 1116 | ||
| 1116 | - | k, err := ports.UnmarshalKill(f.Payload) | |
| 1117 | + | k, err := wire.UnmarshalKill(f.Payload) | |
| 1117 | 1118 | if err != nil { | |
| 1118 | 1119 | _ = d.boundedControlSend(tr, frameError(protocol.ErrInternal, "malformed kill request")) | |
| 1119 | 1120 | return | |
| @@ -1151,7 +1152,7 @@ func (d *Daemon) handleKill(tr ports.Transport, f ports.Frame) { | |||
| 1151 | 1152 | // handleHello runs the attach handshake for direct package callers. Accepted | |
| 1152 | 1153 | // connections use handleHelloWithContext so the deadline also covers the first | |
| 1153 | 1154 | // frame read in handleConn. | |
| 1154 | - | func (d *Daemon) handleHello(tr ports.Transport, f ports.Frame) { | |
| 1155 | + | func (d *Daemon) handleHello(tr ports.Transport, f wire.Frame) { | |
| 1155 | 1156 | handshakeCtx, timedOut, finishHandshake := d.newHandshakeContext(context.Background()) | |
| 1156 | 1157 | stopTransport := watchHandshakeTransport(handshakeCtx, tr) | |
| 1157 | 1158 | defer finishHandshake() | |
| @@ -1161,21 +1162,21 @@ func (d *Daemon) handleHello(tr ports.Transport, f ports.Frame) { | |||
| 1161 | 1162 | ||
| 1162 | 1163 | // handleHelloWithContext runs the attach handshake: version check, intent | |
| 1163 | 1164 | // routing, Welcome, guaranteed first paint, then the per-connection input loop. | |
| 1164 | - | func (d *Daemon) handleHelloWithContext(handshakeCtx context.Context, timedOut <-chan struct{}, stopHandshakeTransport, finishHandshake func(), tr ports.Transport, f ports.Frame) { | |
| 1165 | + | func (d *Daemon) handleHelloWithContext(handshakeCtx context.Context, timedOut <-chan struct{}, stopHandshakeTransport, finishHandshake func(), tr ports.Transport, f wire.Frame) { | |
| 1165 | 1166 | if err := handshakeContextError(context.Background(), timedOut, handshakeCtx.Err()); err != nil { | |
| 1166 | 1167 | _ = tr.Close() | |
| 1167 | 1168 | return | |
| 1168 | 1169 | } | |
| 1169 | - | sendHandshake := func(frame ports.Frame) error { | |
| 1170 | + | sendHandshake := func(frame wire.Frame) error { | |
| 1170 | 1171 | err := boundedHandshakeOperation(handshakeCtx, tr, func() error { return tr.Send(frame) }) | |
| 1171 | 1172 | if err != nil { | |
| 1172 | 1173 | return handshakeContextError(context.Background(), timedOut, err) | |
| 1173 | 1174 | } | |
| 1174 | 1175 | return nil | |
| 1175 | 1176 | } | |
| 1176 | - | h, err := ports.UnmarshalHello(f.Payload) | |
| 1177 | + | h, err := wire.UnmarshalHello(f.Payload) | |
| 1177 | 1178 | if err != nil { | |
| 1178 | - | if version, ok := ports.PeekHelloVersion(f.Payload); ok && version != protocol.Version { | |
| 1179 | + | if version, ok := wire.PeekHelloVersion(f.Payload); ok && version != protocol.Version { | |
| 1179 | 1180 | d.log.Warn("hello rejected", "err", "protocol version mismatch", "version", version, "expected", protocol.Version) | |
| 1180 | 1181 | _ = sendHandshake(frameError(protocol.ErrVersionMismatch, "protocol version mismatch")) | |
| 1181 | 1182 | } else { | |
M internal/usecase/daemon/daemon_test.go +36 -35
| @@ -17,6 +17,7 @@ import ( | |||
| 17 | 17 | "github.com/bnema/vev/internal/ports" | |
| 18 | 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 19 | 19 | "github.com/bnema/vev/internal/protocol" | |
| 20 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 20 | 21 | "github.com/bnema/vev/internal/usecase/keys" | |
| 21 | 22 | ) | |
| 22 | 23 | ||
| @@ -236,11 +237,11 @@ func newFactorySeq(t *testing.T, ptys ...ports.PTY) *portsmocks.MockPTYFactory { | |||
| 236 | 237 | // newConn scripts a MockTransport: Recv yields first then more (in order), | |
| 237 | 238 | // then blocks until the connection is released or Closed (returning io.EOF). | |
| 238 | 239 | // Every Send is captured on the returned channel. | |
| 239 | - | func newConn(t *testing.T, first ports.Frame, more ...ports.Frame) (*portsmocks.MockTransport, chan ports.Frame, func()) { | |
| 240 | + | func newConn(t *testing.T, first wire.Frame, more ...wire.Frame) (*portsmocks.MockTransport, chan wire.Frame, func()) { | |
| 240 | 241 | t.Helper() | |
| 241 | 242 | tr := portsmocks.NewMockTransport(t) | |
| 242 | - | sends := make(chan ports.Frame, 64) | |
| 243 | - | recvCh := make(chan ports.Frame, 1+len(more)) | |
| 243 | + | sends := make(chan wire.Frame, 64) | |
| 244 | + | recvCh := make(chan wire.Frame, 1+len(more)) | |
| 244 | 245 | recvCh <- first | |
| 245 | 246 | for _, f := range more { | |
| 246 | 247 | recvCh <- f | |
| @@ -249,15 +250,15 @@ func newConn(t *testing.T, first ports.Frame, more ...ports.Frame) (*portsmocks. | |||
| 249 | 250 | var once sync.Once | |
| 250 | 251 | closeDone := func() { once.Do(func() { close(done) }) } | |
| 251 | 252 | ||
| 252 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | |
| 253 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { | |
| 253 | 254 | select { | |
| 254 | 255 | case f := <-recvCh: | |
| 255 | 256 | return f, nil | |
| 256 | 257 | case <-done: | |
| 257 | - | return ports.Frame{}, io.EOF | |
| 258 | + | return wire.Frame{}, io.EOF | |
| 258 | 259 | } | |
| 259 | 260 | }).Maybe() | |
| 260 | - | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f ports.Frame) error { | |
| 261 | + | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f wire.Frame) error { | |
| 261 | 262 | sends <- f | |
| 262 | 263 | return nil | |
| 263 | 264 | }).Maybe() | |
| @@ -265,14 +266,14 @@ func newConn(t *testing.T, first ports.Frame, more ...ports.Frame) (*portsmocks. | |||
| 265 | 266 | return tr, sends, closeDone | |
| 266 | 267 | } | |
| 267 | 268 | ||
| 268 | - | func mustHello(intent uint8, name string, sz domain.Size) ports.Frame { | |
| 269 | - | return ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(protocol.Hello{ | |
| 269 | + | func mustHello(intent uint8, name string, sz domain.Size) wire.Frame { | |
| 270 | + | return wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(protocol.Hello{ | |
| 270 | 271 | Version: protocol.Version, Intent: intent, Name: name, Size: sz, TermEnv: "xterm-256color", | |
| 271 | 272 | })} | |
| 272 | 273 | } | |
| 273 | 274 | ||
| 274 | - | func frameInput(data []byte) ports.Frame { | |
| 275 | - | return ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: data})} | |
| 275 | + | func frameInput(data []byte) wire.Frame { | |
| 276 | + | return wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: data})} | |
| 276 | 277 | } | |
| 277 | 278 | ||
| 278 | 279 | func screenLineText(s *vt.Screen, y int) string { | |
| @@ -284,7 +285,7 @@ func screenLineText(s *vt.Screen, y int) string { | |||
| 284 | 285 | } | |
| 285 | 286 | ||
| 286 | 287 | // awaitFrame waits for the next frame of type typ on ch, failing on timeout. | |
| 287 | - | func awaitFrame(t *testing.T, ch chan ports.Frame, typ ports.MsgType) ports.Frame { | |
| 288 | + | func awaitFrame(t *testing.T, ch chan wire.Frame, typ wire.MsgType) wire.Frame { | |
| 288 | 289 | t.Helper() | |
| 289 | 290 | deadline := time.After(2 * time.Second) | |
| 290 | 291 | for { | |
| @@ -318,10 +319,10 @@ func sessionCount(d *Daemon) int { | |||
| 318 | 319 | ||
| 319 | 320 | func listSessions(t *testing.T, d *Daemon) protocol.Sessions { | |
| 320 | 321 | t.Helper() | |
| 321 | - | tr, sends, _ := newConn(t, ports.Frame{Type: ports.MsgList, Payload: ports.MarshalList(protocol.List{})}) | |
| 322 | + | tr, sends, _ := newConn(t, wire.Frame{Type: wire.MsgList, Payload: wire.MarshalList(protocol.List{})}) | |
| 322 | 323 | d.handleList(tr) | |
| 323 | - | f := awaitFrame(t, sends, ports.MsgSessions) | |
| 324 | - | sessions, err := ports.UnmarshalSessions(f.Payload) | |
| 324 | + | f := awaitFrame(t, sends, wire.MsgSessions) | |
| 325 | + | sessions, err := wire.UnmarshalSessions(f.Payload) | |
| 325 | 326 | require.NoError(t, err) | |
| 326 | 327 | return sessions | |
| 327 | 328 | } | |
| @@ -331,7 +332,7 @@ func listSessions(t *testing.T, d *Daemon) protocol.Sessions { | |||
| 331 | 332 | // transport mock while channels make both sides of the wire deterministic. | |
| 332 | 333 | type welcomeBlockingTransport struct { | |
| 333 | 334 | tr *portsmocks.MockTransport | |
| 334 | - | sends chan ports.Frame | |
| 335 | + | sends chan wire.Frame | |
| 335 | 336 | welcomeEntered chan struct{} | |
| 336 | 337 | releaseWelcome chan struct{} | |
| 337 | 338 | recvDone chan struct{} | |
| @@ -342,23 +343,23 @@ type welcomeBlockingTransport struct { | |||
| 342 | 343 | func newWelcomeBlockingTransport(t *testing.T) *welcomeBlockingTransport { | |
| 343 | 344 | t.Helper() | |
| 344 | 345 | b := &welcomeBlockingTransport{ | |
| 345 | - | sends: make(chan ports.Frame, 8), | |
| 346 | + | sends: make(chan wire.Frame, 8), | |
| 346 | 347 | welcomeEntered: make(chan struct{}), | |
| 347 | 348 | releaseWelcome: make(chan struct{}), | |
| 348 | 349 | recvDone: make(chan struct{}), | |
| 349 | 350 | } | |
| 350 | 351 | b.tr = portsmocks.NewMockTransport(t) | |
| 351 | - | b.tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f ports.Frame) error { | |
| 352 | + | b.tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f wire.Frame) error { | |
| 352 | 353 | b.sends <- f | |
| 353 | - | if f.Type == ports.MsgWelcome { | |
| 354 | + | if f.Type == wire.MsgWelcome { | |
| 354 | 355 | close(b.welcomeEntered) | |
| 355 | 356 | <-b.releaseWelcome | |
| 356 | 357 | } | |
| 357 | 358 | return nil | |
| 358 | 359 | }).Maybe() | |
| 359 | - | b.tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | |
| 360 | + | b.tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { | |
| 360 | 361 | <-b.recvDone | |
| 361 | - | return ports.Frame{}, io.EOF | |
| 362 | + | return wire.Frame{}, io.EOF | |
| 362 | 363 | }).Maybe() | |
| 363 | 364 | b.tr.EXPECT().Close().Return(nil).Maybe() | |
| 364 | 365 | t.Cleanup(b.finish) | |
| @@ -374,11 +375,11 @@ func (b *welcomeBlockingTransport) finish() { | |||
| 374 | 375 | b.closeOnce.Do(func() { close(b.recvDone) }) | |
| 375 | 376 | } | |
| 376 | 377 | ||
| 377 | - | func newCapturingTransport(t testing.TB) (*portsmocks.MockTransport, chan ports.Frame) { | |
| 378 | + | func newCapturingTransport(t testing.TB) (*portsmocks.MockTransport, chan wire.Frame) { | |
| 378 | 379 | t.Helper() | |
| 379 | 380 | tr := portsmocks.NewMockTransport(t) | |
| 380 | - | sends := make(chan ports.Frame, 64) | |
| 381 | - | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f ports.Frame) error { | |
| 381 | + | sends := make(chan wire.Frame, 64) | |
| 382 | + | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f wire.Frame) error { | |
| 382 | 383 | sends <- f | |
| 383 | 384 | return nil | |
| 384 | 385 | }).Maybe() | |
| @@ -386,22 +387,22 @@ func newCapturingTransport(t testing.TB) (*portsmocks.MockTransport, chan ports. | |||
| 386 | 387 | return tr, sends | |
| 387 | 388 | } | |
| 388 | 389 | ||
| 389 | - | func newManualSessionWithPTYs(t testing.TB, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan ports.Frame) { | |
| 390 | + | func newManualSessionWithPTYs(t testing.TB, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan wire.Frame) { | |
| 390 | 391 | t.Helper() | |
| 391 | 392 | return newManualSessionWithPTYsClock(t, stubClock{}, ptys...) | |
| 392 | 393 | } | |
| 393 | 394 | ||
| 394 | - | func newManualSessionWithPTYsClock(t testing.TB, clock ports.Clock, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan ports.Frame) { | |
| 395 | + | func newManualSessionWithPTYsClock(t testing.TB, clock ports.Clock, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan wire.Frame) { | |
| 395 | 396 | t.Helper() | |
| 396 | 397 | return newManualSessionWithPTYsClockCleanup(t, clock, true, ptys...) | |
| 397 | 398 | } | |
| 398 | 399 | ||
| 399 | - | func newManualSessionWithPTYsCleanup(t testing.TB, registerCleanup bool, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan ports.Frame) { | |
| 400 | + | func newManualSessionWithPTYsCleanup(t testing.TB, registerCleanup bool, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan wire.Frame) { | |
| 400 | 401 | t.Helper() | |
| 401 | 402 | return newManualSessionWithPTYsClockCleanup(t, stubClock{}, registerCleanup, ptys...) | |
| 402 | 403 | } | |
| 403 | 404 | ||
| 404 | - | func newManualSessionWithPTYsClockCleanup(t testing.TB, clock ports.Clock, registerCleanup bool, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan ports.Frame) { | |
| 405 | + | func newManualSessionWithPTYsClockCleanup(t testing.TB, clock ports.Clock, registerCleanup bool, ptys ...ports.PTY) (*Daemon, *session, *attachedClient, chan wire.Frame) { | |
| 405 | 406 | t.Helper() | |
| 406 | 407 | d := newTestDaemonWithCleanup(t, nil, clock, registerCleanup) | |
| 407 | 408 | tr, sends := newCapturingTransport(t) | |
| @@ -432,7 +433,7 @@ func newManualSessionWithPTYsClockCleanup(t testing.TB, clock ports.Clock, regis | |||
| 432 | 433 | return d, sess, ac, sends | |
| 433 | 434 | } | |
| 434 | 435 | ||
| 435 | - | func newManualTabSession(t *testing.T, n int) (*Daemon, *session, *attachedClient, chan ports.Frame, []func()) { | |
| 436 | + | func newManualTabSession(t *testing.T, n int) (*Daemon, *session, *attachedClient, chan wire.Frame, []func()) { | |
| 436 | 437 | t.Helper() | |
| 437 | 438 | ptys := make([]ports.PTY, 0, n) | |
| 438 | 439 | releases := make([]func(), 0, n) | |
| @@ -671,8 +672,8 @@ func TestHandleHelloDefersFreshOutputUntilWelcome(t *testing.T) { | |||
| 671 | 672 | ||
| 672 | 673 | awaitTestCompletion(t, tr.welcomeEntered, "timed out waiting for Welcome send") | |
| 673 | 674 | handshakeTimer := awaitHandshakeTimer(t, clock) | |
| 674 | - | welcome := awaitFrame(t, tr.sends, ports.MsgWelcome) | |
| 675 | - | require.Equal(t, ports.MsgWelcome, welcome.Type) | |
| 675 | + | welcome := awaitFrame(t, tr.sends, wire.MsgWelcome) | |
| 676 | + | require.Equal(t, wire.MsgWelcome, welcome.Type) | |
| 676 | 677 | sess := firstSession(d) | |
| 677 | 678 | sess.mu.Lock() | |
| 678 | 679 | ac := sess.snapshotAttachmentsLocked()[0] | |
| @@ -695,8 +696,8 @@ func TestHandleHelloDefersFreshOutputUntilWelcome(t *testing.T) { | |||
| 695 | 696 | requireNoCoordinatorOutputFrame(t, tr.sends) | |
| 696 | 697 | ||
| 697 | 698 | tr.release() | |
| 698 | - | output := awaitFrame(t, tr.sends, ports.MsgOutput) | |
| 699 | - | first, err := ports.UnmarshalOutput(output.Payload) | |
| 699 | + | output := awaitFrame(t, tr.sends, wire.MsgOutput) | |
| 700 | + | first, err := wire.UnmarshalOutput(output.Payload) | |
| 700 | 701 | require.NoError(t, err) | |
| 701 | 702 | require.Zero(t, first.Base, "the first post-Welcome frame is full") | |
| 702 | 703 | tr.finish() | |
| @@ -710,10 +711,10 @@ func TestHandleHelloDefersFreshOutputUntilWelcome(t *testing.T) { | |||
| 710 | 711 | // MsgDetached send until the transport is closed (mirroring a full kernel | |
| 711 | 712 | // send buffer: only Close fails the in-flight write). Serve must still tear | |
| 712 | 713 | ||
| 713 | - | func mustOutputData(t *testing.T, sends chan ports.Frame) []byte { | |
| 714 | + | func mustOutputData(t *testing.T, sends chan wire.Frame) []byte { | |
| 714 | 715 | t.Helper() | |
| 715 | - | f := awaitFrame(t, sends, ports.MsgOutput) | |
| 716 | - | out, err := ports.UnmarshalOutput(f.Payload) | |
| 716 | + | f := awaitFrame(t, sends, wire.MsgOutput) | |
| 717 | + | out, err := wire.UnmarshalOutput(f.Payload) | |
| 717 | 718 | require.NoError(t, err) | |
| 718 | 719 | return out.Data | |
| 719 | 720 | } | |
M internal/usecase/daemon/final_acceptance_test.go +4 -4
| @@ -5,8 +5,8 @@ import ( | |||
| 5 | 5 | ||
| 6 | 6 | vt "github.com/bnema/vev-vt" | |
| 7 | 7 | "github.com/bnema/vev/internal/domain" | |
| 8 | - | "github.com/bnema/vev/internal/ports" | |
| 9 | 8 | "github.com/bnema/vev/internal/protocol" | |
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 10 | 10 | "github.com/bnema/vev/internal/usecase/layout" | |
| 11 | 11 | "github.com/stretchr/testify/require" | |
| 12 | 12 | ) | |
| @@ -149,9 +149,9 @@ func TestAcceptanceAttachmentStateIsolationAcrossResetResizeAndDetach(t *testing | |||
| 149 | 149 | firstEpoch := first.output.currentEpoch() | |
| 150 | 150 | secondEpoch := second.output.currentEpoch() | |
| 151 | 151 | ||
| 152 | - | d.handleAttachmentClientFrame(secondToken, ports.Frame{ | |
| 153 | - | Type: ports.MsgOutputResetRequest, | |
| 154 | - | Payload: ports.MarshalOutputResetRequest(protocol.OutputResetRequest{}), | |
| 152 | + | d.handleAttachmentClientFrame(secondToken, wire.Frame{ | |
| 153 | + | Type: wire.MsgOutputResetRequest, | |
| 154 | + | Payload: wire.MarshalOutputResetRequest(protocol.OutputResetRequest{}), | |
| 155 | 155 | }) | |
| 156 | 156 | require.Greater(t, second.output.currentEpoch(), secondEpoch) | |
| 157 | 157 | require.Equal(t, firstEpoch, first.output.currentEpoch(), "peer output reset crossed attachment boundary") | |
M internal/usecase/daemon/floating_test.go +6 -5
| @@ -18,6 +18,7 @@ import ( | |||
| 18 | 18 | "github.com/bnema/vev/internal/ports" | |
| 19 | 19 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 20 | 20 | "github.com/bnema/vev/internal/protocol" | |
| 21 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 21 | 22 | scopy "github.com/bnema/vev/internal/usecase/copy" | |
| 22 | 23 | "github.com/bnema/vev/internal/usecase/layout" | |
| 23 | 24 | themeui "github.com/bnema/vev/internal/usecase/theme" | |
| @@ -482,7 +483,7 @@ func TestFloatingTeardownClearsCapturedCopyMode(t *testing.T) { | |||
| 482 | 483 | } | |
| 483 | 484 | ||
| 484 | 485 | func TestFloatingEOFRepaintsVisibleSlotOnly(t *testing.T) { | |
| 485 | - | newCase := func(t *testing.T, state floatingState) (*Daemon, *session, *attachedClient, chan ports.Frame, *tab, *pane, func()) { | |
| 486 | + | newCase := func(t *testing.T, state floatingState) (*Daemon, *session, *attachedClient, chan wire.Frame, *tab, *pane, func()) { | |
| 486 | 487 | t.Helper() | |
| 487 | 488 | normalPTY, releaseNormal := newBlockingPTY(t) | |
| 488 | 489 | d, sess, ac, sends := newManualSessionWithPTYs(t, normalPTY) | |
| @@ -513,8 +514,8 @@ func TestFloatingEOFRepaintsVisibleSlotOnly(t *testing.T) { | |||
| 513 | 514 | // Establish a renderer shadow first. The EOF repaint must reset it and | |
| 514 | 515 | // redraw the underlying cell rather than depending on popup damage. | |
| 515 | 516 | d.paint(sess, ac, true, nil) | |
| 516 | - | baseline := awaitFrame(t, sends, ports.MsgOutput) | |
| 517 | - | baselineOutput, err := ports.UnmarshalOutput(baseline.Payload) | |
| 517 | + | baseline := awaitFrame(t, sends, wire.MsgOutput) | |
| 518 | + | baselineOutput, err := wire.UnmarshalOutput(baseline.Payload) | |
| 518 | 519 | require.NoError(t, err) | |
| 519 | 520 | require.Contains(t, string(baselineOutput.Data), "underlying-cell") | |
| 520 | 521 | ||
| @@ -541,8 +542,8 @@ func TestFloatingEOFRepaintsVisibleSlotOnly(t *testing.T) { | |||
| 541 | 542 | require.Equal(t, floatingUninitialized, tb.floating.state) | |
| 542 | 543 | require.Nil(t, tb.floating.pane) | |
| 543 | 544 | tb.mu.Unlock() | |
| 544 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | |
| 545 | - | output, err := ports.UnmarshalOutput(repaint.Payload) | |
| 545 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) | |
| 546 | + | output, err := wire.UnmarshalOutput(repaint.Payload) | |
| 546 | 547 | require.NoError(t, err) | |
| 547 | 548 | require.Zero(t, output.Base, "visible EOF must force a dependency-free full repaint") | |
| 548 | 549 | require.Contains(t, string(output.Data), "underlying-cell", "repaint must restore cells previously covered by the popup") | |
M internal/usecase/daemon/graphics_output_test.go +12 -11
| @@ -15,6 +15,7 @@ import ( | |||
| 15 | 15 | "github.com/bnema/vev/internal/domain" | |
| 16 | 16 | "github.com/bnema/vev/internal/ports" | |
| 17 | 17 | "github.com/bnema/vev/internal/protocol" | |
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 18 | 19 | "github.com/bnema/vev/internal/usecase/layout" | |
| 19 | 20 | "github.com/stretchr/testify/require" | |
| 20 | 21 | ) | |
| @@ -53,7 +54,7 @@ type lateGraphicsCleanupTransport struct { | |||
| 53 | 54 | started chan struct{} | |
| 54 | 55 | release chan struct{} | |
| 55 | 56 | finished chan struct{} | |
| 56 | - | sends chan ports.Frame | |
| 57 | + | sends chan wire.Frame | |
| 57 | 58 | startedOnce sync.Once | |
| 58 | 59 | finishOnce sync.Once | |
| 59 | 60 | } | |
| @@ -63,11 +64,11 @@ func newLateGraphicsCleanupTransport() *lateGraphicsCleanupTransport { | |||
| 63 | 64 | started: make(chan struct{}), | |
| 64 | 65 | release: make(chan struct{}), | |
| 65 | 66 | finished: make(chan struct{}), | |
| 66 | - | sends: make(chan ports.Frame, 1), | |
| 67 | + | sends: make(chan wire.Frame, 1), | |
| 67 | 68 | } | |
| 68 | 69 | } | |
| 69 | 70 | ||
| 70 | - | func (t *lateGraphicsCleanupTransport) Send(frame ports.Frame) error { | |
| 71 | + | func (t *lateGraphicsCleanupTransport) Send(frame wire.Frame) error { | |
| 71 | 72 | t.startedOnce.Do(func() { close(t.started) }) | |
| 72 | 73 | <-t.release | |
| 73 | 74 | t.sends <- frame | |
| @@ -75,8 +76,8 @@ func (t *lateGraphicsCleanupTransport) Send(frame ports.Frame) error { | |||
| 75 | 76 | return nil | |
| 76 | 77 | } | |
| 77 | 78 | ||
| 78 | - | func (*lateGraphicsCleanupTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 79 | - | func (*lateGraphicsCleanupTransport) Close() error { return nil } | |
| 79 | + | func (*lateGraphicsCleanupTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 80 | + | func (*lateGraphicsCleanupTransport) Close() error { return nil } | |
| 80 | 81 | ||
| 81 | 82 | func TestGraphicsOutputReplaysStaticKittenIcatFixture(t *testing.T) { | |
| 82 | 83 | state := newGraphicsOutputState() | |
| @@ -127,8 +128,8 @@ func TestKittyAttachmentPaintCarriesGraphicsInTheOutputStateRecord(t *testing.T) | |||
| 127 | 128 | pane.screen.Write(fixture) | |
| 128 | 129 | ||
| 129 | 130 | d.paint(sess, ac, true, nil) | |
| 130 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | |
| 131 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 131 | + | frame := awaitFrame(t, sends, wire.MsgOutput) | |
| 132 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 132 | 133 | require.NoError(t, err) | |
| 133 | 134 | require.Contains(t, string(output.Data), "\x1b_Ga=t,i=") | |
| 134 | 135 | require.Contains(t, string(output.Data), ",f=100") | |
| @@ -157,8 +158,8 @@ func TestFreshCapabilityDowngradePreservesForeignTerminalGraphics(t *testing.T) | |||
| 157 | 158 | require.False(t, ac.output.graphicsUnsupportedWarned.Load(), "replacement terminal must receive its own unsupported-graphics warning") | |
| 158 | 159 | ||
| 159 | 160 | d.paint(sess, ac, true, nil) | |
| 160 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | |
| 161 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 161 | + | frame := awaitFrame(t, sends, wire.MsgOutput) | |
| 162 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 162 | 163 | require.NoError(t, err) | |
| 163 | 164 | require.Positive(t, output.New) | |
| 164 | 165 | require.NotContains(t, string(output.Data), "\x1b_Ga=d,d=A", "vev must never globally delete terminal images") | |
| @@ -449,7 +450,7 @@ func TestGraphicsNamespaceStaysQuarantinedAfterSocketSendSuccessWithoutTerminalF | |||
| 449 | 450 | require.Nil(t, ac.output.graphicsOutput) | |
| 450 | 451 | sends := transport.Sends() | |
| 451 | 452 | require.Len(t, sends, 1) | |
| 452 | - | cleanup, err := ports.UnmarshalOutput(sends[0].Payload) | |
| 453 | + | cleanup, err := wire.UnmarshalOutput(sends[0].Payload) | |
| 453 | 454 | require.NoError(t, err) | |
| 454 | 455 | require.Zero(t, cleanup.New, "graphics cleanup is an unacknowledged side-effect frame") | |
| 455 | 456 | ||
| @@ -572,7 +573,7 @@ func TestGraphicsNamespaceQuarantineFencesTimedOutLateDelete(t *testing.T) { | |||
| 572 | 573 | close(transport.release) | |
| 573 | 574 | staleFrame := awaitTestValue(t, transport.sends, "late stale cleanup did not execute") | |
| 574 | 575 | awaitTestCompletion(t, transport.finished, "late stale cleanup did not return") | |
| 575 | - | staleOutput, err := ports.UnmarshalOutput(staleFrame.Payload) | |
| 576 | + | staleOutput, err := wire.UnmarshalOutput(staleFrame.Payload) | |
| 576 | 577 | require.NoError(t, err) | |
| 577 | 578 | require.Contains(t, string(staleOutput.Data), "i="+strconv.FormatUint(oldID, 10)) | |
| 578 | 579 | require.NotContains(t, string(staleOutput.Data), "i="+strconv.FormatUint(newID, 10), "late cleanup must never target the fresh attachment") | |
M internal/usecase/daemon/handshake_test.go +6 -6
| @@ -10,8 +10,8 @@ import ( | |||
| 10 | 10 | "github.com/stretchr/testify/require" | |
| 11 | 11 | ||
| 12 | 12 | "github.com/bnema/vev/internal/domain" | |
| 13 | - | "github.com/bnema/vev/internal/ports" | |
| 14 | 13 | "github.com/bnema/vev/internal/protocol" | |
| 14 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 15 | 15 | ) | |
| 16 | 16 | ||
| 17 | 17 | type handshakeBlockingTransport struct { | |
| @@ -29,8 +29,8 @@ func newHandshakeBlockingTransport(blockWelcome bool) *handshakeBlockingTranspor | |||
| 29 | 29 | } | |
| 30 | 30 | } | |
| 31 | 31 | ||
| 32 | - | func (t *handshakeBlockingTransport) Send(frame ports.Frame) error { | |
| 33 | - | if t.blockWelcome && frame.Type == ports.MsgWelcome { | |
| 32 | + | func (t *handshakeBlockingTransport) Send(frame wire.Frame) error { | |
| 33 | + | if t.blockWelcome && frame.Type == wire.MsgWelcome { | |
| 34 | 34 | close(t.welcome) | |
| 35 | 35 | <-t.closed | |
| 36 | 36 | return io.ErrClosedPipe | |
| @@ -38,9 +38,9 @@ func (t *handshakeBlockingTransport) Send(frame ports.Frame) error { | |||
| 38 | 38 | return nil | |
| 39 | 39 | } | |
| 40 | 40 | ||
| 41 | - | func (t *handshakeBlockingTransport) Recv() (ports.Frame, error) { | |
| 41 | + | func (t *handshakeBlockingTransport) Recv() (wire.Frame, error) { | |
| 42 | 42 | <-t.closed | |
| 43 | - | return ports.Frame{}, io.ErrClosedPipe | |
| 43 | + | return wire.Frame{}, io.ErrClosedPipe | |
| 44 | 44 | } | |
| 45 | 45 | ||
| 46 | 46 | func (t *handshakeBlockingTransport) Close() error { | |
| @@ -183,7 +183,7 @@ func TestFailedResumeHandshakeRestoresParkedCredential(t *testing.T) { | |||
| 183 | 183 | resumeTransport := newHandshakeBlockingTransport(true) | |
| 184 | 184 | done := make(chan struct{}) | |
| 185 | 185 | go func() { | |
| 186 | - | d.handleHello(resumeTransport, ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(helloResumeCapable(protocol.IntentResume, sess.name, token))}) | |
| 186 | + | d.handleHello(resumeTransport, wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(helloResumeCapable(protocol.IntentResume, sess.name, token))}) | |
| 187 | 187 | close(done) | |
| 188 | 188 | }() | |
| 189 | 189 | ||
M internal/usecase/daemon/input_test.go +29 -29
| @@ -15,9 +15,9 @@ import ( | |||
| 15 | 15 | ||
| 16 | 16 | vt "github.com/bnema/vev-vt" | |
| 17 | 17 | "github.com/bnema/vev/internal/domain" | |
| 18 | - | "github.com/bnema/vev/internal/ports" | |
| 19 | 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 20 | 19 | "github.com/bnema/vev/internal/protocol" | |
| 20 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 21 | 21 | scopy "github.com/bnema/vev/internal/usecase/copy" | |
| 22 | 22 | "github.com/bnema/vev/internal/usecase/keys" | |
| 23 | 23 | "github.com/bnema/vev/internal/usecase/layout" | |
| @@ -196,8 +196,8 @@ func TestSwitchTabFirstFrameDoesNotReuseSamePaneIDCapture(t *testing.T) { | |||
| 196 | 196 | source.screen.Write([]byte("source")) | |
| 197 | 197 | source.mu.Unlock() | |
| 198 | 198 | d.paint(sess, ac, true, nil) | |
| 199 | - | first := awaitFrame(t, sends, ports.MsgOutput) | |
| 200 | - | firstOutput, err := ports.UnmarshalOutput(first.Payload) | |
| 199 | + | first := awaitFrame(t, sends, wire.MsgOutput) | |
| 200 | + | firstOutput, err := wire.UnmarshalOutput(first.Payload) | |
| 201 | 201 | require.NoError(t, err) | |
| 202 | 202 | terminal := vt.NewScreen(ac.size.Cols, ac.size.Rows) | |
| 203 | 203 | terminal.Write(firstOutput.Data) | |
| @@ -212,8 +212,8 @@ func TestSwitchTabFirstFrameDoesNotReuseSamePaneIDCapture(t *testing.T) { | |||
| 212 | 212 | daemonKeyHandler{d: d, ac: ac}.Action(keys.ActionSwitchTab2, nil) | |
| 213 | 213 | require.Equal(t, 1, testAttachmentTabIndex(sess)) | |
| 214 | 214 | ||
| 215 | - | second := awaitFrame(t, sends, ports.MsgOutput) | |
| 216 | - | secondOutput, err := ports.UnmarshalOutput(second.Payload) | |
| 215 | + | second := awaitFrame(t, sends, wire.MsgOutput) | |
| 216 | + | secondOutput, err := wire.UnmarshalOutput(second.Payload) | |
| 217 | 217 | require.NoError(t, err) | |
| 218 | 218 | require.Zero(t, secondOutput.Base, "tab switch must emit the complete target frame first") | |
| 219 | 219 | terminal.Write(secondOutput.Data) | |
| @@ -309,11 +309,11 @@ func TestAltFToggleRetainedFloatingPaneRepaintsImmediately(t *testing.T) { | |||
| 309 | 309 | ||
| 310 | 310 | // Establish the client shadow while the retained popup is hidden. | |
| 311 | 311 | d.paint(sess, ac, true, nil) | |
| 312 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 312 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 313 | 313 | ||
| 314 | 314 | // Route the real Alt+F binding. Showing a retained pane must paint once. | |
| 315 | 315 | d.handleInput(sess, ac, []byte("\x1bf")) | |
| 316 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 316 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 317 | 317 | require.Contains(t, strings.Join(frameRows(client.Frame), "\n"), "popup-content") | |
| 318 | 318 | require.Contains(t, strings.Join(frameRows(client.Frame), "\n"), "┌") | |
| 319 | 319 | select { | |
| @@ -325,7 +325,7 @@ func TestAltFToggleRetainedFloatingPaneRepaintsImmediately(t *testing.T) { | |||
| 325 | 325 | // The second real key must repaint immediately, rather than waiting for | |
| 326 | 326 | // unrelated output, while retaining the existing PTY and context. | |
| 327 | 327 | d.handleInput(sess, ac, []byte("\x1bf")) | |
| 328 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 328 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 329 | 329 | require.NotContains(t, strings.Join(frameRows(client.Frame), "\n"), "popup-content") | |
| 330 | 330 | tb := testAttachmentTab(sess) | |
| 331 | 331 | tb.mu.Lock() | |
| @@ -343,7 +343,7 @@ func TestAltFToggleRetainedFloatingPaneRepaintsImmediately(t *testing.T) { | |||
| 343 | 343 | // A third show uses the installed pane; it must not launch or emit a second | |
| 344 | 344 | // resize/start frame. | |
| 345 | 345 | d.handleInput(sess, ac, []byte("\x1bf")) | |
| 346 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 346 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 347 | 347 | require.Contains(t, strings.Join(frameRows(client.Frame), "\n"), "popup-content") | |
| 348 | 348 | tb.mu.Lock() | |
| 349 | 349 | require.Equal(t, floatingVisible, tb.floating.state) | |
| @@ -630,13 +630,13 @@ func TestBracketedMultilinePasteForwardsDelimitersAndNewlines(t *testing.T) { | |||
| 630 | 630 | func TestOverlayInputPrecedence(t *testing.T) { | |
| 631 | 631 | cases := []struct { | |
| 632 | 632 | name string | |
| 633 | - | setup func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan ports.Frame) | |
| 633 | + | setup func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan wire.Frame) | |
| 634 | 634 | input []byte | |
| 635 | 635 | check func(t *testing.T, ac *attachedClient, writes chan []byte) | |
| 636 | 636 | }{ | |
| 637 | 637 | { | |
| 638 | 638 | name: "prompt before palette picker copy and normal", | |
| 639 | - | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan ports.Frame) { | |
| 639 | + | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan wire.Frame) { | |
| 640 | 640 | t.Helper() | |
| 641 | 641 | d.enterCopyMode(sess, ac) | |
| 642 | 642 | d.enterPicker(sess, ac) | |
| @@ -655,7 +655,7 @@ func TestOverlayInputPrecedence(t *testing.T) { | |||
| 655 | 655 | }, | |
| 656 | 656 | { | |
| 657 | 657 | name: "palette before picker copy and normal", | |
| 658 | - | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan ports.Frame) { | |
| 658 | + | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan wire.Frame) { | |
| 659 | 659 | t.Helper() | |
| 660 | 660 | d.enterCopyMode(sess, ac) | |
| 661 | 661 | d.enterPicker(sess, ac) | |
| @@ -672,7 +672,7 @@ func TestOverlayInputPrecedence(t *testing.T) { | |||
| 672 | 672 | }, | |
| 673 | 673 | { | |
| 674 | 674 | name: "picker before copy and normal", | |
| 675 | - | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan ports.Frame) { | |
| 675 | + | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan wire.Frame) { | |
| 676 | 676 | t.Helper() | |
| 677 | 677 | d.enterCopyMode(sess, ac) | |
| 678 | 678 | d.enterPicker(sess, ac) | |
| @@ -689,7 +689,7 @@ func TestOverlayInputPrecedence(t *testing.T) { | |||
| 689 | 689 | }, | |
| 690 | 690 | { | |
| 691 | 691 | name: "copy before normal", | |
| 692 | - | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan ports.Frame) { | |
| 692 | + | setup: func(t *testing.T, d *Daemon, sess *session, ac *attachedClient, sends chan wire.Frame) { | |
| 693 | 693 | t.Helper() | |
| 694 | 694 | d.enterCopyMode(sess, ac) | |
| 695 | 695 | }, | |
| @@ -798,8 +798,8 @@ func TestPaletteBackSessionSendsClientPreviousRouteAction(t *testing.T) { | |||
| 798 | 798 | }) | |
| 799 | 799 | ||
| 800 | 800 | require.NoError(t, d.backSessionForAttachment(effect)) | |
| 801 | - | frame := awaitFrame(t, sends, ports.MsgNavigateRecentRoute) | |
| 802 | - | action, err := ports.UnmarshalRouteNavigationAction(frame.Payload) | |
| 801 | + | frame := awaitFrame(t, sends, wire.MsgNavigateRecentRoute) | |
| 802 | + | action, err := wire.UnmarshalRouteNavigationAction(frame.Payload) | |
| 803 | 803 | require.NoError(t, err) | |
| 804 | 804 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 3, Key: 2, Generation: 2}, action) | |
| 805 | 805 | } | |
| @@ -825,7 +825,7 @@ func TestSwitchSourceDoesNotOwnPreviousRoute(t *testing.T) { | |||
| 825 | 825 | require.Equal(t, uint64(0), ac.routeSnapshotCopy().Generation, "route ownership starts in the client") | |
| 826 | 826 | } | |
| 827 | 827 | ||
| 828 | - | func newRecentNavigationTestSessions(t *testing.T) (*Daemon, *session, *attachedClient, chan ports.Frame, []func()) { | |
| 828 | + | func newRecentNavigationTestSessions(t *testing.T) (*Daemon, *session, *attachedClient, chan wire.Frame, []func()) { | |
| 829 | 829 | t.Helper() | |
| 830 | 830 | p1, release1 := newBlockingPTY(t) | |
| 831 | 831 | p2, release2 := newBlockingPTY(t) | |
| @@ -881,8 +881,8 @@ func TestAltDDetachesCurrentClient(t *testing.T) { | |||
| 881 | 881 | d.handleInput(sess, ac, []byte("DET\r")) | |
| 882 | 882 | ||
| 883 | 883 | require.Empty(t, sess.snapshotAttachments()) | |
| 884 | - | f := awaitFrame(t, sends, ports.MsgDetached) | |
| 885 | - | det, err := ports.UnmarshalDetached(f.Payload) | |
| 884 | + | f := awaitFrame(t, sends, wire.MsgDetached) | |
| 885 | + | det, err := wire.UnmarshalDetached(f.Payload) | |
| 886 | 886 | require.NoError(t, err) | |
| 887 | 887 | require.Equal(t, protocol.ReasonDetach, det.Reason) | |
| 888 | 888 | } | |
| @@ -894,13 +894,13 @@ func TestRNSOpensPromptAndEnterPromotesEphemeralSession(t *testing.T) { | |||
| 894 | 894 | sess.name = "0" | |
| 895 | 895 | ||
| 896 | 896 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 897 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 897 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 898 | 898 | d.handleInput(sess, ac, []byte("RNS\r")) | |
| 899 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 899 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 900 | 900 | require.True(t, ac.overlays.promptActive()) | |
| 901 | 901 | ||
| 902 | 902 | d.handleInput(sess, ac, []byte("\r")) | |
| 903 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 903 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 904 | 904 | ||
| 905 | 905 | require.False(t, ac.overlays.promptActive()) | |
| 906 | 906 | require.False(t, sess.ephemeral) | |
| @@ -917,16 +917,16 @@ func TestRNTOpensPromptAndRenamesActiveTab(t *testing.T) { | |||
| 917 | 917 | selectTestAttachmentTab(sess, 1) | |
| 918 | 918 | ||
| 919 | 919 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 920 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 920 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 921 | 921 | d.handleInput(sess, ac, []byte("RNT\r")) | |
| 922 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 922 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 923 | 923 | require.True(t, ac.overlays.promptActive()) | |
| 924 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 924 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 925 | 925 | require.NoError(t, err) | |
| 926 | 926 | require.Contains(t, string(msg.Data), "> 2") | |
| 927 | 927 | ||
| 928 | 928 | d.handleInput(sess, ac, []byte("\x7flogs\r")) | |
| 929 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 929 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 930 | 930 | ||
| 931 | 931 | require.False(t, ac.overlays.promptActive()) | |
| 932 | 932 | require.Equal(t, "logs", sess.tabs[1].name) | |
| @@ -1091,9 +1091,9 @@ func TestCopyModeMouseHorizontalReverseDragUsesExactOSC52(t *testing.T) { | |||
| 1091 | 1091 | d.handleInput(sess, ac, []byte("y")) | |
| 1092 | 1092 | var msg protocol.Output | |
| 1093 | 1093 | require.Eventually(t, func() bool { | |
| 1094 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | |
| 1094 | + | frame := awaitFrame(t, sends, wire.MsgOutput) | |
| 1095 | 1095 | var err error | |
| 1096 | - | msg, err = ports.UnmarshalOutput(frame.Payload) | |
| 1096 | + | msg, err = wire.UnmarshalOutput(frame.Payload) | |
| 1097 | 1097 | return err == nil && string(msg.Data) == string(scopy.OSC52("lph")[0]) | |
| 1098 | 1098 | }, 2*time.Second, 5*time.Millisecond) | |
| 1099 | 1099 | require.Equal(t, scopy.OSC52("lph")[0], msg.Data) | |
| @@ -1573,7 +1573,7 @@ func TestMouseGatedWhileNoticesOverlayActive(t *testing.T) { | |||
| 1573 | 1573 | ||
| 1574 | 1574 | d.notices.record(domain.Notification{Code: domain.NoticePaneSpawn, Message: "m", Time: time.Unix(1, 0)}) | |
| 1575 | 1575 | d.enterNotices(sess, ac) | |
| 1576 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1576 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1577 | 1577 | require.True(t, ac.overlays.noticesActive()) | |
| 1578 | 1578 | ||
| 1579 | 1579 | // Same coordinates that TestMouseHitTestFocusesPaneAndTranslatesSGRColumns | |
M internal/usecase/daemon/notice_render_test.go +7 -7
| @@ -9,24 +9,24 @@ import ( | |||
| 9 | 9 | ||
| 10 | 10 | vt "github.com/bnema/vev-vt" | |
| 11 | 11 | "github.com/bnema/vev/internal/domain" | |
| 12 | - | "github.com/bnema/vev/internal/ports" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 13 | ) | |
| 14 | 14 | ||
| 15 | 15 | // replayOutputFrames decodes and writes each MsgOutput frame's terminal bytes | |
| 16 | 16 | // into screen, growing its shadow the same way a real client would. | |
| 17 | - | func replayOutputFrames(t *testing.T, screen *vt.Screen, frames []ports.Frame) { | |
| 17 | + | func replayOutputFrames(t *testing.T, screen *vt.Screen, frames []wire.Frame) { | |
| 18 | 18 | t.Helper() | |
| 19 | 19 | for _, f := range frames { | |
| 20 | - | require.Equal(t, ports.MsgOutput, f.Type) | |
| 21 | - | out, err := ports.UnmarshalOutput(f.Payload) | |
| 20 | + | require.Equal(t, wire.MsgOutput, f.Type) | |
| 21 | + | out, err := wire.UnmarshalOutput(f.Payload) | |
| 22 | 22 | require.NoError(t, err) | |
| 23 | 23 | screen.Write(out.Data) | |
| 24 | 24 | } | |
| 25 | 25 | } | |
| 26 | 26 | ||
| 27 | 27 | // drainAllFrames collects every frame already queued on sends without blocking. | |
| 28 | - | func drainAllFrames(sends chan ports.Frame) []ports.Frame { | |
| 29 | - | var out []ports.Frame | |
| 28 | + | func drainAllFrames(sends chan wire.Frame) []wire.Frame { | |
| 29 | + | var out []wire.Frame | |
| 30 | 30 | for { | |
| 31 | 31 | select { | |
| 32 | 32 | case f := <-sends: | |
| @@ -96,7 +96,7 @@ func TestPaintComposesNoticeToastTopRightAndExpiresOnTTL(t *testing.T) { | |||
| 96 | 96 | awaitToastCount(t, ac, 0) | |
| 97 | 97 | select { | |
| 98 | 98 | case f := <-sends: | |
| 99 | - | replayOutputFrames(t, screen, append([]ports.Frame{f}, drainAllFrames(sends)...)) | |
| 99 | + | replayOutputFrames(t, screen, append([]wire.Frame{f}, drainAllFrames(sends)...)) | |
| 100 | 100 | case <-time.After(2 * time.Second): | |
| 101 | 101 | t.Fatal("expiry did not invalidate the render") | |
| 102 | 102 | } | |
M internal/usecase/daemon/notices_overlay_test.go +31 -31
| @@ -11,7 +11,7 @@ import ( | |||
| 11 | 11 | ||
| 12 | 12 | renderer "github.com/bnema/vev-vt" | |
| 13 | 13 | "github.com/bnema/vev/internal/domain" | |
| 14 | - | "github.com/bnema/vev/internal/ports" | |
| 14 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 15 | 15 | "github.com/bnema/vev/internal/usecase/notices" | |
| 16 | 16 | themeui "github.com/bnema/vev/internal/usecase/theme" | |
| 17 | 17 | ) | |
| @@ -47,13 +47,13 @@ func TestNoticesOpenViaPaletteCommandShowsModalWithHistory(t *testing.T) { | |||
| 47 | 47 | d.notices.record(domain.Notification{Code: domain.NoticePaneSpawn, Severity: domain.NoticeError, Message: "couldn't open pane", Time: time.Unix(1, 0)}) | |
| 48 | 48 | ||
| 49 | 49 | d.enterPalette(sess, ac) | |
| 50 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 50 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 51 | 51 | d.handlePaletteInput(ac, []byte("NTC\r")) | |
| 52 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 52 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 53 | 53 | ||
| 54 | 54 | require.False(t, ac.overlays.paletteActive()) | |
| 55 | 55 | require.NotNil(t, ac.overlays.noticesOverlay) | |
| 56 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 56 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 57 | 57 | require.NoError(t, err) | |
| 58 | 58 | require.Contains(t, string(msg.Data), "Notifications") | |
| 59 | 59 | require.Contains(t, string(msg.Data), "pane-spawn") | |
| @@ -69,32 +69,32 @@ func TestNoticesJKNavigatesSelection(t *testing.T) { | |||
| 69 | 69 | d.notices.record(domain.Notification{Code: domain.NoticeInternal, Message: "third", Time: time.Unix(3, 0)}) | |
| 70 | 70 | ||
| 71 | 71 | d.enterNotices(sess, ac) | |
| 72 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 72 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 73 | 73 | selected, ok := ac.overlays.noticesOverlay.Selected() | |
| 74 | 74 | require.True(t, ok) | |
| 75 | 75 | require.Equal(t, "third", selected.Message) | |
| 76 | 76 | ||
| 77 | 77 | d.handleInput(sess, ac, []byte("j")) | |
| 78 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 78 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 79 | 79 | selected, ok = ac.overlays.noticesOverlay.Selected() | |
| 80 | 80 | require.True(t, ok) | |
| 81 | 81 | require.Equal(t, "second", selected.Message) | |
| 82 | 82 | ||
| 83 | 83 | d.handleInput(sess, ac, []byte("j")) | |
| 84 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 84 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 85 | 85 | selected, ok = ac.overlays.noticesOverlay.Selected() | |
| 86 | 86 | require.True(t, ok) | |
| 87 | 87 | require.Equal(t, "first", selected.Message) | |
| 88 | 88 | ||
| 89 | 89 | // One more 'j' at the bottom must clamp rather than wrap. | |
| 90 | 90 | d.handleInput(sess, ac, []byte("j")) | |
| 91 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 91 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 92 | 92 | selected, ok = ac.overlays.noticesOverlay.Selected() | |
| 93 | 93 | require.True(t, ok) | |
| 94 | 94 | require.Equal(t, "first", selected.Message) | |
| 95 | 95 | ||
| 96 | 96 | d.handleInput(sess, ac, []byte("k")) | |
| 97 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 97 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 98 | 98 | selected, ok = ac.overlays.noticesOverlay.Selected() | |
| 99 | 99 | require.True(t, ok) | |
| 100 | 100 | require.Equal(t, "second", selected.Message) | |
| @@ -109,11 +109,11 @@ func TestNoticesQAndCtrlCCloseImmediatelyAndClearState(t *testing.T) { | |||
| 109 | 109 | d.notices.record(domain.Notification{Code: domain.NoticePaneSpawn, Message: "m", Time: time.Unix(1, 0)}) | |
| 110 | 110 | ||
| 111 | 111 | d.enterNotices(sess, ac) | |
| 112 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 112 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 113 | 113 | require.True(t, ac.overlays.noticesActive()) | |
| 114 | 114 | ||
| 115 | 115 | d.handleInput(sess, ac, []byte{key}) | |
| 116 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 116 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 117 | 117 | ||
| 118 | 118 | require.False(t, ac.overlays.noticesActive()) | |
| 119 | 119 | require.Nil(t, ac.overlays.noticesOverlay) | |
| @@ -128,7 +128,7 @@ func TestNoticesLoneEscapeClosesAfterDelay(t *testing.T) { | |||
| 128 | 128 | d.notices.record(domain.Notification{Code: domain.NoticePaneSpawn, Message: "m", Time: time.Unix(1, 0)}) | |
| 129 | 129 | ||
| 130 | 130 | d.enterNotices(sess, ac) | |
| 131 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 131 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 132 | 132 | ||
| 133 | 133 | clk := &signalClock{timers: make(chan *signalTimer, 1)} | |
| 134 | 134 | d.clock = clk | |
| @@ -138,7 +138,7 @@ func TestNoticesLoneEscapeClosesAfterDelay(t *testing.T) { | |||
| 138 | 138 | ||
| 139 | 139 | timer.ch <- time.Now() | |
| 140 | 140 | require.Eventually(t, func() bool { return !ac.overlays.noticesActive() }, time.Second, 5*time.Millisecond) | |
| 141 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 141 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 142 | 142 | } | |
| 143 | 143 | ||
| 144 | 144 | func TestNoticesSplitArrowNavigatesWithoutClosing(t *testing.T) { | |
| @@ -161,7 +161,7 @@ func TestNoticesSplitArrowNavigatesWithoutClosing(t *testing.T) { | |||
| 161 | 161 | d.notices.record(domain.Notification{Code: domain.NoticeTabSpawn, Message: "second", Time: time.Unix(2, 0)}) | |
| 162 | 162 | ||
| 163 | 163 | d.enterNotices(sess, ac) | |
| 164 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 164 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 165 | 165 | for _, input := range tc.input { | |
| 166 | 166 | d.handleInput(sess, ac, input) | |
| 167 | 167 | } | |
| @@ -343,10 +343,10 @@ func TestNoticesOpenWithEmptyHistoryShowsPlaceholderWithoutPanic(t *testing.T) { | |||
| 343 | 343 | defer release() | |
| 344 | 344 | ||
| 345 | 345 | require.NotPanics(t, func() { d.enterNotices(sess, ac) }) | |
| 346 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 346 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 347 | 347 | ||
| 348 | 348 | require.NotNil(t, ac.overlays.noticesOverlay) | |
| 349 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 349 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 350 | 350 | require.NoError(t, err) | |
| 351 | 351 | require.Contains(t, string(msg.Data), "Notifications") | |
| 352 | 352 | require.Contains(t, string(msg.Data), "No notifications") | |
| @@ -391,11 +391,11 @@ func TestYankLastNotificationCommandCopiesOSC52AndShowsFeedback(t *testing.T) { | |||
| 391 | 391 | want := noticeYankPayload(n) | |
| 392 | 392 | ||
| 393 | 393 | d.enterPalette(sess, ac) | |
| 394 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 394 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 395 | 395 | d.handlePaletteInput(ac, []byte("YLN\r")) | |
| 396 | 396 | ||
| 397 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 398 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 397 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 398 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 399 | 399 | require.NoError(t, err) | |
| 400 | 400 | payload := string(msg.Data) | |
| 401 | 401 | require.True(t, strings.HasPrefix(payload, "\x1b]52;c;"), "OSC52 payload = %q", payload) | |
| @@ -404,8 +404,8 @@ func TestYankLastNotificationCommandCopiesOSC52AndShowsFeedback(t *testing.T) { | |||
| 404 | 404 | require.NoError(t, err) | |
| 405 | 405 | require.Equal(t, want, string(decoded)) | |
| 406 | 406 | ||
| 407 | - | live := awaitFrame(t, sends, ports.MsgOutput) | |
| 408 | - | liveMsg, err := ports.UnmarshalOutput(live.Payload) | |
| 407 | + | live := awaitFrame(t, sends, wire.MsgOutput) | |
| 408 | + | liveMsg, err := wire.UnmarshalOutput(live.Payload) | |
| 409 | 409 | require.NoError(t, err) | |
| 410 | 410 | require.Contains(t, string(liveMsg.Data), "copied notification details") | |
| 411 | 411 | } | |
| @@ -416,11 +416,11 @@ func TestYankLastNotificationWithEmptyHistoryShowsWarnToast(t *testing.T) { | |||
| 416 | 416 | defer release() | |
| 417 | 417 | ||
| 418 | 418 | d.enterPalette(sess, ac) | |
| 419 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 419 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 420 | 420 | d.handlePaletteInput(ac, []byte("YLN\r")) | |
| 421 | 421 | ||
| 422 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 423 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 422 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 423 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 424 | 424 | require.NoError(t, err) | |
| 425 | 425 | require.Contains(t, string(msg.Data), "no notifications yet") | |
| 426 | 426 | ||
| @@ -439,7 +439,7 @@ func TestNoticesYKeyYanksSelectedNotification(t *testing.T) { | |||
| 439 | 439 | d.notices.record(domain.Notification{Code: domain.NoticeTabSpawn, Severity: domain.NoticeError, Message: "second", Time: time.Unix(2, 0)}) | |
| 440 | 440 | ||
| 441 | 441 | d.enterNotices(sess, ac) | |
| 442 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 442 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 443 | 443 | selected, ok := ac.overlays.noticesOverlay.Selected() | |
| 444 | 444 | require.True(t, ok) | |
| 445 | 445 | require.Equal(t, "second", selected.Message) | |
| @@ -447,8 +447,8 @@ func TestNoticesYKeyYanksSelectedNotification(t *testing.T) { | |||
| 447 | 447 | ||
| 448 | 448 | d.handleInput(sess, ac, []byte("y")) | |
| 449 | 449 | ||
| 450 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 451 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 450 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 451 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 452 | 452 | require.NoError(t, err) | |
| 453 | 453 | payload := string(msg.Data) | |
| 454 | 454 | require.True(t, strings.HasPrefix(payload, "\x1b]52;c;"), "OSC52 payload = %q", payload) | |
| @@ -481,11 +481,11 @@ func TestNoticesBatchedYankCapturesSelectionAtY(t *testing.T) { | |||
| 481 | 481 | d.notices.record(domain.Notification{Code: domain.NoticeInternal, Message: "third", Time: time.Unix(3, 0)}) | |
| 482 | 482 | ||
| 483 | 483 | d.enterNotices(sess, ac) | |
| 484 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 484 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 485 | 485 | d.handleInput(sess, ac, tt.input) | |
| 486 | 486 | ||
| 487 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 488 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 487 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 488 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 489 | 489 | require.NoError(t, err) | |
| 490 | 490 | payload := strings.TrimSuffix(strings.TrimPrefix(string(msg.Data), "\x1b]52;c;"), "\a") | |
| 491 | 491 | decoded, err := base64.StdEncoding.DecodeString(payload) | |
| @@ -505,7 +505,7 @@ func TestNoticesYKeyWithNoSelectionIsNoOp(t *testing.T) { | |||
| 505 | 505 | defer release() | |
| 506 | 506 | ||
| 507 | 507 | require.NotPanics(t, func() { d.enterNotices(sess, ac) }) | |
| 508 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 508 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 509 | 509 | ||
| 510 | 510 | require.NotPanics(t, func() { d.handleInput(sess, ac, []byte("y")) }) | |
| 511 | 511 | require.True(t, ac.overlays.noticesActive()) | |
M internal/usecase/daemon/notify_test.go +10 -9
| @@ -17,6 +17,7 @@ import ( | |||
| 17 | 17 | "github.com/bnema/vev/internal/ports" | |
| 18 | 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 19 | 19 | "github.com/bnema/vev/internal/protocol" | |
| 20 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 20 | 21 | ) | |
| 21 | 22 | ||
| 22 | 23 | func TestReportAttachmentErrorPreservesLocalOrNilScope(t *testing.T) { | |
| @@ -56,11 +57,11 @@ func TestMalformedClientNoticeIsIgnored(t *testing.T) { | |||
| 56 | 57 | d.attachCoordinator(sess, nil, ac, true) | |
| 57 | 58 | tr, ok := ac.tr.(*portsmocks.MockTransport) | |
| 58 | 59 | require.True(t, ok, "attached client transport must be a MockTransport") | |
| 59 | - | frames := []ports.Frame{ | |
| 60 | - | {Type: ports.MsgClientNotice, Payload: []byte{0xff}}, | |
| 61 | - | {Type: ports.MsgDetach, Payload: ports.MarshalDetach(protocol.Detach{})}, | |
| 60 | + | frames := []wire.Frame{ | |
| 61 | + | {Type: wire.MsgClientNotice, Payload: []byte{0xff}}, | |
| 62 | + | {Type: wire.MsgDetach, Payload: wire.MarshalDetach(protocol.Detach{})}, | |
| 62 | 63 | } | |
| 63 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | |
| 64 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { | |
| 64 | 65 | frame := frames[0] | |
| 65 | 66 | frames = frames[1:] | |
| 66 | 67 | return frame, nil | |
| @@ -268,7 +269,7 @@ func (c *noticeClock) durations() []time.Duration { | |||
| 268 | 269 | // caller-supplied clock so toast TTLs are deterministic. The session has no | |
| 269 | 270 | // render coordinator, so invalidateRender paints directly and every repaint is | |
| 270 | 271 | // observable as a frame on the returned channel. | |
| 271 | - | func newNoticeFixture(t *testing.T, clk ports.Clock) (*Daemon, *session, *attachedClient, chan ports.Frame) { | |
| 272 | + | func newNoticeFixture(t *testing.T, clk ports.Clock) (*Daemon, *session, *attachedClient, chan wire.Frame) { | |
| 272 | 273 | t.Helper() | |
| 273 | 274 | p, _ := newBlockingPTY(t) | |
| 274 | 275 | d := newTestDaemon(t, nil, clk) | |
| @@ -864,8 +865,8 @@ func TestToastExpiresOnFakeClock(t *testing.T) { | |||
| 864 | 865 | ||
| 865 | 866 | d.notify(sess, domain.NoticeError, domain.NoticePaneSpawn, "could not open pane", nil) | |
| 866 | 867 | awaitToastCount(t, ac, 1) | |
| 867 | - | shown := awaitFrame(t, sends, ports.MsgOutput) | |
| 868 | - | shownOutput, err := ports.UnmarshalOutput(shown.Payload) | |
| 868 | + | shown := awaitFrame(t, sends, wire.MsgOutput) | |
| 869 | + | shownOutput, err := wire.UnmarshalOutput(shown.Payload) | |
| 869 | 870 | require.NoError(t, err) | |
| 870 | 871 | terminal := vt.NewScreen(80, 25) | |
| 871 | 872 | terminal.Write(shownOutput.Data) | |
| @@ -880,8 +881,8 @@ func TestToastExpiresOnFakeClock(t *testing.T) { | |||
| 880 | 881 | _, overflow := visibleToasts(ac) | |
| 881 | 882 | require.Zero(t, overflow, "overflow resets once no toast is visible") | |
| 882 | 883 | ||
| 883 | - | expired := awaitFrame(t, sends, ports.MsgOutput) | |
| 884 | - | expiredOutput, err := ports.UnmarshalOutput(expired.Payload) | |
| 884 | + | expired := awaitFrame(t, sends, wire.MsgOutput) | |
| 885 | + | expiredOutput, err := wire.UnmarshalOutput(expired.Payload) | |
| 885 | 886 | require.NoError(t, err) | |
| 886 | 887 | terminal.Write(expiredOutput.Data) | |
| 887 | 888 | ac.sendMu.Lock() | |
M internal/usecase/daemon/output_state_sync_test.go +37 -36
| @@ -13,36 +13,37 @@ import ( | |||
| 13 | 13 | "github.com/bnema/vev/internal/domain" | |
| 14 | 14 | "github.com/bnema/vev/internal/ports" | |
| 15 | 15 | "github.com/bnema/vev/internal/protocol" | |
| 16 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 16 | 17 | "github.com/stretchr/testify/require" | |
| 17 | 18 | ) | |
| 18 | 19 | ||
| 19 | 20 | type datagramTestTransport struct { | |
| 20 | - | sends chan ports.Frame | |
| 21 | - | recv chan ports.Frame | |
| 21 | + | sends chan wire.Frame | |
| 22 | + | recv chan wire.Frame | |
| 22 | 23 | once sync.Once | |
| 23 | 24 | } | |
| 24 | 25 | ||
| 25 | 26 | type failingOutputTransport struct{} | |
| 26 | 27 | ||
| 27 | - | func (failingOutputTransport) Send(ports.Frame) error { return errors.New("send failed") } | |
| 28 | - | func (failingOutputTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 29 | - | func (failingOutputTransport) Close() error { return nil } | |
| 28 | + | func (failingOutputTransport) Send(wire.Frame) error { return errors.New("send failed") } | |
| 29 | + | func (failingOutputTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 30 | + | func (failingOutputTransport) Close() error { return nil } | |
| 30 | 31 | ||
| 31 | 32 | type asyncPaintTransport struct { | |
| 32 | - | syncSends chan ports.Frame | |
| 33 | - | asyncSends chan ports.Frame | |
| 33 | + | syncSends chan wire.Frame | |
| 34 | + | asyncSends chan wire.Frame | |
| 34 | 35 | } | |
| 35 | 36 | ||
| 36 | - | func (t *asyncPaintTransport) Send(f ports.Frame) error { t.syncSends <- f; return nil } | |
| 37 | - | func (t *asyncPaintTransport) SendAsync(f ports.Frame) error { t.asyncSends <- f; return nil } | |
| 38 | - | func (t *asyncPaintTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 39 | - | func (t *asyncPaintTransport) Close() error { return nil } | |
| 37 | + | func (t *asyncPaintTransport) Send(f wire.Frame) error { t.syncSends <- f; return nil } | |
| 38 | + | func (t *asyncPaintTransport) SendAsync(f wire.Frame) error { t.asyncSends <- f; return nil } | |
| 39 | + | func (t *asyncPaintTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 40 | + | func (t *asyncPaintTransport) Close() error { return nil } | |
| 40 | 41 | ||
| 41 | 42 | type timedSideEffectTransport struct { | |
| 42 | 43 | closeTrackingTransport | |
| 43 | 44 | } | |
| 44 | 45 | ||
| 45 | - | func (t *timedSideEffectTransport) SendSynchronous(f ports.Frame) error { | |
| 46 | + | func (t *timedSideEffectTransport) SendSynchronous(f wire.Frame) error { | |
| 46 | 47 | return t.Send(f) | |
| 47 | 48 | } | |
| 48 | 49 | ||
| @@ -54,14 +55,14 @@ func (noWatchdogClock) NewTimer(time.Duration) ports.Timer { | |||
| 54 | 55 | } | |
| 55 | 56 | ||
| 56 | 57 | func newDatagramTestTransport() *datagramTestTransport { | |
| 57 | - | return &datagramTestTransport{sends: make(chan ports.Frame, 64), recv: make(chan ports.Frame, 64)} | |
| 58 | + | return &datagramTestTransport{sends: make(chan wire.Frame, 64), recv: make(chan wire.Frame, 64)} | |
| 58 | 59 | } | |
| 59 | 60 | ||
| 60 | - | func (t *datagramTestTransport) Send(f ports.Frame) error { t.sends <- f; return nil } | |
| 61 | - | func (t *datagramTestTransport) Recv() (ports.Frame, error) { | |
| 61 | + | func (t *datagramTestTransport) Send(f wire.Frame) error { t.sends <- f; return nil } | |
| 62 | + | func (t *datagramTestTransport) Recv() (wire.Frame, error) { | |
| 62 | 63 | f, ok := <-t.recv | |
| 63 | 64 | if !ok { | |
| 64 | - | return ports.Frame{}, io.EOF | |
| 65 | + | return wire.Frame{}, io.EOF | |
| 65 | 66 | } | |
| 66 | 67 | return f, nil | |
| 67 | 68 | } | |
| @@ -90,20 +91,20 @@ func TestDatagramAttachPipelinesRendererBeforeAck(t *testing.T) { | |||
| 90 | 91 | ||
| 91 | 92 | sess.tabs[0].focusedPane().screen.Write([]byte("A")) | |
| 92 | 93 | d.paint(sess, ac, false, nil) | |
| 93 | - | first := awaitFrame(t, tr.sends, ports.MsgOutput) | |
| 94 | - | out, err := ports.UnmarshalOutput(first.Payload) | |
| 94 | + | first := awaitFrame(t, tr.sends, wire.MsgOutput) | |
| 95 | + | out, err := wire.UnmarshalOutput(first.Payload) | |
| 95 | 96 | require.NoError(t, err) | |
| 96 | 97 | require.Equal(t, uint64(1), out.New) | |
| 97 | 98 | ||
| 98 | 99 | sess.tabs[0].focusedPane().screen.Write([]byte("\rB")) | |
| 99 | 100 | d.paint(sess, ac, false, nil) | |
| 100 | - | updated := awaitFrame(t, tr.sends, ports.MsgOutput) | |
| 101 | - | out, err = ports.UnmarshalOutput(updated.Payload) | |
| 101 | + | updated := awaitFrame(t, tr.sends, wire.MsgOutput) | |
| 102 | + | out, err = wire.UnmarshalOutput(updated.Payload) | |
| 102 | 103 | require.NoError(t, err) | |
| 103 | 104 | require.Equal(t, uint64(2), out.New) | |
| 104 | 105 | // Both states were emitted before the MsgAck; the ordered dependency chain | |
| 105 | 106 | // must therefore remain valid without waiting for renderer acknowledgement. | |
| 106 | - | tr.recv <- ports.Frame{Type: ports.MsgAck, Payload: mustMarshalAck(protocol.Ack{Epoch: out.Epoch, State: out.New})} | |
| 107 | + | tr.recv <- wire.Frame{Type: wire.MsgAck, Payload: mustMarshalAck(protocol.Ack{Epoch: out.Epoch, State: out.New})} | |
| 107 | 108 | require.NoError(t, tr.Close()) | |
| 108 | 109 | d.runConnLoop(ac) | |
| 109 | 110 | ||
| @@ -117,13 +118,13 @@ func TestPaintExplicitlyUsesAsyncTransportCapability(t *testing.T) { | |||
| 117 | 118 | p, releasePTY := newBlockingPTY(t) | |
| 118 | 119 | defer releasePTY() | |
| 119 | 120 | d, sess, ac, _ := newManualSessionWithPTYs(t, p) | |
| 120 | - | tr := &asyncPaintTransport{syncSends: make(chan ports.Frame, 1), asyncSends: make(chan ports.Frame, 1)} | |
| 121 | + | tr := &asyncPaintTransport{syncSends: make(chan wire.Frame, 1), asyncSends: make(chan wire.Frame, 1)} | |
| 121 | 122 | ac.replaceTransport(tr) | |
| 122 | 123 | sess.tabs[0].focusedPane().screen.Write([]byte("A")) | |
| 123 | 124 | ||
| 124 | 125 | d.paint(sess, ac, false, nil) | |
| 125 | 126 | ||
| 126 | - | awaitFrame(t, tr.asyncSends, ports.MsgOutput) | |
| 127 | + | awaitFrame(t, tr.asyncSends, wire.MsgOutput) | |
| 127 | 128 | select { | |
| 128 | 129 | case frame := <-tr.syncSends: | |
| 129 | 130 | t.Fatalf("paint used synchronous Send: %+v", frame) | |
| @@ -155,7 +156,7 @@ func TestDatagramMultipleUnackedScrollPaintsMatchLatestFrame(t *testing.T) { | |||
| 155 | 156 | pane.screen.ClearDamage() | |
| 156 | 157 | client := vt.NewScreen(80, 25) | |
| 157 | 158 | d.paint(sess, ac, true, nil) | |
| 158 | - | first := mustApplyOutput(t, client, awaitFrame(t, tr.sends, ports.MsgOutput)) | |
| 159 | + | first := mustApplyOutput(t, client, awaitFrame(t, tr.sends, wire.MsgOutput)) | |
| 159 | 160 | ac.ackOutputState(first.Epoch, first.New) | |
| 160 | 161 | ||
| 161 | 162 | // Preserve the frame after one scroll while inducing a real VT scroll | |
| @@ -175,7 +176,7 @@ func TestDatagramMultipleUnackedScrollPaintsMatchLatestFrame(t *testing.T) { | |||
| 175 | 176 | pane.screen.Write([]byte("\nq")) | |
| 176 | 177 | pane.screen.Frame = desired.Clone() | |
| 177 | 178 | d.paint(sess, ac, false, nil) | |
| 178 | - | mustApplyOutput(t, client, awaitFrame(t, tr.sends, ports.MsgOutput)) | |
| 179 | + | mustApplyOutput(t, client, awaitFrame(t, tr.sends, wire.MsgOutput)) | |
| 179 | 180 | } | |
| 180 | 181 | ||
| 181 | 182 | require.Equal(t, 'B', client.Frame.At(0, 1).Rune, | |
| @@ -198,9 +199,9 @@ func outputStateRow(row []renderer.Cell) string { | |||
| 198 | 199 | return string(runes) | |
| 199 | 200 | } | |
| 200 | 201 | ||
| 201 | - | func mustApplyOutput(t *testing.T, screen *vt.Screen, frame ports.Frame) protocol.Output { | |
| 202 | + | func mustApplyOutput(t *testing.T, screen *vt.Screen, frame wire.Frame) protocol.Output { | |
| 202 | 203 | t.Helper() | |
| 203 | - | out, err := ports.UnmarshalOutput(frame.Payload) | |
| 204 | + | out, err := wire.UnmarshalOutput(frame.Payload) | |
| 204 | 205 | require.NoError(t, err) | |
| 205 | 206 | screen.Write(out.Data) | |
| 206 | 207 | return out | |
| @@ -213,7 +214,7 @@ func TestLocalAttachStillAdvancesRendererOnSend(t *testing.T) { | |||
| 213 | 214 | ||
| 214 | 215 | sess.tabs[0].focusedPane().screen.Write([]byte("A")) | |
| 215 | 216 | d.paint(sess, ac, false, nil) | |
| 216 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 217 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 217 | 218 | ||
| 218 | 219 | // The first paint updates the renderer shadow without waiting for MsgAck. | |
| 219 | 220 | d.paint(sess, ac, false, nil) | |
| @@ -228,13 +229,13 @@ func TestLocalOutputAckDoesNotMoveRendererShadowBackward(t *testing.T) { | |||
| 228 | 229 | ||
| 229 | 230 | pane.screen.Write([]byte("A")) | |
| 230 | 231 | d.paint(sess, ac, false, nil) | |
| 231 | - | first := awaitFrame(t, sends, ports.MsgOutput) | |
| 232 | - | out, err := ports.UnmarshalOutput(first.Payload) | |
| 232 | + | first := awaitFrame(t, sends, wire.MsgOutput) | |
| 233 | + | out, err := wire.UnmarshalOutput(first.Payload) | |
| 233 | 234 | require.NoError(t, err) | |
| 234 | 235 | ||
| 235 | 236 | pane.screen.Write([]byte("\rB")) | |
| 236 | 237 | d.paint(sess, ac, false, nil) | |
| 237 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 238 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 238 | 239 | ||
| 239 | 240 | ac.ackOutputState(out.Epoch, out.New) | |
| 240 | 241 | d.paint(sess, ac, false, nil) | |
| @@ -252,7 +253,7 @@ func TestRawTerminalSideEffectDoesNotEnterFullOutputWindow(t *testing.T) { | |||
| 252 | 253 | require.Equal(t, uint64(maxUnackedOutputStates), ac.output.outstanding()) | |
| 253 | 254 | sends := tr.Sends() | |
| 254 | 255 | require.Len(t, sends, 1) | |
| 255 | - | out, err := ports.UnmarshalOutput(sends[0].Payload) | |
| 256 | + | out, err := wire.UnmarshalOutput(sends[0].Payload) | |
| 256 | 257 | require.NoError(t, err) | |
| 257 | 258 | require.Zero(t, out.Base) | |
| 258 | 259 | require.Zero(t, out.New) | |
| @@ -304,7 +305,7 @@ func TestResizeGrowthFirstFrameIncludesConcurrentPTYRedraw(t *testing.T) { | |||
| 304 | 305 | pane.screen.Write([]byte(strings.Repeat("A", 79))) | |
| 305 | 306 | d.paint(sess, ac, true, nil) | |
| 306 | 307 | client := vt.NewScreen(80, 24) | |
| 307 | - | initial := mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 308 | + | initial := mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 308 | 309 | ac.ackOutputState(initial.Epoch, initial.New) | |
| 309 | 310 | ||
| 310 | 311 | d.sessWg.Add(1) | |
| @@ -325,7 +326,7 @@ func TestResizeGrowthFirstFrameIncludesConcurrentPTYRedraw(t *testing.T) { | |||
| 325 | 326 | require.Equal(t, 'B', pane.screen.Frame.At(100, 0).Rune, "replay must parse the redraw before commit") | |
| 326 | 327 | ||
| 327 | 328 | client.Resize(120, 24) | |
| 328 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 329 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 329 | 330 | require.Equal(t, 'B', client.Frame.At(100, 1).Rune, | |
| 330 | 331 | "first grown frame exposed stale pre-SIGWINCH pane content") | |
| 331 | 332 | select { | |
| @@ -356,7 +357,7 @@ func TestResizeWithoutPTYOutputFlushesOneFullFrameAtDeadline(t *testing.T) { | |||
| 356 | 357 | done := captureResizeCallbackDone(t, sess.renderCoordinator()) | |
| 357 | 358 | timer.ch <- time.Now() | |
| 358 | 359 | awaitTestCompletion(t, done, "resize callback did not complete") | |
| 359 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | |
| 360 | + | frame := awaitFrame(t, sends, wire.MsgOutput) | |
| 360 | 361 | client := vt.NewScreen(120, 24) | |
| 361 | 362 | out := mustApplyOutput(t, client, frame) | |
| 362 | 363 | require.Zero(t, out.Base) | |
| @@ -395,7 +396,7 @@ func TestResizeBurstFlushesOnlyLatestGeometry(t *testing.T) { | |||
| 395 | 396 | requireNoOutputFrame(t, sends) | |
| 396 | 397 | latest.ch <- time.Now() | |
| 397 | 398 | awaitTestCompletion(t, latestDone, "latest resize callback did not complete") | |
| 398 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 399 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 399 | 400 | require.Equal(t, domain.Size{Cols: 120, Rows: 24}, ac.size) | |
| 400 | 401 | require.Equal(t, 120, testAttachmentTab(sess).focusedPane().screen.Frame.Width) | |
| 401 | 402 | requireNoOutputFrame(t, sends) | |
M internal/usecase/daemon/paint_gate_test.go +3 -3
| @@ -4,16 +4,16 @@ import ( | |||
| 4 | 4 | "testing" | |
| 5 | 5 | "time" | |
| 6 | 6 | ||
| 7 | - | "github.com/bnema/vev/internal/ports" | |
| 7 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 8 | 8 | ) | |
| 9 | 9 | ||
| 10 | - | func requireNoOutputFrame(t *testing.T, sends chan ports.Frame) { | |
| 10 | + | func requireNoOutputFrame(t *testing.T, sends chan wire.Frame) { | |
| 11 | 11 | t.Helper() | |
| 12 | 12 | deadline := time.After(50 * time.Millisecond) | |
| 13 | 13 | for { | |
| 14 | 14 | select { | |
| 15 | 15 | case f := <-sends: | |
| 16 | - | if f.Type == ports.MsgOutput { | |
| 16 | + | if f.Type == wire.MsgOutput { | |
| 17 | 17 | t.Fatalf("unexpected output frame: %+v", f) | |
| 18 | 18 | } | |
| 19 | 19 | case <-deadline: | |
M internal/usecase/daemon/palette_test.go +80 -79
| @@ -14,6 +14,7 @@ import ( | |||
| 14 | 14 | "github.com/bnema/vev/internal/ports" | |
| 15 | 15 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 16 | 16 | "github.com/bnema/vev/internal/protocol" | |
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 17 | 18 | "github.com/bnema/vev/internal/usecase/command" | |
| 18 | 19 | "github.com/bnema/vev/internal/usecase/palette" | |
| 19 | 20 | "github.com/bnema/vev/internal/usecase/picker" | |
| @@ -130,8 +131,8 @@ func TestPaletteOpenTypeEnterRunAndEscClose(t *testing.T) { | |||
| 130 | 131 | ||
| 131 | 132 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 132 | 133 | require.True(t, ac.overlays.paletteActive()) | |
| 133 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 134 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 134 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 135 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 135 | 136 | require.NoError(t, err) | |
| 136 | 137 | require.Contains(t, string(msg.Data), "Commands") | |
| 137 | 138 | ||
| @@ -139,13 +140,13 @@ func TestPaletteOpenTypeEnterRunAndEscClose(t *testing.T) { | |||
| 139 | 140 | require.False(t, ac.overlays.paletteActive()) | |
| 140 | 141 | require.Equal(t, 1, testAttachmentTabIndex(sess)) | |
| 141 | 142 | requireFloatingInitialized(t, testAttachmentTab(sess)) | |
| 142 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 143 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 143 | 144 | ||
| 144 | 145 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 145 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 146 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 146 | 147 | d.handleInput(sess, ac, []byte("\x1b")) | |
| 147 | 148 | require.False(t, ac.overlays.paletteActive()) | |
| 148 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 149 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 149 | 150 | } | |
| 150 | 151 | ||
| 151 | 152 | // TestPaletteCommandFailureSurfacesAsNotice drives a palette command whose Run | |
| @@ -162,9 +163,9 @@ func TestPaletteCommandFailureSurfacesAsNotice(t *testing.T) { | |||
| 162 | 163 | d.ptys = ptys | |
| 163 | 164 | ||
| 164 | 165 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 165 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 166 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 166 | 167 | d.handleInput(sess, ac, []byte("CNT\r")) | |
| 167 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 168 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 168 | 169 | ||
| 169 | 170 | history := d.notices.history() | |
| 170 | 171 | require.NotEmpty(t, history, "failed palette command must record a notice") | |
| @@ -291,13 +292,13 @@ func TestPaletteEnterFreezesActiveSessionSelectionAgainstTrailingInput(t *testin | |||
| 291 | 292 | target.createdAt = 42 | |
| 292 | 293 | ||
| 293 | 294 | d.handleInput(current, ac, []byte("\x1b ")) | |
| 294 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 295 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 295 | 296 | d.handleInput(current, ac, []byte("recent\rx")) | |
| 296 | 297 | ||
| 297 | 298 | require.Same(t, target, ac.currentSession(), "Enter must retain the selected session despite trailing frame bytes") | |
| 298 | 299 | require.False(t, ac.overlays.paletteActive(), "trailing input must not prevent the captured selection from closing the palette") | |
| 299 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 300 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 300 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 301 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 301 | 302 | } | |
| 302 | 303 | ||
| 303 | 304 | func TestPaletteSelectedActiveSessionSwitchesWithoutRecordingCommandRecency(t *testing.T) { | |
| @@ -307,15 +308,15 @@ func TestPaletteSelectedActiveSessionSwitchesWithoutRecordingCommandRecency(t *t | |||
| 307 | 308 | target.createdAt = 42 | |
| 308 | 309 | ||
| 309 | 310 | d.handleInput(current, ac, []byte("\x1b ")) | |
| 310 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 311 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 311 | 312 | d.handleInput(current, ac, []byte("recent\r")) | |
| 312 | 313 | ||
| 313 | 314 | require.Same(t, target, ac.currentSession()) | |
| 314 | 315 | require.Contains(t, target.snapshotAttachments(), ac, "canonical handoff reuses the attached client") | |
| 315 | 316 | require.False(t, ac.overlays.paletteActive()) | |
| 316 | 317 | require.Empty(t, d.paletteRecent, "session selections are not command recency") | |
| 317 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 318 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 318 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 319 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 319 | 320 | } | |
| 320 | 321 | ||
| 321 | 322 | func TestPaletteStoppedSessionResumeFailureKeepsPaletteAndSourceAttachment(t *testing.T) { | |
| @@ -329,7 +330,7 @@ func TestPaletteStoppedSessionResumeFailureKeepsPaletteAndSourceAttachment(t *te | |||
| 329 | 330 | d.ptys = ptys | |
| 330 | 331 | ||
| 331 | 332 | d.handleInput(current, ac, []byte("\x1b ")) | |
| 332 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 333 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 333 | 334 | d.handleInput(current, ac, []byte("stopped\r")) | |
| 334 | 335 | ||
| 335 | 336 | require.Same(t, current, ac.currentSession(), "failed resume must retain the source attachment") | |
| @@ -341,7 +342,7 @@ func TestPaletteStoppedSessionResumeFailureKeepsPaletteAndSourceAttachment(t *te | |||
| 341 | 342 | require.Equal(t, "requested session is unavailable", ac.overlays.paletteFeedback) | |
| 342 | 343 | ac.overlays.paletteMu.Unlock() | |
| 343 | 344 | require.Equal(t, stopped, d.inactive[stopped.name], "failed resume must retain stopped lifecycle metadata") | |
| 344 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 345 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 345 | 346 | } | |
| 346 | 347 | ||
| 347 | 348 | func TestPaletteSelectedStoppedSessionResumesAndSwitches(t *testing.T) { | |
| @@ -354,7 +355,7 @@ func TestPaletteSelectedStoppedSessionResumesAndSwitches(t *testing.T) { | |||
| 354 | 355 | d.inactive["stopped"] = inactiveSession{name: "stopped", cwd: "/tmp", createdAt: 42, state: protocol.SessionDown} | |
| 355 | 356 | ||
| 356 | 357 | d.handleInput(current, ac, []byte("\x1b ")) | |
| 357 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 358 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 358 | 359 | generation := ac.lifecycle.generationValue() | |
| 359 | 360 | d.handleInput(current, ac, []byte("stopped\r")) | |
| 360 | 361 | ||
| @@ -364,11 +365,11 @@ func TestPaletteSelectedStoppedSessionResumesAndSwitches(t *testing.T) { | |||
| 364 | 365 | require.Equal(t, true, resumed.attachmentRegistered(ac)) | |
| 365 | 366 | require.Greater(t, ac.lifecycle.generationValue(), generation, "stopped-session handoff must publish through the attachment transition") | |
| 366 | 367 | require.False(t, ac.overlays.paletteActive()) | |
| 367 | - | firstPaint := awaitFrame(t, sends, ports.MsgOutput) | |
| 368 | - | firstOutput, err := ports.UnmarshalOutput(firstPaint.Payload) | |
| 368 | + | firstPaint := awaitFrame(t, sends, wire.MsgOutput) | |
| 369 | + | firstOutput, err := wire.UnmarshalOutput(firstPaint.Payload) | |
| 369 | 370 | require.NoError(t, err) | |
| 370 | 371 | require.Zero(t, firstOutput.Base, "stopped-session first paint must reset moving output state") | |
| 371 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 372 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 372 | 373 | } | |
| 373 | 374 | ||
| 374 | 375 | func TestPaletteJRSActivatesOnlyExactContextualHint(t *testing.T) { | |
| @@ -378,9 +379,9 @@ func TestPaletteJRSActivatesOnlyExactContextualHint(t *testing.T) { | |||
| 378 | 379 | ac.setRouteSnapshot(protocol.RecentRouteSnapshot{Generation: 1, Active: protocol.RouteRef{Key: 1, Generation: 1}}) | |
| 379 | 380 | ||
| 380 | 381 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 381 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 382 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 382 | 383 | d.handleInput(sess, ac, []byte("JRS")) | |
| 383 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 384 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 384 | 385 | ||
| 385 | 386 | ac.overlays.paletteMu.Lock() | |
| 386 | 387 | require.Equal(t, command.ContextHintRecentSessions, ac.overlays.paletteHints.Kind) | |
| @@ -388,7 +389,7 @@ func TestPaletteJRSActivatesOnlyExactContextualHint(t *testing.T) { | |||
| 388 | 389 | ac.overlays.paletteMu.Unlock() | |
| 389 | 390 | ||
| 390 | 391 | d.handleInput(sess, ac, []byte("\b\b\bRNS")) | |
| 391 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 392 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 392 | 393 | ac.overlays.paletteMu.Lock() | |
| 393 | 394 | require.Equal(t, command.ContextHintNone, ac.overlays.paletteHints.Kind) | |
| 394 | 395 | ac.overlays.paletteMu.Unlock() | |
| @@ -402,25 +403,25 @@ func TestPaletteJRSUsesEffectiveOverrideOnly(t *testing.T) { | |||
| 402 | 403 | d.ApplyConfig(domain.Config{Codes: map[string]string{"jump-recent-session": "RJS"}}) | |
| 403 | 404 | ||
| 404 | 405 | d.handleInputForAttachment(token, []byte("\x1b ")) | |
| 405 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 406 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 406 | 407 | d.handleInputForAttachment(token, []byte("RJS")) | |
| 407 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 408 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 408 | 409 | ac.overlays.paletteMu.Lock() | |
| 409 | 410 | require.Equal(t, command.ContextHintRecentSessions, ac.overlays.paletteHints.Kind) | |
| 410 | 411 | ac.overlays.paletteMu.Unlock() | |
| 411 | 412 | d.handleInputForAttachment(token, []byte(" 1\r")) | |
| 412 | 413 | ||
| 413 | - | actionFrame := awaitFrame(t, sends, ports.MsgNavigateRecentRoute) | |
| 414 | - | action, err := ports.UnmarshalRouteNavigationAction(actionFrame.Payload) | |
| 414 | + | actionFrame := awaitFrame(t, sends, wire.MsgNavigateRecentRoute) | |
| 415 | + | action, err := wire.UnmarshalRouteNavigationAction(actionFrame.Payload) | |
| 415 | 416 | require.NoError(t, err) | |
| 416 | 417 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 1, Key: 2, Generation: 1}, action) | |
| 417 | 418 | require.Same(t, current, ac.currentSession()) | |
| 418 | 419 | require.False(t, ac.overlays.paletteActive()) | |
| 419 | 420 | ||
| 420 | 421 | d.handleInputForAttachment(token, []byte("\x1b ")) | |
| 421 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 422 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 422 | 423 | d.handleInputForAttachment(token, []byte("JRS")) | |
| 423 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 424 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 424 | 425 | ac.overlays.paletteMu.Lock() | |
| 425 | 426 | require.Equal(t, command.ContextHintNone, ac.overlays.paletteHints.Kind) | |
| 426 | 427 | ac.overlays.paletteMu.Unlock() | |
| @@ -588,11 +589,11 @@ func TestPaletteRemoteCatalogSelectionSendsExactAttachTarget(t *testing.T) { | |||
| 588 | 589 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | |
| 589 | 590 | ||
| 590 | 591 | d.handleInputForAttachment(token, []byte("\x1b ")) | |
| 591 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 592 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 592 | 593 | d.handleInputForAttachment(token, []byte("work@arch\r")) | |
| 593 | 594 | ||
| 594 | - | frame := awaitFrame(t, sends, ports.MsgAttachTarget) | |
| 595 | - | target, err := ports.UnmarshalAttachTarget(frame.Payload) | |
| 595 | + | frame := awaitFrame(t, sends, wire.MsgAttachTarget) | |
| 596 | + | target, err := wire.UnmarshalAttachTarget(frame.Payload) | |
| 596 | 597 | require.NoError(t, err) | |
| 597 | 598 | remoteTarget := domain.RemoteSessionTarget{ | |
| 598 | 599 | Endpoint: "user@arch", DisplayOrigin: "arch", LifecycleID: remoteLifecycle, | |
| @@ -627,7 +628,7 @@ func TestPaletteCachedRemoteSelectionFailsClosed(t *testing.T) { | |||
| 627 | 628 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | |
| 628 | 629 | ||
| 629 | 630 | d.handleInputForAttachment(token, []byte("\x1b ")) | |
| 630 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 631 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 631 | 632 | d.handleInputForAttachment(token, []byte("cached@arch\r")) | |
| 632 | 633 | ||
| 633 | 634 | require.Same(t, current, ac.currentAttachmentSession()) | |
| @@ -639,7 +640,7 @@ func TestPaletteCachedRemoteSelectionFailsClosed(t *testing.T) { | |||
| 639 | 640 | for { | |
| 640 | 641 | select { | |
| 641 | 642 | case frame := <-sends: | |
| 642 | - | require.NotEqual(t, ports.MsgAttachTarget, frame.Type) | |
| 643 | + | require.NotEqual(t, wire.MsgAttachTarget, frame.Type) | |
| 643 | 644 | default: | |
| 644 | 645 | return | |
| 645 | 646 | } | |
| @@ -772,7 +773,7 @@ func TestPaletteLifecycleTargetRejectsSameNameReplacement(t *testing.T) { | |||
| 772 | 773 | for { | |
| 773 | 774 | select { | |
| 774 | 775 | case frame := <-sends: | |
| 775 | - | require.NotEqual(t, ports.MsgAttachTarget, frame.Type) | |
| 776 | + | require.NotEqual(t, wire.MsgAttachTarget, frame.Type) | |
| 776 | 777 | default: | |
| 777 | 778 | return | |
| 778 | 779 | } | |
| @@ -793,11 +794,11 @@ func TestPaletteFuzzyRemoteRecentRouteSendsExactNavigationAction(t *testing.T) { | |||
| 793 | 794 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | |
| 794 | 795 | ||
| 795 | 796 | d.handleInputForAttachment(token, []byte("\x1b ")) | |
| 796 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 797 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 797 | 798 | d.handleInputForAttachment(token, []byte("logs@edge\r")) | |
| 798 | 799 | ||
| 799 | - | actionFrame := awaitFrame(t, sends, ports.MsgNavigateRecentRoute) | |
| 800 | - | action, err := ports.UnmarshalRouteNavigationAction(actionFrame.Payload) | |
| 800 | + | actionFrame := awaitFrame(t, sends, wire.MsgNavigateRecentRoute) | |
| 801 | + | action, err := wire.UnmarshalRouteNavigationAction(actionFrame.Payload) | |
| 801 | 802 | require.NoError(t, err) | |
| 802 | 803 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 9, Key: 8, Generation: 4}, action) | |
| 803 | 804 | require.False(t, ac.overlays.paletteActive()) | |
| @@ -809,12 +810,12 @@ func TestPaletteFuzzySelectedStaticCommandExecutes(t *testing.T) { | |||
| 809 | 810 | defer releases[1]() | |
| 810 | 811 | ||
| 811 | 812 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 812 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 813 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 813 | 814 | d.handleInput(sess, ac, []byte("next\r")) | |
| 814 | 815 | ||
| 815 | 816 | require.False(t, ac.overlays.paletteActive()) | |
| 816 | 817 | require.Equal(t, 1, testAttachmentTabIndex(sess)) | |
| 817 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 818 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 818 | 819 | } | |
| 819 | 820 | ||
| 820 | 821 | func TestPaletteJRSUsesCapturedRankAfterMRUChanges(t *testing.T) { | |
| @@ -823,13 +824,13 @@ func TestPaletteJRSUsesCapturedRankAfterMRUChanges(t *testing.T) { | |||
| 823 | 824 | ac.setRouteSnapshot(testRecentRouteSnapshot()) | |
| 824 | 825 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | |
| 825 | 826 | d.handleInputForAttachment(token, []byte("\x1b ")) | |
| 826 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 827 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 827 | 828 | // Reordering live MRU after opening must not shift rank 1 from its capture. | |
| 828 | 829 | d.sessions[domain.SessionID("older")].core().mruAt.Store(100) | |
| 829 | 830 | d.handleInputForAttachment(token, []byte("JRS 1\r")) | |
| 830 | 831 | ||
| 831 | - | actionFrame := awaitFrame(t, sends, ports.MsgNavigateRecentRoute) | |
| 832 | - | action, err := ports.UnmarshalRouteNavigationAction(actionFrame.Payload) | |
| 832 | + | actionFrame := awaitFrame(t, sends, wire.MsgNavigateRecentRoute) | |
| 833 | + | action, err := wire.UnmarshalRouteNavigationAction(actionFrame.Payload) | |
| 833 | 834 | require.NoError(t, err) | |
| 834 | 835 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 1, Key: 2, Generation: 1}, action) | |
| 835 | 836 | require.Same(t, current, ac.currentSession()) | |
| @@ -877,7 +878,7 @@ func TestPaletteJRSDoesNotRevalidateTargetInDaemon(t *testing.T) { | |||
| 877 | 878 | } | |
| 878 | 879 | token := beginRecentRoutePaletteEffect(t, d, sess, ac) | |
| 879 | 880 | d.handleInputForAttachment(token, []byte("\x1b ")) | |
| 880 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 881 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 881 | 882 | inputHandled := make(chan struct{}) | |
| 882 | 883 | go func() { | |
| 883 | 884 | d.handleInputForAttachment(token, []byte("JRS 1\r")) | |
| @@ -889,8 +890,8 @@ func TestPaletteJRSDoesNotRevalidateTargetInDaemon(t *testing.T) { | |||
| 889 | 890 | close(releaseHandoff) | |
| 890 | 891 | awaitTestCompletion(t, inputHandled, "JRS route-action input did not complete") | |
| 891 | 892 | ||
| 892 | - | actionFrame := awaitFrame(t, sends, ports.MsgNavigateRecentRoute) | |
| 893 | - | action, err := ports.UnmarshalRouteNavigationAction(actionFrame.Payload) | |
| 893 | + | actionFrame := awaitFrame(t, sends, wire.MsgNavigateRecentRoute) | |
| 894 | + | action, err := wire.UnmarshalRouteNavigationAction(actionFrame.Payload) | |
| 894 | 895 | require.NoError(t, err) | |
| 895 | 896 | require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 7, Key: 9, Generation: 4}, action) | |
| 896 | 897 | require.False(t, ac.overlays.paletteActive()) | |
| @@ -903,7 +904,7 @@ func TestPaletteJRSOutOfRangeKeepsPaletteOpenWithoutClamping(t *testing.T) { | |||
| 903 | 904 | token := beginRecentRoutePaletteEffect(t, d, current, ac) | |
| 904 | 905 | ||
| 905 | 906 | d.handleInputForAttachment(token, []byte("\x1b ")) | |
| 906 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 907 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 907 | 908 | d.handleInputForAttachment(token, []byte("JRS 3\r")) | |
| 908 | 909 | ||
| 909 | 910 | require.Same(t, current, ac.currentSession()) | |
| @@ -912,7 +913,7 @@ func TestPaletteJRSOutOfRangeKeepsPaletteOpenWithoutClamping(t *testing.T) { | |||
| 912 | 913 | require.Equal(t, "JRS 3", ac.overlays.palette.Query()) | |
| 913 | 914 | require.Equal(t, "requested recent session is unavailable", ac.overlays.paletteFeedback) | |
| 914 | 915 | ac.overlays.paletteMu.Unlock() | |
| 915 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 916 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 916 | 917 | } | |
| 917 | 918 | ||
| 918 | 919 | func TestPaletteJRSMalformedRankFeedback(t *testing.T) { | |
| @@ -920,7 +921,7 @@ func TestPaletteJRSMalformedRankFeedback(t *testing.T) { | |||
| 920 | 921 | defer releaseAll(releases) | |
| 921 | 922 | ||
| 922 | 923 | d.handleInput(current, ac, []byte("\x1b ")) | |
| 923 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 924 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 924 | 925 | d.handleInput(current, ac, []byte("JRS 0\r")) | |
| 925 | 926 | ||
| 926 | 927 | require.Same(t, current, ac.currentSession()) | |
| @@ -929,7 +930,7 @@ func TestPaletteJRSMalformedRankFeedback(t *testing.T) { | |||
| 929 | 930 | require.Equal(t, "JRS 0", ac.overlays.palette.Query()) | |
| 930 | 931 | require.Equal(t, "rank must be one positive decimal", ac.overlays.paletteFeedback) | |
| 931 | 932 | ac.overlays.paletteMu.Unlock() | |
| 932 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 933 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 933 | 934 | } | |
| 934 | 935 | ||
| 935 | 936 | func TestPaletteFailureDoesNotOverwriteChangedQueryInSameGeneration(t *testing.T) { | |
| @@ -964,8 +965,8 @@ func TestPaletteFailureDoesNotOverwriteNewerInteraction(t *testing.T) { | |||
| 964 | 965 | ac.overlays.paletteMu.Lock() | |
| 965 | 966 | require.Empty(t, ac.overlays.paletteFeedback) | |
| 966 | 967 | ac.overlays.paletteMu.Unlock() | |
| 967 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 968 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 968 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 969 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 969 | 970 | } | |
| 970 | 971 | ||
| 971 | 972 | func TestPaletteTFPExecutesFloatingToggle(t *testing.T) { | |
| @@ -976,14 +977,14 @@ func TestPaletteTFPExecutesFloatingToggle(t *testing.T) { | |||
| 976 | 977 | installTestFloating(tb, newPane("floating", nil, domain.Size{Cols: 20, Rows: 5}), false) | |
| 977 | 978 | ||
| 978 | 979 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 979 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 980 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 980 | 981 | d.handleInput(sess, ac, []byte("TFP\r")) | |
| 981 | 982 | ||
| 982 | 983 | require.False(t, ac.overlays.paletteActive()) | |
| 983 | 984 | tb.mu.Lock() | |
| 984 | 985 | require.Equal(t, floatingVisible, tb.floating.state) | |
| 985 | 986 | tb.mu.Unlock() | |
| 986 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 987 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 987 | 988 | } | |
| 988 | 989 | ||
| 989 | 990 | func TestPaletteCNSPromptsForSessionNameThenCreatesAndSwitches(t *testing.T) { | |
| @@ -995,10 +996,10 @@ func TestPaletteCNSPromptsForSessionNameThenCreatesAndSwitches(t *testing.T) { | |||
| 995 | 996 | d.ptys = newFactorySeq(t, p2) | |
| 996 | 997 | ||
| 997 | 998 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 998 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 999 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 999 | 1000 | d.handleInput(sess, ac, []byte("CNS\r")) | |
| 1000 | - | promptFrame := awaitFrame(t, sends, ports.MsgOutput) | |
| 1001 | - | promptOutput, err := ports.UnmarshalOutput(promptFrame.Payload) | |
| 1001 | + | promptFrame := awaitFrame(t, sends, wire.MsgOutput) | |
| 1002 | + | promptOutput, err := wire.UnmarshalOutput(promptFrame.Payload) | |
| 1002 | 1003 | require.NoError(t, err) | |
| 1003 | 1004 | require.False(t, ac.overlays.paletteActive()) | |
| 1004 | 1005 | require.True(t, ac.overlays.promptActive()) | |
| @@ -1009,12 +1010,12 @@ func TestPaletteCNSPromptsForSessionNameThenCreatesAndSwitches(t *testing.T) { | |||
| 1009 | 1010 | // The submit first paints the newly attached session while the prompt is | |
| 1010 | 1011 | // still open, then handlePromptInput closes the prompt and repaints the | |
| 1011 | 1012 | // client's current session. The final frame must be for the new session. | |
| 1012 | - | firstPaint := awaitFrame(t, sends, ports.MsgOutput) | |
| 1013 | - | firstOutput, err := ports.UnmarshalOutput(firstPaint.Payload) | |
| 1013 | + | firstPaint := awaitFrame(t, sends, wire.MsgOutput) | |
| 1014 | + | firstOutput, err := wire.UnmarshalOutput(firstPaint.Payload) | |
| 1014 | 1015 | require.NoError(t, err) | |
| 1015 | 1016 | require.Zero(t, firstOutput.Base, "new-session first paint must reset moving output state") | |
| 1016 | - | finalRepaint := awaitFrame(t, sends, ports.MsgOutput) | |
| 1017 | - | finalOutput, err := ports.UnmarshalOutput(finalRepaint.Payload) | |
| 1017 | + | finalRepaint := awaitFrame(t, sends, wire.MsgOutput) | |
| 1018 | + | finalOutput, err := wire.UnmarshalOutput(finalRepaint.Payload) | |
| 1018 | 1019 | require.NoError(t, err) | |
| 1019 | 1020 | require.False(t, ac.overlays.promptActive()) | |
| 1020 | 1021 | require.Equal(t, 2, sessionCount(d)) | |
| @@ -1049,9 +1050,9 @@ func TestPaletteDirectSessionCreation(t *testing.T) { | |||
| 1049 | 1050 | d.ptys = newFactorySeq(t, p2) | |
| 1050 | 1051 | ||
| 1051 | 1052 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 1052 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1053 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1053 | 1054 | d.handleInput(sess, ac, []byte(tc.input)) | |
| 1054 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1055 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1055 | 1056 | ||
| 1056 | 1057 | require.False(t, ac.overlays.paletteActive()) | |
| 1057 | 1058 | require.False(t, ac.overlays.promptActive()) | |
| @@ -1072,13 +1073,13 @@ func TestPaletteReopensWithSuccessfulCommandFirst(t *testing.T) { | |||
| 1072 | 1073 | defer releases[1]() | |
| 1073 | 1074 | ||
| 1074 | 1075 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 1075 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1076 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1076 | 1077 | d.handleInput(sess, ac, []byte("NXT\r")) | |
| 1077 | 1078 | require.False(t, ac.overlays.paletteActive()) | |
| 1078 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1079 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1079 | 1080 | ||
| 1080 | 1081 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 1081 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1082 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1082 | 1083 | result, ok := ac.overlays.palette.Selected() | |
| 1083 | 1084 | require.True(t, ok) | |
| 1084 | 1085 | cmd, ok := result.Command() | |
| @@ -1163,15 +1164,15 @@ func TestPaletteCommandNoopRepaintsAfterClose(t *testing.T) { | |||
| 1163 | 1164 | defer releases[0]() | |
| 1164 | 1165 | ||
| 1165 | 1166 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 1166 | - | paletteFrame := awaitFrame(t, sends, ports.MsgOutput) | |
| 1167 | - | paletteOutput, err := ports.UnmarshalOutput(paletteFrame.Payload) | |
| 1167 | + | paletteFrame := awaitFrame(t, sends, wire.MsgOutput) | |
| 1168 | + | paletteOutput, err := wire.UnmarshalOutput(paletteFrame.Payload) | |
| 1168 | 1169 | require.NoError(t, err) | |
| 1169 | 1170 | require.Contains(t, string(paletteOutput.Data), "Commands") | |
| 1170 | 1171 | ||
| 1171 | 1172 | d.handleInput(sess, ac, []byte("NXT\r")) | |
| 1172 | 1173 | require.False(t, ac.overlays.paletteActive()) | |
| 1173 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | |
| 1174 | - | repaintOutput, err := ports.UnmarshalOutput(repaint.Payload) | |
| 1174 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) | |
| 1175 | + | repaintOutput, err := wire.UnmarshalOutput(repaint.Payload) | |
| 1175 | 1176 | require.NoError(t, err) | |
| 1176 | 1177 | require.NotContains(t, string(repaintOutput.Data), "Commands") | |
| 1177 | 1178 | } | |
| @@ -1184,11 +1185,11 @@ func TestPaletteCreateTabErrorRepaintsAfterClose(t *testing.T) { | |||
| 1184 | 1185 | d.ptys = ptys | |
| 1185 | 1186 | ||
| 1186 | 1187 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 1187 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1188 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1188 | 1189 | d.handleInput(sess, ac, []byte("CNT\r")) | |
| 1189 | 1190 | require.False(t, ac.overlays.paletteActive()) | |
| 1190 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | |
| 1191 | - | repaintOutput, err := ports.UnmarshalOutput(repaint.Payload) | |
| 1191 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) | |
| 1192 | + | repaintOutput, err := wire.UnmarshalOutput(repaint.Payload) | |
| 1192 | 1193 | require.NoError(t, err) | |
| 1193 | 1194 | require.NotContains(t, string(repaintOutput.Data), "Commands") | |
| 1194 | 1195 | require.Len(t, sess.tabs, 1) | |
| @@ -1199,10 +1200,10 @@ func TestPaletteEnterNoMatchKeepsOpenAndEscapeSplit(t *testing.T) { | |||
| 1199 | 1200 | defer releases[0]() | |
| 1200 | 1201 | ||
| 1201 | 1202 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 1202 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1203 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1203 | 1204 | d.handleInput(sess, ac, []byte("zzzz\r")) | |
| 1204 | 1205 | require.True(t, ac.overlays.paletteActive()) | |
| 1205 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1206 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1206 | 1207 | ||
| 1207 | 1208 | d.handlePaletteInput(ac, []byte{0x1b, '['}) | |
| 1208 | 1209 | require.True(t, ac.overlays.paletteActive()) | |
| @@ -1210,7 +1211,7 @@ func TestPaletteEnterNoMatchKeepsOpenAndEscapeSplit(t *testing.T) { | |||
| 1210 | 1211 | d.handlePaletteInput(ac, []byte{'A'}) | |
| 1211 | 1212 | require.True(t, ac.overlays.paletteActive()) | |
| 1212 | 1213 | require.Empty(t, ac.overlays.palettePending) | |
| 1213 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1214 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1214 | 1215 | } | |
| 1215 | 1216 | ||
| 1216 | 1217 | func TestPaletteCtrlNAndCtrlPNavigate(t *testing.T) { | |
| @@ -1218,10 +1219,10 @@ func TestPaletteCtrlNAndCtrlPNavigate(t *testing.T) { | |||
| 1218 | 1219 | defer releases[0]() | |
| 1219 | 1220 | ||
| 1220 | 1221 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 1221 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1222 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1222 | 1223 | ||
| 1223 | 1224 | d.handlePaletteInput(ac, []byte{0x0e}) | |
| 1224 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1225 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1225 | 1226 | result, ok := ac.overlays.palette.Selected() | |
| 1226 | 1227 | require.True(t, ok) | |
| 1227 | 1228 | cmd, ok := result.Command() | |
| @@ -1229,7 +1230,7 @@ func TestPaletteCtrlNAndCtrlPNavigate(t *testing.T) { | |||
| 1229 | 1230 | require.Equal(t, "CNS", cmd.Code) | |
| 1230 | 1231 | ||
| 1231 | 1232 | d.handlePaletteInput(ac, []byte{0x10}) | |
| 1232 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1233 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1233 | 1234 | result, ok = ac.overlays.palette.Selected() | |
| 1234 | 1235 | require.True(t, ok) | |
| 1235 | 1236 | cmd, ok = result.Command() | |
| @@ -1337,7 +1338,7 @@ func TestPaletteUTF8PendingCompletesFilter(t *testing.T) { | |||
| 1337 | 1338 | defer releases[0]() | |
| 1338 | 1339 | ||
| 1339 | 1340 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 1340 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1341 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1341 | 1342 | d.handlePaletteInput(ac, []byte{0xc3}) | |
| 1342 | 1343 | require.Equal(t, []byte{0xc3}, ac.overlays.palettePending) | |
| 1343 | 1344 | d.handlePaletteInput(ac, []byte{0xa9}) | |
M internal/usecase/daemon/pane_actions_test.go +3 -2
| @@ -16,6 +16,7 @@ import ( | |||
| 16 | 16 | "github.com/bnema/vev/internal/domain" | |
| 17 | 17 | "github.com/bnema/vev/internal/ports" | |
| 18 | 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 19 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 19 | 20 | scopy "github.com/bnema/vev/internal/usecase/copy" | |
| 20 | 21 | "github.com/bnema/vev/internal/usecase/layout" | |
| 21 | 22 | ) | |
| @@ -695,7 +696,7 @@ func TestClosePaneRepaintFanoutRespectsAttachmentScope(t *testing.T) { | |||
| 695 | 696 | closingPTY.EXPECT().Close().Return(nil).Once() | |
| 696 | 697 | ||
| 697 | 698 | clients := make([]*attachedClient, 2) | |
| 698 | - | sends := make([]chan ports.Frame, 2) | |
| 699 | + | sends := make([]chan wire.Frame, 2) | |
| 699 | 700 | for i := range clients { | |
| 700 | 701 | tr, sent := newCapturingTransport(t) | |
| 701 | 702 | clients[i] = &attachedClient{tr: tr, output: newOutputStateStream(), size: domain.Size{Cols: 41, Rows: 12}} | |
| @@ -715,7 +716,7 @@ func TestClosePaneRepaintFanoutRespectsAttachmentScope(t *testing.T) { | |||
| 715 | 716 | select { | |
| 716 | 717 | case frame := <-sends[i]: | |
| 717 | 718 | require.True(t, want, "attachment %d unexpectedly repainted: %#v", i, frame) | |
| 718 | - | require.Equal(t, ports.MsgOutput, frame.Type) | |
| 719 | + | require.Equal(t, wire.MsgOutput, frame.Type) | |
| 719 | 720 | default: | |
| 720 | 721 | require.False(t, want, "attachment %d was not repainted", i) | |
| 721 | 722 | } | |
M internal/usecase/daemon/parked_route.go +5 -4
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | 9 | "github.com/bnema/vev/internal/domain" | |
| 10 | 10 | "github.com/bnema/vev/internal/ports" | |
| 11 | 11 | "github.com/bnema/vev/internal/protocol" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 12 | 13 | ) | |
| 13 | 14 | ||
| 14 | 15 | const parkedRouteLeaseTTL = 15 * time.Minute | |
| @@ -237,12 +238,12 @@ func (ac *attachedClient) consumePublishedParkedRoute(previous, published attach | |||
| 237 | 238 | return 0 | |
| 238 | 239 | } | |
| 239 | 240 | ||
| 240 | - | func parkedRouteResponseFrame(response protocol.ParkedRouteResponse) (ports.Frame, error) { | |
| 241 | - | payload := ports.MarshalParkedRouteResponse(response) | |
| 241 | + | func parkedRouteResponseFrame(response protocol.ParkedRouteResponse) (wire.Frame, error) { | |
| 242 | + | payload := wire.MarshalParkedRouteResponse(response) | |
| 242 | 243 | if payload == nil { | |
| 243 | - | return ports.Frame{}, errAttachmentTransition | |
| 244 | + | return wire.Frame{}, errAttachmentTransition | |
| 244 | 245 | } | |
| 245 | - | return ports.Frame{Type: ports.MsgParkedRouteResponse, Payload: payload}, nil | |
| 246 | + | return wire.Frame{Type: wire.MsgParkedRouteResponse, Payload: payload}, nil | |
| 246 | 247 | } | |
| 247 | 248 | ||
| 248 | 249 | func (d *Daemon) sendParkedRouteResponse(effect *attachmentEffect, response protocol.ParkedRouteResponse) error { | |
M internal/usecase/daemon/parked_route_test.go +37 -36
| @@ -14,28 +14,29 @@ import ( | |||
| 14 | 14 | "github.com/bnema/vev/internal/ports" | |
| 15 | 15 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 16 | 16 | "github.com/bnema/vev/internal/protocol" | |
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 17 | 18 | ) | |
| 18 | 19 | ||
| 19 | 20 | type parkedRouteFailTransport struct{} | |
| 20 | 21 | ||
| 21 | - | func (parkedRouteFailTransport) Send(ports.Frame) error { return errors.New("send failed") } | |
| 22 | - | func (parkedRouteFailTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 23 | - | func (parkedRouteFailTransport) Close() error { return nil } | |
| 22 | + | func (parkedRouteFailTransport) Send(wire.Frame) error { return errors.New("send failed") } | |
| 23 | + | func (parkedRouteFailTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 24 | + | func (parkedRouteFailTransport) Close() error { return nil } | |
| 24 | 25 | ||
| 25 | 26 | type parkedRouteExpiryTransport struct { | |
| 26 | - | sends chan ports.Frame | |
| 27 | + | sends chan wire.Frame | |
| 27 | 28 | closed chan struct{} | |
| 28 | 29 | once sync.Once | |
| 29 | 30 | } | |
| 30 | 31 | ||
| 31 | - | func (t *parkedRouteExpiryTransport) Send(frame ports.Frame) error { | |
| 32 | + | func (t *parkedRouteExpiryTransport) Send(frame wire.Frame) error { | |
| 32 | 33 | t.sends <- frame | |
| 33 | 34 | return nil | |
| 34 | 35 | } | |
| 35 | 36 | ||
| 36 | - | func (t *parkedRouteExpiryTransport) Recv() (ports.Frame, error) { | |
| 37 | + | func (t *parkedRouteExpiryTransport) Recv() (wire.Frame, error) { | |
| 37 | 38 | <-t.closed | |
| 38 | - | return ports.Frame{}, io.EOF | |
| 39 | + | return wire.Frame{}, io.EOF | |
| 39 | 40 | } | |
| 40 | 41 | ||
| 41 | 42 | func (t *parkedRouteExpiryTransport) Close() error { | |
| @@ -62,7 +63,7 @@ func (c *parkedRouteClock) setNow(now time.Time) { | |||
| 62 | 63 | c.mu.Unlock() | |
| 63 | 64 | } | |
| 64 | 65 | ||
| 65 | - | func armAndPrepareParkedRoute(t *testing.T, d *Daemon, source *session, ac *attachedClient, sends chan ports.Frame) protocol.ParkedRouteLeaseID { | |
| 66 | + | func armAndPrepareParkedRoute(t *testing.T, d *Daemon, source *session, ac *attachedClient, sends chan wire.Frame) protocol.ParkedRouteLeaseID { | |
| 66 | 67 | t.Helper() | |
| 67 | 68 | ac.navigationCapabilities |= protocol.NavigationCapabilityHomePicker | |
| 68 | 69 | token := source.captureAttachmentCapability(ac, ac.transport()) | |
| @@ -70,14 +71,14 @@ func armAndPrepareParkedRoute(t *testing.T, d *Daemon, source *session, ac *atta | |||
| 70 | 71 | require.True(t, admitted) | |
| 71 | 72 | require.NoError(t, d.sendNavigationActionForAttachment(effect, protocol.NavigationOpenHomePicker)) | |
| 72 | 73 | effect.End() | |
| 73 | - | directiveFrame := awaitFrame(t, sends, ports.MsgNavigationAction) | |
| 74 | - | directive, err := ports.UnmarshalNavigationDirective(directiveFrame.Payload) | |
| 74 | + | directiveFrame := awaitFrame(t, sends, wire.MsgNavigationAction) | |
| 75 | + | directive, err := wire.UnmarshalNavigationDirective(directiveFrame.Payload) | |
| 75 | 76 | require.NoError(t, err) | |
| 76 | 77 | ||
| 77 | 78 | prepare := protocol.ParkedRouteRequest{RequestID: 1, LeaseID: directive.LeaseID, Action: protocol.ParkedRoutePrepare} | |
| 78 | - | require.False(t, d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(prepare)})) | |
| 79 | - | readyFrame := awaitFrame(t, sends, ports.MsgParkedRouteResponse) | |
| 80 | - | ready, err := ports.UnmarshalParkedRouteResponse(readyFrame.Payload) | |
| 79 | + | require.False(t, d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(prepare)})) | |
| 80 | + | readyFrame := awaitFrame(t, sends, wire.MsgParkedRouteResponse) | |
| 81 | + | ready, err := wire.UnmarshalParkedRouteResponse(readyFrame.Payload) | |
| 81 | 82 | require.NoError(t, err) | |
| 82 | 83 | require.Equal(t, protocol.ParkedRouteResponse{RequestID: 1, Status: protocol.ParkedRouteReady}, ready) | |
| 83 | 84 | return directive.LeaseID | |
| @@ -108,12 +109,12 @@ func TestParkedRouteSwitchesExactLiveTargetOnRetainedTransport(t *testing.T) { | |||
| 108 | 109 | SessionName: "target", LiveTabID: domain.TabStableID(target.tabs[0].stableID), | |
| 109 | 110 | } | |
| 110 | 111 | switchRequest := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteSwitch, Target: &targetRequest} | |
| 111 | - | require.False(t, d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(switchRequest)})) | |
| 112 | + | require.False(t, d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(switchRequest)})) | |
| 112 | 113 | ||
| 113 | 114 | require.Same(t, target, ac.currentAttachmentSession()) | |
| 114 | 115 | require.False(t, ac.parkedRouteOutput.Load()) | |
| 115 | - | responseFrame := awaitFrame(t, sends, ports.MsgParkedRouteResponse) | |
| 116 | - | response, err := ports.UnmarshalParkedRouteResponse(responseFrame.Payload) | |
| 116 | + | responseFrame := awaitFrame(t, sends, wire.MsgParkedRouteResponse) | |
| 117 | + | response, err := wire.UnmarshalParkedRouteResponse(responseFrame.Payload) | |
| 117 | 118 | require.NoError(t, err) | |
| 118 | 119 | require.Equal(t, protocol.ParkedRouteResponse{RequestID: 2, Status: protocol.ParkedRouteSwitched}, response) | |
| 119 | 120 | } | |
| @@ -147,11 +148,11 @@ func TestParkedRouteSwitchAcceptedBeforeLeaseExpiryCommitsAtomically(t *testing. | |||
| 147 | 148 | SessionName: "target", LiveTabID: domain.TabStableID(target.tabs[0].stableID), | |
| 148 | 149 | } | |
| 149 | 150 | switchRequest := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteSwitch, Target: &targetRequest} | |
| 150 | - | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(switchRequest)}) | |
| 151 | + | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(switchRequest)}) | |
| 151 | 152 | ||
| 152 | 153 | require.Same(t, target, ac.currentAttachmentSession()) | |
| 153 | - | responseFrame := awaitFrame(t, sends, ports.MsgParkedRouteResponse) | |
| 154 | - | response, err := ports.UnmarshalParkedRouteResponse(responseFrame.Payload) | |
| 154 | + | responseFrame := awaitFrame(t, sends, wire.MsgParkedRouteResponse) | |
| 155 | + | response, err := wire.UnmarshalParkedRouteResponse(responseFrame.Payload) | |
| 155 | 156 | require.NoError(t, err) | |
| 156 | 157 | require.Equal(t, protocol.ParkedRouteSwitched, response.Status) | |
| 157 | 158 | } | |
| @@ -185,7 +186,7 @@ func TestParkedRouteRestoresExactStoppedTargetWithDaemonEnvironment(t *testing.T | |||
| 185 | 186 | SessionName: "stopped", Stopped: true, StoppedTab: domain.NewStableTabSelector("tab-b"), | |
| 186 | 187 | } | |
| 187 | 188 | switchRequest := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteSwitch, Target: &target} | |
| 188 | - | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(switchRequest)}) | |
| 189 | + | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(switchRequest)}) | |
| 189 | 190 | ||
| 190 | 191 | restored := ac.currentAttachmentSession() | |
| 191 | 192 | require.NotNil(t, restored) | |
| @@ -210,23 +211,23 @@ func TestParkedRouteStaleTargetLeavesSourceResumable(t *testing.T) { | |||
| 210 | 211 | SessionName: "missing", LiveTabID: "tab-1", | |
| 211 | 212 | } | |
| 212 | 213 | switchRequest := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteSwitch, Target: &missing} | |
| 213 | - | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(switchRequest)}) | |
| 214 | - | staleFrame := awaitFrame(t, sends, ports.MsgParkedRouteResponse) | |
| 215 | - | stale, err := ports.UnmarshalParkedRouteResponse(staleFrame.Payload) | |
| 214 | + | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(switchRequest)}) | |
| 215 | + | staleFrame := awaitFrame(t, sends, wire.MsgParkedRouteResponse) | |
| 216 | + | stale, err := wire.UnmarshalParkedRouteResponse(staleFrame.Payload) | |
| 216 | 217 | require.NoError(t, err) | |
| 217 | 218 | require.Equal(t, protocol.ParkedRouteStaleTarget, stale.Status) | |
| 218 | 219 | require.Same(t, source, ac.currentAttachmentSession()) | |
| 219 | 220 | require.True(t, ac.parkedRouteOutput.Load()) | |
| 220 | 221 | ||
| 221 | 222 | resume := protocol.ParkedRouteRequest{RequestID: 3, LeaseID: leaseID, Action: protocol.ParkedRouteResume} | |
| 222 | - | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(resume)}) | |
| 223 | - | resumedFrame := awaitFrame(t, sends, ports.MsgParkedRouteResponse) | |
| 224 | - | resumed, err := ports.UnmarshalParkedRouteResponse(resumedFrame.Payload) | |
| 223 | + | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(resume)}) | |
| 224 | + | resumedFrame := awaitFrame(t, sends, wire.MsgParkedRouteResponse) | |
| 225 | + | resumed, err := wire.UnmarshalParkedRouteResponse(resumedFrame.Payload) | |
| 225 | 226 | require.NoError(t, err) | |
| 226 | 227 | require.Equal(t, protocol.ParkedRouteResumed, resumed.Status) | |
| 227 | 228 | require.False(t, ac.parkedRouteOutput.Load()) | |
| 228 | - | outputFrame := awaitFrame(t, sends, ports.MsgOutput) | |
| 229 | - | output, err := ports.UnmarshalOutput(outputFrame.Payload) | |
| 229 | + | outputFrame := awaitFrame(t, sends, wire.MsgOutput) | |
| 230 | + | output, err := wire.UnmarshalOutput(outputFrame.Payload) | |
| 230 | 231 | require.NoError(t, err) | |
| 231 | 232 | require.True(t, output.Full) | |
| 232 | 233 | } | |
| @@ -245,10 +246,10 @@ func TestParkedRouteDoesNotReplayOneShotEffectsAfterResume(t *testing.T) { | |||
| 245 | 246 | } | |
| 246 | 247 | ||
| 247 | 248 | resume := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteResume} | |
| 248 | - | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(resume)}) | |
| 249 | - | _ = awaitFrame(t, sends, ports.MsgParkedRouteResponse) | |
| 250 | - | outputFrame := awaitFrame(t, sends, ports.MsgOutput) | |
| 251 | - | output, err := ports.UnmarshalOutput(outputFrame.Payload) | |
| 249 | + | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(resume)}) | |
| 250 | + | _ = awaitFrame(t, sends, wire.MsgParkedRouteResponse) | |
| 251 | + | outputFrame := awaitFrame(t, sends, wire.MsgOutput) | |
| 252 | + | output, err := wire.UnmarshalOutput(outputFrame.Payload) | |
| 252 | 253 | require.NoError(t, err) | |
| 253 | 254 | require.True(t, output.Full) | |
| 254 | 255 | require.NotContains(t, string(output.Data), "one-shot effect") | |
| @@ -270,9 +271,9 @@ func TestParkedRouteExpiredLeaseFailsClosed(t *testing.T) { | |||
| 270 | 271 | ac.parkedRoute.expiresAt = d.clock.Now() | |
| 271 | 272 | ac.parkedRouteMu.Unlock() | |
| 272 | 273 | resume := protocol.ParkedRouteRequest{RequestID: 2, LeaseID: leaseID, Action: protocol.ParkedRouteResume} | |
| 273 | - | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), ports.Frame{Type: ports.MsgParkedRouteRequest, Payload: ports.MarshalParkedRouteRequest(resume)}) | |
| 274 | - | responseFrame := awaitFrame(t, sends, ports.MsgParkedRouteResponse) | |
| 275 | - | response, err := ports.UnmarshalParkedRouteResponse(responseFrame.Payload) | |
| 274 | + | d.handleAttachmentClientFrame(source.captureAttachmentCapability(ac, ac.transport()), wire.Frame{Type: wire.MsgParkedRouteRequest, Payload: wire.MarshalParkedRouteRequest(resume)}) | |
| 275 | + | responseFrame := awaitFrame(t, sends, wire.MsgParkedRouteResponse) | |
| 276 | + | response, err := wire.UnmarshalParkedRouteResponse(responseFrame.Payload) | |
| 276 | 277 | require.NoError(t, err) | |
| 277 | 278 | require.Equal(t, protocol.ParkedRouteExpired, response.Status) | |
| 278 | 279 | require.Same(t, source, ac.currentAttachmentSession()) | |
| @@ -308,7 +309,7 @@ func TestParkedRouteLeaseExpiryClosesExactRetainedTransport(t *testing.T) { | |||
| 308 | 309 | clock.EXPECT().Now().Return(time.Time{}).Maybe() | |
| 309 | 310 | clock.EXPECT().NewTimer(mock.Anything).Return(timer).Once() | |
| 310 | 311 | d.clock = clock | |
| 311 | - | transport := &parkedRouteExpiryTransport{sends: make(chan ports.Frame, 8), closed: make(chan struct{})} | |
| 312 | + | transport := &parkedRouteExpiryTransport{sends: make(chan wire.Frame, 8), closed: make(chan struct{})} | |
| 312 | 313 | ac.replaceTransport(transport) | |
| 313 | 314 | ||
| 314 | 315 | _ = armAndPrepareParkedRoute(t, d, source, ac, transport.sends) | |
M internal/usecase/daemon/performance_benchmark_test.go +9 -8
| @@ -16,6 +16,7 @@ import ( | |||
| 16 | 16 | "github.com/bnema/vev/internal/domain" | |
| 17 | 17 | "github.com/bnema/vev/internal/ports" | |
| 18 | 18 | "github.com/bnema/vev/internal/protocol" | |
| 19 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 19 | 20 | "github.com/bnema/vev/internal/usecase/layout" | |
| 20 | 21 | snapcodec "github.com/bnema/vev/internal/usecase/snapshot" | |
| 21 | 22 | ) | |
| @@ -184,12 +185,12 @@ func TestPerformanceFixtureExplicitCloseReleasesIterationState(t *testing.T) { | |||
| 184 | 185 | func TestCountingOutputTransportCountsOpaquePayloadAndRejectsShortPayload(t *testing.T) { | |
| 185 | 186 | transport := &countingOutputTransport{} | |
| 186 | 187 | ||
| 187 | - | err := transport.Send(ports.Frame{Type: ports.MsgOutput, Payload: make([]byte, 23)}) | |
| 188 | + | err := transport.Send(wire.Frame{Type: wire.MsgOutput, Payload: make([]byte, 23)}) | |
| 188 | 189 | require.Error(t, err) | |
| 189 | 190 | require.Equal(t, countingOutputMetrics{}, transport.metrics()) | |
| 190 | 191 | ||
| 191 | 192 | payload := append(make([]byte, 24), 0xff, 0x00, 0xfe) | |
| 192 | - | require.NoError(t, transport.Send(ports.Frame{Type: ports.MsgOutput, Payload: payload})) | |
| 193 | + | require.NoError(t, transport.Send(wire.Frame{Type: wire.MsgOutput, Payload: payload})) | |
| 193 | 194 | require.Equal(t, countingOutputMetrics{frames: 1, bytes: 3, payloadBytes: uint64(len(payload))}, transport.metrics()) | |
| 194 | 195 | require.Equal(t, payload, transport.lastPayload()) | |
| 195 | 196 | ||
| @@ -230,7 +231,7 @@ func TestPerformanceFixtureCounters(t *testing.T) { | |||
| 230 | 231 | func TestRenderStageHooksCountProductionBoundariesOnFailedSend(t *testing.T) { | |
| 231 | 232 | d, sess, ac, sends := newManualSessionWithPTYs(t, nil) | |
| 232 | 233 | d.paint(sess, ac, true, nil) | |
| 233 | - | _ = awaitFrame(t, sends, ports.MsgOutput) | |
| 234 | + | _ = awaitFrame(t, sends, wire.MsgOutput) | |
| 234 | 235 | var captures, compositions, emissions int | |
| 235 | 236 | ac.renderStages = renderStageHooks{ | |
| 236 | 237 | capture: func() { captures++ }, | |
| @@ -446,7 +447,7 @@ func benchmarkDaemonLargeHistory(b *testing.B, workload string, run func(*perfor | |||
| 446 | 447 | } | |
| 447 | 448 | metrics := fixture.metrics() | |
| 448 | 449 | if payload := fixture.output.lastPayload(); payload != nil { | |
| 449 | - | if _, err := ports.UnmarshalOutput(payload); err != nil { | |
| 450 | + | if _, err := wire.UnmarshalOutput(payload); err != nil { | |
| 450 | 451 | b.Fatalf("decode last output: %v", err) | |
| 451 | 452 | } | |
| 452 | 453 | } | |
| @@ -1347,8 +1348,8 @@ type countingOutputTransport struct { | |||
| 1347 | 1348 | last []byte | |
| 1348 | 1349 | } | |
| 1349 | 1350 | ||
| 1350 | - | func (t *countingOutputTransport) Send(frame ports.Frame) error { | |
| 1351 | - | if frame.Type != ports.MsgOutput { | |
| 1351 | + | func (t *countingOutputTransport) Send(frame wire.Frame) error { | |
| 1352 | + | if frame.Type != wire.MsgOutput { | |
| 1352 | 1353 | return nil | |
| 1353 | 1354 | } | |
| 1354 | 1355 | if len(frame.Payload) < outputPayloadHeaderBytes { | |
| @@ -1362,8 +1363,8 @@ func (t *countingOutputTransport) Send(frame ports.Frame) error { | |||
| 1362 | 1363 | t.mu.Unlock() | |
| 1363 | 1364 | return nil | |
| 1364 | 1365 | } | |
| 1365 | - | func (*countingOutputTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 1366 | - | func (*countingOutputTransport) Close() error { return nil } | |
| 1366 | + | func (*countingOutputTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 1367 | + | func (*countingOutputTransport) Close() error { return nil } | |
| 1367 | 1368 | func (t *countingOutputTransport) reset() { | |
| 1368 | 1369 | t.mu.Lock() | |
| 1369 | 1370 | t.countingOutputMetrics = countingOutputMetrics{} | |
M internal/usecase/daemon/picker.go +5 -4
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | 11 | "github.com/bnema/vev/internal/domain" | |
| 12 | 12 | "github.com/bnema/vev/internal/ports" | |
| 13 | 13 | "github.com/bnema/vev/internal/protocol" | |
| 14 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 14 | 15 | "github.com/bnema/vev/internal/usecase/layout" | |
| 15 | 16 | "github.com/bnema/vev/internal/usecase/picker" | |
| 16 | 17 | "github.com/bnema/vev/internal/usecase/ui" | |
| @@ -923,7 +924,7 @@ func (d *Daemon) sendLocalAttachTargetForAttachment(effect *attachmentEffect, ta | |||
| 923 | 924 | // Explicit tab rows already take the direct transition path above, while | |
| 924 | 925 | // stopped sessions have no active target session and retain the fallback. | |
| 925 | 926 | samePeerEligible := guard.allowSamePeer && targetSess != nil && target.TabIndex <= 0 | |
| 926 | - | payload := ports.MarshalAttachTarget(protocol.AttachTarget{ | |
| 927 | + | payload := wire.MarshalAttachTarget(protocol.AttachTarget{ | |
| 927 | 928 | Session: sessionName, | |
| 928 | 929 | Intent: protocol.IntentAttach, | |
| 929 | 930 | ExactTarget: exactTarget, | |
| @@ -943,7 +944,7 @@ func (d *Daemon) sendLocalAttachTargetForAttachment(effect *attachmentEffect, ta | |||
| 943 | 944 | } else { | |
| 944 | 945 | effect.ac.offerSamePeerTarget(*exactTarget) | |
| 945 | 946 | } | |
| 946 | - | if err := effect.sendControl(ports.Frame{Type: ports.MsgAttachTarget, Payload: payload}); err != nil { | |
| 947 | + | if err := effect.sendControl(wire.Frame{Type: wire.MsgAttachTarget, Payload: payload}); err != nil { | |
| 947 | 948 | if samePeerEligible { | |
| 948 | 949 | effect.ac.clearSamePeerOffer() | |
| 949 | 950 | } | |
| @@ -989,11 +990,11 @@ func (d *Daemon) sendRemoteAttachTargetForAttachment(effect *attachmentEffect, t | |||
| 989 | 990 | RemoteTarget: &remoteTarget, | |
| 990 | 991 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | |
| 991 | 992 | } | |
| 992 | - | payload := ports.MarshalAttachTarget(handoff) | |
| 993 | + | payload := wire.MarshalAttachTarget(handoff) | |
| 993 | 994 | if payload == nil { | |
| 994 | 995 | return failUnavailable() | |
| 995 | 996 | } | |
| 996 | - | if err := effect.sendControl(ports.Frame{Type: ports.MsgAttachTarget, Payload: payload}); err != nil { | |
| 997 | + | if err := effect.sendControl(wire.Frame{Type: wire.MsgAttachTarget, Payload: payload}); err != nil { | |
| 997 | 998 | return domain.UserErr(domain.NoticeSessionUnavailable, "couldn't attach to remote session", err) | |
| 998 | 999 | } | |
| 999 | 1000 | if guard.closePicker { | |
M internal/usecase/daemon/picker_test.go +30 -29
| @@ -17,6 +17,7 @@ import ( | |||
| 17 | 17 | "github.com/bnema/vev/internal/ports" | |
| 18 | 18 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 19 | 19 | "github.com/bnema/vev/internal/protocol" | |
| 20 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 20 | 21 | "github.com/bnema/vev/internal/usecase/layout" | |
| 21 | 22 | "github.com/bnema/vev/internal/usecase/picker" | |
| 22 | 23 | recoveryusecase "github.com/bnema/vev/internal/usecase/recovery" | |
| @@ -34,9 +35,9 @@ type remotePickerSendErrorTransport struct { | |||
| 34 | 35 | err error | |
| 35 | 36 | } | |
| 36 | 37 | ||
| 37 | - | func (t *remotePickerSendErrorTransport) Send(ports.Frame) error { return t.err } | |
| 38 | - | func (*remotePickerSendErrorTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 39 | - | func (*remotePickerSendErrorTransport) Close() error { return nil } | |
| 38 | + | func (t *remotePickerSendErrorTransport) Send(wire.Frame) error { return t.err } | |
| 39 | + | func (*remotePickerSendErrorTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 40 | + | func (*remotePickerSendErrorTransport) Close() error { return nil } | |
| 40 | 41 | ||
| 41 | 42 | type refusingSnapshotDeleteRepository struct { | |
| 42 | 43 | noOpSnapshotRepository | |
| @@ -222,11 +223,11 @@ func TestPickerSortToggleFlipsModeAndKeepsSelection(t *testing.T) { | |||
| 222 | 223 | d.mu.Unlock() | |
| 223 | 224 | ||
| 224 | 225 | d.enterPicker(sess, ac) | |
| 225 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 226 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 226 | 227 | // Move off the attached session's active tab: a navigate rebuild snaps | |
| 227 | 228 | // back to it unless the toggle preserves the selection. | |
| 228 | 229 | d.handleInput(sess, ac, tc.navigate) | |
| 229 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 230 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 230 | 231 | ac.overlays.pickerMu.Lock() | |
| 231 | 232 | before, ok := ac.overlays.picker.Selected() | |
| 232 | 233 | ac.overlays.pickerMu.Unlock() | |
| @@ -239,7 +240,7 @@ func TestPickerSortToggleFlipsModeAndKeepsSelection(t *testing.T) { | |||
| 239 | 240 | } | |
| 240 | 241 | ||
| 241 | 242 | d.handleInput(sess, ac, []byte("s")) | |
| 242 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 243 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 243 | 244 | ||
| 244 | 245 | require.Equal(t, uint32(pickerSortGrouped), d.pickerSort.Load()) | |
| 245 | 246 | require.True(t, ac.overlays.pickerActive()) | |
| @@ -252,7 +253,7 @@ func TestPickerSortToggleFlipsModeAndKeepsSelection(t *testing.T) { | |||
| 252 | 253 | require.Equal(t, " Sessions · grouped ", title) | |
| 253 | 254 | ||
| 254 | 255 | d.handleInput(sess, ac, []byte("s")) | |
| 255 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 256 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 256 | 257 | ||
| 257 | 258 | require.Equal(t, uint32(pickerSortRecent), d.pickerSort.Load()) | |
| 258 | 259 | require.True(t, ac.overlays.pickerActive()) | |
| @@ -812,7 +813,7 @@ func TestPickerResumesStoppedSessionWithPersistedTabNames(t *testing.T) { | |||
| 812 | 813 | d.inactive["work"] = inactiveSession{name: "work", cwd: "/tmp/work", createdAt: 7, tabNames: []string{"shell", "logs"}, record: domain.CatalogueRecord{Name: "work"}, state: protocol.SessionDown} | |
| 813 | 814 | ||
| 814 | 815 | d.resumeStoppedAndSwitch(from, ac, picker.Target{Name: "work", Stopped: true}) | |
| 815 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 816 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 816 | 817 | ||
| 817 | 818 | target := ac.currentSession() | |
| 818 | 819 | require.NotNil(t, target) | |
| @@ -835,16 +836,16 @@ func TestPickerSameSessionNavigationSwitchAndEscClose(t *testing.T) { | |||
| 835 | 836 | }() | |
| 836 | 837 | ||
| 837 | 838 | d.enterPicker(sess, ac) | |
| 838 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 839 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 839 | 840 | d.handleInput(sess, ac, []byte("j")) | |
| 840 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 841 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 841 | 842 | d.handleInput(sess, ac, []byte("\r")) | |
| 842 | 843 | ||
| 843 | 844 | require.Equal(t, 1, testAttachmentTabIndex(sess)) | |
| 844 | 845 | requireFloatingInitialized(t, testAttachmentTab(sess)) | |
| 845 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 846 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 846 | 847 | d.enterPicker(sess, ac) | |
| 847 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 848 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 848 | 849 | clk := &signalClock{timers: make(chan *signalTimer, 1)} | |
| 849 | 850 | d.clock = clk | |
| 850 | 851 | d.handleInput(sess, ac, []byte("\x1b")) | |
| @@ -852,7 +853,7 @@ func TestPickerSameSessionNavigationSwitchAndEscClose(t *testing.T) { | |||
| 852 | 853 | require.True(t, ac.overlays.pickerActive()) | |
| 853 | 854 | timer.ch <- time.Now() | |
| 854 | 855 | require.Eventually(t, func() bool { return !ac.overlays.pickerActive() }, time.Second, 5*time.Millisecond) | |
| 855 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 856 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 856 | 857 | } | |
| 857 | 858 | ||
| 858 | 859 | func TestPickerSplitArrowNavigatesWithoutExiting(t *testing.T) { | |
| @@ -876,7 +877,7 @@ func TestPickerSplitArrowNavigatesWithoutExiting(t *testing.T) { | |||
| 876 | 877 | }() | |
| 877 | 878 | ||
| 878 | 879 | d.enterPicker(sess, ac) | |
| 879 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 880 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 880 | 881 | for _, input := range tc.input { | |
| 881 | 882 | d.handleInput(sess, ac, input) | |
| 882 | 883 | } | |
| @@ -950,7 +951,7 @@ func TestPickerLoneEscapeExitsAfterDelay(t *testing.T) { | |||
| 950 | 951 | defer releases[0]() | |
| 951 | 952 | ||
| 952 | 953 | d.enterPicker(sess, ac) | |
| 953 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 954 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 954 | 955 | clk := &signalClock{timers: make(chan *signalTimer, 1)} | |
| 955 | 956 | d.clock = clk | |
| 956 | 957 | d.handleInput(sess, ac, []byte("\x1b")) | |
| @@ -984,10 +985,10 @@ func TestPickerStalePaintAfterSessionSwitchSendsNoFrame(t *testing.T) { | |||
| 984 | 985 | d.sessions[sess2.id] = sess2 | |
| 985 | 986 | ||
| 986 | 987 | d.firstPaint(sess1, ac1) | |
| 987 | - | awaitFrame(t, sends1, ports.MsgOutput) | |
| 988 | + | awaitFrame(t, sends1, wire.MsgOutput) | |
| 988 | 989 | d.stealClientForTarget(sess1, ac1, sess2, picker.Target{Session: sess2.id}) | |
| 989 | 990 | d.firstPaint(sess2, ac1) | |
| 990 | - | awaitFrame(t, sends1, ports.MsgOutput) | |
| 991 | + | awaitFrame(t, sends1, wire.MsgOutput) | |
| 991 | 992 | require.Same(t, sess2, ac1.currentSession()) | |
| 992 | 993 | for len(sends1) > 0 { | |
| 993 | 994 | <-sends1 | |
| @@ -1011,7 +1012,7 @@ func TestPickerSessionSwitchPublishesBeforeInFlightPaintSendCompletes(t *testing | |||
| 1011 | 1012 | enteredSend := make(chan struct{}) | |
| 1012 | 1013 | releaseSend := make(chan struct{}) | |
| 1013 | 1014 | tr := portsmocks.NewMockTransport(t) | |
| 1014 | - | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(ports.Frame) error { | |
| 1015 | + | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(wire.Frame) error { | |
| 1015 | 1016 | close(enteredSend) | |
| 1016 | 1017 | <-releaseSend | |
| 1017 | 1018 | return nil | |
| @@ -1370,14 +1371,14 @@ func TestPickerResizeRecomposesModal(t *testing.T) { | |||
| 1370 | 1371 | defer releasePTY() | |
| 1371 | 1372 | ||
| 1372 | 1373 | d.enterPicker(sess, ac) | |
| 1373 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1374 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1374 | 1375 | d.resize(sess, ac, domain.Size{Cols: 100, Rows: 30}) | |
| 1375 | 1376 | // Picker recomposition is the relevant event here; do not depend on a real | |
| 1376 | 1377 | // resize-idle timer in this synchronous rendering test. | |
| 1377 | 1378 | d.paint(sess, ac, false, nil) | |
| 1378 | 1379 | ||
| 1379 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 1380 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 1380 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 1381 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 1381 | 1382 | require.NoError(t, err) | |
| 1382 | 1383 | require.Contains(t, string(msg.Data), "┌") | |
| 1383 | 1384 | require.Contains(t, string(msg.Data), "Sessions") | |
| @@ -1455,11 +1456,11 @@ func TestPickerEnterOnStoppedSessionRestoreFailureSurfacesNoticeAndStaysPut(t *t | |||
| 1455 | 1456 | d.ptys = ptys | |
| 1456 | 1457 | ||
| 1457 | 1458 | d.enterPicker(from, ac) | |
| 1458 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1459 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1459 | 1460 | d.handleInput(from, ac, []byte("j")) | |
| 1460 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1461 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1461 | 1462 | d.handleInput(from, ac, []byte("\r")) | |
| 1462 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1463 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1463 | 1464 | ||
| 1464 | 1465 | history := d.notices.history() | |
| 1465 | 1466 | require.Len(t, history, 1, "failed stopped-session restore must record exactly one notice") | |
| @@ -1615,10 +1616,10 @@ func TestPickerKillActiveSessionSnapshotDeleteRefusalReportsOnceAndKeepsPicker(t | |||
| 1615 | 1616 | require.NoError(t, d.catalogue.Create(record)) | |
| 1616 | 1617 | ||
| 1617 | 1618 | d.enterPicker(from, ac) | |
| 1618 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1619 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1619 | 1620 | // MRU-desc order is from(current), recent, older; "j" moves onto "recent". | |
| 1620 | 1621 | d.handleInput(from, ac, []byte("j")) | |
| 1621 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1622 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1622 | 1623 | d.handleInput(from, ac, []byte("x")) | |
| 1623 | 1624 | ||
| 1624 | 1625 | history := d.notices.history() | |
| @@ -1662,11 +1663,11 @@ func TestPickerKillStoppedSessionPersistDeleteFailureSurfacesNoticeAndKeepsEntry | |||
| 1662 | 1663 | d.inactive["stopped"] = inactiveSession{name: "stopped", cwd: "/tmp/stopped", createdAt: 7, incarnation: record.IncarnationID, record: record} | |
| 1663 | 1664 | ||
| 1664 | 1665 | d.enterPicker(from, ac) | |
| 1665 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1666 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1666 | 1667 | d.handleInput(from, ac, []byte("j")) | |
| 1667 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1668 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1668 | 1669 | d.handleInput(from, ac, []byte("x")) | |
| 1669 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 1670 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 1670 | 1671 | ||
| 1671 | 1672 | history := d.notices.history() | |
| 1672 | 1673 | require.NotEmpty(t, history, "failed persisted-record delete must record a notice") | |
M internal/usecase/daemon/prompt_test.go +20 -19
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/vev/internal/domain" | |
| 11 | 11 | "github.com/bnema/vev/internal/ports" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 12 | 13 | ) | |
| 13 | 14 | ||
| 14 | 15 | type failingPTYFactory struct{ err error } | |
| @@ -29,8 +30,8 @@ func TestEnterPromptRendersTitleAndPrefill(t *testing.T) { | |||
| 29 | 30 | defer release() | |
| 30 | 31 | ||
| 31 | 32 | d.enterPrompt(sess, ac, " Rename session ", "0", func(string) error { return nil }) | |
| 32 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 33 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 33 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 34 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 34 | 35 | require.NoError(t, err) | |
| 35 | 36 | require.Contains(t, string(msg.Data), "Rename session") | |
| 36 | 37 | require.Contains(t, string(msg.Data), "> 0") | |
| @@ -45,14 +46,14 @@ func TestPromptSubmitRenamesAndPromotesSession(t *testing.T) { | |||
| 45 | 46 | sess.ephemeral = true | |
| 46 | 47 | ||
| 47 | 48 | d.enterPrompt(sess, ac, " Rename session ", sess.name, func(name string) error { return d.renameSession(sess, name) }) | |
| 48 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 49 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 49 | 50 | d.handlePromptInput(ac, []byte("work\r")) | |
| 50 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | |
| 51 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) | |
| 51 | 52 | ||
| 52 | 53 | require.False(t, ac.overlays.promptActive()) | |
| 53 | 54 | require.Equal(t, "0work", sess.name) | |
| 54 | 55 | require.False(t, sess.ephemeral) | |
| 55 | - | out, err := ports.UnmarshalOutput(repaint.Payload) | |
| 56 | + | out, err := wire.UnmarshalOutput(repaint.Payload) | |
| 56 | 57 | require.NoError(t, err) | |
| 57 | 58 | require.Contains(t, string(out.Data), "0work") | |
| 58 | 59 | require.NotContains(t, string(out.Data), "0work*") | |
| @@ -69,13 +70,13 @@ func TestPromptSubmitErrorKeepsPromptOpen(t *testing.T) { | |||
| 69 | 70 | d.sessions["other"] = &session{sessionCore: sessionCore{id: "other", name: "taken"}, ctx: ctx, cancel: cancel, tabs: []*tab{newTestTabWithContext(p2, ctx, cancel)}} | |
| 70 | 71 | ||
| 71 | 72 | d.enterPrompt(sess, ac, " Rename session ", "", func(name string) error { return d.renameSession(sess, name) }) | |
| 72 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 73 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 73 | 74 | d.handlePromptInput(ac, []byte("taken\r")) | |
| 74 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | |
| 75 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) | |
| 75 | 76 | ||
| 76 | 77 | require.True(t, ac.overlays.promptActive()) | |
| 77 | 78 | require.NotEqual(t, "taken", sess.name) | |
| 78 | - | out, err := ports.UnmarshalOutput(repaint.Payload) | |
| 79 | + | out, err := wire.UnmarshalOutput(repaint.Payload) | |
| 79 | 80 | require.NoError(t, err) | |
| 80 | 81 | require.Contains(t, string(out.Data), "name already in use") | |
| 81 | 82 | } | |
| @@ -92,10 +93,10 @@ func TestPromptSubmitSessionSpawnFailureReportsOneSafeNotice(t *testing.T) { | |||
| 92 | 93 | d.enterPrompt(sess, ac, " Create session ", "", func(name string) error { | |
| 93 | 94 | return d.createSessionAndSwitch(sess, ac, name) | |
| 94 | 95 | }) | |
| 95 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 96 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 96 | 97 | d.handlePromptInput(ac, []byte("new\r")) | |
| 97 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | |
| 98 | - | output, err := ports.UnmarshalOutput(repaint.Payload) | |
| 98 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) | |
| 99 | + | output, err := wire.UnmarshalOutput(repaint.Payload) | |
| 99 | 100 | require.NoError(t, err) | |
| 100 | 101 | require.Contains(t, string(output.Data), "couldn't create session: shell failed to start") | |
| 101 | 102 | ||
| @@ -140,10 +141,10 @@ func TestPromptSubmitValidationErrorStaysInlineOnly(t *testing.T) { | |||
| 140 | 141 | d.enterPrompt(sess, ac, " Create session ", "", func(name string) error { | |
| 141 | 142 | return d.createSessionAndSwitch(sess, ac, name) | |
| 142 | 143 | }) | |
| 143 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 144 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 144 | 145 | d.handlePromptInput(ac, tt.input) | |
| 145 | - | repaint := awaitFrame(t, sends, ports.MsgOutput) | |
| 146 | - | output, err := ports.UnmarshalOutput(repaint.Payload) | |
| 146 | + | repaint := awaitFrame(t, sends, wire.MsgOutput) | |
| 147 | + | output, err := wire.UnmarshalOutput(repaint.Payload) | |
| 147 | 148 | require.NoError(t, err) | |
| 148 | 149 | require.Contains(t, string(output.Data), tt.wantErr.Error()) | |
| 149 | 150 | ||
| @@ -160,9 +161,9 @@ func TestPromptEscapeCancelsWithoutRename(t *testing.T) { | |||
| 160 | 161 | oldName := sess.name | |
| 161 | 162 | ||
| 162 | 163 | d.enterPrompt(sess, ac, " Rename session ", oldName, func(name string) error { return d.renameSession(sess, name) }) | |
| 163 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 164 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 164 | 165 | d.handlePromptInput(ac, []byte("new\x1b")) | |
| 165 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 166 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 166 | 167 | ||
| 167 | 168 | require.False(t, ac.overlays.promptActive()) | |
| 168 | 169 | require.Equal(t, oldName, sess.name) | |
| @@ -176,13 +177,13 @@ func TestPaletteRNSOpensRenamePrompt(t *testing.T) { | |||
| 176 | 177 | sess.ephemeral = true | |
| 177 | 178 | ||
| 178 | 179 | d.enterPalette(sess, ac) | |
| 179 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 180 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 180 | 181 | d.handlePaletteInput(ac, []byte("RNS\r")) | |
| 181 | - | out := awaitFrame(t, sends, ports.MsgOutput) | |
| 182 | + | out := awaitFrame(t, sends, wire.MsgOutput) | |
| 182 | 183 | ||
| 183 | 184 | require.False(t, ac.overlays.paletteActive()) | |
| 184 | 185 | require.True(t, ac.overlays.promptActive()) | |
| 185 | - | msg, err := ports.UnmarshalOutput(out.Payload) | |
| 186 | + | msg, err := wire.UnmarshalOutput(out.Payload) | |
| 186 | 187 | require.NoError(t, err) | |
| 187 | 188 | require.Contains(t, string(msg.Data), "Rename session") | |
| 188 | 189 | require.Contains(t, string(msg.Data), "> 0") | |
M internal/usecase/daemon/recent_route_snapshot_test.go +6 -6
| @@ -4,8 +4,8 @@ import ( | |||
| 4 | 4 | "testing" | |
| 5 | 5 | ||
| 6 | 6 | "github.com/bnema/vev/internal/domain" | |
| 7 | - | "github.com/bnema/vev/internal/ports" | |
| 8 | 7 | "github.com/bnema/vev/internal/protocol" | |
| 8 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 9 | 9 | "github.com/stretchr/testify/require" | |
| 10 | 10 | ) | |
| 11 | 11 | ||
| @@ -69,11 +69,11 @@ func TestRecentRouteSnapshotRepaintsWithoutDeferredIdentity(t *testing.T) { | |||
| 69 | 69 | ac.installTestAttachmentCapability(token) | |
| 70 | 70 | ac.setRouteSnapshot(protocol.RecentRouteSnapshot{Generation: 1}) | |
| 71 | 71 | ||
| 72 | - | payload, err := ports.MarshalRecentRouteSnapshot(protocol.RecentRouteSnapshot{Generation: 2}) | |
| 72 | + | payload, err := wire.MarshalRecentRouteSnapshot(protocol.RecentRouteSnapshot{Generation: 2}) | |
| 73 | 73 | require.NoError(t, err) | |
| 74 | - | require.False(t, d.handleAttachmentClientFrame(token, ports.Frame{Type: ports.MsgRecentRouteSnapshot, Payload: payload})) | |
| 74 | + | require.False(t, d.handleAttachmentClientFrame(token, wire.Frame{Type: wire.MsgRecentRouteSnapshot, Payload: payload})) | |
| 75 | 75 | ||
| 76 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 76 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 77 | 77 | } | |
| 78 | 78 | ||
| 79 | 79 | func TestAttachmentRouteSnapshotCopiesPublishedEntries(t *testing.T) { | |
| @@ -115,11 +115,11 @@ func TestPaletteRecentRouteSelectionSendsTypedClientAction(t *testing.T) { | |||
| 115 | 115 | var action protocol.RouteNavigationAction | |
| 116 | 116 | found := false | |
| 117 | 117 | for _, frame := range frames { | |
| 118 | - | if frame.Type != ports.MsgNavigateRecentRoute { | |
| 118 | + | if frame.Type != wire.MsgNavigateRecentRoute { | |
| 119 | 119 | continue | |
| 120 | 120 | } | |
| 121 | 121 | var err error | |
| 122 | - | action, err = ports.UnmarshalRouteNavigationAction(frame.Payload) | |
| 122 | + | action, err = wire.UnmarshalRouteNavigationAction(frame.Payload) | |
| 123 | 123 | require.NoError(t, err) | |
| 124 | 124 | found = true | |
| 125 | 125 | } | |
M internal/usecase/daemon/remote_attach.go +7 -6
| @@ -7,6 +7,7 @@ import ( | |||
| 7 | 7 | "github.com/bnema/vev/internal/domain" | |
| 8 | 8 | "github.com/bnema/vev/internal/ports" | |
| 9 | 9 | "github.com/bnema/vev/internal/protocol" | |
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 10 | 11 | ) | |
| 11 | 12 | ||
| 12 | 13 | // routeRemoteTargetWithContext is the exact-target branch for picker handoffs. | |
| @@ -119,12 +120,12 @@ func (d *Daemon) sendNavigationActionForAttachment(effect *attachmentEffect, act | |||
| 119 | 120 | effect.ac.clearParkedRoute() | |
| 120 | 121 | } | |
| 121 | 122 | } | |
| 122 | - | payload := ports.MarshalNavigationDirective(directive) | |
| 123 | + | payload := wire.MarshalNavigationDirective(directive) | |
| 123 | 124 | if payload == nil { | |
| 124 | 125 | rollback() | |
| 125 | 126 | return errAttachmentTransition | |
| 126 | 127 | } | |
| 127 | - | if err := effect.sendControl(ports.Frame{Type: ports.MsgNavigationAction, Payload: payload}); err != nil { | |
| 128 | + | if err := effect.sendControl(wire.Frame{Type: wire.MsgNavigationAction, Payload: payload}); err != nil { | |
| 128 | 129 | rollback() | |
| 129 | 130 | return err | |
| 130 | 131 | } | |
| @@ -132,11 +133,11 @@ func (d *Daemon) sendNavigationActionForAttachment(effect *attachmentEffect, act | |||
| 132 | 133 | } | |
| 133 | 134 | ||
| 134 | 135 | func (d *Daemon) sendRecentRouteNavigationActionForAttachment(effect *attachmentEffect, action protocol.RouteNavigationAction) error { | |
| 135 | - | payload, err := ports.MarshalRouteNavigationAction(action) | |
| 136 | + | payload, err := wire.MarshalRouteNavigationAction(action) | |
| 136 | 137 | if err != nil { | |
| 137 | 138 | return errAttachmentTransition | |
| 138 | 139 | } | |
| 139 | - | return effect.sendControl(ports.Frame{Type: ports.MsgNavigateRecentRoute, Payload: payload}) | |
| 140 | + | return effect.sendControl(wire.Frame{Type: wire.MsgNavigateRecentRoute, Payload: payload}) | |
| 140 | 141 | } | |
| 141 | 142 | ||
| 142 | 143 | func (d *Daemon) sendCommittedRouteIdentityForAttachment(effect *attachmentEffect) error { | |
| @@ -149,11 +150,11 @@ func (d *Daemon) sendCommittedRouteIdentityForAttachment(effect *attachmentEffec | |||
| 149 | 150 | Ephemeral: effect.sess.ephemeral, | |
| 150 | 151 | } | |
| 151 | 152 | effect.sess.mu.Unlock() | |
| 152 | - | payload, err := ports.MarshalCommittedRouteIdentity(identity) | |
| 153 | + | payload, err := wire.MarshalCommittedRouteIdentity(identity) | |
| 153 | 154 | if err != nil { | |
| 154 | 155 | return errAttachmentTransition | |
| 155 | 156 | } | |
| 156 | - | return effect.sendControl(ports.Frame{Type: ports.MsgCommittedRouteIdentity, Payload: payload}) | |
| 157 | + | return effect.sendControl(wire.Frame{Type: wire.MsgCommittedRouteIdentity, Payload: payload}) | |
| 157 | 158 | } | |
| 158 | 159 | ||
| 159 | 160 | func (d *Daemon) finishRouteAttach(sess *session, tr ports.Transport, sz domain.Size, h protocol.Hello, routeCreated, purge bool) (*attachedClient, error) { | |
M internal/usecase/daemon/remote_attach_test.go +8 -7
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | 9 | "github.com/bnema/vev/internal/domain" | |
| 10 | 10 | "github.com/bnema/vev/internal/ports" | |
| 11 | 11 | "github.com/bnema/vev/internal/protocol" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 12 | 13 | "github.com/bnema/vev/internal/usecase/picker" | |
| 13 | 14 | ) | |
| 14 | 15 | ||
| @@ -30,7 +31,7 @@ func TestLocalPickerOfferCarriesExactLifecycle(t *testing.T) { | |||
| 30 | 31 | ||
| 31 | 32 | require.NoError(t, d.switchToTargetForAttachment(effect, picker.Target{Session: target.id}, sessionHandoffGuard{allowSamePeer: true}, "picker-select")) | |
| 32 | 33 | frame := receiveRemotePicker(t, sends, "local attach target") | |
| 33 | - | got, err := ports.UnmarshalAttachTarget(frame.Payload) | |
| 34 | + | got, err := wire.UnmarshalAttachTarget(frame.Payload) | |
| 34 | 35 | require.NoError(t, err) | |
| 35 | 36 | require.Empty(t, got.Endpoint) | |
| 36 | 37 | require.Equal(t, protocol.IntentAttach, got.Intent) | |
| @@ -61,10 +62,10 @@ func TestStoppedLocalPickerHandoffWaitsForClientClose(t *testing.T) { | |||
| 61 | 62 | }, sessionHandoffGuard{closePicker: true, allowSamePeer: true}, "picker-select")) | |
| 62 | 63 | ||
| 63 | 64 | cleanup := receiveRemotePicker(t, sends, "graphics cleanup") | |
| 64 | - | require.Equal(t, ports.MsgOutput, cleanup.Type) | |
| 65 | + | require.Equal(t, wire.MsgOutput, cleanup.Type) | |
| 65 | 66 | handoff := receiveRemotePicker(t, sends, "stopped local attach target") | |
| 66 | - | require.Equal(t, ports.MsgAttachTarget, handoff.Type) | |
| 67 | - | target, err := ports.UnmarshalAttachTarget(handoff.Payload) | |
| 67 | + | require.Equal(t, wire.MsgAttachTarget, handoff.Type) | |
| 68 | + | target, err := wire.UnmarshalAttachTarget(handoff.Payload) | |
| 68 | 69 | require.NoError(t, err) | |
| 69 | 70 | require.False(t, target.SamePeer) | |
| 70 | 71 | require.Equal(t, &protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "stopped"}, target.ExactTarget) | |
| @@ -93,7 +94,7 @@ func TestRemotePickerRichHandoffCarriesLifecycleTabAndPolicy(t *testing.T) { | |||
| 93 | 94 | target := picker.Target{Session: key.ID(), RemoteKey: &key, RemoteTarget: &remoteTarget, TabID: "tab-1"} | |
| 94 | 95 | require.NoError(t, d.sendRemoteAttachTargetForAttachment(effect, target, sessionHandoffGuard{closePicker: true}, "picker-select")) | |
| 95 | 96 | frame := receiveRemotePicker(t, sends, "rich attach target") | |
| 96 | - | got, err := ports.UnmarshalAttachTarget(frame.Payload) | |
| 97 | + | got, err := wire.UnmarshalAttachTarget(frame.Payload) | |
| 97 | 98 | require.NoError(t, err) | |
| 98 | 99 | require.NotNil(t, got.RemoteTarget) | |
| 99 | 100 | require.Equal(t, remoteTarget, *got.RemoteTarget) | |
| @@ -140,7 +141,7 @@ func TestRemotePickerRichHandoffRejectsMismatchedRouteKey(t *testing.T) { | |||
| 140 | 141 | for { | |
| 141 | 142 | select { | |
| 142 | 143 | case frame := <-sends: | |
| 143 | - | require.NotEqual(t, ports.MsgAttachTarget, frame.Type) | |
| 144 | + | require.NotEqual(t, wire.MsgAttachTarget, frame.Type) | |
| 144 | 145 | default: | |
| 145 | 146 | return | |
| 146 | 147 | } | |
| @@ -174,7 +175,7 @@ func TestRemotePickerRichHandoffRejectsReplacedLifecycle(t *testing.T) { | |||
| 174 | 175 | for { | |
| 175 | 176 | select { | |
| 176 | 177 | case frame := <-sends: | |
| 177 | - | require.NotEqual(t, ports.MsgAttachTarget, frame.Type, "rejected handoff must not send an attach target") | |
| 178 | + | require.NotEqual(t, wire.MsgAttachTarget, frame.Type, "rejected handoff must not send an attach target") | |
| 178 | 179 | default: | |
| 179 | 180 | return | |
| 180 | 181 | } | |
M internal/usecase/daemon/remote_picker_test.go +9 -8
| @@ -18,6 +18,7 @@ import ( | |||
| 18 | 18 | "github.com/bnema/vev/internal/ports" | |
| 19 | 19 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 20 | 20 | "github.com/bnema/vev/internal/protocol" | |
| 21 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 21 | 22 | "github.com/bnema/vev/internal/usecase/picker" | |
| 22 | 23 | ) | |
| 23 | 24 | ||
| @@ -696,8 +697,8 @@ func TestRemotePickerHandoffSendsTargetAndLeavesNoShadowSession(t *testing.T) { | |||
| 696 | 697 | require.NoError(t, d.sendRemoteAttachTargetForAttachment(effect, target, sessionHandoffGuard{closePicker: true}, "picker-select")) | |
| 697 | 698 | ||
| 698 | 699 | frame := receiveRemotePicker(t, sends, "attach target") | |
| 699 | - | require.Equal(t, ports.MsgAttachTarget, frame.Type) | |
| 700 | - | got, err := ports.UnmarshalAttachTarget(frame.Payload) | |
| 700 | + | require.Equal(t, wire.MsgAttachTarget, frame.Type) | |
| 701 | + | got, err := wire.UnmarshalAttachTarget(frame.Payload) | |
| 701 | 702 | require.NoError(t, err) | |
| 702 | 703 | require.Equal(t, protocol.AttachTarget{Endpoint: "arch", Session: "work", Intent: protocol.IntentAttach, RemoteTarget: &remoteTarget, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned}, got) | |
| 703 | 704 | require.Nil(t, ac.currentAttachmentSession()) | |
| @@ -748,7 +749,7 @@ func TestRemotePickerSelectsStoppedRemoteTabAndRestoresIt(t *testing.T) { | |||
| 748 | 749 | require.NoError(t, local.sendRemoteAttachTargetForAttachment(effect, selected, sessionHandoffGuard{closePicker: true}, "picker-select")) | |
| 749 | 750 | ||
| 750 | 751 | frame := receiveRemotePicker(t, sends, "stopped remote target") | |
| 751 | - | handoff, err := ports.UnmarshalAttachTarget(frame.Payload) | |
| 752 | + | handoff, err := wire.UnmarshalAttachTarget(frame.Payload) | |
| 752 | 753 | require.NoError(t, err) | |
| 753 | 754 | require.NotNil(t, handoff.RemoteTarget) | |
| 754 | 755 | require.Equal(t, selected.RemoteTarget, handoff.RemoteTarget) | |
| @@ -819,7 +820,7 @@ func TestRemotePickerResurrectsStoppedRemoteSessionWithoutTabMetadata(t *testing | |||
| 819 | 820 | require.NoError(t, local.sendRemoteAttachTargetForAttachment(effect, selected, sessionHandoffGuard{closePicker: true}, "picker-select")) | |
| 820 | 821 | ||
| 821 | 822 | frame := receiveRemotePicker(t, sends, "stopped remote target without tab metadata") | |
| 822 | - | handoff, err := ports.UnmarshalAttachTarget(frame.Payload) | |
| 823 | + | handoff, err := wire.UnmarshalAttachTarget(frame.Payload) | |
| 823 | 824 | require.NoError(t, err) | |
| 824 | 825 | require.Equal(t, selected.RemoteTarget, handoff.RemoteTarget) | |
| 825 | 826 | ||
| @@ -862,8 +863,8 @@ func TestNavigationActionHandoffSendsBoundedAction(t *testing.T) { | |||
| 862 | 863 | defer effect.End() | |
| 863 | 864 | require.NoError(t, d.sendNavigationActionForAttachment(effect, tt.action)) | |
| 864 | 865 | frame := receiveRemotePicker(t, sends, "navigation action") | |
| 865 | - | require.Equal(t, ports.MsgNavigationAction, frame.Type) | |
| 866 | - | directive, err := ports.UnmarshalNavigationDirective(frame.Payload) | |
| 866 | + | require.Equal(t, wire.MsgNavigationAction, frame.Type) | |
| 867 | + | directive, err := wire.UnmarshalNavigationDirective(frame.Payload) | |
| 867 | 868 | require.NoError(t, err) | |
| 868 | 869 | require.Equal(t, tt.action, directive.Action) | |
| 869 | 870 | if tt.action == protocol.NavigationOpenHomePicker { | |
| @@ -920,10 +921,10 @@ func TestRemotePickerHandoffSendFailureKeepsPickerOpen(t *testing.T) { | |||
| 920 | 921 | require.Same(t, sess, ac.currentAttachmentSession()) | |
| 921 | 922 | } | |
| 922 | 923 | ||
| 923 | - | func addRemoteRefreshPickerOwner(t *testing.T, d *Daemon, id domain.SessionID, transports ...ports.Transport) (*session, *attachedClient, chan ports.Frame) { | |
| 924 | + | func addRemoteRefreshPickerOwner(t *testing.T, d *Daemon, id domain.SessionID, transports ...ports.Transport) (*session, *attachedClient, chan wire.Frame) { | |
| 924 | 925 | t.Helper() | |
| 925 | 926 | var tr ports.Transport | |
| 926 | - | var sends chan ports.Frame | |
| 927 | + | var sends chan wire.Frame | |
| 927 | 928 | if len(transports) != 0 { | |
| 928 | 929 | tr = transports[0] | |
| 929 | 930 | } else { | |
M internal/usecase/daemon/remote_preview.go +6 -5
| @@ -7,11 +7,12 @@ import ( | |||
| 7 | 7 | "github.com/bnema/vev/internal/domain" | |
| 8 | 8 | "github.com/bnema/vev/internal/ports" | |
| 9 | 9 | "github.com/bnema/vev/internal/protocol" | |
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 10 | 11 | ) | |
| 11 | 12 | ||
| 12 | - | func (d *Daemon) handleRemotePreview(tr ports.Transport, frame ports.Frame) error { | |
| 13 | + | func (d *Daemon) handleRemotePreview(tr ports.Transport, frame wire.Frame) error { | |
| 13 | 14 | defer func() { _ = tr.Close() }() | |
| 14 | - | request, err := ports.UnmarshalRemotePreviewRequest(frame.Payload) | |
| 15 | + | request, err := wire.UnmarshalRemotePreviewRequest(frame.Payload) | |
| 15 | 16 | if err != nil { | |
| 16 | 17 | return d.sendRemotePreview(tr, protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: protocol.RemotePreviewMalformed}) | |
| 17 | 18 | } | |
| @@ -27,11 +28,11 @@ func (d *Daemon) handleRemotePreview(tr ports.Transport, frame ports.Frame) erro | |||
| 27 | 28 | } | |
| 28 | 29 | ||
| 29 | 30 | func (d *Daemon) sendRemotePreview(tr ports.Transport, preview protocol.RemotePreview) error { | |
| 30 | - | payload := ports.MarshalRemotePreview(preview) | |
| 31 | + | payload := wire.MarshalRemotePreview(preview) | |
| 31 | 32 | if payload == nil { | |
| 32 | - | payload = ports.MarshalRemotePreview(protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: protocol.RemotePreviewMalformed}) | |
| 33 | + | payload = wire.MarshalRemotePreview(protocol.RemotePreview{Version: protocol.RemotePreviewSchemaVersion, Status: protocol.RemotePreviewMalformed}) | |
| 33 | 34 | } | |
| 34 | - | return d.boundedControlSend(tr, ports.Frame{Type: ports.MsgRemotePreviewResponse, Payload: payload}) | |
| 35 | + | return d.boundedControlSend(tr, wire.Frame{Type: wire.MsgRemotePreviewResponse, Payload: payload}) | |
| 35 | 36 | } | |
| 36 | 37 | ||
| 37 | 38 | var errRemotePreviewNoSuchTarget = errors.New("daemon: remote preview target does not exist") | |
M internal/usecase/daemon/render_coordinator_handshake_test.go +7 -7
| @@ -9,13 +9,13 @@ import ( | |||
| 9 | 9 | "github.com/stretchr/testify/require" | |
| 10 | 10 | ||
| 11 | 11 | "github.com/bnema/vev/internal/domain" | |
| 12 | - | "github.com/bnema/vev/internal/ports" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 13 | ) | |
| 14 | 14 | ||
| 15 | 15 | // fanoutBlockingTransport blocks only the first output send. The paired | |
| 16 | 16 | // healthy attachment must still receive its frame while this peer is stuck. | |
| 17 | 17 | type fanoutBlockingTransport struct { | |
| 18 | - | sent chan ports.Frame | |
| 18 | + | sent chan wire.Frame | |
| 19 | 19 | entered chan struct{} | |
| 20 | 20 | release chan struct{} | |
| 21 | 21 | done chan struct{} | |
| @@ -26,16 +26,16 @@ type fanoutBlockingTransport struct { | |||
| 26 | 26 | ||
| 27 | 27 | func newFanoutBlockingTransport() *fanoutBlockingTransport { | |
| 28 | 28 | return &fanoutBlockingTransport{ | |
| 29 | - | sent: make(chan ports.Frame, 8), | |
| 29 | + | sent: make(chan wire.Frame, 8), | |
| 30 | 30 | entered: make(chan struct{}), | |
| 31 | 31 | release: make(chan struct{}), | |
| 32 | 32 | done: make(chan struct{}), | |
| 33 | 33 | } | |
| 34 | 34 | } | |
| 35 | 35 | ||
| 36 | - | func (t *fanoutBlockingTransport) Send(frame ports.Frame) error { | |
| 36 | + | func (t *fanoutBlockingTransport) Send(frame wire.Frame) error { | |
| 37 | 37 | t.sent <- frame | |
| 38 | - | if frame.Type == ports.MsgOutput { | |
| 38 | + | if frame.Type == wire.MsgOutput { | |
| 39 | 39 | t.enteredOne.Do(func() { close(t.entered) }) | |
| 40 | 40 | <-t.release | |
| 41 | 41 | } | |
| @@ -43,7 +43,7 @@ func (t *fanoutBlockingTransport) Send(frame ports.Frame) error { | |||
| 43 | 43 | return nil | |
| 44 | 44 | } | |
| 45 | 45 | ||
| 46 | - | func (t *fanoutBlockingTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 46 | + | func (t *fanoutBlockingTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 47 | 47 | ||
| 48 | 48 | func (t *fanoutBlockingTransport) Close() error { | |
| 49 | 49 | t.releaseOne.Do(func() { close(t.release) }) | |
| @@ -102,7 +102,7 @@ func TestRenderCoordinatorFanoutDoesNotWaitForSlowTransport(t *testing.T) { | |||
| 102 | 102 | ||
| 103 | 103 | select { | |
| 104 | 104 | case frame := <-healthySends: | |
| 105 | - | require.Equal(t, ports.MsgOutput, frame.Type, "healthy attachment did not receive output") | |
| 105 | + | require.Equal(t, wire.MsgOutput, frame.Type, "healthy attachment did not receive output") | |
| 106 | 106 | case <-time.After(2 * time.Second): | |
| 107 | 107 | t.Fatal("healthy attachment remained blocked behind the slow transport") | |
| 108 | 108 | } | |
M internal/usecase/daemon/render_coordinator_test.go +4 -3
| @@ -15,6 +15,7 @@ import ( | |||
| 15 | 15 | "github.com/bnema/vev/internal/ports" | |
| 16 | 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 17 | 17 | "github.com/bnema/vev/internal/protocol" | |
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 18 | 19 | "github.com/bnema/vev/internal/usecase/keys" | |
| 19 | 20 | "github.com/bnema/vev/internal/usecase/layout" | |
| 20 | 21 | ) | |
| @@ -267,12 +268,12 @@ func awaitLatestCoordinatorTimer(t *testing.T, clk *coordinatorMockClock) *coord | |||
| 267 | 268 | } | |
| 268 | 269 | } | |
| 269 | 270 | ||
| 270 | - | func requireNoCoordinatorOutputFrame(t *testing.T, sends chan ports.Frame) { | |
| 271 | + | func requireNoCoordinatorOutputFrame(t *testing.T, sends chan wire.Frame) { | |
| 271 | 272 | t.Helper() | |
| 272 | 273 | for { | |
| 273 | 274 | select { | |
| 274 | 275 | case frame := <-sends: | |
| 275 | - | if frame.Type == ports.MsgRoutePosition { | |
| 276 | + | if frame.Type == wire.MsgRoutePosition { | |
| 276 | 277 | continue | |
| 277 | 278 | } | |
| 278 | 279 | t.Fatalf("unexpected output frame: %+v", frame) | |
| @@ -1509,7 +1510,7 @@ func TestRenderCoordinatorSyncBatchSurvivesAttachmentLifecycle(t *testing.T) { | |||
| 1509 | 1510 | } | |
| 1510 | 1511 | ||
| 1511 | 1512 | func TestRenderCoordinatorResizeEpochDispatch(t *testing.T) { | |
| 1512 | - | newResizeFixture := func(t *testing.T) (*Daemon, *session, *attachedClient, chan ports.Frame, *coordinatorMockClock, chan renderInvalidation) { | |
| 1513 | + | newResizeFixture := func(t *testing.T) (*Daemon, *session, *attachedClient, chan wire.Frame, *coordinatorMockClock, chan renderInvalidation) { | |
| 1513 | 1514 | t.Helper() | |
| 1514 | 1515 | p, releasePTY := newBlockingPTY(t) | |
| 1515 | 1516 | t.Cleanup(releasePTY) | |
M internal/usecase/daemon/render_damage_receipt_test.go +3 -2
| @@ -6,6 +6,7 @@ import ( | |||
| 6 | 6 | renderer "github.com/bnema/vev-vt" | |
| 7 | 7 | "github.com/bnema/vev/internal/domain" | |
| 8 | 8 | "github.com/bnema/vev/internal/ports" | |
| 9 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 9 | 10 | "github.com/bnema/vev/internal/usecase/layout" | |
| 10 | 11 | "github.com/bnema/vev/internal/usecase/picker" | |
| 11 | 12 | "github.com/stretchr/testify/require" | |
| @@ -156,7 +157,7 @@ func TestRenderDamageReceiptRetainsRealVTDamageAcrossFailedEmission(t *testing.T | |||
| 156 | 157 | state, composed = captureComposeForReceiptTest(t, sess, ac) | |
| 157 | 158 | require.True(t, d.emitFrame(sess, ac, state, composed)) | |
| 158 | 159 | frame := <-sends | |
| 159 | - | out, err := ports.UnmarshalOutput(frame.Payload) | |
| 160 | + | out, err := wire.UnmarshalOutput(frame.Payload) | |
| 160 | 161 | require.NoError(t, err) | |
| 161 | 162 | require.Contains(t, string(out.Data), "changed", "retry must emit the retained terminal bytes") | |
| 162 | 163 | p.mu.Lock() | |
| @@ -223,7 +224,7 @@ func TestPrepareFailureFallbackOnlySuppressesRecursiveNoticePaint(t *testing.T) | |||
| 223 | 224 | require.True(t, d.emitFrame(sess, ac, state, composed)) | |
| 224 | 225 | require.Len(t, d.notices.history(), want) | |
| 225 | 226 | frame := <-sends | |
| 226 | - | require.Equal(t, ports.MsgOutput, frame.Type, "outer failure %d must repaint its notice", want) | |
| 227 | + | require.Equal(t, wire.MsgOutput, frame.Type, "outer failure %d must repaint its notice", want) | |
| 227 | 228 | require.False(t, ac.prepareFailureFallback.Load()) | |
| 228 | 229 | } | |
| 229 | 230 | } | |
M internal/usecase/daemon/render_pipeline.go +3 -2
| @@ -7,6 +7,7 @@ import ( | |||
| 7 | 7 | "github.com/bnema/vev/internal/domain" | |
| 8 | 8 | "github.com/bnema/vev/internal/ports" | |
| 9 | 9 | "github.com/bnema/vev/internal/protocol" | |
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 10 | 11 | "github.com/bnema/vev/internal/usecase/layout" | |
| 11 | 12 | "github.com/bnema/vev/internal/usecase/notices" | |
| 12 | 13 | "github.com/bnema/vev/internal/usecase/palette" | |
| @@ -539,7 +540,7 @@ func (d *Daemon) emitFrame(entry *session, ac *attachedClient, state *capturedRe | |||
| 539 | 540 | } | |
| 540 | 541 | ||
| 541 | 542 | if position.ActiveTabID != "" && position != ac.output.lastRoutePosition { | |
| 542 | - | payload, positionMarshalErr := ports.MarshalRoutePosition(position) | |
| 543 | + | payload, positionMarshalErr := wire.MarshalRoutePosition(position) | |
| 543 | 544 | if positionMarshalErr != nil { | |
| 544 | 545 | d.log.Error("marshal route position", "err", positionMarshalErr) | |
| 545 | 546 | } else { | |
| @@ -560,7 +561,7 @@ func (d *Daemon) emitFrame(entry *session, ac *attachedClient, state *capturedRe | |||
| 560 | 561 | if async, ok := sendTr.(ports.AsyncTransport); ok { | |
| 561 | 562 | send = async.SendAsync | |
| 562 | 563 | } | |
| 563 | - | sendErr = send(ports.Frame{Type: ports.MsgRoutePosition, Payload: payload}) | |
| 564 | + | sendErr = send(wire.Frame{Type: wire.MsgRoutePosition, Payload: payload}) | |
| 564 | 565 | } | |
| 565 | 566 | } | |
| 566 | 567 | if marks.attachmentEffect != nil && interruptible { | |
M internal/usecase/daemon/render_pipeline_cache_test.go +5 -5
| @@ -8,7 +8,7 @@ import ( | |||
| 8 | 8 | ||
| 9 | 9 | renderer "github.com/bnema/vev-vt" | |
| 10 | 10 | "github.com/bnema/vev/internal/domain" | |
| 11 | - | "github.com/bnema/vev/internal/ports" | |
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 12 | 12 | "github.com/bnema/vev/internal/usecase/layout" | |
| 13 | 13 | themeui "github.com/bnema/vev/internal/usecase/theme" | |
| 14 | 14 | "github.com/bnema/vev/internal/usecase/ui" | |
| @@ -17,9 +17,9 @@ import ( | |||
| 17 | 17 | ||
| 18 | 18 | type cacheFailTransport struct{} | |
| 19 | 19 | ||
| 20 | - | func (cacheFailTransport) Send(ports.Frame) error { return errors.New("send failed") } | |
| 21 | - | func (cacheFailTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 22 | - | func (cacheFailTransport) Close() error { return nil } | |
| 20 | + | func (cacheFailTransport) Send(wire.Frame) error { return errors.New("send failed") } | |
| 21 | + | func (cacheFailTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 22 | + | func (cacheFailTransport) Close() error { return nil } | |
| 23 | 23 | ||
| 24 | 24 | func TestPipelineCachePublishesOnlyAfterEmission(t *testing.T) { | |
| 25 | 25 | for _, failure := range []struct { | |
| @@ -69,7 +69,7 @@ func TestPipelineCachePublishesOnlyAfterEmission(t *testing.T) { | |||
| 69 | 69 | require.True(t, d.emitFrame(sess, ac, &state, pending)) | |
| 70 | 70 | require.Equal(t, pending.cache, ac.pipelineCache) | |
| 71 | 71 | frame := <-sends | |
| 72 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 72 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 73 | 73 | require.NoError(t, err) | |
| 74 | 74 | require.Contains(t, string(output.Data), "next", "the retry must emit state retained after the failed emission") | |
| 75 | 75 | }) | |
M internal/usecase/daemon/render_pipeline_test.go +10 -10
| @@ -14,7 +14,7 @@ import ( | |||
| 14 | 14 | vt "github.com/bnema/vev-vt" | |
| 15 | 15 | renderer "github.com/bnema/vev-vt/ansi" | |
| 16 | 16 | "github.com/bnema/vev/internal/domain" | |
| 17 | - | "github.com/bnema/vev/internal/ports" | |
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 18 | 18 | "github.com/bnema/vev/internal/testutil/replaytest" | |
| 19 | 19 | scopy "github.com/bnema/vev/internal/usecase/copy" | |
| 20 | 20 | "github.com/bnema/vev/internal/usecase/layout" | |
| @@ -32,11 +32,11 @@ import ( | |||
| 32 | 32 | // assertions must not depend on any adapter's framing implementation. | |
| 33 | 33 | type scriptedReplayTransport struct { | |
| 34 | 34 | t *testing.T | |
| 35 | - | frames []ports.Frame | |
| 35 | + | frames []wire.Frame | |
| 36 | 36 | next int | |
| 37 | 37 | } | |
| 38 | 38 | ||
| 39 | - | func (s *scriptedReplayTransport) Send(got ports.Frame) error { | |
| 39 | + | func (s *scriptedReplayTransport) Send(got wire.Frame) error { | |
| 40 | 40 | s.t.Helper() | |
| 41 | 41 | if s.next >= len(s.frames) { | |
| 42 | 42 | s.t.Errorf("unexpected frame %#v", got) | |
| @@ -48,8 +48,8 @@ func (s *scriptedReplayTransport) Send(got ports.Frame) error { | |||
| 48 | 48 | require.Equal(s.t, want.Payload, got.Payload) | |
| 49 | 49 | return nil | |
| 50 | 50 | } | |
| 51 | - | func (*scriptedReplayTransport) Recv() (ports.Frame, error) { return ports.Frame{}, io.EOF } | |
| 52 | - | func (*scriptedReplayTransport) Close() error { return nil } | |
| 51 | + | func (*scriptedReplayTransport) Recv() (wire.Frame, error) { return wire.Frame{}, io.EOF } | |
| 52 | + | func (*scriptedReplayTransport) Close() error { return nil } | |
| 53 | 53 | ||
| 54 | 54 | func TestTransportReplayFinalShadowAndTerminalBytes(t *testing.T) { | |
| 55 | 55 | frames := replaytest.Transcript() | |
| @@ -57,7 +57,7 @@ func TestTransportReplayFinalShadowAndTerminalBytes(t *testing.T) { | |||
| 57 | 57 | terminal := vt.NewScreen(8, 3) | |
| 58 | 58 | for _, frame := range frames { | |
| 59 | 59 | require.NoError(t, transport.Send(frame)) | |
| 60 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 60 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 61 | 61 | require.NoError(t, err) | |
| 62 | 62 | require.Equal(t, frame.Payload, mustMarshalOutput(output), "output payload must remain byte exact") | |
| 63 | 63 | terminal.Write(output.Data) | |
| @@ -253,7 +253,7 @@ func TestEmitFrameFailedSendDoesNotPublishCursorOrOutputState(t *testing.T) { | |||
| 253 | 253 | require.True(t, d.emitFrame(sess, ac, &state, composed)) | |
| 254 | 254 | require.Equal(t, cursorOut{valid: true, row: 3, col: 4, style: 2, hasStyle: true}, ac.output.lastCursor) | |
| 255 | 255 | require.Equal(t, uint64(1), ac.output.next) | |
| 256 | - | out, err := ports.UnmarshalOutput((<-sends).Payload) | |
| 256 | + | out, err := wire.UnmarshalOutput((<-sends).Payload) | |
| 257 | 257 | require.NoError(t, err) | |
| 258 | 258 | require.Zero(t, out.Base) | |
| 259 | 259 | require.Equal(t, uint64(1), out.New) | |
| @@ -332,12 +332,12 @@ func TestComposeEmitExactReplayTiledFloatingBarsOverlayAndCursor(t *testing.T) { | |||
| 332 | 332 | stream := newOutputStateStream() | |
| 333 | 333 | prepared, err := stream.prepareFrame(nil, &state, composed.frame, composed.damage, composed.reset, composed.cursor) | |
| 334 | 334 | require.NoError(t, err) | |
| 335 | - | var outputFrame ports.Frame | |
| 336 | - | require.NoError(t, prepared.send(0, func(frame ports.Frame) error { | |
| 335 | + | var outputFrame wire.Frame | |
| 336 | + | require.NoError(t, prepared.send(0, func(frame wire.Frame) error { | |
| 337 | 337 | outputFrame = frame | |
| 338 | 338 | return nil | |
| 339 | 339 | })) | |
| 340 | - | output, err := ports.UnmarshalOutput(outputFrame.Payload) | |
| 340 | + | output, err := wire.UnmarshalOutput(outputFrame.Payload) | |
| 341 | 341 | require.NoError(t, err) | |
| 342 | 342 | terminalBytes := output.Data | |
| 343 | 343 | require.Equal(t, "\x1b[1;1H\x1b[0;7m tab \x1b[0m R\x1b[2;1HAAAAAAAAAAAA\x1b[3;1HBBB┌─fl─┐BBB\x1b[4;1H───Prompt───\x1b[5;1HPROMPT\x1b[K\x1b[B\x1b[2K\x1b[7;1H\x1b[0;7m sess \x1b[0m B\x1b[0m\x1b[?25l", string(terminalBytes)) | |
M internal/usecase/daemon/render_test.go +26 -26
| @@ -19,9 +19,9 @@ import ( | |||
| 19 | 19 | vt "github.com/bnema/vev-vt" | |
| 20 | 20 | renderer "github.com/bnema/vev-vt/ansi" | |
| 21 | 21 | "github.com/bnema/vev/internal/domain" | |
| 22 | - | "github.com/bnema/vev/internal/ports" | |
| 23 | 22 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 24 | 23 | "github.com/bnema/vev/internal/protocol" | |
| 24 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 25 | 25 | scopy "github.com/bnema/vev/internal/usecase/copy" | |
| 26 | 26 | "github.com/bnema/vev/internal/usecase/layout" | |
| 27 | 27 | themeui "github.com/bnema/vev/internal/usecase/theme" | |
| @@ -38,14 +38,14 @@ func TestPaletteBackdropDimsSimultaneousCopyMode(t *testing.T) { | |||
| 38 | 38 | pane.screen.Write([]byte("\x1b[38;2;180;90;30mX")) | |
| 39 | 39 | ||
| 40 | 40 | d.enterCopyMode(sess, ac) | |
| 41 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 41 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 42 | 42 | undimmed := client.Frame.At(0, 1) | |
| 43 | 43 | require.Equal(t, 'X', undimmed.Rune, "fixture must address copy-mode pane content") | |
| 44 | 44 | copyBar := append([]renderer.Cell(nil), client.Frame.Row(client.Frame.Height-1)...) | |
| 45 | 45 | require.Contains(t, rowText(copyBar), "[SCROLL]", "fixture must capture the copy status bar") | |
| 46 | 46 | ||
| 47 | 47 | d.enterPalette(sess, ac) | |
| 48 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 48 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 49 | 49 | dimmed := client.Frame.At(0, 1) | |
| 50 | 50 | require.Equal(t, undimmed.Rune, dimmed.Rune, "palette backdrop must preserve copy content") | |
| 51 | 51 | require.Equal(t, themeui.NewDimmer(theme).Dim(undimmed.Style), dimmed.Style, "palette backdrop must dim the composed copy frame") | |
| @@ -84,8 +84,8 @@ func TestFirstPaintRetainedFloatingPaneEmitsOneReset(t *testing.T) { | |||
| 84 | 84 | ||
| 85 | 85 | d.firstPaint(sess, ac) | |
| 86 | 86 | ||
| 87 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | |
| 88 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 87 | + | frame := awaitFrame(t, sends, wire.MsgOutput) | |
| 88 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 89 | 89 | require.NoError(t, err) | |
| 90 | 90 | require.Zero(t, output.Base, "first paint must be a mandatory reset") | |
| 91 | 91 | select { | |
| @@ -107,13 +107,13 @@ func TestPaletteBackdropDimsSimultaneousPicker(t *testing.T) { | |||
| 107 | 107 | pane.screen.Write([]byte("X")) | |
| 108 | 108 | ||
| 109 | 109 | d.enterPicker(sess, ac) | |
| 110 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 110 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 111 | 111 | pickerTitle := client.Frame.At(31, 2) | |
| 112 | 112 | require.Equal(t, 'S', pickerTitle.Rune, "fixture must address the picker title") | |
| 113 | 113 | undimmedPane := client.Frame.At(0, 1) | |
| 114 | 114 | ||
| 115 | 115 | d.enterPalette(sess, ac) | |
| 116 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 116 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 117 | 117 | dimmedPickerTitle := pickerTitle | |
| 118 | 118 | dimmedPickerTitle.Style = themeui.NewDimmer(backdropTheme()).Dim(pickerTitle.Style) | |
| 119 | 119 | require.Equal(t, dimmedPickerTitle, client.Frame.At(31, 2), "the lower-priority picker must be part of the palette backdrop") | |
| @@ -129,13 +129,13 @@ func TestPaletteBackdropProductionRenderAndDismissal(t *testing.T) { | |||
| 129 | 129 | pane := sess.tabs[0].focusedPane() | |
| 130 | 130 | pane.screen.Write([]byte("X")) | |
| 131 | 131 | d.paint(sess, ac, true, nil) | |
| 132 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 132 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 133 | 133 | undimmed := client.Frame.At(0, 1) | |
| 134 | 134 | topBar := client.Frame.At(0, 0) | |
| 135 | 135 | bottomBar := client.Frame.At(0, 24) | |
| 136 | 136 | ||
| 137 | 137 | d.handleInput(sess, ac, []byte("\x1b ")) | |
| 138 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 138 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 139 | 139 | dimmed := client.Frame.At(0, 1) | |
| 140 | 140 | require.Equal(t, 'X', dimmed.Rune) | |
| 141 | 141 | require.Equal(t, themeui.NewDimmer(backdropTheme()).Dim(undimmed.Style), dimmed.Style, "open palette must use the theme dim style") | |
| @@ -147,7 +147,7 @@ func TestPaletteBackdropProductionRenderAndDismissal(t *testing.T) { | |||
| 147 | 147 | require.Equal(t, dimmedBottomBar, client.Frame.At(0, 24), "bottom chrome is part of the complete backdrop") | |
| 148 | 148 | ||
| 149 | 149 | d.handleInput(sess, ac, []byte("\x1b")) | |
| 150 | - | mustApplyOutput(t, client, awaitFrame(t, sends, ports.MsgOutput)) | |
| 150 | + | mustApplyOutput(t, client, awaitFrame(t, sends, wire.MsgOutput)) | |
| 151 | 151 | require.Equal(t, undimmed, client.Frame.At(0, 1), "full redraw restores pane rune and style") | |
| 152 | 152 | require.Equal(t, topBar, client.Frame.At(0, 0)) | |
| 153 | 153 | require.Equal(t, bottomBar, client.Frame.At(0, 24)) | |
| @@ -189,10 +189,10 @@ func awaitPTYReadProcessed(t *testing.T, processed <-chan struct{}) { | |||
| 189 | 189 | <-processed | |
| 190 | 190 | } | |
| 191 | 191 | ||
| 192 | - | func awaitOutputFrameWithoutSleep(t *testing.T, sends <-chan ports.Frame) ports.Frame { | |
| 192 | + | func awaitOutputFrameWithoutSleep(t *testing.T, sends <-chan wire.Frame) wire.Frame { | |
| 193 | 193 | t.Helper() | |
| 194 | 194 | frame := <-sends | |
| 195 | - | require.Equal(t, ports.MsgOutput, frame.Type) | |
| 195 | + | require.Equal(t, wire.MsgOutput, frame.Type) | |
| 196 | 196 | return frame | |
| 197 | 197 | } | |
| 198 | 198 | ||
| @@ -332,7 +332,7 @@ func TestPTYReaderSyncVisibilityTransitions(t *testing.T) { | |||
| 332 | 332 | awaitPTYReadProcessed(t, inactiveProcessed) | |
| 333 | 333 | fireCoordinatorTimer(t, rc, drainCoordinatorTimers(clock), urgentRenderDeadline) | |
| 334 | 334 | frame := awaitOutputFrameWithoutSleep(t, sends) | |
| 335 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 335 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 336 | 336 | require.NoError(t, err) | |
| 337 | 337 | require.Contains(t, string(output.Data), "partial complete") | |
| 338 | 338 | requireNoCoordinatorOutputFrame(t, sends) | |
| @@ -365,7 +365,7 @@ func TestPTYReaderSyncVisibilityTransitions(t *testing.T) { | |||
| 365 | 365 | awaitPTYReadProcessed(t, newProcessed) | |
| 366 | 366 | fireCoordinatorTimer(t, rc, drainCoordinatorTimers(clock), minOutputRenderDeadline) | |
| 367 | 367 | frame := awaitOutputFrameWithoutSleep(t, sends) | |
| 368 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 368 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 369 | 369 | require.NoError(t, err) | |
| 370 | 370 | require.Contains(t, string(output.Data), "newly active") | |
| 371 | 371 | require.NotContains(t, string(output.Data), "old partial") | |
| @@ -515,7 +515,7 @@ func TestPaneRenderableActiveAttachmentDoesNotScanPickerPreviews(t *testing.T) { | |||
| 515 | 515 | } | |
| 516 | 516 | ||
| 517 | 517 | func TestNonRenderablePaneDamageRemainsPendingForCapture(t *testing.T) { | |
| 518 | - | newFixture := func(t *testing.T) (*Daemon, *session, *tab, *pane, chan ports.Frame) { | |
| 518 | + | newFixture := func(t *testing.T) (*Daemon, *session, *tab, *pane, chan wire.Frame) { | |
| 519 | 519 | t.Helper() | |
| 520 | 520 | p, release := newBlockingPTY(t) | |
| 521 | 521 | t.Cleanup(release) | |
| @@ -589,8 +589,8 @@ func TestAltXClosesFinalTabAndDetaches(t *testing.T) { | |||
| 589 | 589 | d.handleInput(sess, ac, []byte("CLT\r")) | |
| 590 | 590 | ||
| 591 | 591 | require.Equal(t, 0, sessionCount(d)) | |
| 592 | - | f := awaitFrame(t, sends, ports.MsgDetached) | |
| 593 | - | det, err := ports.UnmarshalDetached(f.Payload) | |
| 592 | + | f := awaitFrame(t, sends, wire.MsgDetached) | |
| 593 | + | det, err := wire.UnmarshalDetached(f.Payload) | |
| 594 | 594 | require.NoError(t, err) | |
| 595 | 595 | require.Equal(t, protocol.ReasonSessionKilled, det.Reason) | |
| 596 | 596 | } | |
| @@ -610,8 +610,8 @@ func TestPTYEOFClosesActiveNonFinalTabAndRepaintsRemaining(t *testing.T) { | |||
| 610 | 610 | require.Eventually(t, func() bool { return tabCount(sess) == 1 }, 2*time.Second, 5*time.Millisecond) | |
| 611 | 611 | require.Equal(t, 1, sessionCount(d)) | |
| 612 | 612 | require.Equal(t, 0, testAttachmentTabIndex(sess)) | |
| 613 | - | f := awaitFrame(t, sends, ports.MsgOutput) | |
| 614 | - | out, err := ports.UnmarshalOutput(f.Payload) | |
| 613 | + | f := awaitFrame(t, sends, wire.MsgOutput) | |
| 614 | + | out, err := wire.UnmarshalOutput(f.Payload) | |
| 615 | 615 | require.NoError(t, err) | |
| 616 | 616 | data := string(out.Data) | |
| 617 | 617 | require.Contains(t, data, "remaining") | |
| @@ -636,8 +636,8 @@ func TestPTYEOFClosesInactiveNonFinalTabAndRepaintsStatus(t *testing.T) { | |||
| 636 | 636 | require.Eventually(t, func() bool { return tabCount(sess) == 1 }, 2*time.Second, 5*time.Millisecond) | |
| 637 | 637 | require.Equal(t, 1, sessionCount(d)) | |
| 638 | 638 | require.Equal(t, 0, testAttachmentTabIndex(sess)) | |
| 639 | - | f := awaitFrame(t, sends, ports.MsgOutput) | |
| 640 | - | out, err := ports.UnmarshalOutput(f.Payload) | |
| 639 | + | f := awaitFrame(t, sends, wire.MsgOutput) | |
| 640 | + | out, err := wire.UnmarshalOutput(f.Payload) | |
| 641 | 641 | require.NoError(t, err) | |
| 642 | 642 | data := string(out.Data) | |
| 643 | 643 | require.Contains(t, data, "active") | |
| @@ -655,8 +655,8 @@ func TestPTYEOFFinalTabKillsSessionAndDetaches(t *testing.T) { | |||
| 655 | 655 | releases[0]() | |
| 656 | 656 | ||
| 657 | 657 | require.Eventually(t, func() bool { return sessionCount(d) == 0 }, 2*time.Second, 5*time.Millisecond) | |
| 658 | - | f := awaitFrame(t, sends, ports.MsgDetached) | |
| 659 | - | det, err := ports.UnmarshalDetached(f.Payload) | |
| 658 | + | f := awaitFrame(t, sends, wire.MsgDetached) | |
| 659 | + | det, err := wire.UnmarshalDetached(f.Payload) | |
| 660 | 660 | require.NoError(t, err) | |
| 661 | 661 | require.Equal(t, protocol.ReasonSessionKilled, det.Reason) | |
| 662 | 662 | ||
| @@ -933,8 +933,8 @@ func TestResizeOrdersPTYBeforeScreen(t *testing.T) { | |||
| 933 | 933 | var gotOutput atomic.Bool | |
| 934 | 934 | tr := portsmocks.NewMockTransport(t) | |
| 935 | 935 | tr.EXPECT().Close().Return(nil).Maybe() | |
| 936 | - | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f ports.Frame) error { | |
| 937 | - | if f.Type == ports.MsgOutput { | |
| 936 | + | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f wire.Frame) error { | |
| 937 | + | if f.Type == wire.MsgOutput { | |
| 938 | 938 | gotOutput.Store(true) | |
| 939 | 939 | } | |
| 940 | 940 | return nil | |
| @@ -1053,7 +1053,7 @@ func TestPTYKittyIcatDetectionGetsResponsesWrittenBackToPTY(t *testing.T) { | |||
| 1053 | 1053 | } | |
| 1054 | 1054 | select { | |
| 1055 | 1055 | case f := <-sends: | |
| 1056 | - | require.NotEqual(t, ports.MsgOutput, f.Type) | |
| 1056 | + | require.NotEqual(t, wire.MsgOutput, f.Type) | |
| 1057 | 1057 | default: | |
| 1058 | 1058 | } | |
| 1059 | 1059 | } | |
M internal/usecase/daemon/resume_test.go +24 -23
| @@ -16,23 +16,24 @@ import ( | |||
| 16 | 16 | "github.com/bnema/vev/internal/ports" | |
| 17 | 17 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 18 | 18 | "github.com/bnema/vev/internal/protocol" | |
| 19 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 19 | 20 | "github.com/bnema/vev/internal/usecase/layout" | |
| 20 | 21 | ) | |
| 21 | 22 | ||
| 22 | 23 | type closeTrackingTransport struct { | |
| 23 | 24 | mu sync.Mutex | |
| 24 | 25 | closed bool | |
| 25 | - | sends []ports.Frame | |
| 26 | + | sends []wire.Frame | |
| 26 | 27 | } | |
| 27 | 28 | ||
| 28 | - | func (t *closeTrackingTransport) Send(f ports.Frame) error { | |
| 29 | + | func (t *closeTrackingTransport) Send(f wire.Frame) error { | |
| 29 | 30 | t.mu.Lock() | |
| 30 | 31 | defer t.mu.Unlock() | |
| 31 | 32 | t.sends = append(t.sends, f) | |
| 32 | 33 | return nil | |
| 33 | 34 | } | |
| 34 | - | func (t *closeTrackingTransport) Recv() (ports.Frame, error) { | |
| 35 | - | return ports.Frame{}, errors.New("closed") | |
| 35 | + | func (t *closeTrackingTransport) Recv() (wire.Frame, error) { | |
| 36 | + | return wire.Frame{}, errors.New("closed") | |
| 36 | 37 | } | |
| 37 | 38 | func (t *closeTrackingTransport) Close() error { | |
| 38 | 39 | t.mu.Lock() | |
| @@ -46,10 +47,10 @@ func (t *closeTrackingTransport) Closed() bool { | |||
| 46 | 47 | return t.closed | |
| 47 | 48 | } | |
| 48 | 49 | ||
| 49 | - | func (t *closeTrackingTransport) Sends() []ports.Frame { | |
| 50 | + | func (t *closeTrackingTransport) Sends() []wire.Frame { | |
| 50 | 51 | t.mu.Lock() | |
| 51 | 52 | defer t.mu.Unlock() | |
| 52 | - | return append([]ports.Frame(nil), t.sends...) | |
| 53 | + | return append([]wire.Frame(nil), t.sends...) | |
| 53 | 54 | } | |
| 54 | 55 | ||
| 55 | 56 | type closeCountingBlockedTransport struct { | |
| @@ -63,13 +64,13 @@ func newCloseCountingBlockedTransport() *closeCountingBlockedTransport { | |||
| 63 | 64 | return &closeCountingBlockedTransport{closed: make(chan struct{})} | |
| 64 | 65 | } | |
| 65 | 66 | ||
| 66 | - | func (t *closeCountingBlockedTransport) Send(ports.Frame) error { | |
| 67 | + | func (t *closeCountingBlockedTransport) Send(wire.Frame) error { | |
| 67 | 68 | <-t.closed | |
| 68 | 69 | return errors.New("closed") | |
| 69 | 70 | } | |
| 70 | 71 | ||
| 71 | - | func (t *closeCountingBlockedTransport) Recv() (ports.Frame, error) { | |
| 72 | - | return ports.Frame{}, errors.New("closed") | |
| 72 | + | func (t *closeCountingBlockedTransport) Recv() (wire.Frame, error) { | |
| 73 | + | return wire.Frame{}, errors.New("closed") | |
| 73 | 74 | } | |
| 74 | 75 | ||
| 75 | 76 | func (t *closeCountingBlockedTransport) Close() error { | |
| @@ -326,14 +327,14 @@ func TestHandleHelloResumeDefersFreshOutputUntilWelcome(t *testing.T) { | |||
| 326 | 327 | done := make(chan struct{}) | |
| 327 | 328 | resumeHello := helloResumeCapable(protocol.IntentResume, sess.name, token) | |
| 328 | 329 | go func() { | |
| 329 | - | d.handleHello(tr.tr, ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(resumeHello)}) | |
| 330 | + | d.handleHello(tr.tr, wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(resumeHello)}) | |
| 330 | 331 | close(done) | |
| 331 | 332 | }() | |
| 332 | 333 | ||
| 333 | 334 | <-tr.welcomeEntered | |
| 334 | 335 | handshakeTimer := awaitHandshakeTimer(t, clock) | |
| 335 | 336 | welcome := <-tr.sends | |
| 336 | - | require.Equal(t, ports.MsgWelcome, welcome.Type) | |
| 337 | + | require.Equal(t, wire.MsgWelcome, welcome.Type) | |
| 337 | 338 | sess.mu.Lock() | |
| 338 | 339 | resumed := sess.snapshotAttachmentsLocked()[0] | |
| 339 | 340 | sess.mu.Unlock() | |
| @@ -351,8 +352,8 @@ func TestHandleHelloResumeDefersFreshOutputUntilWelcome(t *testing.T) { | |||
| 351 | 352 | requireNoCoordinatorOutputFrame(t, tr.sends) | |
| 352 | 353 | ||
| 353 | 354 | tr.release() | |
| 354 | - | output := awaitFrame(t, tr.sends, ports.MsgOutput) | |
| 355 | - | first, err := ports.UnmarshalOutput(output.Payload) | |
| 355 | + | output := awaitFrame(t, tr.sends, wire.MsgOutput) | |
| 356 | + | first, err := wire.UnmarshalOutput(output.Payload) | |
| 356 | 357 | require.NoError(t, err) | |
| 357 | 358 | require.Zero(t, first.Base) | |
| 358 | 359 | tr.finish() | |
| @@ -1094,7 +1095,7 @@ func TestOutputAckLagAloneDoesNotForceFullStateRepaint(t *testing.T) { | |||
| 1094 | 1095 | ||
| 1095 | 1096 | f := outputStateFrame(ac.output, []byte("incremental while reliable backlog drains"), reset, 0) | |
| 1096 | 1097 | ac.sendMu.Unlock() | |
| 1097 | - | out, err := ports.UnmarshalOutput(f.Payload) | |
| 1098 | + | out, err := wire.UnmarshalOutput(f.Payload) | |
| 1098 | 1099 | require.NoError(t, err) | |
| 1099 | 1100 | require.Equal(t, uint64(5), out.Base, "output should remain incremental unless an explicit reset is requested") | |
| 1100 | 1101 | require.Equal(t, uint64(6), out.New) | |
| @@ -1104,7 +1105,7 @@ func TestOutputAckLagAloneDoesNotForceFullStateRepaint(t *testing.T) { | |||
| 1104 | 1105 | require.True(t, reset, "explicit reset should still force full repaint") | |
| 1105 | 1106 | full := outputStateFrame(ac.output, []byte("explicit full repaint"), reset, 0) | |
| 1106 | 1107 | ac.sendMu.Unlock() | |
| 1107 | - | fullOut, err := ports.UnmarshalOutput(full.Payload) | |
| 1108 | + | fullOut, err := wire.UnmarshalOutput(full.Payload) | |
| 1108 | 1109 | require.NoError(t, err) | |
| 1109 | 1110 | require.Equal(t, uint64(0), fullOut.Base) | |
| 1110 | 1111 | require.Equal(t, uint64(7), fullOut.New) | |
| @@ -1185,9 +1186,9 @@ func TestResumeRebasesFullOutputWindowBeforeFirstPaint(t *testing.T) { | |||
| 1185 | 1186 | require.Same(t, ac, resumedAC) | |
| 1186 | 1187 | d.paint(resumedSess, resumedAC, true, nil) | |
| 1187 | 1188 | ||
| 1188 | - | sends := testFramesOfType(newTr.Sends(), ports.MsgOutput) | |
| 1189 | + | sends := testFramesOfType(newTr.Sends(), wire.MsgOutput) | |
| 1189 | 1190 | require.Len(t, sends, 1) | |
| 1190 | - | first, err := ports.UnmarshalOutput(sends[0].Payload) | |
| 1191 | + | first, err := wire.UnmarshalOutput(sends[0].Payload) | |
| 1191 | 1192 | require.NoError(t, err) | |
| 1192 | 1193 | require.Zero(t, first.Base) | |
| 1193 | 1194 | require.Equal(t, uint64(1), first.New) | |
| @@ -1195,9 +1196,9 @@ func TestResumeRebasesFullOutputWindowBeforeFirstPaint(t *testing.T) { | |||
| 1195 | 1196 | ||
| 1196 | 1197 | resumedSess.tabs[0].focusedPane().screen.Write([]byte("A")) | |
| 1197 | 1198 | d.paint(resumedSess, resumedAC, false, nil) | |
| 1198 | - | sends = testFramesOfType(newTr.Sends(), ports.MsgOutput) | |
| 1199 | + | sends = testFramesOfType(newTr.Sends(), wire.MsgOutput) | |
| 1199 | 1200 | require.Len(t, sends, 2) | |
| 1200 | - | second, err := ports.UnmarshalOutput(sends[1].Payload) | |
| 1201 | + | second, err := wire.UnmarshalOutput(sends[1].Payload) | |
| 1201 | 1202 | require.NoError(t, err) | |
| 1202 | 1203 | require.Equal(t, first.New, second.Base) | |
| 1203 | 1204 | } | |
| @@ -1245,9 +1246,9 @@ func TestParkingReleasesPaneCapturesBeforeHeadlessCloseAndResume(t *testing.T) { | |||
| 1245 | 1246 | require.True(t, resumedSess.renderCoordinator().markAttachmentReady(resumedSess.renderCoordinator().attachmentLease(resumedAC))) | |
| 1246 | 1247 | d.firstPaint(resumedSess, resumedAC) | |
| 1247 | 1248 | ||
| 1248 | - | sends := testFramesOfType(newTransport.Sends(), ports.MsgOutput) | |
| 1249 | + | sends := testFramesOfType(newTransport.Sends(), wire.MsgOutput) | |
| 1249 | 1250 | require.Len(t, sends, 1) | |
| 1250 | - | output, err := ports.UnmarshalOutput(sends[0].Payload) | |
| 1251 | + | output, err := wire.UnmarshalOutput(sends[0].Payload) | |
| 1251 | 1252 | require.NoError(t, err) | |
| 1252 | 1253 | require.Zero(t, output.Base, "resume must start with a complete frame") | |
| 1253 | 1254 | terminal := vt.NewScreen(resumedAC.size.Cols, resumedAC.size.Rows) | |
| @@ -1543,9 +1544,9 @@ func TestRawTerminalSideEffectsAreOutputStateNeutral(t *testing.T) { | |||
| 1543 | 1544 | ||
| 1544 | 1545 | sends := tr.Sends() | |
| 1545 | 1546 | require.Len(t, sends, 2) | |
| 1546 | - | first, err := ports.UnmarshalOutput(sends[0].Payload) | |
| 1547 | + | first, err := wire.UnmarshalOutput(sends[0].Payload) | |
| 1547 | 1548 | require.NoError(t, err) | |
| 1548 | - | second, err := ports.UnmarshalOutput(sends[1].Payload) | |
| 1549 | + | second, err := wire.UnmarshalOutput(sends[1].Payload) | |
| 1549 | 1550 | require.NoError(t, err) | |
| 1550 | 1551 | require.Zero(t, first.Base) | |
| 1551 | 1552 | require.Zero(t, first.New) | |
M internal/usecase/daemon/route_position_test.go +3 -3
| @@ -7,8 +7,8 @@ import ( | |||
| 7 | 7 | "github.com/stretchr/testify/require" | |
| 8 | 8 | ||
| 9 | 9 | "github.com/bnema/vev/internal/domain" | |
| 10 | - | "github.com/bnema/vev/internal/ports" | |
| 11 | 10 | "github.com/bnema/vev/internal/protocol" | |
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 12 | 12 | ) | |
| 13 | 13 | ||
| 14 | 14 | func TestRouteAppliesPreferredTabPerAttachment(t *testing.T) { | |
| @@ -96,10 +96,10 @@ func TestPaintPublishesChangedAttachmentRoutePosition(t *testing.T) { | |||
| 96 | 96 | ||
| 97 | 97 | var positions []protocol.RoutePosition | |
| 98 | 98 | for _, frame := range tr.Sends() { | |
| 99 | - | if frame.Type != ports.MsgRoutePosition { | |
| 99 | + | if frame.Type != wire.MsgRoutePosition { | |
| 100 | 100 | continue | |
| 101 | 101 | } | |
| 102 | - | position, err := ports.UnmarshalRoutePosition(frame.Payload) | |
| 102 | + | position, err := wire.UnmarshalRoutePosition(frame.Payload) | |
| 103 | 103 | require.NoError(t, err) | |
| 104 | 104 | positions = append(positions, position) | |
| 105 | 105 | } | |
M internal/usecase/daemon/same_peer_switch.go +3 -3
| @@ -2,8 +2,8 @@ package daemon | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "github.com/bnema/vev/internal/domain" | |
| 5 | - | "github.com/bnema/vev/internal/ports" | |
| 6 | 5 | "github.com/bnema/vev/internal/protocol" | |
| 6 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 7 | 7 | ) | |
| 8 | 8 | ||
| 9 | 9 | func (ac *attachedClient) offerSamePeerTarget(target protocol.ExactSessionTarget) { | |
| @@ -122,11 +122,11 @@ func (d *Daemon) sendSamePeerSwitchFailure(effect *attachmentEffect, requestID u | |||
| 122 | 122 | } | |
| 123 | 123 | defer sender.End() | |
| 124 | 124 | } | |
| 125 | - | payload, err := ports.MarshalSamePeerSwitchFailure(protocol.SamePeerSwitchFailure{RequestID: requestID, Code: code}) | |
| 125 | + | payload, err := wire.MarshalSamePeerSwitchFailure(protocol.SamePeerSwitchFailure{RequestID: requestID, Code: code}) | |
| 126 | 126 | if err != nil { | |
| 127 | 127 | return | |
| 128 | 128 | } | |
| 129 | - | if err := sender.sendControl(ports.Frame{Type: ports.MsgSamePeerSwitchFailure, Payload: payload}); err != nil { | |
| 129 | + | if err := sender.sendControl(wire.Frame{Type: wire.MsgSamePeerSwitchFailure, Payload: payload}); err != nil { | |
| 130 | 130 | d.detachOnAttachmentSendError(sender.capability(), sender.transport.transport) | |
| 131 | 131 | } | |
| 132 | 132 | } | |
M internal/usecase/daemon/same_peer_switch_test.go +10 -10
| @@ -6,8 +6,8 @@ import ( | |||
| 6 | 6 | "github.com/stretchr/testify/require" | |
| 7 | 7 | ||
| 8 | 8 | "github.com/bnema/vev/internal/domain" | |
| 9 | - | "github.com/bnema/vev/internal/ports" | |
| 10 | 9 | "github.com/bnema/vev/internal/protocol" | |
| 10 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 11 | 11 | ) | |
| 12 | 12 | ||
| 13 | 13 | func TestPaletteSessionSelectionCompletesSamePeerSwitch(t *testing.T) { | |
| @@ -31,10 +31,10 @@ func TestPaletteSessionSelectionCompletesSamePeerSwitch(t *testing.T) { | |||
| 31 | 31 | ||
| 32 | 32 | token := beginRecentRoutePaletteEffect(t, d, source, ac) | |
| 33 | 33 | d.handleInputForAttachment(token, []byte("\x1b ")) | |
| 34 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 34 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 35 | 35 | d.handleInputForAttachment(token, []byte("target\r")) | |
| 36 | - | targetFrame := awaitFrame(t, sends, ports.MsgAttachTarget) | |
| 37 | - | attachTarget, err := ports.UnmarshalAttachTarget(targetFrame.Payload) | |
| 36 | + | targetFrame := awaitFrame(t, sends, wire.MsgAttachTarget) | |
| 37 | + | attachTarget, err := wire.UnmarshalAttachTarget(targetFrame.Payload) | |
| 38 | 38 | require.NoError(t, err) | |
| 39 | 39 | require.Equal(t, &protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "target"}, attachTarget.ExactTarget) | |
| 40 | 40 | ||
| @@ -43,8 +43,8 @@ func TestPaletteSessionSelectionCompletesSamePeerSwitch(t *testing.T) { | |||
| 43 | 43 | }) | |
| 44 | 44 | ||
| 45 | 45 | require.Same(t, target, ac.currentAttachmentSession()) | |
| 46 | - | identityFrame := awaitFrame(t, sends, ports.MsgCommittedRouteIdentity) | |
| 47 | - | identity, err := ports.UnmarshalCommittedRouteIdentity(identityFrame.Payload) | |
| 46 | + | identityFrame := awaitFrame(t, sends, wire.MsgCommittedRouteIdentity) | |
| 47 | + | identity, err := wire.UnmarshalCommittedRouteIdentity(identityFrame.Payload) | |
| 48 | 48 | require.NoError(t, err) | |
| 49 | 49 | require.Equal(t, attachTarget.ExactTarget, &identity.Target) | |
| 50 | 50 | } | |
| @@ -86,8 +86,8 @@ func TestSamePeerSwitchTransitionsExactTargetAndPreferredTab(t *testing.T) { | |||
| 86 | 86 | ||
| 87 | 87 | require.Same(t, target, ac.currentAttachmentSession()) | |
| 88 | 88 | require.Equal(t, domain.TabStableID(target.tabs[1].stableID), ac.viewSnapshot().tabID) | |
| 89 | - | identityFrame := awaitFrame(t, sends, ports.MsgCommittedRouteIdentity) | |
| 90 | - | identity, err := ports.UnmarshalCommittedRouteIdentity(identityFrame.Payload) | |
| 89 | + | identityFrame := awaitFrame(t, sends, wire.MsgCommittedRouteIdentity) | |
| 90 | + | identity, err := wire.UnmarshalCommittedRouteIdentity(identityFrame.Payload) | |
| 91 | 91 | require.NoError(t, err) | |
| 92 | 92 | require.Equal(t, protocol.ExactSessionTarget{LifecycleID: lifecycle, SessionName: "target"}, identity.Target) | |
| 93 | 93 | } | |
| @@ -120,8 +120,8 @@ func TestSamePeerSwitchRejectsStaleTargetWithoutMutation(t *testing.T) { | |||
| 120 | 120 | }) | |
| 121 | 121 | ||
| 122 | 122 | require.Same(t, source, ac.currentAttachmentSession()) | |
| 123 | - | failureFrame := awaitFrame(t, sends, ports.MsgSamePeerSwitchFailure) | |
| 124 | - | failure, err := ports.UnmarshalSamePeerSwitchFailure(failureFrame.Payload) | |
| 123 | + | failureFrame := awaitFrame(t, sends, wire.MsgSamePeerSwitchFailure) | |
| 124 | + | failure, err := wire.UnmarshalSamePeerSwitchFailure(failureFrame.Payload) | |
| 125 | 125 | require.NoError(t, err) | |
| 126 | 126 | require.Equal(t, protocol.SamePeerSwitchFailure{RequestID: 1, Code: protocol.SamePeerSwitchStaleTarget}, failure) | |
| 127 | 127 | } | |
M internal/usecase/daemon/session_back_route_test.go +3 -3
| @@ -3,8 +3,8 @@ package daemon | |||
| 3 | 3 | import ( | |
| 4 | 4 | "testing" | |
| 5 | 5 | ||
| 6 | - | "github.com/bnema/vev/internal/ports" | |
| 7 | 6 | "github.com/bnema/vev/internal/protocol" | |
| 7 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 8 | 8 | "github.com/stretchr/testify/require" | |
| 9 | 9 | ) | |
| 10 | 10 | ||
| @@ -32,11 +32,11 @@ func TestBackSessionUsesClientPreviousRouteAfterSnapshotPublication(t *testing.T | |||
| 32 | 32 | var action protocol.RouteNavigationAction | |
| 33 | 33 | found := false | |
| 34 | 34 | for _, frame := range frames { | |
| 35 | - | if frame.Type != ports.MsgNavigateRecentRoute { | |
| 35 | + | if frame.Type != wire.MsgNavigateRecentRoute { | |
| 36 | 36 | continue | |
| 37 | 37 | } | |
| 38 | 38 | var err error | |
| 39 | - | action, err = ports.UnmarshalRouteNavigationAction(frame.Payload) | |
| 39 | + | action, err = wire.UnmarshalRouteNavigationAction(frame.Payload) | |
| 40 | 40 | require.NoError(t, err) | |
| 41 | 41 | found = true | |
| 42 | 42 | } | |
M internal/usecase/daemon/session_rename_purge_test.go +7 -7
| @@ -6,9 +6,9 @@ import ( | |||
| 6 | 6 | "github.com/stretchr/testify/require" | |
| 7 | 7 | ||
| 8 | 8 | "github.com/bnema/vev/internal/domain" | |
| 9 | - | "github.com/bnema/vev/internal/ports" | |
| 10 | 9 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 11 | 10 | "github.com/bnema/vev/internal/protocol" | |
| 11 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 12 | 12 | ) | |
| 13 | 13 | ||
| 14 | 14 | func TestRenamePublishesCommittedRouteIdentityToAttachedClients(t *testing.T) { | |
| @@ -24,8 +24,8 @@ func TestRenamePublishesCommittedRouteIdentityToAttachedClients(t *testing.T) { | |||
| 24 | 24 | ||
| 25 | 25 | require.NoError(t, d.renameSession(sess, "vps-infra")) | |
| 26 | 26 | ||
| 27 | - | frame := awaitFrame(t, sends, ports.MsgCommittedRouteIdentity) | |
| 28 | - | identity, err := ports.UnmarshalCommittedRouteIdentity(frame.Payload) | |
| 27 | + | frame := awaitFrame(t, sends, wire.MsgCommittedRouteIdentity) | |
| 28 | + | identity, err := wire.UnmarshalCommittedRouteIdentity(frame.Payload) | |
| 29 | 29 | require.NoError(t, err) | |
| 30 | 30 | require.Equal(t, protocol.ExactSessionTarget{ | |
| 31 | 31 | LifecycleID: domain.IncarnationID{1}, | |
| @@ -54,12 +54,12 @@ func TestRenameDefersCommittedRouteIdentityUntilFirstRouteSnapshot(t *testing.T) | |||
| 54 | 54 | ActiveEntry: protocol.RecentRouteEntry{Key: 1, Generation: 1, Target: testRouteTarget("0", 1), Name: "0", Kind: protocol.RouteKindLocal}, | |
| 55 | 55 | Home: activeRef, | |
| 56 | 56 | } | |
| 57 | - | payload, err := ports.MarshalRecentRouteSnapshot(snapshot) | |
| 57 | + | payload, err := wire.MarshalRecentRouteSnapshot(snapshot) | |
| 58 | 58 | require.NoError(t, err) | |
| 59 | - | require.False(t, d.handleAttachmentClientFrame(token, ports.Frame{Type: ports.MsgRecentRouteSnapshot, Payload: payload})) | |
| 59 | + | require.False(t, d.handleAttachmentClientFrame(token, wire.Frame{Type: wire.MsgRecentRouteSnapshot, Payload: payload})) | |
| 60 | 60 | ||
| 61 | - | frame := awaitFrame(t, sends, ports.MsgCommittedRouteIdentity) | |
| 62 | - | identity, err := ports.UnmarshalCommittedRouteIdentity(frame.Payload) | |
| 61 | + | frame := awaitFrame(t, sends, wire.MsgCommittedRouteIdentity) | |
| 62 | + | identity, err := wire.UnmarshalCommittedRouteIdentity(frame.Payload) | |
| 63 | 63 | require.NoError(t, err) | |
| 64 | 64 | require.Equal(t, protocol.ExactSessionTarget{ | |
| 65 | 65 | LifecycleID: domain.IncarnationID{1}, | |
M internal/usecase/daemon/session_test.go +46 -45
| @@ -20,6 +20,7 @@ import ( | |||
| 20 | 20 | "github.com/bnema/vev/internal/ports" | |
| 21 | 21 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 22 | 22 | "github.com/bnema/vev/internal/protocol" | |
| 23 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 23 | 24 | "github.com/bnema/vev/internal/usecase/picker" | |
| 24 | 25 | themeui "github.com/bnema/vev/internal/usecase/theme" | |
| 25 | 26 | ) | |
| @@ -42,12 +43,12 @@ func TestHandshakeEphemeralHappy(t *testing.T) { | |||
| 42 | 43 | var hg sync.WaitGroup | |
| 43 | 44 | hg.Go(func() { d.handleConn(tr) }) | |
| 44 | 45 | ||
| 45 | - | w := awaitFrame(t, sends, ports.MsgWelcome) | |
| 46 | - | welcome, err := ports.UnmarshalWelcome(w.Payload) | |
| 46 | + | w := awaitFrame(t, sends, wire.MsgWelcome) | |
| 47 | + | welcome, err := wire.UnmarshalWelcome(w.Payload) | |
| 47 | 48 | require.NoError(t, err) | |
| 48 | 49 | require.Equal(t, "0", welcome.SessionName) | |
| 49 | 50 | require.True(t, welcome.Ephemeral) | |
| 50 | - | awaitFrame(t, sends, ports.MsgOutput) // guaranteed first paint | |
| 51 | + | awaitFrame(t, sends, wire.MsgOutput) // guaranteed first paint | |
| 51 | 52 | require.Equal(t, 1, sessionCount(d)) | |
| 52 | 53 | ||
| 53 | 54 | releaseConn() | |
| @@ -64,8 +65,8 @@ func TestHandshakeNewHappy(t *testing.T) { | |||
| 64 | 65 | var hg sync.WaitGroup | |
| 65 | 66 | hg.Go(func() { d.handleConn(tr) }) | |
| 66 | 67 | ||
| 67 | - | w := awaitFrame(t, sends, ports.MsgWelcome) | |
| 68 | - | welcome, err := ports.UnmarshalWelcome(w.Payload) | |
| 68 | + | w := awaitFrame(t, sends, wire.MsgWelcome) | |
| 69 | + | welcome, err := wire.UnmarshalWelcome(w.Payload) | |
| 69 | 70 | require.NoError(t, err) | |
| 70 | 71 | require.Equal(t, "work", welcome.SessionName) | |
| 71 | 72 | require.False(t, welcome.Ephemeral) | |
| @@ -84,15 +85,15 @@ func TestHandshakeNewHappy(t *testing.T) { | |||
| 84 | 85 | func TestHandshakeVersionMismatch(t *testing.T) { | |
| 85 | 86 | // No Open expectation: the factory must never be asked to spawn a PTY. | |
| 86 | 87 | d := newTestDaemon(t, portsmocks.NewMockPTYFactory(t), stubClock{}) | |
| 87 | - | bad := ports.Frame{Type: ports.MsgHello, Payload: ports.MarshalHello(protocol.Hello{ | |
| 88 | + | bad := wire.Frame{Type: wire.MsgHello, Payload: wire.MarshalHello(protocol.Hello{ | |
| 88 | 89 | Version: protocol.Version + 99, Intent: protocol.IntentEphemeral, Size: domain.Size{Cols: 80, Rows: 24}, | |
| 89 | 90 | })} | |
| 90 | 91 | tr, sends, _ := newConn(t, bad) | |
| 91 | 92 | ||
| 92 | 93 | d.handleConn(tr) // returns after the rejection; no session, no goroutines | |
| 93 | 94 | ||
| 94 | - | e := awaitFrame(t, sends, ports.MsgError) | |
| 95 | - | em, err := ports.UnmarshalErrorMsg(e.Payload) | |
| 95 | + | e := awaitFrame(t, sends, wire.MsgError) | |
| 96 | + | em, err := wire.UnmarshalErrorMsg(e.Payload) | |
| 96 | 97 | require.NoError(t, err) | |
| 97 | 98 | require.Equal(t, protocol.ErrVersionMismatch, em.Code) | |
| 98 | 99 | require.Equal(t, 0, sessionCount(d)) | |
| @@ -108,11 +109,11 @@ func TestHandshakeOldHelloLayoutReportsVersionMismatch(t *testing.T) { | |||
| 108 | 109 | 0x00, 0x18, | |
| 109 | 110 | 0x00, 0x00, | |
| 110 | 111 | } | |
| 111 | - | tr, sends, _ := newConn(t, ports.Frame{Type: ports.MsgHello, Payload: oldLayout}) | |
| 112 | + | tr, sends, _ := newConn(t, wire.Frame{Type: wire.MsgHello, Payload: oldLayout}) | |
| 112 | 113 | d.handleConn(tr) | |
| 113 | 114 | ||
| 114 | - | e := awaitFrame(t, sends, ports.MsgError) | |
| 115 | - | em, err := ports.UnmarshalErrorMsg(e.Payload) | |
| 115 | + | e := awaitFrame(t, sends, wire.MsgError) | |
| 116 | + | em, err := wire.UnmarshalErrorMsg(e.Payload) | |
| 116 | 117 | require.NoError(t, err) | |
| 117 | 118 | require.Equal(t, protocol.ErrVersionMismatch, em.Code) | |
| 118 | 119 | require.Equal(t, 0, sessionCount(d)) | |
| @@ -126,8 +127,8 @@ func TestHandshakeNameTaken(t *testing.T) { | |||
| 126 | 127 | tr, sends, _ := newConn(t, mustHello(protocol.IntentNew, "work", domain.Size{Cols: 80, Rows: 24})) | |
| 127 | 128 | d.handleConn(tr) | |
| 128 | 129 | ||
| 129 | - | e := awaitFrame(t, sends, ports.MsgError) | |
| 130 | - | em, _ := ports.UnmarshalErrorMsg(e.Payload) | |
| 130 | + | e := awaitFrame(t, sends, wire.MsgError) | |
| 131 | + | em, _ := wire.UnmarshalErrorMsg(e.Payload) | |
| 131 | 132 | require.Equal(t, protocol.ErrNameTaken, em.Code) | |
| 132 | 133 | } | |
| 133 | 134 | ||
| @@ -136,14 +137,14 @@ func TestHandshakeNoSuchSession(t *testing.T) { | |||
| 136 | 137 | tr, sends, _ := newConn(t, mustHello(protocol.IntentAttach, "ghost", domain.Size{Cols: 80, Rows: 24})) | |
| 137 | 138 | d.handleConn(tr) | |
| 138 | 139 | ||
| 139 | - | e := awaitFrame(t, sends, ports.MsgError) | |
| 140 | - | em, _ := ports.UnmarshalErrorMsg(e.Payload) | |
| 140 | + | e := awaitFrame(t, sends, wire.MsgError) | |
| 141 | + | em, _ := wire.UnmarshalErrorMsg(e.Payload) | |
| 141 | 142 | require.Equal(t, protocol.ErrNoSuchSession, em.Code) | |
| 142 | 143 | } | |
| 143 | 144 | ||
| 144 | 145 | func TestKillAllEmptyDaemonSignalsShutdown(t *testing.T) { | |
| 145 | 146 | d := newTestDaemon(t, portsmocks.NewMockPTYFactory(t), stubClock{}) | |
| 146 | - | tr, _, _ := newConn(t, ports.Frame{Type: ports.MsgKill, Payload: ports.MarshalKill(protocol.Kill{All: true})}) | |
| 147 | + | tr, _, _ := newConn(t, wire.Frame{Type: wire.MsgKill, Payload: wire.MarshalKill(protocol.Kill{All: true})}) | |
| 147 | 148 | d.handleConn(tr) | |
| 148 | 149 | ||
| 149 | 150 | select { | |
| @@ -232,8 +233,8 @@ func TestCreateTabClosesPTYIfSessionKilledDuringOpen(t *testing.T) { | |||
| 232 | 233 | tr, sends, releaseConn := newConn(t, mustHello(protocol.IntentNew, "work", domain.Size{Cols: 80, Rows: 24})) | |
| 233 | 234 | var hg sync.WaitGroup | |
| 234 | 235 | hg.Go(func() { d.handleConn(tr) }) | |
| 235 | - | awaitFrame(t, sends, ports.MsgWelcome) | |
| 236 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 236 | + | awaitFrame(t, sends, wire.MsgWelcome) | |
| 237 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 237 | 238 | sess := firstSession(d) | |
| 238 | 239 | require.NotNil(t, sess) | |
| 239 | 240 | ||
| @@ -289,13 +290,13 @@ func TestDetachKeepsEphemeralHeadless(t *testing.T) { | |||
| 289 | 290 | d := newTestDaemon(t, newFactory(t, p), stubClock{}) | |
| 290 | 291 | tr, sends, _ := newConn(t, | |
| 291 | 292 | mustHello(protocol.IntentEphemeral, "", domain.Size{Cols: 80, Rows: 24}), | |
| 292 | - | ports.Frame{Type: ports.MsgDetach, Payload: ports.MarshalDetach(protocol.Detach{})}, | |
| 293 | + | wire.Frame{Type: wire.MsgDetach, Payload: wire.MarshalDetach(protocol.Detach{})}, | |
| 293 | 294 | ) | |
| 294 | 295 | ||
| 295 | 296 | var hg sync.WaitGroup | |
| 296 | 297 | hg.Go(func() { d.handleConn(tr) }) | |
| 297 | - | awaitFrame(t, sends, ports.MsgWelcome) | |
| 298 | - | awaitFrame(t, sends, ports.MsgDetached) | |
| 298 | + | awaitFrame(t, sends, wire.MsgWelcome) | |
| 299 | + | awaitFrame(t, sends, wire.MsgDetached) | |
| 299 | 300 | hg.Wait() | |
| 300 | 301 | ||
| 301 | 302 | require.Equal(t, 1, sessionCount(d), "ephemeral session survives explicit detach") | |
| @@ -338,14 +339,14 @@ func TestDetachKeepsNamed(t *testing.T) { | |||
| 338 | 339 | d := newTestDaemon(t, newFactory(t, p), stubClock{}) | |
| 339 | 340 | tr, sends, _ := newConn(t, | |
| 340 | 341 | mustHello(protocol.IntentNew, "keep", domain.Size{Cols: 80, Rows: 24}), | |
| 341 | - | ports.Frame{Type: ports.MsgDetach, Payload: ports.MarshalDetach(protocol.Detach{})}, | |
| 342 | + | wire.Frame{Type: wire.MsgDetach, Payload: wire.MarshalDetach(protocol.Detach{})}, | |
| 342 | 343 | ) | |
| 343 | 344 | ||
| 344 | 345 | var hg sync.WaitGroup | |
| 345 | 346 | hg.Go(func() { d.handleConn(tr) }) | |
| 346 | - | awaitFrame(t, sends, ports.MsgWelcome) | |
| 347 | - | awaitFrame(t, sends, ports.MsgDetached) // ack for explicit detach | |
| 348 | - | hg.Wait() // handler returns after detach | |
| 347 | + | awaitFrame(t, sends, wire.MsgWelcome) | |
| 348 | + | awaitFrame(t, sends, wire.MsgDetached) // ack for explicit detach | |
| 349 | + | hg.Wait() // handler returns after detach | |
| 349 | 350 | ||
| 350 | 351 | require.Equal(t, 1, sessionCount(d), "named session survives detach") | |
| 351 | 352 | sess := firstSession(d) | |
| @@ -375,8 +376,8 @@ func TestReaderEOFRemovesSessionAndSignalsShutdown(t *testing.T) { | |||
| 375 | 376 | hg.Go(func() { d.handleConn(tr) }) | |
| 376 | 377 | ||
| 377 | 378 | // The client is detached with ReasonSessionKilled when the child exits. | |
| 378 | - | det := awaitFrame(t, sends, ports.MsgDetached) | |
| 379 | - | dm, _ := ports.UnmarshalDetached(det.Payload) | |
| 379 | + | det := awaitFrame(t, sends, wire.MsgDetached) | |
| 380 | + | dm, _ := wire.UnmarshalDetached(det.Payload) | |
| 380 | 381 | require.Equal(t, protocol.ReasonSessionKilled, dm.Reason) | |
| 381 | 382 | ||
| 382 | 383 | select { | |
| @@ -418,8 +419,8 @@ func TestServeReturnsWhenLastSessionExits(t *testing.T) { | |||
| 418 | 419 | served := make(chan error, 1) | |
| 419 | 420 | go func() { served <- d.Serve(context.Background(), l) }() | |
| 420 | 421 | ||
| 421 | - | awaitFrame(t, sends, ports.MsgWelcome) | |
| 422 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 422 | + | awaitFrame(t, sends, wire.MsgWelcome) | |
| 423 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 423 | 424 | ||
| 424 | 425 | // Child exits -> session removed -> registry empties -> Serve returns. | |
| 425 | 426 | releasePTY() | |
| @@ -459,13 +460,13 @@ func TestServeGracefulShutdownOnContextCancel(t *testing.T) { | |||
| 459 | 460 | served := make(chan error, 1) | |
| 460 | 461 | go func() { served <- d.Serve(ctx, l) }() | |
| 461 | 462 | ||
| 462 | - | awaitFrame(t, sends, ports.MsgWelcome) | |
| 463 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 463 | + | awaitFrame(t, sends, wire.MsgWelcome) | |
| 464 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 464 | 465 | ||
| 465 | 466 | cancel() // graceful shutdown | |
| 466 | 467 | ||
| 467 | - | det := awaitFrame(t, sends, ports.MsgDetached) | |
| 468 | - | dm, _ := ports.UnmarshalDetached(det.Payload) | |
| 468 | + | det := awaitFrame(t, sends, wire.MsgDetached) | |
| 469 | + | dm, _ := wire.UnmarshalDetached(det.Payload) | |
| 469 | 470 | require.Equal(t, protocol.ReasonServerShutdown, dm.Reason) | |
| 470 | 471 | ||
| 471 | 472 | select { | |
| @@ -515,11 +516,11 @@ func TestHelloRacingShutdownIsRejected(t *testing.T) { | |||
| 515 | 516 | tr1, sends1, release1 := newConn(t, mustHello(protocol.IntentEphemeral, "", domain.Size{Cols: 80, Rows: 24})) | |
| 516 | 517 | var hg sync.WaitGroup | |
| 517 | 518 | hg.Go(func() { d.handleConn(tr1) }) | |
| 518 | - | awaitFrame(t, sends1, ports.MsgWelcome) | |
| 519 | + | awaitFrame(t, sends1, wire.MsgWelcome) | |
| 519 | 520 | // firstPaint starts the background prewarm asynchronously. It is valid for | |
| 520 | 521 | // this Open to occur before shutdown, so do not mistake it for the racing | |
| 521 | 522 | // Hello's forbidden launch. | |
| 522 | - | awaitFrame(t, sends1, ports.MsgOutput) | |
| 523 | + | awaitFrame(t, sends1, wire.MsgOutput) | |
| 523 | 524 | select { | |
| 524 | 525 | case <-preShutdownFloatingOpen: | |
| 525 | 526 | case <-time.After(time.Second): | |
| @@ -548,8 +549,8 @@ func TestHelloRacingShutdownIsRejected(t *testing.T) { | |||
| 548 | 549 | } { | |
| 549 | 550 | tr2, sends2, _ := newConn(t, mustHello(intent.intent, intent.sess, domain.Size{Cols: 80, Rows: 24})) | |
| 550 | 551 | d.handleConn(tr2) | |
| 551 | - | e := awaitFrame(t, sends2, ports.MsgError) | |
| 552 | - | em, err := ports.UnmarshalErrorMsg(e.Payload) | |
| 552 | + | e := awaitFrame(t, sends2, wire.MsgError) | |
| 553 | + | em, err := wire.UnmarshalErrorMsg(e.Payload) | |
| 553 | 554 | require.NoError(t, err) | |
| 554 | 555 | require.Equal(t, protocol.ErrServerShutdown, em.Code, "%s hello racing shutdown must be rejected", intent.name) | |
| 555 | 556 | } | |
| @@ -573,23 +574,23 @@ func TestServeReturnsDespiteWedgedClientOnShutdown(t *testing.T) { | |||
| 573 | 574 | p, _ := newBlockingPTY(t) // Close unblocks the parked reader | |
| 574 | 575 | ||
| 575 | 576 | tr := portsmocks.NewMockTransport(t) | |
| 576 | - | sends := make(chan ports.Frame, 64) | |
| 577 | - | recvCh := make(chan ports.Frame, 1) | |
| 577 | + | sends := make(chan wire.Frame, 64) | |
| 578 | + | recvCh := make(chan wire.Frame, 1) | |
| 578 | 579 | recvCh <- mustHello(protocol.IntentNew, "wedge", domain.Size{Cols: 80, Rows: 24}) | |
| 579 | 580 | connDone := make(chan struct{}) | |
| 580 | 581 | var connOnce sync.Once | |
| 581 | 582 | closeConn := func() { connOnce.Do(func() { close(connDone) }) } | |
| 582 | 583 | ||
| 583 | - | tr.EXPECT().Recv().RunAndReturn(func() (ports.Frame, error) { | |
| 584 | + | tr.EXPECT().Recv().RunAndReturn(func() (wire.Frame, error) { | |
| 584 | 585 | select { | |
| 585 | 586 | case f := <-recvCh: | |
| 586 | 587 | return f, nil | |
| 587 | 588 | case <-connDone: | |
| 588 | - | return ports.Frame{}, io.EOF | |
| 589 | + | return wire.Frame{}, io.EOF | |
| 589 | 590 | } | |
| 590 | 591 | }).Maybe() | |
| 591 | - | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f ports.Frame) error { | |
| 592 | - | if f.Type == ports.MsgDetached { | |
| 592 | + | tr.EXPECT().Send(mock.Anything).RunAndReturn(func(f wire.Frame) error { | |
| 593 | + | if f.Type == wire.MsgDetached { | |
| 593 | 594 | // Wedged: blocks until the transport is force-closed. | |
| 594 | 595 | <-connDone | |
| 595 | 596 | return io.ErrClosedPipe | |
| @@ -621,8 +622,8 @@ func TestServeReturnsDespiteWedgedClientOnShutdown(t *testing.T) { | |||
| 621 | 622 | served := make(chan error, 1) | |
| 622 | 623 | go func() { served <- d.Serve(ctx, l) }() | |
| 623 | 624 | ||
| 624 | - | awaitFrame(t, sends, ports.MsgWelcome) | |
| 625 | - | awaitFrame(t, sends, ports.MsgOutput) | |
| 625 | + | awaitFrame(t, sends, wire.MsgWelcome) | |
| 626 | + | awaitFrame(t, sends, wire.MsgOutput) | |
| 626 | 627 | ||
| 627 | 628 | cancel() // shutdown with the wedged client still attached | |
| 628 | 629 | ||
M internal/usecase/daemon/snapshot_scheduler_test.go +4 -3
| @@ -15,6 +15,7 @@ import ( | |||
| 15 | 15 | "github.com/bnema/vev/internal/ports" | |
| 16 | 16 | portsmocks "github.com/bnema/vev/internal/ports/mocks" | |
| 17 | 17 | "github.com/bnema/vev/internal/protocol" | |
| 18 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 18 | 19 | ) | |
| 19 | 20 | ||
| 20 | 21 | func TestSnapshotCoordinatorQuarantineCancelsPublicationBeforeDelete(t *testing.T) { | |
| @@ -311,7 +312,7 @@ func TestServeShutdownDeadlineStillJoinsPaneExitWriter(t *testing.T) { | |||
| 311 | 312 | served := make(chan error, 1) | |
| 312 | 313 | go func() { served <- d.Serve(ctx, listener) }() | |
| 313 | 314 | ||
| 314 | - | awaitFrame(t, sends, ports.MsgWelcome) | |
| 315 | + | awaitFrame(t, sends, wire.MsgWelcome) | |
| 315 | 316 | sess := firstSession(d) | |
| 316 | 317 | require.NotNil(t, sess) | |
| 317 | 318 | ||
| @@ -476,7 +477,7 @@ func TestServeShutdownCheckpointsBeforeStoppingSnapshotWorker(t *testing.T) { | |||
| 476 | 477 | served := make(chan error, 1) | |
| 477 | 478 | go func() { served <- d.Serve(ctx, l) }() | |
| 478 | 479 | ||
| 479 | - | awaitFrame(t, sends, ports.MsgWelcome) | |
| 480 | + | awaitFrame(t, sends, wire.MsgWelcome) | |
| 480 | 481 | markSnapshotDirty(firstSession(d)) | |
| 481 | 482 | d.snapshotWake <- struct{}{} | |
| 482 | 483 | first := <-published | |
| @@ -533,7 +534,7 @@ func TestServeShutdownDeadlineStillJoinsUncooperativeSnapshotRepository(t *testi | |||
| 533 | 534 | served := make(chan error, 1) | |
| 534 | 535 | go func() { served <- d.Serve(ctx, l) }() | |
| 535 | 536 | ||
| 536 | - | awaitFrame(t, sends, ports.MsgWelcome) | |
| 537 | + | awaitFrame(t, sends, wire.MsgWelcome) | |
| 537 | 538 | markSnapshotDirty(firstSession(d)) | |
| 538 | 539 | d.snapshotWake <- struct{}{} | |
| 539 | 540 | select { | |
M internal/usecase/daemon/status_test.go +6 -6
| @@ -13,8 +13,8 @@ import ( | |||
| 13 | 13 | ||
| 14 | 14 | renderer "github.com/bnema/vev-vt/ansi" | |
| 15 | 15 | "github.com/bnema/vev/internal/domain" | |
| 16 | - | "github.com/bnema/vev/internal/ports" | |
| 17 | 16 | "github.com/bnema/vev/internal/protocol" | |
| 17 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 18 | 18 | "github.com/bnema/vev/internal/usecase/command" | |
| 19 | 19 | "github.com/bnema/vev/internal/usecase/layout" | |
| 20 | 20 | "github.com/bnema/vev/internal/usecase/palette" | |
| @@ -1445,13 +1445,13 @@ func TestStatusCoalescesCreateSwitchAndResize(t *testing.T) { | |||
| 1445 | 1445 | frameInput([]byte("\x1b ")), | |
| 1446 | 1446 | frameInput([]byte("CNT\r")), | |
| 1447 | 1447 | frameInput([]byte("\x1b1")), | |
| 1448 | - | ports.Frame{Type: ports.MsgResize, Payload: mustMarshalResize(protocol.Resize{Size: domain.Size{Cols: 22, Rows: 6}})}, | |
| 1448 | + | wire.Frame{Type: wire.MsgResize, Payload: mustMarshalResize(protocol.Resize{Size: domain.Size{Cols: 22, Rows: 6}})}, | |
| 1449 | 1449 | ) | |
| 1450 | 1450 | ||
| 1451 | 1451 | var hg sync.WaitGroup | |
| 1452 | 1452 | hg.Go(func() { d.handleConn(tr) }) | |
| 1453 | - | awaitFrame(t, sends, ports.MsgWelcome) | |
| 1454 | - | first := awaitFrame(t, sends, ports.MsgOutput) | |
| 1453 | + | awaitFrame(t, sends, wire.MsgWelcome) | |
| 1454 | + | first := awaitFrame(t, sends, wire.MsgOutput) | |
| 1455 | 1455 | require.Eventually(t, func() bool { | |
| 1456 | 1456 | sessions := listSessions(t, d) | |
| 1457 | 1457 | return len(sessions.Sessions) == 1 && sessions.Sessions[0].Tabs == 2 | |
| @@ -1466,8 +1466,8 @@ func TestStatusCoalescesCreateSwitchAndResize(t *testing.T) { | |||
| 1466 | 1466 | "timed out awaiting resized output frame", | |
| 1467 | 1467 | ) | |
| 1468 | 1468 | ||
| 1469 | - | for _, f := range []ports.Frame{first, resized} { | |
| 1470 | - | out, err := ports.UnmarshalOutput(f.Payload) | |
| 1469 | + | for _, f := range []wire.Frame{first, resized} { | |
| 1470 | + | out, err := wire.UnmarshalOutput(f.Payload) | |
| 1471 | 1471 | require.NoError(t, err) | |
| 1472 | 1472 | require.Contains(t, string(out.Data), "work") | |
| 1473 | 1473 | require.Contains(t, string(out.Data), ";7m", "active status tab should be inverse-highlighted") | |
M internal/usecase/daemon/test_wait_helpers_test.go +8 -8
| @@ -4,13 +4,13 @@ import ( | |||
| 4 | 4 | "testing" | |
| 5 | 5 | "time" | |
| 6 | 6 | ||
| 7 | - | "github.com/bnema/vev/internal/ports" | |
| 7 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 8 | 8 | ) | |
| 9 | 9 | ||
| 10 | 10 | const testWaitTimeout = 2 * time.Second | |
| 11 | 11 | ||
| 12 | - | func testFramesOfType(frames []ports.Frame, typ ports.MsgType) []ports.Frame { | |
| 13 | - | matched := make([]ports.Frame, 0, len(frames)) | |
| 12 | + | func testFramesOfType(frames []wire.Frame, typ wire.MsgType) []wire.Frame { | |
| 13 | + | matched := make([]wire.Frame, 0, len(frames)) | |
| 14 | 14 | for _, frame := range frames { | |
| 15 | 15 | if frame.Type == typ { | |
| 16 | 16 | matched = append(matched, frame) | |
| @@ -40,21 +40,21 @@ func awaitTestCompletion(t *testing.T, done <-chan struct{}, failure string) { | |||
| 40 | 40 | ||
| 41 | 41 | func awaitCoordinatorOutput( | |
| 42 | 42 | t *testing.T, | |
| 43 | - | sends <-chan ports.Frame, | |
| 43 | + | sends <-chan wire.Frame, | |
| 44 | 44 | timers <-chan *coordinatorMockTimer, | |
| 45 | 45 | frameContext string, | |
| 46 | 46 | timeoutFailure string, | |
| 47 | - | ) ports.Frame { | |
| 47 | + | ) wire.Frame { | |
| 48 | 48 | t.Helper() | |
| 49 | 49 | deadline := time.NewTimer(testWaitTimeout) | |
| 50 | 50 | defer deadline.Stop() | |
| 51 | 51 | for { | |
| 52 | 52 | select { | |
| 53 | 53 | case frame := <-sends: | |
| 54 | - | if frame.Type == ports.MsgRoutePosition { | |
| 54 | + | if frame.Type == wire.MsgRoutePosition { | |
| 55 | 55 | continue | |
| 56 | 56 | } | |
| 57 | - | if frame.Type != ports.MsgOutput { | |
| 57 | + | if frame.Type != wire.MsgOutput { | |
| 58 | 58 | t.Fatalf("unexpected frame type %d %s", frame.Type, frameContext) | |
| 59 | 59 | } | |
| 60 | 60 | return frame | |
| @@ -62,7 +62,7 @@ func awaitCoordinatorOutput( | |||
| 62 | 62 | timer.ch <- time.Time{} | |
| 63 | 63 | case <-deadline.C: | |
| 64 | 64 | t.Fatal(timeoutFailure) | |
| 65 | - | return ports.Frame{} | |
| 65 | + | return wire.Frame{} | |
| 66 | 66 | } | |
| 67 | 67 | } | |
| 68 | 68 | } | |
M internal/usecase/daemon/transactional_resize_test.go +5 -4
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | 12 | ||
| 13 | 13 | "github.com/bnema/vev/internal/domain" | |
| 14 | 14 | "github.com/bnema/vev/internal/ports" | |
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 15 | 16 | "github.com/bnema/vev/internal/usecase/layout" | |
| 16 | 17 | "github.com/bnema/vev/internal/usecase/ui" | |
| 17 | 18 | "github.com/bnema/vev/internal/usecase/visualsearch" | |
| @@ -189,8 +190,8 @@ func TestProcessPTYDataRetainsCallbacksDuringResizeReplay(t *testing.T) { | |||
| 189 | 190 | // normal asynchronous client path, proving replay uses processPTYData. | |
| 190 | 191 | var clipboardOutput string | |
| 191 | 192 | for { | |
| 192 | - | frame := awaitFrame(t, sends, ports.MsgOutput) | |
| 193 | - | out, err := ports.UnmarshalOutput(frame.Payload) | |
| 193 | + | frame := awaitFrame(t, sends, wire.MsgOutput) | |
| 194 | + | out, err := wire.UnmarshalOutput(frame.Payload) | |
| 194 | 195 | require.NoError(t, err) | |
| 195 | 196 | clipboardOutput = string(out.Data) | |
| 196 | 197 | if strings.Contains(clipboardOutput, "\x1b]52;c;YQ==\a") { | |
| @@ -839,8 +840,8 @@ func TestTransactionalResizeObsoleteTimerCallbacksCommitOnlyLatestEpoch(t *testi | |||
| 839 | 840 | // The resize deadline is the only debounce: commit fires its sticky reset | |
| 840 | 841 | // through S2 immediately (subject to ACK/sync gates). | |
| 841 | 842 | frame := <-frames | |
| 842 | - | require.Equal(t, ports.MsgOutput, frame.Type, "the committed epoch emits a full frame") | |
| 843 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 843 | + | require.Equal(t, wire.MsgOutput, frame.Type, "the committed epoch emits a full frame") | |
| 844 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 844 | 845 | require.NoError(t, err) | |
| 845 | 846 | require.Zero(t, output.Base, "the accepted resize frame must reset the renderer state") | |
| 846 | 847 | select { | |
M internal/usecase/daemon/transport_observability_test.go +9 -8
| @@ -9,6 +9,7 @@ import ( | |||
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/vev/internal/domain" | |
| 11 | 11 | "github.com/bnema/vev/internal/ports" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 12 | 13 | ) | |
| 13 | 14 | ||
| 14 | 15 | // This acceptance boundary exercises the attached resize, render, and ACK | |
| @@ -25,11 +26,11 @@ func TestTransportObservabilityDaemonBoundaries(t *testing.T) { | |||
| 25 | 26 | if !d.resizeForFirstPaint(sess, ac, domain.Size{Cols: 90, Rows: 25}) { | |
| 26 | 27 | t.Fatal("first resize was not accepted") | |
| 27 | 28 | } | |
| 28 | - | first := awaitFrame(t, sends, ports.MsgOutput) | |
| 29 | - | if first.Type != ports.MsgOutput { | |
| 29 | + | first := awaitFrame(t, sends, wire.MsgOutput) | |
| 30 | + | if first.Type != wire.MsgOutput { | |
| 30 | 31 | t.Fatalf("first frame = %v, want output", first.Type) | |
| 31 | 32 | } | |
| 32 | - | output, err := ports.UnmarshalOutput(first.Payload) | |
| 33 | + | output, err := wire.UnmarshalOutput(first.Payload) | |
| 33 | 34 | if err != nil { | |
| 34 | 35 | t.Fatalf("decode first output: %v", err) | |
| 35 | 36 | } | |
| @@ -38,8 +39,8 @@ func TestTransportObservabilityDaemonBoundaries(t *testing.T) { | |||
| 38 | 39 | } | |
| 39 | 40 | ac.ackOutputState(output.Epoch, output.New) | |
| 40 | 41 | rc.notifyAck() | |
| 41 | - | second := awaitFrame(t, sends, ports.MsgOutput) | |
| 42 | - | if second.Type != ports.MsgOutput { | |
| 42 | + | second := awaitFrame(t, sends, wire.MsgOutput) | |
| 43 | + | if second.Type != wire.MsgOutput { | |
| 43 | 44 | t.Fatalf("second frame = %v, want output", second.Type) | |
| 44 | 45 | } | |
| 45 | 46 | ||
| @@ -118,8 +119,8 @@ func TestTransportObservabilityBlockedRenderObserverReleasesArchitectureLocks(t | |||
| 118 | 119 | close(paintDone) | |
| 119 | 120 | }() | |
| 120 | 121 | awaitDaemonObserver(t, observer.entered, "blocked render observer") | |
| 121 | - | frame := awaitFrame(t, sends, ports.MsgOutput) // The frame was emitted before the observer began its I/O. | |
| 122 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 122 | + | frame := awaitFrame(t, sends, wire.MsgOutput) // The frame was emitted before the observer began its I/O. | |
| 123 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 123 | 124 | if err != nil { | |
| 124 | 125 | t.Fatalf("decode emitted output: %v", err) | |
| 125 | 126 | } | |
| @@ -153,7 +154,7 @@ func TestTransportObservabilityBlockedRenderObserverReleasesArchitectureLocks(t | |||
| 153 | 154 | d.paint(sess, ac, false, nil) | |
| 154 | 155 | close(secondPaint) | |
| 155 | 156 | }() | |
| 156 | - | _ = awaitFrame(t, sends, ports.MsgOutput) // The second frame is live even though serialized observer I/O waits. | |
| 157 | + | _ = awaitFrame(t, sends, wire.MsgOutput) // The second frame is live even though serialized observer I/O waits. | |
| 157 | 158 | ||
| 158 | 159 | close(observer.release) | |
| 159 | 160 | awaitDaemonObserver(t, paintDone, "first render completion") | |
M internal/usecase/daemon/wire.go +17 -17
| @@ -3,11 +3,11 @@ package daemon | |||
| 3 | 3 | ||
| 4 | 4 | import ( | |
| 5 | 5 | "github.com/bnema/vev/internal/domain" | |
| 6 | - | "github.com/bnema/vev/internal/ports" | |
| 7 | 6 | "github.com/bnema/vev/internal/protocol" | |
| 7 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 8 | 8 | ) | |
| 9 | 9 | ||
| 10 | - | func frameWelcome(s *session, resumeToken uint64) (ports.Frame, error) { | |
| 10 | + | func frameWelcome(s *session, resumeToken uint64) (wire.Frame, error) { | |
| 11 | 11 | s.mu.Lock() | |
| 12 | 12 | var identity *protocol.CommittedRouteIdentity | |
| 13 | 13 | if s.incarnation != (domain.SessionLifecycleID{}) { | |
| @@ -25,36 +25,36 @@ func frameWelcome(s *session, resumeToken uint64) (ports.Frame, error) { | |||
| 25 | 25 | } | |
| 26 | 26 | s.mu.Unlock() | |
| 27 | 27 | w.ResumeToken = resumeToken | |
| 28 | - | payload := ports.MarshalWelcome(w) | |
| 28 | + | payload := wire.MarshalWelcome(w) | |
| 29 | 29 | if payload == nil { | |
| 30 | - | return ports.Frame{}, protocol.ErrInvalidRouteWire | |
| 30 | + | return wire.Frame{}, protocol.ErrInvalidRouteWire | |
| 31 | 31 | } | |
| 32 | - | return ports.Frame{Type: ports.MsgWelcome, Payload: payload}, nil | |
| 32 | + | return wire.Frame{Type: wire.MsgWelcome, Payload: payload}, nil | |
| 33 | 33 | } | |
| 34 | 34 | ||
| 35 | - | func frameError(code uint16, text string) ports.Frame { | |
| 36 | - | return ports.Frame{Type: ports.MsgError, Payload: ports.MarshalErrorMsg(protocol.ErrorMsg{Code: code, Text: text})} | |
| 35 | + | func frameError(code uint16, text string) wire.Frame { | |
| 36 | + | return wire.Frame{Type: wire.MsgError, Payload: wire.MarshalErrorMsg(protocol.ErrorMsg{Code: code, Text: text})} | |
| 37 | 37 | } | |
| 38 | 38 | ||
| 39 | - | func frameOutputState(b []byte, baseState uint64, state uint64, echoAck uint64) (ports.Frame, error) { | |
| 40 | - | payload, err := ports.MarshalOutput(protocol.Output{ | |
| 39 | + | func frameOutputState(b []byte, baseState uint64, state uint64, echoAck uint64) (wire.Frame, error) { | |
| 40 | + | payload, err := wire.MarshalOutput(protocol.Output{ | |
| 41 | 41 | Epoch: 1, Base: baseState, New: state, Echo: echoAck, | |
| 42 | 42 | Size: domain.Size{Cols: 1, Rows: 1}, Full: state != 0 && baseState == 0, Data: b, | |
| 43 | 43 | }) | |
| 44 | 44 | if err != nil { | |
| 45 | - | return ports.Frame{}, err | |
| 45 | + | return wire.Frame{}, err | |
| 46 | 46 | } | |
| 47 | - | return ports.Frame{Type: ports.MsgOutput, Payload: payload}, nil | |
| 47 | + | return wire.Frame{Type: wire.MsgOutput, Payload: payload}, nil | |
| 48 | 48 | } | |
| 49 | 49 | ||
| 50 | - | func frameDetached(reason uint8) ports.Frame { | |
| 51 | - | return ports.Frame{Type: ports.MsgDetached, Payload: ports.MarshalDetached(protocol.Detached{Reason: reason})} | |
| 50 | + | func frameDetached(reason uint8) wire.Frame { | |
| 51 | + | return wire.Frame{Type: wire.MsgDetached, Payload: wire.MarshalDetached(protocol.Detached{Reason: reason})} | |
| 52 | 52 | } | |
| 53 | 53 | ||
| 54 | - | func framePong() ports.Frame { | |
| 55 | - | return ports.Frame{Type: ports.MsgPong, Payload: ports.MarshalPong(protocol.Pong{})} | |
| 54 | + | func framePong() wire.Frame { | |
| 55 | + | return wire.Frame{Type: wire.MsgPong, Payload: wire.MarshalPong(protocol.Pong{})} | |
| 56 | 56 | } | |
| 57 | 57 | ||
| 58 | - | func frameSessions(infos []protocol.SessionInfo) ports.Frame { | |
| 59 | - | return ports.Frame{Type: ports.MsgSessions, Payload: ports.MarshalSessions(protocol.Sessions{Sessions: infos})} | |
| 58 | + | func frameSessions(infos []protocol.SessionInfo) wire.Frame { | |
| 59 | + | return wire.Frame{Type: wire.MsgSessions, Payload: wire.MarshalSessions(protocol.Sessions{Sessions: infos})} | |
| 60 | 60 | } | |
M internal/usecase/daemon/wire_metadata_test.go +2 -2
| @@ -5,7 +5,7 @@ import ( | |||
| 5 | 5 | "sync" | |
| 6 | 6 | "testing" | |
| 7 | 7 | ||
| 8 | - | "github.com/bnema/vev/internal/ports" | |
| 8 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 9 | 9 | ) | |
| 10 | 10 | ||
| 11 | 11 | func TestFrameWelcomeSnapshotsSessionMetadataUnderLock(t *testing.T) { | |
| @@ -27,7 +27,7 @@ func TestFrameWelcomeSnapshotsSessionMetadataUnderLock(t *testing.T) { | |||
| 27 | 27 | if frameErr != nil { | |
| 28 | 28 | t.Fatalf("frameWelcome() error = %v", frameErr) | |
| 29 | 29 | } | |
| 30 | - | welcome, err := ports.UnmarshalWelcome(frame.Payload) | |
| 30 | + | welcome, err := wire.UnmarshalWelcome(frame.Payload) | |
| 31 | 31 | if err != nil { | |
| 32 | 32 | t.Fatalf("UnmarshalWelcome() error = %v", err) | |
| 33 | 33 | } | |
M internal/usecase/daemon/wire_test_helpers_test.go +4 -4
| @@ -1,12 +1,12 @@ | |||
| 1 | 1 | package daemon | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | - | "github.com/bnema/vev/internal/ports" | |
| 5 | 4 | "github.com/bnema/vev/internal/protocol" | |
| 5 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 6 | 6 | ) | |
| 7 | 7 | ||
| 8 | 8 | func mustMarshalOutput(m protocol.Output) []byte { | |
| 9 | - | payload, err := ports.MarshalOutput(m) | |
| 9 | + | payload, err := wire.MarshalOutput(m) | |
| 10 | 10 | if err != nil { | |
| 11 | 11 | panic(err) | |
| 12 | 12 | } | |
| @@ -14,7 +14,7 @@ func mustMarshalOutput(m protocol.Output) []byte { | |||
| 14 | 14 | } | |
| 15 | 15 | ||
| 16 | 16 | func mustMarshalAck(m protocol.Ack) []byte { | |
| 17 | - | payload, err := ports.MarshalAck(m) | |
| 17 | + | payload, err := wire.MarshalAck(m) | |
| 18 | 18 | if err != nil { | |
| 19 | 19 | panic(err) | |
| 20 | 20 | } | |
| @@ -22,7 +22,7 @@ func mustMarshalAck(m protocol.Ack) []byte { | |||
| 22 | 22 | } | |
| 23 | 23 | ||
| 24 | 24 | func mustMarshalResize(m protocol.Resize) []byte { | |
| 25 | - | payload, err := ports.MarshalResize(m) | |
| 25 | + | payload, err := wire.MarshalResize(m) | |
| 26 | 26 | if err != nil { | |
| 27 | 27 | panic(err) | |
| 28 | 28 | } | |
M scripts/remote-picker-harness/main.go +32 -31
| @@ -21,6 +21,7 @@ import ( | |||
| 21 | 21 | "github.com/bnema/vev/internal/domain" | |
| 22 | 22 | "github.com/bnema/vev/internal/ports" | |
| 23 | 23 | "github.com/bnema/vev/internal/protocol" | |
| 24 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 24 | 25 | ) | |
| 25 | 26 | ||
| 26 | 27 | const ( | |
| @@ -458,7 +459,7 @@ func localEnvironment() []string { | |||
| 458 | 459 | } | |
| 459 | 460 | ||
| 460 | 461 | type harnessFrame struct { | |
| 461 | - | frame ports.Frame | |
| 462 | + | frame wire.Frame | |
| 462 | 463 | err error | |
| 463 | 464 | } | |
| 464 | 465 | ||
| @@ -642,44 +643,44 @@ func attachAndCheck(ctx context.Context, tr *harnessTransport, hello protocol.He | |||
| 642 | 643 | if hello.EnvironmentPolicy == 0 { | |
| 643 | 644 | hello.EnvironmentPolicy = protocol.EnvironmentPolicyClientOwned | |
| 644 | 645 | } | |
| 645 | - | payload := ports.MarshalHello(hello) | |
| 646 | - | if err := tr.Send(ports.Frame{Type: ports.MsgHello, Payload: payload}); err != nil { | |
| 646 | + | payload := wire.MarshalHello(hello) | |
| 647 | + | if err := tr.Send(wire.Frame{Type: wire.MsgHello, Payload: payload}); err != nil { | |
| 647 | 648 | return err | |
| 648 | 649 | } | |
| 649 | 650 | frame, err := receiveWithTimeout(ctx, tr) | |
| 650 | 651 | if err != nil { | |
| 651 | 652 | return err | |
| 652 | 653 | } | |
| 653 | - | if frame.Type == ports.MsgError { | |
| 654 | - | message, decodeErr := ports.UnmarshalErrorMsg(frame.Payload) | |
| 654 | + | if frame.Type == wire.MsgError { | |
| 655 | + | message, decodeErr := wire.UnmarshalErrorMsg(frame.Payload) | |
| 655 | 656 | if decodeErr != nil { | |
| 656 | 657 | return decodeErr | |
| 657 | 658 | } | |
| 658 | 659 | return fmt.Errorf("remote error code %d", message.Code) | |
| 659 | 660 | } | |
| 660 | - | if frame.Type != ports.MsgWelcome { | |
| 661 | + | if frame.Type != wire.MsgWelcome { | |
| 661 | 662 | return fmt.Errorf("welcome frame type %d", frame.Type) | |
| 662 | 663 | } | |
| 663 | 664 | tr.probe.recordControl(probeEventWelcome) | |
| 664 | - | if err := tr.Send(ports.Frame{Type: ports.MsgTheme, Payload: ports.MarshalTheme(protocol.Theme{TrueColor: hello.TrueColor, SchemeKnown: true})}); err != nil { | |
| 665 | + | if err := tr.Send(wire.Frame{Type: wire.MsgTheme, Payload: wire.MarshalTheme(protocol.Theme{TrueColor: hello.TrueColor, SchemeKnown: true})}); err != nil { | |
| 665 | 666 | return fmt.Errorf("send initial theme: %w", err) | |
| 666 | 667 | } | |
| 667 | 668 | return nil | |
| 668 | 669 | } | |
| 669 | 670 | ||
| 670 | 671 | func sendRawInput(tr *harnessTransport, data string) error { | |
| 671 | - | return tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte(data)})}) | |
| 672 | + | return tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte(data)})}) | |
| 672 | 673 | } | |
| 673 | 674 | ||
| 674 | - | func processOutputFrame(tr *harnessTransport, frame ports.Frame) error { | |
| 675 | - | output, err := ports.UnmarshalOutput(frame.Payload) | |
| 675 | + | func processOutputFrame(tr *harnessTransport, frame wire.Frame) error { | |
| 676 | + | output, err := wire.UnmarshalOutput(frame.Payload) | |
| 676 | 677 | if err != nil { | |
| 677 | 678 | return err | |
| 678 | 679 | } | |
| 679 | 680 | result := tr.probe.apply(output) | |
| 680 | 681 | if !result.Accepted { | |
| 681 | 682 | if !tr.probe.resetPending { | |
| 682 | - | if err := tr.Send(ports.Frame{Type: ports.MsgOutputResetRequest, Payload: ports.MarshalOutputResetRequest(protocol.OutputResetRequest{})}); err != nil { | |
| 683 | + | if err := tr.Send(wire.Frame{Type: wire.MsgOutputResetRequest, Payload: wire.MarshalOutputResetRequest(protocol.OutputResetRequest{})}); err != nil { | |
| 683 | 684 | return err | |
| 684 | 685 | } | |
| 685 | 686 | tr.probe.resetPending = true | |
| @@ -690,11 +691,11 @@ func processOutputFrame(tr *harnessTransport, frame ports.Frame) error { | |||
| 690 | 691 | if !result.StateBearing { | |
| 691 | 692 | return nil | |
| 692 | 693 | } | |
| 693 | - | payload, err := ports.MarshalAck(result.Ack) | |
| 694 | + | payload, err := wire.MarshalAck(result.Ack) | |
| 694 | 695 | if err != nil { | |
| 695 | 696 | return err | |
| 696 | 697 | } | |
| 697 | - | if err := tr.Send(ports.Frame{Type: ports.MsgAck, Payload: payload}); err != nil { | |
| 698 | + | if err := tr.Send(wire.Frame{Type: wire.MsgAck, Payload: payload}); err != nil { | |
| 698 | 699 | return err | |
| 699 | 700 | } | |
| 700 | 701 | tr.probe.resetPending = false | |
| @@ -714,7 +715,7 @@ func awaitOutputContains(ctx context.Context, tr *harnessTransport, want string) | |||
| 714 | 715 | if err != nil { | |
| 715 | 716 | return err | |
| 716 | 717 | } | |
| 717 | - | if frame.Type != ports.MsgOutput { | |
| 718 | + | if frame.Type != wire.MsgOutput { | |
| 718 | 719 | continue | |
| 719 | 720 | } | |
| 720 | 721 | if err := processOutputFrame(tr, frame); err != nil { | |
| @@ -738,7 +739,7 @@ func awaitRemotePickerPreview(ctx context.Context, tr *harnessTransport, marker | |||
| 738 | 739 | if err != nil { | |
| 739 | 740 | return fmt.Errorf("no rendered remote preview after %d output frames (loading=%t): %w", tr.probe.outputFrames, sawLoading, err) | |
| 740 | 741 | } | |
| 741 | - | if frame.Type != ports.MsgOutput { | |
| 742 | + | if frame.Type != wire.MsgOutput { | |
| 742 | 743 | continue | |
| 743 | 744 | } | |
| 744 | 745 | if err := processOutputFrame(tr, frame); err != nil { | |
| @@ -768,7 +769,7 @@ func remotePreviewContains(preview protocol.RemotePreview, want string) bool { | |||
| 768 | 769 | } | |
| 769 | 770 | ||
| 770 | 771 | func sendInputAndAwait(ctx context.Context, tr *harnessTransport, command, want string) error { | |
| 771 | - | if err := tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(protocol.Input{Data: []byte(command + "\n")})}); err != nil { | |
| 772 | + | if err := tr.Send(wire.Frame{Type: wire.MsgInput, Payload: wire.MarshalInput(protocol.Input{Data: []byte(command + "\n")})}); err != nil { | |
| 772 | 773 | return err | |
| 773 | 774 | } | |
| 774 | 775 | deadline, cancel := context.WithTimeout(ctx, 5*time.Second) | |
| @@ -779,7 +780,7 @@ func sendInputAndAwait(ctx context.Context, tr *harnessTransport, command, want | |||
| 779 | 780 | if err != nil { | |
| 780 | 781 | return fmt.Errorf("waiting for marker after %d output frames/%d bytes: %w", tr.probe.outputFrames, tr.probe.outputBytes, err) | |
| 781 | 782 | } | |
| 782 | - | if frame.Type != ports.MsgOutput { | |
| 783 | + | if frame.Type != wire.MsgOutput { | |
| 783 | 784 | continue | |
| 784 | 785 | } | |
| 785 | 786 | if err := processOutputFrame(tr, frame); err != nil { | |
| @@ -801,11 +802,11 @@ func sendCommand(ctx context.Context, tr *harnessTransport, slug string) error { | |||
| 801 | 802 | Attached: true, | |
| 802 | 803 | Slug: slug, | |
| 803 | 804 | } | |
| 804 | - | payload, err := ports.MarshalCommandRequest(request) | |
| 805 | + | payload, err := wire.MarshalCommandRequest(request) | |
| 805 | 806 | if err != nil { | |
| 806 | 807 | return err | |
| 807 | 808 | } | |
| 808 | - | if err := tr.Send(ports.Frame{Type: ports.MsgCommand, Payload: payload}); err != nil { | |
| 809 | + | if err := tr.Send(wire.Frame{Type: wire.MsgCommand, Payload: payload}); err != nil { | |
| 809 | 810 | return err | |
| 810 | 811 | } | |
| 811 | 812 | deadline, cancel := context.WithTimeout(ctx, 5*time.Second) | |
| @@ -815,16 +816,16 @@ func sendCommand(ctx context.Context, tr *harnessTransport, slug string) error { | |||
| 815 | 816 | if err != nil { | |
| 816 | 817 | return err | |
| 817 | 818 | } | |
| 818 | - | if frame.Type == ports.MsgOutput { | |
| 819 | + | if frame.Type == wire.MsgOutput { | |
| 819 | 820 | if err := processOutputFrame(tr, frame); err != nil { | |
| 820 | 821 | return err | |
| 821 | 822 | } | |
| 822 | 823 | continue | |
| 823 | 824 | } | |
| 824 | - | if frame.Type != ports.MsgCommandResult { | |
| 825 | + | if frame.Type != wire.MsgCommandResult { | |
| 825 | 826 | continue | |
| 826 | 827 | } | |
| 827 | - | result, err := ports.UnmarshalCommandResult(frame.Payload) | |
| 828 | + | result, err := wire.UnmarshalCommandResult(frame.Payload) | |
| 828 | 829 | if err != nil { | |
| 829 | 830 | return err | |
| 830 | 831 | } | |
| @@ -836,7 +837,7 @@ func sendCommand(ctx context.Context, tr *harnessTransport, slug string) error { | |||
| 836 | 837 | } | |
| 837 | 838 | ||
| 838 | 839 | func detach(ctx context.Context, tr *harnessTransport) error { | |
| 839 | - | if err := tr.Send(ports.Frame{Type: ports.MsgDetach, Payload: ports.MarshalDetach(protocol.Detach{})}); err != nil { | |
| 840 | + | if err := tr.Send(wire.Frame{Type: wire.MsgDetach, Payload: wire.MarshalDetach(protocol.Detach{})}); err != nil { | |
| 840 | 841 | return err | |
| 841 | 842 | } | |
| 842 | 843 | deadline, cancel := context.WithTimeout(ctx, 5*time.Second) | |
| @@ -846,7 +847,7 @@ func detach(ctx context.Context, tr *harnessTransport) error { | |||
| 846 | 847 | if err != nil { | |
| 847 | 848 | return err | |
| 848 | 849 | } | |
| 849 | - | if frame.Type == ports.MsgDetached { | |
| 850 | + | if frame.Type == wire.MsgDetached { | |
| 850 | 851 | return nil | |
| 851 | 852 | } | |
| 852 | 853 | } | |
| @@ -871,18 +872,18 @@ func expectNoSuchTarget(ctx context.Context, tr *harnessTransport, target domain | |||
| 871 | 872 | RemoteTarget: &target, | |
| 872 | 873 | EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, | |
| 873 | 874 | } | |
| 874 | - | payload := ports.MarshalHello(hello) | |
| 875 | - | if err := tr.Send(ports.Frame{Type: ports.MsgHello, Payload: payload}); err != nil { | |
| 875 | + | payload := wire.MarshalHello(hello) | |
| 876 | + | if err := tr.Send(wire.Frame{Type: wire.MsgHello, Payload: payload}); err != nil { | |
| 876 | 877 | return err | |
| 877 | 878 | } | |
| 878 | 879 | frame, err := receiveWithTimeout(ctx, tr) | |
| 879 | 880 | if err != nil { | |
| 880 | 881 | return err | |
| 881 | 882 | } | |
| 882 | - | if frame.Type != ports.MsgError { | |
| 883 | + | if frame.Type != wire.MsgError { | |
| 883 | 884 | return fmt.Errorf("stale target returned frame type %d", frame.Type) | |
| 884 | 885 | } | |
| 885 | - | message, err := ports.UnmarshalErrorMsg(frame.Payload) | |
| 886 | + | message, err := wire.UnmarshalErrorMsg(frame.Payload) | |
| 886 | 887 | if err != nil { | |
| 887 | 888 | return err | |
| 888 | 889 | } | |
| @@ -1002,7 +1003,7 @@ func assertNoDirectHandoff(tr *harnessTransport) error { | |||
| 1002 | 1003 | queued := len(tr.frames) | |
| 1003 | 1004 | for range queued { | |
| 1004 | 1005 | outcome := <-tr.frames | |
| 1005 | - | if outcome.frame.Type == ports.MsgAttachTarget { | |
| 1006 | + | if outcome.frame.Type == wire.MsgAttachTarget { | |
| 1006 | 1007 | tr.probe.recordIncoming(outcome.frame) | |
| 1007 | 1008 | } else { | |
| 1008 | 1009 | tr.queued = append(tr.queued, outcome) | |
| @@ -1014,7 +1015,7 @@ func assertNoDirectHandoff(tr *harnessTransport) error { | |||
| 1014 | 1015 | return nil | |
| 1015 | 1016 | } | |
| 1016 | 1017 | ||
| 1017 | - | func receiveWithTimeout(ctx context.Context, tr *harnessTransport) (ports.Frame, error) { | |
| 1018 | + | func receiveWithTimeout(ctx context.Context, tr *harnessTransport) (wire.Frame, error) { | |
| 1018 | 1019 | if len(tr.queued) != 0 { | |
| 1019 | 1020 | outcome := tr.queued[0] | |
| 1020 | 1021 | tr.queued = tr.queued[1:] | |
| @@ -1025,7 +1026,7 @@ func receiveWithTimeout(ctx context.Context, tr *harnessTransport) (ports.Frame, | |||
| 1025 | 1026 | } | |
| 1026 | 1027 | select { | |
| 1027 | 1028 | case <-ctx.Done(): | |
| 1028 | - | return ports.Frame{}, ctx.Err() | |
| 1029 | + | return wire.Frame{}, ctx.Err() | |
| 1029 | 1030 | case outcome := <-tr.frames: | |
| 1030 | 1031 | if outcome.err == nil { | |
| 1031 | 1032 | tr.probe.recordIncoming(outcome.frame) | |
M scripts/remote-picker-harness/main_test.go +4 -4
| @@ -5,7 +5,7 @@ import ( | |||
| 5 | 5 | "strings" | |
| 6 | 6 | "testing" | |
| 7 | 7 | ||
| 8 | - | "github.com/bnema/vev/internal/ports" | |
| 8 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 9 | 9 | ) | |
| 10 | 10 | ||
| 11 | 11 | func TestBoundedStderrRetainsAtMostDiagnosticLimit(t *testing.T) { | |
| @@ -50,13 +50,13 @@ func TestAssertNoDirectHandoffProcessesInitialFramesAndRetainsOutput(t *testing. | |||
| 50 | 50 | probe: &visualProbe{}, | |
| 51 | 51 | frames: make(chan harnessFrame, 2), | |
| 52 | 52 | } | |
| 53 | - | tr.frames <- harnessFrame{frame: ports.Frame{Type: ports.MsgOutput}} | |
| 54 | - | tr.frames <- harnessFrame{frame: ports.Frame{Type: ports.MsgAttachTarget}} | |
| 53 | + | tr.frames <- harnessFrame{frame: wire.Frame{Type: wire.MsgOutput}} | |
| 54 | + | tr.frames <- harnessFrame{frame: wire.Frame{Type: wire.MsgAttachTarget}} | |
| 55 | 55 | ||
| 56 | 56 | if err := assertNoDirectHandoff(tr); err == nil { | |
| 57 | 57 | t.Fatal("direct handoff was not rejected") | |
| 58 | 58 | } | |
| 59 | - | if len(tr.queued) != 1 || tr.queued[0].frame.Type != ports.MsgOutput { | |
| 59 | + | if len(tr.queued) != 1 || tr.queued[0].frame.Type != wire.MsgOutput { | |
| 60 | 60 | t.Fatalf("queued frames = %#v, want one retained output", tr.queued) | |
| 61 | 61 | } | |
| 62 | 62 | if tr.probe.unexpectedHandoffs != 1 { | |
M scripts/remote-picker-harness/visual_probe.go +3 -3
| @@ -11,8 +11,8 @@ import ( | |||
| 11 | 11 | ||
| 12 | 12 | vt "github.com/bnema/vev-vt" | |
| 13 | 13 | "github.com/bnema/vev/internal/domain" | |
| 14 | - | "github.com/bnema/vev/internal/ports" | |
| 15 | 14 | "github.com/bnema/vev/internal/protocol" | |
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 16 | 16 | ) | |
| 17 | 17 | ||
| 18 | 18 | const ( | |
| @@ -237,8 +237,8 @@ func (p *visualProbe) contains(want string) bool { | |||
| 237 | 237 | return strings.Contains(p.text(), want) | |
| 238 | 238 | } | |
| 239 | 239 | ||
| 240 | - | func (p *visualProbe) recordIncoming(frame ports.Frame) { | |
| 241 | - | if p == nil || frame.Type != ports.MsgAttachTarget { | |
| 240 | + | func (p *visualProbe) recordIncoming(frame wire.Frame) { | |
| 241 | + | if p == nil || frame.Type != wire.MsgAttachTarget { | |
| 242 | 242 | return | |
| 243 | 243 | } | |
| 244 | 244 | p.unexpectedHandoffs++ | |
M scripts/remote-picker-harness/visual_probe_test.go +11 -11
| @@ -8,8 +8,8 @@ import ( | |||
| 8 | 8 | "testing" | |
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/vev/internal/domain" | |
| 11 | - | "github.com/bnema/vev/internal/ports" | |
| 12 | 11 | "github.com/bnema/vev/internal/protocol" | |
| 12 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 13 | 13 | "github.com/stretchr/testify/require" | |
| 14 | 14 | ) | |
| 15 | 15 | ||
| @@ -19,24 +19,24 @@ const ( | |||
| 19 | 19 | ) | |
| 20 | 20 | ||
| 21 | 21 | type probeTestTransport struct { | |
| 22 | - | sent []ports.Frame | |
| 22 | + | sent []wire.Frame | |
| 23 | 23 | } | |
| 24 | 24 | ||
| 25 | - | func (t *probeTestTransport) Send(frame ports.Frame) error { | |
| 25 | + | func (t *probeTestTransport) Send(frame wire.Frame) error { | |
| 26 | 26 | t.sent = append(t.sent, frame) | |
| 27 | 27 | return nil | |
| 28 | 28 | } | |
| 29 | 29 | ||
| 30 | - | func (*probeTestTransport) Recv() (ports.Frame, error) { return ports.Frame{}, errors.New("not used") } | |
| 31 | - | func (*probeTestTransport) Close() error { return nil } | |
| 30 | + | func (*probeTestTransport) Recv() (wire.Frame, error) { return wire.Frame{}, errors.New("not used") } | |
| 31 | + | func (*probeTestTransport) Close() error { return nil } | |
| 32 | 32 | ||
| 33 | - | func probeTestOutput(t *testing.T, output protocol.Output) ports.Frame { | |
| 33 | + | func probeTestOutput(t *testing.T, output protocol.Output) wire.Frame { | |
| 34 | 34 | t.Helper() | |
| 35 | - | payload, err := ports.MarshalOutput(output) | |
| 35 | + | payload, err := wire.MarshalOutput(output) | |
| 36 | 36 | if err != nil { | |
| 37 | 37 | t.Fatalf("marshal output: %v", err) | |
| 38 | 38 | } | |
| 39 | - | return ports.Frame{Type: ports.MsgOutput, Payload: payload} | |
| 39 | + | return wire.Frame{Type: wire.MsgOutput, Payload: payload} | |
| 40 | 40 | } | |
| 41 | 41 | ||
| 42 | 42 | func TestVisualProbePersistsFullAndIncrementalOutput(t *testing.T) { | |
| @@ -240,9 +240,9 @@ func TestProcessOutputFrameACKsOnlyAcceptedStateBearingFrames(t *testing.T) { | |||
| 240 | 240 | var ackCount, resetCount int | |
| 241 | 241 | for _, frame := range transport.sent { | |
| 242 | 242 | switch frame.Type { | |
| 243 | - | case ports.MsgAck: | |
| 243 | + | case wire.MsgAck: | |
| 244 | 244 | ackCount++ | |
| 245 | - | case ports.MsgOutputResetRequest: | |
| 245 | + | case wire.MsgOutputResetRequest: | |
| 246 | 246 | resetCount++ | |
| 247 | 247 | } | |
| 248 | 248 | } | |
| @@ -268,7 +268,7 @@ func TestCaptureUnifiedPickerRowsRequiresLocalAndRemoteEntries(t *testing.T) { | |||
| 268 | 268 | ||
| 269 | 269 | func TestVisualProbeRecordsUnexpectedAttachTarget(t *testing.T) { | |
| 270 | 270 | probe := newVisualProbe(domain.Size{Cols: probeTestCols, Rows: probeTestRows}) | |
| 271 | - | probe.recordIncoming(ports.Frame{Type: ports.MsgAttachTarget}) | |
| 271 | + | probe.recordIncoming(wire.Frame{Type: wire.MsgAttachTarget}) | |
| 272 | 272 | ||
| 273 | 273 | if probe.unexpectedHandoffs != 1 { | |
| 274 | 274 | t.Fatalf("unexpected handoffs = %d, want 1", probe.unexpectedHandoffs) | |
M transport_replay_integration_test.go +6 -5
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | 12 | "github.com/bnema/vev/internal/adapters/sshstdio" | |
| 13 | 13 | "github.com/bnema/vev/internal/ports" | |
| 14 | 14 | "github.com/bnema/vev/internal/protocol" | |
| 15 | + | "github.com/bnema/vev/internal/protocol/wire" | |
| 15 | 16 | "github.com/bnema/vev/internal/testutil/replaytest" | |
| 16 | 17 | "github.com/stretchr/testify/require" | |
| 17 | 18 | ) | |
| @@ -39,7 +40,7 @@ func TestTransportReplayIntegration(t *testing.T) { | |||
| 39 | 40 | got, err := receiver.Recv() | |
| 40 | 41 | require.NoError(t, err) | |
| 41 | 42 | require.Equal(t, want, got) | |
| 42 | - | output, err := ports.UnmarshalOutput(got.Payload) | |
| 43 | + | output, err := wire.UnmarshalOutput(got.Payload) | |
| 43 | 44 | require.NoError(t, err) | |
| 44 | 45 | bytes = append(bytes, output.Data...) | |
| 45 | 46 | terminal.Write(output.Data) | |
| @@ -102,7 +103,7 @@ func TestThemeGenerationTransportSequences(t *testing.T) { | |||
| 102 | 103 | done := make(chan error, 1) | |
| 103 | 104 | go func() { | |
| 104 | 105 | for _, snapshot := range sequence { | |
| 105 | - | if err := sender.Send(ports.Frame{Type: ports.MsgTheme, Payload: ports.MarshalTheme(snapshot)}); err != nil { | |
| 106 | + | if err := sender.Send(wire.Frame{Type: wire.MsgTheme, Payload: wire.MarshalTheme(snapshot)}); err != nil { | |
| 106 | 107 | done <- err | |
| 107 | 108 | return | |
| 108 | 109 | } | |
| @@ -113,9 +114,9 @@ func TestThemeGenerationTransportSequences(t *testing.T) { | |||
| 113 | 114 | for _, want := range sequence { | |
| 114 | 115 | frame, err := receiver.Recv() | |
| 115 | 116 | require.NoError(t, err) | |
| 116 | - | require.Equal(t, ports.MsgTheme, frame.Type) | |
| 117 | - | require.Equal(t, ports.MarshalTheme(want), frame.Payload, "theme payload must be preserved byte-for-byte before decode") | |
| 118 | - | got, err := ports.UnmarshalTheme(frame.Payload) | |
| 117 | + | require.Equal(t, wire.MsgTheme, frame.Type) | |
| 118 | + | require.Equal(t, wire.MarshalTheme(want), frame.Payload, "theme payload must be preserved byte-for-byte before decode") | |
| 119 | + | got, err := wire.UnmarshalTheme(frame.Payload) | |
| 119 | 120 | require.NoError(t, err) | |
| 120 | 121 | require.Equal(t, want, got) | |
| 121 | 122 | } | |