Skip to content

Commit f68d889

Browse files
henrybarretogustavosbarreto
authored andcommitted
refactor(ssh): use structure to represent seats instead of a counter
1 parent e64cf55 commit f68d889

File tree

3 files changed

+94
-31
lines changed

3 files changed

+94
-31
lines changed

ssh/server/channels/session.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ func DefaultSessionHandler() gliderssh.ChannelHandler {
262262

263263
switch req.Type {
264264
case ShellRequestType:
265-
if sess.Pty.Term != "" {
265+
if seat, ok := sess.Seats.Get(seat); ok && seat.HasPty {
266266
if err := sess.Announce(client.Channel); err != nil {
267267
logger.WithError(err).Warn("failed to get the namespace announcement")
268268
}
@@ -280,7 +280,7 @@ func DefaultSessionHandler() gliderssh.ChannelHandler {
280280
reject(nil, "failed to recover the session dimensions")
281281
}
282282

283-
sess.Pty = pty
283+
sess.Seats.SetPty(seat, true)
284284

285285
sess.Event(req.Type, pty, seat) //nolint:errcheck
286286
case WindowChangeRequestType:
@@ -290,9 +290,6 @@ func DefaultSessionHandler() gliderssh.ChannelHandler {
290290
reject(nil, "failed to recover the session dimensions")
291291
}
292292

293-
sess.Pty.Columns = dimensions.Columns
294-
sess.Pty.Rows = dimensions.Rows
295-
296293
sess.Event(req.Type, dimensions, seat) //nolint:errcheck
297294
case AuthRequestOpenSSHRequest:
298295
gliderssh.SetAgentRequested(ctx)

ssh/server/channels/utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func pipe(sess *session.Session, client gossh.Channel, agent gossh.Channel, seat
6767
Warning("failed to connect to session record endpoint")
6868
}
6969

70-
if err := sess.Recorded(); err != nil {
70+
if err := sess.Recorded(seat); err != nil {
7171
log.WithError(err).
7272
WithFields(log.Fields{"session": sess.UID, "sshid": sess.SSHID}).
7373
Warning("failed to set the session as recorded")

ssh/session/session.go

Lines changed: 91 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ type Data struct {
4040
Term string
4141
// TODO:
4242
Lookup map[string]string
43-
// Pty is the PTY dimension.
44-
Pty models.SSHPty
4543
// Handled check if the session is already handling a "shell", "exec" or a "subsystem".
4644
Handled bool
4745
}
@@ -156,15 +154,77 @@ type Session struct {
156154

157155
once *sync.Once
158156

159-
// Seat is a counter of how many passengers a session has. It's used on the record session feature.
157+
// Seats represents passengers a session.
160158
//
161159
// A passenger is, in a multiplexed SSH session, the subsequent SSH sessions that connect to the same server using
162160
// the already established master connection.
163-
Seat *atomic.Int32
161+
Seats Seats
164162

165163
Data
166164
}
167165

166+
// Seat represent a passenger in a session.
167+
type Seat struct {
168+
// HasPty is the status of pty on the seat.
169+
HasPty bool
170+
}
171+
172+
type Seats struct {
173+
// counter count atomically seats of a session.
174+
counter *atomic.Int32
175+
// Items represents the individual seat of a session.
176+
Items *sync.Map
177+
}
178+
179+
// NewSeats creates a new [Seats] defining initial values for internal properties.
180+
func NewSeats() Seats {
181+
return Seats{
182+
counter: new(atomic.Int32),
183+
Items: new(sync.Map),
184+
}
185+
}
186+
187+
// NewSeat creates a new seat inside seats.
188+
func (s *Seats) NewSeat() (int, error) {
189+
id := int(s.counter.Load())
190+
defer s.counter.Add(1)
191+
192+
s.Items.Store(id, &Seat{
193+
HasPty: false,
194+
})
195+
196+
return id, nil
197+
}
198+
199+
// Get gets a seat reference from their id.
200+
func (s *Seats) Get(seat int) (*Seat, bool) {
201+
loaded, ok := s.Items.Load(seat)
202+
if !ok {
203+
return nil, false
204+
}
205+
206+
item, ok := loaded.(*Seat)
207+
if !ok {
208+
return nil, false
209+
}
210+
211+
return item, true
212+
}
213+
214+
// SetPty sets a pty status to a seat from their id.
215+
func (s *Seats) SetPty(seat int, status bool) {
216+
item, ok := s.Get(seat)
217+
if !ok {
218+
log.Warn("failed to set pty because no seat was created before")
219+
220+
return
221+
}
222+
223+
item.HasPty = status
224+
225+
s.Items.Store(seat, item)
226+
}
227+
168228
// NewSession creates a new Session but differs from [New] as it only creates
169229
// the session without registering, connecting to the agent, etc.
170230
//
@@ -268,8 +328,8 @@ func NewSession(ctx gliderssh.Context, tunnel *httptunnel.Tunnel, cache cache.Ca
268328
Lookup: lookup,
269329
SSHID: fmt.Sprintf("%s@%s.%s", target.Username, domain, hostname),
270330
},
271-
once: new(sync.Once),
272-
Seat: new(atomic.Int32),
331+
once: new(sync.Once),
332+
Seats: NewSeats(),
273333
Agent: &Agent{
274334
Channels: make(map[int]*AgentChannel),
275335
},
@@ -403,16 +463,14 @@ func (s *Session) authenticate() error {
403463
})
404464
}
405465

406-
func (s *Session) Recorded() error {
466+
func (s *Session) Recorded(seat int) error {
407467
value := true
408468

409469
if !s.Namespace.Settings.SessionRecord {
410470
return errors.New("record is disable for this namespace")
411471
}
412472

413-
// NOTE: For now, [s.Pty] helps to indicate if the session is recorded.
414-
// TODO: After seats refactoring, [pty-req] event on session will indicate if it was recorded.
415-
if s.Pty.Columns == 0 && s.Pty.Rows == 0 {
473+
if seat, ok := s.Seats.Get(seat); !ok || !seat.HasPty {
416474
return errors.New("session won't be recorded because there is no pty")
417475
}
418476

@@ -578,15 +636,14 @@ func (s *Session) Auth(ctx gliderssh.Context, auth Auth) error {
578636
}
579637

580638
func (s *Session) NewSeat() (int, error) {
581-
seat := int(s.Seat.Load())
582-
defer s.Seat.Add(1)
583-
584-
return seat, nil
639+
return s.Seats.NewSeat()
585640
}
586641

587642
// Events register an event to the session.
588643
func (s *Session) Event(t string, data any, seat int) {
589644
if s.Events.Closed() {
645+
log.Debug("failed to save because events connection was closed")
646+
590647
return
591648
}
592649

@@ -601,6 +658,8 @@ func (s *Session) Event(t string, data any, seat int) {
601658

602659
func Event[D any](sess *Session, t string, data []byte, seat int) {
603660
if sess.Events.Closed() {
661+
log.Debug("failed to save because events connection was closed")
662+
604663
return
605664
}
606665

@@ -689,21 +748,28 @@ func (s *Session) Finish() (err error) {
689748
"uid": s.UID,
690749
}).Info("saving sessions as Asciinema files")
691750

692-
for seat := range s.Seat.Load() {
693-
if err := s.api.SaveSession(s.UID, int(seat)); err != nil {
694-
log.WithError(err).WithFields(log.Fields{
751+
s.Seats.Items.Range(func(key, value any) bool {
752+
id := key.(int)
753+
seat := value.(*Seat)
754+
755+
if seat.HasPty {
756+
if err := s.api.SaveSession(s.UID, id); err != nil {
757+
log.WithError(err).WithFields(log.Fields{
758+
"uid": s.UID,
759+
"seat": seat,
760+
}).Error("failed to save the session as Asciinema file")
761+
762+
return true
763+
}
764+
765+
log.WithFields(log.Fields{
695766
"uid": s.UID,
696767
"seat": seat,
697-
}).Error("failed to save the session as Asciinema file")
698-
699-
continue
768+
}).Info("asciinema file saved")
700769
}
701770

702-
log.WithFields(log.Fields{
703-
"uid": s.UID,
704-
"seat": seat,
705-
}).Info("asciinema file saved")
706-
}
771+
return true
772+
})
707773
}
708774

709775
log.WithFields(

0 commit comments

Comments
 (0)