From 8c0b8ad931045c70845f662238230edb81f8cd94 Mon Sep 17 00:00:00 2001 From: Alexander Neonxp Kiryukhin Date: Wed, 31 Dec 2025 14:15:42 +0300 Subject: =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20=D0=BA=D0=BE?= =?UTF-8?q?=D1=80=D1=80=D0=B5=D0=BA=D1=82=D0=BD=D1=83=D1=8E=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D1=83=20=D1=81=20=D1=82=D0=B5=D1=80=D0=BC?= =?UTF-8?q?=D0=B8=D0=BD=D0=B0=D0=BB=D0=BE=D0=BC=20=D0=B8=20=D0=B8=D1=81?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/server/client.go | 72 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 18 deletions(-) (limited to 'internal/server/client.go') diff --git a/internal/server/client.go b/internal/server/client.go index 698f7fa..8a23c8b 100644 --- a/internal/server/client.go +++ b/internal/server/client.go @@ -2,18 +2,30 @@ package server import ( "context" + "encoding/binary" "io" "log/slog" + "sync" - "go.neonxp.ru/qchat/internal/chat" + "golang.org/x/crypto/ssh" "golang.org/x/term" ) -func (s *Server) serveClient(ctx context.Context, rw io.ReadWriteCloser, user *chat.User) { - t := term.NewTerminal(rw, "[] ") - // TODO resize terminal to user size +func (s *Server) serveClient( + ctx context.Context, + conn *ssh.ServerConn, + channel ssh.Channel, + requests <-chan *ssh.Request, +) { + wg := sync.WaitGroup{} - go func() { + identify := conn.Permissions.ExtraData["identify"].(string) + user := s.chat.NewUser(conn.User(), identify) + + t := term.NewTerminal(channel, "[] ") + + // Обработка ввода пользователя + wg.Go(func() { for { select { case <-ctx.Done(): @@ -31,6 +43,8 @@ func (s *Server) serveClient(ctx context.Context, rw io.ReadWriteCloser, user *c slog.Error("failed read line", slog.Any("err", err)) } + conn.Close() + return } if len(line) == 0 { @@ -39,20 +53,42 @@ func (s *Server) serveClient(ctx context.Context, rw io.ReadWriteCloser, user *c s.chat.Input(ctx, user, line) } - }() + }) - for message := range user.Events { - switch message := message.(type) { - case chat.Message: - displayMessage(t, message, user) - case chat.SelfMessage: - displaySelfMessage(t, message) - case chat.SystemMessage: - displaySystemMessage(t, message) - case chat.UserJoined: - displayUserJoined(t, message) - case chat.UserLeft: - displayUserLeft(t, message) + wg.Go(func() { + for req := range requests { + switch req.Type { + case "pty-req": + termLen := req.Payload[3] + w, h := parseDims(req.Payload[termLen+4:]) + t.SetSize(w, h) + req.Reply(true, nil) + case "window-change": + w, h := parseDims(req.Payload) + t.SetSize(w, h) + req.Reply(true, nil) + case "shell": + req.Reply(len(req.Payload) == 0, nil) + default: + req.Reply(false, nil) + } + slog.Debug( + "req", + slog.String("type", req.Type), + slog.Bool("want-reply", req.WantReply), + slog.String("payload", string(req.Payload)), + ) } + }) + + for message := range user.Events { + processUserEvent(message, t, user) } } + +func parseDims(b []byte) (int, int) { + w := binary.BigEndian.Uint32(b) + h := binary.BigEndian.Uint32(b[4:]) + + return int(w), int(h) +} -- cgit v1.2.3