@@ -39,7 +39,13 @@ class DirectWatcher implements Abortable, Watcher {
39
39
private jobs : ( Abortable & FlowControllable ) [ ] = [ ]
40
40
41
41
/** We only seem to get these once */
42
- private columnDefinitions : MetaTable [ 'columnDefinitions' ]
42
+ private bodyColumnDefinitions : MetaTable [ 'columnDefinitions' ]
43
+ private footerColumnDefinitions : {
44
+ lastSeenColumnIdx : number
45
+ objectColumnIdx : number
46
+ messageColumnIdx : number
47
+ nameColumnIdx : number
48
+ }
43
49
44
50
// eslint-disable-next-line no-useless-constructor
45
51
public constructor (
@@ -104,20 +110,11 @@ class DirectWatcher implements Abortable, Watcher {
104
110
105
111
/** Format a MetaTable of events into a string[] */
106
112
private formatFooter ( table : MetaTable ) : string [ ] {
107
- const lastSeenColumnIdx = table . columnDefinitions . findIndex ( _ => / L a s t S e e n / i. test ( _ . name ) )
108
- const objectColumnIdx = table . columnDefinitions . findIndex ( _ => / O b j e c t / i. test ( _ . name ) )
109
- const messageColumnIdx = table . columnDefinitions . findIndex ( _ => / M e s s a g e / i. test ( _ . name ) )
110
- const nameColumnIdx = table . columnDefinitions . findIndex ( _ => / N a m e / i. test ( _ . name ) )
111
-
112
- if ( lastSeenColumnIdx < 0 ) {
113
- console . error ( 'Unable to format event footer, due to missing Last Seen column' , table )
114
- } else if ( objectColumnIdx < 0 ) {
115
- console . error ( 'Unable to format event footer, due to missing Object column' , table )
116
- } else if ( messageColumnIdx < 0 ) {
117
- console . error ( 'Unable to format event footer, due to missing Message column' , table )
118
- } else if ( nameColumnIdx < 0 ) {
119
- console . error ( 'Unable to format event footer, due to missing Name column' , table )
113
+ if ( ! this . footerColumnDefinitions ) {
114
+ console . error ( 'Dropping footer update, due to missing column definitions' )
120
115
} else {
116
+ const { lastSeenColumnIdx, objectColumnIdx, messageColumnIdx, nameColumnIdx } = this . footerColumnDefinitions
117
+
121
118
return this . filterFooterRows ( table , nameColumnIdx ) . map ( _ => {
122
119
const lastSeen = _ . cells [ lastSeenColumnIdx ]
123
120
const involvedObjectName = _ . cells [ objectColumnIdx ]
@@ -132,8 +129,44 @@ class DirectWatcher implements Abortable, Watcher {
132
129
}
133
130
}
134
131
132
+ /** We pre-process the columnDefinitions for the events, to pick out the column indices of interest. */
133
+ private initFooterColumnDefinitions ( columnDefinitions : MetaTable [ 'columnDefinitions' ] ) {
134
+ const indices = columnDefinitions . reduce (
135
+ ( indices , _ , idx ) => {
136
+ if ( _ . name === 'Last Seen' ) {
137
+ indices . lastSeenColumnIdx = idx
138
+ } else if ( _ . name === 'Object' ) {
139
+ indices . objectColumnIdx = idx
140
+ } else if ( _ . name === 'Message' ) {
141
+ indices . messageColumnIdx = idx
142
+ } else if ( _ . name === 'Name' ) {
143
+ indices . nameColumnIdx = idx
144
+ }
145
+ return indices
146
+ } ,
147
+ { lastSeenColumnIdx : - 1 , objectColumnIdx : - 1 , messageColumnIdx : - 1 , nameColumnIdx : - 1 }
148
+ )
149
+
150
+ const { lastSeenColumnIdx, objectColumnIdx, messageColumnIdx, nameColumnIdx } = indices
151
+ if ( lastSeenColumnIdx < 0 ) {
152
+ console . error ( 'Unable to process footer column definitions, due to missing Last Seen column' , columnDefinitions )
153
+ } else if ( objectColumnIdx < 0 ) {
154
+ console . error ( 'Unable to process footer column definitions, due to missing Object column' , columnDefinitions )
155
+ } else if ( messageColumnIdx < 0 ) {
156
+ console . error ( 'Unable to process footer column definitions, due to missing Message column' , columnDefinitions )
157
+ } else if ( nameColumnIdx < 0 ) {
158
+ console . error ( 'Unable to process footer column definitions, due to missing Name column' , columnDefinitions )
159
+ } else {
160
+ this . footerColumnDefinitions = indices
161
+ }
162
+ }
163
+
135
164
/** This will be called by the event streamer when it has new data */
136
- private onEventData ( update : WatchUpdate ) {
165
+ private onEventData ( update : Pick < WatchUpdate , 'object' > ) {
166
+ if ( ! this . footerColumnDefinitions && update . object . columnDefinitions ) {
167
+ this . initFooterColumnDefinitions ( update . object . columnDefinitions )
168
+ }
169
+
137
170
this . pusher . footer ( this . formatFooter ( update . object ) )
138
171
}
139
172
@@ -142,7 +175,7 @@ class DirectWatcher implements Abortable, Watcher {
142
175
// first: we need to fetch the initial table (so that we have a resourceVersion)
143
176
const events = ( await fetchFile ( this . args . REPL , this . formatEventUrl ( ) , headersForTableRequest ) ) [ 0 ] as MetaTable
144
177
if ( isMetaTable ( events ) ) {
145
- this . pusher . footer ( this . formatFooter ( events ) )
178
+ this . onEventData ( { object : events } )
146
179
147
180
// second: now we can start the streamer against that resourceVersion
148
181
const watchUrl = this . formatEventUrl ( { resourceVersion : events . metadata . resourceVersion } )
@@ -162,6 +195,7 @@ class DirectWatcher implements Abortable, Watcher {
162
195
}
163
196
}
164
197
198
+ /** This is the stream management bits for the body */
165
199
private mgmt ( onInit : Arguments [ 'execOptions' ] [ 'onInit' ] ) {
166
200
return {
167
201
onInit,
@@ -190,8 +224,8 @@ class DirectWatcher implements Abortable, Watcher {
190
224
191
225
/** This will be called whenever the streamer has data for us. */
192
226
private onData ( update : WatchUpdate ) {
193
- if ( ! update . object . columnDefinitions && this . columnDefinitions ) {
194
- update . object . columnDefinitions = this . columnDefinitions
227
+ if ( ! update . object . columnDefinitions && this . bodyColumnDefinitions ) {
228
+ update . object . columnDefinitions = this . bodyColumnDefinitions
195
229
}
196
230
197
231
if ( ! update . object . columnDefinitions ) {
@@ -200,9 +234,9 @@ class DirectWatcher implements Abortable, Watcher {
200
234
}
201
235
202
236
let sendHeaders = false
203
- if ( ! this . columnDefinitions ) {
237
+ if ( ! this . bodyColumnDefinitions ) {
204
238
sendHeaders = true
205
- this . columnDefinitions = update . object . columnDefinitions
239
+ this . bodyColumnDefinitions = update . object . columnDefinitions
206
240
}
207
241
208
242
setTimeout ( async ( ) => {
@@ -225,6 +259,12 @@ class DirectWatcher implements Abortable, Watcher {
225
259
}
226
260
}
227
261
262
+ /**
263
+ * If possible, turn a table into a Table & Watchable. If the given
264
+ * `table` does not have a `resourceVersion` attribute, this mapping
265
+ * will not be possible.
266
+ *
267
+ */
228
268
export default async function makeWatchable (
229
269
args : Arguments < KubeOptions > ,
230
270
kind : string | Promise < string > ,
0 commit comments