2
2
3
3
import asyncio
4
4
import concurrent .futures
5
+ import functools
5
6
import inspect
6
7
import json
7
8
import re
8
9
import threading
9
- import time
10
10
import weakref
11
11
from abc import ABC , abstractmethod
12
12
from collections import OrderedDict
21
21
Iterator ,
22
22
List ,
23
23
Mapping ,
24
- NamedTuple ,
25
24
Optional ,
26
25
Protocol ,
27
26
Set ,
42
41
from robotcode .core .utils .dataclasses import as_json , from_dict
43
42
from robotcode .core .utils .inspect import ensure_coroutine , iter_methods
44
43
from robotcode .core .utils .logging import LoggingDescriptor
45
- from robotcode .core .utils .threading import is_threaded_callable
44
+ from robotcode .core .utils .threading import is_threaded_callable , run_callable_in_thread
46
45
47
46
__all__ = [
48
47
"JsonRPCErrors" ,
@@ -344,15 +343,23 @@ def get_param_type(self, name: str) -> Optional[Type[Any]]:
344
343
return result .param_type
345
344
346
345
347
- class SendedRequestEntry (NamedTuple ):
348
- future : concurrent .futures .Future [Any ]
349
- result_type : Optional [Type [Any ]]
346
+ class SendedRequestEntry :
347
+ def __init__ (self , future : concurrent .futures .Future [Any ], result_type : Optional [Type [Any ]]) -> None :
348
+ self .future = future
349
+ self .result_type = result_type
350
350
351
351
352
- class ReceivedRequestEntry (NamedTuple ):
353
- future : asyncio .Future [Any ]
354
- request : Optional [Any ]
355
- cancelable : bool
352
+ class ReceivedRequestEntry :
353
+ def __init__ (self , future : asyncio .Future [Any ], request : JsonRPCRequest , cancelable : bool ) -> None :
354
+ self .future = future
355
+ self .request = request
356
+ self .cancelable = cancelable
357
+ self .cancel_requested = False
358
+
359
+ def cancel (self ) -> None :
360
+ self .cancel_requested = True
361
+ if self .future is not None and not self .future .cancelled ():
362
+ self .future .cancel ()
356
363
357
364
358
365
class JsonRPCProtocolBase (asyncio .Protocol , ABC ):
@@ -711,7 +718,6 @@ def _convert_params(
711
718
return args , kw_args
712
719
713
720
async def handle_request (self , message : JsonRPCRequest ) -> None :
714
- start = time .monotonic_ns ()
715
721
try :
716
722
e = self .registry .get_entry (message .method )
717
723
@@ -725,13 +731,18 @@ async def handle_request(self, message: JsonRPCRequest) -> None:
725
731
726
732
params = self ._convert_params (e .method , e .param_type , message .params )
727
733
728
- if not e .is_coroutine :
734
+ is_threaded_method = is_threaded_callable (e .method )
735
+
736
+ if not is_threaded_method and not e .is_coroutine :
729
737
self .send_response (message .id , e .method (* params [0 ], ** params [1 ]))
730
738
else :
731
- if is_threaded_callable (e .method ):
732
- task = run_coroutine_in_thread (
733
- ensure_coroutine (cast (Callable [..., Any ], e .method )), * params [0 ], ** params [1 ]
734
- )
739
+ if is_threaded_method :
740
+ if e .is_coroutine :
741
+ task = run_coroutine_in_thread (
742
+ ensure_coroutine (cast (Callable [..., Any ], e .method )), * params [0 ], ** params [1 ]
743
+ )
744
+ else :
745
+ task = asyncio .wrap_future (run_callable_in_thread (e .method , * params [0 ], ** params [1 ]))
735
746
else :
736
747
task = create_sub_task (
737
748
ensure_coroutine (e .method )(* params [0 ], ** params [1 ]),
@@ -741,49 +752,56 @@ async def handle_request(self, message: JsonRPCRequest) -> None:
741
752
with self ._received_request_lock :
742
753
self ._received_request [message .id ] = ReceivedRequestEntry (task , message , e .cancelable )
743
754
744
- def done (t : asyncio .Future [Any ]) -> None :
745
- try :
746
- if not t .cancelled ():
747
- ex = t .exception ()
748
- if ex is not None :
749
- self .__logger .exception (ex , exc_info = ex )
750
- raise JsonRPCErrorException (
751
- JsonRPCErrors .INTERNAL_ERROR , f"{ type (ex ).__name__ } : { ex } "
752
- ) from ex
753
-
754
- self .send_response (message .id , t .result ())
755
- except asyncio .CancelledError :
756
- self .__logger .debug (lambda : f"request message { message !r} canceled" )
757
- self .send_error (JsonRPCErrors .REQUEST_CANCELLED , "Request canceled." , id = message .id )
758
- except (SystemExit , KeyboardInterrupt ):
759
- raise
760
- except JsonRPCErrorException as e :
761
- self .send_error (e .code , e .message or f"{ type (e ).__name__ } : { e } " , id = message .id , data = e .data )
762
- except BaseException as e :
763
- self .__logger .exception (e )
764
- self .send_error (JsonRPCErrors .INTERNAL_ERROR , f"{ type (e ).__name__ } : { e } " , id = message .id )
765
- finally :
766
- with self ._received_request_lock :
767
- self ._received_request .pop (message .id , None )
768
-
769
- task .add_done_callback (done )
755
+ task .add_done_callback (functools .partial (self ._received_request_done , message ))
770
756
771
757
await task
772
- finally :
773
- self .__logger .debug (lambda : f"request message { message !r} done in { time .monotonic_ns () - start } ns" )
758
+ except (SystemExit , KeyboardInterrupt , asyncio .CancelledError ):
759
+ raise
760
+ except BaseException as e :
761
+ self .__logger .exception (e )
762
+
763
+ def _received_request_done (self , message : JsonRPCRequest , t : asyncio .Future [Any ]) -> None :
764
+ try :
765
+ with self ._received_request_lock :
766
+ entry = self ._received_request .pop (message .id , None )
767
+
768
+ if entry is None :
769
+ self .__logger .critical (lambda : f"unknown request { message !r} " )
770
+ return
771
+
772
+ if entry .cancel_requested :
773
+ self .__logger .debug (lambda : f"request { message !r} canceled" )
774
+ self .send_error (JsonRPCErrors .REQUEST_CANCELLED , "Request canceled." , id = message .id )
775
+ else :
776
+ if not t .cancelled ():
777
+ ex = t .exception ()
778
+ if ex is not None :
779
+ self .__logger .exception (ex , exc_info = ex )
780
+ raise JsonRPCErrorException (JsonRPCErrors .INTERNAL_ERROR , f"{ type (ex ).__name__ } : { ex } " ) from ex
781
+
782
+ self .send_response (message .id , t .result ())
783
+ except asyncio .CancelledError :
784
+ self .__logger .debug (lambda : f"request message { message !r} canceled" )
785
+ self .send_error (JsonRPCErrors .REQUEST_CANCELLED , "Request canceled." , id = message .id )
786
+ except (SystemExit , KeyboardInterrupt ):
787
+ raise
788
+ except JsonRPCErrorException as e :
789
+ self .send_error (e .code , e .message or f"{ type (e ).__name__ } : { e } " , id = message .id , data = e .data )
790
+ except BaseException as e :
791
+ self .__logger .exception (e )
792
+ self .send_error (JsonRPCErrors .INTERNAL_ERROR , f"{ type (e ).__name__ } : { e } " , id = message .id )
774
793
775
794
def cancel_request (self , id : Union [int , str , None ]) -> None :
776
795
with self ._received_request_lock :
777
796
entry = self ._received_request .get (id , None )
778
797
779
- if entry is not None and entry . future is not None and not entry . future . cancelled () :
798
+ if entry is not None :
780
799
self .__logger .debug (lambda : f"try to cancel request { entry .request if entry is not None else '' } " )
781
- entry .future . cancel ()
800
+ entry .cancel ()
782
801
783
802
def cancel_all_received_request (self ) -> None :
784
803
for entry in self ._received_request .values ():
785
- if entry is not None and entry .cancelable and entry .future is not None and not entry .future .cancelled ():
786
- entry .future .cancel ()
804
+ entry .cancel ()
787
805
788
806
@__logger .call
789
807
async def handle_notification (self , message : JsonRPCNotification ) -> None :
0 commit comments