5
5
"sync"
6
6
7
7
"github.com/Masterminds/semver"
8
- gliderssh "github.com/gliderlabs/ssh"
9
8
"github.com/shellhub-io/shellhub/pkg/envs"
10
9
"github.com/shellhub-io/shellhub/pkg/models"
11
10
"github.com/shellhub-io/shellhub/ssh/session"
@@ -14,88 +13,48 @@ import (
14
13
)
15
14
16
15
type Recorder struct {
17
- queue chan string
16
+ // channels is the source of data read, recorded and redirected to client.
18
17
channel gossh.Channel
18
+ // session is the session between Agent and Client.
19
+ session * session.Session
20
+ // seat is the current identifier of session's.
21
+ seat int
19
22
}
20
23
21
- func NewRecorder (channel gossh.Channel , sess * session.Session , camera * session.Camera , seat int ) (io.WriteCloser , error ) {
22
- // NOTE: The queue's size is a random number.
23
- queue := make (chan string , 100 )
24
-
25
- go func () {
26
- for {
27
- msg , ok := <- queue
28
- if ! ok {
29
- log .WithFields (log.Fields {"session" : sess .UID , "sshid" : sess .SSHID }).
30
- Warning ("recorder queue is closed" )
31
-
32
- return
33
- }
34
-
35
- if err := camera .WriteFrame (& models.SessionRecorded { //nolint:errcheck
36
- UID : sess .UID ,
37
- Seat : seat ,
38
- Namespace : sess .Lookup ["domain" ],
39
- Message : msg ,
40
- Width : int (sess .Pty .Columns ),
41
- Height : int (sess .Pty .Rows ),
42
- }); err != nil {
43
- log .WithError (err ).
44
- WithFields (log.Fields {"session" : sess .UID , "sshid" : sess .SSHID }).
45
- Warning ("failed to send the session frame to record" )
46
-
47
- // NOTE: When a frame isn't sent correctly, we stop the writing loop, only reading from the queue,
48
- // and discarding the messages to avoid stuck the go routine.
49
- break
50
- }
51
- }
52
-
53
- for {
54
- // NOTE: Reads the queue and discards the data to avoid stuck the go routine.
55
- if _ , ok := <- queue ; ! ok {
56
- log .WithFields (log.Fields {"session" : sess .UID , "sshid" : sess .SSHID }).
57
- Warning ("recorder queue is closed" )
58
-
59
- return
60
- }
61
- }
62
- }()
63
-
24
+ func NewRecorder (channel gossh.Channel , session * session.Session , seat int ) (io.WriteCloser , error ) {
64
25
return & Recorder {
65
- queue : queue ,
66
26
channel : channel ,
27
+ session : session ,
28
+ seat : seat ,
67
29
}, nil
68
30
}
69
31
70
- // record enqueues a session frame to be recorded. If the queue is closed, nothing is done.
71
- func (c * Recorder ) record (msg string ) {
72
- select {
73
- case c .queue <- msg :
74
- default :
75
- log .Trace ("the message couldn't sent to the record queue" )
76
- }
77
- }
32
+ // PtyOutputEventType is the event's type for an output.
33
+ const PtyOutputEventType = "pty-output"
78
34
79
- func (c * Recorder ) Write (data []byte ) (int , error ) {
80
- read , err := c .channel .Write (data )
35
+ func (c * Recorder ) Write (output []byte ) (int , error ) {
36
+ read , err := c .channel .Write (output )
81
37
if err != nil {
82
38
return read , err
83
39
}
84
40
85
- c .record (string (data ))
41
+ // NOTE: Writes the event into the event stream to be processed and send to target endpoint.
42
+ c .session .Event (PtyOutputEventType , & models.SessionRecorded {
43
+ UID : c .session .UID ,
44
+ Output : string (output ),
45
+ }, c .seat )
86
46
87
47
return read , nil
88
48
}
89
49
50
+ // Close closes the internal channel.
90
51
func (c * Recorder ) Close () error {
91
- close (c .queue )
92
-
93
52
return c .channel .CloseWrite ()
94
53
}
95
54
96
55
// pipe function pipes data between client and agent, and vice versa, recording each frame when ShellHub instance are
97
56
// Cloud or Enterprise.
98
- func pipe (ctx gliderssh. Context , sess * session.Session , client gossh.Channel , agent gossh.Channel , seat int ) {
57
+ func pipe (sess * session.Session , client gossh.Channel , agent gossh.Channel , seat int ) {
99
58
defer log .
100
59
WithFields (log.Fields {"session" : sess .UID , "sshid" : sess .SSHID }).
101
60
Trace ("data pipe between client and agent has done" )
@@ -110,23 +69,10 @@ func pipe(ctx gliderssh.Context, sess *session.Session, client gossh.Channel, ag
110
69
defer wg .Done ()
111
70
112
71
if envs .IsEnterprise () || envs .IsCloud () {
113
- recordURL := ctx .Value ("RECORD_URL" ).(string )
114
- if recordURL == "" {
115
- log .WithFields (log.Fields {"session" : sess .UID , "sshid" : sess .SSHID , "record_url" : recordURL }).
116
- Warning ("failed to start session's record because the record URL is empty" )
117
-
118
- goto normal
119
- }
120
-
121
- camera , err := sess .Record (ctx , recordURL , seat )
122
- if err != nil {
123
- goto normal
124
- }
125
-
126
- recorder , err := NewRecorder (client , sess , camera , seat )
72
+ recorder , err := NewRecorder (client , sess , seat )
127
73
if err != nil {
128
74
log .WithError (err ).
129
- WithFields (log.Fields {"session" : sess .UID , "sshid" : sess .SSHID , "record_url" : recordURL }).
75
+ WithFields (log.Fields {"session" : sess .UID , "sshid" : sess .SSHID }).
130
76
Warning ("failed to connect to session record endpoint" )
131
77
132
78
goto normal
0 commit comments