11import Bluebird from 'bluebird'
22import debugModule from 'debug'
33import _ from 'lodash'
4+ import { ChildProcess } from 'child_process'
45
56const chromeRemoteInterface = require ( 'chrome-remote-interface' )
67const errors = require ( '../errors' )
@@ -85,41 +86,40 @@ const getMajorMinorVersion = (version: string): Version => {
8586
8687const maybeDebugCdpMessages = ( cri ) => {
8788 if ( debugVerboseReceive . enabled ) {
88- cri . _ws . on ( 'message' , ( data ) => {
89- data = _
90- . chain ( JSON . parse ( data ) )
91- . tap ( ( data ) => {
92- ( [
93- 'params.data' , // screencast frame data
94- 'result.data' , // screenshot data
95- ] ) . forEach ( ( truncatablePath ) => {
96- const str = _ . get ( data , truncatablePath )
97-
98- if ( ! _ . isString ( str ) ) {
99- return
100- }
89+ const handleMessage = cri . _handleMessage
10190
102- _ . set ( data , truncatablePath , _ . truncate ( str , {
103- length : 100 ,
104- omission : `... [truncated string of total bytes: ${ str . length } ]` ,
105- } ) )
106- } )
91+ cri . _handleMessage = ( message ) => {
92+ const formatted = _ . cloneDeep ( message )
93+
94+ ; ( [
95+ 'params.data' , // screencast frame data
96+ 'result.data' , // screenshot data
97+ ] ) . forEach ( ( truncatablePath ) => {
98+ const str = _ . get ( formatted , truncatablePath )
99+
100+ if ( ! _ . isString ( str ) ) {
101+ return
102+ }
107103
108- return data
104+ _ . set ( formatted , truncatablePath , _ . truncate ( str , {
105+ length : 100 ,
106+ omission : `... [truncated string of total bytes: ${ str . length } ]` ,
107+ } ) )
109108 } )
110- . value ( )
111109
112- debugVerboseReceive ( 'received CDP message %o' , data )
113- } )
110+ debugVerboseReceive ( 'received CDP message %o' , formatted )
111+
112+ return handleMessage . call ( cri , message )
113+ }
114114 }
115115
116116 if ( debugVerboseSend . enabled ) {
117- const send = cri . _ws . send
117+ const send = cri . _send
118118
119- cri . _ws . send = ( data , callback ) => {
119+ cri . _send = ( data , callback ) => {
120120 debugVerboseSend ( 'sending CDP command %o' , JSON . parse ( data ) )
121121
122- return send . call ( cri . _ws , data , callback )
122+ return send . call ( cri , data , callback )
123123 }
124124 }
125125}
@@ -135,17 +135,36 @@ export { chromeRemoteInterface }
135135
136136type DeferredPromise = { resolve : Function , reject : Function }
137137
138- export const create = Bluebird . method ( ( target : websocketUrl , onAsynchronousError : Function ) : Bluebird < CRIWrapper > => {
138+ type CreateOpts = {
139+ target ?: websocketUrl
140+ process ?: ChildProcess
141+ }
142+
143+ type Message = {
144+ method : CRI . Command
145+ params ?: any
146+ sessionId ?: string
147+ }
148+
149+ export const create = Bluebird . method ( ( opts : CreateOpts , onAsynchronousError : Function ) : Bluebird < CRIWrapper > => {
139150 const subscriptions : { eventName : CRI . EventName , cb : Function } [ ] = [ ]
140- let enqueuedCommands : { command : CRI . Command , params : any , p : DeferredPromise } [ ] = [ ]
151+ let enqueuedCommands : { message : Message , params : any , p : DeferredPromise } [ ] = [ ]
141152
142153 let closed = false // has the user called .close on this?
143154 let connected = false // is this currently connected to CDP?
144155
145156 let cri
146157 let client : CRIWrapper
158+ let sessionId : string | undefined
147159
148160 const reconnect = ( ) => {
161+ if ( opts . process ) {
162+ // reconnecting doesn't make sense for stdio
163+ onAsynchronousError ( errors . get ( 'CDP_STDIO_ERROR' ) )
164+
165+ return
166+ }
167+
149168 debug ( 'disconnected, attempting to reconnect... %o' , { closed } )
150169
151170 connected = false
@@ -162,7 +181,7 @@ export const create = Bluebird.method((target: websocketUrl, onAsynchronousError
162181 } )
163182
164183 enqueuedCommands . forEach ( ( cmd ) => {
165- cri . send ( cmd . command , cmd . params )
184+ cri . sendRaw ( cmd . message )
166185 . then ( cmd . p . resolve , cmd . p . reject )
167186 } )
168187
@@ -176,10 +195,10 @@ export const create = Bluebird.method((target: websocketUrl, onAsynchronousError
176195 const connect = ( ) => {
177196 cri ?. close ( )
178197
179- debug ( 'connecting %o' , { target } )
198+ debug ( 'connecting %o' , opts )
180199
181200 return chromeRemoteInterface ( {
182- target ,
201+ ... opts ,
183202 local : true ,
184203 } )
185204 . then ( ( newCri ) => {
@@ -193,6 +212,46 @@ export const create = Bluebird.method((target: websocketUrl, onAsynchronousError
193212
194213 // @see https://github.com/cyrus-and/chrome-remote-interface/issues/72
195214 cri . _notifier . on ( 'disconnect' , reconnect )
215+
216+ if ( opts . process ) {
217+ // if using stdio, we need to find the target before declaring the connection complete
218+ return findTarget ( )
219+ }
220+
221+ return
222+ } )
223+ }
224+
225+ const findTarget = ( ) => {
226+ debug ( 'finding CDP target...' )
227+
228+ return new Bluebird < void > ( ( resolve , reject ) => {
229+ const isAboutBlank = ( target ) => target . type === 'page' && target . url === 'about:blank'
230+
231+ const attachToTarget = _ . once ( ( { targetId } ) => {
232+ debug ( 'attaching to target %o' , { targetId } )
233+ cri . send ( 'Target.attachToTarget' , {
234+ targetId,
235+ flatten : true , // enable selecting via sessionId
236+ } ) . then ( ( result ) => {
237+ debug ( 'attached to target %o' , result )
238+ sessionId = result . sessionId
239+ resolve ( )
240+ } ) . catch ( reject )
241+ } )
242+
243+ cri . send ( 'Target.setDiscoverTargets' , { discover : true } )
244+ . then ( ( ) => {
245+ cri . on ( 'Target.targetCreated' , ( target ) => {
246+ if ( isAboutBlank ( target ) ) {
247+ attachToTarget ( target )
248+ }
249+ } )
250+
251+ return cri . send ( 'Target.getTargets' )
252+ . then ( ( { targetInfos } ) => targetInfos . filter ( isAboutBlank ) . map ( attachToTarget ) )
253+ } )
254+ . catch ( reject )
196255 } )
197256 }
198257
@@ -222,14 +281,23 @@ export const create = Bluebird.method((target: websocketUrl, onAsynchronousError
222281 ensureMinimumProtocolVersion,
223282 getProtocolVersion,
224283 send : Bluebird . method ( ( command : CRI . Command , params ?: object ) => {
284+ const message : Message = {
285+ method : command ,
286+ params,
287+ }
288+
289+ if ( sessionId ) {
290+ message . sessionId = sessionId
291+ }
292+
225293 const enqueue = ( ) => {
226294 return new Bluebird ( ( resolve , reject ) => {
227- enqueuedCommands . push ( { command , params, p : { resolve, reject } } )
295+ enqueuedCommands . push ( { message , params, p : { resolve, reject } } )
228296 } )
229297 }
230298
231299 if ( connected ) {
232- return cri . send ( command , params )
300+ return cri . sendRaw ( message )
233301 . catch ( ( err ) => {
234302 if ( ! WEBSOCKET_NOT_OPEN_RE . test ( err . message ) ) {
235303 throw err
0 commit comments