Skip to content

Commit 5f47bec

Browse files
committed
First commit
1 parent 0fbe8c7 commit 5f47bec

File tree

9 files changed

+2086
-2
lines changed

9 files changed

+2086
-2
lines changed

README.md

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,88 @@
1-
qdb
2-
===
1+
# qdb #
32

43
Quantopian Remote Debugger for Python
4+
5+
6+
### Overview ###
7+
8+
qdb is a debugger for python that allows users to debug code executing
9+
on remote machine. qdb is split into three main components that may all be
10+
running on seperate hardware:
11+
12+
- The client
13+
- The tracer
14+
- The server
15+
16+
The client is the user's interface to the debugger. All communication here is
17+
through a websocket connected to the server. This client could be any type
18+
of application. qdb provides a terminal client and emacs mode for this.
19+
20+
21+
The tracer is the main debugging process. This is the actual code that the user
22+
wishes to debug. Communication here is through a socket sending pickle'd
23+
dictionaries representing only the valid json messages sent to the server from
24+
the client. A single tracer may have multiple clients connected to it.
25+
26+
27+
The server is the main routing station for messages between the clients and the
28+
tracer. The server is responsible for validating that the messages from the
29+
clients are well formed and routing them to the tracer. A single server may
30+
manage multiple tracers, so it is responsible for making sure that connections
31+
are routed to the proper place. The server can clean up tracer processes whos
32+
clients have become inactive if the server manager decides.
33+
34+
35+
36+
### json protocol ###
37+
38+
All communication to the server is through a structured protocol of the form:
39+
40+
{
41+
"e": event,
42+
"p": payload
43+
}
44+
45+
The event is the type of the message, and the payload is any parameter or data
46+
that is associated with this packet. Not all messages require a payload.
47+
For example, the client can send the command:
48+
49+
{
50+
"e": "step"
51+
}
52+
53+
Which steps into the next expression on the tracer. The client may also send:
54+
55+
{
56+
"e": "eval"
57+
"p": "a + b"
58+
}
59+
60+
This command is equivelent to evaluating the code `a + b` in the current stack
61+
frame.
62+
63+
The server will always send back data that is formatted in this way.
64+
65+
66+
### Modularity ###
67+
68+
qdb is designed with modularity in mind. For this reason, many components of the
69+
qdb system may be swapped out with user defined alternatives to help blend qdb
70+
into larger projects. For example, the qdb server can have the websocket server
71+
swapped out to make it work as a route point in a larger flask project.
72+
73+
While qdb provides a minimal client, the beauty in the websocket / json
74+
combination is that it allows users to plug in their own client, so long as
75+
it can make the connection and interpret the commands.
76+
77+
78+
79+
### Security ###
80+
81+
qdb provides multiple features that are security oriented. Because it is a
82+
remote debugger, the owner of the hardware running the tracer or server may
83+
not want the user to do things. For example, the the server may define an
84+
authentication function that reads the authentication message out of the
85+
start command and either accepts or denies that websocket. Also, the tracer
86+
may define their own eval function to use when evaluating repl code or the
87+
condition of conditional breakpoints. This lets the tracer deny potentially
88+
dangerous code if it so wishes.

emacs/qdb.el

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
(defvar qdb-executable (executable-find "qdb-cli")
2+
"Program used by `run-qdb'")
3+
4+
(defvar qdb-mode-map
5+
(let ((map (nconc (make-sparse-keymap) comint-mode-map)))
6+
;; example definition
7+
(define-key map "\t" 'completion-at-point)
8+
map)
9+
"Basic mode map for `run-qdb'")
10+
11+
(defvar qdb-prompt-regexp "(qdb)"
12+
"Prompt for `run-qdb'.")
13+
14+
(defun qdb--initialize ()
15+
"Helper function to initialize qdb"
16+
(setq comint-process-echoes t)
17+
(setq comint-use-prompt-regexp t))
18+
19+
(defconst qdb-keywords
20+
'("b" "break"
21+
"c" "continue"
22+
"cl" "clear"
23+
"list"
24+
"n" "next"
25+
"q" "quit"
26+
"s" "step"
27+
"r" "return"
28+
"unt" "until"
29+
"w" "watch"
30+
"unw" "unwatch"
31+
"tbreak"))
32+
33+
(defvar qdb-font-lock-keywords
34+
(list
35+
;; highlight all the reserved commands.
36+
`(,(concat "\\_<"
37+
(regexp-opt qdb-keywords) "\\_>") . font-lock-keyword-face))
38+
"Additional expressions to highlight in `qdb-mode'.")
39+
40+
(define-derived-mode qdb-mode comint-mode "qdb"
41+
"Major mode for `run-qdb'.
42+
43+
\\<qdb-mode-map>"
44+
nil "qdb"
45+
(setq comint-prompt-regexp qdb-prompt-regexp)
46+
(setq comint-prompt-read-only t)
47+
(set (make-local-variable 'paragraph-separate) "\\'")
48+
(set (make-local-variable 'font-lock-defaults) '(qdb-font-lock-keywords t))
49+
(set (make-local-variable 'paragraph-start) qdb-prompt-regexp))
50+
(add-hook 'qdb-mode-hook 'qdb--initialize)
51+
52+
(defun qdb-open-out-file (out-file qdb-buffer)
53+
"Opens the out-file in a tail -f type mode and pops back the repl."
54+
(start-process "qdb-out" "*qdb-out*" "tail" "-f" out-file)
55+
(switch-to-buffer "*qdb-out*")
56+
(read-only-mode)
57+
(pop-to-buffer qdb-buffer))
58+
59+
(defun run-qdb (uuid addr auth)
60+
"Starts a new qdb session inside of emacs."
61+
(interactive "suuid (default: \"qdb\"): \nsaddr (default: \
62+
\"ws://localhost:8002/debug_session/{uuid}\"): \nsauth (default: \"\"): ")
63+
(let* ((real-uuid (if (not (string= uuid ""))
64+
uuid
65+
"qdb"))
66+
(real-addr (if (not (string= addr ""))
67+
addr
68+
"ws://localhost:8002/debug_session/{uuid}"))
69+
(qdb-buffer (make-comint-in-buffer
70+
"qdb" nil qdb-executable
71+
nil "-w" real-addr "-u" real-uuid "-a" auth)))
72+
(switch-to-buffer qdb-buffer)
73+
(qdb-mode)
74+
(qdb-open-out-file (format "/tmp/qdb/.%s" real-uuid) qdb-buffer)))

0 commit comments

Comments
 (0)