Remote Debugging
From OpenLaszlo
This is the protocol that is used to support the integrated debugger in IDE4Laszlo. It is not used by the internal debugger (the ?debug query parameter, which the developer console requests).
Contents |
Startup Process
The startup process is:
- Eclipse starts a listener on a socket.
- The app starts up with the remotedebug=portnum flag.
- The app opens a socket to the specified portnum. There is now a bidirectional stream open for commands.
- Commands they can come asynch from the app, or an external debugger front end can issue them.
So for example, Debug.write at any place in your app will asynchronously notify the debugger front end to print it out in its log window. commands have a sequence number, so when eclipse issues a command, a response comes back later with matching sequence number.
Flash apps with remote debug enabled will open a connection as soon as the app gets to the "init" stage. But debug messages can be queued, so you can see errors that happen before that.
External Command-Line Debugger
Compile the file server/src/org/openlaszlo/test/debugserver.java
cd server/src/org/openlaszlo/test/debugserver.java javac debugserver.java
Then run it like this:
java -cp . debugserver 5559
Then load your app into a browser like this:
http://localhost:8080/intl2/test/myapp.lzx?lzr=swf7&debug=true&remotedebug=5559
The command line listener will let you type expressions or statements, and will return XML responses:
domokun% domokun% java -cp . debugserver Listening on port 5559 Accepting connection on port 5559 2 + 2 <response seq="1"><value value="4" type="number" /></response> canvas.subviews <response seq="2"><value id="0" value="LzText: Hello Laszlo!,focusoverlay " type="object"><property value="focusoverlay" type="object" name="1" /><property value="LzText: Hello Laszlo!" type="object" name="0" /></value></response>
Remote Debugger Protocol
The remote debugger protocol is based on DBGP - A common debugger protocol for languages and debugger UI communication.
There are two types of requests supported
<eval>expression or statements</eval> <inspect id="someid"/>
Actually ,the "inspect" is equivalent to
<eval>__LZDebug.ObjectForId(someid)</eval>
The response that comes back is always of the form:
<response> <value <warning ..> <warning ..> </response>
Examples:
<eval>2+2</eval> <response><value type="number" value="4" id="null" /></response>
<eval>canvas</eval>
<response>
<value type="LzCanvas" value="This is the canvas" id="39">
<property id="null" type="function" value="[type Function]" name="__LZmakeDatapath" />
<property id="null" type="function" value="[type Function]" name="__LZassignClassRoot" />
<property id="null" type="function" value="[type Function]" name="getDebugIdentification" />
<property id="null" type="function" value="[type Function]" name="_dbg_name" />
<property id="null" type="string" value="INTERNAL" name="build" />
<property id="null" type="string" value="2.3.0" name="lpsversion" />
<property id="null" type="number" value="16777215" name="bgcolor" />
<property id="null" type="number" value="600" name="height" />
<property id="null" type="number" value="1200" name="width" />
<property id="null" type="number" value="30" name="framerate" />
<property id="null" type="number" value="67" name="totalnodes" />
<property id="54" type="object" value="[object Object]"
name="resourcetable" />
....
....
</value>
</response>
<exec><![CDATA[ for (i = 0; i < 10; i ++) { foo[i] = i } ]]> </exec>
<response><value type="boolean" value="true" id="null" /></response>
If the code errors out during the eval, nothing comes back at all. This is sort of a problem, you'll have to time out or something listening. We don't have any easy way to make sure something always gets sent back, except maybe some sort of timer we set up to check that some routine completes. It will be easier in Flash 7, which supports try/catch exceptions.
Calls to Debug.write() in the application will result in asynchronous <log> elements being written back to the server.
Debugger warnings which occur during execution of an app will be written back to the server asynchronously as <warning> elements.
Implementation
The remote debugger code is in WEB-INF/lps/lfc/debugger/LzRemote.as
The remote debugger looks for the query arg at startup:
remotedebug=DDDD
where DDDDD is a decimal TCP port number to connect to.
If remotedebug is supplied, then the debugger code will:
- suppress the debugger window from becoming visible
- open a connection to the specified socket at startup
- redirect input/output to the remote socket
Console Remote Debugger
This is a proposed mechanism to extend remote debugger to console debugger
On top of the remote debugger protocol, there is a transport mechanism which can be used instead of the XMLSocket TCP channel.
If the query arg lzconsoledebug=true is supplied, the server will create a console page wrapper which contains a flag and extra info to allow the app being debugged to communicate with a console debugger SOLO app, using the Flash LocalConnection mechanism.
The server assigns a unique Application ID to the app page, so that multiple LocalConnection listeners can be used with different labels, allowing multiple apps to be debugged in the same browser.
Internally, LzRemote will be modified to check the lzconsoledebug flag in addition to the remotedebug flag. If lzconsoledebug is set, then XML commands are received and sent from a LocalConnection port, with a name derived from the "lzappuid" arg, a unique ID which is supplied by the server HTML wrapper page to both the app under debug and the console debugger app.
The console debug app lives in /lps/admin/dev-console.lzx, and the wrapper for it is generated by WEB-INF/lps/templates/app-console.xslt, in combination with servlets/responders/ResponderAPP_CONSOLE.java
An example URL for console debugging would be http://localhost:8080/lps-dev/examples/image-loading/test.lzx?lzconsoledebug=true&remotedebug=9999&debug=true
the value for remotedebug doesn't matter, since the presence of the lzconsoledebug=true will cause LzRremote to use a LocalConnection instead of a TCP socket.
Implementation note: there should be an interlock so that messages from the app are not sent until a connection is opened to the console. There is already a mechanism in LzDebugWindow which pushes out queued boot messages. The this.startupRemote() method should have some kind of interlock to wait for the connection to be confirmed. However, maybe a queue of XML messages is needed at the LzRemote level.

