newSpeaker creates a new protocol speaker.
( ctx context.Context, logger slog.Logger, conn io.ReadWriteCloser, me, them SpeakerRole, )
| 108 | |
| 109 | // newSpeaker creates a new protocol speaker. |
| 110 | func newSpeaker[S rpcMessage, R receivableRPCMessage[RR], RR any]( |
| 111 | ctx context.Context, logger slog.Logger, conn io.ReadWriteCloser, |
| 112 | me, them SpeakerRole, |
| 113 | ) ( |
| 114 | *speaker[S, R, RR], error, |
| 115 | ) { |
| 116 | ctx, cancel := context.WithCancel(ctx) |
| 117 | if err := handshake(ctx, conn, logger, me, them); err != nil { |
| 118 | cancel() |
| 119 | return nil, xerrors.Errorf("handshake failed: %w", err) |
| 120 | } |
| 121 | sendCh := make(chan S) |
| 122 | recvCh := make(chan R) |
| 123 | s := &speaker[S, R, RR]{ |
| 124 | serdes: newSerdes(ctx, logger, conn, sendCh, recvCh), |
| 125 | logger: logger, |
| 126 | requests: make(chan *request[S, R]), |
| 127 | responseChans: make(map[uint64]chan R), |
| 128 | nextMsgID: 1, |
| 129 | ctx: ctx, |
| 130 | cancel: cancel, |
| 131 | sendCh: sendCh, |
| 132 | recvCh: recvCh, |
| 133 | recvLoopDone: make(chan struct{}), |
| 134 | } |
| 135 | return s, nil |
| 136 | } |
| 137 | |
| 138 | // start starts the serialzation/deserialization. It's important this happens |
| 139 | // after any assignments of the speaker to its owning Tunnel or Manager, since |