1- import { field } from '@coder/logger' ;
1+ import { field , logger , Logger } from '@coder/logger' ;
22import * as net from 'net' ;
33import { VSBuffer } from 'vs/base/common/buffer' ;
44import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net' ;
55import { NodeSocket , WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net' ;
66import { AuthRequest , ConnectionTypeRequest , HandshakeMessage } from 'vs/platform/remote/common/remoteAgentConnection' ;
7- import { logger } from 'vs/server/node/logger' ;
87
98export interface SocketOptions {
9+ /** The token is how we identify and connect to existing sessions. */
1010 readonly reconnectionToken : string ;
11+ /** Specifies that the client is trying to reconnect. */
1112 readonly reconnection : boolean ;
13+ /** If true assume this is not a web socket (always false for code-server). */
1214 readonly skipWebSocketFrames : boolean ;
15+ /** Whether to support compression (web socket only). */
1316 readonly permessageDeflate ?: boolean ;
17+ /**
18+ * Seed zlib with these bytes (web socket only). If parts of inflating was
19+ * done in a different zlib instance we need to pass all those bytes into zlib
20+ * otherwise the inflate might hit an inflated portion referencing a distance
21+ * too far back.
22+ */
1423 readonly inflateBytes ?: VSBuffer ;
15- readonly recordInflateBytes ?: boolean ;
1624}
1725
1826export class Protocol extends PersistentProtocol {
27+ private readonly logger : Logger ;
28+
1929 public constructor ( socket : net . Socket , public readonly options : SocketOptions ) {
2030 super (
2131 options . skipWebSocketFrames
@@ -24,9 +34,12 @@ export class Protocol extends PersistentProtocol {
2434 new NodeSocket ( socket ) ,
2535 options . permessageDeflate || false ,
2636 options . inflateBytes || null ,
27- options . recordInflateBytes || false ,
37+ // Always record inflate bytes if using permessage-deflate.
38+ options . permessageDeflate || false ,
2839 ) ,
2940 ) ;
41+
42+ this . logger = logger . named ( 'protocol' , field ( 'token' , this . options . reconnectionToken ) ) ;
3043 }
3144
3245 public getUnderlyingSocket ( ) : net . Socket {
@@ -40,24 +53,25 @@ export class Protocol extends PersistentProtocol {
4053 * Perform a handshake to get a connection request.
4154 */
4255 public handshake ( ) : Promise < ConnectionTypeRequest > {
43- logger . trace ( 'Protocol handshake' , field ( 'token' , this . options . reconnectionToken ) ) ;
56+ this . logger . debug ( 'Initiating handshake...' ) ;
4457 return new Promise ( ( resolve , reject ) => {
4558 const timeout = setTimeout ( ( ) => {
46- logger . error ( 'Handshake timed out' , field ( 'token' , this . options . reconnectionToken ) ) ;
47- reject ( new Error ( 'timed out' ) ) ;
59+ this . logger . debug ( 'Handshake timed out' ) ;
60+ reject ( new Error ( 'protocol handshake timed out' ) ) ;
4861 } , 10000 ) ; // Matches the client timeout.
4962
5063 const handler = this . onControlMessage ( ( rawMessage ) => {
5164 try {
5265 const raw = rawMessage . toString ( ) ;
53- logger . trace ( 'Protocol message' , field ( 'token' , this . options . reconnectionToken ) , field ( 'message' , raw ) ) ;
66+ this . logger . trace ( 'Got message' , field ( 'message' , raw ) ) ;
5467 const message = JSON . parse ( raw ) ;
5568 switch ( message . type ) {
5669 case 'auth' :
5770 return this . authenticate ( message ) ;
5871 case 'connectionType' :
5972 handler . dispose ( ) ;
6073 clearTimeout ( timeout ) ;
74+ this . logger . debug ( 'Handshake completed' ) ;
6175 return resolve ( message ) ;
6276 default :
6377 throw new Error ( 'Unrecognized message type' ) ;
@@ -90,10 +104,38 @@ export class Protocol extends PersistentProtocol {
90104 }
91105
92106 /**
93- * Send a handshake message. In the case of the extension host, it just sends
94- * back a debug port.
107+ * Send a handshake message. In the case of the extension host it should just
108+ * send a debug port.
95109 */
96- public sendMessage ( message : HandshakeMessage | { debugPort ?: number } ) : void {
110+ public sendMessage ( message : HandshakeMessage | { debugPort ?: number | null } ) : void {
97111 this . sendControl ( VSBuffer . fromString ( JSON . stringify ( message ) ) ) ;
98112 }
113+
114+ /**
115+ * Disconnect and dispose everything including the underlying socket.
116+ */
117+ public destroy ( reason ?: string ) : void {
118+ try {
119+ if ( reason ) {
120+ this . sendMessage ( { type : 'error' , reason } ) ;
121+ }
122+ // If still connected try notifying the client.
123+ this . sendDisconnect ( ) ;
124+ } catch ( error ) {
125+ // I think the write might fail if already disconnected.
126+ this . logger . warn ( error . message || error ) ;
127+ }
128+ this . dispose ( ) ; // This disposes timers and socket event handlers.
129+ this . getSocket ( ) . dispose ( ) ; // This will destroy() the socket.
130+ }
131+
132+ /**
133+ * Get inflateBytes in base64 format from the current socket.
134+ */
135+ public get inflateBytes ( ) : string | undefined {
136+ const socket = this . getSocket ( ) ;
137+ return socket instanceof WebSocketNodeSocket
138+ ? Buffer . from ( socket . recordedInflateBytes . buffer ) . toString ( 'base64' )
139+ : undefined ;
140+ }
99141}
0 commit comments