33import json
44import logging
55from abc import ABC , abstractmethod
6+ from collections .abc import Iterator
67from dataclasses import dataclass
78from functools import partial
89from http .server import BaseHTTPRequestHandler , HTTPServer
9- from typing import TYPE_CHECKING , Any , Final , NamedTuple
10+ from typing import TYPE_CHECKING , NamedTuple
1011
1112from typing_extensions import Protocol
1213
1516if TYPE_CHECKING :
1617 from collections .abc import Callable
1718 from pathlib import Path
19+ from typing import Any , Final
1820
1921
2022_LOGGER : Final = logging .getLogger (__name__ )
@@ -86,7 +88,7 @@ class JsonRpcBatchRequest(NamedTuple):
8688class JsonRpcResult (ABC ):
8789
8890 @abstractmethod
89- def encode (self ) -> bytes : ...
91+ def encode (self ) -> Iterator [ bytes ] : ...
9092
9193
9294@dataclass (frozen = True )
@@ -96,7 +98,7 @@ class JsonRpcError(JsonRpcResult):
9698 message : str
9799 id : str | int | None
98100
99- def to_json (self ) -> dict [str , Any ]:
101+ def wrap_response (self ) -> dict [str , Any ]:
100102 return {
101103 'jsonrpc' : JsonRpcServer .JSONRPC_VERSION ,
102104 'error' : {
@@ -106,32 +108,40 @@ def to_json(self) -> dict[str, Any]:
106108 'id' : self .id ,
107109 }
108110
109- def encode (self ) -> bytes :
110- return json .dumps (self .to_json ()).encode ('ascii ' )
111+ def encode (self ) -> Iterator [ bytes ] :
112+ yield json .dumps (self .wrap_response ()).encode ('utf-8 ' )
111113
112114
113115@dataclass (frozen = True )
114116class JsonRpcSuccess (JsonRpcResult ):
115117 payload : Any
116118 id : Any
117119
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' )
120+ def encode (self ) -> Iterator [ bytes ]:
121+ id_encoded = json . dumps ( self . id )
122+ version_encoded = json . dumps ( JsonRpcServer .JSONRPC_VERSION )
123+ yield f'{{"jsonrpc": { version_encoded } , "id": { id_encoded } , " result": ' . encode ()
124+ if isinstance ( self .payload , Iterator ):
125+ yield from self . payload
126+ else :
127+ yield json . dumps (self . payload ). encode ( 'utf-8' )
128+ yield b'}'
127129
128130
129131@dataclass (frozen = True )
130132class JsonRpcBatchResult (JsonRpcResult ):
131133 results : tuple [JsonRpcError | JsonRpcSuccess , ...]
132134
133- def encode (self ) -> bytes :
134- return json .dumps ([result .to_json () for result in self .results ]).encode ('ascii' )
135+ def encode (self ) -> Iterator [bytes ]:
136+ yield b'['
137+ first = True
138+ for result in self .results :
139+ if not first :
140+ yield b','
141+ else :
142+ first = False
143+ yield from result .encode ()
144+ yield b']'
135145
136146
137147class JsonRpcRequestHandler (BaseHTTPRequestHandler ):
@@ -143,8 +153,10 @@ def __init__(self, methods: dict[str, JsonRpcMethod], *args: Any, **kwargs: Any)
143153
144154 def _send_response (self , response : JsonRpcResult ) -> None :
145155 self .send_response_headers ()
146- response_bytes = response .encode ()
147- self .wfile .write (response_bytes )
156+ response_body = response .encode ()
157+ for chunk in response_body :
158+ self .wfile .write (chunk )
159+ self .wfile .flush ()
148160
149161 def send_response_headers (self ) -> None :
150162 self .send_response (200 )
0 commit comments