@@ -4,7 +4,13 @@ import stream = require('stream');
44import { V1Status } from './api' ;
55import { KubeConfig } from './config' ;
66
7- const protocols = [ 'v4.channel.k8s.io' , 'v3.channel.k8s.io' , 'v2.channel.k8s.io' , 'channel.k8s.io' ] ;
7+ const protocols = [
8+ 'v5.channel.k8s.io' ,
9+ 'v4.channel.k8s.io' ,
10+ 'v3.channel.k8s.io' ,
11+ 'v2.channel.k8s.io' ,
12+ 'channel.k8s.io' ,
13+ ] ;
814
915export type TextHandler = ( text : string ) => boolean ;
1016export type BinaryHandler = ( stream : number , buff : Buffer ) => boolean ;
@@ -17,12 +23,39 @@ export interface WebSocketInterface {
1723 ) : Promise < WebSocket . WebSocket > ;
1824}
1925
26+ export interface StreamInterface {
27+ stdin : stream . Readable ;
28+ stdout : stream . Writable ;
29+ stderr : stream . Writable ;
30+ }
31+
2032export class WebSocketHandler implements WebSocketInterface {
2133 public static readonly StdinStream : number = 0 ;
2234 public static readonly StdoutStream : number = 1 ;
2335 public static readonly StderrStream : number = 2 ;
2436 public static readonly StatusStream : number = 3 ;
2537 public static readonly ResizeStream : number = 4 ;
38+ public static readonly CloseStream : number = 255 ;
39+
40+ public static supportsClose ( protocol : string ) : boolean {
41+ return protocol === 'v5.channel.k8s.io' ;
42+ }
43+
44+ public static closeStream ( streamNum : number , streams : StreamInterface ) : void {
45+ console . log ( 'Closing stream: ' + streamNum ) ;
46+ switch ( streamNum ) {
47+ case WebSocketHandler . StdinStream :
48+ streams . stdin . pause ( ) ;
49+ break ;
50+ case WebSocketHandler . StdoutStream :
51+ console . log ( 'closing stdout' ) ;
52+ streams . stdout . end ( ) ;
53+ break ;
54+ case WebSocketHandler . StderrStream :
55+ streams . stderr . end ( ) ;
56+ break ;
57+ }
58+ }
2659
2760 public static handleStandardStreams (
2861 streamNum : number ,
@@ -39,6 +72,7 @@ export class WebSocketHandler implements WebSocketInterface {
3972 stderr . write ( buff ) ;
4073 } else if ( streamNum === WebSocketHandler . StatusStream ) {
4174 // stream closing.
75+ // Hacky, change tests to use the stream interface
4276 if ( stdout && stdout !== process . stdout ) {
4377 stdout . end ( ) ;
4478 }
@@ -69,6 +103,12 @@ export class WebSocketHandler implements WebSocketInterface {
69103 } ) ;
70104
71105 stdin . on ( 'end' , ( ) => {
106+ if ( WebSocketHandler . supportsClose ( ws . protocol ) ) {
107+ const buff = Buffer . alloc ( 2 ) ;
108+ buff . writeUint8 ( this . CloseStream , 0 ) ;
109+ buff . writeUint8 ( this . StdinStream , 1 ) ;
110+ ws . send ( buff ) ;
111+ }
72112 ws . close ( ) ;
73113 } ) ;
74114 // Keep the stream open
@@ -141,7 +181,16 @@ export class WebSocketHandler implements WebSocketInterface {
141181 // factory is really just for test injection
142182 public constructor (
143183 readonly config : KubeConfig ,
144- readonly socketFactory ?: ( uri : string , opts : WebSocket . ClientOptions ) => WebSocket . WebSocket ,
184+ readonly socketFactory ?: (
185+ uri : string ,
186+ protocols : string [ ] ,
187+ opts : WebSocket . ClientOptions ,
188+ ) => WebSocket . WebSocket ,
189+ readonly streams : StreamInterface = {
190+ stdin : process . stdin ,
191+ stdout : process . stdout ,
192+ stderr : process . stderr ,
193+ } ,
145194 ) { }
146195
147196 /**
@@ -173,7 +222,7 @@ export class WebSocketHandler implements WebSocketInterface {
173222
174223 return await new Promise < WebSocket . WebSocket > ( ( resolve , reject ) => {
175224 const client = this . socketFactory
176- ? this . socketFactory ( uri , opts )
225+ ? this . socketFactory ( uri , protocols , opts )
177226 : new WebSocket ( uri , protocols , opts ) ;
178227 let resolved = false ;
179228
@@ -191,11 +240,18 @@ export class WebSocketHandler implements WebSocketInterface {
191240 client . onmessage = ( { data } : { data : WebSocket . Data } ) => {
192241 // TODO: support ArrayBuffer and Buffer[] data types?
193242 if ( typeof data === 'string' ) {
243+ if ( data . charCodeAt ( 0 ) === WebSocketHandler . CloseStream ) {
244+ WebSocketHandler . closeStream ( data . charCodeAt ( 1 ) , this . streams ) ;
245+ }
194246 if ( textHandler && ! textHandler ( data ) ) {
195247 client . close ( ) ;
196248 }
197249 } else if ( data instanceof Buffer ) {
198- const streamNum = data . readInt8 ( 0 ) ;
250+ const streamNum = data . readUint8 ( 0 ) ;
251+ if ( streamNum === WebSocketHandler . CloseStream ) {
252+ console . log ( 'Closing stream!' ) ;
253+ WebSocketHandler . closeStream ( data . readInt8 ( 1 ) , this . streams ) ;
254+ }
199255 if ( binaryHandler && ! binaryHandler ( streamNum , data . subarray ( 1 ) ) ) {
200256 client . close ( ) ;
201257 }
0 commit comments