diff options
| author | Paul Buetow <paul@buetow.org> | 2026-01-24 00:10:15 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-01-24 00:10:15 +0200 |
| commit | 65ec49a97b1fcf633c1c6ba92e3db71ecd477196 (patch) | |
| tree | 48b47389e1384f86ff81f849fd526a09ab9c4e0d /internal/server/server.go | |
| parent | ecb963eb98dd9174d017dd504a48fb2ea048c42d (diff) | |
refactor: split large functions for maintainability
Split functions exceeding 50 lines into smaller, focused helpers:
- DirectTurboWriter.WriteLineData (~97 lines) split into:
- WriteLineData (dispatcher, 9 lines)
- writeServerlessLine (serverless mode, 48 lines)
- writeNetworkLine (network mode, 40 lines)
- TurboNetworkWriter.WriteLineData (~60 lines) split into:
- WriteLineData (builds protocol line, 33 lines)
- sendToTurboChannel (channel send with retry, 28 lines)
- Server.handleRequests (~67 lines) split into:
- handleRequests (request loop, 23 lines)
- handleShellRequest (shell session setup, 57 lines)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'internal/server/server.go')
| -rw-r--r-- | internal/server/server.go | 107 |
1 files changed, 61 insertions, 46 deletions
diff --git a/internal/server/server.go b/internal/server/server.go index 8b581b1..38b042f 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -170,52 +170,7 @@ func (s *Server) handleRequests(ctx context.Context, sshConn gossh.Conn, switch req.Type { case "shell": - var handler handlers.Handler - switch user.Name { - case config.HealthUser: - handler = handlers.NewHealthHandler(user) - default: - handler = handlers.NewServerHandler(user, s.catLimiter, s.tailLimiter) - } - terminate := func() { - handler.Shutdown() - sshConn.Close() - } - - go func() { - defer terminate() - // Broken pipe, cancel - if _, err := io.Copy(channel, handler); err != nil { - dlog.Server.Trace(user, fmt.Errorf("channel->handler: %w", err)) - } - }() - go func() { - defer terminate() - // Broken pipe, cancel - if _, err := io.Copy(handler, channel); err != nil { - dlog.Server.Trace(user, fmt.Errorf("handler->channel: %w", err)) - } - }() - go func() { - select { - case <-ctx.Done(): - case <-handler.Done(): - } - terminate() - }() - go func() { - if err := sshConn.Wait(); err != nil && err != io.EOF { - dlog.Server.Error(user, err) - } - s.stats.decrementConnections() - dlog.Server.Info(user, "Good bye Mister!") - terminate() - }() - - // Only serving shell type - if err := req.Reply(true, nil); err != nil { - dlog.Server.Trace(user, fmt.Errorf("reply(true): %w", err)) - } + s.handleShellRequest(ctx, sshConn, channel, user, req) default: if err := req.Reply(false, nil); err != nil { dlog.Server.Trace(user, fmt.Errorf("reply(false): %w", err)) @@ -227,6 +182,66 @@ func (s *Server) handleRequests(ctx context.Context, sshConn gossh.Conn, return nil } +// handleShellRequest sets up the shell session with handler goroutines for I/O, +// context cancellation, and connection lifecycle management. +func (s *Server) handleShellRequest(ctx context.Context, sshConn gossh.Conn, + channel gossh.Channel, user *user.User, req *gossh.Request) { + + // Create the appropriate handler based on user type + var handler handlers.Handler + switch user.Name { + case config.HealthUser: + handler = handlers.NewHealthHandler(user) + default: + handler = handlers.NewServerHandler(user, s.catLimiter, s.tailLimiter) + } + + terminate := func() { + handler.Shutdown() + sshConn.Close() + } + + // Start goroutine to copy data from channel to handler + go func() { + defer terminate() + if _, err := io.Copy(channel, handler); err != nil { + dlog.Server.Trace(user, fmt.Errorf("channel->handler: %w", err)) + } + }() + + // Start goroutine to copy data from handler to channel + go func() { + defer terminate() + if _, err := io.Copy(handler, channel); err != nil { + dlog.Server.Trace(user, fmt.Errorf("handler->channel: %w", err)) + } + }() + + // Start goroutine to handle context or handler completion + go func() { + select { + case <-ctx.Done(): + case <-handler.Done(): + } + terminate() + }() + + // Start goroutine to handle connection lifecycle and cleanup + go func() { + if err := sshConn.Wait(); err != nil && err != io.EOF { + dlog.Server.Error(user, err) + } + s.stats.decrementConnections() + dlog.Server.Info(user, "Good bye Mister!") + terminate() + }() + + // Reply to indicate shell request was accepted + if err := req.Reply(true, nil); err != nil { + dlog.Server.Trace(user, fmt.Errorf("reply(true): %w", err)) + } +} + // Callback for SSH authentication. func (s *Server) Callback(c gossh.ConnMetadata, authPayload []byte) (*gossh.Permissions, error) { |
