Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2022-10

JSON RPC send server request to client

11 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Hairy Pixels

Quick question, I’ve been using the JSON RPC package to receive messages from the client and dispatch methods but I need to send a request from the server to the client now. Is this possible in the library? I can’t find a method in TCustomJSONRPCDispatcher which seems appropriate. Thanks!

Regards,
Ryan Joseph

Reply by email

Michael Van Canneyt
to Hairy Pixels
Hairy Pixels wrote
Quick question, I’ve been using the JSON RPC package to receive messages from the client and dispatch methods but I need to send a request from the server to the client now. Is this possible in the library? I can’t find a method in TCustomJSONRPCDispatcher which seems appropriate. Thanks!

There is no way to send data from server to client, only responses to client requests.

What's more, HTTP 1 and 1.1 simplu do not allow this. You'd need HTTP2 and/or websockets in order to send data from server to client.

Michael.

Reply by email

Hairy Pixels
to Michael Van Canneyt
Show quoted text 7 lines
On Oct 2, 2022, at 9:16 AM, Michael Van Canneyt wrote: There is no way to send data from server to client, only responses to client requests. What's more, HTTP 1 and 1.1 simplu do not allow this. You'd need HTTP2 and/or websockets in order to send data from server to client.

I mean with a standard IO pipe using read/write between processes.

For example in the LSP docs:

https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_executeCommand

It says:

The workspace/executeCommand request is sent from the client to the server to trigger command execution on the server. In most cases the server creates a WorkspaceEdit structure and applies the changes to the workspace using the request workspace/applyEdit which is sent from the server to the client."

So I need to send the message manually back to the client (the IDE) with the ID which JSON RPC requires also. I’m confused about the ID in particular and if it can be anything or it needs to be generated in the same stream as existing IDs.

Regards,
Ryan Joseph

Reply by email

Hairy Pixels
to Hairy Pixels
On Oct 2, 2022, at 10:23 AM, Hairy Pixels wrote: So I need to send the message manually back to the client (the IDE) with the ID which JSON RPC requires also. I’m confused about the ID in particular and if it can be anything or it needs to be generated in the same stream as existing IDs.

Follow up, I sent the message by manually packaging it with the RPC protocol and made my own ID, which works but there is no way to get a response from the client in your library it appears (like you said this may just not be supported)

In LSP the client is sending back this response payload which has the ID of the request. I guess to implement this you would need to keep a list of sent requests by ID and then find their handler (like the method dispatcher for requests) and invoke with the “results” data.

interface ResponseMessage extends Message {
	id: integer | string | null;
	result?: string | number | boolean | object | null;
	error?: ResponseError;
}

Regards,
Ryan Joseph

Reply by email

Wayne Sherman
to Michael Van Canneyt: There is no way to send data from server to client, only responses to client requests.…
Michael wrote 7 lines
There is no way to send data from server to client, only responses to client requests. What's more, HTTP 1 and 1.1 simplu do not allow this. You'd need HTTP2 and/or websockets in order to send data from server to client. From the spec, JSON-RPC 2.0 is "transport agnostic in that the

concepts can be used within the same process, over sockets, over http, or in many various message passing environments."
https://www.jsonrpc.org/specification#overview

Thus JSON-RPC can be used bi-directionally when using UNIX domain sockets, TCP sockets, and other bidirectional transports (e.g websockets).

If implemented as such using a bi-direction transport, the endpoints can be both a server and a client at the same time, i.e. both endpoints can issue requests and/or handle responses: https://www.jsonrpc.org/specification#conventions

"The Client is defined as the origin of Request objects and the handler of Response objects.
The Server is defined as the origin of Response objects and the handler of Request objects.
One implementation of this specification could easily fill both of those roles, even at the same time, to other different clients or the same client. This specification does not address that layer of complexity."

Reply by email

Wayne Sherman
to Wayne Sherman
Wayne wrote 6 lines
JSON-RPC can be used bi-directionally when using UNIX domain sockets, TCP sockets, and other bidirectional transports (e.g websockets). If implemented as such using a bi-direction transport, the endpoints can be both a server and a client at the same time...

Sorry, my use of the term "bi-directional" is not really correct. JSON-RPC is generally a bi-directional protocol (except when sending a "notification"). The issue is that some bi-directional transports (e.g. HTTP) close the connection after a response. So for these types of transports, a "server" cannot become a "client" since the connection has been closed.

But if JSON-RPC is implemented using a transport which maintains (or keeps open) a bi-directional connection, then either endpoint can issue requests during the session if so desired. (i.e. either side can be a server or a client at any point during the session).

Reply by email

Michael Van Canneyt
to Wayne Sherman
Wayne Sherman wrote 19 lines
Wayne wrote: > JSON-RPC can be used bi-directionally when using > UNIX domain sockets, TCP sockets, and other > bidirectional transports (e.g websockets). > If implemented as such using a bi-direction transport, > the endpoints can be both a server and a client > at the same time... Sorry, my use of the term "bi-directional" is not really correct. JSON-RPC is generally a bi-directional protocol (except when sending a "notification"). The issue is that some bi-directional transports (e.g. HTTP) close the connection after a response. So for these types of transports, a "server" cannot become a "client" since the connection has been closed. But if JSON-RPC is implemented using a transport which maintains (or keeps open) a bi-directional connection, then either endpoint can issue requests during the session if so desired. (i.e. either side can be a server or a client at any point during the session).

FPC's JSON-RPC is designed to be used using HTTP(s) transport only, i.e. synchronous request and answer.

Hence Ryan's failure to achieve what he wants to do.

But if changes need to be made to make it usable over other transports, then I am open for suggestions. With the new support for websockets in FPC, this seems like a good time to review the architecture.

Michael.

Reply by email

Hairy Pixels
to Michael Van Canneyt
Show quoted text 8 lines
On Oct 3, 2022, at 10:48 PM, Michael Van Canneyt via fpc-pascal wrote: FPC's JSON-RPC is designed to be used using HTTP(s) transport only, i.e. synchronous request and answer. Hence Ryan's failure to achieve what he wants to do. But if changes need to be made to make it usable over other transports, then I am open for suggestions. With the new support for websockets in FPC, this seems like a good time to review the architecture.

In my experience making a Pascal language server using LSP (https://microsoft.github.io/language-server-protocol/)l here are top issues I’ve had:

1) As mentioned the server can’t send messages to the client or receive their responses.
2) LSP has various “any” types which aren’t streamed currently. If TJSONData, TJSONArray etc.. types were streamed this would be good enough probably.
3) A minor issue is I wish dynamic arrays were streamed instead of the TCollection types. They are easier to use and manage their own memory which is nice.

Regards,
Ryan Joseph

Reply by email

Michael Van Canneyt
to Hairy Pixels
Hairy Pixels wrote 14 lines
> On Oct 3, 2022, at 10:48 PM, Michael Van Canneyt via fpc-pascal wrote: > > FPC's JSON-RPC is designed to be used using HTTP(s) transport only, i.e. > synchronous request and answer. > > Hence Ryan's failure to achieve what he wants to do. > > But if changes need to be made to make it usable over other transports, then I am open for suggestions. With the new support for websockets in FPC, this seems like a good time to review the architecture. In my experience making a Pascal language server using LSP (https://microsoft.github.io/language-server-protocol/)l here are top issues I’ve had: 1) As mentioned the server can’t send messages to the client or receive their responses.

Seems like both parts in the LSP protocol are playing 'client' and 'server', because:

"The Client is defined as the origin of Request objects and the handler of Response objects. The Server is defined as the origin of Response objects and the handler of Request objects."

As usual one can trust Microsoft to give an own interpretation to a protocol :)

2) LSP has various “any” types which aren’t streamed currently. If TJSONData, TJSONArray etc.. types were streamed this would be good enough probably.

This is not specifc to JSON-RPC, but to JSON streaming in general.

3) A minor issue is I wish dynamic arrays were streamed instead of the TCollection types. They are easier to use and manage their own memory which is nice.

It is since long on my TODO list:

The restbase unit (which already has this capability) needs to be unified with the jsonstreamer unit.

Also on my TODO list are related things such as:
* a more complete JSON Schema implementation
and
* a Swagger (OpenAPI) output
and
* an input system to convert a swagger description to a class that handles an API.

Michael.

Reply by email

Wayne Sherman
to Michael Van Canneyt
Michael wrote 6 lines
Seems like both parts in the LSP protocol are playing 'client' and 'server', because: "The Client is defined as the origin of Request objects and the handler of Response objects. The Server is defined as the origin of Response objects and the handler of Request objects." As usual one can trust Microsoft to give an own interpretation to a protocol :)

The JSON-RPC protocol defines client and server strictly by who sends the request and who handles the response. An endpoint can be both a client and server at the same time over the same connection if the transport permits. For example, Endpoint-1 connects to Endpoint-2 using a standard TCP socket or UNIX socket. Endpoint-1 is a "JSON-RPC" client when it sends a request, and Endpoint-2 is a "JSON-RPC" server when it receives the request and sends a response. But when Endpoint-2 initiates a request to Endpoint-1 over the same connection, Endpoint-2 is a "JSON-RPC" client and Endpoint-1 is a "JSON-RPC" server (i.e. the roles have switched, which is not prohibited by the protocol). After the definition of client/server the spec says:

"One implementation of this specification could easily fill both of those roles, *even at the same time*, to other different clients or the same client"

Reply by email

Michael Van Canneyt
to Wayne Sherman
Wayne Sherman wrote 24 lines
Michael wrote: > Seems like both parts in the LSP protocol are playing 'client' and 'server', because: > > "The Client is defined as the origin of Request objects and the handler of Response objects. > The Server is defined as the origin of Response objects and the handler of Request objects." > > As usual one can trust Microsoft to give an own interpretation to a protocol :) The JSON-RPC protocol defines client and server strictly by who sends the request and who handles the response. An endpoint can be both a client and server at the same time over the same connection if the transport permits. For example, Endpoint-1 connects to Endpoint-2 using a standard TCP socket or UNIX socket. Endpoint-1 is a "JSON-RPC" client when it sends a request, and Endpoint-2 is a "JSON-RPC" server when it receives the request and sends a response. But when Endpoint-2 initiates a request to Endpoint-1 over the same connection, Endpoint-2 is a "JSON-RPC" client and Endpoint-1 is a "JSON-RPC" server (i.e. the roles have switched, which is not prohibited by the protocol). After the definition of client/server the spec says: "One implementation of this specification could easily fill both of those roles, *even at the same time*, to other different clients or the same client"

No doubt, but I've never seen this in practice.
Not surprising, since HTTP is the dominant protocol.

But as said, if we can extend the implementation to support other transports which do allow bi-directional sending of requests, then I am all for it.

Michael.

Reply by email