(ctx context.Context, _ string, conn net.Conn, height, width uint16, logger slog.Logger)
| 167 | } |
| 168 | |
| 169 | func (rpty *screenReconnectingPTY) Attach(ctx context.Context, _ string, conn net.Conn, height, width uint16, logger slog.Logger) error { |
| 170 | logger.Info(ctx, "attach to reconnecting pty") |
| 171 | |
| 172 | // This will kill the heartbeat once we hit EOF or an error. |
| 173 | ctx, cancel := context.WithCancel(ctx) |
| 174 | defer cancel() |
| 175 | |
| 176 | state, err := rpty.state.waitForStateOrContext(ctx, StateReady) |
| 177 | if state != StateReady { |
| 178 | return err |
| 179 | } |
| 180 | |
| 181 | go heartbeat(ctx, rpty.timer, rpty.timeout) |
| 182 | |
| 183 | ptty, process, err := rpty.doAttach(ctx, conn, height, width, logger) |
| 184 | if err != nil { |
| 185 | logger.Debug(ctx, "unable to attach to screen reconnecting pty", slog.Error(err)) |
| 186 | if errors.Is(err, context.Canceled) { |
| 187 | // Likely the process was too short-lived and canceled the version command. |
| 188 | // TODO: Is it worth distinguishing between that and a cancel from the |
| 189 | // Attach() caller? Additionally, since this could also happen if |
| 190 | // the command was invalid, should we check the process's exit code? |
| 191 | return nil |
| 192 | } |
| 193 | return err |
| 194 | } |
| 195 | logger.Debug(ctx, "attached to screen reconnecting pty") |
| 196 | |
| 197 | defer func() { |
| 198 | // Log only for debugging since the process might have already exited on its |
| 199 | // own. |
| 200 | err := ptty.Close() |
| 201 | if err != nil { |
| 202 | logger.Debug(ctx, "closed ptty with error", slog.Error(err)) |
| 203 | } |
| 204 | err = process.Kill() |
| 205 | if err != nil { |
| 206 | logger.Debug(ctx, "killed process with error", slog.Error(err)) |
| 207 | } |
| 208 | }() |
| 209 | |
| 210 | // Pipe conn -> pty and block. |
| 211 | readConnLoop(ctx, conn, ptty, rpty.metrics, logger) |
| 212 | return nil |
| 213 | } |
| 214 | |
| 215 | // doAttach spawns the screen client and starts the heartbeat. It exists |
| 216 | // separately only so we can defer the mutex unlock which is not possible in |
nothing calls this directly
no test coverage detected