package lifecycle import ( "errors" "io" "net" portUtil "tunnel_pls/internal/port" "tunnel_pls/session/slug" "tunnel_pls/types" "golang.org/x/crypto/ssh" ) type Interaction interface { SendMessage(string) } type Forwarder interface { Close() error GetTunnelType() types.TunnelType GetForwardedPort() uint16 } type Lifecycle struct { status types.Status conn ssh.Conn channel ssh.Channel interaction Interaction forwarder Forwarder slugManager slug.Manager unregisterClient func(slug string) } func NewLifecycle(conn ssh.Conn, interaction Interaction, forwarder Forwarder, slugManager slug.Manager) *Lifecycle { return &Lifecycle{ status: "", conn: conn, channel: nil, interaction: interaction, forwarder: forwarder, slugManager: slugManager, unregisterClient: nil, } } func (l *Lifecycle) SetUnregisterClient(unregisterClient func(slug string)) { l.unregisterClient = unregisterClient } type SessionLifecycle interface { Close() error SetStatus(status types.Status) GetConnection() ssh.Conn GetChannel() ssh.Channel SetChannel(channel ssh.Channel) SetUnregisterClient(unregisterClient func(slug string)) } func (l *Lifecycle) GetChannel() ssh.Channel { return l.channel } func (l *Lifecycle) SetChannel(channel ssh.Channel) { l.channel = channel } func (l *Lifecycle) GetConnection() ssh.Conn { return l.conn } func (l *Lifecycle) SetStatus(status types.Status) { l.status = status } func (l *Lifecycle) Close() error { err := l.forwarder.Close() if err != nil && !errors.Is(err, net.ErrClosed) { return err } if l.channel != nil { err := l.channel.Close() if err != nil && !errors.Is(err, io.EOF) { return err } } if l.conn != nil { err := l.conn.Close() if err != nil && !errors.Is(err, net.ErrClosed) { return err } } clientSlug := l.slugManager.Get() if clientSlug != "" { l.unregisterClient(clientSlug) } if l.forwarder.GetTunnelType() == types.TCP { err := portUtil.Default.SetPortStatus(l.forwarder.GetForwardedPort(), false) if err != nil { return err } } return nil }