66from dataclasses import dataclass
77from functools import partial
88from http .server import BaseHTTPRequestHandler , HTTPServer
9- from typing import TYPE_CHECKING , Any , Final , NamedTuple
10-
9+ from typing import TYPE_CHECKING , NamedTuple
1110from typing_extensions import Protocol
1211
1312from ..cli .cli import Options
1413
1514if TYPE_CHECKING :
1615 from collections .abc import Callable
1716 from pathlib import Path
17+ from typing import Any , Final , Iterator
1818
1919
2020_LOGGER : Final = logging .getLogger (__name__ )
@@ -86,7 +86,8 @@ class JsonRpcBatchRequest(NamedTuple):
8686class JsonRpcResult (ABC ):
8787
8888 @abstractmethod
89- def encode (self ) -> bytes : ...
89+ def encode (self ) -> Iterator [bytes ]:
90+ ...
9091
9192
9293@dataclass (frozen = True )
@@ -96,7 +97,7 @@ class JsonRpcError(JsonRpcResult):
9697 message : str
9798 id : str | int | None
9899
99- def to_json (self ) -> dict [str , Any ]:
100+ def wrap_response (self ) -> dict [str , Any ]:
100101 return {
101102 'jsonrpc' : JsonRpcServer .JSONRPC_VERSION ,
102103 'error' : {
@@ -106,32 +107,40 @@ def to_json(self) -> dict[str, Any]:
106107 'id' : self .id ,
107108 }
108109
109- def encode (self ) -> bytes :
110- return json .dumps (self .to_json ()).encode ('ascii' )
110+ def encode (self ) -> Iterator [ bytes ] :
111+ yield json .dumps (self .wrap_response ()).encode ('ascii' )
111112
112113
113114@dataclass (frozen = True )
114115class JsonRpcSuccess (JsonRpcResult ):
115116 payload : Any
116117 id : Any
117118
118- def to_json (self ) -> dict [str , Any ]:
119- return {
120- 'jsonrpc' : JsonRpcServer .JSONRPC_VERSION ,
121- 'result' : self .payload ,
122- 'id' : self .id ,
123- }
124-
125- def encode (self ) -> bytes :
126- return json .dumps (self .to_json ()).encode ('ascii' )
119+ def encode (self ) -> Iterator [bytes ]:
120+ yield f'{{"jsonrpc":"2.0", "id": { self .id } , "result": ' .encode ('ascii' )
121+ if isinstance (self .payload , Iterator ):
122+ for chunk in self .payload :
123+ yield chunk .encode ('ascii' )
124+ else :
125+ yield json .dumps (self .payload ).encode ('ascii' )
126+ yield b'}'
127127
128128
129129@dataclass (frozen = True )
130130class JsonRpcBatchResult (JsonRpcResult ):
131131 results : tuple [JsonRpcError | JsonRpcSuccess , ...]
132132
133- def encode (self ) -> bytes :
134- return json .dumps ([result .to_json () for result in self .results ]).encode ('ascii' )
133+ def encode (self ) -> Iterator [bytes ]:
134+ yield b'['
135+ first = True
136+ for result in self .results :
137+ if not first :
138+ yield b','
139+ else :
140+ first = False
141+ for chunk in result .encode ():
142+ yield chunk
143+ yield b']'
135144
136145
137146class JsonRpcRequestHandler (BaseHTTPRequestHandler ):
@@ -143,8 +152,10 @@ def __init__(self, methods: dict[str, JsonRpcMethod], *args: Any, **kwargs: Any)
143152
144153 def _send_response (self , response : JsonRpcResult ) -> None :
145154 self .send_response_headers ()
146- response_bytes = response .encode ()
147- self .wfile .write (response_bytes )
155+ response_body = response .encode ()
156+ for chunk in response_body :
157+ self .wfile .write (chunk )
158+ self .wfile .flush ()
148159
149160 def send_response_headers (self ) -> None :
150161 self .send_response (200 )
0 commit comments