package server import ( "context" "encoding/binary" "io" "log/slog" "sync" "golang.org/x/crypto/ssh" "golang.org/x/term" ) func (s *Server) serveClient( ctx context.Context, conn *ssh.ServerConn, channel ssh.Channel, requests <-chan *ssh.Request, ) { wg := sync.WaitGroup{} 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(): return default: } if user.CurrentChan != nil { t.SetPrompt("[" + user.CurrentChan.Name + "] ") } line, err := t.ReadLine() if err != nil { s.chat.RemoveUser(user) if err != io.EOF { slog.Error("failed read line", slog.Any("err", err)) } _ = conn.Close() return } if len(line) == 0 { continue } s.chat.Input(ctx, user, line) } }) 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) }