This repository has been archived by the owner on Dec 13, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 682
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
iwdp debugger #1 -- introduce end to end iwdp debugger
Reviewed By: jgebhardt Differential Revision: D3963634 fbshipit-source-id: 7cbfff8e4f24ec39270cef080c458cc125517372
- Loading branch information
1 parent
205960a
commit 4de9360
Showing
13 changed files
with
517 additions
and
0 deletions.
There are no files selected for viewing
114 changes: 114 additions & 0 deletions
114
pkg/nuclide-debugger-iwdp-rpc/lib/IwdpDebuggerService.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
'use babel'; | ||
/* @flow */ | ||
|
||
/* | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
*/ | ||
|
||
import {CompositeDisposable} from 'event-kit'; | ||
import {logger} from './logger'; | ||
import WS from 'ws'; | ||
import xfetch from '../../commons-node/xfetch'; | ||
import fsPromise from '../../commons-node/fsPromise'; | ||
|
||
import type {ConnectableObservable} from 'rxjs'; | ||
|
||
const {log} = logger; | ||
|
||
let lastServiceObjectDispose = null; | ||
|
||
import {ClientCallback} from '../../nuclide-debugger-common/lib/main'; | ||
|
||
export class IwdpDebuggerService { | ||
_state: string; | ||
_clientCallback: ClientCallback; | ||
_disposables: CompositeDisposable; | ||
_webSocket: ?WS; | ||
_package: ?string; | ||
|
||
constructor() { | ||
if (lastServiceObjectDispose != null) { | ||
lastServiceObjectDispose(); | ||
} | ||
lastServiceObjectDispose = this.dispose.bind(this); | ||
this._disposables = new CompositeDisposable(); | ||
this._clientCallback = new ClientCallback(); | ||
this._disposables.add(this._clientCallback); | ||
} | ||
|
||
getServerMessageObservable(): ConnectableObservable<string> { | ||
return this._clientCallback.getServerMessageObservable().publish(); | ||
} | ||
|
||
async debug(): Promise<string> { | ||
// TODO | ||
// 1. start ios-webkit-debug-proxy | ||
// 2. see what devices there are | ||
// 3. send request to json endpoint to get web socket data | ||
// 4. set up websocket to iwdp server. | ||
|
||
const webSocket = new WS('ws://localhost:9222/devtools/page/1'); | ||
this._webSocket = webSocket; | ||
webSocket.on( | ||
'message', | ||
async message => { | ||
const obj = JSON.parse(message); | ||
if (obj.method !== 'Debugger.scriptParsed') { | ||
this._clientCallback.sendChromeMessage(message); | ||
} else if ( | ||
obj.params == null || obj.params.url == null || !obj.params.url.startsWith('http:') | ||
) { | ||
this._clientCallback.sendChromeMessage(message); | ||
} else { | ||
// It's a bundle being served by the webserver hosted by the target, so we should | ||
// download it. | ||
const {url} = obj.params; | ||
this._package = url; | ||
const response = await xfetch(url, {}); | ||
const text = await response.text(); | ||
const tempPath = await fsPromise.tempfile({prefix: 'jsfile', suffix: '.js'}); | ||
await fsPromise.writeFile(tempPath, text); | ||
obj.params.url = `file://${tempPath}`; | ||
|
||
|
||
// Also source maps | ||
const SOURCE_MAP_REGEX = /\/\/# sourceMappingURL=(.+)$/; | ||
const matches = SOURCE_MAP_REGEX.exec(text); | ||
const sourceMapUrl = `http://localhost:8081${matches[1]}`; | ||
|
||
const response2 = await xfetch(sourceMapUrl, {}); | ||
const text2 = await response2.text(); | ||
const base64Text = new Buffer(text2).toString('base64'); | ||
obj.params.sourceMapURL = `data:application/json;base64,${base64Text}`; | ||
|
||
this._clientCallback.sendChromeMessage(JSON.stringify(obj)); | ||
} | ||
}, | ||
); | ||
|
||
log('IWDP Connected'); | ||
return 'IWDP connected'; | ||
} | ||
|
||
async sendCommand(message: string): Promise<void> { | ||
if (this._webSocket == null) { | ||
return; | ||
} | ||
const webSocket = this._webSocket; | ||
const obj = JSON.parse(message); | ||
if (obj.method === 'Debugger.setBreakpointByUrl') { | ||
obj.params.url = this._package; | ||
webSocket.send(JSON.stringify(obj)); | ||
} else { | ||
webSocket.send(message); | ||
} | ||
} | ||
|
||
async dispose(): Promise<void> { | ||
this._disposables.dispose(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
'use babel'; | ||
/* @flow */ | ||
|
||
/* | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
*/ | ||
|
||
import {getCategoryLogger} from '../../nuclide-logging'; | ||
|
||
const DEBUGGER_LOGGER_CATEGORY = 'nuclide-debugger-iwdp-rpc'; | ||
|
||
export const logger = getCategoryLogger(DEBUGGER_LOGGER_CATEGORY); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"name": "nuclide-debugger-iwdp-rpc", | ||
"repository": "https://github.com/facebook/nuclide", | ||
"main": "./lib/IwdpDebuggerService.js", | ||
"version": "0.0.0", | ||
"description": "Adapter between Nuclide's debugger client and the iOS webkit debug proxy", | ||
"nuclide": { | ||
"packageType": "Node", | ||
"testRunner": "npm" | ||
}, | ||
"scripts": { | ||
"test": "node ../nuclide-jasmine/bin/jasmine-node-transpiled spec" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# IOS Webkit Proxy Debugger |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
'use babel'; | ||
/* @flow */ | ||
|
||
/* | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
*/ | ||
|
||
import {DebuggerProcessInfo} from '../../nuclide-debugger-base'; | ||
import {IwdpDebuggerInstance} from './IwdpDebuggerInstance'; | ||
|
||
import type {NuclideUri} from '../../commons-node/nuclideUri'; | ||
|
||
export class AttachProcessInfo extends DebuggerProcessInfo { | ||
constructor(targetUri: NuclideUri) { | ||
super('iwdp', targetUri); | ||
} | ||
|
||
async debug(): Promise<IwdpDebuggerInstance> { | ||
return new IwdpDebuggerInstance(this); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
'use babel'; | ||
/* @flow */ | ||
|
||
/* | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
*/ | ||
|
||
import {React} from 'react-for-atom'; | ||
import {AttachProcessInfo} from './AttachProcessInfo'; | ||
import {Button, ButtonTypes} from '../../nuclide-ui/Button'; | ||
import {Dropdown} from '../../nuclide-ui/Dropdown'; | ||
import consumeFirstProvider from '../../commons-atom/consumeFirstProvider'; | ||
|
||
import type {NuclideUri} from '../../commons-node/nuclideUri'; | ||
|
||
type PropsType = { | ||
targetUri: NuclideUri, | ||
}; | ||
|
||
type StateType = { | ||
selectedPathIndex: number, | ||
pathMenuItems: Array<{label: string, value: number}>, | ||
}; | ||
|
||
export class AttachUiComponent extends React.Component<void, PropsType, StateType> { | ||
props: PropsType; | ||
state: StateType; | ||
|
||
constructor(props: PropsType) { | ||
super(props); | ||
(this: any)._handleCancelButtonClick = this._handleCancelButtonClick.bind(this); | ||
(this: any)._handleAttachButtonClick = this._handleAttachButtonClick.bind(this); | ||
(this: any)._handlePathsDropdownChange = this._handlePathsDropdownChange.bind(this); | ||
this.state = { | ||
selectedPathIndex: 0, | ||
pathMenuItems: this._getPathMenuItems(), | ||
}; | ||
} | ||
|
||
render(): React.Element<any> { | ||
return ( | ||
<div className="block"> | ||
<div className="nuclide-debugger-iwdp-launch-attach-ui-select-project"> | ||
<label>Selected Project Directory: </label> | ||
<Dropdown | ||
className="inline-block nuclide-debugger-connection-box" | ||
options={this.state.pathMenuItems} | ||
onChange={this._handlePathsDropdownChange} | ||
value={this.state.selectedPathIndex} | ||
/> | ||
</div> | ||
<div className="padded text-right"> | ||
<Button onClick={this._handleCancelButtonClick}>Cancel</Button> | ||
<Button | ||
buttonType={ButtonTypes.PRIMARY} | ||
onClick={this._handleAttachButtonClick}> | ||
Attach | ||
</Button> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
_getPathMenuItems(): Array<{label: string, value: number}> { | ||
return []; | ||
} | ||
|
||
_handlePathsDropdownChange(newIndex: number): void { | ||
this.setState({ | ||
selectedPathIndex: newIndex, | ||
pathMenuItems: this._getPathMenuItems(), | ||
}); | ||
} | ||
|
||
_handleAttachButtonClick(): void { | ||
const processInfo = new AttachProcessInfo(this.props.targetUri); | ||
consumeFirstProvider('nuclide-debugger.remote') | ||
.then(debuggerService => debuggerService.startDebugging(processInfo)); | ||
this._showDebuggerPanel(); | ||
this._handleCancelButtonClick(); | ||
} | ||
|
||
_showDebuggerPanel(): void { | ||
atom.commands.dispatch( | ||
atom.views.getView(atom.workspace), | ||
'nuclide-debugger:show', | ||
); | ||
} | ||
|
||
_handleCancelButtonClick(): void { | ||
atom.commands.dispatch( | ||
atom.views.getView(atom.workspace), | ||
'nuclide-debugger:toggle-launch-attach', | ||
); | ||
} | ||
} |
Oops, something went wrong.