(ctx context.Context, connID string, conn net.Conn, height, width uint16, logger slog.Logger)
| 172 | } |
| 173 | |
| 174 | func (rpty *bufferedReconnectingPTY) Attach(ctx context.Context, connID string, conn net.Conn, height, width uint16, logger slog.Logger) error { |
| 175 | logger.Info(ctx, "attach to reconnecting pty") |
| 176 | |
| 177 | // This will kill the heartbeat once we hit EOF or an error. |
| 178 | ctx, cancel := context.WithCancel(ctx) |
| 179 | defer cancel() |
| 180 | |
| 181 | err := rpty.doAttach(connID, conn) |
| 182 | if err != nil { |
| 183 | return err |
| 184 | } |
| 185 | |
| 186 | defer func() { |
| 187 | rpty.state.cond.L.Lock() |
| 188 | defer rpty.state.cond.L.Unlock() |
| 189 | delete(rpty.activeConns, connID) |
| 190 | }() |
| 191 | |
| 192 | state, err := rpty.state.waitForStateOrContext(ctx, StateReady) |
| 193 | if state != StateReady { |
| 194 | return err |
| 195 | } |
| 196 | |
| 197 | go heartbeat(ctx, rpty.timer, rpty.timeout) |
| 198 | |
| 199 | // Resize the PTY to initial height + width. |
| 200 | err = rpty.ptty.Resize(height, width) |
| 201 | if err != nil { |
| 202 | // We can continue after this, it's not fatal! |
| 203 | logger.Warn(ctx, "reconnecting PTY initial resize failed, but will continue", slog.Error(err)) |
| 204 | rpty.metrics.WithLabelValues("resize").Add(1) |
| 205 | } |
| 206 | |
| 207 | // Pipe conn -> pty and block. pty -> conn is handled in newBuffered(). |
| 208 | readConnLoop(ctx, conn, rpty.ptty, rpty.metrics, logger) |
| 209 | return nil |
| 210 | } |
| 211 | |
| 212 | // doAttach adds the connection to the map and replays the buffer. It exists |
| 213 | // separately only for convenience to defer the mutex unlock which is not |
nothing calls this directly
no test coverage detected