Files
sdk/pkg/dtd_impl/dtd_protocol.md
T
Dan Chevalier a995f7930b Solidify, test and document DTD errors
Change-Id: Ied0f1af43954e47a2c51837bd2fc8d7ce0e03fa7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/345800
Commit-Queue: Dan Chevalier <danchevalier@google.com>
Reviewed-by: Ben Konyi <bkonyi@google.com>
2024-01-18 16:07:31 +00:00

11 KiB

Overview

This document describes the Dart Tooling Daemon protocol. This daemon, and it's protocol is meant to facilitate communication channels between various tools.

To start a tooling daemon run dart tooling-daemon.

The Dart Tooling Daemon Protocol uses JSON-RPC 2.0.

Streams

The following is a visualization of normal stream interaction. It is presented in function notation, instead of RPC calls, for brevity.

sequenceDiagram
    participant c1 as Client 1
    participant c2 as Client 2
    participant dtd as Dart Tooling Daemon
    participant c3 as Client 3

    c1->>dtd: streamListen(streamId: "foo")
    activate dtd
    dtd-->>c1: Success
    deactivate dtd

    c2->>dtd: streamListen(streamId: "foo")
    activate dtd
    dtd-->>c2: Success
    deactivate dtd

    Note right of c2: Client 1 and Client 2 are now listening to the "foo" stream.
    Note right of dtd: Client 3 posts an event to the "foo" stream.

    c3->>dtd: postEvent( streamId: "foo", eventKind: "example", eventData: { "bar": "baz" })
    activate dtd
    dtd-->>c3: Success

    Note right of c2: Client 1 and Client 2 are forwarded the event using streamNotify.
    dtd-->>c2: streamNotify( streamId: "foo", eventKind: "example", eventData: { "bar": "baz" })
    dtd-->>c1: streamNotify( streamId: "foo", eventKind: "example", eventData: { "bar": "baz" })
    deactivate dtd

    Note right of c2: Client 2 now cancels listening to the "foo" stream.
    c2-->>dtd: streamCancel(streamId: "foo")
    activate dtd
    dtd-->>c2: Success
    deactivate dtd

    Note right of dtd: Client 3 posts another event to the "foo" stream.
    c3->>dtd: postEvent( streamId: "foo", eventKind: "example", eventData: { "bar": "baz 2" })
    activate dtd
    dtd-->>c3: Success

    Note right of c2: Client 1 is still listening to the "foo" stream, so the event<br/>is still forwarded to it using streamNotify.
    dtd-->>c1: streamNotify( streamId: "foo", eventKind: "example", eventData: { "bar": "baz2 " })
    deactivate dtd

Service Methods

The following is a visualization of normal service method interaction. It is presented in function notation, instead of RPC calls, for brevity.

sequenceDiagram
    participant c1 as Client 1
    participant dtd as Dart Tooling Daemon
    participant c2 as Client 2

    Note right of c1: Client 1 registers the foo.bar method.
    c1->>dtd: registerService(service: "foo", method: "bar)
    activate dtd
    dtd-->>c1: Success
    deactivate dtd

    Note left of c2: Client 2 calls foo.bar
    c2->>dtd: foo.bar({{"a": 1, "b": 2}})
    activate dtd

    Note left of dtd: dtd forwards the service method call to Client 1.
    dtd->>c1: foo.bar({{"a": 1, "b": 2}})
    activate c1

    Note right of c1: Client 1 handles the<br/>request and responds to the Dart Tooling Daemon.
    c1-->>dtd: {"example": "response"}
    deactivate c1

    Note right of dtd: Dart Tooling Daemon forwards the response to Client 2.
    dtd-->>c2: {"example": "response"}
    deactivate dtd

Interacting with the Dart Tooling Daemon

package:dtd

package:dtd is available for use with Dart. It facilitates access to the Dart Tooling Daemon, by providing a convenient Dart interface.

Dart Tooling Daemon protocol

Alternatively you can interact with the tooling daemon using the RPC protocol directly.

streamListen

Registers the calling client as listening to the stream named streamId.

The calling client will then receive streamNotify calls when any client calls postEvent on the streamId stream.

Parameters

String streamId - The name of the stream to start listening to.

Result

If successful responds with Success.

If the client is already subscribed to the stream, the 103 (Stream already subscribed) RPC error code is returned.

Code Sample

{
  "jsonrpc": "2.0",
  "method": "streamListen",
  "params": {
    "streamId": "foo_stream"
  },
  "id": "2"
}

Response

{"id": "2", "type": "Success"}

streamCancel

Unregisters the calling client from listening to the stream named streamId.

The calling client will no longer receive streamNotify method calls for events on the streamId stream.

Parameters

String streamId - The name of the stream to stop listening to.

Result

If successful responds with Success.

If the client is not subscribed to the stream, the 104 (Stream not subscribed) RPC error code is returned.

Code Sample

{
  "jsonrpc": "2.0",
  "method": "streamCancel",
  "params": {
    "streamId": "foo_stream"
  },
  "id": "2"
}

Response

{"id": "2", "type": "Success"}

postEvent

Calls streamNotify on all clients that are currently streamListening to the streamId stream.

Parameters

  • String streamId - The stream to post the event to
  • String eventKind - The kind of event being sent.
  • Map<String, Object?> eventData - A map object of data to send with the event. eventData must be serializable to json.

Result

If successful responds with Success.

Code Sample

{
  "jsonrpc": "2.0",
  "method": "postEvent",
  "params": {
    "streamId": "fooStream",
    "eventKind": "bar",
    "eventData": { "bazKey": "apple" }
  },
  "id": "2"
}

Response

{"id": "2", "type": "Success"}

registerService

Registers the calling client as the handler for any service method calls where the service is service and the method is method.

To call the method registered by this call, a client can send a service method call to the Dart Tooling Daemon.

When a client disconnects, then all of the service methods registered to it are removed.

Parameters

  • String service - The name of the service to register the client to. Once a client has registered a method to a service then only that client can register other methods to that service.
  • String method - The name of the method to register to service.

Result

If successful responds with Success.

If the service has already been registered by another client , the 111 (Service already registered) RPC error code is returned.

If the method has already been registered on the service, the 132 (Service method already registered) RPC error code is returned.

Code Sample

{
  "jsonrpc": "2.0",
  "method": "registerService",
  "params": {
    "service": "foo",
    "method": "bar",
  },
  "id": "2"
}

Response

{"id": "2", "type": "Success"}

service.method

Triggers the service method registered by registerService, for service and method.

Dart Tooling Daemon will forward the service method call to the client that registered it. The client's response will be returned from this method call.

Parameters

The parameters must be a Map<String, Object?> where the contents are defined on a case by case basis on the expectations of the client who registered the service method.

Result

The result is defined on a case by case basis based on the implementer of the service method.

If service method does not exist, the -32601 (Method not found) RPC error code is returned.

Code Sample

Assume that a client has registered a service method with:

  • service: foo
  • method: bar

Then calling that service method might look like:

{
  "jsonrpc": "2.0",
  "method": "foo.bar",
  "params": { "baz": 3 },
  "id": "2"
}

Response

The response is defined on a case by case basis based on the implementer of the service method.

DTD Client Responsibilities

When creating a client that interacts with the Dart Tooling Daemon, implement the following methods in order to participate in the full lifecycle.

streamNotify

In order to handle messages posted to streams that the client is streamListening to, then the calling client may handle incoming streamNotify RPC methods.

When any client calls postEvent for a given _streamId , if a client hasstreamListened to streamId, then that client will receive streamNotify method calls for those events. Implement this method in order to receive those calls.

Parameters

  • String streamId - The stream to post the event to
  • String eventKind - The kind of event being sent.
  • Map<String, Object?> eventData - A map object of data to send with the event.

Result

No response is given since this is sent as a notification.

Code Sample

{
    "jsonrpc": "2.0",
    "method": "streamNotify",
    "params": {
        "streamId": "fooStream",
        "eventKind": "bar",
        "eventData": { "baz": "car" }
    },
    "id": "2"
}

Response

None, streamNotify is called as a notification and expects no response.

service.method

Any time the client calls registerService then it will receive method calls for that service method.

The method name will take the form service.method. Any response returned by the RPC handler will be forwarded to the service method caller.

Parameters

The parameters are defined on a case by case basis based on the expectations of the client who registered the service method.

Result

The result is defined on a case by case basis based on the implementer of the service method.

Code Sample

Assume that a client has registered a service method with:

  • service: foo
  • method: bar

Then calling that service method might look like:

{
  "jsonrpc": "2.0",
  "method": "foo.bar",
  "params": { "baz": 3 },
  "id": "2"
}

Response

The response is defined on a case by case basis based on the implementer of the service method. It should be a valid RPC response.

Responses

Success

Methods that respond with Success do so with the following RPC.

{"id": "2", "type": "Success"}

RPC Error

When an RPC encounters an error, it is provided in the error property of the response object. JSON-RPC errors always provide code, message, and data properties.

Here is an example error response for our streamListen request above. This error would be generated if we were attempting to subscribe to the GC stream multiple times from the same client.

{
  "jsonrpc": "2.0",
  "error": {
    "code": 103,
    "message": "Stream already subscribed",
    "data": {
      "details": "The stream 'GC' is already subscribed"
    }
  }
  "id": "2"
}

In addition to the error codes specified in the JSON-RPC spec, we use the following application specific error codes:

code message meaning
-32601 Method not found The method does not exist / is not available.
-32602 Invalid params Invalid params. Invalid method parameter(s).
103 Stream already subscribed The client is already subscribed to the specified streamId.
104 Stream not subscribed The client is not subscribed to the specified streamId.
111 Service already registered Service with such name has already been registered by this client.
112 Service disappeared Failed to fulfill service request, likely service handler is no longer available.
132 Service method already registered Method for the given service has already been registered by this client.