Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Commit

Permalink
Merge pull request #50 from ericsnowcurrently/fix-up
Browse files Browse the repository at this point in the history
Minor cleanup.
  • Loading branch information
ericsnowcurrently authored Feb 9, 2018
2 parents c658160 + 8912574 commit 63eada2
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 11 deletions.
114 changes: 114 additions & 0 deletions debugger_protocol/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# VSC Debugger Protocol

[Visual Studio Code](https://code.visualstudio.com/) defines several
protocols that extensions may leverage to fully integrate with VSC
features. For ptvad the most notable of those is the debugger protocol.
When VSC handles debugger-related input via the UI, it delegates the
underlying behavior to an extension's debug adapter (e.g. ptvsd) via
the protocol. The
[debugger_protocol](https://github.com/ericsnowcurrently/ptvsd/blob/master/debugger_protocol)
package (at which you are looking) provides resources for understanding
and using the protocol.

For more high-level info see:

* [the VSC debug protocol page](https://code.visualstudio.com/docs/extensionAPI/api-debugging)
* [the example extension page](https://code.visualstudio.com/docs/extensions/example-debuggers)


## Protocol Definition

The VSC debugger protocol has [a schema](https://github.com/Microsoft/vscode-debugadapter-node/blob/master/debugProtocol.json)
which defines its messages. The wire format is HTTP messages with JSON
bodies. Note that the schema does not define the semantics of the
protocol, though a large portion is elaborated in the "description"
fields in
[the schema document](https://github.com/Microsoft/vscode-debugadapter-node/blob/master/debugProtocol.json).

[//]: # (TODO: Add a link to where the wire format is defined.)


## Components

### Participants

The VSC debugger protocol involves 2 participants: the `client` and the
`debug adapter`, AKA `server`. VSC is an example of a `client`. ptvsd
is an example of a `debug adapter`. VSC extensions are responsible for
providing the `debug adapter`, declaring it to VSC and connecting the
adapter to VSC when desired.

### Communication

Messages are sent back and forth over a socket. The messages are
JSON-encoded and sent as the body of an HTTP message.

Flow:

<TBD>

### Message Types

All messages specify their `type` and a globally-unique
monotonically-increasing ID (`seq`).

The protocol consists for 3 types of messages:

* event
* request
* response

An `event` is a message by which the `debug adapter` reports to the
`client` that something happened. Only the `debug adapter` sends
`event`s. An `event` may be sent at any time, so the `client` may get
one after sending a `request` but before receiving the corresponding
`response`.

A `request` is a message by which the `client` requests something from
the `debug adapter` over the connection. That "something" may be data
corresponding to the state of the debugger or it may be an action that
should be performed. Note that the protocol dictates that the `debug
adapter` may also send `request`s to the `client`, but currently there
aren't any such `request` types.

Each `request` type has a corresponding `response` type; and for each
`request` sent by the `client`, the `debug adapter` sends back the
corresponding `response`. `response` messages include a `request_seq`
field that matches the `seq` field of the corresponding `request`.


## Protocol-related Tools

Tools related to the schema, as well as
[a vendored copy](https://github.com/ericsnowcurrently/ptvsd/blob/master/debugger_protocol/schema/debugProtocol.json)
of the schema file itself, are found in
[debugger_protocol/schema](https://github.com/Microsoft/ptvsd/tree/master/debugger_protocol/schema).
Python bindings for the messages are found in
[debugger_protocol/messages](https://github.com/ericsnowcurrently/ptvsd/blob/master/debugger_protocol/messages).
Tools for handling the wire format are found in
[debugger_protocol/messages/wireformat.py](https://github.com/ericsnowcurrently/ptvsd/blob/master/debugger_protocol/messages/wireformat.py).

### Using the Python-implemented Message Types

The Python implementations of the schema-defined messages all share a
[ProtocolMessage](https://github.com/ericsnowcurrently/ptvsd/blob/master/debugger_protocol/messages/message.py#L27)
base class. The 3 message types each have their own base class. Every
message class has the following methods to aid with serialization:

* a `from_data(**raw)` factory method
* a `as_data()` method

These methods are used by
[the wireformat helpers](https://github.com/ericsnowcurrently/ptvsd/blob/master/debugger_protocol/messages/wireformat.py).


## Other Resources

* https://github.com/Microsoft/vscode-mock-debug
* https://github.com/Microsoft/vscode-debugadapter-node/tree/master/testSupport
* https://github.com/Microsoft/vscode-debugadapter-node/blob/master/protocol/src/debugProtocol.ts
* https://github.com/Microsoft/vscode-mono-debug

* http://json-schema.org/latest/json-schema-core.html
* https://python-jsonschema.readthedocs.io/
* http://python-jsonschema-objects.readthedocs.io/
9 changes: 9 additions & 0 deletions debugger_protocol/messages/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ def register(cls, msgtype=None, typekey=None, key=None):
return cls


def look_up(data):
"""Return the message class for the given raw message data."""
msgtype = data['type']
typekey = MESSAGE_TYPE_KEYS[msgtype]
key = data[typekey]
return MESSAGE_TYPES[msgtype][key]


class Message(object):
"""The API for register-able message types."""

Expand All @@ -63,5 +71,6 @@ def as_data(self):


# Force registration.
from .message import ProtocolMessage, Request, Response, Event
from .requests import * # noqa
from .events import * # noqa
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json

from . import MESSAGE_TYPES, MESSAGE_TYPE_KEYS
from . import look_up


def read(stream):
Expand All @@ -22,14 +22,16 @@ def read(stream):

data = json.loads(body.decode('utf-8'))

msgtype = data['type']
typekey = MESSAGE_TYPE_KEYS[msgtype]
key = data[typekey]
cls = MESSAGE_TYPES[msgtype][key]

cls = look_up(data)
return cls.from_data(**data)


def write(stream, msg):
"""Serialize the message and write it to the stream."""
raw = as_bytes(msg)
stream.write(raw)


def as_bytes(msg):
"""Return the raw bytes for the message."""
headers, body = _as_http_data(msg)
Expand Down
28 changes: 24 additions & 4 deletions ptvsd/wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,22 @@ def shutdown(self, mode):
pass

def recv(self, count):
# TODO: docstring
"""Return the requested number of bytes.
This is where the "socket" sends requests to pydevd. The data
must follow the pydevd line protocol.
"""
data = os.read(self.pipe_r, count)
#self.log.write('>>>[' + data.decode('utf8') + ']\n\n')
#self.log.flush()
return data

def send(self, data):
# TODO: docstring
"""Handle the given bytes.
This is where pydevd sends responses and events. The data will
follow the pydevd line protocol.
"""
result = len(data)
data = unquote(data.decode('utf8'))
#self.log.write('<<<[' + data + ']\n\n')
Expand Down Expand Up @@ -781,7 +789,13 @@ def on_pydevd_send_curr_exception_trace_proceeded(self, seq, args):


def start_server(port):
# TODO: docstring
"""Return a socket to a (new) local pydevd-handling daemon.
The daemon supports the pydevd client wire protocol, sending
requests and handling responses (and events).
This is a replacement fori _pydevd_bundle.pydevd_comm.start_server.
"""
server = socket.socket(socket.AF_INET,
socket.SOCK_STREAM,
socket.IPPROTO_TCP)
Expand All @@ -804,7 +818,13 @@ def start_server(port):


def start_client(host, port):
# TODO: docstring
"""Return a socket to an existing "remote" pydevd-handling daemon.
The daemon supports the pydevd client wire protocol, sending
requests and handling responses (and events).
This is a replacement fori _pydevd_bundle.pydevd_comm.start_client.
"""
client = socket.socket(socket.AF_INET,
socket.SOCK_STREAM,
socket.IPPROTO_TCP)
Expand Down
2 changes: 1 addition & 1 deletion tests/helpers/stub.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def set_exceptions(self, *exceptions):
def add_call(self, name, *args, **kwargs):
self.add_call_exact(name, args, kwargs)

def add_call_exact(self, name, args, kwargs):
def add_call_exact(self, name, args=None, kwargs=None):
self.calls.append((name, args, kwargs))

def maybe_raise(self):
Expand Down

0 comments on commit 63eada2

Please sign in to comment.