@@ -12,14 +12,20 @@ import (
12
12
"github.com/gorilla/mux"
13
13
"github.com/rockbears/log"
14
14
15
- "github.com/ovh/cds/engine/cdn/item"
16
15
"github.com/ovh/cds/engine/cdn/redis"
17
16
"github.com/ovh/cds/engine/cdn/storage"
18
17
"github.com/ovh/cds/engine/service"
19
18
"github.com/ovh/cds/engine/websocket"
20
19
"github.com/ovh/cds/sdk"
21
20
)
22
21
22
+ type WSLine struct {
23
+ Number int64 `json:"number"`
24
+ Value string `json:"value"`
25
+ Since int64 `json:"since,omitempty"`
26
+ ApiRefHash string `json:"api_ref_hash"`
27
+ }
28
+
23
29
func (s * Service ) getItemLogsStreamHandler () service.Handler {
24
30
return func (ctx context.Context , w http.ResponseWriter , r * http.Request ) error {
25
31
c , err := websocket .Upgrader .Upgrade (w , r , nil )
@@ -29,8 +35,8 @@ func (s *Service) getItemLogsStreamHandler() service.Handler {
29
35
}
30
36
defer c .Close () //nolint
31
37
32
- jwt := ctx .Value (service .ContextJWT ).(* jwt.Token )
33
- claims := jwt .Claims .(* sdk.AuthSessionJWTClaims )
38
+ jwtToken := ctx .Value (service .ContextJWT ).(* jwt.Token )
39
+ claims := jwtToken .Claims .(* sdk.AuthSessionJWTClaims )
34
40
sessionID := claims .StandardClaims .Id
35
41
36
42
wsClient := websocket .NewClient (c )
@@ -39,7 +45,23 @@ func (s *Service) getItemLogsStreamHandler() service.Handler {
39
45
defer s .WSServer .RemoveClient (wsClient .UUID ())
40
46
41
47
wsClient .OnMessage (func (m []byte ) {
42
- if err := wsClientData .UpdateFilter (m ); err != nil {
48
+ var filter sdk.CDNStreamFilter
49
+ if err := sdk .JSONUnmarshal (m , & filter ); err != nil {
50
+ ctx = sdk .ContextWithStacktrace (ctx , err )
51
+ log .Warn (ctx , err .Error ())
52
+ return
53
+ }
54
+
55
+ // Load last running step
56
+ var iuID string
57
+ if filter .JobRunID > 0 {
58
+ iu , _ := storage .LoadLastItemUnitByJobUnitType (ctx , s .Mapper , s .mustDBWithCtx (ctx ), s .Units .LogsBuffer ().ID (), filter .JobRunID , sdk .CDNTypeItemStepLog )
59
+ if iu != nil {
60
+ iuID = iu .ID
61
+ }
62
+ }
63
+
64
+ if err := wsClientData .UpdateFilter (filter , iuID ); err != nil {
43
65
ctx = sdk .ContextWithStacktrace (ctx , err )
44
66
log .Warn (ctx , err .Error ())
45
67
return
@@ -92,38 +114,45 @@ func (s *Service) sendLogsToWSClient(ctx context.Context, wsClient websocket.Cli
92
114
return nil
93
115
}
94
116
95
- if wsClientData .itemUnit == nil {
96
- it , err := item .LoadByAPIRefHashAndType (ctx , s .Mapper , s .mustDBWithCtx (ctx ), wsClientData .itemFilter .APIRef , wsClientData .itemFilter .ItemType )
97
- if err != nil {
98
- // Catch not found error as the item can be created after the client stream subscription
99
- if sdk .ErrorIs (err , sdk .ErrNotFound ) {
100
- log .Debug (ctx , "sendLogsToWSClient> can't found item with type %s and ref %s for client %s: %+v" , wsClientData .itemFilter .ItemType , wsClientData .itemFilter .APIRef , wsClient .UUID (), err )
101
- return nil
117
+ if wsClientData .itemUnitsData == nil {
118
+ wsClientData .itemUnitsData = make (map [string ]ItemUnitClientData )
119
+ }
120
+
121
+ for k := range wsClientData .itemUnitsData {
122
+ if wsClientData .itemUnitsData [k ].itemUnit == nil {
123
+ iu , err := storage .LoadItemUnitByID (ctx , s .Mapper , s .mustDBWithCtx (ctx ), k )
124
+ if err != nil {
125
+ return err
102
126
}
103
- return nil
104
- }
105
127
106
- if err := s .itemAccessCheck (ctx , * it ); err != nil {
107
- var projectKey , workflow string
108
- logRef , has := it .GetCDNLogApiRef ()
109
- if has {
110
- projectKey = logRef .ProjectKey
111
- workflow = logRef .WorkflowName
128
+ if err := s .itemAccessCheck (ctx , * iu .Item ); err != nil {
129
+ var projectKey , workflow string
130
+ logRef , has := iu .Item .GetCDNLogApiRef ()
131
+ if has {
132
+ projectKey = logRef .ProjectKey
133
+ workflow = logRef .WorkflowName
134
+ }
135
+ return sdk .WrapError (err , "client %s can't access logs for workflow %s/%s" , wsClient .UUID (), projectKey , workflow )
136
+ }
137
+ wsClientData .itemUnitsData [k ] = ItemUnitClientData {
138
+ itemUnit : iu ,
139
+ scoreNextLineToSend : wsClientData .itemUnitsData [k ].scoreNextLineToSend ,
112
140
}
113
- return sdk .WrapError (err , "client %s can't access logs for workflow %s/%s" , wsClient .UUID (), projectKey , workflow )
114
141
}
115
142
116
- iu , err := storage .LoadItemUnitByUnit (ctx , s .Mapper , s .mustDBWithCtx (ctx ), s .Units .LogsBuffer ().ID (), it .ID )
117
- if err != nil {
143
+ if err := s .sendStepLog (ctx , wsClient , wsClientData , k ); err != nil {
118
144
return err
119
145
}
120
146
121
- wsClientData .itemUnit = iu
122
147
}
148
+ return nil
149
+ }
123
150
124
- log .Debug (ctx , "getItemLogsStreamHandler> send log to client %s from %d" , wsClient .UUID (), wsClientData .scoreNextLineToSend )
151
+ func (s * Service ) sendStepLog (ctx context.Context , wsClient websocket.Client , wsClientData * websocketClientData , mapIndex string ) error {
152
+ data := wsClientData .itemUnitsData [mapIndex ]
125
153
126
- rc , err := s .Units .LogsBuffer ().NewAdvancedReader (ctx , * wsClientData .itemUnit , sdk .CDNReaderFormatJSON , wsClientData .scoreNextLineToSend , 100 , 0 )
154
+ log .Debug (ctx , "getItemLogsStreamHandler> send log to client %s from %d" , wsClient .UUID (), data .scoreNextLineToSend )
155
+ rc , err := s .Units .LogsBuffer ().NewAdvancedReader (ctx , * data .itemUnit , sdk .CDNReaderFormatJSON , data .scoreNextLineToSend , 100 , 0 )
127
156
if err != nil {
128
157
return err
129
158
}
@@ -138,26 +167,31 @@ func (s *Service) sendLogsToWSClient(ctx context.Context, wsClient websocket.Cli
138
167
}
139
168
140
169
log .Debug (ctx , "getItemLogsStreamHandler> iterate over %d lines to send for client %s" , len (lines ), wsClient .UUID ())
141
- oldNextLineToSend := wsClientData .scoreNextLineToSend
170
+ oldNextLineToSend := data .scoreNextLineToSend
142
171
for i := range lines {
143
- if wsClientData .scoreNextLineToSend > 0 && wsClientData .scoreNextLineToSend != lines [i ].Number {
172
+ if data .scoreNextLineToSend > 0 && data .scoreNextLineToSend != lines [i ].Number {
144
173
break
145
174
}
146
- if err := wsClient .Send (lines [i ]); err != nil {
175
+
176
+ if err := wsClient .Send (WSLine {
177
+ Number : lines [i ].Number ,
178
+ Value : lines [i ].Value ,
179
+ Since : lines [i ].Since ,
180
+ ApiRefHash : data .itemUnit .Item .APIRefHash ,
181
+ }); err != nil {
147
182
return err
148
183
}
149
- if wsClientData .scoreNextLineToSend < 0 {
150
- wsClientData .scoreNextLineToSend = lines [i ].Number + 1
184
+ if data .scoreNextLineToSend < 0 {
185
+ data .scoreNextLineToSend = lines [i ].Number + 1
151
186
} else {
152
- wsClientData .scoreNextLineToSend ++
187
+ data .scoreNextLineToSend ++
153
188
}
154
189
}
155
-
190
+ wsClientData . itemUnitsData [ mapIndex ] = data
156
191
// If all the lines were sent, we can trigger another update, if only one line was send do not trigger an update wait for next event from broker
157
- if len (lines ) > 1 && (oldNextLineToSend > 0 || int (wsClientData .scoreNextLineToSend - oldNextLineToSend ) == len (lines )) {
192
+ if len (lines ) > 1 && (oldNextLineToSend > 0 || int (data .scoreNextLineToSend - oldNextLineToSend ) == len (lines )) {
158
193
wsClientData .TriggerUpdate ()
159
194
}
160
-
161
195
return nil
162
196
}
163
197
0 commit comments