debugger: Added Websocket compatible implementation of the debugger.
authorLucas Bajolet <r4pass@hotmail.com>
Wed, 2 Apr 2014 21:08:14 +0000 (17:08 -0400)
committerLucas Bajolet <r4pass@hotmail.com>
Mon, 7 Apr 2014 17:57:04 +0000 (13:57 -0400)
Signed-off-by: Lucas Bajolet <r4pass@hotmail.com>

src/nitdbg_websocket_server.nit [new file with mode: 0644]
src/websocket_debugger.nit [new file with mode: 0644]

diff --git a/src/nitdbg_websocket_server.nit b/src/nitdbg_websocket_server.nit
new file mode 100644 (file)
index 0000000..d8c23ca
--- /dev/null
@@ -0,0 +1,38 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Lucas Bajolet <r4pass@hotmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Network debugger for a nit program (server part)
+module nitdbg_websocket_server
+
+import websocket_debugger
+import debugger_commons
+
+redef class InterpretCommons
+
+       redef fun launch
+       do
+               super
+               if toolcontext.opt_debug_port.value < 0 or toolcontext.opt_debug_port.value > 65535 then
+                       toolcontext.option_context.usage
+                       return
+               end
+
+               modelbuilder.run_debugger_network_mode(mainmodule.as(not null),arguments.as(not null),toolcontext.opt_debug_port.value)
+       end
+
+end
+
+(new InterpretCommons).launch
diff --git a/src/websocket_debugger.nit b/src/websocket_debugger.nit
new file mode 100644 (file)
index 0000000..f3c7cc0
--- /dev/null
@@ -0,0 +1,209 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Lucas Bajolet <r4pass@hotmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Network debugger for a nit program, based on the original debugger
+# Replaces access to stdin/stdout to send data on the network to the client concerned
+module websocket_debugger
+
+import websocket
+intrude import debugger
+
+redef class ToolContext
+
+       var opt_debug_port: OptionInt = new OptionInt("Sets the debug port (Defaults to 22125) - Must be contained between 0 and 65535", 22125, "--port")
+
+       redef init
+       do
+               super
+               self.option_context.add_option(self.opt_debug_port)
+       end
+
+end
+
+redef class ModelBuilder
+       fun run_debugger_network_mode(mainmodule: MModule, arguments: Array[String], port: Int)
+       do
+               var time0 = get_time
+               self.toolcontext.info("*** START INTERPRETING ***", 1)
+
+               var interpreter = new NetworkDebugger(self, mainmodule, arguments, port)
+
+               init_naive_interpreter(interpreter, mainmodule)
+
+               var time1 = get_time
+               self.toolcontext.info("*** END INTERPRETING: {time1-time0} ***", 2)
+
+               interpreter.ns.stop_server
+       end
+end
+
+# Extends the debugger by adding new network capabilities for remote debugging
+class NetworkDebugger
+       super Debugger
+
+       # Represents the connexion with a particular client (Actually the only one accepted at the moment)
+       private var ns: WebSocket
+
+       # Initializes the debugger, waits for a client to connect
+       # Then starts debugging as usual
+       init(modelbuilder: ModelBuilder, mainmodule: MModule, arguments: Array[String], port: Int)
+       do
+               print "Listening on port {port}"
+
+               ns = new WebSocket(port, 1)
+
+               ns.accept
+
+               print "Client connected"
+
+               stdin.connection = ns
+
+               if stdout isa Stdout then
+                       (stdout.as(Stdout)).connection = ns
+               else
+                       ns.stop_server
+                       abort
+               end
+
+               super
+       end
+
+       # Checks on every call if the client has sent a command before continuing debugging
+       redef fun stmt(n)
+       do
+               if stdin.poll_in then
+                       var command = gets
+                       if command == "stop" then
+                               n.debug("Stopped by client")
+                               while process_debug_command(gets) do end
+                       else
+                               process_debug_command(command)
+                       end
+               end
+
+               super(n)
+       end
+
+end
+
+redef class ANode
+
+       # Breaks automatically when encountering an error
+       # Permits the injunction of commands before crashing
+       # Disconnects from the client before crashing
+       redef private fun fatal(v: NaiveInterpreter, message: String)
+       do
+               if v isa Debugger then
+                       print "An error was encountered, the program will stop now."
+                       self.debug(message)
+                       while v.process_debug_command(gets) do end
+               end
+
+               if v isa NetworkDebugger then
+                       stdin.connection.stop_server
+               end
+
+               super
+       end
+end
+
+# Replaces Stdin to read on the network
+redef class Stdin
+
+       # Represents the connection with a client
+       var connection: nullable WebSocket = null
+
+       # Used to store data that has been read from the connection
+       var buf: Buffer = new FlatBuffer
+       var buf_pos: Int = 0
+
+       # Checks if data is available for reading
+       redef fun poll_in
+       do
+               return connection.can_read(0)
+       end
+
+       # Reads the whole content of the buffer
+       # Blocking if the buffer is empty
+       redef fun read_all
+       do
+               var loc_buf = new FlatBuffer
+               if connection.can_read(0) then buf.append(connection.read)
+               for i in [buf_pos .. buf.length-1] do loc_buf.add(buf.chars[i])
+               buf.clear
+               buf_pos = 0
+               return loc_buf.to_s
+       end
+
+       # Reads a single char on the incoming buffer
+       # If the buffer is empty, the call is blocking
+       redef fun read_char
+       do
+               if connection.can_read(0) then buf.append(connection.read)
+               if buf_pos >= buf.length then
+                       buf.clear
+                       buf_pos = 0
+                       #Blocking call
+                       buf.append(connection.read)
+               end
+               buf_pos += 1
+               return buf.chars[buf_pos-1].ascii
+       end
+
+       # Reads a line on the network if available
+       # Stops at the first encounter of a \n character
+       # If the buffer is empty, the read_line call is blocking
+       redef fun read_line
+       do
+               var line_buf = new FlatBuffer
+               if connection.can_read(0) then
+                       buf.append(connection.read)
+               end
+               var has_found_eol: Bool = false
+               loop
+                       if buf_pos >= buf.length then
+                               buf.clear
+                               buf_pos = 0
+                               # Blocking call
+                               buf.append(connection.read)
+                       end
+                       buf_pos += 1
+                       if buf.chars[buf_pos-1] == '\n' then break
+                       line_buf.add(buf.chars[buf_pos-1])
+               end
+               return line_buf.to_s
+       end
+end
+
+# Replaces Stdout to write on the network
+redef class Stdout
+
+       # Connection with the client object
+       var connection: nullable WebSocket = null
+
+       # Writes a string on the network if available, else
+       # it is written in the standard output (Terminal)
+       redef fun write(s)
+       do
+               if connection != null then
+                       connection.write(s)
+               else
+                       super
+               end
+       end
+
+end
+